From 8602e384f223521679a78dc607a37a63075e769c Mon Sep 17 00:00:00 2001 From: Mike Fienen Date: Thu, 16 Sep 2021 15:03:13 -0500 Subject: [PATCH 1/7] observations code updated --- dependencies/sfrmaker/observations.py | 13 +++++++++++-- notebooks/modflow_setup/1_preprocessing.ipynb | 19 +++++++++++++------ .../2_build_model_from_YML.ipynb | 2 +- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/dependencies/sfrmaker/observations.py b/dependencies/sfrmaker/observations.py index afc68f0..fb278fc 100644 --- a/dependencies/sfrmaker/observations.py +++ b/dependencies/sfrmaker/observations.py @@ -83,9 +83,18 @@ def add_observations(sfrdata, data, flowline_routing=None, """ sfrd = sfrdata reach_data = sfrdata.reach_data.copy() - + # allow input via a list of tables or single table - data = read_tables(data, dtype={obsname_column: object}) + data = read_tables(data)#, dtype={obsname_column: object}) + # need a special case if allowing obsname_column to also be identifier + if obsname_column == rno_column: + obsname_column = f'obsnamecol_{obsname_column}' + data[obsname_column] = data[rno_column].astype(object) + elif obsname_column == line_id_column: + obsname_column = f'obsnamecol_{obsname_column}' + data[obsname_column] = data[line_id_column].astype(object) + else: + data[obsname_column] = data[obsname_column].astype(object) assert data[obsname_column].dtype == np.object # read reach geometries from a shapefile diff --git a/notebooks/modflow_setup/1_preprocessing.ipynb b/notebooks/modflow_setup/1_preprocessing.ipynb index 3d7339f..5e58f63 100644 --- a/notebooks/modflow_setup/1_preprocessing.ipynb +++ b/notebooks/modflow_setup/1_preprocessing.ipynb @@ -1163,7 +1163,7 @@ { "cell_type": "code", "execution_count": null, - "id": "06d0b3da", + "id": "8f52fc29", "metadata": {}, "outputs": [], "source": [ @@ -1174,25 +1174,24 @@ { "cell_type": "code", "execution_count": null, - "id": "d90c9fe7", + "id": "9be496f1", "metadata": {}, "outputs": [], "source": [ "# for SFR observations, we need to make a CSV file with the segments identified\n", "inriv = gp.read_file(rivfile)\n", - "inriv['obsname'] = [f'seg_{i}' for i in inriv.segname]\n", "inriv.head()" ] }, { "cell_type": "code", "execution_count": null, - "id": "bf446cc5", + "id": "8ed47573", "metadata": {}, "outputs": [], "source": [ "rivsegfile = str(datapath / 'csv' / 'river_segments.csv')\n", - "inriv[['segname', 'obsname']].to_csv(rivsegfile)" + "inriv['segname'].to_csv(rivsegfile)" ] }, { @@ -1222,7 +1221,7 @@ "config_data['sfr']['source_data']['observations']['filename'] = rivsegfile\n", "config_data['sfr']['source_data']['observations']['obstype'] = ['sfr','outflow', 'downstream-flow','ext-outflow']\n", "config_data['sfr']['source_data']['observations']['line_id_column'] = 'segname'\n", - "config_data['sfr']['source_data']['observations']['obsname_column'] = 'obsname'\n", + "config_data['sfr']['source_data']['observations']['obsname_column'] = 'segname'\n", "\n", "config_data['sfr']['set_streambed_top_elevations_from_dem'] = True\n", "\n" @@ -1265,6 +1264,14 @@ "metadata": {}, "outputs": [], "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab12633b", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/notebooks/modflow_setup/2_build_model_from_YML.ipynb b/notebooks/modflow_setup/2_build_model_from_YML.ipynb index 50bda6d..3f6dfe6 100644 --- a/notebooks/modflow_setup/2_build_model_from_YML.ipynb +++ b/notebooks/modflow_setup/2_build_model_from_YML.ipynb @@ -323,7 +323,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7430cacf", + "id": "1a3156cc", "metadata": {}, "outputs": [], "source": [] From e79e54e9f731dcf649e38412570d1adbd05b8033 Mon Sep 17 00:00:00 2001 From: jdub Date: Wed, 22 Sep 2021 14:54:07 -0600 Subject: [PATCH 2/7] updated flopy and pyemu --- dependencies/flopy/datbase.py | 16 +- dependencies/flopy/discretization/grid.py | 61 +- .../flopy/discretization/structuredgrid.py | 45 +- .../flopy/discretization/unstructuredgrid.py | 25 +- .../flopy/discretization/vertexgrid.py | 21 +- dependencies/flopy/export/metadata.py | 8 +- dependencies/flopy/export/netcdf.py | 196 +- dependencies/flopy/export/shapefile_utils.py | 121 +- dependencies/flopy/export/utils.py | 187 +- dependencies/flopy/export/vtk.py | 120 +- dependencies/flopy/mbase.py | 151 +- .../flopy/mf6/coordinates/modeldimensions.py | 2 +- .../flopy/mf6/coordinates/modelgrid.py | 11 +- .../flopy/mf6/coordinates/simulationtime.py | 3 +- dependencies/flopy/mf6/data/dfn/gwf-api.dfn | 96 + dependencies/flopy/mf6/data/dfn/gwf-buy.dfn | 2 +- dependencies/flopy/mf6/data/dfn/gwf-disu.dfn | 9 + dependencies/flopy/mf6/data/dfn/gwf-sfr.dfn | 2 +- dependencies/flopy/mf6/data/dfn/gwf-sto.dfn | 8 + dependencies/flopy/mf6/data/dfn/gwf-uzf.dfn | 47 +- dependencies/flopy/mf6/data/dfn/gwt-api.dfn | 96 + dependencies/flopy/mf6/data/dfn/gwt-disu.dfn | 25 +- dependencies/flopy/mf6/data/dfn/gwt-fmi.dfn | 8 + dependencies/flopy/mf6/data/dfn/gwt-ist.dfn | 12 +- dependencies/flopy/mf6/data/dfn/gwt-lkt.dfn | 2 +- dependencies/flopy/mf6/data/dfn/gwt-mst.dfn | 10 +- dependencies/flopy/mf6/data/dfn/gwt-mwt.dfn | 2 +- dependencies/flopy/mf6/data/dfn/gwt-sft.dfn | 2 +- dependencies/flopy/mf6/data/dfn/gwt-ssm.dfn | 2 +- dependencies/flopy/mf6/data/dfn/gwt-uzt.dfn | 2 +- dependencies/flopy/mf6/data/dfn/sim-tdis.dfn | 44 +- dependencies/flopy/mf6/data/dfn/sln-ims.dfn | 10 +- dependencies/flopy/mf6/data/dfn/utl-ats.dfn | 84 + dependencies/flopy/mf6/data/mfdata.py | 34 +- dependencies/flopy/mf6/data/mfdataarray.py | 82 +- dependencies/flopy/mf6/data/mfdatalist.py | 57 +- dependencies/flopy/mf6/data/mfdatascalar.py | 29 +- dependencies/flopy/mf6/data/mfdatastorage.py | 94 +- dependencies/flopy/mf6/data/mfdatautil.py | 24 +- dependencies/flopy/mf6/data/mffileaccess.py | 75 +- dependencies/flopy/mf6/data/mfstructure.py | 112 +- dependencies/flopy/mf6/mfbase.py | 112 +- dependencies/flopy/mf6/mfmodel.py | 154 +- dependencies/flopy/mf6/mfpackage.py | 215 +- dependencies/flopy/mf6/modflow/__init__.py | 32 +- dependencies/flopy/mf6/modflow/mfgnc.py | 2 +- dependencies/flopy/mf6/modflow/mfgwf.py | 6 +- dependencies/flopy/mf6/modflow/mfgwfapi.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfbuy.py | 4 +- dependencies/flopy/mf6/modflow/mfgwfchd.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfcsub.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfdis.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfdisu.py | 22 +- dependencies/flopy/mf6/modflow/mfgwfdisv.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfdrn.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfevt.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfevta.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfghb.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfgnc.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfgwf.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfgwt.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfhfb.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfic.py | 2 +- dependencies/flopy/mf6/modflow/mfgwflak.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfmaw.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfmvr.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfnam.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfnpf.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfoc.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfrch.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfrcha.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfriv.py | 2 +- dependencies/flopy/mf6/modflow/mfgwfsfr.py | 14 +- dependencies/flopy/mf6/modflow/mfgwfsto.py | 19 +- dependencies/flopy/mf6/modflow/mfgwfuzf.py | 78 +- dependencies/flopy/mf6/modflow/mfgwfwel.py | 2 +- dependencies/flopy/mf6/modflow/mfgwt.py | 2 +- dependencies/flopy/mf6/modflow/mfgwtadv.py | 2 +- dependencies/flopy/mf6/modflow/mfgwtapi.py | 189 ++ dependencies/flopy/mf6/modflow/mfgwtcnc.py | 2 +- dependencies/flopy/mf6/modflow/mfgwtdis.py | 2 +- dependencies/flopy/mf6/modflow/mfgwtdisu.py | 52 +- dependencies/flopy/mf6/modflow/mfgwtdisv.py | 2 +- dependencies/flopy/mf6/modflow/mfgwtdsp.py | 2 +- dependencies/flopy/mf6/modflow/mfgwtfmi.py | 15 +- dependencies/flopy/mf6/modflow/mfgwtic.py | 2 +- dependencies/flopy/mf6/modflow/mfgwtist.py | 20 +- dependencies/flopy/mf6/modflow/mfgwtlkt.py | 4 +- dependencies/flopy/mf6/modflow/mfgwtmst.py | 14 +- dependencies/flopy/mf6/modflow/mfgwtmvt.py | 2 +- dependencies/flopy/mf6/modflow/mfgwtmwt.py | 4 +- dependencies/flopy/mf6/modflow/mfgwtnam.py | 2 +- dependencies/flopy/mf6/modflow/mfgwtoc.py | 2 +- dependencies/flopy/mf6/modflow/mfgwtsft.py | 4 +- dependencies/flopy/mf6/modflow/mfgwtsrc.py | 2 +- dependencies/flopy/mf6/modflow/mfgwtssm.py | 9 +- dependencies/flopy/mf6/modflow/mfgwtuzt.py | 4 +- dependencies/flopy/mf6/modflow/mfims.py | 33 +- dependencies/flopy/mf6/modflow/mfmvr.py | 2 +- dependencies/flopy/mf6/modflow/mfnam.py | 2 +- .../flopy/mf6/modflow/mfsimulation.py | 569 ++-- dependencies/flopy/mf6/modflow/mftdis.py | 54 +- dependencies/flopy/mf6/modflow/mfutlats.py | 211 ++ dependencies/flopy/mf6/modflow/mfutllaktab.py | 2 +- dependencies/flopy/mf6/modflow/mfutlobs.py | 2 +- dependencies/flopy/mf6/modflow/mfutltas.py | 2 +- dependencies/flopy/mf6/modflow/mfutlts.py | 2 +- dependencies/flopy/mf6/utils/__init__.py | 1 + .../flopy/mf6/utils/binaryfile_utils.py | 22 +- .../flopy/mf6/utils/binarygrid_util.py | 110 +- .../flopy/mf6/utils/createpackages.py | 186 +- .../flopy/mf6/utils/generate_classes.py | 32 +- dependencies/flopy/mf6/utils/lakpak_utils.py | 281 ++ dependencies/flopy/mf6/utils/mfobservation.py | 13 +- dependencies/flopy/mf6/utils/output_util.py | 92 +- .../flopy/mf6/utils/postprocessing.py | 17 +- dependencies/flopy/mf6/utils/reference.py | 34 +- dependencies/flopy/modflow/mf.py | 158 +- dependencies/flopy/modflow/mfag.py | 91 +- dependencies/flopy/modflow/mfbas.py | 20 +- dependencies/flopy/modflow/mfbcf.py | 32 +- dependencies/flopy/modflow/mfbct.py | 2 +- dependencies/flopy/modflow/mfchd.py | 17 +- dependencies/flopy/modflow/mfde4.py | 47 +- dependencies/flopy/modflow/mfdis.py | 130 +- dependencies/flopy/modflow/mfdisu.py | 119 +- dependencies/flopy/modflow/mfdrn.py | 22 +- dependencies/flopy/modflow/mfdrt.py | 22 +- dependencies/flopy/modflow/mfevt.py | 44 +- dependencies/flopy/modflow/mffhb.py | 216 +- dependencies/flopy/modflow/mfflwob.py | 44 +- dependencies/flopy/modflow/mfgage.py | 53 +- dependencies/flopy/modflow/mfghb.py | 19 +- dependencies/flopy/modflow/mfgmg.py | 25 +- dependencies/flopy/modflow/mfhfb.py | 17 +- dependencies/flopy/modflow/mfhob.py | 125 +- dependencies/flopy/modflow/mfhyd.py | 40 +- dependencies/flopy/modflow/mflak.py | 85 +- dependencies/flopy/modflow/mflmt.py | 35 +- dependencies/flopy/modflow/mflpf.py | 41 +- dependencies/flopy/modflow/mfmlt.py | 20 +- dependencies/flopy/modflow/mfmnw1.py | 9 +- dependencies/flopy/modflow/mfmnw2.py | 54 +- dependencies/flopy/modflow/mfmnwi.py | 32 +- dependencies/flopy/modflow/mfnwt.py | 152 +- dependencies/flopy/modflow/mfoc.py | 91 +- dependencies/flopy/modflow/mfpar.py | 34 +- dependencies/flopy/modflow/mfparbc.py | 4 +- dependencies/flopy/modflow/mfpbc.py | 27 +- dependencies/flopy/modflow/mfpcg.py | 60 +- dependencies/flopy/modflow/mfpcgn.py | 63 +- dependencies/flopy/modflow/mfpks.py | 60 +- dependencies/flopy/modflow/mfpval.py | 13 +- dependencies/flopy/modflow/mfrch.py | 60 +- dependencies/flopy/modflow/mfriv.py | 28 +- dependencies/flopy/modflow/mfsfr2.py | 182 +- dependencies/flopy/modflow/mfsip.py | 35 +- dependencies/flopy/modflow/mfsms.py | 111 +- dependencies/flopy/modflow/mfsor.py | 37 +- dependencies/flopy/modflow/mfstr.py | 97 +- dependencies/flopy/modflow/mfsub.py | 144 +- dependencies/flopy/modflow/mfswi2.py | 77 +- dependencies/flopy/modflow/mfswr1.py | 9 +- dependencies/flopy/modflow/mfswt.py | 97 +- dependencies/flopy/modflow/mfupw.py | 42 +- dependencies/flopy/modflow/mfuzf1.py | 68 +- dependencies/flopy/modflow/mfwel.py | 55 +- dependencies/flopy/modflow/mfzon.py | 16 +- dependencies/flopy/modflowlgr/mflgr.py | 102 +- dependencies/flopy/modpath/mp6.py | 48 +- dependencies/flopy/modpath/mp6bas.py | 10 +- dependencies/flopy/modpath/mp6sim.py | 88 +- dependencies/flopy/modpath/mp7.py | 87 +- dependencies/flopy/modpath/mp7bas.py | 31 +- dependencies/flopy/modpath/mp7particledata.py | 295 +- .../flopy/modpath/mp7particlegroup.py | 75 +- dependencies/flopy/modpath/mp7sim.py | 185 +- dependencies/flopy/mt3d/mt.py | 132 +- dependencies/flopy/mt3d/mtadv.py | 35 +- dependencies/flopy/mt3d/mtbtn.py | 131 +- dependencies/flopy/mt3d/mtdsp.py | 17 +- dependencies/flopy/mt3d/mtgcg.py | 25 +- dependencies/flopy/mt3d/mtlkt.py | 43 +- dependencies/flopy/mt3d/mtrct.py | 99 +- dependencies/flopy/mt3d/mtsft.py | 68 +- dependencies/flopy/mt3d/mtssm.py | 86 +- dependencies/flopy/mt3d/mtuzt.py | 92 +- dependencies/flopy/pakbase.py | 239 +- dependencies/flopy/pest/params.py | 3 +- dependencies/flopy/pest/templatewriter.py | 8 +- dependencies/flopy/pest/tplarray.py | 28 +- dependencies/flopy/plot/__init__.py | 4 +- dependencies/flopy/plot/crosssection.py | 332 +-- dependencies/flopy/plot/map.py | 426 +-- dependencies/flopy/plot/plotutil.py | 184 +- dependencies/flopy/plot/styles.py | 14 +- dependencies/flopy/seawat/swt.py | 40 +- dependencies/flopy/seawat/swtvdf.py | 18 +- dependencies/flopy/seawat/swtvsc.py | 64 +- dependencies/flopy/utils/__init__.py | 4 - dependencies/flopy/utils/binaryfile.py | 148 +- dependencies/flopy/utils/binarygrid_util.py | 42 - dependencies/flopy/utils/check.py | 40 +- dependencies/flopy/utils/cvfdutil.py | 25 +- dependencies/flopy/utils/datafile.py | 58 +- dependencies/flopy/utils/datautil.py | 37 +- dependencies/flopy/utils/flopy_io.py | 46 +- dependencies/flopy/utils/formattedfile.py | 22 +- dependencies/flopy/utils/geometry.py | 44 +- dependencies/flopy/utils/gridgen.py | 160 +- dependencies/flopy/utils/gridintersect.py | 72 +- dependencies/flopy/utils/mflistfile.py | 51 +- dependencies/flopy/utils/mfreadnam.py | 60 +- dependencies/flopy/utils/modpathfile.py | 183 +- dependencies/flopy/utils/mtlistfile.py | 50 +- dependencies/flopy/utils/observationfile.py | 8 +- dependencies/flopy/utils/optionblock.py | 41 +- dependencies/flopy/utils/postprocessing.py | 89 +- dependencies/flopy/utils/rasters.py | 55 +- dependencies/flopy/utils/reference.py | 2375 ----------------- dependencies/flopy/utils/sfroutputfile.py | 6 +- dependencies/flopy/utils/swroutputfile.py | 19 +- dependencies/flopy/utils/triangle.py | 86 +- dependencies/flopy/utils/util_array.py | 410 +-- dependencies/flopy/utils/util_list.py | 130 +- dependencies/flopy/utils/voronoi.py | 7 +- dependencies/flopy/utils/zonbud.py | 489 +--- dependencies/flopy/version.py | 22 +- dependencies/pyemu/pst/pst_handler.py | 167 +- dependencies/pyemu/pyemu_warnings.py | 6 +- dependencies/pyemu/utils/gw_utils.py | 8 +- dependencies/pyemu/utils/helpers.py | 68 +- dependencies/pyemu/utils/os_utils.py | 2 +- dependencies/pyemu/utils/pp_utils.py | 42 +- dependencies/pyemu/utils/pst_from.py | 173 +- 235 files changed, 6213 insertions(+), 9769 deletions(-) create mode 100644 dependencies/flopy/mf6/data/dfn/gwf-api.dfn create mode 100644 dependencies/flopy/mf6/data/dfn/gwt-api.dfn create mode 100644 dependencies/flopy/mf6/data/dfn/utl-ats.dfn create mode 100644 dependencies/flopy/mf6/modflow/mfgwtapi.py create mode 100644 dependencies/flopy/mf6/modflow/mfutlats.py create mode 100644 dependencies/flopy/mf6/utils/lakpak_utils.py delete mode 100644 dependencies/flopy/utils/binarygrid_util.py diff --git a/dependencies/flopy/datbase.py b/dependencies/flopy/datbase.py index b57f001..2ae5d83 100644 --- a/dependencies/flopy/datbase.py +++ b/dependencies/flopy/datbase.py @@ -18,7 +18,7 @@ class DataInterface: @abc.abstractmethod def data_type(self): raise NotImplementedError( - "must define dat_type in child " "class to use this base class" + "must define dat_type in child class to use this base class" ) @property @@ -26,35 +26,35 @@ def data_type(self): def dtype(self): def dtype(self): raise NotImplementedError( - "must define dtype in child " "class to use this base class" + "must define dtype in child class to use this base class" ) @property @abc.abstractmethod def array(self): raise NotImplementedError( - "must define array in child " "class to use this base class" + "must define array in child class to use this base class" ) @property @abc.abstractmethod def name(self): raise NotImplementedError( - "must define name in child " "class to use this base class" + "must define name in child class to use this base class" ) @property @abc.abstractmethod def model(self): raise NotImplementedError( - "must define name in child " "class to use this base class" + "must define name in child class to use this base class" ) @property @abc.abstractmethod def plottable(self): raise NotImplementedError( - "must define plottable in child " "class to use this base class" + "must define plottable in child class to use this base class" ) @@ -63,7 +63,7 @@ class DataListInterface: @abc.abstractmethod def package(self): raise NotImplementedError( - "must define package in child " "class to use this base class" + "must define package in child class to use this base class" ) @property @@ -71,7 +71,7 @@ def package(self): def to_array(self, kper=0, mask=False): def to_array(self): raise NotImplementedError( - "must define to_array in child " "class to use this base class" + "must define to_array in child class to use this base class" ) @abc.abstractmethod diff --git a/dependencies/flopy/discretization/grid.py b/dependencies/flopy/discretization/grid.py index 9c4e72f..1bc0cb4 100644 --- a/dependencies/flopy/discretization/grid.py +++ b/dependencies/flopy/discretization/grid.py @@ -180,6 +180,7 @@ def __init__( self._iverts = None self._verts = None + self._laycbd = None ################################### # access to basic grid properties @@ -192,16 +193,16 @@ def __repr__(self): and self.angrot is not None ): items += [ - "xll:" + str(self.xoffset), - "yll:" + str(self.yoffset), - "rotation:" + str(self.angrot), + f"xll:{self.xoffset!s}", + f"yll:{self.yoffset!s}", + f"rotation:{self.angrot!s}", ] if self.proj4 is not None: - items.append("proj4_str:" + str(self.proj4)) + items.append(f"proj4_str:{self.proj4}") if self.units is not None: - items.append("units:" + str(self.units)) + items.append(f"units:{self.units}") if self.lenuni is not None: - items.append("lenuni:" + str(self.lenuni)) + items.append(f"lenuni:{self.lenuni}") return "; ".join(items) @property @@ -258,7 +259,7 @@ def proj4(self): else: proj4 = self._proj4 elif self.epsg is not None: - proj4 = "epsg:{}".format(self.epsg) + proj4 = f"epsg:{self.epsg}" return proj4 @proj4.setter @@ -285,6 +286,13 @@ def botm(self): def top_botm(self): raise NotImplementedError("must define top_botm in child class") + @property + def laycbd(self): + if self._laycbd is None: + return None + else: + return self._laycbd + @property def thick(self): """ @@ -317,6 +325,11 @@ def saturated_thick(self, array, mask=None): thick = self.thick top = self.top_botm[:-1].reshape(thick.shape) bot = self.top_botm[1:].reshape(thick.shape) + thick = self.remove_confining_beds(thick) + top = self.remove_confining_beds(top) + bot = self.remove_confining_beds(bot) + array = self.remove_confining_beds(array) + idx = np.where((array < top) & (array > bot)) thick[idx] = array[idx] - bot[idx] idx = np.where(array <= bot) @@ -443,6 +456,32 @@ def xyzvertices(self): def cross_section_vertices(self): return self.xyzvertices[0], self.xyzvertices[1] + def remove_confining_beds(self, array): + """ + Method to remove confining bed layers from an array + + Parameters + ---------- + array : np.ndarray + array to remove quasi3d confining bed data from. Shape of axis 0 + should be (self.lay + ncb) to remove beds + Returns + ------- + np.ndarray + """ + if self.laycbd is not None: + ncb = np.count_nonzero(self.laycbd) + if ncb > 0: + if array.shape[0] == self.shape[0] + ncb: + cb = 0 + idx = [] + for ix, i in enumerate(self.laycbd): + idx.append(ix + cb) + if i > 0: + cb += 1 + array = array[idx] + return array + def cross_section_lay_ncpl_ncb(self, ncb): """ Get PlotCrossSection compatible layers, ncpl, and ncb @@ -706,19 +745,11 @@ def attribs_from_namfile_header(self, namefile): elif "xul" in item.lower(): try: xul = float(item.split(":")[1]) - warnings.warn( - "xul/yul have been deprecated. Use xll/yll instead.", - DeprecationWarning, - ) except: pass elif "yul" in item.lower(): try: yul = float(item.split(":")[1]) - warnings.warn( - "xul/yul have been deprecated. Use xll/yll instead.", - DeprecationWarning, - ) except: pass elif "rotation" in item.lower(): diff --git a/dependencies/flopy/discretization/structuredgrid.py b/dependencies/flopy/discretization/structuredgrid.py index c85c78d..8d300a2 100644 --- a/dependencies/flopy/discretization/structuredgrid.py +++ b/dependencies/flopy/discretization/structuredgrid.py @@ -4,34 +4,6 @@ import numpy as np from .grid import Grid, CachedData -try: - from numpy.lib import NumpyVersion - - numpy115 = NumpyVersion(np.__version__) >= "1.15.0" -except ImportError: - numpy115 = False - -if not numpy115: - - def flip_numpy115(m, axis=None): - """Provide same behavior for np.flip since numpy 1.15.0.""" - import numpy.core.numeric as _nx - from numpy.core.numeric import asarray - - if not hasattr(m, "ndim"): - m = asarray(m) - if axis is None: - indexer = (np.s_[::-1],) * m.ndim - else: - axis = _nx.normalize_axis_tuple(axis, m.ndim) - indexer = [np.s_[:]] * m.ndim - for ax in axis: - indexer[ax] = np.s_[::-1] - indexer = tuple(indexer) - return m[indexer] - - np.flip = flip_numpy115 - def array_at_verts_basic2d(a): """ @@ -189,15 +161,15 @@ def __init__( self.__nlay = nlay else: if laycbd is not None: - self.__nlay = len(botm) - np.sum(laycbd > 0) + self.__nlay = len(botm) - np.count_nonzero(laycbd) else: self.__nlay = len(botm) else: self.__nlay = nlay if laycbd is not None: - self.__laycbd = laycbd + self._laycbd = laycbd else: - self.__laycbd = np.zeros(self.__nlay or (), dtype=int) + self._laycbd = np.zeros(self.__nlay or (), dtype=int) #################### # Properties @@ -464,7 +436,7 @@ def xyzcellcenters(self): z = np.empty((self.__nlay, self.__nrow, self.__ncol)) z[0, :, :] = (self._top[:, :] + self._botm[0, :, :]) / 2.0 ibs = np.arange(self.__nlay) - quasi3d = [cbd != 0 for cbd in self.__laycbd] + quasi3d = [cbd != 0 for cbd in self._laycbd] if np.any(quasi3d): ibs[1:] = ibs[1:] + np.cumsum(quasi3d)[: self.__nlay - 1] for l, ib in enumerate(ibs[1:], 1): @@ -1562,7 +1534,7 @@ def get_plottable_layer_array(self, a, layer): plotarray = plotarray[layer, :, :] else: raise Exception("Array to plot must be of dimension 1, 2, or 3") - msg = "{} /= {}".format(plotarray.shape, required_shape) + msg = f"{plotarray.shape} /= {required_shape}" assert plotarray.shape == required_shape, msg return plotarray @@ -1643,11 +1615,10 @@ def from_binary_grid_file(cls, file_path, verbose=False): grb_obj = MfGrdFile(file_path, verbose=verbose) if grb_obj.grid_type != "DIS": - err_msg = ( - "Binary grid file ({}) ".format(os.path.basename(file_path)) - + "is not a structured (DIS) grid." + raise ValueError( + f"Binary grid file ({os.path.basename(file_path)}) " + "is not a structured (DIS) grid." ) - raise ValueError(err_msg) idomain = grb_obj.idomain xorigin = grb_obj.xorigin diff --git a/dependencies/flopy/discretization/unstructuredgrid.py b/dependencies/flopy/discretization/unstructuredgrid.py index 0df3829..1955a88 100644 --- a/dependencies/flopy/discretization/unstructuredgrid.py +++ b/dependencies/flopy/discretization/unstructuredgrid.py @@ -128,14 +128,13 @@ def __init__( if iverts is not None: if self.grid_varies_by_layer: - msg = "Length of iverts must equal grid nodes ({} {})".format( - len(iverts), self.nnodes + msg = ( + "Length of iverts must equal grid nodes " + f"({len(iverts)} {self.nnodes})" ) assert len(iverts) == self.nnodes, msg else: - msg = "Length of iverts must equal ncpl ({} {})".format( - len(iverts), self.ncpl - ) + msg = f"Length of iverts must equal ncpl ({len(iverts)} {self.ncpl})" assert np.all([cpl == len(iverts) for cpl in self.ncpl]), msg return @@ -208,7 +207,7 @@ def verts(self): if self._vertices is None: return self._vertices else: - return np.array([t[1:] for t in self._vertices], dtype=float) + return np.array([list(t)[1:] for t in self._vertices], dtype=float) @property def ia(self): @@ -809,11 +808,10 @@ def from_binary_grid_file(cls, file_path, verbose=False): grb_obj = MfGrdFile(file_path, verbose=verbose) if grb_obj.grid_type != "DISU": - err_msg = ( - "Binary grid file ({}) ".format(os.path.basename(file_path)) - + "is not a vertex (DISU) grid." + raise ValueError( + f"Binary grid file ({os.path.basename(file_path)}) " + "is not a vertex (DISU) grid." ) - raise ValueError(err_msg) iverts = grb_obj.iverts if iverts is not None: @@ -842,8 +840,7 @@ def from_binary_grid_file(cls, file_path, verbose=False): angrot=angrot, ) else: - err_msg = ( - "{} binary grid file".format(os.path.basename(file_path)) - + " does not include vertex data" + raise TypeError( + f"{os.path.basename(file_path)} binary grid file " + "does not include vertex data" ) - raise TypeError(err_msg) diff --git a/dependencies/flopy/discretization/vertexgrid.py b/dependencies/flopy/discretization/vertexgrid.py index 6f2f0a6..40e8555 100644 --- a/dependencies/flopy/discretization/vertexgrid.py +++ b/dependencies/flopy/discretization/vertexgrid.py @@ -4,7 +4,7 @@ try: from matplotlib.path import Path -except ImportError: +except (ImportError, RuntimeError): Path = None from .grid import Grid, CachedData @@ -128,11 +128,11 @@ def nvert(self): @property def iverts(self): - return [[t[0]] + t[4:] for t in self._cell2d] + return [[t[0]] + list(t)[4:] for t in self._cell2d] @property def verts(self): - return np.array([t[1:] for t in self._vertices], dtype=float) + return np.array([list(t)[1:] for t in self._vertices], dtype=float) @property def shape(self): @@ -273,7 +273,7 @@ def intersect(self, x, y, local=False, forgive=False): if Path is None: s = ( "Could not import matplotlib. Must install matplotlib " - + " in order to use VertexGrid.intersect() method" + "in order to use VertexGrid.intersect() method" ) raise ImportError(s) @@ -314,9 +314,7 @@ def get_cell_vertices(self, cellid): """ while cellid >= self.ncpl: if cellid > self.nnodes: - err = "cellid {} out of index for size {}".format( - cellid, self.nnodes - ) + err = f"cellid {cellid} out of index for size {self.nnodes}" raise IndexError(err) cellid -= self.ncpl @@ -491,7 +489,7 @@ def get_plottable_layer_array(self, a, layer): plotarray = plotarray[layer, :] else: raise Exception("Array to plot must be of dimension 1 or 2") - msg = "{} /= {}".format(plotarray.shape[0], required_shape) + msg = f"{plotarray.shape[0]} /= {required_shape}" assert plotarray.shape == required_shape, msg return plotarray @@ -518,11 +516,10 @@ def from_binary_grid_file(cls, file_path, verbose=False): grb_obj = MfGrdFile(file_path, verbose=verbose) if grb_obj.grid_type != "DISV": - err_msg = ( - "Binary grid file ({}) ".format(os.path.basename(file_path)) - + "is not a vertex (DISV) grid." + raise ValueError( + f"Binary grid file ({os.path.basename(file_path)}) " + "is not a vertex (DISV) grid." ) - raise ValueError(err_msg) idomain = grb_obj.idomain xorigin = grb_obj.xorigin diff --git a/dependencies/flopy/export/metadata.py b/dependencies/flopy/export/metadata.py index 1ff420c..d73646c 100644 --- a/dependencies/flopy/export/metadata.py +++ b/dependencies/flopy/export/metadata.py @@ -40,9 +40,7 @@ def __init__(self, sciencebase_id, model): self.model_grid = model.modelgrid self.model_time = model.modeltime self.sciencebase_url = ( - "https://www.sciencebase.gov/catalog/item/{}".format( - sciencebase_id - ) + f"https://www.sciencebase.gov/catalog/item/{sciencebase_id}" ) self.sb = self.get_sciencebase_metadata(sciencebase_id) if self.sb is None: @@ -140,7 +138,7 @@ def creator(self): @property def creator_url(self): urlname = "-".join(self.creator.get("name").replace(".", "").split()) - url = "https://www.usgs.gov/staff-profiles/" + urlname.lower() + url = f"https://www.usgs.gov/staff-profiles/{urlname.lower()}" # check if it exists txt = get_url_text(url) if txt is not None: @@ -208,7 +206,7 @@ def time_coverage(self): strt = pd.Timestamp(self.model_time.start_datetime) mlen = self.model_time.perlen.sum() tunits = self.model_time.time_units - tc["duration"] = "{} {}".format(mlen, tunits) + tc["duration"] = f"{mlen} {tunits}" end = strt + pd.Timedelta(mlen, unit="d") tc["end"] = str(end) return tc diff --git a/dependencies/flopy/export/netcdf.py b/dependencies/flopy/export/netcdf.py index 1381b0f..d919e9a 100644 --- a/dependencies/flopy/export/netcdf.py +++ b/dependencies/flopy/export/netcdf.py @@ -76,18 +76,9 @@ def log(self, phrase): pass t = datetime.now() if phrase in self.items.keys(): - s = ( - str(t) - + " finished: " - + str(phrase) - + ", took: " - + str(t - self.items[phrase]) - + "\n" - ) + s = f"{t} finished: {phrase}, took: {t - self.items[phrase]}\n" if self.echo: - print( - s, - ) + print(s) if self.filename: self.f.write(s) self.items.pop(phrase) @@ -165,7 +156,7 @@ def __init__( prj=None, logger=None, forgive=False, - **kwargs + **kwargs, ): assert output_filename.lower().endswith(".nc") @@ -198,7 +189,7 @@ def __init__( # self.dimension_names = ('layer', 'ncpl') else: raise Exception( - "Grid type {} not supported.".format(self.model_grid.grid_type) + f"Grid type {self.model_grid.grid_type} not supported." ) self.shape = self.model_grid.shape @@ -207,21 +198,21 @@ def __init__( except: print( "python-dateutil is not installed\n" - + "try pip install python-dateutil" + "try pip install python-dateutil" ) return self.start_datetime = self._dt_str( dateutil.parser.parse(self.model_time.start_datetime) ) - self.logger.warn("start datetime:{0}".format(str(self.start_datetime))) + self.logger.warn(f"start datetime:{self.start_datetime!s}") proj4_str = self.model_grid.proj4 if proj4_str is None: proj4_str = "epsg:4326" self.log( "Warning: model has no coordinate reference system specified. " - "Using default proj4 string: {}".format(proj4_str) + f"Using default proj4 string: {proj4_str}" ) self.proj4_str = proj4_str self.grid_units = self.model_grid.units @@ -260,9 +251,7 @@ def __add__(self, other): ) else: raise Exception( - "NetCdf.__add__(): unrecognized other:{0}".format( - str(type(other)) - ) + f"NetCdf.__add__(): unrecognized other:{type(other)}" ) return new_net @@ -280,9 +269,7 @@ def __sub__(self, other): ) else: raise Exception( - "NetCdf.__sub__(): unrecognized other:{0}".format( - str(type(other)) - ) + f"NetCdf.__sub__(): unrecognized other:{type(other)}" ) return new_net @@ -300,9 +287,7 @@ def __mul__(self, other): ) else: raise Exception( - "NetCdf.__mul__(): unrecognized other:{0}".format( - str(type(other)) - ) + f"NetCdf.__mul__(): unrecognized other:{type(other)}" ) return new_net @@ -325,9 +310,7 @@ def __truediv__(self, other): ) else: raise Exception( - "NetCdf.__sub__(): unrecognized other:{0}".format( - str(type(other)) - ) + f"NetCdf.__sub__(): unrecognized other:{type(other)}" ) return new_net @@ -362,9 +345,7 @@ def append(self, other, suffix="_1"): vname_norm = self.normalize_name(vname) assert ( vname_norm in self.nc.variables.keys() - ), "dict var not in " "self.vars:{0}-->".format( - vname - ) + ",".join( + ), f"dict var not in self.vars:{vname}-->" + ",".join( self.nc.variables.keys() ) @@ -409,10 +390,10 @@ def zeros_like( for vname in other.var_attr_dict.keys(): if new_net.nc.variables.get(vname) is not None: new_net.logger.warn( - "variable {0} already defined, skipping".format(vname) + f"variable {vname} already defined, skipping" ) continue - new_net.log("adding variable {0}".format(vname)) + new_net.log(f"adding variable {vname}") var = other.nc.variables[vname] data = var[:] try: @@ -429,7 +410,7 @@ def zeros_like( dimensions=var.dimensions, ) new_var[:] = new_data - new_net.log("adding variable {0}".format(vname)) + new_net.log(f"adding variable {vname}") global_attrs = {} for attr in other.nc.ncattrs(): if attr not in new_net.nc.ncattrs(): @@ -447,14 +428,11 @@ def empty_like( ) while os.path.exists(output_filename): - print("{}...already exists".format(output_filename)) + print(f"{output_filename}...already exists") output_filename = ( str(time.mktime(datetime.now().timetuple())) + ".nc" ) - print( - "creating temporary netcdf file..." - + "{}".format(output_filename) - ) + print("creating temporary netcdf file..." + output_filename) new_net = cls( output_filename, @@ -500,20 +478,18 @@ def difference( """ - assert self.nc is not None, ( - "can't call difference() if nc " + "hasn't been populated" - ) + assert ( + self.nc is not None + ), "can't call difference() if nc hasn't been populated" try: import netCDF4 except Exception as e: - mess = "error import netCDF4: {0}".format(str(e)) + mess = f"error import netCDF4: {e!s}" self.logger.warn(mess) raise Exception(mess) if isinstance(other, str): - assert os.path.exists( - other - ), "filename 'other' not found:" + "{0}".format(other) + assert os.path.exists(other), f"filename 'other' not found:{other}" other = netCDF4.Dataset(other, "r") assert isinstance(other, netCDF4.Dataset) @@ -524,8 +500,7 @@ def difference( diff = self_vars.symmetric_difference(other_vars) if len(diff) > 0: self.logger.warn( - "variables are not the same between the two " - + "nc files: " + "variables are not the same between the two nc files: " + ",".join(diff) ) return @@ -535,12 +510,11 @@ def difference( other_dimens = other.dimensions for d in self_dimens.keys(): if d not in other_dimens: - self.logger.warn("missing dimension in other:{0}".format(d)) + self.logger.warn(f"missing dimension in other:{d}") return if len(self_dimens[d]) != len(other_dimens[d]): self.logger.warn( - "dimension not consistent: " - + "{0}:{1}".format(self_dimens[d], other_dimens[d]) + f"dimension not consistent: {self_dimens[d]}:{other_dimens[d]}" ) return # should be good to go @@ -556,9 +530,9 @@ def difference( vname not in self.var_attr_dict or new_net.nc.variables.get(vname) is not None ): - self.logger.warn("skipping variable: {0}".format(vname)) + self.logger.warn(f"skipping variable: {vname}") continue - self.log("processing variable {0}".format(vname)) + self.log(f"processing variable {vname}") s_var = self.nc.variables[vname] o_var = other.variables[vname] s_data = s_var[:] @@ -567,7 +541,7 @@ def difference( # keep the masks to apply later if isinstance(s_data, np.ma.MaskedArray): - self.logger.warn("masked array for {0}".format(vname)) + self.logger.warn(f"masked array for {vname}") s_mask = s_data.mask s_data = np.array(s_data) s_data[s_mask] = 0.0 @@ -587,21 +561,19 @@ def difference( elif minuend.lower() == "other": d_data = o_data - s_data else: - mess = "unrecognized minuend {0}".format(minuend) + mess = f"unrecognized minuend {minuend}" self.logger.warn(mess) raise Exception(mess) # check for non-zero diffs if onlydiff and d_data.sum() == 0.0: self.logger.warn( - "var {0} has zero differences, skipping...".format(vname) + f"var {vname} has zero differences, skipping..." ) continue self.logger.warn( - "resetting diff attrs max,min:{0},{1}".format( - d_data.min(), d_data.max() - ) + f"resetting diff attrs max,min:{d_data.min()},{d_data.max()}" ) attrs = self.var_attr_dict[vname].copy() attrs["max"] = np.nanmax(d_data) @@ -627,12 +599,13 @@ def difference( ) var[:] = d_data - self.log("processing variable {0}".format(vname)) + self.log(f"processing variable {vname}") def _dt_str(self, dt): """for datetime to string for year < 1900""" - dt_str = "{0:04d}-{1:02d}-{2:02d}T{3:02d}:{4:02d}:{5:02}Z".format( - dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second + dt_str = ( + f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d}T" + f"{dt.hour:02d}:{dt.minute:02d}:{dt.second:02}Z" ) return dt_str @@ -650,9 +623,7 @@ def write(self): if self.nc.attributes.get(k) is not None: self.nc.setncattr(k, v) except Exception: - self.logger.warn( - "error setting global attribute {0}".format(k) - ) + self.logger.warn(f"error setting global attribute {k}") self.nc.sync() self.nc.close() @@ -685,9 +656,7 @@ def _initialize_attributes(self): try: htol, rtol = self.model.solver_tols() except Exception as e: - self.logger.warn( - "unable to get solver tolerances:" + "{0}".format(str(e)) - ) + self.logger.warn(f"unable to get solver tolerances:{e!s}") self.global_attributes["solver_head_tolerance"] = htol self.global_attributes["solver_flux_tolerance"] = rtol spatial_attribs = { @@ -727,9 +696,9 @@ def initialize_geometry(self): pyproj220 = LooseVersion(pyproj.__version__) >= LooseVersion("2.2.0") proj4_str = self.proj4_str - print("initialize_geometry::proj4_str = {}".format(proj4_str)) + print(f"initialize_geometry::proj4_str = {proj4_str}") - self.log("building grid crs using proj4 string: {}".format(proj4_str)) + self.log(f"building grid crs using proj4 string: {proj4_str}") if pyproj220: self.grid_crs = pyproj.CRS(proj4_str) else: @@ -737,7 +706,7 @@ def initialize_geometry(self): proj4_str = "+init=" + proj4_str self.grid_crs = pyproj.Proj(proj4_str, preserve_units=True) - print("initialize_geometry::self.grid_crs = {}".format(self.grid_crs)) + print(f"initialize_geometry::self.grid_crs = {self.grid_crs}") vmin, vmax = self.model_grid.botm.min(), self.model_grid.top.max() if self.z_positive == "down": @@ -761,12 +730,10 @@ def initialize_geometry(self): nc_crs = pyproj.Proj(nc_epsg_str) self.transformer = None - print("initialize_geometry::nc_crs = {}".format(nc_crs)) + print(f"initialize_geometry::nc_crs = {nc_crs}") if pyproj220: - print( - "transforming coordinates using = {}".format(self.transformer) - ) + print(f"transforming coordinates using = {self.transformer}") self.log("projecting grid cell center arrays") if pyproj220: @@ -817,7 +784,7 @@ def initialize_file(self, time_values=None): try: self.nc = netCDF4.Dataset(self.output_filename, "w") except Exception as e: - msg = "error creating netcdf dataset:\n{}".format(str(e)) + msg = f"error creating netcdf dataset:\n{e!s}" raise Exception(msg) # write some attributes @@ -825,14 +792,12 @@ def initialize_file(self, time_values=None): self.nc.setncattr( "Conventions", - "CF-1.6, ACDD-1.3, flopy {}".format(flopy.__version__), + f"CF-1.6, ACDD-1.3, flopy {flopy.__version__}", ) self.nc.setncattr( "date_created", datetime.utcnow().strftime("%Y-%m-%dT%H:%M:00Z") ) - self.nc.setncattr( - "geospatial_vertical_positive", "{}".format(self.z_positive) - ) + self.nc.setncattr("geospatial_vertical_positive", str(self.z_positive)) min_vertical = np.min(self.zs) max_vertical = np.max(self.zs) self.nc.setncattr("geospatial_vertical_min", min_vertical) @@ -843,9 +808,7 @@ def initialize_file(self, time_values=None): try: self.nc.setncattr(k, v) except: - self.logger.warn( - "error setting global attribute {0}".format(k) - ) + self.logger.warn(f"error setting global attribute {k}") self.global_attributes = {} self.log("setting standard attributes") @@ -869,9 +832,7 @@ def initialize_file(self, time_values=None): self.log("setting CRS info") attribs = { - "units": "{} since {}".format( - self.time_units, self.start_datetime - ), + "units": f"{self.time_units} since {self.start_datetime}", "standard_name": "time", "long_name": NC_LONG_NAMES.get("time", "time"), "calendar": "gregorian", @@ -880,7 +841,7 @@ def initialize_file(self, time_values=None): time = self.create_variable( "time", attribs, precision_str="f8", dimensions=("time",) ) - self.logger.warn("time_values:{0}".format(str(time_values))) + self.logger.warn(f"time_values:{time_values!s}") time[:] = np.asarray(time_values) # Elevation @@ -968,7 +929,7 @@ def initialize_file(self, time_values=None): y[:] = self.model_grid.xyzcellcenters[1] # grid mapping variable - crs = flopy.utils.reference.crs( + crs = flopy.export.shapefile_utils.CRS( prj=self.model_grid.prj, epsg=self.model_grid.epsg ) attribs = crs.grid_mapping_attribs @@ -1004,8 +965,8 @@ def initialize_file(self, time_values=None): if self.model_grid.angrot != 0: delc.comments = ( "This is the row spacing that applied to the UNROTATED grid. " - + "This grid HAS been rotated before being saved to NetCDF. " - + "To compute the unrotated grid, use the origin point and this array." + "This grid HAS been rotated before being saved to NetCDF. " + "To compute the unrotated grid, use the origin point and this array." ) # delr @@ -1020,8 +981,8 @@ def initialize_file(self, time_values=None): if self.model_grid.angrot != 0: delr.comments = ( "This is the col spacing that applied to the UNROTATED grid. " - + "This grid HAS been rotated before being saved to NetCDF. " - + "To compute the unrotated grid, use the origin point and this array." + "This grid HAS been rotated before being saved to NetCDF. " + "To compute the unrotated grid, use the origin point and this array." ) # else: # vertices @@ -1079,13 +1040,13 @@ def initialize_group( self.initialize_file() if group in self.nc.groups: - raise AttributeError("{} group already initialized".format(group)) + raise AttributeError(f"{group} group already initialized") - self.log("creating netcdf group {}".format(group)) + self.log(f"creating netcdf group {group}") self.nc.createGroup(group) - self.log("{} group created".format(group)) + self.log(f"{group} group created") - self.log("creating {} group dimensions".format(group)) + self.log(f"creating {group} group dimensions") for dim in dimensions: if dim == "time": if "time" not in dimension_data: @@ -1098,8 +1059,7 @@ def initialize_group( else: if dim not in dimension_data: raise AssertionError( - "{} information must be supplied " - "to dimension data".format(dim) + f"{dim} information must be supplied to dimension data" ) else: @@ -1107,14 +1067,14 @@ def initialize_group( dim, len(dimension_data[dim]) ) - self.log("created {} group dimensions".format(group)) + self.log(f"created {group} group dimensions") dim_names = tuple([i for i in dimensions if i != "time"]) for dim in dimensions: if dim.lower() == "time": if "time" not in attributes: - unit_value = "{} since {}".format( - self.time_units, self.start_datetime + unit_value = ( + f"{self.time_units} since {self.start_datetime}" ) attribs = { "units": unit_value, @@ -1217,31 +1177,29 @@ def create_group_variable( if name in self.nc.groups[group].variables.keys(): if self.forgive: self.logger.warn( - "skipping duplicate {} group variable: {}".format( - group, name - ) + f"skipping duplicate {group} group variable: {name}" ) return else: raise Exception( - "duplicate {} group variable name: {}".format(group, name) + f"duplicate {group} group variable name: {name}" ) - self.log("creating group {} variable: {}".format(group, name)) + self.log(f"creating group {group} variable: {name}") if precision_str not in PRECISION_STRS: raise AssertionError( "netcdf.create_variable() error: precision " - "string {} not in {}".format(precision_str, PRECISION_STRS) + f"string {precision_str} not in {PRECISION_STRS}" ) if group not in self.nc.groups: raise AssertionError( - "netcdf group `{}` must be created before " - "variables can be added to it".format(group) + f"netcdf group `{group}` must be created before " + "variables can be added to it" ) - self.var_attr_dict["{}/{}".format(group, name)] = attributes + self.var_attr_dict[f"{group}/{name}"] = attributes var = self.nc.groups[group].createVariable( name, @@ -1256,10 +1214,9 @@ def create_group_variable( var.setncattr(k, v) except: self.logger.warn( - "error setting attribute" - + "{} for group {} variable {}".format(k, group, name) + f"error setting attribute{k} for group {group} variable {name}" ) - self.log("creating group {} variable: {}".format(group, name)) + self.log(f"creating group {group} variable: {name}") return var @@ -1311,14 +1268,12 @@ def create_variable( and name in self.nc.variables.keys() ): if self.forgive: - self.logger.warn( - "skipping duplicate variable: {0}".format(name) - ) + self.logger.warn(f"skipping duplicate variable: {name}") return else: - raise Exception("duplicate variable name: {0}".format(name)) + raise Exception(f"duplicate variable name: {name}") if name in self.nc.variables.keys(): - raise Exception("duplicate variable name: {0}".format(name)) + raise Exception(f"duplicate variable name: {name}") self.log("creating variable: " + str(name)) assert ( @@ -1357,8 +1312,7 @@ def create_variable( var.setncattr(k, v) except: self.logger.warn( - "error setting attribute" - + "{0} for variable {1}".format(k, name) + f"error setting attribute{k} for variable {name}" ) self.log("creating variable: " + str(name)) return var @@ -1384,7 +1338,7 @@ def add_global_attributes(self, attr_dict): # self.initialize_file() mess = ( "NetCDF.add_global_attributes() should only " - + "be called after the file has been initialized" + "be called after the file has been initialized" ) self.logger.warn(mess) raise Exception(mess) diff --git a/dependencies/flopy/export/shapefile_utils.py b/dependencies/flopy/export/shapefile_utils.py index ce5ca3b..fd9bf58 100755 --- a/dependencies/flopy/export/shapefile_utils.py +++ b/dependencies/flopy/export/shapefile_utils.py @@ -9,7 +9,6 @@ import numpy as np import os import warnings -from collections import OrderedDict from ..datbase import DataType, DataInterface from ..utils import Util3d @@ -144,7 +143,7 @@ def write_grid_shapefile( elif mg.grid_type == "unstructured": verts = [mg.get_cell_vertices(cellid) for cellid in range(mg.nnodes)] else: - raise Exception("Grid type {} not supported.".format(mg.grid_type)) + raise Exception(f"Grid type {mg.grid_type} not supported.") # set up the attribute fields and arrays of attributes if mg.grid_type == "structured": @@ -180,15 +179,35 @@ def write_grid_shapefile( names = enforce_10ch_limit(names) elif mg.grid_type == "unstructured": - names = ["node"] + list(array_dict.keys()) - dtypes = [("node", np.dtype("int"))] + [ - (enforce_10ch_limit([name])[0], array_dict[name].dtype) - for name in names[1:] - ] - node = list(range(1, mg.nnodes + 1)) - at = np.vstack( - [node] + [array_dict[name].ravel() for name in names[1:]] - ).transpose() + if mg.nlay is None: + names = ["node"] + list(array_dict.keys()) + dtypes = [("node", np.dtype("int"))] + [ + (enforce_10ch_limit([name])[0], array_dict[name].dtype) + for name in names[1:] + ] + node = list(range(1, mg.nnodes + 1)) + at = np.vstack( + [node] + [array_dict[name].ravel() for name in names[1:]] + ).transpose() + else: + names = ["node", "layer"] + list(array_dict.keys()) + dtypes = [ + ("node", np.dtype("int")), + ("layer", np.dtype("int")), + ] + [ + (enforce_10ch_limit([name])[0], array_dict[name].dtype) + for name in names[2:] + ] + node = list(range(1, mg.nnodes + 1)) + layer = np.zeros(mg.nnodes) + for ilay in range(mg.nlay): + istart, istop = mg.get_layer_node_range(ilay) + layer[istart:istop] = ilay + 1 + at = np.vstack( + [node] + + [layer] + + [array_dict[name].ravel() for name in names[2:]] + ).transpose() names = enforce_10ch_limit(names) @@ -213,7 +232,7 @@ def write_grid_shapefile( # close w.close() - print("wrote {}".format(filename)) + print(f"wrote {filename}") # write the projection file write_prj(filename, mg, epsg, prj) return @@ -275,11 +294,6 @@ def model_attributes_to_shapefile( else: grid = ml.modelgrid - if grid.grid_type == "USG-Unstructured": - raise Exception( - "Flopy does not support exporting to shapefile from " - "and MODFLOW-USG unstructured grid." - ) horz_shape = grid.get_plottable_layer_shape() for pname in package_names: pak = ml.get_package(pname) @@ -310,16 +324,22 @@ def model_attributes_to_shapefile( assert a.array is not None except: print( - "Failed to get data for {} array, {} package".format( - a.name, pak.name[0] - ) + "Failed to get data for " + f"{a.name} array, {pak.name[0]} package" ) continue if isinstance(a.name, list) and a.name[0] == "thickness": continue if a.array.shape == horz_shape: - array_dict[a.name] = a.array + if hasattr(a, "shape"): + if a.shape[1] is None: # usg unstructured Util3d + # return a flattened array, with a.name[0] (a per-layer list) + array_dict[a.name[0]] = a.array + else: + array_dict[a.name] = a.array + else: + array_dict[a.name] = a.array else: # array is not the same shape as the layer shape for ilay in range(a.array.shape[0]): @@ -337,7 +357,7 @@ def model_attributes_to_shapefile( # fix for mf6 case arr = arr[0] assert arr.shape == horz_shape - name = "{}_{}".format(aname, ilay + 1) + name = f"{aname}_{ilay + 1}" array_dict[name] = arr elif ( a.data_type == DataType.transient2d @@ -347,13 +367,12 @@ def model_attributes_to_shapefile( assert a.array is not None except: print( - "Failed to get data for {} array, {} package".format( - a.name, pak.name[0] - ) + "Failed to get data for " + f"{a.name} array, {pak.name[0]} package" ) continue for kper in range(a.array.shape[0]): - name = "{}{}".format(shape_attr_name(a.name), kper + 1) + name = f"{shape_attr_name(a.name)}{kper + 1}" arr = a.array[kper][0] assert arr.shape == horz_shape array_dict[name] = arr @@ -368,7 +387,7 @@ def model_attributes_to_shapefile( for kper in range(array.shape[0]): for k in range(array.shape[1]): n = shape_attr_name(name, length=4) - aname = "{}{}{}".format(n, k + 1, kper + 1) + aname = f"{n}{k + 1}{kper + 1}" arr = array[kper][k] assert arr.shape == horz_shape if np.all(np.isnan(arr)): @@ -382,9 +401,8 @@ def model_attributes_to_shapefile( ): for ilay in range(a.model.modelgrid.nlay): u2d = a[ilay] - name = "{}_{}".format( - shape_attr_name(u2d.name), - ilay + 1, + name = ( + f"{shape_attr_name(u2d.name)}_{ilay + 1}" ) arr = u2d.array assert arr.shape == horz_shape @@ -538,7 +556,7 @@ def recarray2shp( mg=None, epsg=None, prj=None, - **kwargs + **kwargs, ): """ Write a numpy record array to a shapefile, using a corresponding @@ -625,7 +643,7 @@ def recarray2shp( w.close() write_prj(shpname, mg, epsg, prj) - print("wrote {}".format(shpname)) + print(f"wrote {shpname}") return @@ -850,7 +868,7 @@ def _getvalue(self, k): def _getgcsparam(self, txt): nvalues = 3 if txt.lower() == "spheroid" else 2 - tmp = self._gettxt('{}["'.format(txt), "]") + tmp = self._gettxt(f'{txt}["', "]") if tmp is not None: tmp = tmp.replace('"', "").split(",") name = tmp[0:1] @@ -916,29 +934,30 @@ def get_spatialreference(epsg, text="esriwkt"): """ from flopy.utils.flopy_io import get_url_text - epsg_categories = ["epsg", "esri"] + epsg_categories = ( + "epsg", + "esri", + ) + urls = [] for cat in epsg_categories: - url = "{}/ref/".format(srefhttp) + "{}/{}/{}/".format( - cat, epsg, text - ) + url = f"{srefhttp}/ref/{cat}/{epsg}/{text}/" + urls.append(url) result = get_url_text(url) if result is not None: break if result is not None: return result.replace("\n", "") elif result is None and text != "epsg": - for cat in epsg_categories: - error_msg = ( - "No internet connection or " - + "epsg code {} ".format(epsg) - + "not found at {}/ref/".format(srefhttp) - + "{}/{}/{}".format(cat, epsg, text) - ) - print(error_msg) + error_msg = ( + f"No internet connection or epsg code {epsg} not found at:\n" + ) + for idx, url in enumerate(urls): + error_msg += f" {idx + 1:>2d}: {url}\n" + print(error_msg) # epsg code not listed on spatialreference.org # may still work with pyproj elif text == "epsg": - return "epsg:{}".format(epsg) + return f"epsg:{epsg}" @staticmethod def getproj4(epsg): @@ -987,10 +1006,10 @@ def to_dict(self): """ returns dict with EPSG code integer key, and WKT CRS text """ - data = OrderedDict() + data = {} if os.path.exists(self.location): with open(self.location, "r") as f: - loaded_data = json.load(f, object_pairs_hook=OrderedDict) + loaded_data = json.load(f) # convert JSON key from str to EPSG integer for key, value in loaded_data.items(): try: @@ -1007,10 +1026,10 @@ def _write(self, data): def reset(self, verbose=True): if os.path.exists(self.location): if verbose: - print("Resetting {}".format(self.location)) + print(f"Resetting {self.location}") os.remove(self.location) elif verbose: - print("{} does not exist, no reset required".format(self.location)) + print(f"{self.location} does not exist, no reset required") def add(self, epsg, prj): """ @@ -1041,4 +1060,4 @@ def show(): ep = EpsgReference() prj = ep.to_dict() for k, v in prj.items(): - print("{}:\n{}\n".format(k, v)) + print(f"{k}:\n{v}\n") diff --git a/dependencies/flopy/export/utils.py b/dependencies/flopy/export/utils.py index e3f5793..0ded8e0 100644 --- a/dependencies/flopy/export/utils.py +++ b/dependencies/flopy/export/utils.py @@ -1,4 +1,3 @@ -from __future__ import print_function import json import os import numpy as np @@ -26,9 +25,9 @@ } path = os.path.split(netcdf.__file__)[0] -with open(path + "/longnames.json") as f: +with open(f"{path}/longnames.json") as f: NC_LONG_NAMES = json.load(f) -with open(path + "/unitsformat.json") as f: +with open(f"{path}/unitsformat.json") as f: NC_UNITS_FORMAT = json.load(f) @@ -88,7 +87,7 @@ def ensemble_helper( outputs_filename, models[0], models[0].load_results(as_dict=True), - **kwargs + **kwargs, ) vdict = {} vdicts = [ @@ -96,7 +95,7 @@ def ensemble_helper( vdict, models[0], models[0].load_results(as_dict=True), - **kwargs + **kwargs, ) ] i = 1 @@ -150,7 +149,7 @@ def _add_output_nc_variable( mask_array3d=None, ): if logger: - logger.log("creating array for {0}".format(var_name)) + logger.log(f"creating array for {var_name}") array = np.zeros( (len(times), shape3d[0], shape3d[1], shape3d[2]), dtype=np.float32 @@ -204,7 +203,7 @@ def _add_output_nc_variable( continue if logger: - logger.log("creating array for {0}".format(var_name)) + logger.log(f"creating array for {var_name}") for mask_val in mask_vals: array[np.where(array == mask_val)] = np.NaN @@ -239,7 +238,7 @@ def _add_output_nc_variable( dimensions=dim_tuple, ) except Exception as e: - estr = "error creating variable {0}:\n{1}".format(var_name, str(e)) + estr = f"error creating variable {var_name}:\n{e!s}" if logger: logger.lraise(estr) else: @@ -248,9 +247,7 @@ def _add_output_nc_variable( try: var[:] = array except Exception as e: - estr = "error setting array to variable {0}:\n{1}".format( - var_name, str(e) - ) + estr = f"error setting array to variable {var_name}:\n{e!s}" if logger: logger.lraise(estr) else: @@ -275,16 +272,16 @@ def _add_output_nc_zonebudget_variable(f, array, var_name, flux, logger=None): """ if logger: - logger.log("creating array for {}".format(var_name)) + logger.log(f"creating array for {var_name}") mn = np.min(array) mx = np.max(array) precision_str = "f4" if flux: - units = "{}^3/{}".format(f.grid_units, f.time_units) + units = f"{f.grid_units}^3/{f.time_units}" else: - units = "{}^3".format(f.grid_units) + units = f"{f.grid_units}^3" attribs = {"long_name": var_name} attribs["coordinates"] = "time zone" attribs["min"] = mn @@ -340,7 +337,7 @@ def output_helper(f, ml, oudic, **kwargs): mask_vals = kwargs.pop("masked_vals") if len(kwargs) > 0 and logger is not None: str_args = ",".join(kwargs) - logger.warn("unused kwargs: " + str_args) + logger.warn(f"unused kwargs: {str_args}") zonebud = None zbkey = None @@ -356,9 +353,7 @@ def output_helper(f, ml, oudic, **kwargs): # that they will line up for key in oudic.keys(): out = oudic[key] - times = [ - float("{0:15.6f}".format(t)) for t in out.recordarray["totim"] - ] + times = [float(f"{t:15.6f}") for t in out.recordarray["totim"]] out.recordarray["totim"] = times times = [] @@ -394,18 +389,14 @@ def output_helper(f, ml, oudic, **kwargs): assert len(common_times) > 0 if len(skipped_times) > 0: + msg = ( + "the following output times are not common to all " + f"output files and are being skipped:\n{skipped_times}" + ) if logger: - logger.warn( - "the following output times are not common to all" - + " output files and are being skipped:\n" - + "{0}".format(skipped_times) - ) + logger.warn(msg) else: - print( - "the following output times are not common to all" - + " output files and are being skipped:\n" - + "{0}".format(skipped_times) - ) + print(msg) times = [t for t in common_times[::stride]] if isinstance(f, str) and f.lower().endswith(".nc"): f = NetCdf( @@ -480,7 +471,7 @@ def output_helper(f, ml, oudic, **kwargs): ) else: - estr = "unrecognized file extension:{0}".format(filename) + estr = f"unrecognized file extension:{filename}" if logger: logger.lraise(estr) else: @@ -539,7 +530,7 @@ def output_helper(f, ml, oudic, **kwargs): continue if mflay is not None and k != mflay: continue - name = attrib_name + "{}_{}".format(per, k) + name = f"{attrib_name}{per}_{k}" attrib_dict[name] = plotarray[per][k] elif isinstance(out_obj, CellBudgetFile): @@ -565,19 +556,18 @@ def output_helper(f, ml, oudic, **kwargs): continue if mflay is not None and k != mflay: continue - name = attrib_name + "{}_{}".format(per, k) + name = f"{attrib_name}{per}_{k}" attrib_dict[name] = plotarray[per][k] if attrib_dict: shapefile_utils.write_grid_shapefile(f, ml.modelgrid, attrib_dict) else: + msg = f"unrecognized export argument:{f}" if logger: - logger.lraise("unrecognized export argument:{0}".format(f)) + logger.lraise(msg) else: - raise NotImplementedError( - "unrecognized export argument" + ":{0}".format(f) - ) + raise NotImplementedError(msg) return f @@ -653,7 +643,7 @@ def model_export(f, ml, fmt=None, **kwargs): ) else: - raise NotImplementedError("unrecognized export argument:{0}".format(f)) + raise NotImplementedError(f"unrecognized export argument:{f}") return f @@ -706,9 +696,7 @@ def package_export(f, pak, fmt=None, **kwargs): try: f = array2d_export(f, a, **kwargs) except: - f.logger.warn( - "error adding {0} as variable".format(a.name) - ) + f.logger.warn(f"error adding {a.name} as variable") elif a.data_type == DataType.array3d: f = array3d_export(f, a, **kwargs) elif a.data_type == DataType.transient2d: @@ -747,7 +735,7 @@ def package_export(f, pak, fmt=None, **kwargs): ) else: - raise NotImplementedError("unrecognized export argument:{0}".format(f)) + raise NotImplementedError(f"unrecognized export argument:{f}") def generic_array_export( @@ -757,7 +745,7 @@ def generic_array_export( dimensions=("time", "layer", "y", "x"), precision_str="f4", units="unitless", - **kwargs + **kwargs, ): """ Method to export a generic array to NetCdf @@ -782,16 +770,15 @@ def generic_array_export( """ if isinstance(f, str) and f.lower().endswith(".nc"): assert "model" in kwargs.keys(), ( - "creating a new netCDF using " - "generic_array_helper requires a " + "creating a new netCDF using generic_array_helper requires a " "'model' kwarg" ) assert isinstance(kwargs["model"], BaseModel) f = NetCdf(f, kwargs.pop("model"), **kwargs) - assert array.ndim == len(dimensions), ( - "generic_array_helper() " + "array.ndim != dimensions" - ) + assert array.ndim == len( + dimensions + ), "generic_array_helper() array.ndim != dimensions" coords_dims = { "time": "time", "layer": "layer", @@ -813,7 +800,7 @@ def generic_array_export( attribs["min"] = mn attribs["max"] = mx if np.isnan(attribs["min"]) or np.isnan(attribs["max"]): - raise Exception("error processing {0}: all NaNs".format(var_name)) + raise Exception(f"error processing {var_name}: all NaNs") try: var = f.create_variable( var_name, @@ -822,15 +809,13 @@ def generic_array_export( dimensions=dimensions, ) except Exception as e: - estr = "error creating variable {0}:\n{1}".format(var_name, str(e)) + estr = f"error creating variable {var_name}:\n{e!s}" f.logger.warn(estr) raise Exception(estr) try: var[:] = array except Exception as e: - estr = "error setting array to variable {0}:\n{1}".format( - var_name, str(e) - ) + estr = f"error setting array to variable {var_name}:\n{e!s}" f.logger.warn(estr) raise Exception(estr) return f @@ -890,7 +875,7 @@ def mflist_export(f, mfl, **kwargs): for k in range(array.shape[0]): # aname = name+"{0:03d}_{1:02d}".format(kk, k) n = shapefile_utils.shape_attr_name(name, length=4) - aname = "{}{}{}".format(n, k + 1, int(kk) + 1) + aname = f"{n}{k + 1}{int(kk) + 1}" array_dict[aname] = array[k] shapefile_utils.write_grid_shapefile(f, modelgrid, array_dict) else: @@ -924,11 +909,11 @@ def mflist_export(f, mfl, **kwargs): # for name, array in m4d.items(): for name, array in mfl.masked_4D_arrays_itr(): - var_name = base_name + "_" + name + var_name = f"{base_name}_{name}" if isinstance(f, dict): f[var_name] = array continue - f.log("processing {0} attribute".format(name)) + f.log(f"processing {name} attribute") units = None if var_name in NC_UNITS_FORMAT: @@ -944,9 +929,7 @@ def mflist_export(f, mfl, **kwargs): attribs["min"] = np.nanmin(array) attribs["max"] = np.nanmax(array) if np.isnan(attribs["min"]) or np.isnan(attribs["max"]): - raise Exception( - "error processing {0}: all NaNs".format(var_name) - ) + raise Exception(f"error processing {var_name}: all NaNs") if units is not None: attribs["units"] = units @@ -959,9 +942,7 @@ def mflist_export(f, mfl, **kwargs): dimensions=dim_tuple, ) except Exception as e: - estr = "error creating variable {0}:\n{1}".format( - var_name, str(e) - ) + estr = f"error creating variable {var_name}:\n{e!s}" f.logger.warn(estr) raise Exception(estr) @@ -969,16 +950,14 @@ def mflist_export(f, mfl, **kwargs): try: var[:] = array except Exception as e: - estr = "error setting array to variable {0}:\n{1}".format( - var_name, str(e) - ) + estr = f"error setting array to variable {var_name}:\n{e!s}" f.logger.warn(estr) raise Exception(estr) - f.log("processing {0} attribute".format(name)) + f.log(f"processing {name} attribute") return f else: - raise NotImplementedError("unrecognized export argument:{0}".format(f)) + raise NotImplementedError(f"unrecognized export argument:{f}") def transient2d_export(f, t2d, fmt=None, **kwargs): @@ -1022,9 +1001,7 @@ def transient2d_export(f, t2d, fmt=None, **kwargs): array_dict = {} for kper in range(t2d.model.modeltime.nper): u2d = t2d[kper] - name = "{}_{}".format( - shapefile_utils.shape_attr_name(u2d.name), kper + 1 - ) + name = f"{shapefile_utils.shape_attr_name(u2d.name)}_{kper + 1}" array_dict[name] = u2d.array shapefile_utils.write_grid_shapefile(f, modelgrid, array_dict) @@ -1083,7 +1060,7 @@ def transient2d_export(f, t2d, fmt=None, **kwargs): attribs["min"] = mn attribs["max"] = mx if np.isnan(attribs["min"]) or np.isnan(attribs["max"]): - raise Exception("error processing {0}: all NaNs".format(var_name)) + raise Exception(f"error processing {var_name}: all NaNs") try: dim_tuple = ("time",) + f.dimension_names var = f.create_variable( @@ -1093,15 +1070,13 @@ def transient2d_export(f, t2d, fmt=None, **kwargs): dimensions=dim_tuple, ) except Exception as e: - estr = "error creating variable {0}:\n{1}".format(var_name, str(e)) + estr = f"error creating variable {var_name}:\n{e!s}" f.logger.warn(estr) raise Exception(estr) try: var[:, 0] = array except Exception as e: - estr = "error setting array to variable {0}:\n{1}".format( - var_name, str(e) - ) + estr = f"error setting array to variable {var_name}:\n{e!s}" f.logger.warn(estr) raise Exception(estr) return f @@ -1130,7 +1105,7 @@ def transient2d_export(f, t2d, fmt=None, **kwargs): kpers=kpers, ) else: - raise NotImplementedError("unrecognized export argument:{0}".format(f)) + raise NotImplementedError(f"unrecognized export argument:{f}") def array3d_export(f, u3d, fmt=None, **kwargs): @@ -1153,9 +1128,9 @@ def array3d_export(f, u3d, fmt=None, **kwargs): """ - assert isinstance(u3d, DataInterface), ( - "array3d_export only helps " "instances that support " "DataInterface" - ) + assert isinstance( + u3d, DataInterface + ), "array3d_export only helps instances that support DataInterface" min_valid = kwargs.get("min_valid", -1.0e9) max_valid = kwargs.get("max_valid", 1.0e9) @@ -1177,9 +1152,7 @@ def array3d_export(f, u3d, fmt=None, **kwargs): else: dname = u2d.name array = u2d.array - name = "{}_{}".format( - shapefile_utils.shape_attr_name(dname), ilay + 1 - ) + name = f"{shapefile_utils.shape_attr_name(dname)}_{ilay + 1}" array_dict[name] = array shapefile_utils.write_grid_shapefile(f, modelgrid, array_dict) @@ -1257,7 +1230,7 @@ def array3d_export(f, u3d, fmt=None, **kwargs): attribs["min"] = mn attribs["max"] = mx if np.isnan(attribs["min"]) or np.isnan(attribs["max"]): - raise Exception("error processing {0}: all NaNs".format(var_name)) + raise Exception(f"error processing {var_name}: all NaNs") try: var = f.create_variable( var_name, @@ -1266,15 +1239,13 @@ def array3d_export(f, u3d, fmt=None, **kwargs): dimensions=f.dimension_names, ) except Exception as e: - estr = "error creating variable {0}:\n{1}".format(var_name, str(e)) + estr = f"error creating variable {var_name}:\n{e!s}" f.logger.warn(estr) raise Exception(estr) try: var[:] = array except Exception as e: - estr = "error setting array to variable {0}:\n{1}".format( - var_name, str(e) - ) + estr = f"error setting array to variable {var_name}:\n{e!s}" f.logger.warn(estr) raise Exception(estr) return f @@ -1305,7 +1276,7 @@ def array3d_export(f, u3d, fmt=None, **kwargs): ) else: - raise NotImplementedError("unrecognized export argument:{0}".format(f)) + raise NotImplementedError(f"unrecognized export argument:{f}") def array2d_export(f, u2d, fmt=None, **kwargs): @@ -1327,9 +1298,9 @@ def array2d_export(f, u2d, fmt=None, **kwargs): if fmt is set to 'vtk', parameters of vtk.export_array """ - assert isinstance(u2d, DataInterface), ( - "util2d_helper only helps " "instances that support " "DataInterface" - ) + assert isinstance( + u2d, DataInterface + ), "util2d_helper only helps instances that support DataInterface" assert len(u2d.array.shape) == 2, "util2d_helper only supports 2D arrays" min_valid = kwargs.get("min_valid", -1.0e9) @@ -1402,7 +1373,7 @@ def array2d_export(f, u2d, fmt=None, **kwargs): attribs["min"] = mn attribs["max"] = mx if np.isnan(attribs["min"]) or np.isnan(attribs["max"]): - raise Exception("error processing {0}: all NaNs".format(var_name)) + raise Exception(f"error processing {var_name}: all NaNs") try: var = f.create_variable( var_name, @@ -1411,15 +1382,13 @@ def array2d_export(f, u2d, fmt=None, **kwargs): dimensions=f.dimension_names[1:], ) except Exception as e: - estr = "error creating variable {0}:\n{1}".format(var_name, str(e)) + estr = f"error creating variable {var_name}:\n{e!s}" f.logger.warn(estr) raise Exception(estr) try: var[:] = array except Exception as e: - estr = "error setting array to variable {0}:\n{1}".format( - var_name, str(e) - ) + estr = f"error setting array to variable {var_name}:\n{e!s}" f.logger.warn(estr) raise Exception(estr) return f @@ -1449,7 +1418,7 @@ def array2d_export(f, u2d, fmt=None, **kwargs): ) else: - raise NotImplementedError("unrecognized export argument:{0}".format(f)) + raise NotImplementedError(f"unrecognized export argument:{f}") def export_array( @@ -1530,18 +1499,18 @@ def export_array( ) # enforce .asc ending nrow, ncol = a.shape a[np.isnan(a)] = nodata - txt = "ncols {:d}\n".format(ncol) - txt += "nrows {:d}\n".format(nrow) - txt += "xllcorner {:f}\n".format(xoffset) - txt += "yllcorner {:f}\n".format(yoffset) - txt += "cellsize {}\n".format(cellsize) + txt = f"ncols {ncol}\n" + txt += f"nrows {nrow}\n" + txt += f"xllcorner {xoffset:f}\n" + txt += f"yllcorner {yoffset:f}\n" + txt += f"cellsize {cellsize}\n" # ensure that nodata fmt consistent w values - txt += "NODATA_value {}\n".format(fmt) % (nodata) + txt += f"NODATA_value {fmt}\n" % (nodata) with open(filename, "w") as output: output.write(txt) with open(filename, "ab") as output: np.savetxt(output, a, **kwargs) - print("wrote {}".format(filename)) + print(f"wrote {filename}") elif filename.lower().endswith(".tif"): if ( @@ -1582,7 +1551,7 @@ def export_array( elif a.dtype.name == "float32": dtype = rasterio.float32 else: - msg = 'ERROR: invalid dtype "{}"'.format(a.dtype.name) + msg = f'ERROR: invalid dtype "{a.dtype.name}"' raise TypeError(msg) meta = { @@ -1598,7 +1567,7 @@ def export_array( meta.update(kwargs) with rasterio.open(filename, "w", **meta) as dst: dst.write(a) - print("wrote {}".format(filename)) + print(f"wrote {filename}") elif filename.lower().endswith(".shp"): from ..export.shapefile_utils import write_grid_shapefile @@ -1624,7 +1593,7 @@ def export_contours( fieldname="level", epsg=None, prj=None, - **kwargs + **kwargs, ): """ Convert matplotlib contour plot object to shapefile. @@ -1761,7 +1730,7 @@ def export_contourf( pg = Polygon([(x, y) for x, y in zip(xa, ya)], interiors=interiors) geoms += [pg] - print("Writing {} polygons".format(len(level))) + print(f"Writing {len(level)} polygons") # Create recarray ra = np.array(level, dtype=[(fieldname, float)]).view(np.recarray) @@ -1780,7 +1749,7 @@ def export_array_contours( maxlevels=1000, epsg=None, prj=None, - **kwargs + **kwargs, ): """ Contour an array using matplotlib; write shapefile of contours. @@ -1823,9 +1792,7 @@ def export_array_contours( imin = np.nanmin(a) imax = np.nanmax(a) nlevels = np.round(np.abs(imax - imin) / interval, 2) - msg = "{:.0f} levels at interval of {} > maxlevels={}".format( - nlevels, interval, maxlevels - ) + msg = f"{nlevels:.0f} levels at interval of {interval} > maxlevels={maxlevels}" assert nlevels < maxlevels, msg levels = np.arange(imin, imax, interval) ax = plt.subplots()[-1] diff --git a/dependencies/flopy/export/vtk.py b/dependencies/flopy/export/vtk.py index 392adf2..898fcd5 100644 --- a/dependencies/flopy/export/vtk.py +++ b/dependencies/flopy/export/vtk.py @@ -1,4 +1,3 @@ -from __future__ import print_function, division import os import numpy as np from ..discretization import StructuredGrid @@ -84,7 +83,7 @@ def open_element(self, tag): self.write_string(">") indent = self.indent_level * self.indent_char self.indent_level += 1 - tag_string = "\n" + indent + "<%s" % tag + tag_string = f"\n{indent}<{tag}" self.write_string(tag_string) self.open_tag = True self.current.append(tag) @@ -98,7 +97,7 @@ def close_element(self, tag=None): self.write_string(">") self.open_tag = False indent = self.indent_level * self.indent_char - tag_string = "\n" + indent + "" % tag + tag_string = f"\n{indent}" self.write_string(tag_string) else: self.write_string("/>") @@ -109,7 +108,7 @@ def close_element(self, tag=None): def add_attributes(self, **kwargs): assert self.open_tag for key in kwargs: - st = ' %s="%s"' % (key, kwargs[key]) + st = f' {key}="{kwargs[key]}"' self.write_string(st) return self @@ -210,8 +209,7 @@ def write_array(self, array, actwcells=None, **kwargs): # https://gitlab.kitware.com/paraview/paraview/issues/19042 # this may be removed in the future if they fix the bug array_lay_flat[np.isnan(array_lay_flat)] = -1e9 - s = " ".join(["{}".format(val) for val in array_lay_flat]) - self.write_line(s) + self.write_line(" ".join(str(val) for val in array_lay_flat)) # close DataArray element self.close_element("DataArray") @@ -299,7 +297,7 @@ def write_array(self, array, actwcells=None, **kwargs): def _write_size(self, block_size): # size is a 64 bit unsigned integer - byte_order = self.byte_order + "Q" + byte_order = f"{self.byte_order}Q" block_size = struct.pack(byte_order, block_size) self.f.write(block_size) @@ -472,7 +470,7 @@ def __init__( self.nx = 0 else: raise ValueError( - "The option true2d was used but the model is " "not 2d." + "The option true2d was used but the model is not 2d." ) self.cell_type = 8 else: @@ -531,8 +529,7 @@ def _vtk_grid_type(self, vtk_grid_type="auto"): ] if not any(vtk_grid_type in s for s in allowable_types): raise ValueError( - '"' + vtk_grid_type + '" is not a correct ' - "vtk_grid_type." + f'"{vtk_grid_type}" is not a correct vtk_grid_type.' ) if ( vtk_grid_type == "ImageData" @@ -733,7 +730,7 @@ def write(self, output_file, timeval=None): # output file output_file = output_file + self.file_extension if self.verbose: - print("Writing vtk file: " + output_file) + print(f"Writing vtk file: {output_file}") # initialize xml file if self.binary: @@ -779,9 +776,7 @@ def write(self, output_file, timeval=None): npoints = ncells * 8 if self.verbose: print( - "Number of point is {}, Number of cells is {}\n".format( - npoints, ncells - ) + f"Number of point is {npoints}, Number of cells is {ncells}\n" ) # piece @@ -821,35 +816,17 @@ def write(self, output_file, timeval=None): elif self.vtk_grid_type == "ImageData": # note: in vtk, "extent" actually means indices of grid lines - vtk_extent_str = ( - "0" - + " " - + str(self.nx) - + " " - + "0" - + " " - + str(self.ny) - + " " - + "0" - + " " - + str(self.nz) - ) + vtk_extent_str = f"0 {self.nx} 0 {self.ny} 0 {self.nz}" xml.add_attributes(WholeExtent=vtk_extent_str) grid_extent = self.modelgrid.xyzextent vtk_origin_str = ( - str(grid_extent[0]) - + " " - + str(grid_extent[2]) - + " " - + str(grid_extent[4]) + f"{grid_extent[0]} {grid_extent[2]} {grid_extent[4]}" ) xml.add_attributes(Origin=vtk_origin_str) - vtk_spacing_str = ( - str(self.modelgrid.delr[0]) - + " " - + str(self.modelgrid.delc[0]) - + " " - + str(self.modelgrid.top[0, 0] - self.modelgrid.botm[0, 0, 0]) + vtk_spacing_str = "{} {} {}".format( + self.modelgrid.delr[0], + self.modelgrid.delc[0], + self.modelgrid.top[0, 0] - self.modelgrid.botm[0, 0, 0], ) xml.add_attributes(Spacing=vtk_spacing_str) @@ -858,19 +835,7 @@ def write(self, output_file, timeval=None): elif self.vtk_grid_type == "RectilinearGrid": # note: in vtk, "extent" actually means indices of grid lines - vtk_extent_str = ( - "0" - + " " - + str(self.nx) - + " " - + "0" - + " " - + str(self.ny) - + " " - + "0" - + " " - + str(self.nz) - ) + vtk_extent_str = f"0 {self.nx} 0 {self.ny} 0 {self.nz}" xml.add_attributes(WholeExtent=vtk_extent_str) # piece @@ -1360,7 +1325,7 @@ def export_cbc( os.mkdir(otfolder) # set up the pvd file to make the output files time enabled - pvdfilename = model.name + "_CBC.pvd" + pvdfilename = f"{model.name}_CBC.pvd" pvdfile = open(os.path.join(otfolder, pvdfilename), "w") pvdfile.write( @@ -1403,7 +1368,7 @@ def export_cbc( kstpkper[0], tuple ): raise Exception( - "kstpkper must be a tuple (kstp, kper) or a list " "of tuples" + "kstpkper must be a tuple (kstp, kper) or a list of tuples" ) else: kstpkper = cbb.get_kstpkper() @@ -1425,15 +1390,14 @@ def export_cbc( addarray = False count = 1 for kstpkper_i in kstpkper: - ot_base = "{}_CBC_KPER{}_KSTP{}".format( - model_name, kstpkper_i[1] + 1, kstpkper_i[0] + 1 + ot_base = ( + f"{model_name}_CBC_KPER{kstpkper_i[1] + 1}_KSTP{kstpkper_i[0] + 1}" ) otfile = os.path.join(otfolder, ot_base) pvdfile.write( - """\n""".format( - count, ot_base - ) + f""" +""" ) for name in keylist: @@ -1459,7 +1423,7 @@ def export_cbc( addarray = True else: raise Exception( - "Data type not currently supported " "for cbc output" + "Data type not currently supported for cbc output" ) # print('Data type not currently supported ' # 'for cbc output') @@ -1551,7 +1515,7 @@ def export_heads( os.mkdir(otfolder) # start writing the pvd file to make the data time aware - pvdfilename = model.name + "_" + text + ".pvd" + pvdfilename = f"{model.name}_{text}.pvd" pvdfile = open(os.path.join(otfolder, pvdfilename), "w") pvdfile.write( @@ -1573,7 +1537,7 @@ def export_heads( kstpkper[0], tuple ): raise Exception( - "kstpkper must be a tuple (kstp, kper) or a list " "of tuples" + "kstpkper must be a tuple (kstp, kper) or a list of tuples" ) else: kstpkper = hds.get_kstpkper() @@ -1594,17 +1558,17 @@ def export_heads( for kstpkper_i in kstpkper: hdarr = hds.get_data(kstpkper_i) vtk.add_array(text, hdarr) - ot_base = ("{}_" + text + "_KPER{}_KSTP{}").format( - model.name, kstpkper_i[1] + 1, kstpkper_i[0] + 1 + ot_base = ( + f"{model.name}_{text}_" + f"KPER{kstpkper_i[1] + 1}_KSTP{kstpkper_i[0] + 1}" ) otfile = os.path.join(otfolder, ot_base) # vtk.write(otfile, timeval=totim_dict[(kstp, kper)]) vtk.write(otfile) pvdfile.write( - """\n""".format( - count, ot_base - ) + f""" +""" ) count += 1 @@ -1682,7 +1646,7 @@ def export_array( binary=binary, ) vtk.add_array(name, array, array2d=array2d) - otfile = os.path.join(output_folder, "{}".format(name)) + otfile = os.path.join(output_folder, name) vtk.write(otfile) return @@ -1756,7 +1720,7 @@ def export_vector( binary=binary, ) vtk.add_vector(name, vector, array2d=array2d) - otfile = os.path.join(output_folder, "{}".format(name)) + otfile = os.path.join(output_folder, name) vtk.write(otfile) return @@ -1854,16 +1818,16 @@ def export_transient( vtk.add_array(name, t2d_array_input, array2d=True) - otname = "{}".format(name) + separator + "0{}".format(kper + 1) - otfile = os.path.join(output_folder, "{}".format(otname)) + otname = f"{name}{separator}0{kper + 1}" + otfile = os.path.join(output_folder, otname) vtk.write(otfile, timeval=to_tim[kper]) else: for kper in kpers: vtk.add_array(name, array[kper]) - otname = "{}".format(name) + separator + "0{}".format(kper + 1) - otfile = os.path.join(output_folder, "{}".format(otname)) + otname = f"{name}{separator}0{kper + 1}" + otfile = os.path.join(output_folder, otname) vtk.write(otfile, timeval=to_tim[kper]) return @@ -2031,7 +1995,7 @@ def export_package( else: raise Exception( - "Data type not understond in data " "list" + "Data type not understond in data list" ) elif value.data_type == DataType.transient3d: @@ -2058,7 +2022,7 @@ def export_package( # write out data # write array data if len(vtk.arrays) > 0: - otfile = os.path.join(otfolder, "{}".format(pak_name)) + otfile = os.path.join(otfolder, pak_name) vtk.write(otfile) # write transient data @@ -2079,9 +2043,7 @@ def export_package( # else: # time = None # set up output file - otfile = os.path.join( - otfolder, "{}_0{}".format(pak_name, kper + 1) - ) + otfile = os.path.join(otfolder, f"{pak_name}_0{kper + 1}") for name, array in sorted(array_dict.items()): if array.array2d: array_shape = array.array.shape diff --git a/dependencies/flopy/mbase.py b/dependencies/flopy/mbase.py index d5b711d..7f053a8 100644 --- a/dependencies/flopy/mbase.py +++ b/dependencies/flopy/mbase.py @@ -4,10 +4,7 @@ all of the other models inherit from. """ - -from __future__ import print_function import abc -import sys import os import shutil import threading @@ -21,7 +18,6 @@ import numpy as np from flopy import utils, discretization from .version import __version__ -from .discretization.modeltime import ModelTime from .discretization.grid import Grid ## Global variables @@ -269,8 +265,7 @@ def _check(self, chk, level=1): chk.summary_array, r.summary_array ).view(np.recarray) chk.passed += [ - "{} package: {}".format(r.package.name[0], psd) - for psd in r.passed + f"{r.package.name[0]} package: {psd}" for psd in r.passed ] chk.summarize() return chk @@ -314,7 +309,7 @@ def __init__( model_ws=None, structured=True, verbose=False, - **kwargs + **kwargs, ): """Initialize BaseModel.""" super().__init__() @@ -334,9 +329,8 @@ def __init__( os.makedirs(model_ws) except: print( - "\n{0:s} not valid, workspace-folder was changed to {1:s}\n".format( - model_ws, os.getcwd() - ) + f"\n{model_ws} not valid, " + f"workspace-folder was changed to {os.getcwd()}\n" ) model_ws = os.getcwd() self._model_ws = model_ws @@ -350,11 +344,6 @@ def __init__( yll = kwargs.pop("yll", None) self._xul = kwargs.pop("xul", None) self._yul = kwargs.pop("yul", None) - if self._xul is not None or self._yul is not None: - warnings.warn( - "xul/yul have been deprecated. Use xll/yll instead.", - DeprecationWarning, - ) self._rotation = kwargs.pop("rotation", 0.0) self._proj4_str = kwargs.pop("proj4_str", None) @@ -362,7 +351,10 @@ def __init__( # build model discretization objects self._modelgrid = Grid( - proj4=self._proj4_str, xoff=xll, yoff=yll, angrot=self._rotation + proj4=self._proj4_str, + xoff=xll, + yoff=yll, + angrot=self._rotation, ) self._modeltime = None @@ -391,13 +383,13 @@ def __init__( @property def modeltime(self): raise NotImplementedError( - "must define modeltime in child " "class to use this base class" + "must define modeltime in child class to use this base class" ) @property def modelgrid(self): raise NotImplementedError( - "must define modelgrid in child " "class to use this base class" + "must define modelgrid in child class to use this base class" ) @property @@ -572,12 +564,9 @@ def add_package(self, p): except: pn = p.name if self.verbose: - msg = ( - "\nWARNING:\n unit {} ".format(u) - + "of package {} ".format(pn) - + "already in use." + print( + f"\nWARNING:\n unit {u} of package {pn} already in use." ) - print(msg) self.package_units.append(u) for i, pp in enumerate(self.packagelist): if pp.allowDuplicates: @@ -586,8 +575,7 @@ def add_package(self, p): if self.verbose: print( "\nWARNING:\n Two packages of the same type, " - + "Replacing existing " - + "'{}' package.".format(p.name[0]) + f"Replacing existing '{p.name[0]}' package." ) self.packagelist[i] = p return @@ -649,16 +637,12 @@ def __getattr__(self, item): if item == "output_packages" or not hasattr(self, "output_packages"): raise AttributeError(item) - if item == "sr": - if self.dis is not None: - return self.dis.sr - else: - return None if item == "tr": if self.dis is not None: return self.dis.tr else: return None + if item == "start_datetime": if self.dis is not None: return self.dis.start_datetime @@ -702,12 +686,10 @@ def _output_msg(self, i, add=True): else: txt1 = "Removing" txt2 = "from" - msg = ( - "{} {} ".format(txt1, self.output_fnames[i]) - + "(unit={}) ".format(self.output_units[i]) - + "{} the output list.".format(txt2) + print( + f"{txt1} {self.output_fnames[i]} (unit={self.output_units[i]}) " + f"{txt2} the output list." ) - print(msg) def add_output_file( self, unit, fname=None, extension="cbc", binflag=True, package=None @@ -757,7 +739,7 @@ def add_output_file( if add_cbc: if fname is None: - fname = self.name + "." + extension + fname = f"{self.name}.{extension}" # check if this file name exists for a different unit number if fname in self.output_fnames: idx = self.output_fnames.index(fname) @@ -766,12 +748,10 @@ def add_output_file( # include unit number in fname if package has # not been passed if package is None: - fname = self.name + ".{}.".format(unit) + extension + fname = f"{self.name}.{unit}.{extension}" # include package name in fname else: - fname = ( - self.name + ".{}.".format(package) + extension - ) + fname = f"{self.name}.{package}.{extension}" else: fname = os.path.basename(fname) self.add_output(fname, unit, binflag=binflag, package=package) @@ -795,11 +775,10 @@ def add_output(self, fname, unit, binflag=False, package=None): """ if fname in self.output_fnames: if self.verbose: - msg = ( + print( "BaseModel.add_output() warning: " - + "replacing existing filename {}".format(fname) + f"replacing existing filename {fname}" ) - print(msg) idx = self.output_fnames.index(fname) if self.verbose: self._output_msg(idx, add=False) @@ -914,7 +893,7 @@ def set_output_attribute(self, fname=None, unit=None, attr=None): else: msg = ( " either fname or unit must be passed " - + " to set_output_attribute()" + "to set_output_attribute()" ) raise Exception(msg) if attr is not None: @@ -956,7 +935,7 @@ def get_output_attribute(self, fname=None, unit=None, attr=None): else: raise Exception( " either fname or unit must be passed " - + " to set_output_attribute()" + "to set_output_attribute()" ) v = None if attr is not None: @@ -987,11 +966,10 @@ def add_external(self, fname, unit, binflag=False, output=False): """ if fname in self.external_fnames: if self.verbose: - msg = ( + print( "BaseModel.add_external() warning: " - + "replacing existing filename {}".format(fname) + f"replacing existing filename {fname}" ) - print(msg) idx = self.external_fnames.index(fname) self.external_fnames.pop(idx) self.external_units.pop(idx) @@ -999,10 +977,7 @@ def add_external(self, fname, unit, binflag=False, output=False): self.external_output.pop(idx) if unit in self.external_units: if self.verbose: - msg = ( - "BaseModel.add_external() warning: " - + "replacing existing unit {}".format(unit) - ) + msg = f"BaseModel.add_external() warning: replacing existing unit {unit}" print(msg) idx = self.external_units.index(unit) self.external_fnames.pop(idx) @@ -1113,11 +1088,7 @@ def get_name_file_entries(self): for i in range(len(p.name)): if p.unit_number[i] == 0: continue - s = ( - "{:14s} ".format(p.name[i]) - + "{:5d} ".format(p.unit_number[i]) - + "{}".format(p.file_name[i]) - ) + s = f"{p.name[i]:14s} {p.unit_number[i]:5d} {p.file_name[i]}" if p.extra[i]: s += " " + p.extra[i] lines.append(s) @@ -1176,32 +1147,24 @@ def set_version(self, version): # check that this is a valid model version if self.version not in list(self.version_types.keys()): err = ( - "Error: Unsupported model " - + "version ({}).".format(self.version) - + " Valid model versions are:" + f"Error: Unsupported model version ({self.version}). " + "Valid model versions are:" ) for v in list(self.version_types.keys()): - err += " {}".format(v) + err += f" {v}" raise Exception(err) # set namefile heading - heading = ( - "# Name file for " - + "{}, ".format(self.version_types[self.version]) - + "generated by Flopy version {}.".format(__version__) + self.heading = ( + f"# Name file for {self.version_types[self.version]}, " + f"generated by Flopy version {__version__}." ) - self.heading = heading # set heading for each package for p in self.get_package_list(): pak = self.get_package(p) - heading = ( - "# {} package for ".format(pak.name[0]) - + "{}, ".format(self.version_types[self.version]) - + "generated by Flopy version {}.".format(__version__) - ) - - pak.heading = heading + if hasattr(pak, "heading"): + pak._generate_heading() return None @@ -1227,14 +1190,10 @@ def change_model_ws(self, new_pth=None, reset_external=False): new_pth = os.getcwd() if not os.path.exists(new_pth): try: - line = "\ncreating model workspace...\n" + " {}".format( - new_pth - ) - print(line) + print(f"\ncreating model workspace...\n {new_pth}") os.makedirs(new_pth) except: - line = "\n{} not valid, workspace-folder ".format(new_pth) - raise OSError(line) + raise OSError(f"{new_pth} not valid, workspace-folder") # line = '\n{} not valid, workspace-folder '.format(new_pth) + \ # 'was changed to {}\n'.format(os.getcwd()) # print(line) @@ -1243,8 +1202,8 @@ def change_model_ws(self, new_pth=None, reset_external=False): # --reset the model workspace old_pth = self._model_ws self._model_ws = new_pth - line = "\nchanging model workspace...\n {}\n".format(new_pth) - sys.stdout.write(line) + if self.verbose: + print(f"\nchanging model workspace...\n {new_pth}") # reset the paths for each package for pp in self.packagelist: pp.fn_path = os.path.join(self.model_ws, pp.file_name[0]) @@ -1329,7 +1288,7 @@ def __setattr__(self, key, value): self.dis.sr = value else: raise Exception( - "cannot set SpatialReference -" "ModflowDis not found" + "cannot set SpatialReference - ModflowDis not found" ) elif key == "tr": assert isinstance( @@ -1339,7 +1298,7 @@ def __setattr__(self, key, value): self.dis.tr = value else: raise Exception( - "cannot set TemporalReference -" "ModflowDis not found" + "cannot set TemporalReference - ModflowDis not found" ) elif key == "start_datetime": if self.dis is not None: @@ -1347,7 +1306,7 @@ def __setattr__(self, key, value): self.tr.start_datetime = value else: raise Exception( - "cannot set start_datetime -" "ModflowDis not found" + "cannot set start_datetime - ModflowDis not found" ) else: super().__setattr__(key, value) @@ -1410,9 +1369,7 @@ def write_input(self, SelPackList=False, check=False): """ if check: # run check prior to writing input - self.check( - f="{}.chk".format(self.name), verbose=self.verbose, level=1 - ) + self.check(f=f"{self.name}.chk", verbose=self.verbose, level=1) # reset the model to free_format if parameter substitution was # performed on a model load @@ -1420,7 +1377,7 @@ def write_input(self, SelPackList=False, check=False): if self.verbose: print( "\nResetting free_format_input to True to " - + "preserve the precision of the parameter data." + "preserve the precision of the parameter data." ) self.free_format_input = True @@ -1719,24 +1676,20 @@ def run_model( if not exe_name.lower().endswith(".exe"): exe = which(exe_name + ".exe") if exe is None: - s = "The program {} does not exist or is not executable.".format( - exe_name + raise Exception( + f"The program {exe_name} does not exist or is not executable." ) - raise Exception(s) else: if not silent: - s = ( - "FloPy is using the following " - + " executable to run the model: {}".format(exe) + print( + f"FloPy is using the following executable to run the model: {exe}" ) - print(s) if namefile is not None: if not os.path.isfile(os.path.join(model_ws, namefile)): - s = "The namefile for this model " + "does not exists: {}".format( - namefile + raise Exception( + f"The namefile for this model does not exists: {namefile}" ) - raise Exception(s) # simple little function for the thread to target def q_output(output, q): @@ -1801,7 +1754,7 @@ def q_output(output, q): now = datetime.now() dt = now - last tsecs = dt.total_seconds() - lastsec - line = "(elapsed:{0})-->{1}".format(tsecs, line) + line = f"(elapsed:{tsecs})-->{line}" lastsec = tsecs + lastsec buff.append(line) if not silent: diff --git a/dependencies/flopy/mf6/coordinates/modeldimensions.py b/dependencies/flopy/mf6/coordinates/modeldimensions.py index ae88e1c..ccda417 100644 --- a/dependencies/flopy/mf6/coordinates/modeldimensions.py +++ b/dependencies/flopy/mf6/coordinates/modeldimensions.py @@ -410,7 +410,7 @@ def get_data_shape( ): if structure is None: raise FlopyException( - "get_data_shape requires a valid structure " "object" + "get_data_shape requires a valid structure object" ) if self.locked: if data_item is not None and data_item.path in self.stored_shapes: diff --git a/dependencies/flopy/mf6/coordinates/modelgrid.py b/dependencies/flopy/mf6/coordinates/modelgrid.py index f3d2e1c..21e0e89 100644 --- a/dependencies/flopy/mf6/coordinates/modelgrid.py +++ b/dependencies/flopy/mf6/coordinates/modelgrid.py @@ -8,9 +8,6 @@ class MFGridException(Exception): Model grid related exception """ - def __init__(self, error): - Exception.__init__(self, "MFGridException: {}".format(error)) - class ModelCell: """ @@ -433,28 +430,28 @@ def get_grid_type(simulation_data, model_name): structure = MFStructure() if ( package_recarray.search_data( - "dis{}".format(structure.get_version_string()), 0 + f"dis{structure.get_version_string()}", 0 ) is not None ): return DiscretizationType.DIS elif ( package_recarray.search_data( - "disv{}".format(structure.get_version_string()), 0 + f"disv{structure.get_version_string()}", 0 ) is not None ): return DiscretizationType.DISV elif ( package_recarray.search_data( - "disu{}".format(structure.get_version_string()), 0 + f"disu{structure.get_version_string()}", 0 ) is not None ): return DiscretizationType.DISU elif ( package_recarray.search_data( - "disl{}".format(structure.get_version_string()), 0 + f"disl{structure.get_version_string()}", 0 ) is not None ): diff --git a/dependencies/flopy/mf6/coordinates/simulationtime.py b/dependencies/flopy/mf6/coordinates/simulationtime.py index e54f7a0..df58080 100644 --- a/dependencies/flopy/mf6/coordinates/simulationtime.py +++ b/dependencies/flopy/mf6/coordinates/simulationtime.py @@ -129,8 +129,7 @@ def get_sp_time_steps(self, sp_num): ].get_data() if len(period_data) <= sp_num: raise FlopyException( - "Stress period {} was requested but does not " - "exist.".format(sp_num) + f"Stress period {sp_num} was requested but does not exist." ) return period_data[sp_num][1] diff --git a/dependencies/flopy/mf6/data/dfn/gwf-api.dfn b/dependencies/flopy/mf6/data/dfn/gwf-api.dfn new file mode 100644 index 0000000..7f86a4f --- /dev/null +++ b/dependencies/flopy/mf6/data/dfn/gwf-api.dfn @@ -0,0 +1,96 @@ +# --------------------- gwf api options --------------------- + +block options +name boundnames +type keyword +shape +reader urword +optional true +longname +description REPLACE boundnames {'{#1}': 'api boundary'} + +block options +name print_input +type keyword +reader urword +optional true +longname print input to listing file +description REPLACE print_input {'{#1}': 'api boundary'} + +block options +name print_flows +type keyword +reader urword +optional true +longname print calculated flows to listing file +description REPLACE print_flows {'{#1}': 'api boundary'} + +block options +name save_flows +type keyword +reader urword +optional true +longname save api flows to budget file +description REPLACE save_flows {'{#1}': 'api boundary'} + +block options +name obs_filerecord +type record obs6 filein obs6_filename +shape +reader urword +tagged true +optional true +longname +description + +block options +name obs6 +type keyword +shape +in_record true +reader urword +tagged true +optional false +longname obs keyword +description keyword to specify that record corresponds to an observations file. + +block options +name filein +type keyword +shape +in_record true +reader urword +tagged true +optional false +longname file keyword +description keyword to specify that an input filename is expected next. + +block options +name obs6_filename +type string +preserve_case true +in_record true +tagged false +reader urword +optional false +longname obs6 input filename +description REPLACE obs6_filename {'{#1}': 'api boundary'} + +block options +name mover +type keyword +tagged true +reader urword +optional true +longname +description REPLACE mover {'{#1}': 'api boundary'} + +# --------------------- gwf api dimensions --------------------- + +block dimensions +name maxbound +type integer +reader urword +optional false +longname maximum number of user-defined api boundaries +description REPLACE maxbound {'{#1}': 'api boundary'} diff --git a/dependencies/flopy/mf6/data/dfn/gwf-buy.dfn b/dependencies/flopy/mf6/data/dfn/gwf-buy.dfn index 13540b7..8412b3a 100644 --- a/dependencies/flopy/mf6/data/dfn/gwf-buy.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwf-buy.dfn @@ -131,7 +131,7 @@ tagged false shape reader urword longname modelname -description name of GWT model used to simulate a species that will be used in the density equation of state. This name will have no affect if the simulation does not include a GWT model that corresponds to this GWF model. +description name of GWT model used to simulate a species that will be used in the density equation of state. This name will have no effect if the simulation does not include a GWT model that corresponds to this GWF model. block packagedata name auxspeciesname diff --git a/dependencies/flopy/mf6/data/dfn/gwf-disu.dfn b/dependencies/flopy/mf6/data/dfn/gwf-disu.dfn index f17083e..e3590bf 100644 --- a/dependencies/flopy/mf6/data/dfn/gwf-disu.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwf-disu.dfn @@ -40,6 +40,15 @@ optional true longname rotation angle description counter-clockwise rotation angle (in degrees) of the model grid coordinate system relative to a real-world coordinate system. If not specified, then a default value of 0.0 is assigned. The value for ANGROT does not affect the model simulation, but it is written to the binary grid file so that postprocessors can locate the grid in space. +block options +name vertical_offset_tolerance +type double precision +reader urword +optional true +default_value 0.0 +longname vertical length dimension for top and bottom checking +description checks are performed to ensure that the top of a cell is not higher than the bottom of an overlying cell. This option can be used to specify the tolerance that is used for checking. If top of a cell is above the bottom of an overlying cell by a value less than this tolerance, then the program will not terminate with an error. The default value is zero. This option should generally not be used. + # --------------------- gwf disu dimensions --------------------- block dimensions diff --git a/dependencies/flopy/mf6/data/dfn/gwf-sfr.dfn b/dependencies/flopy/mf6/data/dfn/gwf-sfr.dfn index 7e54b94..be78661 100644 --- a/dependencies/flopy/mf6/data/dfn/gwf-sfr.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwf-sfr.dfn @@ -529,7 +529,7 @@ tagged false in_record true reader urword longname iprior code -description character string value that defines the the prioritization system for the diversion, such as when insufficient water is available to meet all diversion stipulations, and is used in conjunction with the value of FLOW value specified in the STRESS\_PERIOD\_DATA section. Available diversion options include: (1) CPRIOR = `FRACTION', then the amount of the diversion is computed as a fraction of the streamflow leaving reach RNO ($Q_{DS}$); in this case, 0.0 $\le$ DIVFLOW $\le$ 1.0. (2) CPRIOR = `EXCESS', a diversion is made only if $Q_{DS}$ for reach RNO exceeds the value of DIVFLOW. If this occurs, then the quantity of water diverted is the excess flow ($Q_{DS} -$ DIVFLOW) and $Q_{DS}$ from reach RNO is set equal to DIVFLOW. This represents a flood-control type of diversion, as described by Danskin and Hanson (2002). (3) CPRIOR = `THRESHOLD', then if $Q_{DS}$ in reach RNO is less than the specified diversion flow (DIVFLOW), no water is diverted from reach RNO. If $Q_{DS}$ in reach RNO is greater than or equal to (DIVFLOW), (DIVFLOW) is diverted and $Q_{DS}$ is set to the remainder ($Q_{DS} -$ DIVFLOW)). This approach assumes that once flow in the stream is sufficiently low, diversions from the stream cease, and is the `priority' algorithm that originally was programmed into the STR1 Package (Prudic, 1989). (4) CPRIOR = `UPTO' -- if $Q_{DS}$ in reach RNO is greater than or equal to the specified diversion flow (DIVFLOW), $Q_{DS}$ is reduced by DIVFLOW. If $Q_{DS}$ in reach RNO is less than (DIVFLOW), DIVFLOW is set to $Q_{DS}$ and there will be no flow available for reaches connected to downstream end of reach RNO. +description character string value that defines the the prioritization system for the diversion, such as when insufficient water is available to meet all diversion stipulations, and is used in conjunction with the value of FLOW value specified in the STRESS\_PERIOD\_DATA section. Available diversion options include: (1) CPRIOR = `FRACTION', then the amount of the diversion is computed as a fraction of the streamflow leaving reach RNO ($Q_{DS}$); in this case, 0.0 $\le$ DIVFLOW $\le$ 1.0. (2) CPRIOR = `EXCESS', a diversion is made only if $Q_{DS}$ for reach RNO exceeds the value of DIVFLOW. If this occurs, then the quantity of water diverted is the excess flow ($Q_{DS} -$ DIVFLOW) and $Q_{DS}$ from reach RNO is set equal to DIVFLOW. This represents a flood-control type of diversion, as described by Danskin and Hanson (2002). (3) CPRIOR = `THRESHOLD', then if $Q_{DS}$ in reach RNO is less than the specified diversion flow DIVFLOW, no water is diverted from reach RNO. If $Q_{DS}$ in reach RNO is greater than or equal to DIVFLOW, DIVFLOW is diverted and $Q_{DS}$ is set to the remainder ($Q_{DS} -$ DIVFLOW)). This approach assumes that once flow in the stream is sufficiently low, diversions from the stream cease, and is the `priority' algorithm that originally was programmed into the STR1 Package (Prudic, 1989). (4) CPRIOR = `UPTO' -- if $Q_{DS}$ in reach RNO is greater than or equal to the specified diversion flow DIVFLOW, $Q_{DS}$ is reduced by DIVFLOW. If $Q_{DS}$ in reach RNO is less than DIVFLOW, DIVFLOW is set to $Q_{DS}$ and there will be no flow available for reaches connected to downstream end of reach RNO. # --------------------- gwf sfr period --------------------- diff --git a/dependencies/flopy/mf6/data/dfn/gwf-sto.dfn b/dependencies/flopy/mf6/data/dfn/gwf-sto.dfn index 6239b02..3632490 100644 --- a/dependencies/flopy/mf6/data/dfn/gwf-sto.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwf-sto.dfn @@ -16,6 +16,14 @@ optional true longname keyword to indicate SS is read as storage coefficient description keyword to indicate that the SS array is read as storage coefficient rather than specific storage. +block options +name ss_confined_only +type keyword +reader urword +optional true +longname keyword to indicate specific storage only applied under confined conditions +description keyword to indicate that specific storage is only calculated when a cell is under confined conditions (head greater than or equal to the top of the cell). This option is identical to the approach used to calculate storage changes under confined conditions in MODFLOW-2005. + # --------------------- gwf sto griddata --------------------- block griddata diff --git a/dependencies/flopy/mf6/data/dfn/gwf-uzf.dfn b/dependencies/flopy/mf6/data/dfn/gwf-uzf.dfn index 0d22835..a451463 100644 --- a/dependencies/flopy/mf6/data/dfn/gwf-uzf.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwf-uzf.dfn @@ -51,6 +51,39 @@ optional true longname save well flows to budget file description REPLACE save_flows {'{#1}': 'UZF'} +block options +name wc_filerecord +type record water_content fileout wcfile +shape +reader urword +tagged true +optional true +longname +description + +block options +name water_content +type keyword +shape +in_record true +reader urword +tagged true +optional false +longname water_content keyword +description keyword to specify that record corresponds to unsaturated zone water contents. + +block options +name wcfile +type string +preserve_case true +shape +in_record true +reader urword +tagged false +optional false +longname file keyword +description name of the binary output file to write water content information. + block options name budget_filerecord type record budget fileout budgetfile @@ -364,7 +397,7 @@ tagged false in_record true reader urword longname vertical saturated hydraulic conductivity -description is the vertical saturated hydraulic conductivity of the UZF cell. +description is the saturated vertical hydraulic conductivity of the UZF cell. This value is used with the Brooks-Corey function and the simulated water content to calculate the partially saturated hydraulic conductivity. block packagedata name thtr @@ -374,7 +407,7 @@ tagged false in_record true reader urword longname residual water content -description is the residual (irreducible) water content of the UZF cell. +description is the residual (irreducible) water content of the UZF cell. This residual water is not available to plants and will not drain into underlying aquifer cells. block packagedata name thts @@ -384,7 +417,7 @@ tagged false in_record true reader urword longname saturated water content -description is the saturated water content of the UZF cell. +description is the saturated water content of the UZF cell. The values for saturated and residual water content should be set in a manner that is consistent with the specific yield value specified in the Storage Package. The saturated water content must be greater than the residual content. block packagedata name thti @@ -394,7 +427,7 @@ tagged false in_record true reader urword longname initial water content -description is the initial water content of the UZF cell. +description is the initial water content of the UZF cell. The value must be greater than or equal to the residual water content and less than or equal to the saturated water content. block packagedata name eps @@ -403,8 +436,8 @@ shape tagged false in_record true reader urword -longname initial water content -description is the epsilon exponent of the UZF cell. +longname Brooks-Corey exponent +description is the exponent used in the Brooks-Corey function. The Brooks-Corey function is used by UZF to calculated hydraulic conductivity under partially saturated conditions as a function of water content and the user-specified saturated hydraulic conductivity. block packagedata name boundname @@ -494,7 +527,7 @@ in_record true reader urword time_series true longname extinction water content -description real or character value that defines the evapotranspiration extinction water content of the UZF cell. EXTWC is always specified, but is only used if SIMULATE\_ET and UNSAT\_ETWC are specified in the OPTIONS block. If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. +description real or character value that defines the evapotranspiration extinction water content of the UZF cell. EXTWC is always specified, but is only used if SIMULATE\_ET and UNSAT\_ETWC are specified in the OPTIONS block. The evapotranspiration rate from the unsaturated zone will be set to zero when the calculated water content is at or less than this value. The value for EXTWC cannot be less than the residual water content, and if it is specified as being less than the residual water content it is set to the residual water content. If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. block period name ha diff --git a/dependencies/flopy/mf6/data/dfn/gwt-api.dfn b/dependencies/flopy/mf6/data/dfn/gwt-api.dfn new file mode 100644 index 0000000..62b81c8 --- /dev/null +++ b/dependencies/flopy/mf6/data/dfn/gwt-api.dfn @@ -0,0 +1,96 @@ +# --------------------- gwt api options --------------------- + +block options +name boundnames +type keyword +shape +reader urword +optional true +longname +description REPLACE boundnames {'{#1}': 'api boundary'} + +block options +name print_input +type keyword +reader urword +optional true +longname print input to listing file +description REPLACE print_input {'{#1}': 'api boundary'} + +block options +name print_flows +type keyword +reader urword +optional true +longname print calculated flows to listing file +description REPLACE print_flows {'{#1}': 'api boundary'} + +block options +name save_flows +type keyword +reader urword +optional true +longname save api flows to budget file +description REPLACE save_flows {'{#1}': 'api boundary'} + +block options +name obs_filerecord +type record obs6 filein obs6_filename +shape +reader urword +tagged true +optional true +longname +description + +block options +name obs6 +type keyword +shape +in_record true +reader urword +tagged true +optional false +longname obs keyword +description keyword to specify that record corresponds to an observations file. + +block options +name filein +type keyword +shape +in_record true +reader urword +tagged true +optional false +longname file keyword +description keyword to specify that an input filename is expected next. + +block options +name obs6_filename +type string +preserve_case true +in_record true +tagged false +reader urword +optional false +longname obs6 input filename +description REPLACE obs6_filename {'{#1}': 'api boundary'} + +block options +name mover +type keyword +tagged true +reader urword +optional true +longname +description REPLACE mover {'{#1}': 'api boundary'} + +# --------------------- gwt api dimensions --------------------- + +block dimensions +name maxbound +type integer +reader urword +optional false +longname maximum number of user-defined api boundaries +description REPLACE maxbound {'{#1}': 'api boundary'} diff --git a/dependencies/flopy/mf6/data/dfn/gwt-disu.dfn b/dependencies/flopy/mf6/data/dfn/gwt-disu.dfn index 6d36d35..a81fdef 100644 --- a/dependencies/flopy/mf6/data/dfn/gwt-disu.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwt-disu.dfn @@ -40,6 +40,15 @@ optional true longname rotation angle description counter-clockwise rotation angle (in degrees) of the model grid coordinate system relative to a real-world coordinate system. If not specified, then a default value of 0.0 is assigned. The value for ANGROT does not affect the model simulation, but it is written to the binary grid file so that postprocessors can locate the grid in space. +block options +name vertical_offset_tolerance +type double precision +reader urword +optional true +default_value 0.0 +longname vertical length dimension for top and bottom checking +description checks are performed to ensure that the top of a cell is not higher than the bottom of an overlying cell. This option can be used to specify the tolerance that is used for checking. If top of a cell is above the bottom of an overlying cell by a value less than this tolerance, then the program will not terminate with an error. The default value is zero. This option should generally not be used. + # --------------------- gwt disu dimensions --------------------- block dimensions @@ -92,6 +101,15 @@ reader readarray longname cell surface area description is the cell surface area (in plan view). +block griddata +name idomain +type integer +shape (nodes) +reader readarray +layered false +optional true +longname idomain existence array +description is an optional array that characterizes the existence status of a cell. If the IDOMAIN array is not specified, then all model cells exist within the solution. If the IDOMAIN value for a cell is 0, the cell does not exist in the simulation. Input and output values will be read and written for the cell, but internal to the program, the cell is excluded from the solution. If the IDOMAIN value for a cell is 1 or greater, the cell exists in the simulation. IDOMAIN values of -1 cannot be specified for the DISU Package. # --------------------- gwt disu connectiondata --------------------- @@ -109,8 +127,9 @@ type integer shape (nja) reader readarray longname grid connectivity -description is a list of cell number (n) followed by its connecting cell numbers (m) for each of the m cells connected to cell n. The number of values to provide for cell n is IAC(n). This list is sequentially provided for the first to the last cell. The first value in the list must be cell n itself, and the remaining cells must be listed in an increasing order (sorted from lowest number to highest). Note that the cell and its connections are only supplied for the GWF cells and their connections to the other GWF cells. Also note that the JA list input may be divided such that every node and its connectivity list can be on a separate line for ease in readability of the file. To further ease readability of the file, the node number of the cell whose connectivity is subsequently listed, may be expressed as a negative number, the sign of which is subsequently converted to positive by the code. +description is a list of cell number (n) followed by its connecting cell numbers (m) for each of the m cells connected to cell n. The number of values to provide for cell n is IAC(n). This list is sequentially provided for the first to the last cell. The first value in the list must be cell n itself, and the remaining cells must be listed in an increasing order (sorted from lowest number to highest). Note that the cell and its connections are only supplied for the GWT cells and their connections to the other GWT cells. Also note that the JA list input may be divided such that every node and its connectivity list can be on a separate line for ease in readability of the file. To further ease readability of the file, the node number of the cell whose connectivity is subsequently listed, may be expressed as a negative number, the sign of which is subsequently converted to positive by the code. numeric_index true +jagged_array iac block connectiondata name ihc @@ -119,6 +138,7 @@ shape (nja) reader readarray longname connection type description is an index array indicating the direction between node n and all of its m connections. If IHC = 0 then cell n and cell m are connected in the vertical direction. Cell n overlies cell m if the cell number for n is less than m; cell m overlies cell n if the cell number for m is less than n. If IHC = 1 then cell n and cell m are connected in the horizontal direction. If IHC = 2 then cell n and cell m are connected in the horizontal direction, and the connection is vertically staggered. A vertically staggered connection is one in which a cell is horizontally connected to more than one cell in a horizontal connection. +jagged_array iac block connectiondata name cl12 @@ -127,6 +147,7 @@ shape (nja) reader readarray longname connection lengths description is the array containing connection lengths between the center of cell n and the shared face with each adjacent m cell. +jagged_array iac block connectiondata name hwva @@ -135,6 +156,7 @@ shape (nja) reader readarray longname connection lengths description is a symmetric array of size NJA. For horizontal connections, entries in HWVA are the horizontal width perpendicular to flow. For vertical connections, entries in HWVA are the vertical area for flow. Thus, values in the HWVA array contain dimensions of both length and area. Entries in the HWVA array have a one-to-one correspondence with the connections specified in the JA array. Likewise, there is a one-to-one correspondence between entries in the HWVA array and entries in the IHC array, which specifies the connection type (horizontal or vertical). Entries in the HWVA array must be symmetric; the program will terminate with an error if the value for HWVA for an n to m connection does not equal the value for HWVA for the corresponding n to m connection. +jagged_array iac block connectiondata name angldegx @@ -144,6 +166,7 @@ shape (nja) reader readarray longname angle of face normal to connection description is the angle (in degrees) between the horizontal x-axis and the outward normal to the face between a cell and its connecting cells. The angle varies between zero and 360.0 degrees, where zero degrees points in the positive x-axis direction, and 90 degrees points in the positive y-axis direction. ANGLDEGX is only needed if horizontal anisotropy is specified in the NPF Package, if the XT3D option is used in the NPF Package, or if the SAVE\_SPECIFIC\_DISCHARGE option is specifed in the NPF Package. ANGLDEGX does not need to be specified if these conditions are not met. ANGLDEGX is of size NJA; values specified for vertical connections and for the diagonal position are not used. Note that ANGLDEGX is read in degrees, which is different from MODFLOW-USG, which reads a similar variable (ANGLEX) in radians. +jagged_array iac # --------------------- gwt disu vertices --------------------- diff --git a/dependencies/flopy/mf6/data/dfn/gwt-fmi.dfn b/dependencies/flopy/mf6/data/dfn/gwt-fmi.dfn index 393b1a2..b129371 100644 --- a/dependencies/flopy/mf6/data/dfn/gwt-fmi.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwt-fmi.dfn @@ -1,5 +1,13 @@ # --------------------- gwt fmi options --------------------- +block options +name save_flows +type keyword +reader urword +optional true +longname save calculated flow imbalance correction to budget file +description REPLACE save_flows {'{#1}': 'FMI'} + block options name flow_imbalance_correction type keyword diff --git a/dependencies/flopy/mf6/data/dfn/gwt-ist.dfn b/dependencies/flopy/mf6/data/dfn/gwt-ist.dfn index 5dbf732..92b299e 100644 --- a/dependencies/flopy/mf6/data/dfn/gwt-ist.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwt-ist.dfn @@ -22,7 +22,7 @@ type keyword reader urword optional true longname activate first-order decay -description is a text keyword to indicate that first-order decay will occur. Use of this keyword requires that DECAY and DECAY\_SORBED (if sorbtion is active) are specified in the GRIDDATA block. +description is a text keyword to indicate that first-order decay will occur. Use of this keyword requires that DECAY and DECAY\_SORBED (if sorption is active) are specified in the GRIDDATA block. block options name zero_order_decay @@ -30,7 +30,7 @@ type keyword reader urword optional true longname activate zero-order decay -description is a text keyword to indicate that zero-order decay will occur. Use of this keyword requires that DECAY and DECAY\_SORBED (if sorbtion is active) are specified in the GRIDDATA block. +description is a text keyword to indicate that zero-order decay will occur. Use of this keyword requires that DECAY and DECAY\_SORBED (if sorption is active) are specified in the GRIDDATA block. block options name cim_filerecord @@ -189,7 +189,7 @@ reader readarray layered true optional true longname first rate coefficient -description is the rate coefficient for first or zero-order decay for the aqueous phase of the immobile domain. A negative value indicates solute production. The dimensions of decay for first-order decay is one over time. The dimensions of decay for zero-order decay is mass per length cubed per time. decay will have no affect on simulation results unless either first- or zero-order decay is specified in the options block. +description is the rate coefficient for first or zero-order decay for the aqueous phase of the immobile domain. A negative value indicates solute production. The dimensions of decay for first-order decay is one over time. The dimensions of decay for zero-order decay is mass per length cubed per time. Decay will have no effect on simulation results unless either first- or zero-order decay is specified in the options block. block griddata name decay_sorbed @@ -199,7 +199,7 @@ reader readarray optional true layered true longname second rate coefficient -description is the rate coefficient for first or zero-order decay for the sorbed phase of the immobile domain. A negative value indicates solute production. The dimensions of decay\_sorbed for first-order decay is one over time. The dimensions of decay\_sorbed for zero-order decay is mass of solute per mass of aquifer per time. If decay\_sorbed is not specified and both decay and sorbtion are active, then the program will terminate with an error. decay\_sorbed will have no affect on simulation results unless the SORPTION keyword and either first- or zero-order decay are specified in the options block. +description is the rate coefficient for first or zero-order decay for the sorbed phase of the immobile domain. A negative value indicates solute production. The dimensions of decay\_sorbed for first-order decay is one over time. The dimensions of decay\_sorbed for zero-order decay is mass of solute per mass of aquifer per time. If decay\_sorbed is not specified and both decay and sorption are active, then the program will terminate with an error. decay\_sorbed will have no effect on simulation results unless the SORPTION keyword and either first- or zero-order decay are specified in the options block. block griddata name bulk_density @@ -208,7 +208,7 @@ shape (nodes) reader readarray layered true longname bulk density -description is the bulk density of the aquifer in mass per length cubed. bulk\_density will have no affect on simulation results unless the SORBTION keyword is specified in the options block. +description is the bulk density of the aquifer in mass per length cubed. bulk\_density will have no effect on simulation results unless the SORPTION keyword is specified in the options block. block griddata name distcoef @@ -217,5 +217,5 @@ shape (nodes) reader readarray layered true longname distribution coefficient -description is the distribution coefficient for the equilibrium-controlled linear sorption isotherm in dimensions of length cubed per mass. distcoef will have no affect on simulation results unless the SORBTION keyword is specified in the options block. +description is the distribution coefficient for the equilibrium-controlled linear sorption isotherm in dimensions of length cubed per mass. distcoef will have no effect on simulation results unless the SORPTION keyword is specified in the options block. diff --git a/dependencies/flopy/mf6/data/dfn/gwt-lkt.dfn b/dependencies/flopy/mf6/data/dfn/gwt-lkt.dfn index 313b7e5..b55a9e8 100644 --- a/dependencies/flopy/mf6/data/dfn/gwt-lkt.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwt-lkt.dfn @@ -25,7 +25,7 @@ shape reader urword optional true longname keyword to specify name of concentration auxiliary variable in flow package -description keyword to specify the name of an auxiliary variable in the corresponding flow package. If specified, then the simulated concentrations from this advanced transport package will be copied into the auxiliary variable specified with this name. Note that the flow package must have an auxiliary variable with this name or the program will terminate with an error. If the flows for this advanced transport package are read from a file, then this option will have no affect. +description keyword to specify the name of an auxiliary variable in the corresponding flow package. If specified, then the simulated concentrations from this advanced transport package will be copied into the auxiliary variable specified with this name. Note that the flow package must have an auxiliary variable with this name or the program will terminate with an error. If the flows for this advanced transport package are read from a file, then this option will have no effect. block options name boundnames diff --git a/dependencies/flopy/mf6/data/dfn/gwt-mst.dfn b/dependencies/flopy/mf6/data/dfn/gwt-mst.dfn index 573b952..5fe934b 100644 --- a/dependencies/flopy/mf6/data/dfn/gwt-mst.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwt-mst.dfn @@ -14,7 +14,7 @@ type keyword reader urword optional true longname activate first-order decay -description is a text keyword to indicate that first-order decay will occur. Use of this keyword requires that DECAY and DECAY\_SORBED (if sorbtion is active) are specified in the GRIDDATA block. +description is a text keyword to indicate that first-order decay will occur. Use of this keyword requires that DECAY and DECAY\_SORBED (if sorption is active) are specified in the GRIDDATA block. block options name zero_order_decay @@ -22,7 +22,7 @@ type keyword reader urword optional true longname activate zero-order decay -description is a text keyword to indicate that zero-order decay will occur. Use of this keyword requires that DECAY and DECAY\_SORBED (if sorbtion is active) are specified in the GRIDDATA block. +description is a text keyword to indicate that zero-order decay will occur. Use of this keyword requires that DECAY and DECAY\_SORBED (if sorption is active) are specified in the GRIDDATA block. block options name sorption @@ -52,7 +52,7 @@ reader readarray layered true optional true longname aqueous phase decay rate coefficient -description is the rate coefficient for first or zero-order decay for the aqueous phase of the mobile domain. A negative value indicates solute production. The dimensions of decay for first-order decay is one over time. The dimensions of decay for zero-order decay is mass per length cubed per time. decay will have no affect on simulation results unless either first- or zero-order decay is specified in the options block. +description is the rate coefficient for first or zero-order decay for the aqueous phase of the mobile domain. A negative value indicates solute production. The dimensions of decay for first-order decay is one over time. The dimensions of decay for zero-order decay is mass per length cubed per time. decay will have no effect on simulation results unless either first- or zero-order decay is specified in the options block. block griddata name decay_sorbed @@ -62,7 +62,7 @@ reader readarray optional true layered true longname sorbed phase decay rate coefficient -description is the rate coefficient for first or zero-order decay for the sorbed phase of the mobile domain. A negative value indicates solute production. The dimensions of decay\_sorbed for first-order decay is one over time. The dimensions of decay\_sorbed for zero-order decay is mass of solute per mass of aquifer per time. If decay\_sorbed is not specified and both decay and sorbtion are active, then the program will terminate with an error. decay\_sorbed will have no affect on simulation results unless the SORPTION keyword and either first- or zero-order decay are specified in the options block. +description is the rate coefficient for first or zero-order decay for the sorbed phase of the mobile domain. A negative value indicates solute production. The dimensions of decay\_sorbed for first-order decay is one over time. The dimensions of decay\_sorbed for zero-order decay is mass of solute per mass of aquifer per time. If decay\_sorbed is not specified and both decay and sorption are active, then the program will terminate with an error. decay\_sorbed will have no effect on simulation results unless the SORPTION keyword and either first- or zero-order decay are specified in the options block. block griddata name bulk_density @@ -72,7 +72,7 @@ reader readarray optional true layered true longname bulk density -description is the bulk density of the aquifer in mass per length cubed. bulk\_density is not required unless the SORBTION keyword is specified. +description is the bulk density of the aquifer in mass per length cubed. bulk\_density is not required unless the SORPTION keyword is specified. block griddata name distcoef diff --git a/dependencies/flopy/mf6/data/dfn/gwt-mwt.dfn b/dependencies/flopy/mf6/data/dfn/gwt-mwt.dfn index e49af40..ba76760 100644 --- a/dependencies/flopy/mf6/data/dfn/gwt-mwt.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwt-mwt.dfn @@ -25,7 +25,7 @@ shape reader urword optional true longname keyword to specify name of concentration auxiliary variable in flow package -description keyword to specify the name of an auxiliary variable in the corresponding flow package. If specified, then the simulated concentrations from this advanced transport package will be copied into the auxiliary variable specified with this name. Note that the flow package must have an auxiliary variable with this name or the program will terminate with an error. If the flows for this advanced transport package are read from a file, then this option will have no affect. +description keyword to specify the name of an auxiliary variable in the corresponding flow package. If specified, then the simulated concentrations from this advanced transport package will be copied into the auxiliary variable specified with this name. Note that the flow package must have an auxiliary variable with this name or the program will terminate with an error. If the flows for this advanced transport package are read from a file, then this option will have no effect. block options name boundnames diff --git a/dependencies/flopy/mf6/data/dfn/gwt-sft.dfn b/dependencies/flopy/mf6/data/dfn/gwt-sft.dfn index fe9d6b8..ed49642 100644 --- a/dependencies/flopy/mf6/data/dfn/gwt-sft.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwt-sft.dfn @@ -25,7 +25,7 @@ shape reader urword optional true longname keyword to specify name of concentration auxiliary variable in flow package -description keyword to specify the name of an auxiliary variable in the corresponding flow package. If specified, then the simulated concentrations from this advanced transport package will be copied into the auxiliary variable specified with this name. Note that the flow package must have an auxiliary variable with this name or the program will terminate with an error. If the flows for this advanced transport package are read from a file, then this option will have no affect. +description keyword to specify the name of an auxiliary variable in the corresponding flow package. If specified, then the simulated concentrations from this advanced transport package will be copied into the auxiliary variable specified with this name. Note that the flow package must have an auxiliary variable with this name or the program will terminate with an error. If the flows for this advanced transport package are read from a file, then this option will have no effect. block options name boundnames diff --git a/dependencies/flopy/mf6/data/dfn/gwt-ssm.dfn b/dependencies/flopy/mf6/data/dfn/gwt-ssm.dfn index 394592c..b7a9abc 100644 --- a/dependencies/flopy/mf6/data/dfn/gwt-ssm.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwt-ssm.dfn @@ -34,7 +34,7 @@ type string tagged false reader urword longname package name -description name of the package for which an auxiliary variable contains a source concentration. +description name of the flow package for which an auxiliary variable contains a source concentration. If this flow package is represented using an advanced transport package (SFT, LKT, MWT, or UZT), then the advanced transport package will override SSM terms specified here. block sources name srctype diff --git a/dependencies/flopy/mf6/data/dfn/gwt-uzt.dfn b/dependencies/flopy/mf6/data/dfn/gwt-uzt.dfn index 4679f2f..0f5589a 100644 --- a/dependencies/flopy/mf6/data/dfn/gwt-uzt.dfn +++ b/dependencies/flopy/mf6/data/dfn/gwt-uzt.dfn @@ -25,7 +25,7 @@ shape reader urword optional true longname keyword to specify name of concentration auxiliary variable in flow package -description keyword to specify the name of an auxiliary variable in the corresponding flow package. If specified, then the simulated concentrations from this advanced transport package will be copied into the auxiliary variable specified with this name. Note that the flow package must have an auxiliary variable with this name or the program will terminate with an error. If the flows for this advanced transport package are read from a file, then this option will have no affect. +description keyword to specify the name of an auxiliary variable in the corresponding flow package. If specified, then the simulated concentrations from this advanced transport package will be copied into the auxiliary variable specified with this name. Note that the flow package must have an auxiliary variable with this name or the program will terminate with an error. If the flows for this advanced transport package are read from a file, then this option will have no effect. block options name boundnames diff --git a/dependencies/flopy/mf6/data/dfn/sim-tdis.dfn b/dependencies/flopy/mf6/data/dfn/sim-tdis.dfn index 08587ef..3ad727b 100644 --- a/dependencies/flopy/mf6/data/dfn/sim-tdis.dfn +++ b/dependencies/flopy/mf6/data/dfn/sim-tdis.dfn @@ -14,8 +14,50 @@ type string reader urword optional true longname starting date and time -description is the starting date and time of the simulation. This is a text string that is used as a label within the simulation list file. The value has no affect on the simulation. The recommended format for the starting date and time is described at https://www.w3.org/TR/NOTE-datetime. +description is the starting date and time of the simulation. This is a text string that is used as a label within the simulation list file. The value has no effect on the simulation. The recommended format for the starting date and time is described at https://www.w3.org/TR/NOTE-datetime. +block options +name ats_filerecord +type record ats6 filein ats6_filename +shape +reader urword +tagged true +optional true +longname +description + +block options +name ats6 +type keyword +shape +in_record true +reader urword +tagged true +optional false +longname ats keyword +description keyword to specify that record corresponds to an adaptive time step (ATS) input file. The behavior of ATS and a description of the input file is provided separately. + +block options +name filein +type keyword +shape +in_record true +reader urword +tagged true +optional false +longname file keyword +description keyword to specify that an input filename is expected next. + +block options +name ats6_filename +type string +preserve_case true +in_record true +reader urword +optional false +tagged false +longname file name of adaptive time series information +description defines an adaptive time step (ATS) input file defining ATS controls. Records in the ATS file can be used to override the time step behavior for selected stress periods. # --------------------- sim tdis dimensions --------------------- diff --git a/dependencies/flopy/mf6/data/dfn/sln-ims.dfn b/dependencies/flopy/mf6/data/dfn/sln-ims.dfn index 394aaea..bab5846 100644 --- a/dependencies/flopy/mf6/data/dfn/sln-ims.dfn +++ b/dependencies/flopy/mf6/data/dfn/sln-ims.dfn @@ -157,6 +157,14 @@ tagged false longname no pseudo-transient continuation option description is an optional keyword that is used to define options for disabling pseudo-transient continuation (PTC). FIRST is an optional keyword to disable PTC for the first stress period, if steady-state and one or more model is using the Newton-Raphson formulation. ALL is an optional keyword to disable PTC for all steady-state stress periods for models using the Newton-Raphson formulation. If NO\_PTC\_OPTION is not specified, the NO\_PTC ALL option is used. +block options +name ats_outer_maximum_fraction +type double precision +reader urword +optional true +longname fraction of outer maximum used with ats +description real value defining the fraction of the maximum allowable outer iterations used with the Adaptive Time Step (ATS) capability if it is active. If this value is set to zero by the user, then this solution will have no effect on ATS behavior. This value must be greater than or equal to zero and less than or equal to 0.5 or the program will terminate with an error. If it not specified by the user, then it is assigned a default value of one third. When the number of outer iterations for this solution is less than the product of this value and the maximum allowable outer iterations, then ATS will increase the time step length by a factor of DTADJ in the ATS input file. When the number of outer iterations for this solution is greater than the maximum allowable outer iterations minus the product of this value and the maximum allowable outer iterations, then the ATS (if active) will decrease the time step length by a factor of 1 / DTADJ. + # --------------------- sln ims nonlinear --------------------- @@ -200,7 +208,7 @@ type string reader urword optional true longname under relaxation scheme -description is an optional keyword that defines the nonlinear under-relaxation schemes used. Under-relaxation is also known as dampening, and is used to reduce the size of the calculated dependent variable before proceeding to the next outer iteration. Under-relaxation can be an effective tool for highly nonlinear models when there are large and often counteracting changes in the calculated dependent variable between successive outer iterations. By default under-relaxation is not used. NONE - under-relaxation is not used (default). SIMPLE - Simple under-relaxation scheme with a fixed relaxation factor (UNDER\_RELAXATION\_GAMMA) is used. COOLEY - Cooley under-relaxation scheme is used. DBD - delta-bar-delta under-relaxation is used. Note that the under-relaxation schemes are often used in conjunction with problems that use the Newton-Raphson formulation, however, experience has indicated that they also work well non-Newton problems, such as those with the wet/dry options of MODFLOW 6. +description is an optional keyword that defines the nonlinear under-relaxation schemes used. Under-relaxation is also known as dampening, and is used to reduce the size of the calculated dependent variable before proceeding to the next outer iteration. Under-relaxation can be an effective tool for highly nonlinear models when there are large and often counteracting changes in the calculated dependent variable between successive outer iterations. By default under-relaxation is not used. NONE - under-relaxation is not used (default). SIMPLE - Simple under-relaxation scheme with a fixed relaxation factor (UNDER\_RELAXATION\_GAMMA) is used. COOLEY - Cooley under-relaxation scheme is used. DBD - delta-bar-delta under-relaxation is used. Note that the under-relaxation schemes are often used in conjunction with problems that use the Newton-Raphson formulation, however, experience has indicated that they also work well for non-Newton problems, such as those with the wet/dry options of MODFLOW 6. block nonlinear name under_relaxation_gamma diff --git a/dependencies/flopy/mf6/data/dfn/utl-ats.dfn b/dependencies/flopy/mf6/data/dfn/utl-ats.dfn new file mode 100644 index 0000000..e2bf727 --- /dev/null +++ b/dependencies/flopy/mf6/data/dfn/utl-ats.dfn @@ -0,0 +1,84 @@ +# --------------------- sim ats options --------------------- + + +# --------------------- sim ats dimensions --------------------- + +block dimensions +name maxats +type integer +reader urword +optional false +longname number of ATS periods +description is the number of records in the subsequent perioddata block that will be used for adaptive time stepping. +default_value 1 + +# --------------------- sim ats perioddata --------------------- + +block perioddata +name perioddata +type recarray iperats dt0 dtmin dtmax dtadj dtfailadj +reader urword +optional false +longname stress period ats time information +description + +block perioddata +name iperats +type integer +in_record true +tagged false +reader urword +optional false +longname stress period indicator +description is the period number to designate for adaptive time stepping. The remaining ATS values on this line will apply to period iperats. iperats must be greater than zero. A warning is printed if iperats is greater than nper. +numeric_index true + +block perioddata +name dt0 +type double precision +in_record true +tagged false +reader urword +optional false +longname initial time step length +description is the initial time step length for period iperats. If dt0 is zero, then the final step from the previous stress period will be used as the initial time step. The program will terminate with an error message if dt0 is negative. + +block perioddata +name dtmin +type double precision +in_record true +tagged false +reader urword +optional false +longname minimum time step length +description is the minimum time step length for this period. This value must be greater than zero and less than dtmax. dtmin must be a small value in order to ensure that simulation times end at the end of stress periods and the end of the simulation. A small value, such as 1.e-5, is recommended. + +block perioddata +name dtmax +type double precision +in_record true +tagged false +reader urword +optional false +longname maximum time step length +description is the maximum time step length for this period. This value must be greater than dtmin. + +block perioddata +name dtadj +type double precision +in_record true +tagged false +reader urword +optional false +longname time step multiplier factor +description is the time step multiplier factor for this period. If the number of outer solver iterations are less than the product of the maximum number of outer iterations (OUTER\_MAXIMUM) and ATS\_OUTER\_MAXIMUM\_FRACTION (an optional variable in the IMS input file with a default value of 1/3), then the time step length is multipled by dtadj. If the number of outer solver iterations are greater than the product of the maximum number of outer iterations and ATS\_OUTER\_MAXIMUM\_FRACTION, then the time step length is divided by dtadj. dtadj must be zero, one, or greater than one. If dtadj is zero or one, then it has no effect on the simulation. A value between 2.0 and 5.0 can be used as an initial estimate. + +block perioddata +name dtfailadj +type double precision +in_record true +tagged false +reader urword +optional false +longname divisor for failed time steps +description is the divisor of the time step length when a time step fails to converge. If there is solver failure, then the time step will be tried again with a shorter time step length calculated as the previous time step length divided by dtfailadj. dtfailadj must be zero, one, or greater than one. If dtfailadj is zero or one, then time steps will not be retried with shorter lengths. In this case, the program will terminate with an error, or it will continue of the CONTINUE option is set in the simulation name file. Initial tests with this variable should be set to 5.0 or larger to determine if convergence can be achieved. diff --git a/dependencies/flopy/mf6/data/mfdata.py b/dependencies/flopy/mf6/data/mfdata.py index fd8316a..4a49eaf 100644 --- a/dependencies/flopy/mf6/data/mfdata.py +++ b/dependencies/flopy/mf6/data/mfdata.py @@ -122,10 +122,10 @@ def _load_prep(self, block_header): transient_key = block_header.get_transient_key() if isinstance(transient_key, int): if not self._verify_sp(transient_key): - message = 'Invalid transient key "{}" in block' ' "{}"'.format( - transient_key, block_header.name + raise MFInvalidTransientBlockHeaderException( + f'Invalid transient key "{transient_key}" ' + f'in block "{block_header.name}"' ) - raise MFInvalidTransientBlockHeaderException(message) if transient_key not in self._data_storage: self.add_transient_key(transient_key) self._current_key = transient_key @@ -156,7 +156,7 @@ def _verify_sp(self, sp_num): return True if not ("tdis", "dimensions", "nper") in self._simulation_data.mfdata: raise FlopyException( - "Could not find number of stress periods (" "nper)." + "Could not find number of stress periods (nper)." ) nper = self._simulation_data.mfdata[("tdis", "dimensions", "nper")] if not (sp_num <= nper.get_data()): @@ -226,7 +226,7 @@ def __init__( path=None, dimensions=None, *args, - **kwargs + **kwargs, ): # initialize self._current_key = None @@ -251,7 +251,7 @@ def __init__( index = 0 while self._path in self._simulation_data.mfdata: self._path = self._org_path[:-1] + ( - "{}_{}".format(self._org_path[-1], index), + f"{self._org_path[-1]}_{index}", ) index += 1 self._structure_init() @@ -290,19 +290,19 @@ def model(self): @property def data_type(self): raise NotImplementedError( - "must define dat_type in child " "class to use this base class" + "must define dat_type in child class to use this base class" ) @property def dtype(self): raise NotImplementedError( - "must define dtype in child " "class to use this base class" + "must define dtype in child class to use this base class" ) @property def plottable(self): raise NotImplementedError( - "must define plottable in child " "class to use this base class" + "must define plottable in child class to use this base class" ) @property @@ -438,9 +438,7 @@ def get_description(self, description=None, data_set=None): else: if data_item.description: if description: - description = "{}\n{}".format( - description, data_item.description - ) + description = f"{description}\n{data_item.description}" else: description = data_item.description return description @@ -516,7 +514,7 @@ def _get_constant_formatting_string( self._data_dimensions, verify_data=self._simulation_data.verify_data, ) - return "{}{}".format(sim_data.indent_string.join(const_format), suffix) + return f"{sim_data.indent_string.join(const_format)}{suffix}" def _get_aux_var_name(self, aux_var_index): aux_var_names = self._data_dimensions.package_dim.get_aux_variables() @@ -544,13 +542,13 @@ def __init__( @property def data_type(self): raise NotImplementedError( - "must define dat_type in child " "class to use this base class" + "must define dat_type in child class to use this base class" ) @property def plottable(self): raise NotImplementedError( - "must define plottable in child " "class to use this base class" + "must define plottable in child class to use this base class" ) def _get_internal_formatting_string(self, layer): @@ -591,7 +589,7 @@ def _get_external_formatting_string(self, layer, ext_file_action): layer_storage.fname, model_name, ext_file_action ) layer_storage.fname = ext_file_path - ext_format = ["OPEN/CLOSE", "'{}'".format(ext_file_path)] + ext_format = ["OPEN/CLOSE", f"'{ext_file_path}'"] if storage.data_structure_type != DataStructureType.recarray: if layer_storage.factor is not None: data_type = self.structure.get_datum_type( @@ -607,6 +605,4 @@ def _get_external_formatting_string(self, layer, ext_file_action): if layer_storage.iprn is not None: ext_format.append("IPRN") ext_format.append(str(layer_storage.iprn)) - return "{}\n".format( - self._simulation_data.indent_string.join(ext_format) - ) + return f"{self._simulation_data.indent_string.join(ext_format)}\n" diff --git a/dependencies/flopy/mf6/data/mfdataarray.py b/dependencies/flopy/mf6/data/mfdataarray.py index 0783919..1c7e58a 100644 --- a/dependencies/flopy/mf6/data/mfdataarray.py +++ b/dependencies/flopy/mf6/data/mfdataarray.py @@ -1,6 +1,5 @@ import sys, inspect, copy, os import numpy as np -from collections import OrderedDict from ..data.mfstructure import DatumType from .mfdatastorage import DataStorage, DataStructureType, DataStorageType from ...utils.datautil import MultiList, DatumUtil @@ -192,8 +191,7 @@ def __getitem__(self, k): ) comment = ( - 'Unable to resolve index "{}" for ' - "multidimensional data.".format(k) + f'Unable to resolve index "{k}" for multidimensional data.' ) type_, value_, traceback_ = sys.exc_info() raise MFDataException( @@ -379,10 +377,7 @@ def set_layered_data(self, layered_data): self._data_dimensions.get_model_grid().grid_type() == DiscretizationType.DISU ): - comment = ( - "Layered option not available for unstructured " - "grid. {}".format(self._path) - ) + comment = f"Layered option not available for unstructured grid. {self._path}" else: comment = ( 'Data "{}" does not support layered option. ' @@ -431,10 +426,7 @@ def make_layered(self): self._data_dimensions.get_model_grid().grid_type() == DiscretizationType.DISU ): - comment = ( - "Layered option not available for unstructured " - "grid. {}".format(self._path) - ) + comment = f"Layered option not available for unstructured grid. {self._path}" else: comment = ( 'Data "{}" does not support layered option. ' @@ -518,11 +510,9 @@ def store_as_external_file( if len(layer_list) > 0: fname, ext = os.path.splitext(external_file_path) if len(layer_list) == 1: - file_path = "{}{}".format(fname, ext) + file_path = f"{fname}{ext}" else: - file_path = "{}_layer{}{}".format( - fname, current_layer + 1, ext - ) + file_path = f"{fname}_layer{current_layer + 1}{ext}" else: file_path = external_file_path if isinstance(current_layer, int): @@ -569,8 +559,7 @@ def store_as_external_file( self.structure.get_model(), self.structure.get_package(), self._path, - "storing data in external file " - "{}".format(external_file_path), + f"storing data in external file {external_file_path}", self.structure.name, inspect.stack()[0][3], type_, @@ -657,7 +646,7 @@ def store_internal( self.structure.get_model(), self.structure.get_package(), self._path, - "storing data {} internally".format(self.structure.name), + f"storing data {self.structure.name} internally", self.structure.name, inspect.stack()[0][3], type_, @@ -1045,9 +1034,7 @@ def _get_file_entry( if shape_ml.get_total_size() == 1: data_indent = indent else: - data_indent = "{}{}".format( - indent, self._simulation_data.indent_string - ) + data_indent = f"{indent}{self._simulation_data.indent_string}" file_entry_array = [] if data_storage.data_structure_type == DataStructureType.scalar: @@ -1078,17 +1065,15 @@ def _get_file_entry( # for cellid and numeric indices convert from 0 base to 1 based data = abs(data) + 1 file_entry_array.append( - "{}{}{}{}\n".format(indent, self.structure.name, indent, data) + f"{indent}{self.structure.name}{indent}{data}\n" ) elif data_storage.layered: if not layered_aux: if not self.structure.data_item_structures[0].just_data: name = self.structure.name - file_entry_array.append( - "{}{}{}{}\n".format(indent, name, indent, "LAYERED") - ) + file_entry_array.append(f"{indent}{name}{indent}LAYERED\n") else: - file_entry_array.append("{}{}\n".format(indent, "LAYERED")) + file_entry_array.append(f"{indent}LAYERED\n") if layer is None: layer_min = shape_ml.first_index() @@ -1132,12 +1117,10 @@ def _get_file_entry( if not self.structure.data_item_structures[0].just_data: if self._data_name == "aux": file_entry_array.append( - "{}{}\n".format(indent, self._get_aux_var_name([0])) + f"{indent}{self._get_aux_var_name([0])}\n" ) else: - file_entry_array.append( - "{}{}\n".format(indent, self.structure.name) - ) + file_entry_array.append(f"{indent}{self.structure.name}\n") data_storage_type = data_storage.layer_storage[0].data_storage_type file_entry_array.append( @@ -1204,8 +1187,8 @@ def _get_file_entry_layer( if layered_aux: try: # display aux name - file_entry = "{}{}\n".format( - indent_string, self._get_aux_var_name(layer) + file_entry = ( + f"{indent_string}{self._get_aux_var_name(layer)}\n" ) except Exception as ex: type_, value_, traceback_ = sys.exc_info() @@ -1223,8 +1206,8 @@ def _get_file_entry_layer( self._simulation_data.debug, ex, ) - indent_string = "{}{}".format( - indent_string, self._simulation_data.indent_string + indent_string = ( + f"{indent_string}{self._simulation_data.indent_string}" ) data_storage = self._get_storage_obj() @@ -1232,9 +1215,7 @@ def _get_file_entry_layer( # internal data header + data format_str = self._get_internal_formatting_string(layer).upper() lay_str = self._get_data_layer_string(layer, data_indent).upper() - file_entry = "{}{}{}\n{}".format( - file_entry, indent_string, format_str, lay_str - ) + file_entry = f"{file_entry}{indent_string}{format_str}\n{lay_str}" elif storage_type == DataStorageType.internal_constant: # constant data try: @@ -1258,21 +1239,20 @@ def _get_file_entry_layer( const_str = self._get_constant_formatting_string( const_val, layer, self._data_type ).upper() - file_entry = "{}{}{}".format(file_entry, indent_string, const_str) + file_entry = f"{file_entry}{indent_string}{const_str}" else: # external data ext_str = self._get_external_formatting_string( layer, ext_file_action ) - file_entry = "{}{}{}".format(file_entry, indent_string, ext_str) + file_entry = f"{file_entry}{indent_string}{ext_str}" # add to active list of external files try: file_path = data_storage.get_external_file_path(layer) except Exception as ex: type_, value_, traceback_ = sys.exc_info() comment = ( - "Could not get external file path for layer " - '"{}"'.format(layer), + f'Could not get external file path for layer "{layer}"', ) raise MFDataException( self.structure.get_model(), @@ -1299,7 +1279,7 @@ def _get_data_layer_string(self, layer, data_indent): data = self._get_storage_obj().get_data(layer, False) except Exception as ex: type_, value_, traceback_ = sys.exc_info() - comment = 'Could not get data for layer "{}"'.format(layer) + comment = f'Could not get data for layer "{layer}"' raise MFDataException( self.structure.get_model(), self.structure.get_package(), @@ -1370,7 +1350,7 @@ def plot( mflay=None, fignum=None, title=None, - **kwargs + **kwargs, ): """ Plot 3-D model input data @@ -1439,7 +1419,7 @@ def plot( filename_base=filename_base, file_extension=file_extension, fignum=fignum, - **kwargs + **kwargs, ) elif num_plottable_layers > 1: axes = PlotUtilities._plot_util3d_helper( @@ -1448,7 +1428,7 @@ def plot( file_extension=file_extension, mflay=mflay, fignum=fignum, - **kwargs + **kwargs, ) else: axes = None @@ -1578,9 +1558,9 @@ def store_as_external_file( ): fname, ext = os.path.splitext(external_file_path) if DatumUtil.is_int(sp): - full_name = "{}_{}{}".format(fname, sp + 1, ext) + full_name = f"{fname}_{sp + 1}{ext}" else: - full_name = "{}_{}{}".format(fname, sp, ext) + full_name = f"{fname}_{sp}{ext}" super().store_as_external_file( full_name, layer, @@ -1712,7 +1692,7 @@ def set_data(self, data, multiplier=None, layer=None, key=None): if `data` is a dictionary. """ - if isinstance(data, dict) or isinstance(data, OrderedDict): + if isinstance(data, dict): # each item in the dictionary is a list for one stress period # the dictionary key is the stress period the list is for del_keys = [] @@ -1815,7 +1795,7 @@ def _new_storage( set_layers, base_storage, stress_period ) else: - return OrderedDict() + return {} def _set_storage_obj(self, storage): self._data_storage[self._current_key] = storage @@ -1835,7 +1815,7 @@ def plot( file_extension=None, mflay=None, fignum=None, - **kwargs + **kwargs, ): """ Plot transient array model input data @@ -1898,6 +1878,6 @@ def plot( file_extension=file_extension, kper=kper, fignum=fignum, - **kwargs + **kwargs, ) return axes diff --git a/dependencies/flopy/mf6/data/mfdatalist.py b/dependencies/flopy/mf6/data/mfdatalist.py index dca510d..761dd10 100644 --- a/dependencies/flopy/mf6/data/mfdatalist.py +++ b/dependencies/flopy/mf6/data/mfdatalist.py @@ -1,4 +1,3 @@ -from collections import OrderedDict import math import sys import os @@ -311,10 +310,7 @@ def store_internal( self._simulation_data.verbosity_level.value >= VerbosityLevel.verbose.value ): - print( - "Storing {} internally.." - ".".format(self.structure.name) - ) + print(f"Storing {self.structure.name} internally...") internal_data = { "data": data, } @@ -684,7 +680,7 @@ def search_data(self, search_term, col=None): type_, value_, traceback_, - "search_term={}\ncol={}".format(search_term, col), + f"search_term={search_term}\ncol={col}", self._simulation_data.debug, ex, ) @@ -750,7 +746,7 @@ def _get_file_entry( ext_string = self._get_external_formatting_string( 0, ext_file_action ) - file_entry.append("{}{}{}".format(indent, indent, ext_string)) + file_entry.append(f"{indent}{indent}{ext_string}") # write file except Exception as ex: @@ -801,6 +797,8 @@ def _get_file_entry( self._crnt_line_num = 1 for mflist_line in range(0, data_lines): text_line = [] + + # data index = 0 self._get_file_entry_record( data_complete, @@ -812,16 +810,14 @@ def _get_file_entry( indent, ) - # include comments + # comments if ( - mflist_line in storage.comments - and storage.comments[mflist_line].text + mflist_line + 1 in storage.comments + and storage.comments[mflist_line + 1].text ): - text_line.append(storage.comments[mflist_line].text) + text_line.append(storage.comments[mflist_line + 1].text) - file_entry.append( - "{}{}\n".format(indent, indent.join(text_line)) - ) + file_entry.append(f"{indent}{indent.join(text_line)}\n") self._crnt_line_num += 1 # unfreeze model grid @@ -848,9 +844,7 @@ def _get_file_entry_record( const_str = self._get_constant_formatting_string( storage.get_const_val(0), 0, data_type, "" ) - text_line.append( - "{}{}{}".format(indent, indent, const_str.upper()) - ) + text_line.append(f"{indent}{indent}{const_str.upper()}") except Exception as ex: type_, value_, traceback_ = sys.exc_info() raise MFDataException( @@ -900,7 +894,7 @@ def _get_file_entry_record( self.structure.get_model(), self.structure.get_package(), self._path, - "processing auxiliary " "variables", + "processing auxiliary variables", self.structure.name, inspect.stack()[0][3], type_, @@ -1008,7 +1002,7 @@ def _get_file_entry_record( type_, value_, traceback_, - "Verify that your data is the " "correct shape", + "Verify that your data is the correct shape", self._simulation_data.debug, ex, ) @@ -1033,7 +1027,7 @@ def _get_file_entry_record( data_key = data_val.lower() if data_key not in data_item.keystring_dict: keystr_struct = data_item.keystring_dict[ - "{}record".format(data_key) + f"{data_key}record" ] else: keystr_struct = data_item.keystring_dict[ @@ -1165,7 +1159,7 @@ def _get_file_entry_record( self.structure.get_model(), self.structure.get_package(), self._path, - "converting data " "to a string", + "converting data to a string", self.structure.name, inspect.stack()[0][3], type_, @@ -1280,7 +1274,7 @@ def plot( filename_base=None, file_extension=None, mflay=None, - **kwargs + **kwargs, ): """ Plot boundary condition (MfList) data @@ -1350,7 +1344,7 @@ def plot( filename_base=None, file_extension=None, mflay=None, - **kwargs + **kwargs, ) @@ -1574,9 +1568,9 @@ def store_as_external_file( ): fname, ext = os.path.splitext(external_file_path) if datautil.DatumUtil.is_int(sp): - full_name = "{}_{}{}".format(fname, sp + 1, ext) + full_name = f"{fname}_{sp + 1}{ext}" else: - full_name = "{}_{}{}".format(fname, sp, ext) + full_name = f"{fname}_{sp}{ext}" super().store_as_external_file( full_name, @@ -1671,7 +1665,7 @@ def set_data(self, data, key=None, autofill=False): Automatically correct data. """ self._cache_model_grid = True - if isinstance(data, dict) or isinstance(data, OrderedDict): + if isinstance(data, dict): if "filename" not in data: # each item in the dictionary is a list for one stress period # the dictionary key is the stress period the list is for @@ -1685,7 +1679,10 @@ def set_data(self, data, key=None, autofill=False): self.empty_keys[key] = True else: self.empty_keys[key] = False - if "check" in list_item: + if ( + isinstance(list_item, dict) + and "check" in list_item + ): check = list_item["check"] else: check = True @@ -1815,7 +1812,7 @@ def update_record(self, record, key_index, key=0): super().update_record(record, key_index) def _new_storage(self, stress_period=0): - return OrderedDict() + return {} def _get_storage_obj(self): if ( @@ -1833,7 +1830,7 @@ def plot( filename_base=None, file_extension=None, mflay=None, - **kwargs + **kwargs, ): """ Plot stress period boundary condition (MfList) data for a specified @@ -1911,7 +1908,7 @@ def plot( filename_base=filename_base, file_extension=file_extension, mflay=mflay, - **kwargs + **kwargs, ) return axes diff --git a/dependencies/flopy/mf6/data/mfdatascalar.py b/dependencies/flopy/mf6/data/mfdatascalar.py index 37b02f4..6bab861 100644 --- a/dependencies/flopy/mf6/data/mfdatascalar.py +++ b/dependencies/flopy/mf6/data/mfdatascalar.py @@ -2,7 +2,6 @@ import numpy as np from ..data.mfstructure import DatumType from ..data import mfdata -from collections import OrderedDict from ..mfbase import ExtFileAction, MFDataException from ...datbase import DataType from .mfdatautil import convert_data, to_string @@ -185,8 +184,8 @@ def set_data(self, data): ) except Exception as ex: type_, value_, traceback_ = sys.exc_info() - comment = 'Could not convert data "{}" to type ' '"{}".'.format( - data, self._data_type + comment = ( + f'Could not convert data "{data}" to type "{self._data_type}".' ) raise MFDataException( self.structure.get_model(), @@ -206,8 +205,8 @@ def set_data(self, data): storage.set_data(converted_data, key=self._current_key) except Exception as ex: type_, value_, traceback_ = sys.exc_info() - comment = 'Could not set data "{}" to type ' '"{}".'.format( - data, self._data_type + comment = ( + f'Could not set data "{data}" to type "{self._data_type}".' ) raise MFDataException( self.structure.get_model(), @@ -271,9 +270,7 @@ def add_one(self): self._get_storage_obj().set_data(current_val + 1) except Exception as ex: type_, value_, traceback_ = sys.exc_info() - comment = 'Could increment data "{}" by one' ".".format( - current_val - ) + comment = f'Could increment data "{current_val}" by one.' raise MFDataException( self.structure.get_model(), self.structure.get_package(), @@ -497,7 +494,7 @@ def get_file_entry( index += 1 text = self._simulation_data.indent_string.join(text_line) - return "{}{}\n".format(self._simulation_data.indent_string, text) + return f"{self._simulation_data.indent_string}{text}\n" else: data_item = self.structure.data_item_structures[0] try: @@ -570,9 +567,7 @@ def get_file_entry( self._simulation_data.debug, ) if values_only: - return "{}{}".format( - self._simulation_data.indent_string, values - ) + return f"{self._simulation_data.indent_string}{values}" else: # keyword + data return "{}{}{}{}\n".format( @@ -683,7 +678,7 @@ def plot(self, filename_base=None, file_extension=None, **kwargs): self, filename_base=filename_base, file_extension=file_extension, - **kwargs + **kwargs, ) return axes @@ -820,7 +815,7 @@ def set_data(self, data, key=None): if `data` is a dictionary. """ - if isinstance(data, dict) or isinstance(data, OrderedDict): + if isinstance(data, dict): # each item in the dictionary is a list for one stress period # the dictionary key is the stress period the list is for for key, list_item in data.items(): @@ -902,7 +897,7 @@ def load( ) def _new_storage(self, stress_period=0): - return OrderedDict() + return {} def _get_storage_obj(self): if ( @@ -918,7 +913,7 @@ def plot( file_extension=None, kper=0, fignum=None, - **kwargs + **kwargs, ): """ Plot transient scalar model data @@ -981,6 +976,6 @@ def plot( file_extension=file_extension, kper=kper, fignum=fignum, - **kwargs + **kwargs, ) return axes diff --git a/dependencies/flopy/mf6/data/mfdatastorage.py b/dependencies/flopy/mf6/data/mfdatastorage.py index edd5d10..d3992c2 100644 --- a/dependencies/flopy/mf6/data/mfdatastorage.py +++ b/dependencies/flopy/mf6/data/mfdatastorage.py @@ -3,7 +3,6 @@ import os import inspect from shutil import copyfile -from collections import OrderedDict from enum import Enum import numpy as np from ..mfbase import MFDataException, VerbosityLevel @@ -128,13 +127,13 @@ def name(self): def __repr__(self): if self.data_storage_type == DataStorageType.internal_constant: - return "constant {}".format(self.get_data_const_val()) + return f"constant {self.get_data_const_val()}" else: return repr(self.get_data()) def __str__(self): if self.data_storage_type == DataStorageType.internal_constant: - return "{}".format(self.get_data_const_val()) + return str(self.get_data_const_val()) else: return str(self.get_data()) @@ -205,7 +204,7 @@ class DataStorage: is the data layered pre_data_comments : string any comments before the start of the data - comments : OrderedDict + comments : dict any comments mixed in with the data, dictionary keys are data lines post_data_comments : string any comments after the end of the data @@ -331,7 +330,7 @@ def __init__( # initialize comments self.pre_data_comments = None - self.comments = OrderedDict() + self.comments = {} def __repr__(self): return self.get_data_str(True) @@ -453,7 +452,7 @@ def get_data_str(self, formal): # Assemble strings for internal array data for index, storage in enumerate(self.layer_storage.elements()): if self.layered: - layer_str = "Layer_{}".format(str(index + 1)) + layer_str = f"Layer_{index + 1}" else: layer_str = "" if storage.data_storage_type == DataStorageType.internal_array: @@ -461,7 +460,7 @@ def get_data_str(self, formal): header = self._get_layer_header_str(index) if formal: if self.layered: - data_str = "{}{}{{{}}}" "\n({})\n".format( + data_str = "{}{}{{{}}}\n({})\n".format( data_str, layer_str, header, @@ -486,14 +485,14 @@ def get_data_str(self, formal): ): if formal: if storage.data_const_value is not None: - data_str = "{}{}{{{}}}" "\n".format( + data_str = "{}{}{{{}}}\n".format( data_str, layer_str, self._get_layer_header_str(index), ) else: if storage.data_const_value is not None: - data_str = "{}{}{{{}}}" "\n".format( + data_str = "{}{}{{{}}}\n".format( data_str, layer_str, self._get_layer_header_str(index), @@ -506,15 +505,13 @@ def _get_layer_header_str(self, layer): self.layer_storage[layer].data_storage_type == DataStorageType.external_file ): - header_list.append( - "open/close " "{}".format(self.layer_storage[layer].fname) - ) + header_list.append(f"open/close {self.layer_storage[layer].fname}") elif ( self.layer_storage[layer].data_storage_type == DataStorageType.internal_constant ): lr = self.layer_storage[layer] - header_list.append("constant {}".format(lr)) + header_list.append(f"constant {lr}") else: header_list.append("internal") if ( @@ -522,13 +519,9 @@ def _get_layer_header_str(self, layer): and self.layer_storage[layer].factor != 1 and self.data_structure_type != DataStructureType.recarray ): - header_list.append( - "factor " "{}".format(self.layer_storage[layer].factor) - ) + header_list.append(f"factor {self.layer_storage[layer].factor}") if self.layer_storage[layer].iprn is not None: - header_list.append( - "iprn " "{}".format(self.layer_storage[layer].iprn) - ) + header_list.append(f"iprn {self.layer_storage[layer].iprn}") if len(header_list) > 0: return ", ".join(header_list) else: @@ -692,7 +685,7 @@ def _access_data(self, layer, return_data=False, apply_mult=True): ): return None if not (layer is None or self.layer_storage.in_shape(layer)): - message = 'Layer "{}" is an invalid layer.'.format(layer) + message = f'Layer "{layer}" is an invalid layer.' type_, value_, traceback_ = sys.exc_info() raise MFDataException( self.data_dimensions.structure.get_model(), @@ -914,10 +907,8 @@ def _set_list( elif "data" in data: data = data["data"] if isinstance(data, list): - if ( - len(data) > 0 - and not isinstance(data[0], tuple) - and not isinstance(data[0], list) + if len(data) > 0 and ( + not PyListUtil.is_iterable(data[0]) or isinstance(data[0], str) ): # single line of data needs to be encapsulated in a tuple data = [tuple(data)] @@ -1101,9 +1092,7 @@ def get_active_layer_indices(self): def get_external(self, layer=None): if not (layer is None or self.layer_storage.in_shape(layer)): - message = 'Can not get external data for layer "{}"' ".".format( - layer - ) + message = f'Can not get external data for layer "{layer}".' type_, value_, traceback_ = sys.exc_info() raise MFDataException( self.data_dimensions.structure.get_model(), @@ -1244,10 +1233,8 @@ def store_internal( ) except: message = ( - "An error occurred when reshaping data " - '"{}" to store. Expected data ' - "dimensions: " - "{}".format( + 'An error occurred when reshaping data "{}" to store. ' + "Expected data dimensions: {}".format( self.data_dimensions.structure.name, dimensions ) ) @@ -1397,7 +1384,7 @@ def _build_recarray(self, data, key, autofill): except: data_expected = [] for data_type in self._recarray_type_list: - data_expected.append("<{}>".format(data_type[0])) + data_expected.append(f"<{data_type[0]}>") message = ( "An error occurred when storing data " '"{}" in a recarray. {} data is a one ' @@ -1699,7 +1686,7 @@ def external_to_external( ".".format(self.layer_storage.get_total_size()) ) else: - message = 'layer "{}" is not a valid layer'.format(layer) + message = f'layer "{layer}" is not a valid layer' type_, value_, traceback_ = sys.exc_info() raise MFDataException( self.data_dimensions.structure.get_model(), @@ -1718,7 +1705,7 @@ def external_to_external( if layer is None: layer = 1 if self.layer_storage[layer].fname is None: - message = "No file name exists for layer {}.".format(layer) + message = f"No file name exists for layer {layer}." type_, value_, traceback_ = sys.exc_info() raise MFDataException( self.data_dimensions.structure.get_model(), @@ -1749,6 +1736,10 @@ def external_to_external( ) def external_to_internal(self, layer, store_internal=False): + # reset comments + self.pre_data_comments = None + self.comments = {} + if layer is None: layer = 0 # load data from external file @@ -1985,8 +1976,7 @@ def process_open_close_line(self, arr_line, layer, store=True): if len(arr_line) < 2 and store: message = ( 'Data array "{}" contains a OPEN/CLOSE ' - "that is not followed by a file. " - "{}".format( + "that is not followed by a file. {}".format( data_dim.structure.name, data_dim.structure.path ) ) @@ -2234,9 +2224,9 @@ def _duplicate_last_item(self): if DatumUtil.is_int(arr_item_name[-1]): new_item_num = int(arr_item_name[-1]) + 1 new_item_name = "_".join(arr_item_name[0:-1]) - new_item_name = "{}_{}".format(new_item_name, new_item_num) + new_item_name = f"{new_item_name}_{new_item_num}" else: - new_item_name = "{}_1".format(last_item[0]) + new_item_name = f"{last_item[0]}_1" self._recarray_type_list.append((new_item_name, last_item[1])) def _build_full_data(self, apply_multiplier=False): @@ -2412,11 +2402,7 @@ def _is_type(self, data_item, data_type): self._simulation_data.verbosity_level.value >= VerbosityLevel.normal.value ): - print( - "{} type checking currently not supported".format( - data_type - ) - ) + print(f"{data_type} type checking currently not supported") return True def _fill_dimensions(self, data_iter, dimensions): @@ -2426,10 +2412,10 @@ def _fill_dimensions(self, data_iter, dimensions): data_array = np.ndarray(shape=dimensions, dtype=np_dtype) # fill array for index in ArrayIndexIter(dimensions): - data_array.itemset(index, data_iter.__next__()) + data_array.itemset(index, next(data_iter)) return data_array elif self.data_structure_type == DataStructureType.scalar: - return data_iter.__next__() + return next(data_iter) else: data_array = None data_line = () @@ -2474,7 +2460,7 @@ def _fill_dimensions(self, data_iter, dimensions): ) current_col = 0 data_line = () - data_array[index] = data_iter.next() + data_array[index] = next(data_iter) return data_array def set_tas(self, tas_name, tas_label, current_key, check_name=True): @@ -2493,9 +2479,7 @@ def set_tas(self, tas_name, tas_label, current_key, check_name=True): # this is a time series array with a valid tas variable self.data_structure_type = DataStructureType.scalar try: - self.set_data( - "{} {}".format(tas_label, tas_name), 0, key=current_key - ) + self.set_data(f"{tas_label} {tas_name}", 0, key=current_key) except Exception as ex: type_, value_, traceback_ = sys.exc_info() structure = self.data_dimensions.structure @@ -2615,7 +2599,7 @@ def build_type_list( # add potential data after keystring to type list ks_data_item = deepcopy(data_item) ks_data_item.type = DatumType.string - ks_data_item.name = "{}_data".format(ks_data_item.name) + ks_data_item.name = f"{ks_data_item.name}_data" ks_rec_type = ks_data_item.get_rec_type() if not min_size: self._append_type_lists( @@ -2642,7 +2626,7 @@ def build_type_list( # items of variable length. assume everything at # the end of the data line is related to the last # keystring - name = "{}_{}".format(ks_data_item.name, idx) + name = f"{ks_data_item.name}_{idx}" self._append_type_lists( name, ks_rec_type, ks_data_item.is_cellid ) @@ -2664,7 +2648,7 @@ def build_type_list( data_item.type != DatumType.string and data_item.type != DatumType.keyword ): - name = "{}_label".format(data_item.name) + name = f"{data_item.name}_label" self._append_type_lists( name, object, data_item.is_cellid ) @@ -2749,9 +2733,7 @@ def build_type_list( if not data_item.optional or not min_size: for index in range(0, resolved_shape[0]): if resolved_shape[0] > 1: - name = "{}_{}".format( - data_item.name, index - ) + name = f"{data_item.name}_{index}" else: name = data_item.name self._append_type_lists( @@ -2862,7 +2844,7 @@ def _has_layer_dim(self): def _store_prep(self, layer, multiplier): if not (layer is None or self.layer_storage.in_shape(layer)): - message = "Layer {} is not a valid layer.".format(layer) + message = f"Layer {layer} is not a valid layer." type_, value_, traceback_ = sys.exc_info() raise MFDataException( self.data_dimensions.structure.get_model(), diff --git a/dependencies/flopy/mf6/data/mfdatautil.py b/dependencies/flopy/mf6/data/mfdatautil.py index 1c61d24..c041ca7 100644 --- a/dependencies/flopy/mf6/data/mfdatautil.py +++ b/dependencies/flopy/mf6/data/mfdatautil.py @@ -213,7 +213,7 @@ def to_string( return str(val) if len(arr_val) > 1: # quote any string with spaces - string_val = "'{}'".format(val) + string_val = f"'{val}'" if data_item is not None and data_item.ucase: return string_val.upper() else: @@ -304,9 +304,9 @@ def add_text(self, additional_text, new_line=False): if isinstance(self.text, list): self.text.append(additional_text) elif new_line: - self.text = "{}{}".format(self.text, additional_text) + self.text = f"{self.text}{additional_text}" else: - self.text = "{} {}".format(self.text, additional_text) + self.text = f"{self.text} {additional_text}" """ Get the comment text in the format to write to package files. @@ -329,7 +329,7 @@ def get_file_entry(self, eoln_suffix=True): if self.text.strip(): file_entry = self.text if eoln_suffix: - file_entry = "{}\n".format(file_entry) + file_entry = f"{file_entry}\n" return file_entry def _recursive_get(self, base_list): @@ -337,11 +337,9 @@ def _recursive_get(self, base_list): if base_list and self.sim_data.comments_on: for item in base_list: if not isinstance(item, str) and isinstance(item, list): - file_entry = "{}{}".format( - file_entry, self._recursive_get(item) - ) + file_entry = f"{file_entry}{self._recursive_get(item)}" else: - file_entry = "{} {}".format(file_entry, item) + file_entry = f"{file_entry} {item}" return file_entry """ @@ -427,7 +425,7 @@ def _recursive_write(self, fd, base_list): if not isinstance(item, str) and isinstance(item, list): self._recursive_write(fd, item) else: - fd.write(" {}".format(item)) + fd.write(f" {item}") class TemplateGenerator: @@ -839,8 +837,8 @@ class MFDocString: def __init__(self, description): self.indent = " " self.description = description - self.parameter_header = "{}Parameters\n{}" "----------".format( - self.indent, self.indent + self.parameter_header = ( + f"{self.indent}Parameters\n{self.indent}----------" ) self.parameters = [] self.model_parameters = [] @@ -877,7 +875,7 @@ def get_doc_string(self, model_doc_string=False): else: param_list = self.parameters for parameter in param_list: - doc_string += "{}\n".format(parameter) + doc_string += f"{parameter}\n" if not model_doc_string: - doc_string += '\n{}"""'.format(self.indent) + doc_string += f'\n{self.indent}"""' return doc_string diff --git a/dependencies/flopy/mf6/data/mffileaccess.py b/dependencies/flopy/mf6/data/mffileaccess.py index 1b7d42a..e3fa5f9 100644 --- a/dependencies/flopy/mf6/data/mffileaccess.py +++ b/dependencies/flopy/mf6/data/mffileaccess.py @@ -87,8 +87,6 @@ def _read_pre_data_comments( arr_line, self._path, self._simulation_data, line_num ) - storage.add_data_line_comment(arr_line, line_num) - line = file_handle.readline() arr_line = PyListUtil.split_data_line(line) return line @@ -117,9 +115,8 @@ def _load_keyword(self, arr_line, index_num, keyword): if not keyword_match and aux_var_index is None: aux_text = "" if aux_var_names is not None: - aux_text = " or auxiliary variables " "{}".format( - aux_var_names[0] - ) + # TODO: aux_var_names is None, so this is never touched + aux_text = f" or auxiliary variables {aux_var_names[0]}" message = ( 'Error reading variable "{}". Expected ' 'variable keyword "{}"{} not found ' @@ -158,7 +155,7 @@ def _open_ext_file(self, fname, binary=False, write=False): else: options = "r" if binary: - options = "{}b".format(options) + options = f"{options}b" try: fd = open(read_file, options) return fd @@ -430,7 +427,7 @@ def read_binary_data_from_file( return bin_data def get_data_string(self, data, data_type, data_indent=""): - layer_data_string = ["{}".format(data_indent)] + layer_data_string = [str(data_indent)] line_data_count = 0 indent_str = self._simulation_data.indent_string data_iter = datautil.PyListUtil.next_item(data) @@ -482,13 +479,11 @@ def get_data_string(self, data, data_type, data_indent=""): self._simulation_data.debug, ex, ) - layer_data_string[-1] = "{}{}{}".format( - layer_data_string[-1], indent_str, data_lyr - ) + layer_data_string[-1] += f"{indent_str}{data_lyr}" if jagged_def is not None: if line_data_count == jagged_def[jagged_def_index]: - layer_data_string.append("{}".format(data_indent)) + layer_data_string.append(str(data_indent)) line_data_count = 0 jagged_def_index += 1 else: @@ -497,13 +492,13 @@ def get_data_string(self, data, data_type, data_indent=""): == self._simulation_data.max_columns_of_data or last_item ): - layer_data_string.append("{}".format(data_indent)) + layer_data_string.append(str(data_indent)) line_data_count = 0 if len(layer_data_string) > 0: # clean up the text at the end of the array layer_data_string[-1] = layer_data_string[-1].strip() if len(layer_data_string) == 1: - return "{}{}\n".format(data_indent, layer_data_string[0].rstrip()) + return f"{data_indent}{layer_data_string[0].rstrip()}\n" else: return "\n".join(layer_data_string) @@ -674,8 +669,8 @@ def load_from_package( dimensions = storage.get_data_dimensions(layer_shape) except Exception as ex: type_, value_, traceback_ = sys.exc_info() - comment = 'Could not get data shape for key "{}".'.format( - self._current_key + comment = ( + f'Could not get data shape for key "{self._current_key}".' ) raise MFDataException( self.structure.get_model(), @@ -841,7 +836,7 @@ def _load_layer( self.structure.get_model(), self.structure.get_package(), self._path, - "reading data from file " "{}".format(file_handle.name), + f"reading data from file {file_handle.name}", self.structure.name, inspect.stack()[0][3], type_, @@ -863,7 +858,7 @@ def _load_layer( print_format=print_format, ) except Exception as ex: - comment = 'Could not store data: "{}"'.format(data_shaped) + comment = f'Could not store data: "{data_shaped}"' type_, value_, traceback_ = sys.exc_info() raise MFDataException( self.structure.get_model(), @@ -928,8 +923,8 @@ def _resolve_data_shape(self, data, layer_shape, storage): dimensions = storage.get_data_dimensions(layer_shape) except Exception as ex: type_, value_, traceback_ = sys.exc_info() - comment = 'Could not get data shape for key "{}".'.format( - self._current_key + comment = ( + f'Could not get data shape for key "{self._current_key}".' ) raise MFDataException( self.structure.get_model(), @@ -951,8 +946,7 @@ def _resolve_data_shape(self, data, layer_shape, storage): except Exception as ex: type_, value_, traceback_ = sys.exc_info() comment = ( - "Could not reshape data to dimensions " - '"{}".'.format(dimensions) + f'Could not reshape data to dimensions "{dimensions}".' ) raise MFDataException( self.structure.get_model(), @@ -1179,7 +1173,15 @@ def read_list_data_from_file( # read any pre-data commented lines while current_line and MFComment.is_comment(arr_line, True): arr_line.insert(0, "\n") - storage.add_data_line_comment(arr_line, line_num) + if storage.pre_data_comments is None: + storage.pre_data_comments = MFComment( + " ".join(arr_line), + self._path, + self._simulation_data, + line_num, + ) + else: + storage.pre_data_comments.add_text(" ".join(arr_line)) PyListUtil.reset_delimiter_used() current_line = file_handle.readline() arr_line = PyListUtil.split_data_line(current_line) @@ -1242,15 +1244,14 @@ def read_list_data_from_file( else: # not a constant or open/close line, exception is valid comment = ( - "Unable to process line 1 of data list: " - '"{}"'.format(current_line) + f'Unable to process line 1 of data list: "{current_line}"' ) type_, value_, traceback_ = sys.exc_info() raise MFDataException( struct.get_model(), struct.get_package(), struct.path, - "loading data list from " "package file", + "loading data list from package file", struct.name, inspect.stack()[0][3], type_, @@ -1451,7 +1452,7 @@ def read_list_data_from_file( struct.get_model(), struct.get_package(), struct.path, - "loading data list from " "package file", + "loading data list from package file", struct.name, inspect.stack()[0][3], type_, @@ -1645,9 +1646,7 @@ def load_list_line( name_data not in data_item.keystring_dict ): - name_data = "{}record".format( - name_data - ) + name_data = f"{name_data}record" if ( name_data not in data_item.keystring_dict @@ -1673,11 +1672,7 @@ def load_list_line( data_item.keystring_dict[name_data] ) if data_item_ks == 0: - comment = ( - "Could not find " - "keystring " - "{}.".format(name_data) - ) + comment = f"Could not find keystring {name_data}." ( type_, value_, @@ -2064,7 +2059,7 @@ def _append_data_list( struct.get_model(), struct.get_package(), struct.path, - "loading data list from package " "file", + "loading data list from package file", struct.name, inspect.stack()[0][3], type_, @@ -2094,7 +2089,7 @@ def _append_data_list( struct.get_model(), struct.get_package(), struct.path, - "loading data list from package " "file", + "loading data list from package file", struct.name, inspect.stack()[0][3], type_, @@ -2269,7 +2264,7 @@ def load_from_package( storage.set_data(converted_data, key=self._current_key) index_num += 1 except Exception as ex: - message = 'Could not set data "{}" with key ' '"{}".'.format( + message = 'Could not set data "{}" with key "{}".'.format( converted_data, self._current_key ) type_, value_, traceback_ = sys.exc_info() @@ -2295,9 +2290,7 @@ def load_from_package( try: storage.set_data(True, key=self._current_key) except Exception as ex: - message = 'Could not set data "True" with key ' '"{}".'.format( - self._current_key - ) + message = f'Could not set data "True" with key "{self._current_key}".' type_, value_, traceback_ = sys.exc_info() raise MFDataException( self.structure.get_model(), @@ -2370,7 +2363,7 @@ def load_from_package( # read next word as data storage.set_data(converted_data, key=self._current_key) except Exception as ex: - message = 'Could not set data "{}" with key ' '"{}".'.format( + message = 'Could not set data "{}" with key "{}".'.format( converted_data, self._current_key ) type_, value_, traceback_ = sys.exc_info() diff --git a/dependencies/flopy/mf6/data/mfstructure.py b/dependencies/flopy/mf6/data/mfstructure.py index c0f17ad..3b1b58c 100644 --- a/dependencies/flopy/mf6/data/mfstructure.py +++ b/dependencies/flopy/mf6/data/mfstructure.py @@ -9,7 +9,6 @@ import keyword from enum import Enum from textwrap import TextWrapper -from collections import OrderedDict import numpy as np from ..mfbase import PackageContainer, StructException @@ -93,6 +92,8 @@ def __init__(self): "utlobs": 0, "utlts": 0, "utltas": 0, + "utlspc": 0, + "utlspca": 0, } def get_file_list(self): @@ -143,7 +144,7 @@ def get_file_list(self): if package_abbr not in file_order: file_order.append(package_abbr) return [ - fname + ".dfn" for fname in file_order if fname + ".dfn" in files + f"{fname}.dfn" for fname in file_order if f"{fname}.dfn" in files ] def _file_type(self, file_name): @@ -228,7 +229,7 @@ def multi_package_support(self): return self.package.package_abbr in self.multi_package def get_block_structure_dict(self, path, common, model_file): - block_dict = OrderedDict() + block_dict = {} dataset_items_in_block = {} self.dataset_items_needed_dict = {} keystring_items_needed_dict = {} @@ -497,7 +498,7 @@ def multi_package_support(self): return base_file in self.multi_package def dict_by_name(self): - name_dict = OrderedDict() + name_dict = {} name = None dfn_fp = open(self._file_path, "r") for line in dfn_fp: @@ -512,7 +513,7 @@ def dict_by_name(self): def get_block_structure_dict(self, path, common, model_file): self.dfn_list = [] - block_dict = OrderedDict() + block_dict = {} dataset_items_in_block = {} self.dataset_items_needed_dict = {} keystring_items_needed_dict = {} @@ -952,7 +953,7 @@ def set_value(self, line, common): self.python_name = self.name.replace("-", "_").lower() # don't allow name to be a python keyword if keyword.iskeyword(self.name): - self.python_name = "{}_".format(self.python_name) + self.python_name = f"{self.python_name}_" # performance optimizations if self.name == "aux": self.is_aux = True @@ -1100,20 +1101,18 @@ def set_value(self, line, common): self.jagged_array = arr_line[1] def get_type_string(self): - return "[{}]".format(self.type_string) + return f"[{self.type_string}]" def get_description(self, line_size, initial_indent, level_indent): - item_desc = "* {} ({}) {}".format( - self.name, self.type_string, self.description - ) + item_desc = f"* {self.name} ({self.type_string}) {self.description}" if self.numeric_index or self.is_cellid: # append zero-based index text - item_desc = "{} {}".format(item_desc, numeric_index_text) + item_desc = f"{item_desc} {numeric_index_text}" twr = TextWrapper( width=line_size, initial_indent=initial_indent, drop_whitespace=True, - subsequent_indent=" {}".format(initial_indent), + subsequent_indent=f" {initial_indent}", ) item_desc = "\n".join(twr.wrap(item_desc)) return item_desc @@ -1122,25 +1121,22 @@ def get_doc_string(self, line_size, initial_indent, level_indent): description = self.get_description( line_size, initial_indent + level_indent, level_indent ) - param_doc_string = "{} : {}".format( - self.python_name, self.get_type_string() - ) + param_doc_string = f"{self.python_name} : {self.get_type_string()}" twr = TextWrapper( width=line_size, initial_indent=initial_indent, - subsequent_indent=" {}".format(initial_indent), + subsequent_indent=f" {initial_indent}", drop_whitespace=True, ) param_doc_string = "\n".join(twr.wrap(param_doc_string)) - param_doc_string = "{}\n{}".format(param_doc_string, description) + param_doc_string = f"{param_doc_string}\n{description}" return param_doc_string def get_keystring_desc(self, line_size, initial_indent, level_indent): if self.type != DatumType.keystring: raise StructException( - 'Can not get keystring description for "{}" ' - "because it is not a keystring" - ".".format(self.name), + f'Can not get keystring description for "{self.name}" ' + "because it is not a keystring", self.path, ) @@ -1148,7 +1144,7 @@ def get_keystring_desc(self, line_size, initial_indent, level_indent): description = "" for key, item in self.keystring_dict.items(): if description: - description = "{}\n".format(description) + description = f"{description}\n" description = "{}{}".format( description, item.get_doc_string(line_size, initial_indent, level_indent), @@ -1206,7 +1202,7 @@ def _resolve_common(arr_line, common): return arr_line if not (arr_line[2] in common and len(arr_line) >= 4): raise StructException( - 'Could not find line "{}" in common dfn' ".".format(arr_line) + f'Could not find line "{arr_line}" in common dfn.' ) close_bracket_loc = MFDataItemStructure._find_close_bracket( arr_line[2:] @@ -1275,7 +1271,7 @@ def _str_to_enum_type(self, type_string): elif type_string.lower() == "repeating_record": return DatumType.repeating_record else: - exc_text = 'Data item type "{}" not supported.'.format(type_string) + exc_text = f'Data item type "{type_string}" not supported.' raise StructException(exc_text, self.path) def get_rec_type(self): @@ -1430,9 +1426,9 @@ def __init__(self, data_item, model_data, package_type, dfn_list): self.parameter_name = data_item.parameter_name self.one_per_pkg = data_item.one_per_pkg - # self.data_item_structures_dict = OrderedDict() + # self.data_item_structures_dict = {} self.data_item_structures = [] - self.expected_data_items = OrderedDict() + self.expected_data_items = {} self.shape = data_item.shape if ( self.type == DatumType.recarray @@ -1580,7 +1576,7 @@ def _fpmerge_data_item(self, item, dfn_list): if item.name.lower() in mfstruct.flopy_dict: # read flopy-specific dfn data for name, value in mfstruct.flopy_dict[item.name.lower()].items(): - line = "{} {}".format(name, value) + line = f"{name} {value}" item.set_value(line, None) if dfn_list is not None: dfn_list[-1].append(line) @@ -1707,9 +1703,9 @@ def get_type_string(self): type_header = "[" type_footer = "]" if self.repeating: - type_footer = "] ... [{}]".format(type_string) + type_footer = f"] ... [{type_string}]" - return "{}{}{}".format(type_header, type_string, type_footer) + return f"{type_header}{type_string}{type_footer}" def get_docstring_type_array(self, type_array): for index, item in enumerate(self.data_item_structures): @@ -1722,11 +1718,9 @@ def get_docstring_type_array(self, type_array): or self.type == DatumType.record or self.type == DatumType.repeating_record ): - type_array.append("{}".format(item.name)) + type_array.append(str(item.name)) else: - type_array.append( - "{}".format(self._resolve_item_type(item)) - ) + type_array.append(str(self._resolve_item_type(item))) def get_description( self, line_size=79, initial_indent=" ", level_indent=" " @@ -1742,28 +1736,28 @@ def get_description( item_desc = item.get_description( line_size, initial_indent + level_indent, level_indent ) - description = "{}\n{}".format(description, item_desc) + description = f"{description}\n{item_desc}" elif datastr.display_item(index): if len(description.strip()) > 0: - description = "{}\n".format(description) + description = f"{description}\n" item_desc = item.description if item.numeric_index or item.is_cellid: # append zero-based index text - item_desc = "{} {}".format(item_desc, numeric_index_text) + item_desc = f"{item_desc} {numeric_index_text}" - item_desc = "* {} ({}) {}".format(item.name, itype, item_desc) + item_desc = f"* {item.name} ({itype}) {item_desc}" twr = TextWrapper( width=line_size, initial_indent=initial_indent, - subsequent_indent=" {}".format(initial_indent), + subsequent_indent=f" {initial_indent}", ) item_desc = "\n".join(twr.wrap(item_desc)) - description = "{}{}".format(description, item_desc) + description = f"{description}{item_desc}" if item.type == DatumType.keystring: keystr_desc = item.get_keystring_desc( line_size, initial_indent + level_indent, level_indent ) - description = "{}\n{}".format(description, keystr_desc) + description = f"{description}\n{keystr_desc}" return description def get_subpackage_description( @@ -1786,7 +1780,7 @@ def get_subpackage_description( twr = TextWrapper( width=line_size, initial_indent=initial_indent, - subsequent_indent=" {}".format(initial_indent), + subsequent_indent=f" {initial_indent}", ) return "\n".join(twr.wrap(item_desc)) @@ -1798,9 +1792,7 @@ def get_doc_string( line_size, initial_indent + level_indent, level_indent ) var_name = self.parameter_name - type_name = "{}varname:data{} or {} data".format( - "{", "}", self.construct_data - ) + type_name = f"{{varname:data}} or {self.construct_data} data" else: description = self.get_description( line_size, initial_indent + level_indent, level_indent @@ -1808,14 +1800,14 @@ def get_doc_string( var_name = self.python_name type_name = self.get_type_string() - param_doc_string = "{} : {}".format(var_name, type_name) + param_doc_string = f"{var_name} : {type_name}" twr = TextWrapper( width=line_size, initial_indent=initial_indent, - subsequent_indent=" {}".format(initial_indent), + subsequent_indent=f" {initial_indent}", ) param_doc_string = "\n".join(twr.wrap(param_doc_string)) - param_doc_string = "{}\n{}".format(param_doc_string, description) + param_doc_string = f"{param_doc_string}\n{description}" return param_doc_string def get_type_array(self, type_array): @@ -1828,7 +1820,7 @@ def get_type_array(self, type_array): ( self, index, - "{}".format(self._resolve_item_type(item)), + str(self._resolve_item_type(item)), ) ) @@ -1943,7 +1935,7 @@ class MFBlockStructure: (, , ) model_block : bool true if this block is part of a model - data_structures : OrderedDict + data_structures : dict dictionary of data items in this block, with the data item name as the key block_header_structure : list @@ -1984,7 +1976,7 @@ class MFBlockStructure: def __init__(self, name, path, model_block): # initialize - self.data_structures = OrderedDict() + self.data_structures = {} self.block_header_structure = [] self.name = name self.path = path + (self.name,) @@ -2132,7 +2124,7 @@ class MFModelStructure: simulation structure validity name_file_struct_obj : MFInputFileStructure describes the structure of the simulation name file - package_struct_objs : OrderedDict + package_struct_objs : dict describes the structure of the simulation packages model_type : string dictionary containing simulation package structure @@ -2163,7 +2155,7 @@ def __init__(self, model_type, utl_struct_objs): # add name file structure self.model_type = model_type self.name_file_struct_obj = None - self.package_struct_objs = OrderedDict() + self.package_struct_objs = {} self.utl_struct_objs = utl_struct_objs def add_namefile(self, dfn_file, common): @@ -2219,13 +2211,13 @@ class MFSimulationStructure: ---------- name_file_struct_obj : MFInputFileStructure describes the structure of the simulation name file - package_struct_objs : OrderedDict + package_struct_objs : dict describes the structure of the simulation packages - model_struct_objs : OrderedDict + model_struct_objs : dict describes the structure of the supported model types - utl_struct_objs : OrderedDict + utl_struct_objs : dict describes the structure of the supported utility packages - common : OrderedDict + common : dict common file information model_type : string placeholder @@ -2267,9 +2259,9 @@ class MFSimulationStructure: def __init__(self): # initialize self.name_file_struct_obj = None - self.package_struct_objs = OrderedDict() - self.utl_struct_objs = OrderedDict() - self.model_struct_objs = OrderedDict() + self.package_struct_objs = {} + self.utl_struct_objs = {} + self.model_struct_objs = {} self.common = None self.model_type = "" @@ -2299,9 +2291,7 @@ def process_dfn(self, dfn_file): or dfn_file.dfn_type == DfnType.gnc_file or dfn_file.dfn_type == DfnType.mvr_file ): - model_ver = "{}{}".format( - dfn_file.model_type, MFStructure(True).get_version_string() - ) + model_ver = f"{dfn_file.model_type}{MFStructure(True).get_version_string()}" if model_ver not in self.model_struct_objs: self.add_model(model_ver) if dfn_file.dfn_type == DfnType.model_file: diff --git a/dependencies/flopy/mf6/mfbase.py b/dependencies/flopy/mf6/mfbase.py index a8be86b..c1e8844 100644 --- a/dependencies/flopy/mf6/mfbase.py +++ b/dependencies/flopy/mf6/mfbase.py @@ -2,7 +2,6 @@ import importlib import inspect, sys, traceback import os, copy -from collections import OrderedDict from collections.abc import Iterable from shutil import copyfile from enum import Enum @@ -14,11 +13,6 @@ class MFInvalidTransientBlockHeaderException(Exception): Exception occurs when parsing a transient block header """ - def __init__(self, error): - Exception.__init__( - self, "MFInvalidTransientBlockHeaderException: {}".format(error) - ) - class ReadAsArraysException(Exception): """ @@ -26,9 +20,6 @@ class ReadAsArraysException(Exception): package. """ - def __init__(self, error): - Exception.__init__(self, "ReadAsArraysException: {}".format(error)) - # external exceptions for users class FlopyException(Exception): @@ -38,9 +29,7 @@ class FlopyException(Exception): def __init__(self, error, location=""): self.message = error - Exception.__init__( - self, "FlopyException: {} ({})".format(error, location) - ) + super().__init__(f"{error} ({location})") class StructException(Exception): @@ -50,9 +39,7 @@ class StructException(Exception): def __init__(self, error, location): self.message = error - Exception.__init__( - self, "StructException: {} ({})".format(error, location) - ) + super().__init__(f"{error} ({location})") class MFDataException(Exception): @@ -137,37 +124,21 @@ def __init__( self.org_type, self.org_value, self.org_traceback ) # build error string - error_message_0 = "An error occurred in " + error_message = "An error occurred in " if self.data_element is not None and self.data_element != "": - error_message_1 = 'data element "{}"' " ".format(self.data_element) - else: - error_message_1 = "" + error_message += f'data element "{self.data_element}" ' if self.model is not None and self.model != "": - error_message_2 = 'model "{}" '.format(self.model) - else: - error_message_2 = "" - error_message_3 = 'package "{}".'.format(self.package) - error_message_4 = ( - ' The error occurred while {} in the "{}" method' - ".".format(self.current_process, self.method_caught_in) + error_message += f'model "{self.model}" ' + error_message += ( + f'package "{self.package}". The error occurred while ' + f'{self.current_process} in the "{self.method_caught_in}" method.' ) if len(self.messages) > 0: - error_message_5 = "\nAdditional Information:\n" - for index, message in enumerate(self.messages): - error_message_5 = "{}({}) {}\n".format( - error_message_5, index + 1, message - ) - else: - error_message_5 = "" - error_message = "{}{}{}{}{}{}".format( - error_message_0, - error_message_1, - error_message_2, - error_message_3, - error_message_4, - error_message_5, - ) - Exception.__init__(self, error_message) + error_message += "\nAdditional Information:\n" + error_message += "\n".join( + f"({idx}) {msg}" for (idx, msg) in enumerate(self.messages, 1) + ) + super().__init__(error_message) class VerbosityLevel(Enum): @@ -221,7 +192,7 @@ class MFFileMgmt: Attributes ---------- - model_relative_path : OrderedDict + model_relative_path : dict Dictionary of relative paths to each model folder """ @@ -235,10 +206,10 @@ def __init__(self, path, mfsim=None): self.existing_file_dict = {} # keys:filenames,vals:instance name - self.model_relative_path = OrderedDict() + self.model_relative_path = {} self._last_loaded_sim_path = None - self._last_loaded_model_relative_path = OrderedDict() + self._last_loaded_model_relative_path = {} def copy_files(self, copy_relative_only=True): """Copy files external to updated path. @@ -325,9 +296,9 @@ def unique_file_name(file_name, lookup): def _build_file(file_name, num): file, ext = os.path.splitext(file_name) if ext: - return "{}_{}{}".format(file, num, ext) + return f"{file}_{num}{ext}" else: - return "{}_{}".format(file, num) + return f"{file}_{num}" @staticmethod def string_to_file_path(fp_string): @@ -339,9 +310,7 @@ def string_to_file_path(fp_string): arr_string = new_string.split(delimiter) if len(arr_string) > 1: if os.path.isabs(fp_string): - new_string = "{}{}{}".format( - arr_string[0], delimiter, arr_string[1] - ) + new_string = f"{arr_string[0]}{delimiter}{arr_string[1]}" else: new_string = os.path.join(arr_string[0], arr_string[1]) if len(arr_string) > 2: @@ -512,8 +481,8 @@ def package_factory(package_type, model_type): package : MFPackage subclass """ - package_abbr = "{}{}".format(model_type, package_type) - package_utl_abbr = "utl{}".format(package_type) + package_abbr = f"{model_type}{package_type}" + package_utl_abbr = f"utl{package_type}" package_list = [] # iterate through python files package_file_paths = PackageContainer.get_package_file_paths() @@ -592,16 +561,12 @@ def get_module(package_file_path): internal FloPy use only, not intended for end users.""" package_file_name = os.path.basename(package_file_path) module_path = os.path.splitext(package_file_name)[0] - module_name = "{}{}{}".format( - "Modflow", module_path[2].upper(), module_path[3:] - ) + module_name = f"Modflow{module_path[2].upper()}{module_path[3:]}" if module_name.startswith("__"): return None # import - return importlib.import_module( - "flopy.mf6.modflow.{}".format(module_path) - ) + return importlib.import_module(f"flopy.mf6.modflow.{module_path}") @staticmethod def get_package_file_paths(): @@ -660,6 +625,37 @@ def _remove_package(self, package): for key in items_to_remove: del self.simulation_data.mfdata[key] + def _rename_package(self, package, new_name): + # fix package_name_dict key + if ( + package.package_name is not None + and package.package_name.lower() in self.package_name_dict + ): + del self.package_name_dict[package.package_name.lower()] + self.package_name_dict[new_name.lower()] = package + # fix package_key_dict key + new_package_path = package.path[:-1] + (new_name,) + del self.package_key_dict[package.path[-1].lower()] + self.package_key_dict[new_package_path.lower()] = package + # get keys to fix in main dictionary + main_dict = self.simulation_data.mfdata + items_to_fix = [] + for key in main_dict: + is_subkey = True + for pitem, ditem in zip(package.path, key): + if pitem != ditem: + is_subkey = False + break + if is_subkey: + items_to_fix.append(key) + + # fix keys in main dictionary + for key in items_to_fix: + new_key = ( + package.path[:-1] + (new_name,) + key[len(package.path) - 1 :] + ) + main_dict[new_key] = main_dict.pop(key) + def get_package(self, name=None): """ Finds a package by package name, package key, package type, or partial diff --git a/dependencies/flopy/mf6/mfmodel.py b/dependencies/flopy/mf6/mfmodel.py index 563c8ac..17a14ec 100644 --- a/dependencies/flopy/mf6/mfmodel.py +++ b/dependencies/flopy/mf6/mfmodel.py @@ -20,6 +20,7 @@ from ..mbase import ModelInterface from .utils.mfenums import DiscretizationType from .data import mfstructure +from .utils.output_util import MF6Output from ..utils.check import mf6check @@ -56,7 +57,7 @@ class MFModel(PackageContainer, ModelInterface): Name of the model exe_name : str Model executable name - packages : OrderedDict(MFPackage) + packages : dict of MFPackage Dictionary of model packages """ @@ -73,7 +74,7 @@ def __init__( structure=None, model_rel_path=".", verbose=False, - **kwargs + **kwargs, ): super().__init__(simulation.simulation_data, modelname) self.simulation = simulation @@ -85,7 +86,7 @@ def __init__( self.type = "Model" if model_nam_file is None: - model_nam_file = "{}.nam".format(modelname) + model_nam_file = f"{modelname}.nam" if add_to_simulation: self.structure = simulation.register_model( @@ -104,7 +105,7 @@ def __init__( self._verbose = verbose if model_nam_file is None: - self.model_nam_file = "{}.nam".format(modelname) + self.model_nam_file = f"{modelname}.nam" else: self.model_nam_file = model_nam_file @@ -112,17 +113,7 @@ def __init__( xll = kwargs.pop("xll", None) yll = kwargs.pop("yll", None) self._xul = kwargs.pop("xul", None) - if self._xul is not None: - warnings.warn( - "xul/yul have been deprecated. Use xll/yll instead.", - DeprecationWarning, - ) self._yul = kwargs.pop("yul", None) - if self._yul is not None: - warnings.warn( - "xul/yul have been deprecated. Use xll/yll instead.", - DeprecationWarning, - ) rotation = kwargs.pop("rotation", 0.0) proj4 = kwargs.pop("proj4_str", None) # build model grid object @@ -135,8 +126,7 @@ def __init__( if len(kwargs) > 0: kwargs_str = ", ".join(kwargs.keys()) excpt_str = ( - 'Extraneous kwargs "{}" provided to ' - "MFModel.".format(kwargs_str) + f'Extraneous kwargs "{kwargs_str}" provided to MFModel.' ) raise FlopyException(excpt_str) @@ -144,8 +134,8 @@ def __init__( # create name file based on model type - support different model types package_obj = self.package_factory("nam", model_type[0:3]) if not package_obj: - excpt_str = "Name file could not be found for model" "{}.".format( - model_type[0:3] + excpt_str = ( + f"Name file could not be found for model{model_type[0:3]}." ) raise FlopyException(excpt_str) @@ -606,7 +596,7 @@ def output(self): try: return self.oc.output except AttributeError: - return None + return MF6Output(self) def export(self, f, **kwargs): """Method to export a model to a shapefile or netcdf file @@ -751,9 +741,9 @@ def load_base( vnum = mfstructure.MFStructure().get_version_string() # FIX: Transport - Priority packages maybe should not be hard coded priority_packages = { - "dis{}".format(vnum): 1, - "disv{}".format(vnum): 1, - "disu{}".format(vnum): 1, + f"dis{vnum}": 1, + f"disv{vnum}": 1, + f"disu{vnum}": 1, } packages_ordered = [] package_recarray = instance.simulation_data.mfdata[ @@ -786,7 +776,7 @@ def load_base( simulation.simulation_data.verbosity_level.value >= VerbosityLevel.normal.value ): - print(" skipping package {}...".format(ftype)) + print(f" skipping package {ftype}...") continue if model_rel_path and model_rel_path != ".": # strip off model relative path from the file path @@ -796,7 +786,7 @@ def load_base( simulation.simulation_data.verbosity_level.value >= VerbosityLevel.normal.value ): - print(" loading package {}...".format(ftype)) + print(f" loading package {ftype}...") # load package instance.load_package(ftype, fname, pname, strict, None) sim_data = simulation.simulation_data @@ -857,7 +847,7 @@ def write(self, ext_file_action=ExtFileAction.copy_relative_paths): self.simulation_data.verbosity_level.value >= VerbosityLevel.normal.value ): - print(" writing package {}...".format(pp._get_pname())) + print(f" writing package {pp._get_pname()}...") pp.write(ext_file_action=ext_file_action) def get_grid_type(self): @@ -873,28 +863,28 @@ def get_grid_type(self): structure = mfstructure.MFStructure() if ( package_recarray.search_data( - "dis{}".format(structure.get_version_string()), 0 + f"dis{structure.get_version_string()}", 0 ) is not None ): return DiscretizationType.DIS elif ( package_recarray.search_data( - "disv{}".format(structure.get_version_string()), 0 + f"disv{structure.get_version_string()}", 0 ) is not None ): return DiscretizationType.DISV elif ( package_recarray.search_data( - "disu{}".format(structure.get_version_string()), 0 + f"disu{structure.get_version_string()}", 0 ) is not None ): return DiscretizationType.DISU elif ( package_recarray.search_data( - "disl{}".format(structure.get_version_string()), 0 + f"disl{structure.get_version_string()}", 0 ) is not None ): @@ -1081,14 +1071,15 @@ def remove_package(self, package_name): packages = [package_name] else: packages = self.get_package(package_name) - if not isinstance(packages, list): + if not isinstance(packages, list) and packages is not None: packages = [packages] + if packages is None: + return for package in packages: if package.model_or_sim.name != self.name: except_text = ( - "Package can not be removed from model {} " - "since it is " - "not part of " + "Package can not be removed from model " + "{self.model_name} since it is not part of it." ) raise mfstructure.FlopyException(except_text) @@ -1101,7 +1092,7 @@ def remove_package(self, package_name): message = ( "Error occurred while reading package names " "from name file in model " - '"{}".'.format(self.name) + f'"{self.name}"' ) raise MFDataException( mfdata_except=mfde, @@ -1139,8 +1130,8 @@ def remove_package(self, package_name): except MFDataException as mfde: message = ( "Error occurred while setting package names " - 'from name file in model "{}". Package name ' - "data:\n{}".format(self.name, new_rec_array) + f'from name file in model "{self.name}". Package name ' + f"data:\n{new_rec_array}" ) raise MFDataException( mfdata_except=mfde, @@ -1161,6 +1152,76 @@ def remove_package(self, package_name): for child_package in child_package_list: self._remove_package_from_dictionaries(child_package) + def update_package_filename(self, package, new_name): + """ + Updates the filename for a package. For internal flopy use only. + + Parameters + ---------- + package : MFPackage + Package object + new_name : str + New package name + """ + try: + # get namefile package data + package_data = self.name_file.packages.get_data() + except MFDataException as mfde: + message = ( + "Error occurred while updating package names " + "from name file in model " + f'"{self.name}".' + ) + raise MFDataException( + mfdata_except=mfde, + model=self.model_name, + package=self.name_file._get_pname(), + message=message, + ) + try: + # update namefile package data with new name + new_rec_array = None + for item in package_data: + base, leaf = os.path.split(item[1]) + if leaf == package.filename: + item[1] = os.path.join(base, new_name) + + if new_rec_array is None: + new_rec_array = np.rec.array( + [item.tolist()], package_data.dtype + ) + else: + new_rec_array = np.hstack((item, new_rec_array)) + except: + type_, value_, traceback_ = sys.exc_info() + raise MFDataException( + self.structure.get_model(), + self.structure.get_package(), + self._path, + "updating package filename", + self.structure.name, + inspect.stack()[0][3], + type_, + value_, + traceback_, + None, + self._simulation_data.debug, + ) + try: + self.name_file.packages.set_data(new_rec_array) + except MFDataException as mfde: + message = ( + "Error occurred while updating package names " + f'from name file in model "{self.name}". Package name ' + f"data:\n{new_rec_array}" + ) + raise MFDataException( + mfdata_except=mfde, + model=self.model_name, + package=self.name_file._get_pname(), + message=message, + ) + def rename_all_packages(self, name): """Renames all package files in the model. @@ -1171,11 +1232,14 @@ def rename_all_packages(self, name): .. """ + nam_filename = f"{name}.nam" + self.simulation.rename_model_namefile(self, nam_filename) + self.name_file.filename = nam_filename + self.model_nam_file = nam_filename package_type_count = {} - self.name_file.filename = "{}.nam".format(name) for package in self.packagelist: if package.package_type not in package_type_count: - package.filename = "{}.{}".format(name, package.package_type) + package.filename = f"{name}.{package.package_type}" package_type_count[package.package_type] = 1 else: package_type_count[package.package_type] += 1 @@ -1312,7 +1376,7 @@ def register_package( package.package_name = package.package_type if set_package_filename: - package._filename = "{}.{}".format(self.name, package.package_type) + package._filename = f"{self.name}.{package.package_type}" if add_to_package_list: self._add_package(package, path) @@ -1329,7 +1393,7 @@ def register_package( # recarray self.name_file.packages.update_record( [ - "{}6".format(pkg_type), + f"{pkg_type}6", package._filename, package.package_name, ], @@ -1395,9 +1459,7 @@ def load_package( # resolve dictionary name for package if dict_package_name is not None: if parent_package is not None: - dict_package_name = "{}_{}".format( - parent_package.path[-1], ftype - ) + dict_package_name = f"{parent_package.path[-1]}_{ftype}" else: # use dict_package_name as the base name if ftype in self._ftype_num_dict: @@ -1417,8 +1479,8 @@ def load_package( if pname is not None: dict_package_name = pname else: - dict_package_name = "{}_{}".format( - ftype, self._ftype_num_dict[ftype] + dict_package_name = ( + f"{ftype}_{self._ftype_num_dict[ftype]}" ) else: dict_package_name = ftype @@ -1441,7 +1503,7 @@ def load_package( package.load(strict) except ReadAsArraysException: # create ReadAsArrays package and load it instead - package_obj = self.package_factory("{}a".format(ftype), model_type) + package_obj = self.package_factory(f"{ftype}a", model_type) package = package_obj( self, filename=fname, diff --git a/dependencies/flopy/mf6/mfpackage.py b/dependencies/flopy/mf6/mfpackage.py index d7c8705..786b65d 100644 --- a/dependencies/flopy/mf6/mfpackage.py +++ b/dependencies/flopy/mf6/mfpackage.py @@ -4,7 +4,6 @@ import inspect import datetime import numpy as np -from collections import OrderedDict from .mfbase import PackageContainer, ExtFileAction, PackageContainerType from .mfbase import ( @@ -216,7 +215,7 @@ def write_header(self, fd): File object to write block header to. """ - fd.write("BEGIN {}".format(self.name)) + fd.write(f"BEGIN {self.name}") if len(self.data_items) > 0: if isinstance(self.data_items[0], mfdatascalar.MFScalar): one_based = ( @@ -227,7 +226,7 @@ def write_header(self, fd): ) else: entry = self.data_items[0].get_file_entry() - fd.write("{}".format(entry.rstrip())) + fd.write(str(entry.rstrip())) if len(self.data_items) > 1: for data_item in self.data_items[1:]: entry = data_item.get_file_entry(values_only=True) @@ -246,7 +245,7 @@ def write_footer(self, fd): File object to write block footer to. """ - fd.write("END {}".format(self.name)) + fd.write(f"END {self.name}") if len(self.data_items) > 0: one_based = self.data_items[0].structure.type == DatumType.integer if isinstance(self.data_items[0], mfdatascalar.MFScalar): @@ -255,7 +254,7 @@ def write_footer(self, fd): ) else: entry = self.data_items[0].get_file_entry() - fd.write("{}".format(entry.rstrip())) + fd.write(str(entry.rstrip())) fd.write("\n") def get_transient_key(self): @@ -347,7 +346,7 @@ def __init__( ] self.structure = structure self.path = path - self.datasets = OrderedDict() + self.datasets = {} self.datasets_keyword = {} # initially disable if optional self.enabled = structure.number_non_optional_data() > 0 @@ -367,14 +366,14 @@ def _get_data_str(self, formal): if formal: ds_repr = repr(dataset) if len(ds_repr.strip()) > 0: - data_str = "{}{}\n{}\n".format( - data_str, dataset.structure.name, repr(dataset) + data_str = ( + f"{data_str}{dataset.structure.name}\n{dataset!r}\n" ) else: ds_str = str(dataset) if len(ds_str.strip()) > 0: - data_str = "{}{}\n{}\n".format( - data_str, dataset.structure.name, str(dataset) + data_str = ( + f"{data_str}{dataset.structure.name}\n{dataset!s}\n" ) return data_str @@ -816,8 +815,7 @@ def load(self, block_header, fd, strict=True): >= VerbosityLevel.verbose.value ): print( - ' opening external file "{}"..' - ".".format(file_name) + f' opening external file "{file_name}"...' ) external_file_info = arr_line fd_block = open(os.path.join(root_path, arr_line[1]), "r") @@ -826,10 +824,7 @@ def load(self, block_header, fd, strict=True): arr_line = datautil.PyListUtil.split_data_line(line) except: type_, value_, traceback_ = sys.exc_info() - message = ( - "Error reading external file specified in " - 'line "{}"'.format(line) - ) + message = f'Error reading external file specified in line "{line}"' raise MFDataException( self._container_package.model_name, self._container_package._get_pname(), @@ -852,8 +847,7 @@ def load(self, block_header, fd, strict=True): >= VerbosityLevel.verbose.value ): print( - " loading data {}.." - ".".format(dataset.structure.name) + f" loading data {dataset.structure.name}..." ) next_line = dataset.load( line, @@ -883,8 +877,7 @@ def load(self, block_header, fd, strict=True): >= VerbosityLevel.verbose.value ): print( - " loading child package {}.." - ".".format(package_info[0]) + f" loading child package {package_info[0]}..." ) pkg = self._model_or_sim.load_package( package_info[0], @@ -930,7 +923,7 @@ def load(self, block_header, fd, strict=True): line, fd_block, initial_comment ) except MFInvalidTransientBlockHeaderException as e: - warning_str = "WARNING: {}".format(e) + warning_str = f"WARNING: {e}" print(warning_str) self.block_headers.pop() return @@ -979,7 +972,7 @@ def _find_data_by_keyword(self, line, fd, initial_comment): self._simulation_data.verbosity_level.value >= VerbosityLevel.verbose.value ): - print(" loading data {}...".format(ds_name)) + print(f" loading data {ds_name}...") next_line = self.datasets[ds_name].load( next_line[1], fd, @@ -1009,8 +1002,7 @@ def _find_data_by_keyword(self, line, fd, initial_comment): >= VerbosityLevel.verbose.value ): print( - " loading child package {}.." - ".".format(package_info[1]) + f" loading child package {package_info[1]}..." ) pkg = self._model_or_sim.load_package( package_info[0], @@ -1066,8 +1058,7 @@ def _find_data_by_keyword(self, line, fd, initial_comment): >= VerbosityLevel.verbose.value ): print( - " loading child package {}.." - ".".format(package_info[0]) + f" loading child package {package_info[0]}..." ) pkg = self._model_or_sim.load_package( package_info[0], @@ -1123,9 +1114,7 @@ def _get_package_info(self, dataset): file_location = data package_info_list = [] file_path, file_name = os.path.split(file_location) - dict_package_name = "{}_{}".format( - package_type, self.path[-2] - ) + dict_package_name = f"{package_type}_{self.path[-2]}" package_info_list.append( (package_type, file_name, file_path, dict_package_name) ) @@ -1215,9 +1204,7 @@ def set_all_data_external( ) and dataset.enabled ): - file_path = "{}_{}.txt".format( - base_name, dataset.structure.name - ) + file_path = f"{base_name}_{dataset.structure.name}.txt" if external_data_folder is not None: # get simulation root path root_path = self._simulation_data.mfpath.get_sim_path() @@ -1281,19 +1268,15 @@ def _write_block(self, fd, block_header, ext_file_action): if self.external_file_name is not None: # write block contents to external file indent_string = self._simulation_data.indent_string - fd.write( - "{}open/close {}\n".format( - indent_string, self.external_file_name - ) - ) + fd.write(f"{indent_string}open/close {self.external_file_name}\n") fd_main = fd fd_path = os.path.split(os.path.realpath(fd.name))[0] try: fd = open(os.path.join(fd_path, self.external_file_name), "w") except: type_, value_, traceback_ = sys.exc_info() - message = "Error reading external file " '"{}"'.format( - self.external_file_name + message = ( + f'Error reading external file "{self.external_file_name}"' ) raise MFDataException( self._container_package.model_name, @@ -1318,8 +1301,7 @@ def _write_block(self, fd, block_header, ext_file_action): >= VerbosityLevel.verbose.value ): print( - " writing data {}.." - ".".format(dataset.structure.name) + f" writing data {dataset.structure.name}..." ) fd.write( dataset.get_file_entry(ext_file_action=ext_file_action) @@ -1350,10 +1332,10 @@ def _write_block(self, fd, block_header, ext_file_action): mfdata_except=mfde, model=self._container_package.model_name, package=self._container_package._get_pname(), - message="Error occurred while writing " - 'data "{}" in block "{}" to file' - ' "{}".'.format( - dataset.structure.name, self.structure.name, fd.name + message=( + "Error occurred while writing data " + f'"{dataset.structure.name}" in block ' + f'"{self.structure.name}" to file "{fd.name}"' ), ) # write trailing comments @@ -1475,7 +1457,7 @@ class MFPackage(PackageContainer, PackageInterface): Attributes ---------- - blocks : OrderedDict + blocks : dict Dictionary of blocks contained in this package by block name path : tuple Data dictionary path to this package @@ -1504,6 +1486,10 @@ def __init__( else: self.model_name = None + # a package must have a dfn_file_name + if not hasattr(self, "dfn_file_name"): + self.dfn_file_name = "" + if model_or_sim.type != "Model" and model_or_sim.type != "Simulation": message = ( "Invalid model_or_sim parameter. Expecting either a " @@ -1515,7 +1501,7 @@ def __init__( self.model_name, pname, "", - "initializing " "package", + "initializing package", None, inspect.stack()[0][3], type_, @@ -1530,7 +1516,7 @@ def __init__( self.parent = model_or_sim self._simulation_data = model_or_sim.simulation_data self.parent_file = parent_file - self.blocks = OrderedDict() + self.blocks = {} self.container_type = [] self.loading_package = loading_package if pname is not None: @@ -1561,7 +1547,7 @@ def __init__( if filename is None: self._filename = MFFileMgmt.string_to_file_path( - "{}.{}".format(self.model_or_sim.name, package_type) + f"{self.model_or_sim.name}.{package_type}" ) else: if not isinstance(filename, str): @@ -1656,8 +1642,11 @@ def filename(self, fname): except Exception: print( "WARNING: Unable to update file name for parent" - "package of {}.".format(self.name) + f"package of {self.package_name}." ) + if self.model_or_sim is not None and fname is not None: + if self._package_type != "nam": + self.model_or_sim.update_package_filename(self, fname) self._filename = fname @property @@ -1740,11 +1729,11 @@ def _get_data_str(self, formal, show_data=True): ) ) if self.parent_file is not None and formal: - data_str = "{}parent_file = " "{}\n\n".format( - data_str, self.parent_file._get_pname() + data_str = ( + f"{data_str}parent_file = {self.parent_file._get_pname()}\n\n" ) else: - data_str = "{}\n".format(data_str) + data_str = f"{data_str}\n" if show_data: for block in self.blocks.values(): if formal: @@ -1769,9 +1758,9 @@ def _get_data_str(self, formal, show_data=True): def _get_pname(self): if self.package_name is not None: - return "{}".format(self.package_name) + return str(self.package_name) else: - return "{}".format(self._filename) + return str(self._filename) def _get_block_header_info(self, line, path): # init @@ -1855,7 +1844,7 @@ def _update_size_defs(self): for key in dataset.get_active_key_list(): try: data = dataset.get_data(key=key[0]) - except (IOError, OSError, MFDataException): + except (OSError, MFDataException): # TODO: Handle case where external file # path has been moved data = None @@ -1868,7 +1857,7 @@ def _update_size_defs(self): new_size = -1 try: data = dataset.get_data() - except (IOError, OSError, MFDataException): + except (OSError, MFDataException): # TODO: Handle case where external file # path has been moved data = None @@ -1885,8 +1874,7 @@ def _update_size_defs(self): ): print( "INFORMATION: {} in {} changed to {} " - "based on size of " - "{}".format( + "based on size of {}".format( size_def_name, size_def.structure.path[:-1], new_size, @@ -1908,7 +1896,7 @@ def build_child_packages_container(self, pkg_type, filerecord): pkg_type, self.model_or_sim.model_type ) # create child package object - child_pkgs_name = "utl{}packages".format(pkg_type) + child_pkgs_name = f"utl{pkg_type}packages" child_pkgs_obj = self.package_factory(child_pkgs_name, "") child_pkgs = child_pkgs_obj( self.model_or_sim, self, pkg_type, filerecord, None, package_obj @@ -2091,7 +2079,7 @@ def load(self, strict=True): fd_input_file = open(self.get_file_path(), "r") except OSError as e: if e.errno == errno.ENOENT: - message = "File {} of type {} could not be opened" ".".format( + message = "File {} of type {} could not be opened.".format( self.get_file_path(), self.package_type ) type_, value_, traceback_ = sys.exc_info() @@ -2139,15 +2127,13 @@ def is_valid(self): and not block.enabled and block.is_allowed() ): - self.last_error = 'Required block "{}" not ' "enabled".format( - block.block_header.name + self.last_error = ( + f'Required block "{block.block_header.name}" not enabled' ) return False # Enabled blocks must be valid if block.enabled and not block.is_valid: - self.last_error = "Invalid block " '"{}"'.format( - block.block_header.name - ) + self.last_error = f'Invalid block "{block.block_header.name}"' return False return True @@ -2201,9 +2187,7 @@ def _load_blocks(self, fd_input_file, strict=True, max_blocks=sys.maxsize): # resolve the correct block to use block_key = block_header_info.name.lower() block_num = 1 - possible_key = "{}-{}".format( - block_header_info.name.lower(), block_num - ) + possible_key = f"{block_header_info.name.lower()}-{block_num}" if possible_key in self.blocks: block_key = possible_key block_header_name = block_header_info.name.lower() @@ -2211,9 +2195,7 @@ def _load_blocks(self, fd_input_file, strict=True, max_blocks=sys.maxsize): block_key in self.blocks and not self.blocks[block_key].is_allowed() ): - block_key = "{}-{}".format( - block_header_name, block_num - ) + block_key = f"{block_header_name}-{block_num}" block_num += 1 if block_key not in self.blocks: @@ -2286,9 +2268,7 @@ def _load_blocks(self, fd_input_file, strict=True, max_blocks=sys.maxsize): >= VerbosityLevel.verbose.value ): print( - " loading block {}...".format( - cur_block.structure.name - ) + f" loading block {cur_block.structure.name}..." ) # reset comments self.post_block_comments = MFComment( @@ -2312,9 +2292,7 @@ def _load_blocks(self, fd_input_file, strict=True, max_blocks=sys.maxsize): arr_line = datautil.PyListUtil.split_data_line( clean_line ) - self.post_block_comments.add_text( - "{}".format(line), True - ) + self.post_block_comments.add_text(str(line), True) while arr_line and ( len(line) <= 2 or arr_line[0][:3].upper() != "END" ): @@ -2324,7 +2302,7 @@ def _load_blocks(self, fd_input_file, strict=True, max_blocks=sys.maxsize): ) if arr_line: self.post_block_comments.add_text( - "{}".format(line), True + str(line), True ) self._simulation_data.mfdata[ cur_block.block_headers[-1].blk_post_comment_path @@ -2414,6 +2392,61 @@ def create_package_dimensions(self): ), ] break + elif ( + self.dfn_file_name[4:7] == "gnc" + and self.model_or_sim.type == "Simulation" + ): + # get exchange file name associated with gnc package + exg_file_name = None + for exg in self.model_or_sim.exchange_files: + gnc_data = exg.gnc_filerecord.get_data() + if ( + gnc_data is not None + and gnc_data[0][0].lower() == self.filename.lower() + ): + exg_file_name = exg.filename + self.parent = exg + if exg_file_name is None: + raise Exception( + "Can not create a simulation-level " + "gnc file without a corresponding " + "exchange file. Exchange file must be " + "created first." + ) + # get models associated with exchange file from sim nam file + try: + exchange_recarray_data = ( + self.model_or_sim.name_file.exchanges.get_data() + ) + except MFDataException as mfde: + message = ( + "An error occurred while retrieving exchange " + "data from the simulation name file. The error " + "occurred while processing gnc file " + f'"{self.filename}".' + ) + raise MFDataException( + mfdata_except=mfde, + package=self._get_pname(), + message=message, + ) + assert exchange_recarray_data is not None + model_1 = None + model_2 = None + for exchange in exchange_recarray_data: + if exchange[1] == exg_file_name: + model_1 = exchange[2] + model_2 = exchange[3] + + # assign models to gnc package + model_dims = [ + modeldimensions.ModelDimensions( + model_1, self._simulation_data + ), + modeldimensions.ModelDimensions( + model_2, self._simulation_data + ), + ] elif self.parent_file is not None: model_dims = [] for md in self.parent_file.dimensions.model_dim: @@ -2479,9 +2512,7 @@ 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(f" writing block {block.structure.name}...") # write block block.write(fd, ext_file_action=ext_file_action) block_num += 1 @@ -2608,7 +2639,7 @@ def __getitem__(self, k): if isinstance(k, int): if k < len(self._packages): return self._packages[k] - raise ValueError("Package index {} does not exist.".format(k)) + raise ValueError(f"Package index {k} does not exist.") def __setattr__(self, key, value): if ( @@ -2640,13 +2671,11 @@ def __default_file_path_base(self, file_path, suffix=""): file_name = ".".join(stem_lst[:-1]) if len(stem_lst) > 1: file_ext = stem_lst[-1] - return "{}.{}{}.{}".format( - file_name, file_ext, suffix, self._pkg_type - ) + return f"{file_name}.{file_ext}{suffix}.{self._pkg_type}" elif suffix != "": - return "{}.{}".format(stem, self._pkg_type) + return f"{stem}.{self._pkg_type}" else: - return "{}.{}.{}".format(stem, suffix, self._pkg_type) + return f"{stem}.{suffix}.{self._pkg_type}" def __file_path_taken(self, possible_path): for package in self._packages: @@ -2683,8 +2712,14 @@ def _update_filename(self, old_fname, new_fname): if file_record is not None: file_record_data = file_record[0] for item in file_record_data: - if item.lower() == old_fname.lower(): - new_file_record_data.append((new_fname,)) + base, fname = os.path.split(item) + if fname.lower() == old_fname.lower(): + if base: + new_file_record_data.append( + (os.path.join(base, new_fname),) + ) + else: + new_file_record_data.append((new_fname,)) else: new_file_record_data.append((item,)) else: diff --git a/dependencies/flopy/mf6/modflow/__init__.py b/dependencies/flopy/mf6/modflow/__init__.py index 72a6352..9b6f025 100644 --- a/dependencies/flopy/mf6/modflow/__init__.py +++ b/dependencies/flopy/mf6/modflow/__init__.py @@ -10,6 +10,7 @@ from .mfutlobs import ModflowUtlobs from .mfutlts import ModflowUtlts from .mfutltas import ModflowUtltas +from .mfutlats import ModflowUtlats from .mfutllaktab import ModflowUtllaktab from .mfgwfnam import ModflowGwfnam from .mfgwf import ModflowGwf @@ -36,26 +37,27 @@ from .mfgwfmvr import ModflowGwfmvr from .mfgwfgnc import ModflowGwfgnc from .mfgwfoc import ModflowGwfoc -from .mfgwfapi import ModflowGwfapi -from .mfgwfbuy import ModflowGwfbuy from .mfgwfcsub import ModflowGwfcsub +from .mfgwfbuy import ModflowGwfbuy +from .mfgwfapi import ModflowGwfapi from .mfgwtnam import ModflowGwtnam from .mfgwt import ModflowGwt -from .mfgwtadv import ModflowGwtadv +from .mfgwtuzt import ModflowGwtuzt +from .mfgwtapi import ModflowGwtapi +from .mfgwtmvt import ModflowGwtmvt +from .mfgwtdsp import ModflowGwtdsp +from .mfgwtssm import ModflowGwtssm +from .mfgwtmwt import ModflowGwtmwt from .mfgwtcnc import ModflowGwtcnc -from .mfgwtdis import ModflowGwtdis -from .mfgwtdisu import ModflowGwtdisu +from .mfgwtsft import ModflowGwtsft from .mfgwtdisv import ModflowGwtdisv -from .mfgwtdsp import ModflowGwtdsp -from .mfgwtfmi import ModflowGwtfmi +from .mfgwtlkt import ModflowGwtlkt from .mfgwtic import ModflowGwtic +from .mfgwtdisu import ModflowGwtdisu +from .mfgwtsrc import ModflowGwtsrc +from .mfgwtdis import ModflowGwtdis +from .mfgwtoc import ModflowGwtoc +from .mfgwtadv import ModflowGwtadv +from .mfgwtfmi import ModflowGwtfmi from .mfgwtist import ModflowGwtist -from .mfgwtlkt import ModflowGwtlkt from .mfgwtmst import ModflowGwtmst -from .mfgwtmvt import ModflowGwtmvt -from .mfgwtmwt import ModflowGwtmwt -from .mfgwtoc import ModflowGwtoc -from .mfgwtsft import ModflowGwtsft -from .mfgwtsrc import ModflowGwtsrc -from .mfgwtssm import ModflowGwtssm -from .mfgwtuzt import ModflowGwtuzt diff --git a/dependencies/flopy/mf6/modflow/mfgnc.py b/dependencies/flopy/mf6/modflow/mfgnc.py index 42719a5..9a6427e 100644 --- a/dependencies/flopy/mf6/modflow/mfgnc.py +++ b/dependencies/flopy/mf6/modflow/mfgnc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwf.py b/dependencies/flopy/mf6/modflow/mfgwf.py index e78ba28..ac62815 100644 --- a/dependencies/flopy/mf6/modflow/mfgwf.py +++ b/dependencies/flopy/mf6/modflow/mfgwf.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfmodel from ..data.mfdatautil import ListTemplateGenerator, ArrayTemplateGenerator @@ -19,8 +19,8 @@ class ModflowGwf(mfmodel.MFModel): version of modflow exe_name : string model executable name - model_rel_path : string - model working folder path, relative to simulation directory. + model_ws : string + model working folder path sim : MFSimulation Simulation that this model is a part of. Model is automatically added to simulation when it is initialized. diff --git a/dependencies/flopy/mf6/modflow/mfgwfapi.py b/dependencies/flopy/mf6/modflow/mfgwfapi.py index 6ff23bc..75ea59f 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfapi.py +++ b/dependencies/flopy/mf6/modflow/mfgwfapi.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on July 15, 2021 21:04:25 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfbuy.py b/dependencies/flopy/mf6/modflow/mfgwfbuy.py index 49e0aca..11361b5 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfbuy.py +++ b/dependencies/flopy/mf6/modflow/mfgwfbuy.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator @@ -60,7 +60,7 @@ class ModflowGwfbuy(mfpackage.MFPackage): value used for this species in the density equation of state. * modelname (string) name of GWT model used to simulate a species that will be used in the density equation of state. This name will have no - affect if the simulation does not include a GWT model that + effect if the simulation does not include a GWT model that corresponds to this GWF model. * auxspeciesname (string) name of an auxiliary variable in a GWF stress package that will be used for this species to calculate a density diff --git a/dependencies/flopy/mf6/modflow/mfgwfchd.py b/dependencies/flopy/mf6/modflow/mfgwfchd.py index f015de8..8098a4e 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfchd.py +++ b/dependencies/flopy/mf6/modflow/mfgwfchd.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfcsub.py b/dependencies/flopy/mf6/modflow/mfgwfcsub.py index d9f99d3..1f18bb7 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfcsub.py +++ b/dependencies/flopy/mf6/modflow/mfgwfcsub.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator, ArrayTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfdis.py b/dependencies/flopy/mf6/modflow/mfgwfdis.py index 9ce7fbc..03c35d1 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfdis.py +++ b/dependencies/flopy/mf6/modflow/mfgwfdis.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfdisu.py b/dependencies/flopy/mf6/modflow/mfgwfdisu.py index 0bb7c3c..b4e92ee 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfdisu.py +++ b/dependencies/flopy/mf6/modflow/mfgwfdisu.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator @@ -45,6 +45,14 @@ class ModflowGwfdisu(mfpackage.MFPackage): The value for ANGROT does not affect the model simulation, but it is written to the binary grid file so that postprocessors can locate the grid in space. + vertical_offset_tolerance : double + * vertical_offset_tolerance (double) checks are performed to ensure + that the top of a cell is not higher than the bottom of an overlying + cell. This option can be used to specify the tolerance that is used + for checking. If top of a cell is above the bottom of an overlying + cell by a value less than this tolerance, then the program will not + terminate with an error. The default value is zero. This option + should generally not be used. nodes : integer * nodes (integer) is the number of cells in the model grid. nja : integer @@ -232,6 +240,14 @@ class ModflowGwfdisu(mfpackage.MFPackage): "reader urword", "optional true", ], + [ + "block options", + "name vertical_offset_tolerance", + "type double precision", + "reader urword", + "optional true", + "default_value 0.0", + ], [ "block dimensions", "name nodes", @@ -433,6 +449,7 @@ def __init__( xorigin=None, yorigin=None, angrot=None, + vertical_offset_tolerance=0.0, nodes=None, nja=None, nvert=None, @@ -462,6 +479,9 @@ def __init__( self.xorigin = self.build_mfdata("xorigin", xorigin) self.yorigin = self.build_mfdata("yorigin", yorigin) self.angrot = self.build_mfdata("angrot", angrot) + self.vertical_offset_tolerance = self.build_mfdata( + "vertical_offset_tolerance", vertical_offset_tolerance + ) self.nodes = self.build_mfdata("nodes", nodes) self.nja = self.build_mfdata("nja", nja) self.nvert = self.build_mfdata("nvert", nvert) diff --git a/dependencies/flopy/mf6/modflow/mfgwfdisv.py b/dependencies/flopy/mf6/modflow/mfgwfdisv.py index 5db122b..5e2794b 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfdisv.py +++ b/dependencies/flopy/mf6/modflow/mfgwfdisv.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfdrn.py b/dependencies/flopy/mf6/modflow/mfgwfdrn.py index f796560..1032add 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfdrn.py +++ b/dependencies/flopy/mf6/modflow/mfgwfdrn.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfevt.py b/dependencies/flopy/mf6/modflow/mfgwfevt.py index fe8f25a..53cf439 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfevt.py +++ b/dependencies/flopy/mf6/modflow/mfgwfevt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfevta.py b/dependencies/flopy/mf6/modflow/mfgwfevta.py index 68fd7a7..90bfa1d 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfevta.py +++ b/dependencies/flopy/mf6/modflow/mfgwfevta.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator, ArrayTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfghb.py b/dependencies/flopy/mf6/modflow/mfgwfghb.py index 17a0f87..fa3eae5 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfghb.py +++ b/dependencies/flopy/mf6/modflow/mfgwfghb.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfgnc.py b/dependencies/flopy/mf6/modflow/mfgwfgnc.py index 7123f19..c9dda0d 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfgnc.py +++ b/dependencies/flopy/mf6/modflow/mfgwfgnc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfgwf.py b/dependencies/flopy/mf6/modflow/mfgwfgwf.py index 243164e..3a0eac1 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfgwf.py +++ b/dependencies/flopy/mf6/modflow/mfgwfgwf.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfgwt.py b/dependencies/flopy/mf6/modflow/mfgwfgwt.py index 16fbcc0..fcb2ccd 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfgwt.py +++ b/dependencies/flopy/mf6/modflow/mfgwfgwt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage diff --git a/dependencies/flopy/mf6/modflow/mfgwfhfb.py b/dependencies/flopy/mf6/modflow/mfgwfhfb.py index 2c75edd..466a2d7 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfhfb.py +++ b/dependencies/flopy/mf6/modflow/mfgwfhfb.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfic.py b/dependencies/flopy/mf6/modflow/mfgwfic.py index 8cb9f84..a00cda0 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfic.py +++ b/dependencies/flopy/mf6/modflow/mfgwfic.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwflak.py b/dependencies/flopy/mf6/modflow/mfgwflak.py index 6f6cf79..9ef8510 100644 --- a/dependencies/flopy/mf6/modflow/mfgwflak.py +++ b/dependencies/flopy/mf6/modflow/mfgwflak.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfmaw.py b/dependencies/flopy/mf6/modflow/mfgwfmaw.py index 86b6e71..5832160 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfmaw.py +++ b/dependencies/flopy/mf6/modflow/mfgwfmaw.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfmvr.py b/dependencies/flopy/mf6/modflow/mfgwfmvr.py index 64a6201..6cc9224 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfmvr.py +++ b/dependencies/flopy/mf6/modflow/mfgwfmvr.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfnam.py b/dependencies/flopy/mf6/modflow/mfgwfnam.py index 26e36f9..1106adf 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfnam.py +++ b/dependencies/flopy/mf6/modflow/mfgwfnam.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfnpf.py b/dependencies/flopy/mf6/modflow/mfgwfnpf.py index a7bfdc4..c41c5f1 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfnpf.py +++ b/dependencies/flopy/mf6/modflow/mfgwfnpf.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator, ArrayTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfoc.py b/dependencies/flopy/mf6/modflow/mfgwfoc.py index 18010a0..e750e3a 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfoc.py +++ b/dependencies/flopy/mf6/modflow/mfgwfoc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfrch.py b/dependencies/flopy/mf6/modflow/mfgwfrch.py index 8022797..40abe13 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfrch.py +++ b/dependencies/flopy/mf6/modflow/mfgwfrch.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfrcha.py b/dependencies/flopy/mf6/modflow/mfgwfrcha.py index 38c43e4..2f0a01a 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfrcha.py +++ b/dependencies/flopy/mf6/modflow/mfgwfrcha.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator, ArrayTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfriv.py b/dependencies/flopy/mf6/modflow/mfgwfriv.py index 826dedf..fb4fd6e 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfriv.py +++ b/dependencies/flopy/mf6/modflow/mfgwfriv.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwfsfr.py b/dependencies/flopy/mf6/modflow/mfgwfsfr.py index 77dbce2..c1d8ef5 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfsfr.py +++ b/dependencies/flopy/mf6/modflow/mfgwfsfr.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator @@ -233,19 +233,19 @@ class ModflowGwfsfr(mfpackage.MFPackage): :math:`Q_{DS}` from reach RNO is set equal to DIVFLOW. This represents a flood-control type of diversion, as described by Danskin and Hanson (2002). (3) CPRIOR = 'THRESHOLD', then if :math:`Q_{DS}` - in reach RNO is less than the specified diversion flow (DIVFLOW), no + in reach RNO is less than the specified diversion flow DIVFLOW, no water is diverted from reach RNO. If :math:`Q_{DS}` in reach RNO is - greater than or equal to (DIVFLOW), (DIVFLOW) is diverted and + greater than or equal to DIVFLOW, DIVFLOW is diverted and :math:`Q_{DS}` is set to the remainder (:math:`Q_{DS} -` DIVFLOW)). This approach assumes that once flow in the stream is sufficiently low, diversions from the stream cease, and is the 'priority' algorithm that originally was programmed into the STR1 Package (Prudic, 1989). (4) CPRIOR = 'UPTO' -- if :math:`Q_{DS}` in reach RNO - is greater than or equal to the specified diversion flow (DIVFLOW), + is greater than or equal to the specified diversion flow DIVFLOW, :math:`Q_{DS}` is reduced by DIVFLOW. If :math:`Q_{DS}` in reach RNO - is less than (DIVFLOW), DIVFLOW is set to :math:`Q_{DS}` and there - will be no flow available for reaches connected to downstream end of - reach RNO. + is less than DIVFLOW, DIVFLOW is set to :math:`Q_{DS}` and there will + be no flow available for reaches connected to downstream end of reach + RNO. perioddata : [rno, sfrsetting] * rno (integer) integer value that defines the reach number associated with the specified PERIOD data on the line. RNO must be greater than diff --git a/dependencies/flopy/mf6/modflow/mfgwfsto.py b/dependencies/flopy/mf6/modflow/mfgwfsto.py index f2fe53d..a948904 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfsto.py +++ b/dependencies/flopy/mf6/modflow/mfgwfsto.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator @@ -24,6 +24,12 @@ class ModflowGwfsto(mfpackage.MFPackage): storagecoefficient : boolean * storagecoefficient (boolean) keyword to indicate that the SS array is read as storage coefficient rather than specific storage. + ss_confined_only : boolean + * ss_confined_only (boolean) keyword to indicate that specific storage + is only calculated when a cell is under confined conditions (head + greater than or equal to the top of the cell). This option is + identical to the approach used to calculate storage changes under + confined conditions in MODFLOW-2005. iconvert : [integer] * iconvert (integer) is a flag for each cell that specifies whether or not a cell is convertible for the storage calculation. 0 indicates @@ -83,6 +89,13 @@ class ModflowGwfsto(mfpackage.MFPackage): "reader urword", "optional true", ], + [ + "block options", + "name ss_confined_only", + "type keyword", + "reader urword", + "optional true", + ], [ "block griddata", "name iconvert", @@ -154,6 +167,7 @@ def __init__( loading_package=False, save_flows=None, storagecoefficient=None, + ss_confined_only=None, iconvert=0, ss=1.0e-5, sy=0.15, @@ -172,6 +186,9 @@ def __init__( self.storagecoefficient = self.build_mfdata( "storagecoefficient", storagecoefficient ) + self.ss_confined_only = self.build_mfdata( + "ss_confined_only", ss_confined_only + ) self.iconvert = self.build_mfdata("iconvert", iconvert) self.ss = self.build_mfdata("ss", ss) self.sy = self.build_mfdata("sy", sy) diff --git a/dependencies/flopy/mf6/modflow/mfgwfuzf.py b/dependencies/flopy/mf6/modflow/mfgwfuzf.py index 6db7871..3c4f4d7 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfuzf.py +++ b/dependencies/flopy/mf6/modflow/mfgwfuzf.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator @@ -50,6 +50,9 @@ class ModflowGwfuzf(mfpackage.MFPackage): * save_flows (boolean) keyword to indicate that UZF flow terms will be written to the file specified with "BUDGET FILEOUT" in Output Control. + wc_filerecord : [wcfile] + * wcfile (string) name of the binary output file to write water content + information. budget_filerecord : [budgetfile] * budgetfile (string) name of the binary output file to write budget information. @@ -151,13 +154,26 @@ class ModflowGwfuzf(mfpackage.MFPackage): Flopy will automatically subtract one when loading index variables and add one when writing index variables. * surfdep (double) is the surface depression depth of the UZF cell. - * vks (double) is the vertical saturated hydraulic conductivity of the - UZF cell. + * vks (double) is the saturated vertical hydraulic conductivity of the + UZF cell. This value is used with the Brooks-Corey function and the + simulated water content to calculate the partially saturated + hydraulic conductivity. * thtr (double) is the residual (irreducible) water content of the UZF - cell. - * thts (double) is the saturated water content of the UZF cell. - * thti (double) is the initial water content of the UZF cell. - * eps (double) is the epsilon exponent of the UZF cell. + cell. This residual water is not available to plants and will not + drain into underlying aquifer cells. + * thts (double) is the saturated water content of the UZF cell. The + values for saturated and residual water content should be set in a + manner that is consistent with the specific yield value specified in + the Storage Package. The saturated water content must be greater than + the residual content. + * thti (double) is the initial water content of the UZF cell. The value + must be greater than or equal to the residual water content and less + than or equal to the saturated water content. + * eps (double) is the exponent used in the Brooks-Corey function. The + Brooks-Corey function is used by UZF to calculated hydraulic + conductivity under partially saturated conditions as a function of + water content and the user-specified saturated hydraulic + conductivity. * boundname (string) name of the UZF cell cell. BOUNDNAME is an ASCII character variable that can contain as many as 40 characters. If BOUNDNAME contains spaces in it, then the entire name must be @@ -197,10 +213,15 @@ class ModflowGwfuzf(mfpackage.MFPackage): * extwc (string) real or character value that defines the evapotranspiration extinction water content of the UZF cell. EXTWC is always specified, but is only used if SIMULATE_ET and UNSAT_ETWC are - specified in the OPTIONS block. If the Options block includes a - TIMESERIESFILE entry (see the "Time-Variable Input" section), values - can be obtained from a time series by entering the time-series name - in place of a numeric value. + specified in the OPTIONS block. The evapotranspiration rate from the + unsaturated zone will be set to zero when the calculated water + content is at or less than this value. The value for EXTWC cannot be + less than the residual water content, and if it is specified as being + less than the residual water content it is set to the residual water + content. If the Options block includes a TIMESERIESFILE entry (see + the "Time-Variable Input" section), values can be obtained from a + time series by entering the time-series name in place of a numeric + value. * ha (string) real or character value that defines the air entry potential (head) of the UZF cell. HA is always specified, but is only used if SIMULATE_ET and UNSAT_ETAE are specified in the OPTIONS @@ -242,6 +263,9 @@ class ModflowGwfuzf(mfpackage.MFPackage): """ auxiliary = ListTemplateGenerator(("gwf6", "uzf", "options", "auxiliary")) + wc_filerecord = ListTemplateGenerator( + ("gwf6", "uzf", "options", "wc_filerecord") + ) budget_filerecord = ListTemplateGenerator( ("gwf6", "uzf", "options", "budget_filerecord") ) @@ -308,6 +332,36 @@ class ModflowGwfuzf(mfpackage.MFPackage): "reader urword", "optional true", ], + [ + "block options", + "name wc_filerecord", + "type record water_content fileout wcfile", + "shape", + "reader urword", + "tagged true", + "optional true", + ], + [ + "block options", + "name water_content", + "type keyword", + "shape", + "in_record true", + "reader urword", + "tagged true", + "optional false", + ], + [ + "block options", + "name wcfile", + "type string", + "preserve_case true", + "shape", + "in_record true", + "reader urword", + "tagged false", + "optional false", + ], [ "block options", "name budget_filerecord", @@ -763,6 +817,7 @@ def __init__( print_input=None, print_flows=None, save_flows=None, + wc_filerecord=None, budget_filerecord=None, package_convergence_filerecord=None, timeseries=None, @@ -794,6 +849,7 @@ def __init__( self.print_input = self.build_mfdata("print_input", print_input) self.print_flows = self.build_mfdata("print_flows", print_flows) self.save_flows = self.build_mfdata("save_flows", save_flows) + self.wc_filerecord = self.build_mfdata("wc_filerecord", wc_filerecord) self.budget_filerecord = self.build_mfdata( "budget_filerecord", budget_filerecord ) diff --git a/dependencies/flopy/mf6/modflow/mfgwfwel.py b/dependencies/flopy/mf6/modflow/mfgwfwel.py index 04c37e4..032eca4 100644 --- a/dependencies/flopy/mf6/modflow/mfgwfwel.py +++ b/dependencies/flopy/mf6/modflow/mfgwfwel.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwt.py b/dependencies/flopy/mf6/modflow/mfgwt.py index d790b6e..90ace90 100644 --- a/dependencies/flopy/mf6/modflow/mfgwt.py +++ b/dependencies/flopy/mf6/modflow/mfgwt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfmodel from ..data.mfdatautil import ListTemplateGenerator, ArrayTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwtadv.py b/dependencies/flopy/mf6/modflow/mfgwtadv.py index fe73294..f7c99ea 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtadv.py +++ b/dependencies/flopy/mf6/modflow/mfgwtadv.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage diff --git a/dependencies/flopy/mf6/modflow/mfgwtapi.py b/dependencies/flopy/mf6/modflow/mfgwtapi.py new file mode 100644 index 0000000..8b23155 --- /dev/null +++ b/dependencies/flopy/mf6/modflow/mfgwtapi.py @@ -0,0 +1,189 @@ +# DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY +# mf6/utils/createpackages.py +# FILE created on August 06, 2021 20:57:00 UTC +from .. import mfpackage +from ..data.mfdatautil import ListTemplateGenerator + + +class ModflowGwtapi(mfpackage.MFPackage): + """ + ModflowGwtapi defines a api package within a gwt6 model. + + Parameters + ---------- + model : MFModel + Model that this package is a part of. Package is automatically + added to model when it is initialized. + loading_package : bool + Do not set this parameter. It is intended for debugging and internal + processing purposes only. + boundnames : boolean + * boundnames (boolean) keyword to indicate that boundary names may be + provided with the list of api boundary cells. + print_input : boolean + * print_input (boolean) keyword to indicate that the list of api + boundary information will be written to the listing file immediately + after it is read. + print_flows : boolean + * print_flows (boolean) keyword to indicate that the list of api + boundary flow rates will be printed to the listing file for every + stress period time step in which "BUDGET PRINT" is specified in + Output Control. If there is no Output Control option and + "PRINT_FLOWS" is specified, then flow rates are printed for the last + time step of each stress period. + save_flows : boolean + * save_flows (boolean) keyword to indicate that api boundary flow terms + will be written to the file specified with "BUDGET FILEOUT" in Output + Control. + observations : {varname:data} or continuous data + * Contains data for the obs package. Data can be stored in a dictionary + containing data for the obs package with variable names as keys and + package data as values. Data just for the observations variable is + also acceptable. See obs package documentation for more information. + mover : boolean + * mover (boolean) keyword to indicate that this instance of the api + boundary Package can be used with the Water Mover (MVR) Package. When + the MOVER option is specified, additional memory is allocated within + the package to store the available, provided, and received water. + maxbound : integer + * maxbound (integer) integer value specifying the maximum number of api + boundary cells that will be specified for use during any stress + period. + filename : String + File name for this package. + pname : String + Package name for this package. + parent_file : MFPackage + Parent package file that references this package. Only needed for + utility packages (mfutl*). For example, mfutllaktab package must have + a mfgwflak package parent_file. + + """ + + obs_filerecord = ListTemplateGenerator( + ("gwt6", "api", "options", "obs_filerecord") + ) + package_abbr = "gwtapi" + _package_type = "api" + dfn_file_name = "gwt-api.dfn" + + dfn = [ + [ + "block options", + "name boundnames", + "type keyword", + "shape", + "reader urword", + "optional true", + ], + [ + "block options", + "name print_input", + "type keyword", + "reader urword", + "optional true", + ], + [ + "block options", + "name print_flows", + "type keyword", + "reader urword", + "optional true", + ], + [ + "block options", + "name save_flows", + "type keyword", + "reader urword", + "optional true", + ], + [ + "block options", + "name obs_filerecord", + "type record obs6 filein obs6_filename", + "shape", + "reader urword", + "tagged true", + "optional true", + "construct_package obs", + "construct_data continuous", + "parameter_name observations", + ], + [ + "block options", + "name obs6", + "type keyword", + "shape", + "in_record true", + "reader urword", + "tagged true", + "optional false", + ], + [ + "block options", + "name filein", + "type keyword", + "shape", + "in_record true", + "reader urword", + "tagged true", + "optional false", + ], + [ + "block options", + "name obs6_filename", + "type string", + "preserve_case true", + "in_record true", + "tagged false", + "reader urword", + "optional false", + ], + [ + "block options", + "name mover", + "type keyword", + "tagged true", + "reader urword", + "optional true", + ], + [ + "block dimensions", + "name maxbound", + "type integer", + "reader urword", + "optional false", + ], + ] + + def __init__( + self, + model, + loading_package=False, + boundnames=None, + print_input=None, + print_flows=None, + save_flows=None, + observations=None, + mover=None, + maxbound=None, + filename=None, + pname=None, + parent_file=None, + ): + super().__init__( + model, "api", filename, pname, loading_package, parent_file + ) + + # set up variables + self.boundnames = self.build_mfdata("boundnames", boundnames) + self.print_input = self.build_mfdata("print_input", print_input) + self.print_flows = self.build_mfdata("print_flows", print_flows) + self.save_flows = self.build_mfdata("save_flows", save_flows) + self._obs_filerecord = self.build_mfdata("obs_filerecord", None) + self._obs_package = self.build_child_package( + "obs", observations, "continuous", self._obs_filerecord + ) + self.mover = self.build_mfdata("mover", mover) + self.maxbound = self.build_mfdata("maxbound", maxbound) + self._init_complete = True diff --git a/dependencies/flopy/mf6/modflow/mfgwtcnc.py b/dependencies/flopy/mf6/modflow/mfgwtcnc.py index 773357d..08a4deb 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtcnc.py +++ b/dependencies/flopy/mf6/modflow/mfgwtcnc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwtdis.py b/dependencies/flopy/mf6/modflow/mfgwtdis.py index 29458d3..ec09046 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtdis.py +++ b/dependencies/flopy/mf6/modflow/mfgwtdis.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwtdisu.py b/dependencies/flopy/mf6/modflow/mfgwtdisu.py index 7707f0c..7024be7 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtdisu.py +++ b/dependencies/flopy/mf6/modflow/mfgwtdisu.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator @@ -45,6 +45,14 @@ class ModflowGwtdisu(mfpackage.MFPackage): The value for ANGROT does not affect the model simulation, but it is written to the binary grid file so that postprocessors can locate the grid in space. + vertical_offset_tolerance : double + * vertical_offset_tolerance (double) checks are performed to ensure + that the top of a cell is not higher than the bottom of an overlying + cell. This option can be used to specify the tolerance that is used + for checking. If top of a cell is above the bottom of an overlying + cell by a value less than this tolerance, then the program will not + terminate with an error. The default value is zero. This option + should generally not be used. nodes : integer * nodes (integer) is the number of cells in the model grid. nja : integer @@ -68,6 +76,15 @@ class ModflowGwtdisu(mfpackage.MFPackage): * bot (double) is the bottom elevation for each cell. area : [double] * area (double) is the cell surface area (in plan view). + idomain : [integer] + * idomain (integer) is an optional array that characterizes the + existence status of a cell. If the IDOMAIN array is not specified, + then all model cells exist within the solution. If the IDOMAIN value + for a cell is 0, the cell does not exist in the simulation. Input and + output values will be read and written for the cell, but internal to + the program, the cell is excluded from the solution. If the IDOMAIN + value for a cell is 1 or greater, the cell exists in the simulation. + IDOMAIN values of -1 cannot be specified for the DISU Package. iac : [integer] * iac (integer) is the number of connections (plus 1) for each cell. The sum of all the entries in IAC must be equal to NJA. @@ -78,8 +95,8 @@ class ModflowGwtdisu(mfpackage.MFPackage): sequentially provided for the first to the last cell. The first value in the list must be cell n itself, and the remaining cells must be listed in an increasing order (sorted from lowest number to highest). - Note that the cell and its connections are only supplied for the GWF - cells and their connections to the other GWF cells. Also note that + Note that the cell and its connections are only supplied for the GWT + cells and their connections to the other GWT cells. Also note that the JA list input may be divided such that every node and its connectivity list can be on a separate line for ease in readability of the file. To further ease readability of the file, the node number @@ -172,6 +189,7 @@ class ModflowGwtdisu(mfpackage.MFPackage): top = ArrayTemplateGenerator(("gwt6", "disu", "griddata", "top")) bot = ArrayTemplateGenerator(("gwt6", "disu", "griddata", "bot")) area = ArrayTemplateGenerator(("gwt6", "disu", "griddata", "area")) + idomain = ArrayTemplateGenerator(("gwt6", "disu", "griddata", "idomain")) iac = ArrayTemplateGenerator(("gwt6", "disu", "connectiondata", "iac")) ja = ArrayTemplateGenerator(("gwt6", "disu", "connectiondata", "ja")) ihc = ArrayTemplateGenerator(("gwt6", "disu", "connectiondata", "ihc")) @@ -222,6 +240,14 @@ class ModflowGwtdisu(mfpackage.MFPackage): "reader urword", "optional true", ], + [ + "block options", + "name vertical_offset_tolerance", + "type double precision", + "reader urword", + "optional true", + "default_value 0.0", + ], [ "block dimensions", "name nodes", @@ -264,6 +290,15 @@ class ModflowGwtdisu(mfpackage.MFPackage): "shape (nodes)", "reader readarray", ], + [ + "block griddata", + "name idomain", + "type integer", + "shape (nodes)", + "reader readarray", + "layered false", + "optional true", + ], [ "block connectiondata", "name iac", @@ -278,6 +313,7 @@ class ModflowGwtdisu(mfpackage.MFPackage): "shape (nja)", "reader readarray", "numeric_index true", + "jagged_array iac", ], [ "block connectiondata", @@ -285,6 +321,7 @@ class ModflowGwtdisu(mfpackage.MFPackage): "type integer", "shape (nja)", "reader readarray", + "jagged_array iac", ], [ "block connectiondata", @@ -292,6 +329,7 @@ class ModflowGwtdisu(mfpackage.MFPackage): "type double precision", "shape (nja)", "reader readarray", + "jagged_array iac", ], [ "block connectiondata", @@ -299,6 +337,7 @@ class ModflowGwtdisu(mfpackage.MFPackage): "type double precision", "shape (nja)", "reader readarray", + "jagged_array iac", ], [ "block connectiondata", @@ -307,6 +346,7 @@ class ModflowGwtdisu(mfpackage.MFPackage): "optional true", "shape (nja)", "reader readarray", + "jagged_array iac", ], [ "block vertices", @@ -409,12 +449,14 @@ def __init__( xorigin=None, yorigin=None, angrot=None, + vertical_offset_tolerance=0.0, nodes=None, nja=None, nvert=None, top=None, bot=None, area=None, + idomain=None, iac=None, ja=None, ihc=None, @@ -437,12 +479,16 @@ def __init__( self.xorigin = self.build_mfdata("xorigin", xorigin) self.yorigin = self.build_mfdata("yorigin", yorigin) self.angrot = self.build_mfdata("angrot", angrot) + self.vertical_offset_tolerance = self.build_mfdata( + "vertical_offset_tolerance", vertical_offset_tolerance + ) self.nodes = self.build_mfdata("nodes", nodes) self.nja = self.build_mfdata("nja", nja) self.nvert = self.build_mfdata("nvert", nvert) self.top = self.build_mfdata("top", top) self.bot = self.build_mfdata("bot", bot) self.area = self.build_mfdata("area", area) + self.idomain = self.build_mfdata("idomain", idomain) self.iac = self.build_mfdata("iac", iac) self.ja = self.build_mfdata("ja", ja) self.ihc = self.build_mfdata("ihc", ihc) diff --git a/dependencies/flopy/mf6/modflow/mfgwtdisv.py b/dependencies/flopy/mf6/modflow/mfgwtdisv.py index 2e0c276..af5e3f4 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtdisv.py +++ b/dependencies/flopy/mf6/modflow/mfgwtdisv.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwtdsp.py b/dependencies/flopy/mf6/modflow/mfgwtdsp.py index 2f115b7..9bcf665 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtdsp.py +++ b/dependencies/flopy/mf6/modflow/mfgwtdsp.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwtfmi.py b/dependencies/flopy/mf6/modflow/mfgwtfmi.py index a0d88c3..ba4fbce 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtfmi.py +++ b/dependencies/flopy/mf6/modflow/mfgwtfmi.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator @@ -17,6 +17,10 @@ class ModflowGwtfmi(mfpackage.MFPackage): loading_package : bool Do not set this parameter. It is intended for debugging and internal processing purposes only. + save_flows : boolean + * save_flows (boolean) keyword to indicate that FMI flow terms will be + written to the file specified with "BUDGET FILEOUT" in Output + Control. flow_imbalance_correction : boolean * flow_imbalance_correction (boolean) correct for an imbalance in flows by assuming that any residual flow error comes in or leaves at the @@ -56,6 +60,13 @@ class ModflowGwtfmi(mfpackage.MFPackage): dfn_file_name = "gwt-fmi.dfn" dfn = [ + [ + "block options", + "name save_flows", + "type keyword", + "reader urword", + "optional true", + ], [ "block options", "name flow_imbalance_correction", @@ -103,6 +114,7 @@ def __init__( self, model, loading_package=False, + save_flows=None, flow_imbalance_correction=None, packagedata=None, filename=None, @@ -114,6 +126,7 @@ def __init__( ) # set up variables + self.save_flows = self.build_mfdata("save_flows", save_flows) self.flow_imbalance_correction = self.build_mfdata( "flow_imbalance_correction", flow_imbalance_correction ) diff --git a/dependencies/flopy/mf6/modflow/mfgwtic.py b/dependencies/flopy/mf6/modflow/mfgwtic.py index 6a2a875..82cd016 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtic.py +++ b/dependencies/flopy/mf6/modflow/mfgwtic.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwtist.py b/dependencies/flopy/mf6/modflow/mfgwtist.py index 78ca2c4..d11087e 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtist.py +++ b/dependencies/flopy/mf6/modflow/mfgwtist.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator, ArrayTemplateGenerator @@ -29,12 +29,12 @@ class ModflowGwtist(mfpackage.MFPackage): first_order_decay : boolean * first_order_decay (boolean) is a text keyword to indicate that first- order decay will occur. Use of this keyword requires that DECAY and - DECAY_SORBED (if sorbtion is active) are specified in the GRIDDATA + DECAY_SORBED (if sorption is active) are specified in the GRIDDATA block. zero_order_decay : boolean * zero_order_decay (boolean) is a text keyword to indicate that zero- order decay will occur. Use of this keyword requires that DECAY and - DECAY_SORBED (if sorbtion is active) are specified in the GRIDDATA + DECAY_SORBED (if sorption is active) are specified in the GRIDDATA block. cim_filerecord : [cimfile] * cimfile (string) name of the output file to write immobile @@ -64,7 +64,7 @@ class ModflowGwtist(mfpackage.MFPackage): for the aqueous phase of the immobile domain. A negative value indicates solute production. The dimensions of decay for first-order decay is one over time. The dimensions of decay for zero-order decay - is mass per length cubed per time. decay will have no affect on + is mass per length cubed per time. Decay will have no effect on simulation results unless either first- or zero-order decay is specified in the options block. decay_sorbed : [double] @@ -73,20 +73,20 @@ class ModflowGwtist(mfpackage.MFPackage): indicates solute production. The dimensions of decay_sorbed for first-order decay is one over time. The dimensions of decay_sorbed for zero-order decay is mass of solute per mass of aquifer per time. - If decay_sorbed is not specified and both decay and sorbtion are + If decay_sorbed is not specified and both decay and sorption are active, then the program will terminate with an error. decay_sorbed - will have no affect on simulation results unless the SORPTION keyword + will have no effect on simulation results unless the SORPTION keyword and either first- or zero-order decay are specified in the options block. bulk_density : [double] * bulk_density (double) is the bulk density of the aquifer in mass per - length cubed. bulk_density will have no affect on simulation results - unless the SORBTION keyword is specified in the options block. + length cubed. bulk_density will have no effect on simulation results + unless the SORPTION keyword is specified in the options block. distcoef : [double] * distcoef (double) is the distribution coefficient for the equilibrium-controlled linear sorption isotherm in dimensions of - length cubed per mass. distcoef will have no affect on simulation - results unless the SORBTION keyword is specified in the options + length cubed per mass. distcoef will have no effect on simulation + results unless the SORPTION keyword is specified in the options block. filename : String File name for this package. diff --git a/dependencies/flopy/mf6/modflow/mfgwtlkt.py b/dependencies/flopy/mf6/modflow/mfgwtlkt.py index 89ccf22..eb3cf0a 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtlkt.py +++ b/dependencies/flopy/mf6/modflow/mfgwtlkt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator @@ -42,7 +42,7 @@ class ModflowGwtlkt(mfpackage.MFPackage): specified with this name. Note that the flow package must have an auxiliary variable with this name or the program will terminate with an error. If the flows for this advanced transport package are read - from a file, then this option will have no affect. + from a file, then this option will have no effect. boundnames : boolean * boundnames (boolean) keyword to indicate that boundary names may be provided with the list of lake cells. diff --git a/dependencies/flopy/mf6/modflow/mfgwtmst.py b/dependencies/flopy/mf6/modflow/mfgwtmst.py index b4d97a8..df2ae06 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtmst.py +++ b/dependencies/flopy/mf6/modflow/mfgwtmst.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator @@ -24,12 +24,12 @@ class ModflowGwtmst(mfpackage.MFPackage): first_order_decay : boolean * first_order_decay (boolean) is a text keyword to indicate that first- order decay will occur. Use of this keyword requires that DECAY and - DECAY_SORBED (if sorbtion is active) are specified in the GRIDDATA + DECAY_SORBED (if sorption is active) are specified in the GRIDDATA block. zero_order_decay : boolean * zero_order_decay (boolean) is a text keyword to indicate that zero- order decay will occur. Use of this keyword requires that DECAY and - DECAY_SORBED (if sorbtion is active) are specified in the GRIDDATA + DECAY_SORBED (if sorption is active) are specified in the GRIDDATA block. sorption : string * sorption (string) is a text keyword to indicate that sorption will be @@ -45,7 +45,7 @@ class ModflowGwtmst(mfpackage.MFPackage): for the aqueous phase of the mobile domain. A negative value indicates solute production. The dimensions of decay for first-order decay is one over time. The dimensions of decay for zero-order decay - is mass per length cubed per time. decay will have no affect on + is mass per length cubed per time. decay will have no effect on simulation results unless either first- or zero-order decay is specified in the options block. decay_sorbed : [double] @@ -54,14 +54,14 @@ class ModflowGwtmst(mfpackage.MFPackage): indicates solute production. The dimensions of decay_sorbed for first-order decay is one over time. The dimensions of decay_sorbed for zero-order decay is mass of solute per mass of aquifer per time. - If decay_sorbed is not specified and both decay and sorbtion are + If decay_sorbed is not specified and both decay and sorption are active, then the program will terminate with an error. decay_sorbed - will have no affect on simulation results unless the SORPTION keyword + will have no effect on simulation results unless the SORPTION keyword and either first- or zero-order decay are specified in the options block. bulk_density : [double] * bulk_density (double) is the bulk density of the aquifer in mass per - length cubed. bulk_density is not required unless the SORBTION + length cubed. bulk_density is not required unless the SORPTION keyword is specified. distcoef : [double] * distcoef (double) is the distribution coefficient for the diff --git a/dependencies/flopy/mf6/modflow/mfgwtmvt.py b/dependencies/flopy/mf6/modflow/mfgwtmvt.py index 77a53d6..cef5272 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtmvt.py +++ b/dependencies/flopy/mf6/modflow/mfgwtmvt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwtmwt.py b/dependencies/flopy/mf6/modflow/mfgwtmwt.py index 7e04e16..48d440c 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtmwt.py +++ b/dependencies/flopy/mf6/modflow/mfgwtmwt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator @@ -42,7 +42,7 @@ class ModflowGwtmwt(mfpackage.MFPackage): specified with this name. Note that the flow package must have an auxiliary variable with this name or the program will terminate with an error. If the flows for this advanced transport package are read - from a file, then this option will have no affect. + from a file, then this option will have no effect. boundnames : boolean * boundnames (boolean) keyword to indicate that boundary names may be provided with the list of well cells. diff --git a/dependencies/flopy/mf6/modflow/mfgwtnam.py b/dependencies/flopy/mf6/modflow/mfgwtnam.py index 544a432..8a4131d 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtnam.py +++ b/dependencies/flopy/mf6/modflow/mfgwtnam.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwtoc.py b/dependencies/flopy/mf6/modflow/mfgwtoc.py index 706c01e..2292910 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtoc.py +++ b/dependencies/flopy/mf6/modflow/mfgwtoc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwtsft.py b/dependencies/flopy/mf6/modflow/mfgwtsft.py index 3b1c378..91f04d1 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtsft.py +++ b/dependencies/flopy/mf6/modflow/mfgwtsft.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator @@ -42,7 +42,7 @@ class ModflowGwtsft(mfpackage.MFPackage): specified with this name. Note that the flow package must have an auxiliary variable with this name or the program will terminate with an error. If the flows for this advanced transport package are read - from a file, then this option will have no affect. + from a file, then this option will have no effect. boundnames : boolean * boundnames (boolean) keyword to indicate that boundary names may be provided with the list of reach cells. diff --git a/dependencies/flopy/mf6/modflow/mfgwtsrc.py b/dependencies/flopy/mf6/modflow/mfgwtsrc.py index c4b3440..0f3957a 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtsrc.py +++ b/dependencies/flopy/mf6/modflow/mfgwtsrc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfgwtssm.py b/dependencies/flopy/mf6/modflow/mfgwtssm.py index 90c6a6f..c6dc8d1 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtssm.py +++ b/dependencies/flopy/mf6/modflow/mfgwtssm.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator @@ -29,8 +29,11 @@ class ModflowGwtssm(mfpackage.MFPackage): written to the file specified with "BUDGET FILEOUT" in Output Control. sources : [pname, srctype, auxname] - * pname (string) name of the package for which an auxiliary variable - contains a source concentration. + * pname (string) name of the flow package for which an auxiliary + variable contains a source concentration. If this flow package is + represented using an advanced transport package (SFT, LKT, MWT, or + UZT), then the advanced transport package will override SSM terms + specified here. * srctype (string) keyword indicating how concentration will be assigned for sources and sinks. Keyword must be specified as either AUX or AUXMIXED. For both options the user must provide an auxiliary diff --git a/dependencies/flopy/mf6/modflow/mfgwtuzt.py b/dependencies/flopy/mf6/modflow/mfgwtuzt.py index 5a68f02..dff239f 100644 --- a/dependencies/flopy/mf6/modflow/mfgwtuzt.py +++ b/dependencies/flopy/mf6/modflow/mfgwtuzt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:57:00 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator @@ -42,7 +42,7 @@ class ModflowGwtuzt(mfpackage.MFPackage): specified with this name. Note that the flow package must have an auxiliary variable with this name or the program will terminate with an error. If the flows for this advanced transport package are read - from a file, then this option will have no affect. + from a file, then this option will have no effect. boundnames : boolean * boundnames (boolean) keyword to indicate that boundary names may be provided with the list of unsaturated zone flow cells. diff --git a/dependencies/flopy/mf6/modflow/mfims.py b/dependencies/flopy/mf6/modflow/mfims.py index e1b1878..e5fda9f 100644 --- a/dependencies/flopy/mf6/modflow/mfims.py +++ b/dependencies/flopy/mf6/modflow/mfims.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator @@ -80,6 +80,22 @@ class ModflowIms(mfpackage.MFPackage): steady-state stress periods for models using the Newton-Raphson formulation. If NO_PTC_OPTION is not specified, the NO_PTC ALL option is used. + ats_outer_maximum_fraction : double + * ats_outer_maximum_fraction (double) real value defining the fraction + of the maximum allowable outer iterations used with the Adaptive Time + Step (ATS) capability if it is active. If this value is set to zero + by the user, then this solution will have no effect on ATS behavior. + This value must be greater than or equal to zero and less than or + equal to 0.5 or the program will terminate with an error. If it not + specified by the user, then it is assigned a default value of one + third. When the number of outer iterations for this solution is less + than the product of this value and the maximum allowable outer + iterations, then ATS will increase the time step length by a factor + of DTADJ in the ATS input file. When the number of outer iterations + for this solution is greater than the maximum allowable outer + iterations minus the product of this value and the maximum allowable + outer iterations, then the ATS (if active) will decrease the time + step length by a factor of 1 / DTADJ. outer_hclose : double * outer_hclose (double) real value defining the head change criterion for convergence of the outer (nonlinear) iterations, in units of @@ -133,8 +149,8 @@ class ModflowIms(mfpackage.MFPackage): relaxation is used. Note that the under-relaxation schemes are often used in conjunction with problems that use the Newton-Raphson formulation, however, experience has indicated that they also work - well non-Newton problems, such as those with the wet/dry options of - MODFLOW 6. + well for non-Newton problems, such as those with the wet/dry options + of MODFLOW 6. under_relaxation_gamma : double * under_relaxation_gamma (double) real value defining either the relaxation factor for the SIMPLE scheme or the history or memory term @@ -505,6 +521,13 @@ class ModflowIms(mfpackage.MFPackage): "optional true", "tagged false", ], + [ + "block options", + "name ats_outer_maximum_fraction", + "type double precision", + "reader urword", + "optional true", + ], [ "block nonlinear", "name outer_hclose", @@ -706,6 +729,7 @@ def __init__( csv_outer_output_filerecord=None, csv_inner_output_filerecord=None, no_ptcrecord=None, + ats_outer_maximum_fraction=None, outer_hclose=None, outer_dvclose=None, outer_rclosebnd=None, @@ -751,6 +775,9 @@ def __init__( "csv_inner_output_filerecord", csv_inner_output_filerecord ) self.no_ptcrecord = self.build_mfdata("no_ptcrecord", no_ptcrecord) + self.ats_outer_maximum_fraction = self.build_mfdata( + "ats_outer_maximum_fraction", ats_outer_maximum_fraction + ) self.outer_hclose = self.build_mfdata("outer_hclose", outer_hclose) self.outer_dvclose = self.build_mfdata("outer_dvclose", outer_dvclose) self.outer_rclosebnd = self.build_mfdata( diff --git a/dependencies/flopy/mf6/modflow/mfmvr.py b/dependencies/flopy/mf6/modflow/mfmvr.py index 65f1f17..ef3096a 100644 --- a/dependencies/flopy/mf6/modflow/mfmvr.py +++ b/dependencies/flopy/mf6/modflow/mfmvr.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfnam.py b/dependencies/flopy/mf6/modflow/mfnam.py index 79cfa19..fac5dc1 100644 --- a/dependencies/flopy/mf6/modflow/mfnam.py +++ b/dependencies/flopy/mf6/modflow/mfnam.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfsimulation.py b/dependencies/flopy/mf6/modflow/mfsimulation.py index 245647e..b19fa03 100644 --- a/dependencies/flopy/mf6/modflow/mfsimulation.py +++ b/dependencies/flopy/mf6/modflow/mfsimulation.py @@ -1,8 +1,8 @@ import errno import sys import inspect -import collections import os.path +import numpy as np from ...mbase import run_model from ..mfbase import ( PackageContainer, @@ -22,13 +22,13 @@ from ..data.mfdatautil import MFComment -class SimulationDict(collections.OrderedDict): +class SimulationDict(dict): """ Class containing custom dictionary for MODFLOW simulations. Dictionary contains model data. Dictionary keys are "paths" to the data that include the model and package containing the data. - Behaves as an OrderedDict with some additional features described below. + Behaves as an dict with some additional features described below. Parameters ---------- @@ -38,11 +38,12 @@ class SimulationDict(collections.OrderedDict): """ def __init__(self, path=None): - collections.OrderedDict.__init__(self) + dict.__init__(self) self._path = path def __getitem__(self, key): - """Define the __getitem__ magic method. + """ + Define the __getitem__ magic method. Parameters ---------- @@ -65,12 +66,13 @@ def __getitem__(self, key): return val.data if key in self: - val = collections.OrderedDict.__getitem__(self, key) + val = dict.__getitem__(self, key) return val return AttributeError(key) def __setitem__(self, key, val): - """Define the __setitem__ magic method. + """ + Define the __setitem__ magic method. Parameters ---------- @@ -80,10 +82,11 @@ def __setitem__(self, key, val): MFData to store in dictionary """ - collections.OrderedDict.__setitem__(self, key, val) + dict.__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. + """ + Attempt to find key_leaf in a partial key path key_path. Parameters ---------- @@ -117,7 +120,8 @@ 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 supported by the dictionary. + """ + Return a list of output data keys supported by the dictionary. Parameters ---------- @@ -136,7 +140,8 @@ def output_keys(self, print_keys=True): return [key for key in x.dataDict] def input_keys(self): - """Return a list of input data keys. + """ + Return a list of input data keys. Returns ------- @@ -148,7 +153,8 @@ def input_keys(self): print(key) def observation_keys(self): - """Return a list of observation keys. + """ + Return a list of observation keys. Returns ------- @@ -159,7 +165,8 @@ def observation_keys(self): mfobservation.MFObservationRequester.getkeys(self, self._path) def keys(self): - """Return a list of all keys. + """ + Return a list of all keys. Returns ------- @@ -219,7 +226,7 @@ class MFSimulationData: Numbers less than this threshold are written in scientific notation mfpath : MFFileMgmt File path location information for the simulation - model_dimensions : OrderedDict + model_dimensions : dict Dictionary containing discretization information for each model mfdata : SimulationDict Custom dictionary containing all model data for the simulation @@ -254,14 +261,14 @@ def __init__(self, path, mfsim): # --- ease of use variables to make working with modflow input and # output data easier --- model dimension class for each model - self.model_dimensions = collections.OrderedDict() + self.model_dimensions = {} # --- model data --- self.mfdata = SimulationDict(self.mfpath) # --- temporary variables --- # other external files referenced - self.referenced_files = collections.OrderedDict() + self.referenced_files = {} @property def max_columns_of_data(self): @@ -276,7 +283,8 @@ def max_columns_of_data(self, val): self.max_columns_user_set = True def set_sci_note_upper_thres(self, value): - """Sets threshold number where any number larger than threshold + """ + Sets threshold number where any number larger than threshold is represented in scientific notation. Parameters @@ -289,7 +297,8 @@ def set_sci_note_upper_thres(self, value): self._update_str_format() def set_sci_note_lower_thres(self, value): - """Sets threshold number where any number smaller than threshold + """ + Sets threshold number where any number smaller than threshold is represented in scientific notation. Parameters @@ -302,11 +311,11 @@ def set_sci_note_lower_thres(self, value): self._update_str_format() def _update_str_format(self): - """Update floating point formatting strings.""" - self.reg_format_str = "{:.%dE}" % self.float_precision - self.sci_format_str = "{:%d.%df" "}" % ( - self.float_characters, - self.float_precision, + """ + Update floating point formatting strings.""" + self.reg_format_str = f"{{:.{self.float_precision}E}}" + self.sci_format_str = ( + f"{{:{self.float_characters}.{self.float_precision}f}}" ) @@ -402,13 +411,13 @@ def __init__( self.version = version self.exe_name = exe_name - self._models = collections.OrderedDict() + self._models = {} self._tdis_file = None - self._exchange_files = collections.OrderedDict() - self._ims_files = collections.OrderedDict() + self._exchange_files = {} + self._ims_files = {} self._ghost_node_files = {} self._mover_files = {} - self._other_files = collections.OrderedDict() + self._other_files = {} self.structure = fpdata.sim_struct self.model_type = None @@ -448,7 +457,8 @@ def __init__( self.valid = False def __getattr__(self, item): - """Override __getattr__ to allow retrieving models. + """ + Override __getattr__ to allow retrieving models. __getattr__ is used to allow for getting models and packages as if they are attributes @@ -490,7 +500,8 @@ def __getattr__(self, item): raise AttributeError(item) def __repr__(self): - """Override __repr__ to print custom string. + """ + Override __repr__ to print custom string. Returns -------- @@ -501,7 +512,8 @@ def __repr__(self): return self._get_data_str(True) def __str__(self): - """Override __str__ to print custom string. + """ + Override __str__ to print custom string. Returns -------- @@ -556,7 +568,8 @@ def _get_data_str(self, formal): @property def model_names(self): - """Return a list of model names associated with this simulation. + """ + Return a list of model names associated with this simulation. Returns -------- @@ -565,6 +578,18 @@ def model_names(self): """ return self._models.keys() + @property + def exchange_files(self): + """ + Return list of exchange files associated with this simulation. + + Returns + -------- + list: list of exchange names + + """ + return self._exchange_files.values() + @classmethod def load( cls, @@ -578,7 +603,8 @@ def load( verify_data=False, write_headers=True, ): - """Load an existing model. + """ + Load an existing model. Parameters ---------- @@ -646,9 +672,7 @@ def load( instance.name_file.load(strict) # load TDIS file - tdis_pkg = "tdis{}".format( - mfstructure.MFStructure().get_version_string() - ) + tdis_pkg = f"tdis{mfstructure.MFStructure().get_version_string()}" tdis_attr = getattr(instance.name_file, tdis_pkg) instance._tdis_file = mftdis.ModflowTdis( instance, filename=tdis_attr.get_data() @@ -684,7 +708,7 @@ def load( model_obj = PackageContainer.model_factory(item[0][:-1].lower()) # load model if verbosity_level.value >= VerbosityLevel.normal.value: - print(" loading model {}...".format(item[0].lower())) + print(f" loading model {item[0].lower()}...") instance._models[item[2]] = model_obj.load( instance, instance.structure.model_struct_objs[item[0].lower()], @@ -734,10 +758,7 @@ def load( instance.simulation_data.verbosity_level.value >= VerbosityLevel.normal.value ): - print( - " skipping package {}.." - ".".format(exgfile[0].lower()) - ) + print(f" skipping package {exgfile[0].lower()}...") continue # get exchange type by removing numbers from exgtype exchange_type = "".join( @@ -751,9 +772,7 @@ def load( exchange_file_num = instance._exg_file_num[exchange_type] instance._exg_file_num[exchange_type] += 1 - exchange_name = "{}_EXG_{}".format( - exchange_type, exchange_file_num - ) + exchange_name = f"{exchange_type}_EXG_{exchange_file_num}" # find package class the corresponds to this exchange type package_obj = instance.package_factory( exchange_type.replace("-", "").lower(), "" @@ -791,8 +810,7 @@ def load( ) if verbosity_level.value >= VerbosityLevel.normal.value: print( - " loading exchange package {}.." - ".".format(exchange_file._get_pname()) + f" loading exchange package {exchange_file._get_pname()}..." ) exchange_file.load(strict) instance._exchange_files[exgfile[1]] = exchange_file @@ -825,18 +843,14 @@ def load( >= VerbosityLevel.normal.value ): print( - " skipping package {}.." - ".".format(solution_info[0].lower()) + f" skipping package {solution_info[0].lower()}..." ) continue ims_file = mfims.ModflowIms( instance, filename=solution_info[1], pname=solution_info[2] ) if verbosity_level.value >= VerbosityLevel.normal.value: - print( - " loading ims package {}.." - ".".format(ims_file._get_pname()) - ) + print(f" loading ims package {ims_file._get_pname()}...") ims_file.load(strict) instance.simulation_data.mfpath.set_last_accessed_path() @@ -879,7 +893,7 @@ def check(self, f=None, verbose=True, level=1): # check models for model in self._models.values(): - print('Checking model "{}"...'.format(model.name)) + print(f'Checking model "{model.name}"...') chk_list.append(model.check(f, verbose, level)) print("Checking for missing simulation packages...") @@ -923,7 +937,8 @@ def load_package( dict_package_name=None, parent_package=None, ): - """Load a package from a file. + """ + Load a package from a file. Parameters ---------- @@ -951,7 +966,7 @@ def load_package( else: package_abbr = "GWF" # build package name and package - gnc_name = "{}-GNC_{}".format(package_abbr, self._gnc_file_num) + gnc_name = f"{package_abbr}-GNC_{self._gnc_file_num}" ghost_node_file = mfgwfgnc.ModflowGwfgnc( self, filename=fname, @@ -971,7 +986,7 @@ def load_package( else: package_abbr = "GWF" # build package name and package - mvr_name = "{}-MVR_{}".format(package_abbr, self._mvr_file_num) + mvr_name = f"{package_abbr}-MVR_{self._mvr_file_num}" mover_file = mfgwfmvr.ModflowGwfmvr( self, filename=fname, @@ -1016,7 +1031,8 @@ def load_package( return package def register_ims_package(self, ims_file, model_list): - """Register an ims package with the simulation. + """ + Register an ims package with the simulation. Parameters ims_file : MFPackage @@ -1067,6 +1083,7 @@ def register_ims_package(self, ims_file, model_list): ) self._remove_package(self._ims_files[file.filename]) del self._ims_files[file.filename] + break # register ims package if not in_simulation: self._add_package(ims_file, self._get_package_path(ims_file)) @@ -1076,7 +1093,7 @@ def register_ims_package(self, ims_file, model_list): # create unique file/package name if ims_file.package_name is None: file_num = len(self._ims_files) - 1 - ims_file.package_name = "ims_{}".format(file_num) + ims_file.package_name = f"ims_{file_num}" if ims_file.filename in self._ims_files: ims_file.filename = MFFileMgmt.unique_file_name( ims_file.filename, self._ims_files @@ -1115,7 +1132,7 @@ def register_ims_package(self, ims_file, model_list): # associate any models in the model list to this # simulation file version_string = mfstructure.MFStructure().get_version_string() - ims_pkg = "ims{}".format(version_string) + ims_pkg = f"ims{version_string}" new_record = [ims_pkg, ims_file.filename] for model in model_list: new_record.append(model) @@ -1136,20 +1153,126 @@ def register_ims_package(self, ims_file, model_list): @staticmethod def _rename_package_group(group_dict, name): package_type_count = {} + # first build an array to avoid key modification errors + package_array = [] for package in group_dict.values(): + package_array.append(package) + # update package file names and count + for package in package_array: if package.package_type not in package_type_count: - package.filename = "{}.{}".format(name, package.package_type) + package.filename = f"{name}.{package.package_type}" package_type_count[package.package_type] = 1 else: package_type_count[package.package_type] += 1 - package.filename = "{}_{}.{}".format( - name, - package_type_count[package.package.package_type], - package.package_type, - ) + ptc = package_type_count[package.package_type] + package.filename = f"{name}_{ptc}.{package.package_type}" + + def _rename_exchange_file(self, package, new_filename): + self._exchange_files[package.filename] = package + try: + exchange_recarray_data = self.name_file.exchanges.get_data() + except MFDataException as mfde: + message = ( + "An error occurred while retrieving exchange " + "data from the simulation name file. The error " + "occurred while registering exchange file " + f'"{package.filename}".' + ) + raise MFDataException( + mfdata_except=mfde, + package=package._get_pname(), + message=message, + ) + if exchange_recarray_data is not None: + for index, exchange in zip( + range(0, len(exchange_recarray_data)), + exchange_recarray_data, + ): + if exchange[1] == package.filename: + # update existing exchange + exchange_recarray_data[index][1] = new_filename + ex_recarray = self.name_file.exchanges + try: + ex_recarray.set_data(exchange_recarray_data) + except MFDataException as mfde: + message = ( + "An error occurred while setting " + "exchange data in the simulation name " + "file. The error occurred while " + "registering the following " + "values (exgtype, filename, " + f'exgmnamea, exgmnameb): "{package.exgtype} ' + f"{package.filename} {package.exgmnamea}" + f'{package.exgmnameb}".' + ) + raise MFDataException( + mfdata_except=mfde, + package=package._get_pname(), + message=message, + ) + return + + def _set_timing_block(self, file_name): + struct_root = mfstructure.MFStructure() + tdis_pkg = "tdis{}".format(struct_root.get_version_string()) + tdis_attr = getattr(self.name_file, tdis_pkg) + try: + tdis_attr.set_data(file_name) + except MFDataException as mfde: + message = ( + "An error occurred while setting the tdis package " + f'file name "{file_name}". The error occurred while ' + "registering the tdis package with the " + "simulation" + ) + raise MFDataException( + mfdata_except=mfde, + package=file_name, + message=message, + ) + + def update_package_filename(self, package, new_name): + """ + Updates internal arrays to be consistent with a new file name. + This is for internal flopy library use only. + + Parameters + ---------- + package: MFPackage + Package with new name + new_name: str + Package's new name + + """ + if ( + self._tdis_file is not None + and package.filename == self._tdis_file.filename + ): + self._set_timing_block(new_name) + if package.filename in self._exchange_files: + self._exchange_files[new_name] = self._exchange_files.pop( + package.filename + ) + self._rename_exchange_file(package, new_name) + if package.filename in self._ims_files: + self._ims_files[new_name] = self._ims_files.pop(package.filename) + self._update_ims_solution_group(package.filename, new_name) + if package.filename in self._ghost_node_files: + self._ghost_node_files[new_name] = self._ghost_node_files.pop( + package.filename + ) + if package.filename in self._mover_files: + self._mover_files[new_name] = self._mover_files.pop( + package.filename + ) + if package.filename in self._other_files: + self._other_files[new_name] = self._other_files.pop( + package.filename + ) def rename_all_packages(self, name): - """Rename all packages with name as prefix. + """ + Rename all packages with name as prefix. Parameters ---------- @@ -1158,9 +1281,7 @@ def rename_all_packages(self, name): """ if self._tdis_file is not None: - self._tdis_file.filename = "{}.{}".format( - name, self._tdis_file.package_type - ) + self._tdis_file.filename = f"{name}.{self._tdis_file.package_type}" self._rename_package_group(self._exchange_files, name) self._rename_package_group(self._ims_files, name) @@ -1221,7 +1342,8 @@ def set_all_data_internal(self, check_data=True): def write_simulation( self, ext_file_action=ExtFileAction.copy_relative_paths, silent=False ): - """Write the simulation to files. + """ + Write the simulation to files. Parameters ext_file_action : ExtFileAction @@ -1270,10 +1392,7 @@ def write_simulation( self.simulation_data.verbosity_level.value >= VerbosityLevel.normal.value ): - print( - " writing ims package {}.." - ".".format(ims_file._get_pname()) - ) + print(f" writing ims package {ims_file._get_pname()}...") ims_file.write(ext_file_action=ext_file_action) # write exchange files @@ -1367,7 +1486,7 @@ def write_simulation( self.simulation_data.verbosity_level.value >= VerbosityLevel.normal.value ): - print(" writing package {}...".format(pp._get_pname())) + print(f" writing package {pp._get_pname()}...") pp.write(ext_file_action=ext_file_action) # FIX: model working folder should be model name file folder @@ -1378,7 +1497,7 @@ def write_simulation( self.simulation_data.verbosity_level.value >= VerbosityLevel.normal.value ): - print(" writing model {}...".format(model.name)) + print(f" writing model {model.name}...") model.write(ext_file_action=ext_file_action) self.simulation_data.mfpath.set_last_accessed_path() @@ -1414,7 +1533,8 @@ def run_simulation( use_async=False, cargs=None, ): - """Run the simulation. + """ + Run the simulation. Parameters ---------- @@ -1473,7 +1593,8 @@ def delete_output_files(self): os.remove(path) def remove_package(self, package_name): - """Removes package from the simulation. `package_name` can be the + """ + Removes package from the simulation. `package_name` can be the package's name, type, or package object to be removed from the model. Parameters @@ -1498,7 +1619,7 @@ def remove_package(self, package_name): del self._exchange_files[package.filename] if package.filename in self._ims_files: del self._ims_files[package.filename] - self._remove_ims_soultion_group(package.filename) + self._update_ims_solution_group(package.filename) if package.filename in self._ghost_node_files: del self._ghost_node_files[package.filename] if package.filename in self._mover_files: @@ -1510,7 +1631,8 @@ def remove_package(self, package_name): @property def model_dict(self): - """Return a dictionary of models associated with this simulation. + """ + Return a dictionary of models associated with this simulation. Returns -------- @@ -1521,7 +1643,8 @@ def model_dict(self): return self._models.copy() def get_model(self, model_name=None): - """Returns the models in the simulation with a given model name, name + """ + Returns the models in the simulation with a given model name, name file name, or model type. Parameters @@ -1550,7 +1673,8 @@ 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 ---------- @@ -1565,13 +1689,12 @@ def get_exchange_file(self, filename): if filename in self._exchange_files: return self._exchange_files[filename] else: - excpt_str = 'Exchange file "{}" can not be found' ".".format( - filename - ) + excpt_str = f'Exchange file "{filename}" can not be found.' raise FlopyException(excpt_str) def get_mvr_file(self, filename): - """Get a specified mover file. + """ + Get a specified mover file. Parameters ---------- @@ -1586,11 +1709,12 @@ def get_mvr_file(self, filename): if filename in self._mover_files: return self._mover_files[filename] else: - excpt_str = 'MVR file "{}" can not be ' "found.".format(filename) + excpt_str = f'MVR file "{filename}" can not be found.' raise FlopyException(excpt_str) def get_gnc_file(self, filename): - """Get a specified gnc file. + """ + Get a specified gnc file. Parameters ---------- @@ -1605,11 +1729,54 @@ def get_gnc_file(self, filename): if filename in self._ghost_node_files: return self._ghost_node_files[filename] else: - excpt_str = 'GNC file "{}" can not be ' "found.".format(filename) + excpt_str = f'GNC file "{filename}" can not be found.' raise FlopyException(excpt_str) + def remove_exchange_file(self, package): + """ + Removes the exchange file "package". This is for internal flopy + library use only. + + Parameters + ---------- + package: MFPackage + Exchange package to be removed + + """ + self._exchange_files[package.filename] = package + try: + exchange_recarray_data = self.name_file.exchanges.get_data() + except MFDataException as mfde: + message = ( + "An error occurred while retrieving exchange " + "data from the simulation name file. The error " + "occurred while registering exchange file " + f'"{package.filename}".' + ) + raise MFDataException( + mfdata_except=mfde, + package=package._get_pname(), + message=message, + ) + remove_indices = [] + if exchange_recarray_data is not None: + for index, exchange in zip( + range(0, len(exchange_recarray_data)), + exchange_recarray_data, + ): + if ( + package.filename is not None + and exchange[1] == package.filename + ): + remove_indices.append(index) + if len(remove_indices) > 0: + self.name_file.exchanges.set_data( + np.delete(exchange_recarray_data, remove_indices) + ) + def register_exchange_file(self, package): - """Register an exchange package file with the simulation. This is a + """ + Register an exchange package file with the simulation. This is a call-back method made from the package and should not be called directly. @@ -1639,7 +1806,7 @@ def register_exchange_file(self, package): "An error occurred while retrieving exchange " "data from the simulation name file. The error " "occurred while registering exchange file " - '"{}".'.format(package.filename) + f'"{package.filename}".' ) raise MFDataException( mfdata_except=mfde, @@ -1666,13 +1833,9 @@ def register_exchange_file(self, package): "file. The error occurred while " "registering the following " "values (exgtype, filename, " - 'exgmnamea, exgmnameb): "{} {} {}' - '{}".'.format( - exgtype, - package.filename, - exgmnamea, - exgmnameb, - ) + f'exgmnamea, exgmnameb): "{exgtype} ' + f"{package.filename} {exgmnamea}" + f'{exgmnameb}".' ) raise MFDataException( mfdata_except=mfde, @@ -1690,10 +1853,8 @@ def register_exchange_file(self, package): "An error occurred while setting exchange data " "in the simulation name file. The error occurred " "while registering the following values (exgtype, " - 'filename, exgmnamea, exgmnameb): "{} {} {}' - '{}".'.format( - exgtype, package.filename, exgmnamea, exgmnameb - ) + f'filename, exgmnamea, exgmnameb): "{exgtype} ' + f'{package.filename} {exgmnamea} {exgmnameb}".' ) raise MFDataException( mfdata_except=mfde, @@ -1707,6 +1868,75 @@ def register_exchange_file(self, package): # resolve exchange package dimensions object package.dimensions = package.create_package_dimensions() + def _remove_package_by_type(self, package): + pname = None + if package.package_name is not None: + pname = package.package_name.lower() + if ( + package.package_type.lower() == "tdis" + and self._tdis_file is not None + and self._tdis_file in self._packagelist + ): + # tdis package already exists. there can be only one tdis + # package. remove existing tdis package + if ( + self.simulation_data.verbosity_level.value + >= VerbosityLevel.normal.value + ): + print( + "WARNING: tdis package already exists. Replacing " + "existing tdis package." + ) + self._remove_package(self._tdis_file) + elif ( + package.package_type.lower() == "gnc" + and package.filename in self._ghost_node_files + and self._ghost_node_files[package.filename] in self._packagelist + ): + # gnc package with same file name already exists. remove old + # gnc package + if ( + self.simulation_data.verbosity_level.value + >= VerbosityLevel.normal.value + ): + print( + f"WARNING: gnc package with name {pname} already exists. " + "Replacing existing gnc package." + ) + self._remove_package(self._ghost_node_files[package.filename]) + del self._ghost_node_files[package.filename] + elif ( + package.package_type.lower() == "mvr" + and package.filename in self._mover_files + and self._mover_files[package.filename] in self._packagelist + ): + # mvr package with same file name already exists. remove old + # mvr package + if ( + self.simulation_data.verbosity_level.value + >= VerbosityLevel.normal.value + ): + print( + f"WARNING: mvr package with name {pname} already exists. " + "Replacing existing mvr package." + ) + self._remove_package(self._mover_files[package.filename]) + del self._mover_files[package.filename] + elif ( + package.package_type.lower() != "ims" + and pname in self.package_name_dict + ): + if ( + self.simulation_data.verbosity_level.value + >= VerbosityLevel.normal.value + ): + print( + "WARNING: Package with name " + f"{package.package_name.lower()} already exists. " + "Replacing existing package." + ) + self._remove_package(self.package_name_dict[pname]) + def register_package( self, package, @@ -1714,7 +1944,8 @@ def register_package( set_package_name=True, set_package_filename=True, ): - """Register a package file with the simulation. This is a + """ + Register a package file with the simulation. This is a call-back method made from the package and should not be called directly. @@ -1737,76 +1968,7 @@ def register_package( package.container_type = [PackageContainerType.simulation] path = self._get_package_path(package) if add_to_package_list and package.package_type.lower != "nam": - pname = None - if package.package_name is not None: - pname = package.package_name.lower() - if ( - package.package_type.lower() == "tdis" - and self._tdis_file is not None - and self._tdis_file in self._packagelist - ): - # tdis package already exists. there can be only one tdis - # package. remove existing tdis package - if ( - self.simulation_data.verbosity_level.value - >= VerbosityLevel.normal.value - ): - print( - "WARNING: tdis package already exists. Replacing " - "existing tdis package." - ) - self._remove_package(self._tdis_file) - elif ( - package.package_type.lower() == "gnc" - and package.filename in self._ghost_node_files - and self._ghost_node_files[package.filename] - in self._packagelist - ): - # gnc package with same file name already exists. remove old - # gnc package - if ( - self.simulation_data.verbosity_level.value - >= VerbosityLevel.normal.value - ): - print( - "WARNING: gnc package with name {} already exists. " - "Replacing existing gnc package" - ".".format(pname) - ) - self._remove_package(self._ghost_node_files[package.filename]) - del self._ghost_node_files[package.filename] - elif ( - package.package_type.lower() == "mvr" - and package.filename in self._mover_files - and self._mover_files[package.filename] in self._packagelist - ): - # mvr package with same file name already exists. remove old - # mvr package - if ( - self.simulation_data.verbosity_level.value - >= VerbosityLevel.normal.value - ): - print( - "WARNING: mvr package with name {} already exists. " - "Replacing existing mvr package" - ".".format(pname) - ) - self._remove_package(self._mover_files[package.filename]) - del self._mover_files[package.filename] - elif ( - package.package_type.lower() != "ims" - and pname in self.package_name_dict - ): - if ( - self.simulation_data.verbosity_level.value - >= VerbosityLevel.normal.value - ): - print( - "WARNING: Package with name {} already exists. " - "Replacing existing package" - ".".format(package.package_name.lower()) - ) - self._remove_package(self.package_name_dict[pname]) + self._remove_package_by_type(package) if package.package_type.lower() != "ims": # all but ims packages get added here. ims packages are # added during ims package registration @@ -1815,23 +1977,7 @@ def register_package( return path, self.structure.name_file_struct_obj elif package.package_type.lower() == "tdis": self._tdis_file = package - struct_root = mfstructure.MFStructure() - tdis_pkg = "tdis{}".format(struct_root.get_version_string()) - tdis_attr = getattr(self.name_file, tdis_pkg) - try: - tdis_attr.set_data(package.filename) - except MFDataException as mfde: - message = ( - "An error occurred while setting the tdis package " - 'file name "{}". The error occurred while ' - "registering the tdis package with the " - "simulation".format(package.filename) - ) - raise MFDataException( - mfdata_except=mfde, - package=package._get_pname(), - message=message, - ) + self._set_timing_block(package.filename) return ( path, self.structure.package_struct_objs[ @@ -1900,8 +2046,29 @@ def register_package( print(excpt_str) raise FlopyException(excpt_str) + def rename_model_namefile(self, model, new_namefile): + """ + Rename a model's namefile. For internal flopy library use only. + + Parameters + ---------- + model : MFModel + Model object whose namefile to rename + new_namefile : str + Name of the new namefile + + """ + # update simulation name file + models = self.name_file.models.get_data() + for mdl in models: + path, name_file_name = os.path.split(mdl[1]) + if name_file_name == model.name_file.filename: + mdl[1] = os.path.join(path, new_namefile) + self.name_file.models.set_data(models) + def register_model(self, model, model_type, model_name, model_namefile): - """Add a model to the simulation. This is a call-back method made + """ + Add a model to the simulation. This is a call-back method made from the package and should not be called directly. Parameters @@ -1918,7 +2085,7 @@ def register_model(self, model, model_type, model_name, model_namefile): # get model structure from model type if model_type not in self.structure.model_struct_objs: - message = 'Invalid model type: "{}".'.format(model_type) + message = f'Invalid model type: "{model_type}".' type_, value_, traceback_ = sys.exc_info() raise MFDataException( model.name, @@ -1952,7 +2119,8 @@ 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): - """Get the ims package with the specified `key`. + """ + Get the ims package with the specified `key`. Parameters ---------- @@ -1969,7 +2137,8 @@ def get_ims_package(self, key): return None def remove_model(self, model_name): - """Remove model with name `model_name` from the simulation + """ + Remove model with name `model_name` from the simulation Parameters ---------- @@ -1984,7 +2153,8 @@ def remove_model(self, model_name): # Update simulation name file def is_valid(self): - """Checks the validity of the solution and all of its models and + """ + Checks the validity of the solution and all of its models and packages. Returns true if the solution is valid, false if it is not. @@ -2043,7 +2213,7 @@ def _get_package_path(package): else: return (package.package_type,) - def _remove_ims_soultion_group(self, ims_file): + def _update_ims_solution_group(self, ims_file, new_name=None): solution_recarray = self.name_file.solutiongroup for solution_group_num in solution_recarray.get_active_key_list(): try: @@ -2061,7 +2231,11 @@ def _remove_ims_soultion_group(self, ims_file): new_array = [] for record in rec_array: if record.slnfname == ims_file: - continue + if new_name is not None: + record.slnfname = new_name + new_array.append(tuple(record)) + else: + continue else: new_array.append(record) @@ -2148,7 +2322,8 @@ def _is_in_solution_group(self, item, index): return False def plot(self, model_list=None, SelPackList=None, **kwargs): - """Plot simulation or models. + """ + Plot simulation or models. Method to plot a whole simulation or a series of models that are part of a simulation. diff --git a/dependencies/flopy/mf6/modflow/mftdis.py b/dependencies/flopy/mf6/modflow/mftdis.py index 9279af5..bdea3e1 100644 --- a/dependencies/flopy/mf6/modflow/mftdis.py +++ b/dependencies/flopy/mf6/modflow/mftdis.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator @@ -25,9 +25,13 @@ class ModflowTdis(mfpackage.MFPackage): start_date_time : string * start_date_time (string) is the starting date and time of the simulation. This is a text string that is used as a label within the - simulation list file. The value has no affect on the simulation. The + simulation list file. The value has no effect on the simulation. The recommended format for the starting date and time is described at https://www.w3.org/TR/NOTE-datetime. + ats_filerecord : [ats6_filename] + * ats6_filename (string) defines an adaptive time step (ATS) input file + defining ATS controls. Records in the ATS file can be used to + override the time step behavior for selected stress periods. nper : integer * nper (integer) is the number of stress periods for the simulation. perioddata : [perlen, nstp, tsmult] @@ -50,6 +54,9 @@ class ModflowTdis(mfpackage.MFPackage): """ + ats_filerecord = ListTemplateGenerator( + ("tdis", "options", "ats_filerecord") + ) perioddata = ListTemplateGenerator(("tdis", "perioddata", "perioddata")) package_abbr = "tdis" _package_type = "tdis" @@ -70,6 +77,45 @@ class ModflowTdis(mfpackage.MFPackage): "reader urword", "optional true", ], + [ + "block options", + "name ats_filerecord", + "type record ats6 filein ats6_filename", + "shape", + "reader urword", + "tagged true", + "optional true", + ], + [ + "block options", + "name ats6", + "type keyword", + "shape", + "in_record true", + "reader urword", + "tagged true", + "optional false", + ], + [ + "block options", + "name filein", + "type keyword", + "shape", + "in_record true", + "reader urword", + "tagged true", + "optional false", + ], + [ + "block options", + "name ats6_filename", + "type string", + "preserve_case true", + "in_record true", + "reader urword", + "optional false", + "tagged false", + ], [ "block dimensions", "name nper", @@ -121,6 +167,7 @@ def __init__( loading_package=False, time_units=None, start_date_time=None, + ats_filerecord=None, nper=1, perioddata=((1.0, 1, 1.0),), filename=None, @@ -136,6 +183,9 @@ def __init__( self.start_date_time = self.build_mfdata( "start_date_time", start_date_time ) + self.ats_filerecord = self.build_mfdata( + "ats_filerecord", ats_filerecord + ) self.nper = self.build_mfdata("nper", nper) self.perioddata = self.build_mfdata("perioddata", perioddata) self._init_complete = True diff --git a/dependencies/flopy/mf6/modflow/mfutlats.py b/dependencies/flopy/mf6/modflow/mfutlats.py new file mode 100644 index 0000000..c4427b8 --- /dev/null +++ b/dependencies/flopy/mf6/modflow/mfutlats.py @@ -0,0 +1,211 @@ +# DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY +# mf6/utils/createpackages.py +# FILE created on August 06, 2021 20:56:59 UTC +from .. import mfpackage +from ..data.mfdatautil import ListTemplateGenerator + + +class ModflowUtlats(mfpackage.MFPackage): + """ + ModflowUtlats defines a ats package within a utl model. + + Parameters + ---------- + model : MFModel + Model that this package is a part of. Package is automatically + added to model when it is initialized. + loading_package : bool + Do not set this parameter. It is intended for debugging and internal + processing purposes only. + maxats : integer + * maxats (integer) is the number of records in the subsequent + perioddata block that will be used for adaptive time stepping. + perioddata : [iperats, dt0, dtmin, dtmax, dtadj, dtfailadj] + * iperats (integer) is the period number to designate for adaptive time + stepping. The remaining ATS values on this line will apply to period + iperats. iperats must be greater than zero. A warning is printed if + iperats is greater than nper. This argument is an index variable, + which means that it should be treated as zero-based when working with + FloPy and Python. Flopy will automatically subtract one when loading + index variables and add one when writing index variables. + * dt0 (double) is the initial time step length for period iperats. If + dt0 is zero, then the final step from the previous stress period will + be used as the initial time step. The program will terminate with an + error message if dt0 is negative. + * dtmin (double) is the minimum time step length for this period. This + value must be greater than zero and less than dtmax. dtmin must be a + small value in order to ensure that simulation times end at the end + of stress periods and the end of the simulation. A small value, such + as 1.e-5, is recommended. + * dtmax (double) is the maximum time step length for this period. This + value must be greater than dtmin. + * dtadj (double) is the time step multiplier factor for this period. If + the number of outer solver iterations are less than the product of + the maximum number of outer iterations (OUTER_MAXIMUM) and + ATS_OUTER_MAXIMUM_FRACTION (an optional variable in the IMS input + file with a default value of 1/3), then the time step length is + multipled by dtadj. If the number of outer solver iterations are + greater than the product of the maximum number of outer iterations + and ATS_OUTER_MAXIMUM_FRACTION, then the time step length is divided + by dtadj. dtadj must be zero, one, or greater than one. If dtadj is + zero or one, then it has no effect on the simulation. A value between + 2.0 and 5.0 can be used as an initial estimate. + * dtfailadj (double) is the divisor of the time step length when a time + step fails to converge. If there is solver failure, then the time + step will be tried again with a shorter time step length calculated + as the previous time step length divided by dtfailadj. dtfailadj must + be zero, one, or greater than one. If dtfailadj is zero or one, then + time steps will not be retried with shorter lengths. In this case, + the program will terminate with an error, or it will continue of the + CONTINUE option is set in the simulation name file. Initial tests + with this variable should be set to 5.0 or larger to determine if + convergence can be achieved. + filename : String + File name for this package. + pname : String + Package name for this package. + parent_file : MFPackage + Parent package file that references this package. Only needed for + utility packages (mfutl*). For example, mfutllaktab package must have + a mfgwflak package parent_file. + + """ + + perioddata = ListTemplateGenerator(("ats", "perioddata", "perioddata")) + package_abbr = "utlats" + _package_type = "ats" + dfn_file_name = "utl-ats.dfn" + + dfn = [ + [ + "block dimensions", + "name maxats", + "type integer", + "reader urword", + "optional false", + "default_value 1", + ], + [ + "block perioddata", + "name perioddata", + "type recarray iperats dt0 dtmin dtmax dtadj dtfailadj", + "reader urword", + "optional false", + ], + [ + "block perioddata", + "name iperats", + "type integer", + "in_record true", + "tagged false", + "reader urword", + "optional false", + "numeric_index true", + ], + [ + "block perioddata", + "name dt0", + "type double precision", + "in_record true", + "tagged false", + "reader urword", + "optional false", + ], + [ + "block perioddata", + "name dtmin", + "type double precision", + "in_record true", + "tagged false", + "reader urword", + "optional false", + ], + [ + "block perioddata", + "name dtmax", + "type double precision", + "in_record true", + "tagged false", + "reader urword", + "optional false", + ], + [ + "block perioddata", + "name dtadj", + "type double precision", + "in_record true", + "tagged false", + "reader urword", + "optional false", + ], + [ + "block perioddata", + "name dtfailadj", + "type double precision", + "in_record true", + "tagged false", + "reader urword", + "optional false", + ], + ] + + def __init__( + self, + model, + loading_package=False, + maxats=1, + perioddata=None, + filename=None, + pname=None, + parent_file=None, + ): + super().__init__( + model, "ats", filename, pname, loading_package, parent_file + ) + + # set up variables + self.maxats = self.build_mfdata("maxats", maxats) + self.perioddata = self.build_mfdata("perioddata", perioddata) + self._init_complete = True + + +class UtlatsPackages(mfpackage.MFChildPackages): + """ + UtlatsPackages is a container class for the ModflowUtlats class. + + Methods + ---------- + initialize + Initializes a new ModflowUtlats package removing any sibling child + packages attached to the same parent package. See ModflowUtlats init + documentation for definition of parameters. + append_package + Adds a new ModflowUtlats package to the container. See ModflowUtlats + init documentation for definition of parameters. + """ + + package_abbr = "utlatspackages" + + def initialize(self, maxats=1, perioddata=None, filename=None, pname=None): + new_package = ModflowUtlats( + self._model, + maxats=maxats, + perioddata=perioddata, + filename=filename, + pname=pname, + parent_file=self._cpparent, + ) + self._init_package(new_package, filename) + + def append_package( + self, maxats=1, perioddata=None, filename=None, pname=None + ): + new_package = ModflowUtlats( + self._model, + maxats=maxats, + perioddata=perioddata, + filename=filename, + pname=pname, + parent_file=self._cpparent, + ) + self._append_package(new_package, filename) diff --git a/dependencies/flopy/mf6/modflow/mfutllaktab.py b/dependencies/flopy/mf6/modflow/mfutllaktab.py index 468af07..b72d51d 100644 --- a/dependencies/flopy/mf6/modflow/mfutllaktab.py +++ b/dependencies/flopy/mf6/modflow/mfutllaktab.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfutlobs.py b/dependencies/flopy/mf6/modflow/mfutlobs.py index 9025046..a30428c 100644 --- a/dependencies/flopy/mf6/modflow/mfutlobs.py +++ b/dependencies/flopy/mf6/modflow/mfutlobs.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfutltas.py b/dependencies/flopy/mf6/modflow/mfutltas.py index c1b73bc..71d7a18 100644 --- a/dependencies/flopy/mf6/modflow/mfutltas.py +++ b/dependencies/flopy/mf6/modflow/mfutltas.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator, ArrayTemplateGenerator diff --git a/dependencies/flopy/mf6/modflow/mfutlts.py b/dependencies/flopy/mf6/modflow/mfutlts.py index dc463f2..be80d0d 100644 --- a/dependencies/flopy/mf6/modflow/mfutlts.py +++ b/dependencies/flopy/mf6/modflow/mfutlts.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on March 19, 2021 03:08:37 UTC +# FILE created on August 06, 2021 20:56:59 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/dependencies/flopy/mf6/utils/__init__.py b/dependencies/flopy/mf6/utils/__init__.py index 9637283..984a79e 100644 --- a/dependencies/flopy/mf6/utils/__init__.py +++ b/dependencies/flopy/mf6/utils/__init__.py @@ -3,3 +3,4 @@ from .generate_classes import generate_classes from .binarygrid_util import MfGrdFile from .postprocessing import get_structured_faceflows, get_residuals +from .lakpak_utils import get_lak_connections diff --git a/dependencies/flopy/mf6/utils/binaryfile_utils.py b/dependencies/flopy/mf6/utils/binaryfile_utils.py index ff6ea13..596ff3f 100644 --- a/dependencies/flopy/mf6/utils/binaryfile_utils.py +++ b/dependencies/flopy/mf6/utils/binaryfile_utils.py @@ -13,7 +13,7 @@ class MFOutput: ---------- path: binary file path location mfdict: SimulationDict() object - key: OrderedDictionary key ex. ('flow15','CBC','FLOW RIGHT FACE') + key: dict key ex. ('flow15','CBC','FLOW RIGHT FACE') Returns ------- @@ -55,7 +55,7 @@ class MFOutputRequester: Parameters: ---------- - mfdict: OrderedDict + mfdict: dict local instance of the SimulationDict() object path: pointer to the MFSimulationPath object @@ -97,7 +97,7 @@ def __init__(self, mfdict, path, key): print("\nValid Keys Are:\n") for valid_key in self.dataDict: print(valid_key) - raise KeyError("Invalid key {}".format(key)) + raise KeyError(f"Invalid key {key}") def _querybinarydata(self, key): # Basic definition to get output from modflow binary files for @@ -178,33 +178,25 @@ def _get_binary_file_object(self, path, bintype, key): try: return bf.CellBudgetFile(path, precision="double") except AssertionError: - raise AssertionError( - "{} does not " "exist".format(self.dataDict[key]) - ) + raise AssertionError(f"{self.dataDict[key]} does not exist") elif bintype == "HDS": try: return bf.HeadFile(path, precision="double") except AssertionError: - raise AssertionError( - "{} does not " "exist".format(self.dataDict[key]) - ) + raise AssertionError(f"{self.dataDict[key]} does not exist") elif bintype == "DDN": try: return bf.HeadFile(path, text="drawdown", precision="double") except AssertionError: - raise AssertionError( - "{} does not " "exist".format(self.dataDict[key]) - ) + raise AssertionError(f"{self.dataDict[key]} does not exist") elif bintype == "UCN": try: return bf.UcnFile(path, precision="single") except AssertionError: - raise AssertionError( - "{} does not " "exist".format(self.dataDict[key]) - ) + raise AssertionError(f"{self.dataDict[key]} does not exist") else: raise AssertionError() diff --git a/dependencies/flopy/mf6/utils/binarygrid_util.py b/dependencies/flopy/mf6/utils/binarygrid_util.py index 9a7d9f0..2b498ab 100644 --- a/dependencies/flopy/mf6/utils/binarygrid_util.py +++ b/dependencies/flopy/mf6/utils/binarygrid_util.py @@ -6,7 +6,6 @@ """ import numpy as np -import collections from ...utils.utils_def import FlopyBinaryData import warnings @@ -62,13 +61,13 @@ def __init__(self, filename, precision="double", verbose=False): self.set_float(precision=precision) self.verbose = verbose self._initial_len = 50 - self._recorddict = collections.OrderedDict() - self._datadict = collections.OrderedDict() + self._recorddict = {} + self._datadict = {} self._recordkeys = [] self.filename = filename if self.verbose: - print("\nProcessing binary grid file: {}".format(filename)) + print(f"\nProcessing binary grid file: {filename}") # open the grb file self.file = open(filename, "rb") @@ -119,21 +118,14 @@ def __init__(self, filename, precision="double", verbose=False): s = "" if nd > 0: s = shp - msg = " File contains data for {} ".format( - key - ) + "with shape {}".format(s) - print(msg) + print(f" File contains data for {key} with shape {s}") if self.verbose: - msg = "Attempting to read {} ".format( - self._ntxt - ) + "records from {}".format(filename) - print(msg) + print(f"Attempting to read {self._ntxt} records from {filename}") for key in self._recordkeys: if self.verbose: - msg = " Reading {}".format(key) - print(msg) + print(f" Reading {key}") dt, nd, shp = self._recorddict[key] # read array data if nd > 0: @@ -153,13 +145,9 @@ def __init__(self, filename, precision="double", verbose=False): if self.verbose: if nd == 0: - msg = " {} = {}".format(key, v) - print(msg) + print(f" {key} = {v}") else: - msg = " {}: ".format(key) + "min = {} max = {}".format( - v.min(), v.max() - ) - print(msg) + print(f" {key}: min = {v.min()} max = {v.max()}") # close the file self.file.close() @@ -255,66 +243,12 @@ def __set_modelgrid(self): ) except: - print("could not set model grid for {}".format(self.file.name)) + print(f"could not set model grid for {self.file.name}") self.__modelgrid = modelgrid return - def __set_spatialreference(self): - """ - Define structured or unstructured spatial reference based on - MODFLOW 6 discretization type. - Returns - ------- - sr : SpatialReference - """ - sr = None - try: - if self._grid_type in ("DISV", "DISU"): - from flopy.utils.reference import SpatialReferenceUnstructured - - try: - vertc = self.xycentroids() - xc = vertc[:, 0] - yc = vertc[:, 1] - sr = SpatialReferenceUnstructured( - xc, - yc, - self.__modelgrid.verts, - self.__modelgrid.iverts, - [xc.shape[0]], - ) - except: - msg = ( - "could not set spatial reference for " - + "{} discretization ".format(self._grid_type) - + "defined in {}".format(self.file.name) - ) - print(msg) - elif self._grid_type == "DIS": - from flopy.utils.reference import SpatialReference - - delr, delc = self._datadict["DELR"], self._datadict["DELC"] - xorigin, yorigin, rot = ( - self._datadict["XORIGIN"], - self._datadict["YORIGIN"], - self._datadict["ANGROT"], - ) - sr = SpatialReference( - delr=delr, - delc=delc, - xll=xorigin, - yll=yorigin, - rotation=rot, - ) - except: - print( - "could not set spatial reference for {}".format(self.file.name) - ) - - return sr - def __build_vertices_cell2d(self): """ Build the mf6 vertices and cell2d array to generate a VertexGrid @@ -357,8 +291,7 @@ def __get_iverts(self): i1 = iavert[ivert + 1] iverts.append((javert[i0:i1]).tolist()) if self.verbose: - msg = "returning iverts from {}".format(self.file.name) - print(msg) + print(f"returning iverts from {self.file.name}") return iverts def __get_verts(self): @@ -383,8 +316,7 @@ def __get_verts(self): for idx in range(shpvert[0]) ] if self.verbose: - msg = "returning verts from {}".format(self.file.name) - print(msg) + print(f"returning verts from {self.file.name}") return verts def __get_cellcenters(self): @@ -404,8 +336,7 @@ def __get_cellcenters(self): y = self._datadict["CELLY"] xycellcenters = np.column_stack((x, y)) if self.verbose: - msg = "returning cell centers from {}".format(self.file.name) - print(msg) + print(f"returning cell centers from {self.file.name}") return xycellcenters # properties @@ -775,20 +706,3 @@ def cell2d(self): else: vertices, cell2d = None, None return vertices, cell2d - - @property - def spatialreference(self): - """ - Spatial reference for model grid. - - Returns - ------- - spatialreference : SpatialReference - """ - warnings.warn( - "SpatialReference has been deprecated and will be " - "removed in version 3.3.5. Use get_modelgrid instead.", - category=DeprecationWarning, - ) - - return self.__set_spatialreference() diff --git a/dependencies/flopy/mf6/utils/createpackages.py b/dependencies/flopy/mf6/utils/createpackages.py index e4513cd..45c4e02 100644 --- a/dependencies/flopy/mf6/utils/createpackages.py +++ b/dependencies/flopy/mf6/utils/createpackages.py @@ -19,9 +19,7 @@ class PackageLevel(Enum): def build_doc_string(param_name, param_type, param_desc, indent): - return "{}{} : {}\n{}* {}".format( - indent, param_name, param_type, indent * 2, param_desc - ) + return f"{indent}{param_name} : {param_type}\n{indent * 2}* {param_desc}" def generator_type(data_type): @@ -75,11 +73,11 @@ def build_dfn_string(dfn_list): for data_item in dfn_list: line_length += 1 if not first_di: - dfn_string = "{},\n{}".format(dfn_string, leading_spaces) + dfn_string = f"{dfn_string},\n{leading_spaces}" line_length = len(leading_spaces) else: first_di = False - dfn_string = "{}{}".format(dfn_string, "[") + dfn_string = f"{dfn_string}[" first_line = True # process each line in a data item for line in data_item: @@ -91,38 +89,34 @@ def build_dfn_string(dfn_list): line = line.replace('"', "'") line_length += len(line) + 4 if not first_line: - dfn_string = "{},".format(dfn_string) + dfn_string = f"{dfn_string}," if line_length < 77: # added text fits on the current line if first_line: - dfn_string = '{}"{}"'.format(dfn_string, line) + dfn_string = f'{dfn_string}"{line}"' else: - dfn_string = '{} "{}"'.format(dfn_string, line) + dfn_string = f'{dfn_string} "{line}"' else: # added text does not fit on the current line line_length = len(line) + len(leading_spaces) + 2 if line_length > 79: # added text too long to fit on a single line, wrap # text as needed - line = '"{}"'.format(line) + line = f'"{line}"' lines = textwrap.wrap( line, 75 - len(leading_spaces), drop_whitespace=True, ) - lines[0] = "{} {}".format(leading_spaces, lines[0]) - line_join = ' "\n{} "'.format(leading_spaces) - dfn_string = "{}\n{}".format( - dfn_string, line_join.join(lines) - ) + lines[0] = f"{leading_spaces} {lines[0]}" + line_join = f' "\n{leading_spaces} "' + dfn_string = f"{dfn_string}\n{line_join.join(lines)}" else: - dfn_string = '{}\n{} "{}"'.format( - dfn_string, leading_spaces, line - ) + dfn_string = f'{dfn_string}\n{leading_spaces} "{line}"' first_line = False - dfn_string = "{}{}".format(dfn_string, "]") - dfn_string = "{}{}".format(dfn_string, "]") + dfn_string = f"{dfn_string}]" + dfn_string = f"{dfn_string}]" return dfn_string @@ -130,38 +124,34 @@ def create_init_var(clean_ds_name, data_structure_name, init_val=None): if init_val is None: init_val = clean_ds_name - init_var = " self.{} = self.build_mfdata(".format(clean_ds_name) + init_var = f" self.{clean_ds_name} = self.build_mfdata(" leading_spaces = " " * len(init_var) if len(init_var) + len(data_structure_name) + 2 > 79: - second_line = '\n "{}",'.format(data_structure_name) + second_line = f'\n "{data_structure_name}",' if len(second_line) + len(clean_ds_name) + 2 > 79: - init_var = "{}{}\n {})".format( - init_var, second_line, init_val - ) + init_var = f"{init_var}{second_line}\n {init_val})" else: - init_var = "{}{} {})".format(init_var, second_line, init_val) + init_var = f"{init_var}{second_line} {init_val})" else: - init_var = '{}"{}",'.format(init_var, data_structure_name) + init_var = f'{init_var}"{data_structure_name}",' if len(init_var) + len(clean_ds_name) + 2 > 79: - init_var = "{}\n{}{})".format(init_var, leading_spaces, init_val) + init_var = f"{init_var}\n{leading_spaces}{init_val})" else: - init_var = "{} {})".format(init_var, init_val) + init_var = f"{init_var} {init_val})" return init_var def create_basic_init(clean_ds_name): - return " self.{} = {}\n".format(clean_ds_name, clean_ds_name) + return f" self.{clean_ds_name} = {clean_ds_name}\n" def create_property(clean_ds_name): - return " {} = property(get_{}, set_{}" ")".format( - clean_ds_name, clean_ds_name, clean_ds_name - ) + return f" {clean_ds_name} = property(get_{clean_ds_name}, set_{clean_ds_name})" def format_var_list(base_string, var_list, is_tuple=False): if is_tuple: - base_string = "{}(".format(base_string) + base_string = f"{base_string}(" extra_chars = 4 else: extra_chars = 2 @@ -171,43 +161,39 @@ def format_var_list(base_string, var_list, is_tuple=False): for item in var_list: if line_length + len(item) + extra_chars > 80: leading_spaces = " " - base_string = "{}\n{}".format(base_string, leading_spaces) + base_string = f"{base_string}\n{leading_spaces}" line_length = len(leading_spaces) break for index, item in enumerate(var_list): if is_tuple: - item = "'{}'".format(item) + item = f"'{item}'" if index == len(var_list) - 1: next_var_str = item else: - next_var_str = "{},".format(item) + next_var_str = f"{item}," line_length += len(item) + extra_chars if line_length > 80: - base_string = "{}\n{}{}".format( - base_string, leading_spaces, next_var_str - ) + base_string = f"{base_string}\n{leading_spaces}{next_var_str}" else: if base_string[-1] == ",": - base_string = "{} ".format(base_string) - base_string = "{}{}".format(base_string, next_var_str) + base_string = f"{base_string} " + base_string = f"{base_string}{next_var_str}" if is_tuple: - return "{}))".format(base_string) + return f"{base_string}))" else: - return "{})".format(base_string) + return f"{base_string})" def create_package_init_var(parameter_name, package_abbr, data_name): - one_line = " self._{}_package = self.build_child_package(".format( - package_abbr + one_line = ( + f" self._{package_abbr}_package = self.build_child_package(" ) - one_line_b = '"{}", {},'.format(package_abbr, parameter_name) + one_line_b = f'"{package_abbr}", {parameter_name},' leading_spaces = " " * len(one_line) - two_line = '\n{}"{}",'.format(leading_spaces, data_name) - three_line = "\n{}self._{}_filerecord)".format( - leading_spaces, package_abbr - ) - return "{}{}{}{}".format(one_line, one_line_b, two_line, three_line) + two_line = f'\n{leading_spaces}"{data_name}",' + three_line = f"\n{leading_spaces}self._{package_abbr}_filerecord)" + return f"{one_line}{one_line_b}{two_line}{three_line}" def add_var( @@ -241,15 +227,13 @@ def add_var( # add to parameter list if default_value is None: default_value = "None" - init_param_list.append("{}={}".format(clean_ds_name, default_value)) + init_param_list.append(f"{clean_ds_name}={default_value}") # add to set parameter list - set_param_list.append("{}={}".format(clean_ds_name, clean_ds_name)) + set_param_list.append(f"{clean_ds_name}={clean_ds_name}") else: clean_parameter_name = datautil.clean_name(parameter_name) # init hidden variable - init_vars.append( - create_init_var("_{}".format(clean_ds_name), name, "None") - ) + init_vars.append(create_init_var(f"_{clean_ds_name}", name, "None")) # init child package init_vars.append( create_package_init_var( @@ -257,11 +241,9 @@ def add_var( ) ) # add to parameter list - init_param_list.append("{}=None".format(clean_parameter_name)) + init_param_list.append(f"{clean_parameter_name}=None") # add to set parameter list - set_param_list.append( - "{}={}".format(clean_parameter_name, clean_parameter_name) - ) + set_param_list.append(f"{clean_parameter_name}={clean_parameter_name}") package_properties.append(create_property(clean_ds_name)) doc_string.add_parameter(description, model_parameter=True) @@ -269,7 +251,7 @@ def add_var( if class_vars is not None: gen_type = generator_type(data_type) if gen_type != "ScalarTemplateGenerator": - new_class_var = " {} = {}(".format(clean_ds_name, gen_type) + new_class_var = f" {clean_ds_name} = {gen_type}(" class_vars.append(format_var_list(new_class_var, path, True)) return gen_type return None @@ -298,11 +280,11 @@ def build_init_string( ) line_chars = len(param_list[1]) + len(whitespace) + 1 continue - init_string = "{},\n{}{}".format(init_string, whitespace, param) + init_string = f"{init_string},\n{whitespace}{param}" line_chars = len(param) + len(whitespace) + 1 else: - init_string = "{}, {}".format(init_string, param) - return "{}):\n".format(init_string) + init_string = f"{init_string}, {param}" + return f"{init_string}):\n" def build_model_load(model_type): @@ -339,8 +321,7 @@ def build_model_init_vars(param_list): for param in param_list: param_parts = param.split("=") init_var_list.append( - " self.name_file.{}.set_data({}" - ")".format(param_parts[0], param_parts[0]) + f" self.name_file.{param_parts[0]}.set_data({param_parts[0]})" ) return "\n".join(init_var_list) @@ -432,7 +413,7 @@ def create_packages(): template_gens = [] dfn_string = build_dfn_string(package[3]) package_abbr = clean_class_string( - "{}{}".format(clean_class_string(package[2]), package[0].file_type) + f"{clean_class_string(package[2])}{package[0].file_type}" ).lower() package_name = clean_class_string( "{}{}{}".format( @@ -445,12 +426,10 @@ def create_packages(): doc_string = mfdatautil.MFDocString(package[0].description) else: if package[2]: - package_container_text = " within a {} model".format( - package[2] - ) + package_container_text = f" within a {package[2]} model" else: package_container_text = "" - ds = "Modflow{} defines a {} package" "{}.".format( + ds = "Modflow{} defines a {} package{}.".format( package_name.title(), package[0].file_type, package_container_text, @@ -489,7 +468,7 @@ def create_packages(): build_doc_string( "exgtype", "", - "is the exchange type (GWF-GWF or " "GWF-GWT).", + "is the exchange type (GWF-GWF or GWF-GWT).", indent, ), None, @@ -571,22 +550,20 @@ def create_packages(): import_string = "from .. import mfpackage" if template_gens: - import_string = "{}\nfrom ..data.mfdatautil import" " ".format( - import_string - ) + import_string = f"{import_string}\nfrom ..data.mfdatautil import " first_string = True for template in template_gens: if first_string: - import_string = "{}{}".format(import_string, template) + import_string = f"{import_string}{template}" first_string = False else: - import_string = "{}, {}".format(import_string, template) + import_string = f"{import_string}, {template}" # add extra docstrings for additional variables doc_string.add_parameter( - " filename : String\n " "File name for this package." + " filename : String\n File name for this package." ) doc_string.add_parameter( - " pname : String\n " "Package name for this package." + " pname : String\n Package name for this package." ) doc_string.add_parameter( " parent_file : MFPackage\n " @@ -616,7 +593,7 @@ def create_packages(): ) ) init_string_full = init_string_def - init_string_model = "{}, simulation".format(init_string_def) + init_string_model = f"{init_string_def}, simulation" # add variables to init string doc_string.add_parameter( " loading_package : bool\n " @@ -635,8 +612,7 @@ def create_packages(): beginning_of_list=True, ) init_string_full = ( - "{}, simulation, loading_package=" - "False".format(init_string_full) + f"{init_string_full}, simulation, loading_package=False" ) else: doc_string.add_parameter( @@ -646,8 +622,8 @@ def create_packages(): "to model when it is initialized.", beginning_of_list=True, ) - init_string_full = "{}, model, loading_package=False".format( - init_string_full + init_string_full = ( + f"{init_string_full}, model, loading_package=False" ) init_param_list.append("filename=None") init_param_list.append("pname=None") @@ -671,8 +647,8 @@ def create_packages(): local_datetime = datetime.datetime.now(datetime.timezone.utc) comment_string = ( "# DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE " - + "MUST BE CREATED BY\n# mf6/utils/createpackages.py\n# FILE " - + "created on {} UTC".format( + "MUST BE CREATED BY\n# mf6/utils/createpackages.py\n" + "# FILE created on {} UTC".format( local_datetime.strftime("%B %d, %Y %H:%M:%S") ) ) @@ -691,9 +667,7 @@ def create_packages(): # open new Packages file pb_file = io.open( - os.path.join( - util_path, "..", "modflow", "mf{}.py".format(package_name) - ), + os.path.join(util_path, "..", "modflow", f"mf{package_name}.py"), "w", newline="\n", ) @@ -718,18 +692,15 @@ def create_packages(): "\n\nclass Utl{}Packages(mfpackage.MFChildPackage" "s):\n".format(package_short_name) ) - chld_var = ' package_abbr = "utl{}packages"\n\n'.format( - package_short_name + chld_var = ( + f' package_abbr = "utl{package_short_name}packages"\n\n' ) chld_init = " def initialize(self" chld_init = build_init_string( chld_init, init_param_list[:-1], whsp_1 ) init_pkg = "\n self._init_package(new_package, filename)" - params_init = ( - " new_package = ModflowUtl{}(" - "self._model".format(package_short_name) - ) + params_init = f" new_package = ModflowUtl{package_short_name}(self._model" params_init = build_init_string( params_init, set_param_list, whsp_2 ) @@ -753,12 +724,9 @@ def create_packages(): chld_appn, init_param_list[:-1], whsp_1 ) append_pkg = ( - "\n self._append_package(new_package, " "filename)" - ) - params_appn = ( - " new_package = ModflowUtl{}(" - "self._model".format(package_short_name) + "\n self._append_package(new_package, filename)" ) + params_appn = f" new_package = ModflowUtl{package_short_name}(self._model" params_appn = build_init_string( params_appn, set_param_list, whsp_2 ) @@ -771,7 +739,7 @@ def create_packages(): chld_doc_string, package_short_name, package_short_name ) ) - chld_doc_string = '{} """\n'.format(chld_doc_string) + chld_doc_string = f'{chld_doc_string} """\n' packages_str = "{}{}{}{}{}{}{}{}{}\n".format( chld_cls, chld_doc_string, @@ -787,8 +755,7 @@ def create_packages(): pb_file.close() init_file.write( - "from .mf{} import " - "Modflow{}\n".format(package_name, package_name.title()) + f"from .mf{package_name} import Modflow{package_name.title()}\n" ) if package[0].dfn_type == mfstructure.DfnType.model_name_file: @@ -819,10 +786,10 @@ def create_packages(): beginning_of_list=True, model_parameter=True, ) - doc_string.description = "Modflow{} defines a {} model".format( - model_name, model_name + doc_string.description = ( + f"Modflow{model_name} defines a {model_name} model" ) - class_var_string = " model_type = '{}'\n".format(model_name) + class_var_string = f" model_type = '{model_name}'\n" mparent_init_string = " super().__init__(" spaces = " " * len(mparent_init_string) mparent_init_string = ( @@ -856,17 +823,14 @@ def create_packages(): load_txt, ) md_file = io.open( - os.path.join( - util_path, "..", "modflow", "mf{}.py".format(model_name) - ), + os.path.join(util_path, "..", "modflow", f"mf{model_name}.py"), "w", newline="\n", ) md_file.write(package_string) md_file.close() init_file.write( - "from .mf{} import " - "Modflow{}\n".format(model_name, model_name.capitalize()) + f"from .mf{model_name} import Modflow{model_name.capitalize()}\n" ) init_file.close() diff --git a/dependencies/flopy/mf6/utils/generate_classes.py b/dependencies/flopy/mf6/utils/generate_classes.py index d9ae60a..e21780a 100644 --- a/dependencies/flopy/mf6/utils/generate_classes.py +++ b/dependencies/flopy/mf6/utils/generate_classes.py @@ -24,17 +24,17 @@ def delete_files(files, pth, allow_failure=False, exclude=None): continue fpth = os.path.join(pth, fn) try: - print(" removing...{}".format(fn)) + print(f" removing...{fn}") os.remove(fpth) except: - print("could not remove...{}".format(fn)) + print(f"could not remove...{fn}") if not allow_failure: return False return True def list_files(pth, exts=["py"]): - print("\nLIST OF FILES IN {}".format(pth)) + print(f"\nLIST OF FILES IN {pth}") files = [ entry for entry in os.listdir(pth) @@ -45,7 +45,7 @@ def list_files(pth, exts=["py"]): ext = os.path.splitext(fn)[1][1:].lower() if ext in exts: idx += 1 - print(" {:5d} - {}".format(idx, fn)) + print(f" {idx:5d} - {fn}") return @@ -66,12 +66,10 @@ def download_dfn(branch, new_dfn_pth): mf6url = "https://github.com/MODFLOW-USGS/modflow6/archive/{}.zip" mf6url = mf6url.format(branch) - print(" Downloading MODFLOW 6 repository from {}".format(mf6url)) + print(f" Downloading MODFLOW 6 repository from {mf6url}") with tempfile.TemporaryDirectory() as tmpdirname: pymake.download_and_unzip(mf6url, tmpdirname) - downloaded_dfn_pth = os.path.join( - tmpdirname, "modflow6-{}".format(branch) - ) + downloaded_dfn_pth = os.path.join(tmpdirname, f"modflow6-{branch}") downloaded_dfn_pth = os.path.join( downloaded_dfn_pth, "doc", "mf6io", "mf6ivar", "dfn" ) @@ -86,7 +84,7 @@ def backup_existing_dfns(flopy_dfn_path): shutil.copytree(flopy_dfn_path, backup_folder) assert os.path.isdir( backup_folder - ), "dfn backup files not found: {}".format(backup_folder) + ), f"dfn backup files not found: {backup_folder}" return @@ -100,7 +98,7 @@ def replace_dfn_files(new_dfn_pth, flopy_dfn_path): filenames = os.listdir(new_dfn_pth) for filename in filenames: filename_w_path = os.path.join(new_dfn_pth, filename) - print(" copying..{}".format(filename)) + print(f" copying..{filename}") shutil.copy(filename_w_path, flopy_dfn_path) @@ -146,23 +144,17 @@ def generate_classes(branch="master", dfnpath=None, backup=True): # download the dfn files and put them in flopy.mf6.data or update using # user provided dfnpath if dfnpath is None: - print( - " Updating the MODFLOW 6 classes using the branch: {}".format( - branch - ) - ) + print(f" Updating the MODFLOW 6 classes using the branch: {branch}") timestr = time.strftime("%Y%m%d-%H%M%S") - new_dfn_pth = os.path.join(flopypth, "mf6", "data", "dfn_" + timestr) + new_dfn_pth = os.path.join(flopypth, "mf6", "data", f"dfn_{timestr}") download_dfn(branch, new_dfn_pth) else: - print(" Updating the MODFLOW 6 classes using {}".format(dfnpath)) + print(f" Updating the MODFLOW 6 classes using {dfnpath}") assert os.path.isdir(dfnpath) new_dfn_pth = dfnpath if backup: - print( - " Backup existing definition files in: {}".format(flopy_dfn_path) - ) + print(f" Backup existing definition files in: {flopy_dfn_path}") backup_existing_dfns(flopy_dfn_path) print(" Replacing existing definition files with new ones.") diff --git a/dependencies/flopy/mf6/utils/lakpak_utils.py b/dependencies/flopy/mf6/utils/lakpak_utils.py new file mode 100644 index 0000000..1b0bd51 --- /dev/null +++ b/dependencies/flopy/mf6/utils/lakpak_utils.py @@ -0,0 +1,281 @@ +import numpy as np + + +def get_lak_connections(modelgrid, lake_map, idomain=None, bedleak=None): + """ + Function to create lake package connection data from a zero-based + integer array of lake numbers. If the shape of lake number array is + equal to (nrow, ncol) or (ncpl) then the lakes are on top of the model + and are vertically connected to cells at the top of the model. Otherwise + the lakes are embedded in the grid. + + TODO: implement embedded lakes for VertexGrid + + TODO: add support for UnstructuredGrid + + Parameters + ---------- + modelgrid : StructuredGrid, VertexGrid + model grid + lake_map : MaskedArray, ndarray, list, tuple + location and zero-based lake number for lakes in the model domain. + If lake_map is of size (nrow, ncol) or (ncpl) lakes are located on + top of the model and vertically connected to cells in model layer 1. + If lake_map is of size (nlay, nrow, ncol) or (nlay, ncpl) lakes + are embedded in the model domain and horizontal and vertical lake + connections are defined. + idomain : int or ndarray + location of inactive cells, which are defined with a zero value. If a + ndarray is passed it must be of size (nlay, nrow, ncol) or + (nlay, ncpl). + bedleak : ndarray, list, tuple, float + bed leakance for lakes in the model domain. If bedleak is a float the + same bed leakance is applied to each lake connection in the model. + If bedleak is of size (nrow, ncol) or (ncpl) then all lake + connections for the cellid are given the same bed leakance value. If + bedleak is None, lake conductance is only a function of aquifer + properties for all lakes. Can also pass mixed values as list or + ndarray of size (nrow, ncol) or (ncpl) with floats and 'none' strings. + + Returns + ------- + idomain : ndarry + idomain adjusted to inactivate cells with lakes + connection_dict : dict + dictionary with the zero-based lake number keys and number of + connections in a lake values + connectiondata : list of lists + connectiondata block for the lake package + + """ + + if modelgrid.grid_type in ("unstructured",): + raise ValueError( + "unstructured grids not supported in get_lak_connections()" + ) + + embedded = True + shape3d = modelgrid.shape + shape2d = shape3d[1:] + + # convert to numpy array if necessary + if isinstance(lake_map, (list, tuple)): + lake_map = np.array(lake_map, dtype=np.int32) + elif isinstance(lake_map, (int, float)): + raise TypeError( + "lake_map must be a Masked Array, ndarray, list, or tuple" + ) + + # evaluate lake_map shape + shape_map = lake_map.shape + if shape_map != shape3d: + if shape_map != shape2d: + raise ValueError( + "lake_map shape ({}) must be equal to the grid shape for " + "each layer ({})".format(shape_map, shape2d) + ) + else: + embedded = False + + # process idomain + if idomain is None: + idomain = np.ones(shape3d, dtype=np.int32) + elif isinstance(idomain, int): + idomain = np.ones(shape3d, dtype=np.int32) * idomain + elif isinstance(idomain, (float, bool)): + raise ValueError("idomain must be a integer") + + # check dimensions of idomain + if idomain.shape != shape3d: + raise ValueError( + f"shape of idomain ({idomain.shape}) not equal to {shape3d}" + ) + + # convert bedleak to numpy array if necessary + if bedleak is None: + bedleak = np.chararray(shape2d, itemsize=4, unicode=True) + bedleak[:] = "none" + elif isinstance(bedleak, (float, int)): + bedleak = np.ones(shape2d, dtype=float) * float(bedleak) + elif isinstance(bedleak, (list, tuple)): + bedleak = np.array(bedleak, dtype=object) + + # check the dimensions of the bedleak array + if bedleak.shape != shape2d: + raise ValueError( + f"shape of bedleak ({bedleak.shape}) not equal to {shape2d}" + ) + + # get the model grid elevations and reset lake_map using idomain + # if lake is embedded and in an inactive cell + if embedded: + elevations = modelgrid.top_botm + lake_map[idomain < 1] = -1 + else: + elevations = None + + # determine if masked array, in not convert to masked array + if not np.ma.is_masked(lake_map): + lake_map = np.ma.masked_where(lake_map < 0, lake_map) + + connection_dict = {} + connectiondata = [] + + # find unique lake numbers + unique = np.unique(lake_map) + + # exclude lakes with lake numbers less than 0 + idx = np.where(unique > -1) + unique = unique[idx] + + dx, dy = None, None + + # embedded lakes + for lake_number in unique: + iconn = 0 + indices = np.argwhere(lake_map == lake_number) + for index in indices: + cell_index = tuple(index.tolist()) + if embedded: + leak_value = bedleak[cell_index[1:]] + if modelgrid.grid_type == "structured": + if dx is None: + xv, yv = modelgrid.xvertices, modelgrid.yvertices + dx = xv[0, 1:] - xv[0, :-1] + dy = yv[:-1, 0] - yv[1:, 0] + ( + cellids, + claktypes, + belevs, + televs, + connlens, + connwidths, + ) = __structured_lake_connections( + lake_map, idomain, cell_index, dx, dy, elevations + ) + elif modelgrid.grid_type == "vertex": + raise NotImplementedError( + "embedded lakes have not been implemented" + ) + else: + cellid = (0,) + cell_index + leak_value = bedleak[cell_index] + if idomain[cellid] > 0: + cellids = [cellid] + claktypes = ["vertical"] + belevs = [0.0] + televs = [0.0] + connlens = [0.0] + connwidths = [0.0] + else: + cellids = [] + claktypes = [] + belevs = [] + televs = [] + connlens = [] + connwidths = [] + + # iterate through each cellid + for (cellid, claktype, belev, telev, connlen, connwidth) in zip( + cellids, claktypes, belevs, televs, connlens, connwidths + ): + connectiondata.append( + [ + lake_number, + iconn, + cellid[:], + claktype, + leak_value, + belev, + telev, + connlen, + connwidth, + ] + ) + iconn += 1 + + # set number of connections for lake + connection_dict[lake_number] = iconn + + # reset idomain for lake + if iconn > 0: + idx = np.where((lake_map == lake_number) & (idomain > 0)) + idomain[idx] = 0 + + return idomain, connection_dict, connectiondata + + +def __structured_lake_connections( + lake_map, idomain, cell_index, dx, dy, elevations +): + nlay, nrow, ncol = lake_map.shape + cellids = [] + claktypes = [] + belevs = [] + televs = [] + connlens = [] + connwidths = [] + + k, i, j = cell_index + + if idomain[cell_index] > 0: + # back face + if i > 0: + ci = (k, i - 1, j) + cit = (k + 1, i - 1, j) + if np.ma.is_masked(lake_map[ci]) and idomain[ci] > 0: + cellids.append(ci) + claktypes.append("horizontal") + belevs.append(elevations[cit]) + televs.append(elevations[ci]) + connlens.append(0.5 * dy[i - 1]) + connwidths.append(dx[j]) + + # left face + if j > 0: + ci = (k, i, j - 1) + cit = (k + 1, i, j - 1) + if np.ma.is_masked(lake_map[ci]) and idomain[ci] > 0: + cellids.append(ci) + claktypes.append("horizontal") + belevs.append(elevations[cit]) + televs.append(elevations[ci]) + connlens.append(0.5 * dx[j - 1]) + connwidths.append(dy[i]) + + # right face + if j < ncol - 1: + ci = (k, i, j + 1) + cit = (k + 1, i, j + 1) + if np.ma.is_masked(lake_map[ci]) and idomain[ci] > 0: + cellids.append(ci) + claktypes.append("horizontal") + belevs.append(elevations[cit]) + televs.append(elevations[ci]) + connlens.append(0.5 * dx[j + 1]) + connwidths.append(dy[i]) + + # front face + if i < nrow - 1: + ci = (k, i + 1, j) + cit = (k + 1, i + 1, j) + if np.ma.is_masked(lake_map[ci]) and idomain[ci] > 0: + cellids.append(ci) + claktypes.append("horizontal") + belevs.append(elevations[cit]) + televs.append(elevations[ci]) + connlens.append(0.5 * dy[i + 1]) + connwidths.append(dx[j]) + + # lower face + if k < nlay - 1: + ci = (k + 1, i, j) + if np.ma.is_masked(lake_map[ci]) and idomain[ci] > 0: + cellids.append(ci) + claktypes.append("vertical") + belevs.append(0.0) + televs.append(0.0) + connlens.append(0.0) + connwidths.append(0.0) + + return cellids, claktypes, belevs, televs, connlens, connwidths diff --git a/dependencies/flopy/mf6/utils/mfobservation.py b/dependencies/flopy/mf6/utils/mfobservation.py index 04a1c6c..dc48344 100644 --- a/dependencies/flopy/mf6/utils/mfobservation.py +++ b/dependencies/flopy/mf6/utils/mfobservation.py @@ -255,9 +255,7 @@ def get_dataframe( keys = self._key_list(keys) for key in keys: if key not in data: - raise KeyError( - "Supplied data key: {} is not " "valid".format(key) - ) + raise KeyError(f"Supplied data key: {key} is not valid") else: pass @@ -410,8 +408,7 @@ def __init__(self, mfdict, path, key, **kwargs): pass else: - err = "{} is not a valid dictionary key\n".format(str(key)) - raise KeyError(err) + raise KeyError(f"{key} is not a valid dictionary key") def _query_observation_data(self, modelpath, key): # get absolute path for observation data files @@ -448,7 +445,7 @@ def _check_for_observations(self): if check > 1: multi_observations = [i for i in partial_key if i == line] for i in range(len(multi_observations)): - obs8_file = "OBS8_{}".format(i + 1) + obs8_file = f"OBS8_{i + 1}" # check for single observations, continuous observations self._get_obsfile_names( multi_observations[i], obs8_file, "SINGLE" @@ -532,9 +529,7 @@ def _get_package_type(self, obstypes): return "GWF" else: - raise KeyError( - "{} is not a valid observation " "type".format(package) - ) + raise KeyError(f"{package} is not a valid observation type") @staticmethod def getkeys(mfdict, path): diff --git a/dependencies/flopy/mf6/utils/output_util.py b/dependencies/flopy/mf6/utils/output_util.py index cf46990..1184f86 100644 --- a/dependencies/flopy/mf6/utils/output_util.py +++ b/dependencies/flopy/mf6/utils/output_util.py @@ -1,7 +1,15 @@ import os -from ...utils import HeadFile, CellBudgetFile, Mf6Obs, ZoneBudget6, ZoneFile6 +from ...utils import ( + HeadFile, + CellBudgetFile, + Mf6Obs, + ZoneBudget6, + ZoneFile6, + Mf6ListBudget, +) from ...utils.observationfile import CsvFile from ...pakbase import PackageInterface +from ...mbase import ModelInterface class MF6Output: @@ -16,7 +24,7 @@ class MF6Output: """ def __init__(self, obj): - from ..modflow import ModflowUtlobs + from ..modflow import ModflowUtlobs, ModflowGwtoc, ModflowGwfoc # set initial observation definitions methods = { @@ -31,9 +39,25 @@ def __init__(self, obj): self._methods = [] self._sim_ws = obj.simulation_data.mfpath.get_sim_path() - if not isinstance(obj, PackageInterface): + if not isinstance(obj, (PackageInterface, ModelInterface)): raise TypeError("Only mf6 PackageInterface types can be used") + # capture the list file for Models and for OC packages + if isinstance(obj, (ModelInterface, ModflowGwfoc, ModflowGwtoc)): + if isinstance(obj, ModelInterface): + ml = obj + else: + ml = obj.parent + self._mtype = ml.model_type + nam_file = ml.model_nam_file[:-4] + self._lst = ml.name_file.blocks["options"].datasets["list"].array + if self._lst is None: + self._lst = f"{nam_file}.lst" + setattr(self, "list", self.__list) + self._methods.append("list()") + if isinstance(obj, ModelInterface): + return + obspkg = False if isinstance(obj, ModflowUtlobs): # this is a package @@ -68,7 +92,7 @@ def __init__(self, obj): self, "zonebudget", methods["zonebudget"] ) self._methods.append("zonebudget()") - self._methods.append("{}()".format(rectype)) + self._methods.append(f"{rectype}()") if rectype == "obs": data = None for ky in obj._simulation_data.mfdata: @@ -76,10 +100,32 @@ def __init__(self, obj): if str(ky[-2]).lower() == "fileout": data = [[ky[-1]]] break + elif ( + str(ky[-3]) == "continuous" + and str(ky[-1]) == "output" + ): + if ( + obj._simulation_data.mfdata[ + ky + ].array[0][0] + == "fileout" + ): + data = [ + [ + obj._simulation_data.mfdata[ + ky + ].array[ + 0 + ][ + -2 + ] + ] + ] + break if rectype == "package_convergence": rectype = "csv" - attr_name = "_{}".format(rectype) + attr_name = f"_{rectype}" # need a check for obs.... if data is not None: if not hasattr(self, attr_name): @@ -96,10 +142,10 @@ def __init__(self, obj): else: setattr(self, rectype, methods[rectype]) - self._methods.append("{}()".format(rectype)) + self._methods.append(f"{rectype}()") data = obj.data_list[2].data for f in data.keys(): - attr_name = "_{}".format(rectype) + attr_name = f"_{rectype}" if not hasattr(self, attr_name): setattr(self, attr_name, [f]) else: @@ -137,11 +183,11 @@ def get_layerfile_data(self, f=data, text=rectype): try: f = os.path.join(self._sim_ws, f) return HeadFile(f, text=text) - except (IOError, FileNotFoundError): + except OSError: return setattr(self.__class__, rectype, get_layerfile_data) - self._methods.append("{}()".format(rectype)) + self._methods.append(f"{rectype}()") def methods(self): """ @@ -204,7 +250,7 @@ def __zonebudget(self, izone): is None ): grb = os.path.join( - self._sim_ws, dis.filename + ".grb" + self._sim_ws, f"{dis.filename}.grb" ) except AttributeError: pass @@ -224,7 +270,7 @@ def __budget(self, precision="double"): try: budget_file = os.path.join(self._sim_ws, self._budget[0]) return CellBudgetFile(budget_file, precision=precision) - except (IOError, FileNotFoundError): + except OSError: return None def __obs(self, f=None): @@ -244,7 +290,7 @@ def __obs(self, f=None): try: obs_file = os.path.join(self._sim_ws, obs_file) return Mf6Obs(obs_file) - except (IOError, FileNotFoundError): + except OSError: return None def __csv(self, f=None): @@ -264,7 +310,22 @@ def __csv(self, f=None): try: csv_file = os.path.join(self._sim_ws, csv_file) return CsvFile(csv_file) - except (IOError, FileNotFoundError): + except OSError: + return None + + def __list(self): + """ + Method to read list files + + Returns + ------- + Mf6ListBudget object + """ + if self._lst is not None: + try: + list_file = os.path.join(self._sim_ws, self._lst) + return Mf6ListBudget(list_file) + except (AssertionError, OSError): return None def __mulitfile_handler(self, f, flist): @@ -288,10 +349,7 @@ def __mulitfile_handler(self, f, flist): else: idx = flist.index(f) if idx is None: - err = ( - "File name not found, " - "available files are {}".format(", ".join(flist)) - ) + err = f"File name not found, available files are {', '.join(flist)}" raise FileNotFoundError(err) else: filename = flist[idx] diff --git a/dependencies/flopy/mf6/utils/postprocessing.py b/dependencies/flopy/mf6/utils/postprocessing.py index 6e795ab..bf4bee9 100644 --- a/dependencies/flopy/mf6/utils/postprocessing.py +++ b/dependencies/flopy/mf6/utils/postprocessing.py @@ -39,16 +39,15 @@ def get_structured_faceflows( if grb.grid_type != "DIS": raise ValueError( "get_structured_faceflows method " - + "is only for structured DIS grids" + "is only for structured DIS grids" ) ia, ja = grb.ia, grb.ja else: if ia is None or ja is None: - err_msg = ( + raise ValueError( "ia and ja arrays must be specified if the MODFLOW 6" - + "binary grid file name is not specified." + "binary grid file name is not specified." ) - raise ValueError(err_msg) # flatten flowja, if necessary if len(flowja.shape) > 0: @@ -116,11 +115,10 @@ def get_residuals( ia, ja = grb.ia, grb.ja else: if ia is None or ja is None: - err_msg = ( - "ia and ja arrays must be specified if the MODFLOW 6" - + "binary grid file name is not specified." + raise ValueError( + "ia and ja arrays must be specified if the MODFLOW 6 " + "binary grid file name is not specified." ) - raise ValueError(err_msg) # flatten flowja, if necessary if len(flowja.shape) > 0: @@ -154,6 +152,5 @@ def __check_flowja_size(flowja, ja): """ if flowja.shape != ja.shape: raise ValueError( - "size of flowja ({}) ".format(flowja.shape) - + "not equal to {}".format(ja.shape) + f"size of flowja ({flowja.shape}) not equal to {ja.shape}" ) diff --git a/dependencies/flopy/mf6/utils/reference.py b/dependencies/flopy/mf6/utils/reference.py index 2622ed9..7c60447 100644 --- a/dependencies/flopy/mf6/utils/reference.py +++ b/dependencies/flopy/mf6/utils/reference.py @@ -79,7 +79,7 @@ def __init__( yul=None, rotation=0.0, proj4_str=None, - **kwargs + **kwargs, ): self.delc = np.atleast_1d(np.array(delc)) self.delr = np.atleast_1d(np.array(delr)) @@ -260,10 +260,8 @@ def set_spatialreference(self, xul=None, yul=None, rotation=0.0): self._reset() def __repr__(self): - s = "xul:{0: 0: f_nam.write( @@ -486,7 +482,7 @@ def write_name_file(self): self.lst.file_name[0], ) ) - f_nam.write("{}".format(self.get_name_file_entries())) + f_nam.write(str(self.get_name_file_entries())) # write the external files for u, f, b, o in zip( @@ -499,17 +495,13 @@ def write_name_file(self): continue replace_text = "" if o: - replace_text = "REPLACE" + replace_text = " REPLACE" if b: - line = ( - "DATA(BINARY) {0:5d} ".format(u) - + f - + replace_text - + "\n" - ) + line = f"DATA(BINARY) {u:5d} {f}{replace_text}\n" + f_nam.write(line) else: - f_nam.write("DATA {0:5d} ".format(u) + f + "\n") + f_nam.write(f"DATA {u:5d} {f}\n") # write the output files for u, f, b in zip( @@ -518,11 +510,9 @@ def write_name_file(self): if u == 0: continue if b: - f_nam.write( - "DATA(BINARY) {0:5d} ".format(u) + f + " REPLACE\n" - ) + f_nam.write(f"DATA(BINARY) {u:5d} {f} REPLACE\n") else: - f_nam.write("DATA {0:5d} ".format(u) + f + "\n") + f_nam.write(f"DATA {u:5d} {f}\n") # close the name file f_nam.close() @@ -623,20 +613,11 @@ def load_results(self, **kwargs): if v.lower() == "save budget": savebud = True except Exception as e: - print( - "error reading output filenames " - + "from OC package: {}".format(str(e)) - ) + print(f"error reading output filenames from OC package: {e!s}") - self.hpth = os.path.join( - self.model_ws, "{}.{}".format(self.name, self.hext) - ) - self.dpth = os.path.join( - self.model_ws, "{}.{}".format(self.name, self.dext) - ) - self.cpth = os.path.join( - self.model_ws, "{}.{}".format(self.name, self.cext) - ) + self.hpth = os.path.join(self.model_ws, f"{self.name}.{self.hext}") + self.dpth = os.path.join(self.model_ws, f"{self.name}.{self.dext}") + self.cpth = os.path.join(self.model_ws, f"{self.name}.{self.cext}") hdObj = None ddObj = None @@ -661,7 +642,7 @@ def load_results(self, **kwargs): text="subsidence", ) except Exception as e: - print("error loading subsidence.hds:{0}".format(str(e))) + print(f"error loading subsidence.hds:{e!s}") if as_dict: oudic = {} @@ -731,11 +712,11 @@ def load( # similar to modflow command: if file does not exist , try file.nam namefile_path = os.path.join(model_ws, f) if not os.path.isfile(namefile_path) and os.path.isfile( - namefile_path + ".nam" + f"{namefile_path}.nam" ): namefile_path += ".nam" if not os.path.isfile(namefile_path): - raise IOError("cannot find name file: " + str(namefile_path)) + raise OSError(f"cannot find name file: {namefile_path}") # Determine model name from 'f', without any extension or path modelname = os.path.splitext(os.path.basename(f))[0] @@ -743,11 +724,7 @@ def load( # if model_ws is None: # model_ws = os.path.dirname(f) if verbose: - print( - "\nCreating new model with name: {}\n{}\n".format( - modelname, 50 * "-" - ) - ) + print(f"\nCreating new model with name: {modelname}\n{50 * '-'}\n") attribs = mfreadnam.attribs_from_namfile_header( os.path.join(model_ws, f) @@ -759,7 +736,7 @@ def load( exe_name=exe_name, verbose=verbose, model_ws=model_ws, - **attribs + **attribs, ) files_successfully_loaded = [] @@ -825,7 +802,7 @@ def load( ml.free_format_input = True bas.filehandle.seek(start) if verbose: - print("ModflowBas6 free format:{0}\n".format(ml.free_format_input)) + print(f"ModflowBas6 free format:{ml.free_format_input}\n") # load dis dis_key = ext_pkg_d.get("DIS") or ext_pkg_d.get("DISU") @@ -837,7 +814,7 @@ def load( ) files_successfully_loaded.append(disnamdata.filename) if ml.verbose: - print(" {:4s} package load...success".format(dis.name[0])) + print(f" {dis.name[0]:4s} package load...success") assert ml.pop_key_list.pop() == dis_key ext_unit_dict.pop(dis_key).filehandle.close() @@ -894,21 +871,15 @@ def load( files_successfully_loaded.append(item.filename) if ml.verbose: print( - " {:4s} package load...success".format( - item.filetype - ) + f" {item.filetype:4s} package load...success" ) except Exception as e: ml.load_fail = True if ml.verbose: - msg = ( - 3 * " " - + "{:4s} ".format(item.filetype) - + "package load...failed\n" - + 3 * " " - + "{!s}".format(e) + print( + f" {item.filetype:4s} package load...failed" ) - print(msg) + print(f" {e!s}") files_not_loaded.append(item.filename) else: if "check" in package_load_args: @@ -926,40 +897,21 @@ def load( ) files_successfully_loaded.append(item.filename) if ml.verbose: - msg = ( - 3 * " " - + "{:4s} ".format(item.filetype) - + "package load...success" + print( + f" {item.filetype:4s} package load...success" ) - print(msg) else: if ml.verbose: - msg = ( - 3 * " " - + "{:4s} ".format(item.filetype) - + "package load...skipped" - ) - print(msg) + print(f" {item.filetype:4s} package load...skipped") files_not_loaded.append(item.filename) elif "data" not in item.filetype.lower(): files_not_loaded.append(item.filename) if ml.verbose: - msg = ( - 3 * " " - + "{:4s} ".format(item.filetype) - + "package load...skipped" - ) - print(msg) + print(f" {item.filetype:4s} package load...skipped") elif "data" in item.filetype.lower(): if ml.verbose: - msg = ( - 3 * " " - + "{:s} ".format(item.filetype) - + "file load...skipped\n" - + 6 * " " - + "{}".format(os.path.basename(item.filename)) - ) - print(msg) + print(f" {item.filetype} package load...skipped") + print(f" {os.path.basename(item.filename)}") if key not in ml.pop_key_list: # do not add unit number (key) if it already exists if key not in ml.external_units: @@ -970,7 +922,7 @@ def load( ) ml.external_output.append(False) else: - raise KeyError("unhandled case: {}, {}".format(key, item)) + raise KeyError(f"unhandled case: {key}, {item}") # pop binary output keys and any external file units that are now # internal @@ -982,37 +934,29 @@ def load( item.filehandle.close() except KeyError: if ml.verbose: - msg = ( - "\nWARNING:\n External file " - + "unit {} ".format(key) - + "does not exist in ext_unit_dict." + print( + f"\nWARNING:\n External file unit {key} does not " + "exist in ext_unit_dict." ) - print(msg) # write message indicating packages that were successfully loaded if ml.verbose: - msg = ( - 3 * " " - + "The following " - + "{} ".format(len(files_successfully_loaded)) - + "packages were successfully loaded." - ) print("") - print(msg) + print( + f" The following {len(files_successfully_loaded)} packages " + "were successfully loaded." + ) for fname in files_successfully_loaded: - print(" " + os.path.basename(fname)) + print(f" {os.path.basename(fname)}") if len(files_not_loaded) > 0: - msg = ( - 3 * " " - + "The following " - + "{} ".format(len(files_not_loaded)) - + "packages were not loaded." + print( + f" The following {len(files_not_loaded)} packages " + "were not loaded." ) - print(msg) for fname in files_not_loaded: - print(" " + os.path.basename(fname)) + print(f" {os.path.basename(fname)}") if check: - ml.check(f="{}.chk".format(ml.name), verbose=ml.verbose, level=0) + ml.check(f=f"{ml.name}.chk", verbose=ml.verbose, level=0) # return model object return ml diff --git a/dependencies/flopy/modflow/mfag.py b/dependencies/flopy/modflow/mfag.py index a42cdc4..e29f663 100644 --- a/dependencies/flopy/modflow/mfag.py +++ b/dependencies/flopy/modflow/mfag.py @@ -14,7 +14,6 @@ from ..pakbase import Package from ..utils.recarray_utils import create_empty_recarray from ..utils.optionblock import OptionBlock -from collections import OrderedDict class ModflowAg(Package): @@ -58,7 +57,7 @@ class ModflowAg(Package): """ - _options = OrderedDict( + _options = dict( [ ("noprint", OptionBlock.simple_flag), ( @@ -67,7 +66,7 @@ class ModflowAg(Package): OptionBlock.dtype: np.bool_, OptionBlock.nested: True, OptionBlock.n_nested: 2, - OptionBlock.vars: OrderedDict( + OptionBlock.vars: dict( [ ("numirrdiversions", OptionBlock.simple_int), ("maxcellsdiversion", OptionBlock.simple_int), @@ -81,7 +80,7 @@ class ModflowAg(Package): OptionBlock.dtype: np.bool_, OptionBlock.nested: True, OptionBlock.n_nested: 2, - OptionBlock.vars: OrderedDict( + OptionBlock.vars: dict( [ ("numirrwells", OptionBlock.simple_int), ("maxcellswell", OptionBlock.simple_int), @@ -95,7 +94,7 @@ class ModflowAg(Package): OptionBlock.dtype: np.bool_, OptionBlock.nested: True, OptionBlock.n_nested: 2, - OptionBlock.vars: OrderedDict( + OptionBlock.vars: dict( [ ("numsupwells", OptionBlock.simple_int), ("maxdiversions", OptionBlock.simple_int), @@ -109,7 +108,7 @@ class ModflowAg(Package): OptionBlock.dtype: np.bool_, OptionBlock.nested: True, OptionBlock.n_nested: 1, - OptionBlock.vars: OrderedDict( + OptionBlock.vars: dict( [("nummaxwell", OptionBlock.simple_int)] ), }, @@ -128,7 +127,7 @@ class ModflowAg(Package): OptionBlock.dtype: np.bool_, OptionBlock.nested: True, OptionBlock.n_nested: 1, - OptionBlock.vars: OrderedDict( + OptionBlock.vars: dict( [("unit_diversionlist", OptionBlock.simple_int)] ), }, @@ -139,7 +138,7 @@ class ModflowAg(Package): OptionBlock.dtype: np.bool_, OptionBlock.nested: True, OptionBlock.n_nested: 1, - OptionBlock.vars: OrderedDict( + OptionBlock.vars: dict( [("unit_welllist", OptionBlock.simple_int)] ), }, @@ -150,7 +149,7 @@ class ModflowAg(Package): OptionBlock.dtype: np.bool_, OptionBlock.nested: True, OptionBlock.n_nested: 1, - OptionBlock.vars: OrderedDict( + OptionBlock.vars: dict( [("unit_wellirrlist", OptionBlock.simple_int)] ), }, @@ -161,7 +160,7 @@ class ModflowAg(Package): OptionBlock.dtype: np.bool_, OptionBlock.nested: True, OptionBlock.n_nested: 1, - OptionBlock.vars: OrderedDict( + OptionBlock.vars: dict( [("unit_diversionirrlist", OptionBlock.simple_int)] ), }, @@ -172,7 +171,7 @@ class ModflowAg(Package): OptionBlock.dtype: np.bool_, OptionBlock.nested: True, OptionBlock.n_nested: 1, - OptionBlock.vars: OrderedDict( + OptionBlock.vars: dict( [("unitcbc", OptionBlock.simple_int)] ), }, @@ -197,7 +196,7 @@ def __init__( if "nwt" not in model.version: raise AssertionError( - "Model version must be mfnwt " "to use the AG package" + "Model version must be mfnwt to use the AG package" ) # setup the package parent class @@ -226,9 +225,7 @@ def __init__( ) # set up class - self.heading = "# {} package for {}, generated " "by flopy\n".format( - self.name[0], model.version_types[model.version] - ) + self._generate_heading() self.url = "ag.htm" # options @@ -336,7 +333,7 @@ def write_file(self, check=False): ws = self.parent.model_ws name = self.file_name[0] with open(os.path.join(ws, name), "w") as foo: - foo.write(self.heading) + foo.write(f"{self.heading}\n") # update options self.options.update_from_package(self) @@ -350,9 +347,7 @@ def write_file(self, check=False): for record in self.time_series: if record["keyword"] in ("welletall", "wellall"): foo.write( - "{} {:d}\n".format( - record["keyword"], record["unit"] - ).upper() + f"{record['keyword']} {record['unit']}\n".upper() ) else: foo.write(fmt.format(*record).upper()) @@ -364,7 +359,7 @@ def write_file(self, check=False): foo.write("# segment list for irriagation diversions\n") foo.write("SEGMENT LIST\n") for iseg in self.segment_list: - foo.write("{:d}\n".format(iseg)) + foo.write(f"{iseg}\n") foo.write("END \n") @@ -406,7 +401,7 @@ def write_file(self, check=False): foo.write("# ag stress period data\n") for per in range(self._nper): - foo.write("STRESS PERIOD {}\n".format(per + 1)) + foo.write(f"STRESS PERIOD {per + 1}\n") # check for item 18 and write items 18 - 21 if self.irrdiversion is not None: @@ -428,7 +423,7 @@ def write_file(self, check=False): recarray = self.irrdiversion[per] # write item 19 - foo.write("{:d} \n".format(len(recarray))) + foo.write(f"{len(recarray)} \n") fmt21 = "{:d} {:d} {:f} {:f}\n" for rec in recarray: @@ -452,10 +447,10 @@ def write_file(self, check=False): for i in range(num): foo.write( fmt21.format( - rec["i{}".format(i)] + 1, - rec["j{}".format(i)] + 1, - rec["eff_fact{}".format(i)], - rec["field_fact{}".format(i)], + rec[f"i{i}"] + 1, + rec[f"j{i}"] + 1, + rec[f"eff_fact{i}"], + rec[f"field_fact{i}"], ) ) @@ -481,7 +476,7 @@ def write_file(self, check=False): recarray = self.irrwell[per] # write item 23 - foo.write("{:d} \n".format(len(recarray))) + foo.write(f"{len(recarray)} \n") fmt25 = "{:d} {:d} {:f} {:f}\n" for rec in recarray: @@ -505,10 +500,10 @@ def write_file(self, check=False): for i in range(num): foo.write( fmt25.format( - rec["i{}".format(i)] + 1, - rec["j{}".format(i)] + 1, - rec["eff_fact{}".format(i)], - rec["field_fact{}".format(i)], + rec[f"i{i}"] + 1, + rec[f"j{i}"] + 1, + rec[f"eff_fact{i}"], + rec[f"field_fact{i}"], ) ) else: @@ -528,7 +523,7 @@ def write_file(self, check=False): recarray = self.supwell[per] # write item 27 - foo.write("{:d} \n".format(len(recarray))) + foo.write(f"{len(recarray)} \n") for rec in recarray: num = rec["numcell"] @@ -540,7 +535,7 @@ def write_file(self, check=False): ) for i in range(num): - if rec["fracsupmax{}".format(i)] != -1e10: + if rec[f"fracsupmax{i}"] != -1e10: foo.write( "{:d} {:f} {:f}\n".format( rec["segid{}".format(i)], @@ -646,10 +641,10 @@ def get_default_dtype(maxells=0, block="well"): for i in range(maxells): dtype += [ - ("i{}".format(i), int), - ("j{}".format(i), int), - ("eff_fact{}".format(i), float), - ("field_fact{}".format(i), float), + (f"i{i}", int), + (f"j{i}", int), + (f"eff_fact{i}", float), + (f"field_fact{i}", float), ] elif block == "irrwell": @@ -662,10 +657,10 @@ def get_default_dtype(maxells=0, block="well"): for i in range(maxells): dtype += [ - ("i{}".format(i), int), - ("j{}".format(i), int), - ("eff_fact{}".format(i), float), - ("field_fact{}".format(i), float), + (f"i{i}", int), + (f"j{i}", int), + (f"eff_fact{i}", float), + (f"field_fact{i}", float), ] elif block == "supwell": @@ -673,15 +668,13 @@ def get_default_dtype(maxells=0, block="well"): for i in range(maxells): dtype += [ - ("segid{}".format(i), int), - ("fracsup{}".format(i), float), - ("fracsupmax{}".format(i), float), + (f"segid{i}", int), + (f"fracsup{i}", float), + (f"fracsupmax{i}", float), ] else: - raise NotImplementedError( - "block type {}, not supported".format(block) - ) + raise NotImplementedError(f"block type {block}, not supported") return np.dtype(dtype) @@ -887,9 +880,7 @@ def load(cls, f, model, nper=0, ext_unit_dict=None): break else: - raise ValueError( - "Something went wrong at: {}".format(line) - ) + raise ValueError(f"Something went wrong at: {line}") return cls( model, diff --git a/dependencies/flopy/modflow/mfbas.py b/dependencies/flopy/modflow/mfbas.py index a5fb35a..1d81b29 100644 --- a/dependencies/flopy/modflow/mfbas.py +++ b/dependencies/flopy/modflow/mfbas.py @@ -9,7 +9,6 @@ """ import re -import sys import numpy as np from ..pakbase import Package from ..utils import Util3d @@ -155,11 +154,7 @@ def __init__( name="strt", locat=self.unit_number[0], ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.options = "" self.ixsec = ixsec self.ichflg = ichflg @@ -252,15 +247,14 @@ def write_file(self, check=True): # allows turning off package checks when writing files at model level if check: self.check( - f="{}.chk".format(self.name[0]), + f=f"{self.name[0]}.chk", verbose=self.parent.verbose, level=1, ) # Open file for writing f_bas = open(self.fn_path, "w") # First line: heading - # f_bas.write('%s\n' % self.heading) - f_bas.write("{0:s}\n".format(self.heading)) + f_bas.write(f"{self.heading}\n") # Second line: format specifier opts = [] if self.ixsec: @@ -270,7 +264,7 @@ def write_file(self, check=True): if self.ifrefm: opts.append("FREE") if self.stoper is not None: - opts.append("STOPERROR {0}".format(self.stoper)) + opts.append(f"STOPERROR {self.stoper}") self.options = " ".join(opts) f_bas.write(self.options + "\n") # IBOUND array @@ -279,7 +273,7 @@ def write_file(self, check=True): str_hnoflo = str(self.hnoflo).rjust(10) if not self.ifrefm and len(str_hnoflo) > 10: # write fixed-width no more than 10 characters - str_hnoflo = "{0:10.4G}".format(self.hnoflo) + str_hnoflo = f"{self.hnoflo:10.4G}" assert len(str_hnoflo) <= 10, str_hnoflo f_bas.write(str_hnoflo + "\n") # Starting heads array @@ -329,7 +323,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True, **kwargs): """ if model.verbose: - sys.stdout.write("loading bas6 package file...\n") + print("loading bas6 package file...") # parse keywords if "nlay" in kwargs: @@ -413,7 +407,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True, **kwargs): ) if check: bas.check( - f="{}.chk".format(bas.name[0]), + f=f"{bas.name[0]}.chk", verbose=bas.parent.verbose, level=0, ) diff --git a/dependencies/flopy/modflow/mfbcf.py b/dependencies/flopy/modflow/mfbcf.py index 5dbf48b..137ca76 100644 --- a/dependencies/flopy/modflow/mfbcf.py +++ b/dependencies/flopy/modflow/mfbcf.py @@ -1,5 +1,3 @@ -import sys - import numpy as np from ..pakbase import Package @@ -282,22 +280,14 @@ def write_file(self, f=None): for k in range(nlay): if ifrefm: if self.intercellt[k] > 0: - f_bcf.write( - "{0:1d}{1:1d} ".format( - self.intercellt[k], self.laycon[k] - ) - ) + f_bcf.write(f"{self.intercellt[k]:1d}{self.laycon[k]:1d} ") else: - f_bcf.write("0{0:1d} ".format(self.laycon[k])) + f_bcf.write(f"0{self.laycon[k]:1d} ") else: if self.intercellt[k] > 0: - f_bcf.write( - "{0:1d}{1:1d}".format( - self.intercellt[k], self.laycon[k] - ) - ) + f_bcf.write(f"{self.intercellt[k]:1d}{self.laycon[k]:1d}") else: - f_bcf.write("0{0:1d}".format(self.laycon[k])) + f_bcf.write(f"0{self.laycon[k]:1d}") f_bcf.write("\n") f_bcf.write(self.trpy.get_file_entry()) transient = not dis.steady.all() @@ -357,7 +347,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading bcf package file...\n") + print("loading bcf package file...") openfile = not hasattr(f, "read") if openfile: @@ -463,7 +453,7 @@ def load(cls, f, model, ext_unit_dict=None): # sf1 if transient: if model.verbose: - print(" loading sf1 layer {0:3d}...".format(k + 1)) + print(f" loading sf1 layer {k + 1:3d}...") t = Util2d.load( f, model, (nrow, ncol), np.float32, "sf1", ext_unit_dict ) @@ -472,14 +462,14 @@ def load(cls, f, model, ext_unit_dict=None): # tran or hy if (laycon[k] == 0) or (laycon[k] == 2): if model.verbose: - print(" loading tran layer {0:3d}...".format(k + 1)) + print(f" loading tran layer {k + 1:3d}...") t = Util2d.load( f, model, (nrow, ncol), np.float32, "tran", ext_unit_dict ) tran[k] = t else: if model.verbose: - print(" loading hy layer {0:3d}...".format(k + 1)) + print(f" loading hy layer {k + 1:3d}...") t = Util2d.load( f, model, (nrow, ncol), np.float32, "hy", ext_unit_dict ) @@ -488,7 +478,7 @@ def load(cls, f, model, ext_unit_dict=None): # vcont if k < (nlay - 1): if model.verbose: - print(" loading vcont layer {0:3d}...".format(k + 1)) + print(f" loading vcont layer {k + 1:3d}...") t = Util2d.load( f, model, (nrow, ncol), np.float32, "vcont", ext_unit_dict ) @@ -497,7 +487,7 @@ def load(cls, f, model, ext_unit_dict=None): # sf2 if transient and ((laycon[k] == 2) or (laycon[k] == 3)): if model.verbose: - print(" loading sf2 layer {0:3d}...".format(k + 1)) + print(f" loading sf2 layer {k + 1:3d}...") t = Util2d.load( f, model, (nrow, ncol), np.float32, "sf2", ext_unit_dict ) @@ -506,7 +496,7 @@ def load(cls, f, model, ext_unit_dict=None): # wetdry if (iwdflg != 0) and ((laycon[k] == 1) or (laycon[k] == 3)): if model.verbose: - print(" loading sf2 layer {0:3d}...".format(k + 1)) + print(f" loading sf2 layer {k + 1:3d}...") t = Util2d.load( f, model, (nrow, ncol), np.float32, "wetdry", ext_unit_dict ) diff --git a/dependencies/flopy/modflow/mfbct.py b/dependencies/flopy/modflow/mfbct.py index 15f1424..bde5498 100644 --- a/dependencies/flopy/modflow/mfbct.py +++ b/dependencies/flopy/modflow/mfbct.py @@ -139,7 +139,7 @@ def write_file(self): # # arad if self.idisp != 0: - f_bct.write("open/close arad.dat 1.0 (free) -1" + "\n") + f_bct.write("open/close arad.dat 1.0 (free) -1\n") # # dlh if self.idisp == 1: diff --git a/dependencies/flopy/modflow/mfchd.py b/dependencies/flopy/modflow/mfchd.py index ae9b1b0..d8cb1b7 100644 --- a/dependencies/flopy/modflow/mfchd.py +++ b/dependencies/flopy/modflow/mfchd.py @@ -8,7 +8,6 @@ """ -import sys import numpy as np from ..pakbase import Package from ..utils import MfList @@ -110,7 +109,7 @@ def __init__( extension="chd", unitnumber=None, filenames=None, - **kwargs + **kwargs, ): # set default unit number if one is not specified @@ -143,11 +142,7 @@ def __init__( ) self.url = "chd.htm" - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() if dtype is not None: self.dtype = dtype @@ -185,8 +180,8 @@ def write_file(self): """ f_chd = open(self.fn_path, "w") - f_chd.write("{0:s}\n".format(self.heading)) - f_chd.write(" {0:9d}".format(self.stress_period_data.mxact)) + f_chd.write(f"{self.heading}\n") + f_chd.write(f" {self.stress_period_data.mxact:9d}") for option in self.options: f_chd.write(" {}".format(option)) f_chd.write("\n") @@ -197,7 +192,7 @@ def add_record(self, kper, index, values): try: self.stress_period_data.add_record(kper, index, values) except Exception as e: - raise Exception("mfchd error adding record to list: " + str(e)) + raise Exception(f"mfchd error adding record to list: {e!s}") @staticmethod def get_empty(ncells=0, aux_names=None, structured=True): @@ -270,7 +265,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None, check=True): """ if model.verbose: - sys.stdout.write("loading chd package file...\n") + print("loading chd package file...") return Package.load( f, diff --git a/dependencies/flopy/modflow/mfde4.py b/dependencies/flopy/modflow/mfde4.py index c44b76b..97a9c7e 100644 --- a/dependencies/flopy/modflow/mfde4.py +++ b/dependencies/flopy/modflow/mfde4.py @@ -7,7 +7,6 @@ `_. """ -import sys from ..pakbase import Package @@ -169,11 +168,7 @@ def __init__( ) raise Exception(err) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "de4.htm" self.itmx = itmx @@ -199,31 +194,31 @@ def write_file(self): """ # Open file for writing f = open(self.fn_path, "w") - f.write("{}\n".format(self.heading)) + f.write(f"{self.heading}\n") ifrfm = self.parent.get_ifrefm() if ifrfm: - f.write("{} ".format(self.itmx)) - f.write("{} ".format(self.mxup)) - f.write("{} ".format(self.mxlow)) - f.write("{} ".format(self.mxbw)) + f.write(f"{self.itmx} ") + f.write(f"{self.mxup} ") + f.write(f"{self.mxlow} ") + f.write(f"{self.mxbw} ") f.write("\n") - f.write("{} ".format(self.ifreq)) - f.write("{} ".format(self.mutd4)) - f.write("{} ".format(self.accl)) - f.write("{} ".format(self.hclose)) - f.write("{} ".format(self.iprd4)) + f.write(f"{self.ifreq} ") + f.write(f"{self.mutd4} ") + f.write(f"{self.accl} ") + f.write(f"{self.hclose} ") + f.write(f"{self.iprd4} ") f.write("\n") else: - f.write("{:10d}".format(self.itmx)) - f.write("{:10d}".format(self.mxup)) - f.write("{:10d}".format(self.mxlow)) - f.write("{:10d}".format(self.mxbw)) + f.write(f"{self.itmx:10d}") + f.write(f"{self.mxup:10d}") + f.write(f"{self.mxlow:10d}") + f.write(f"{self.mxbw:10d}") f.write("\n") - f.write("{:10d}".format(self.ifreq)) - f.write("{:10d}".format(self.mutd4)) - f.write("{:9.4e} ".format(self.accl)) - f.write("{:9.4e} ".format(self.hclose)) - f.write("{:10d}".format(self.iprd4)) + f.write(f"{self.ifreq:10d}") + f.write(f"{self.mutd4:10d}") + f.write(f"{self.accl:9.4e} ") + f.write(f"{self.hclose:9.4e} ") + f.write(f"{self.iprd4:10d}") f.write("\n") f.close() @@ -260,7 +255,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading de4 package file...\n") + print("loading de4 package file...") openfile = not hasattr(f, "read") if openfile: diff --git a/dependencies/flopy/modflow/mfdis.py b/dependencies/flopy/modflow/mfdis.py index 4a47793..a4c4df0 100644 --- a/dependencies/flopy/modflow/mfdis.py +++ b/dependencies/flopy/modflow/mfdis.py @@ -7,8 +7,6 @@ `_. """ - -import sys import warnings import numpy as np @@ -21,8 +19,6 @@ ITMUNI = {"u": 0, "s": 1, "m": 2, "h": 3, "d": 4, "y": 5} LENUNI = {"u": 0, "f": 1, "m": 2, "c": 3} -warnings.simplefilter("always", PendingDeprecationWarning) - class ModflowDis(Package): """ @@ -190,11 +186,7 @@ def __init__( botm = np.linspace(top, botm, nlay) # Set values of all parameters - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.laycbd = Util2d( model, (self.nlay,), np.int32, laycbd, name="laycbd" ) @@ -287,39 +279,8 @@ def __init__( ) self.start_datetime = start_datetime - # calculate layer thicknesses - self.__calculate_thickness() self._totim = None - @property - def sr(self): - from ..utils.reference import SpatialReference - - warnings.warn( - "SpatialReference has been deprecated. Use Grid instead.", - DeprecationWarning, - ) - if not hasattr(self, "_sr"): - mg = self.parent.modelgrid - self._sr = SpatialReference( - self.delr, - self.delc, - self.lenuni, - xll=mg.xoffset, - yll=mg.yoffset, - rotation=mg.angrot or 0.0, - proj4_str=mg.proj4, - ) - return self._sr - - @sr.setter - def sr(self, sr): - warnings.warn( - "SpatialReference has been deprecated. Use Grid instead.", - DeprecationWarning, - ) - self._sr = sr - def checklayerthickness(self): """ Check layer thickness. @@ -459,12 +420,9 @@ def get_totim_from_kper_toffset( if kper < 0: kper = 0.0 if kper >= self.nper: - msg = ( - "kper ({}) ".format(kper) - + "must be less than " - + "to nper ({}).".format(self.nper) + raise ValueError( + f"kper ({kper}) must be less than to nper ({self.nper})." ) - raise ValueError(msg) totim = self.get_totim(use_cached_totim) nstp = self.nstp.array @@ -635,36 +593,6 @@ def getbotm(self, k=None): else: return self.botm.array[k, :, :] - def __calculate_thickness(self): - # thk = [] - # thk.append(self.top - self.botm[0]) - # for k in range(1, self.nlay + sum(self.laycbd)): - # thk.append(self.botm[k - 1] - self.botm[k]) - self.__thickness = Util3d( - self.parent, - (self.nlay + sum(self.laycbd), self.nrow, self.ncol), - np.float32, - self.parent.modelgrid.thick, - name="thickness", - ) - - @property - def thickness(self): - """ - Return cell thicknesses. - - Returns - ------- - thickness : array of floats (nlay, nrow, ncol) - - """ - warnings.warn( - "ModflowDis.thickness will be deprecated and removed " - "in version 3.3.5. Use grid.thick().", - PendingDeprecationWarning, - ) - return self.parent.modelgrid.thick - def write_file(self, check=True): """ Write the package file. @@ -683,14 +611,14 @@ def write_file(self, check=True): check ): # allows turning off package checks when writing files at model level self.check( - f="{}.chk".format(self.name[0]), + f=f"{self.name[0]}.chk", verbose=self.parent.verbose, level=1, ) # Open file for writing f_dis = open(self.fn_path, "w") # Item 0: heading - f_dis.write("{0:s}\n".format(self.heading)) + f_dis.write(f"{self.heading}\n") # Item 1: NLAY, NROW, NCOL, NPER, ITMUNI, LENUNI f_dis.write( "{0:10d}{1:10d}{2:10d}{3:10d}{4:10d}{5:10d}\n".format( @@ -704,7 +632,7 @@ def write_file(self, check=True): ) # Item 2: LAYCBD for l in range(0, self.nlay): - f_dis.write("{0:3d}".format(self.laycbd[l])) + f_dis.write(f"{self.laycbd[l]:3d}") f_dis.write("\n") # Item 3: DELR f_dis.write(self.delr.get_file_entry()) @@ -718,9 +646,7 @@ def write_file(self, check=True): # Item 6: NPER, NSTP, TSMULT, Ss/tr for t in range(self.nper): f_dis.write( - "{0:14f}{1:14d}{2:10f} ".format( - self.perlen[t], self.nstp[t], self.tsmult[t] - ) + f"{self.perlen[t]:14f}{self.nstp[t]:14d}{self.tsmult[t]:10f} " ) if self.steady[t]: f_dis.write(" {0:3s}\n".format("SS")) @@ -835,7 +761,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): """ if model.verbose: - sys.stdout.write("loading dis package file...\n") + print("loading dis package file...") openfile = not hasattr(f, "read") if openfile: @@ -862,50 +788,35 @@ def load(cls, f, model, ext_unit_dict=None, check=True): xul = float(item.split(":")[1]) except: if model.verbose: - print( - " could not parse xul " - + "in {}".format(filename) - ) + print(f" could not parse xul in {filename}") dep = True elif "yul" in item.lower(): try: yul = float(item.split(":")[1]) except: if model.verbose: - print( - " could not parse yul " - + "in {}".format(filename) - ) + print(f" could not parse yul in {filename}") dep = True elif "rotation" in item.lower(): try: rotation = float(item.split(":")[1]) except: if model.verbose: - print( - " could not parse rotation " - + "in {}".format(filename) - ) + print(f" could not parse rotation in {filename}") dep = True elif "proj4_str" in item.lower(): try: proj4_str = ":".join(item.split(":")[1:]).strip() except: if model.verbose: - print( - " could not parse proj4_str " - + "in {}".format(filename) - ) + print(f" could not parse proj4_str in {filename}") dep = True elif "start" in item.lower(): try: start_datetime = item.split(":")[1].strip() except: if model.verbose: - print( - " could not parse start " - + "in {}".format(filename) - ) + print(f" could not parse start in {filename}") dep = True if dep: warnings.warn( @@ -925,10 +836,8 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # dataset 2 -- laycbd if model.verbose: print( - " Loading dis package with:\n " - + "{0} layers, {1} rows, {2} columns, and {3} stress periods".format( - nlay, nrow, ncol, nper - ) + " Loading dis package with:\n {} layers, {} rows, {} " + "columns, and {} stress periods".format(nlay, nrow, ncol, nper) ) print(" loading laycbd...") laycbd = np.zeros(nlay, dtype=int) @@ -966,10 +875,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): ncbd = laycbd.sum() if model.verbose: print(" loading botm...") - print( - " for {} layers and ".format(nlay) - + "{} confining beds".format(ncbd) - ) + print(f" for {nlay} layers and {ncbd} confining beds") if nlay > 1: botm = Util3d.load( f, @@ -986,7 +892,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # dataset 7 -- stress period info if model.verbose: print(" loading stress period data...") - print(" for {} stress periods".format(nper)) + print(f" for {nper} stress periods") perlen = [] nstp = [] tsmult = [] @@ -1045,7 +951,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): ) if check: dis.check( - f="{}.chk".format(dis.name[0]), + f=f"{dis.name[0]}.chk", verbose=dis.parent.verbose, level=0, ) diff --git a/dependencies/flopy/modflow/mfdisu.py b/dependencies/flopy/modflow/mfdisu.py index 6e80fd0..e967614 100644 --- a/dependencies/flopy/modflow/mfdisu.py +++ b/dependencies/flopy/modflow/mfdisu.py @@ -3,9 +3,6 @@ the ModflowDisU class as `flopy.modflow.ModflowDisU`. """ - -import sys -import warnings import numpy as np from ..pakbase import Package from ..utils import Util2d, Util3d, read1d @@ -15,8 +12,6 @@ ITMUNI = {"u": 0, "s": 1, "m": 2, "h": 3, "d": 4, "y": 5} LENUNI = {"u": 0, "f": 1, "m": 2, "c": 3} -warnings.simplefilter("always", PendingDeprecationWarning) - class ModflowDisU(Package): """ @@ -265,11 +260,7 @@ def __init__( # Set values of all parameters self.url = "dis.htm" - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.nodes = nodes self.nlay = nlay @@ -475,9 +466,6 @@ def __init__( self.start_datetime = start_datetime - # calculate layer thicknesses - self.__calculate_thickness() - # get neighboring nodes self._get_neighboring_nodes() @@ -485,40 +473,6 @@ def __init__( self.parent.add_package(self) return - def __calculate_thickness(self): - # set ncol and nrow for array readers - nrow = None - ncol = self.nodelay.array - nlay = self.nlay - thk = [] - for k in range(self.nlay): - thk.append(self.top[k] - self.bot[k]) - self.__thickness = Util3d( - self.parent, - (nlay, nrow, ncol), - np.float32, - thk, - name="thickness", - ) - return - - @property - def thickness(self): - """ - Return cell thicknesses. - - Returns - ------- - thickness : array of floats (nodes,) - - """ - warnings.warn( - "ModflowDisU.thickness will be deprecated and removed " - "in version 3.3.5. Use grid.thick().", - PendingDeprecationWarning, - ) - return self.__thickness.array - def checklayerthickness(self): """ Check layer thickness. @@ -552,7 +506,7 @@ def zcentroids(self): """ z = np.empty((self.nodes)) - z[:] = (self.top[:] - self.bot[:]) / 2.0 + z[:] = (self.top.array - self.bot.array) / 2.0 return z @property @@ -595,16 +549,13 @@ def load(cls, f, model, ext_unit_dict=None, check=True): """ if model.verbose: - sys.stdout.write("loading disu package file...\n") + print("loading disu package file...") if model.version != "mfusg": - msg = ( - "Warning: model version was reset from " - + "'{}' to 'mfusg' in order to load a DISU file".format( - model.version - ) + print( + "Warning: model version was reset from '{}' to 'mfusg' " + "in order to load a DISU file".format(model.version) ) - print(msg) model.version = "mfusg" openfile = not hasattr(f, "read") @@ -644,19 +595,19 @@ def load(cls, f, model, ext_unit_dict=None, check=True): else: idsymrd = 0 if model.verbose: - print(" NODES {}".format(nodes)) - print(" NLAY {}".format(nlay)) - print(" NJAG {}".format(njag)) - print(" IVSD {}".format(ivsd)) - print(" NPER {}".format(nper)) - print(" ITMUNI {}".format(itmuni)) - print(" LENUNI {}".format(lenuni)) - print(" IDSYMRD {}".format(idsymrd)) + print(f" NODES {nodes}") + print(f" NLAY {nlay}") + print(f" NJAG {njag}") + print(f" IVSD {ivsd}") + print(f" NPER {nper}") + print(f" ITMUNI {itmuni}") + print(f" LENUNI {lenuni}") + print(f" IDSYMRD {idsymrd}") # Calculate njags njags = int((njag - nodes) / 2) if model.verbose: - print(" NJAGS calculated as {}".format(njags)) + print(f" NJAGS calculated as {njags}") # dataset 2 -- laycbd if model.verbose: @@ -664,7 +615,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): laycbd = np.empty((nlay,), np.int32) laycbd = read1d(f, laycbd) if model.verbose: - print(" LAYCBD {}".format(laycbd)) + print(f" LAYCBD {laycbd}") # dataset 3 -- nodelay if model.verbose: @@ -673,7 +624,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): f, model, (nlay,), np.int32, "nodelay", ext_unit_dict ) if model.verbose: - print(" NODELAY {}".format(nodelay)) + print(f" NODELAY {nodelay}") # dataset 4 -- top if model.verbose: @@ -686,7 +637,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): top[k] = tpk if model.verbose: for k, tpk in enumerate(top): - print(" TOP layer {}: {}".format(k, tpk.array)) + print(f" TOP layer {k}: {tpk.array}") # dataset 5 -- bot if model.verbose: @@ -699,7 +650,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): bot[k] = btk if model.verbose: for k, btk in enumerate(bot): - print(" BOT layer {}: {}".format(k, btk.array)) + print(f" BOT layer {k}: {btk.array}") # dataset 6 -- area if model.verbose: @@ -717,21 +668,21 @@ def load(cls, f, model, ext_unit_dict=None, check=True): area[k] = ak if model.verbose: for k, ak in enumerate(area): - print(" AREA layer {}: {}".format(k, ak)) + print(f" AREA layer {k}: {ak}") # dataset 7 -- iac if model.verbose: print(" loading IAC...") iac = Util2d.load(f, model, (nodes,), np.int32, "iac", ext_unit_dict) if model.verbose: - print(" IAC {}".format(iac)) + print(f" IAC {iac}") # dataset 8 -- ja if model.verbose: print(" loading JA...") ja = Util2d.load(f, model, (njag,), np.int32, "ja", ext_unit_dict) if model.verbose: - print(" JA {}".format(ja)) + print(f" JA {ja}") # dataset 9 -- ivc ivc = None @@ -742,7 +693,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): f, model, (njag,), np.int32, "ivc", ext_unit_dict ) if model.verbose: - print(" IVC {}".format(ivc)) + print(f" IVC {ivc}") # dataset 10a -- cl1 cl1 = None @@ -753,7 +704,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): f, model, (njags,), np.float32, "cl1", ext_unit_dict ) if model.verbose: - print(" CL1 {}".format(cl1)) + print(f" CL1 {cl1}") # dataset 10b -- cl2 cl2 = None @@ -764,7 +715,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): f, model, (njags,), np.float32, "cl2", ext_unit_dict ) if model.verbose: - print(" CL2 {}".format(cl2)) + print(f" CL2 {cl2}") # dataset 11 -- cl12 cl12 = None @@ -775,7 +726,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): f, model, (njag,), np.float32, "cl12", ext_unit_dict ) if model.verbose: - print(" CL12 {}".format(cl12)) + print(f" CL12 {cl12}") # dataset 12 -- fahl fahl = None @@ -787,7 +738,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): print(" loading FAHL...") fahl = Util2d.load(f, model, (n,), np.float32, "fahl", ext_unit_dict) if model.verbose: - print(" FAHL {}".format(fahl)) + print(f" FAHL {fahl}") # dataset 7 -- stress period info if model.verbose: @@ -811,10 +762,10 @@ def load(cls, f, model, ext_unit_dict=None, check=True): tsmult.append(a3) steady.append(a4) if model.verbose: - print(" PERLEN {}".format(perlen)) - print(" NSTP {}".format(nstp)) - print(" TSMULT {}".format(tsmult)) - print(" STEADY {}".format(steady)) + print(f" PERLEN {perlen}") + print(f" NSTP {nstp}") + print(f" TSMULT {tsmult}") + print(f" STEADY {steady}") if openfile: f.close() @@ -874,7 +825,7 @@ def write_file(self): f_dis = open(self.fn_path, "w") # Item 0: heading - f_dis.write("{0:s}\n".format(self.heading)) + f_dis.write(f"{self.heading}\n") # Item 1: NODES NLAY NJAG IVSD NPER ITMUNI LENUNI IDSYMRD s = "" @@ -893,7 +844,7 @@ def write_file(self): # Item 2: LAYCBD for k in range(self.nlay): - f_dis.write("{0:3d}".format(self.laycbd[k])) + f_dis.write(f"{self.laycbd[k]:3d}") f_dis.write("\n") # Item 3: NODELAY @@ -936,9 +887,7 @@ def write_file(self): # Item 13: NPER, NSTP, TSMULT, Ss/tr for t in range(self.nper): f_dis.write( - "{0:14f}{1:14d}{2:10f} ".format( - self.perlen[t], self.nstp[t], self.tsmult[t] - ) + f"{self.perlen[t]:14f}{self.nstp[t]:14d}{self.tsmult[t]:10f} " ) if self.steady[t]: f_dis.write(" {0:3s}\n".format("SS")) diff --git a/dependencies/flopy/modflow/mfdrn.py b/dependencies/flopy/modflow/mfdrn.py index 3de2986..ee68943 100644 --- a/dependencies/flopy/modflow/mfdrn.py +++ b/dependencies/flopy/modflow/mfdrn.py @@ -7,7 +7,6 @@ `_. """ -import sys import numpy as np from ..pakbase import Package from ..utils.util_list import MfList @@ -117,7 +116,7 @@ def __init__( unitnumber=None, options=None, filenames=None, - **kwargs + **kwargs, ): # set default unit number of one is not specified @@ -170,11 +169,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "drn.htm" self.ipakcb = ipakcb @@ -254,16 +249,13 @@ def write_file(self, check=True): check ): # allows turning off package checks when writing files at model level self.check( - f="{}.chk".format(self.name[0]), + f=f"{self.name[0]}.chk", verbose=self.parent.verbose, level=1, ) f_drn = open(self.fn_path, "w") - f_drn.write("{0}\n".format(self.heading)) - # f_drn.write('%10i%10i\n' % (self.mxactd, self.idrncb)) - line = "{0:10d}{1:10d}".format( - self.stress_period_data.mxact, self.ipakcb - ) + f_drn.write(f"{self.heading}\n") + line = f"{self.stress_period_data.mxact:10d}{self.ipakcb:10d}" if self.is_drt: line += "{0:10d}{0:10d}".format(0) @@ -278,7 +270,7 @@ def add_record(self, kper, index, values): try: self.stress_period_data.add_record(kper, index, values) except Exception as e: - raise Exception("mfdrn error adding record to list: " + str(e)) + raise Exception(f"mfdrn error adding record to list: {e!s}") @staticmethod def get_empty(ncells=0, aux_names=None, structured=True, is_drt=False): @@ -330,7 +322,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None, check=True): """ if model.verbose: - sys.stdout.write("loading drn package file...\n") + print("loading drn package file...") return Package.load( f, diff --git a/dependencies/flopy/modflow/mfdrt.py b/dependencies/flopy/modflow/mfdrt.py index 294ccb6..7540761 100644 --- a/dependencies/flopy/modflow/mfdrt.py +++ b/dependencies/flopy/modflow/mfdrt.py @@ -7,7 +7,6 @@ `_. """ -import sys import numpy as np from ..pakbase import Package from ..utils.util_list import MfList @@ -115,7 +114,7 @@ def __init__( unitnumber=None, options=None, filenames=None, - **kwargs + **kwargs, ): # set default unit number of one is not specified @@ -168,11 +167,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "drt.htm" self.ipakcb = ipakcb @@ -249,16 +244,13 @@ def write_file(self, check=True): check ): # allows turning off package checks when writing files at model level self.check( - f="{}.chk".format(self.name[0]), + f=f"{self.name[0]}.chk", verbose=self.parent.verbose, level=1, ) f_drn = open(self.fn_path, "w") - f_drn.write("{0}\n".format(self.heading)) - # f_drn.write('%10i%10i\n' % (self.mxactd, self.idrncb)) - line = "{0:10d}{1:10d}{2:10d}{3:10d}".format( - self.stress_period_data.mxact, self.ipakcb, 0, 0 - ) + f_drn.write(f"{self.heading}\n") + line = f"{self.stress_period_data.mxact:10d}{self.ipakcb:10d}{0:10d}{0:10d}" for opt in self.options: line += " " + str(opt) line += "\n" @@ -270,7 +262,7 @@ def add_record(self, kper, index, values): try: self.stress_period_data.add_record(kper, index, values) except Exception as e: - raise Exception("mfdrt error adding record to list: " + str(e)) + raise Exception(f"mfdrt error adding record to list: {e!s}") @staticmethod def get_empty(ncells=0, aux_names=None, structured=True, is_drt=False): @@ -316,7 +308,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None, check=True): """ if model.verbose: - sys.stdout.write("loading drt package file...\n") + print("loading drt package file...") return Package.load( f, diff --git a/dependencies/flopy/modflow/mfevt.py b/dependencies/flopy/modflow/mfevt.py index a86c969..44d3a7c 100644 --- a/dependencies/flopy/modflow/mfevt.py +++ b/dependencies/flopy/modflow/mfevt.py @@ -7,8 +7,6 @@ `_. """ -import sys - import numpy as np from .mfparbc import ModflowParBc as mfparbc from ..utils import Transient2d, Util2d @@ -142,11 +140,7 @@ def __init__( ) nrow, ncol, nlay, nper = self.parent.nrow_ncol_nlay_nper - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "evt.htm" self.nevtop = nevtop self.ipakcb = ipakcb @@ -203,8 +197,8 @@ def write_file(self, f=None): f_evt = f else: f_evt = open(self.fn_path, "w") - f_evt.write("{0:s}\n".format(self.heading)) - f_evt.write("{0:10d}{1:10d}\n".format(self.nevtop, self.ipakcb)) + f_evt.write(f"{self.heading}\n") + f_evt.write(f"{self.nevtop:10d}{self.ipakcb:10d}\n") if self.nevtop == 2 and not self.parent.structured: mxndevt = np.max( [ @@ -212,7 +206,7 @@ def write_file(self, f=None): for kper, u2d in self.ievt.transient_2ds.items() ] ) - f_evt.write("{0:10d}\n".format(mxndevt)) + f_evt.write(f"{mxndevt:10d}\n") for n in range(nper): insurf, surf = self.surf.get_kper_entry(n) @@ -221,13 +215,9 @@ def write_file(self, f=None): inievt, ievt = self.ievt.get_kper_entry(n) if self.nevtop == 2 and not self.parent.structured: inievt = self.ievt[n].array.size - comment = "Evapotranspiration dataset 5 for stress period " + str( - n + 1 - ) + comment = f"Evapotranspiration dataset 5 for stress period {n + 1}" f_evt.write( - "{0:10d}{1:10d}{2:10d}{3:10d} # {4:s}\n".format( - insurf, inevtr, inexdp, inievt, comment - ) + f"{insurf:10d}{inevtr:10d}{inexdp:10d}{inievt:10d} # {comment}\n" ) if insurf >= 0: f_evt.write(surf) @@ -275,7 +265,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading evt package file...\n") + print("loading evt package file...") openfile = not hasattr(f, "read") if openfile: @@ -346,11 +336,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): if insurf >= 0: if model.verbose: - print( - " loading surf stress period {0:3d}...".format( - iper + 1 - ) - ) + print(f" loading surf stress period {iper + 1:3d}...") t = Util2d.load( f, model, u2d_shape, np.float32, "surf", ext_unit_dict ) @@ -361,9 +347,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): if npar == 0: if model.verbose: print( - " loading evtr stress period {0:3d}...".format( - iper + 1 - ) + f" loading evtr stress period {iper + 1:3d}..." ) t = Util2d.load( f, @@ -400,11 +384,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): evtr[iper] = current_evtr if inexdp >= 0: if model.verbose: - print( - " loading exdp stress period {0:3d}...".format( - iper + 1 - ) - ) + print(f" loading exdp stress period {iper + 1:3d}...") t = Util2d.load( f, model, u2d_shape, np.float32, "exdp", ext_unit_dict ) @@ -414,9 +394,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): if inievt >= 0: if model.verbose: print( - " loading ievt stress period {0:3d}...".format( - iper + 1 - ) + f" loading ievt stress period {iper + 1:3d}..." ) t = Util2d.load( f, model, u2d_shape, np.int32, "ievt", ext_unit_dict diff --git a/dependencies/flopy/modflow/mffhb.py b/dependencies/flopy/modflow/mffhb.py index 49d979f..5d7f7c5 100644 --- a/dependencies/flopy/modflow/mffhb.py +++ b/dependencies/flopy/modflow/mffhb.py @@ -7,8 +7,6 @@ `_. """ -import sys - import numpy as np from ..pakbase import Package @@ -198,11 +196,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "flow_and_head_boundary_packag2.htm" self.nbdtim = nbdtim @@ -260,57 +254,53 @@ def __init__( # perform some simple verification if len(self.bdtime) != self.nbdtim: - msg = "bdtime has {} entries ".format( - len(self.bdtime) - ) + "but requires {} entries.".format(self.nbdtim) - raise ValueError(msg) + raise ValueError( + "bdtime has {} entries but requires " + "{} entries.".format(len(self.bdtime), self.nbdtim) + ) if self.nflw > 0: if self.ds5 is None: - msg = ( - "dataset 5 is not specified but " - + "nflw > 0 ({})".format(self.nflw) + raise TypeError( + f"dataset 5 is not specified but nflw > 0 ({self.nflw})" ) - raise TypeError(msg) if self.ds5.shape[0] != self.nflw: - msg = "dataset 5 has {} rows ".format( - self.ds5.shape[0] - ) + "but requires {} rows.".format(self.nflw) - raise ValueError(msg) + raise ValueError( + "dataset 5 has {} rows but requires " + "{} rows.".format(self.ds5.shape[0], self.nflw) + ) nc = self.nbdtim if model.structured: nc += 4 else: nc += 2 if len(self.ds5.dtype.names) != nc: - msg = "dataset 5 has {} ".format( - len(self.ds5.dtype.names) - ) + "columns but requires {} columns.".format(nc) - raise ValueError(msg) + raise ValueError( + "dataset 5 has {} columns but requires " + "{} columns.".format(len(self.ds5.dtype.names), nc) + ) if self.nhed > 0: if self.ds7 is None: - msg = ( - "dataset 7 is not specified but " - + "nhed > 0 ({})".format(self.nhed) + raise TypeError( + f"dataset 7 is not specified but nhed > 0 ({self.nhed})" ) - raise TypeError(msg) if self.ds7.shape[0] != self.nhed: - msg = "dataset 7 has {} rows ".format( - self.ds7.shape[0] - ) + "but requires {} rows.".format(self.nhed) - raise ValueError(msg) + raise ValueError( + "dataset 7 has {} rows but requires " + "{} rows.".format(self.ds7.shape[0], self.nhed) + ) nc = self.nbdtim if model.structured: nc += 4 else: nc += 2 if len(self.ds7.dtype.names) != nc: - msg = "dataset 7 has {} ".format( - len(self.ds7.dtype.names) - ) + "columns but requires {} columns.".format(nc) - raise ValueError(msg) + raise ValueError( + "dataset 7 has {} columns but requires " + "{} columns.".format(len(self.ds7.dtype.names), nc) + ) self.parent.add_package(self) @@ -331,9 +321,9 @@ def get_default_dtype(nbdtim=1, structured=True, head=False): dtype.append(("iaux", int)) for n in range(nbdtim): if head: - name = "sbhed{}".format(n + 1) + name = f"sbhed{n + 1}" else: - name = "flwrat{}".format(n + 1) + name = f"flwrat{n + 1}" dtype.append((name, np.float32)) return np.dtype(dtype) @@ -363,34 +353,34 @@ def write_file(self): # f.write('{0:s}\n'.format(self.heading)) # Data set 1 - f.write("{} ".format(self.nbdtim)) - f.write("{} ".format(self.nflw)) - f.write("{} ".format(self.nhed)) - f.write("{} ".format(self.ifhbss)) - f.write("{} ".format(self.ipakcb)) - f.write("{} ".format(self.nfhbx1)) - f.write("{}\n".format(self.nfhbx2)) + f.write(f"{self.nbdtim} ") + f.write(f"{self.nflw} ") + f.write(f"{self.nhed} ") + f.write(f"{self.ifhbss} ") + f.write(f"{self.ipakcb} ") + f.write(f"{self.nfhbx1} ") + f.write(f"{self.nfhbx2}\n") # Dataset 2 - flow auxiliary names # Dataset 3 - head auxiliary names # Dataset 4a IFHBUN CNSTM IFHBPT - f.write("{} ".format(self.unit_number[0])) - f.write("{} ".format(self.bdtimecnstm)) - f.write("{}\n".format(self.ifhbpt)) + f.write(f"{self.unit_number[0]} ") + f.write(f"{self.bdtimecnstm} ") + f.write(f"{self.ifhbpt}\n") # Dataset 4b for n in range(self.nbdtim): - f.write("{} ".format(self.bdtime[n])) + f.write(f"{self.bdtime[n]} ") f.write("\n") # Dataset 5 and 6 if self.nflw > 0: # Dataset 5a IFHBUN CNSTM IFHBPT - f.write("{} ".format(self.unit_number[0])) - f.write("{} ".format(self.cnstm5)) - f.write("{}\n".format(self.ifhbpt)) + f.write(f"{self.unit_number[0]} ") + f.write(f"{self.cnstm5} ") + f.write(f"{self.ifhbpt}\n") # Dataset 5b for n in range(self.nflw): @@ -398,7 +388,7 @@ def write_file(self): v = self.ds5[n][name] if name in ["k", "i", "j", "node"]: v += 1 - f.write("{} ".format(v)) + f.write(f"{v} ") f.write("\n") # Dataset 6a and 6b - flow auxiliary data @@ -408,9 +398,9 @@ def write_file(self): # Dataset 7 if self.nhed > 0: # Dataset 7a IFHBUN CNSTM IFHBPT - f.write("{} ".format(self.unit_number[0])) - f.write("{} ".format(self.cnstm7)) - f.write("{}\n".format(self.ifhbpt)) + f.write(f"{self.unit_number[0]} ") + f.write(f"{self.cnstm7} ") + f.write(f"{self.ifhbpt}\n") # Dataset 7b IFHBUN CNSTM IFHBPT for n in range(self.nhed): @@ -418,7 +408,7 @@ def write_file(self): v = self.ds7[n][name] if name in ["k", "i", "j", "node"]: v += 1 - f.write("{} ".format(v)) + f.write(f"{v} ") f.write("\n") # Dataset 8a and 8b - head auxiliary data @@ -463,7 +453,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading fhb package file...\n") + print("loading fhb package file...") openfile = not hasattr(f, "read") if openfile: @@ -485,7 +475,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): # dataset 1 if model.verbose: - sys.stdout.write("loading fhb dataset 1\n") + print("loading fhb dataset 1") raw = line.strip().split() nbdtim = int(raw[0]) nflw = int(raw[1]) @@ -501,12 +491,8 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): flow_aux = [] if nfhbx1 > 0: if model.verbose: - sys.stdout.write("loading fhb dataset 2\n") - msg = ( - "dataset 2 will not be preserved " - + "in the created hfb object.\n" - ) - sys.stdout.write(msg) + print("loading fhb dataset 2") + print("dataset 2 will not be preserved in the created hfb object.") for idx in range(nfhbx1): line = f.readline() raw = line.strip().split() @@ -520,12 +506,8 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): head_aux = [] if nfhbx2 > 0: if model.verbose: - sys.stdout.write("loading fhb dataset 3\n") - msg = ( - "dataset 3 will not be preserved " - + "in the created hfb object.\n" - ) - sys.stdout.write(msg) + print("loading fhb dataset 3") + print("dataset 3 will not be preserved in the created hfb object.") for idx in range(nfhbx2): line = f.readline() raw = line.strip().split() @@ -537,21 +519,21 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): # Dataset 4a IFHBUN CNSTM IFHBPT if model.verbose: - sys.stdout.write("loading fhb dataset 4a\n") + print("loading fhb dataset 4a") line = f.readline() raw = line.strip().split() ifhbun = int(raw[0]) if ifhbun != iufhb: - msg = "fhb dataset 4a must be in the fhb file " - msg += "(unit={}) ".format(iufhb) - msg += "fhb data is specified in unit={}".format(ifhbun) - raise ValueError(msg) + raise ValueError( + "fhb dataset 4a must be in the fhb file (unit={}) " + "fhb data is specified in unit={}".format(iufhb, ifhbun) + ) bdtimecnstm = float(raw[1]) ifhbpt = max(ifhbpt, int(raw[2])) # Dataset 4b if model.verbose: - sys.stdout.write("loading fhb dataset 4b\n") + print("loading fhb dataset 4b") line = f.readline() raw = line.strip().split() bdtime = [] @@ -565,21 +547,21 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): ds6 = None if nflw > 0: if model.verbose: - sys.stdout.write("loading fhb dataset 5a\n") + print("loading fhb dataset 5a") # Dataset 5a IFHBUN CNSTM IFHBPT line = f.readline() raw = line.strip().split() ifhbun = int(raw[0]) if ifhbun != iufhb: - msg = "fhb dataset 5a must be in the fhb file " - msg += "(unit={}) ".format(iufhb) - msg += "fhb data is specified in unit={}".format(ifhbun) - raise ValueError(msg) + raise ValueError( + "fhb dataset 5a must be in the fhb file (unit={}) " + "fhb data is specified in unit={}".format(iufhb, ifhbun) + ) cnstm5 = float(raw[1]) ifhbpt = max(ifhbpt, int(raw[2])) if model.verbose: - sys.stdout.write("loading fhb dataset 5b\n") + print("loading fhb dataset 5b") dtype = ModflowFhb.get_default_dtype( nbdtim=nbdtim, head=False, structured=model.structured ) @@ -610,39 +592,30 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): dtype.append((name, np.float32)) for naux in range(nfhbx1): if model.verbose: - sys.stdout.write( - "loading fhb dataset 6a - aux " - + "{}\n".format(naux + 1) - ) - msg = ( + print(f"loading fhb dataset 6a - aux {naux + 1}") + print( "dataset 6a will not be preserved in " - + "the created hfb object.\n" + "the created hfb object." ) - sys.stdout.write(msg) # Dataset 6a IFHBUN CNSTM IFHBPT line = f.readline() raw = line.strip().split() ifhbun = int(raw[0]) if ifhbun != iufhb: - msg = "fhb dataset 6a must be in the fhb file " - msg += "(unit={}) ".format(iufhb) - msg += "fhb data is specified in " + "unit={}".format( - ifhbun + raise ValueError( + "fhb dataset 6a must be in the fhb file (unit={}) " + "fhb data is specified in " + "unit={}".format(iufhb, ifhbun) ) - raise ValueError(msg) cnstm6.append(float(raw[1])) ifhbpt = max(ifhbpt, int(raw[2])) if model.verbose: - sys.stdout.write( - "loading fhb dataset 6b - aux " - + "{}\n".format(naux + 1) - ) - msg = ( + print(f"loading fhb dataset 6b - aux {naux + 1}") + print( "dataset 6b will not be preserved in " - + "the created hfb object.\n" + "the created hfb object." ) - sys.stdout.write(msg) current = np.recarray(nflw, dtype=dtype) for n in range(nflw): line = f.readline() @@ -657,21 +630,21 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): ds8 = None if nhed > 0: if model.verbose: - sys.stdout.write("loading fhb dataset 7a\n") + print("loading fhb dataset 7a") # Dataset 7a IFHBUN CNSTM IFHBPT line = f.readline() raw = line.strip().split() ifhbun = int(raw[0]) if ifhbun != iufhb: - msg = "fhb dataset 7a must be in the fhb file " - msg += "(unit={}) ".format(iufhb) - msg += "fhb data is specified in unit={}".format(ifhbun) - raise ValueError(msg) + raise ValueError( + "fhb dataset 7a must be in the fhb file (unit={}) " + "fhb data is specified in unit={}".format(iufhb, ifhbun) + ) cnstm7 = float(raw[1]) ifhbpt = max(ifhbpt, int(raw[2])) if model.verbose: - sys.stdout.write("loading fhb dataset 7b\n") + print("loading fhb dataset 7b") dtype = ModflowFhb.get_default_dtype( nbdtim=nbdtim, head=True, structured=model.structured ) @@ -702,40 +675,31 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): dtype.append((name, np.float32)) for naux in range(nfhbx1): if model.verbose: - sys.stdout.write( - "loading fhb dataset 8a - aux " - + "{}\n".format(naux + 1) - ) - msg = ( + print(f"loading fhb dataset 8a - aux {naux + 1}") + print( "dataset 8a will not be preserved in " - + "the created hfb object.\n" + "the created hfb object." ) - sys.stdout.write(msg) # Dataset 6a IFHBUN CNSTM IFHBPT line = f.readline() raw = line.strip().split() ifhbun = int(raw[0]) if ifhbun != iufhb: - msg = "fhb dataset 8a must be in the fhb file " - msg += "(unit={}) ".format(iufhb) - msg += "fhb data is specified in " + "unit={}".format( - ifhbun + raise ValueError( + "fhb dataset 8a must be in the fhb file (unit={}) " + "fhb data is specified in " + "unit={}".format(iufhb, ifhbun) ) - raise ValueError(msg) cnstm8.append(float(raw[1])) ifhbpt6 = int(raw[2]) ifhbpt = max(ifhbpt, ifhbpt6) if model.verbose: - sys.stdout.write( - "loading fhb dataset 8b - aux " - + "{}\n".format(naux + 1) - ) - msg = ( + print(f"loading fhb dataset 8b - aux {naux + 1}") + print( "dataset 8b will not be preserved in " - + "the created hfb object." + "the created hfb object." ) - sys.stdout.write(msg) current = np.recarray(nflw, dtype=dtype) for n in range(nhed): line = f.readline() diff --git a/dependencies/flopy/modflow/mfflwob.py b/dependencies/flopy/modflow/mfflwob.py index f4642b9..a8c8a2a 100755 --- a/dependencies/flopy/modflow/mfflwob.py +++ b/dependencies/flopy/modflow/mfflwob.py @@ -1,5 +1,4 @@ import os -import sys import numpy as np from ..pakbase import Package from ..utils import parsenamefile @@ -315,35 +314,33 @@ def write_file(self): f_fbob = open(self.fn_path, "w") # write header - f_fbob.write("{}\n".format(self.heading)) + f_fbob.write(f"{self.heading}\n") # write sections 1 and 2 : NOTE- what about NOPRINT? - line = "{:10d}".format(self.nqfb) - line += "{:10d}".format(self.nqcfb) - line += "{:10d}".format(self.nqtfb) - line += "{:10d}".format(self.iufbobsv) + line = f"{self.nqfb:10d}" + line += f"{self.nqcfb:10d}" + line += f"{self.nqtfb:10d}" + line += f"{self.iufbobsv:10d}" if self.no_print or "NOPRINT" in self.options: line += "{: >10}".format("NOPRINT") line += "\n" f_fbob.write(line) - f_fbob.write("{:10e}\n".format(self.tomultfb)) + f_fbob.write(f"{self.tomultfb:10e}\n") # write sections 3-5 looping through observations groups c = 0 for i in range(self.nqfb): # while (i < self.nqfb): # write section 3 - f_fbob.write( - "{:10d}{:10d}\n".format(self.nqobfb[i], self.nqclfb[i]) - ) + f_fbob.write(f"{self.nqobfb[i]:10d}{self.nqclfb[i]:10d}\n") # Loop through observation times for the groups for j in range(self.nqobfb[i]): # write section 4 - line = "{:12}".format(self.obsnam[c]) - line += "{:8d}".format(self.irefsp[c] + 1) - line += "{:16.10g}".format(self.toffset[c]) - line += " {:10.4g}\n".format(self.flwobs[c]) + line = f"{self.obsnam[c]:12}" + line += f"{self.irefsp[c] + 1:8d}" + line += f"{self.toffset[c]:16.10g}" + line += f" {self.flwobs[c]:10.4g}\n" f_fbob.write(line) c += 1 # index variable @@ -353,12 +350,12 @@ def write_file(self): # set factor to 1.0 for all cells in group if self.nqclfb[i] < 0: self.factor[i, :] = 1.0 - line = "{:10d}".format(self.layer[i, j] + 1) - line += "{:10d}".format(self.row[i, j] + 1) - line += "{:10d}".format(self.column[i, j] + 1) + line = f"{self.layer[i, j] + 1:10d}" + line += f"{self.row[i, j] + 1:10d}" + line += f"{self.column[i, j] + 1:10d}" line += " ".format(self.factor[i, j]) # note is 10f good enough here? - line += "{:10f}\n".format(self.factor[i, j]) + line += f"{self.factor[i, j]:10f}\n" f_fbob.write(line) f_fbob.close() @@ -371,9 +368,9 @@ def write_file(self): # write header f_ins = open(sfname, "w") f_ins.write("jif @\n") - f_ins.write("StandardFile 0 1 {}\n".format(self.nqtfb)) + f_ins.write(f"StandardFile 0 1 {self.nqtfb}\n") for i in range(0, self.nqtfb): - f_ins.write("{}\n".format(self.obsnam[i])) + f_ins.write(f"{self.obsnam[i]}\n") f_ins.close() # swm: END hack for writing standard file @@ -416,7 +413,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): """ if model.verbose: - sys.stdout.write("loading flwob package file...\n") + print("loading flwob package file...") openfile = not hasattr(f, "read") if openfile: @@ -610,10 +607,7 @@ def _get_ftype_from_filename(fn, ext_unit_dict=None): elif "rv" in ext.lower(): ftype = "RVOB" - msg = ( - "ModflowFlwob: filetype cannot be inferred " - "from file name {}".format(fn) - ) + msg = f"ModflowFlwob: filetype cannot be inferred from file name {fn}" if ftype is None: raise AssertionError(msg) diff --git a/dependencies/flopy/modflow/mfgage.py b/dependencies/flopy/modflow/mfgage.py index 36e4525..f4958b6 100644 --- a/dependencies/flopy/modflow/mfgage.py +++ b/dependencies/flopy/modflow/mfgage.py @@ -8,7 +8,6 @@ """ import os -import sys import numpy as np @@ -87,7 +86,7 @@ def __init__( extension="gage", unitnumber=None, filenames=None, - **kwargs + **kwargs, ): """ Package constructor. @@ -115,30 +114,24 @@ def __init__( if files is None: files = [] for idx in range(numgage): - files.append( - "{}.gage{}.go".format(model.name, idx + 1) - ) + files.append(f"{model.name}.gage{idx + 1}.go") if isinstance(files, np.ndarray): files = files.flatten().tolist() elif isinstance(files, str): files = [files] elif isinstance(files, int) or isinstance(files, float): - files = ["{}.go".format(files)] + files = [f"{files}.go"] if len(files) < numgage: - err = ( - "a filename needs to be provided " - + "for {} gages ".format(numgage) - + "- {} filenames were provided".format(len(files)) + raise Exception( + "a filename needs to be provided for {} gages - {} " + "filenames were provided".format(numgage, len(files)) ) - raise Exception(err) else: if len(filenames) < numgage + 1: - err = ( - "filenames must have a " - + "length of {} ".format(numgage + 1) - + "the length provided is {}".format(len(filenames)) + raise Exception( + "filenames must have a length of {} the length " + "provided is {}".format(numgage + 1, len(filenames)) ) - raise Exception(err) else: files = [] for n in range(numgage): @@ -172,11 +165,10 @@ def __init__( d["outtype"][n] = outtype gage_data = d else: - err = ( - "gage_data must be a numpy record array, numpy array" - + "or a list" + raise Exception( + "gage_data must be a numpy record array, numpy array " + "or a list" ) - raise Exception(err) # add gage output files to model for n in range(numgage): @@ -208,11 +200,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + # no heading for this format self.url = "gage.htm" self.numgage = numgage @@ -267,11 +255,7 @@ def write_file(self): """ f = open(self.fn_path, "w") - # # dataset 0 - # vn = self.parent.version_types[self.parent.version] - # self.heading = '# {} package for '.format(self.name[0]) + \ - # '{}, generated by Flopy.'.format(vn) - # f.write('{0}\n'.format(self.heading)) + # no heading for this format # dataset 1 f.write(write_fixed_var([self.numgage], free=True)) @@ -333,22 +317,19 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading gage package file...\n") + print("loading gage package file...") openfile = not hasattr(f, "read") if openfile: filename = f f = open(filename, "r", errors="replace") - # dataset 0 -- header - while True: - line = f.readline().rstrip() - if line[0] != "#": - break + # no heading for this format # read dataset 1 if model.verbose: print(" reading gage dataset 1") + line = f.readline().rstrip() t = read_fixed_var(line, free=True) numgage = int(t[0]) diff --git a/dependencies/flopy/modflow/mfghb.py b/dependencies/flopy/modflow/mfghb.py index e6bed6d..d5b7308 100644 --- a/dependencies/flopy/modflow/mfghb.py +++ b/dependencies/flopy/modflow/mfghb.py @@ -7,7 +7,6 @@ `_. """ -import sys import numpy as np from ..pakbase import Package from ..utils import MfList @@ -163,11 +162,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "ghb.htm" self.ipakcb = ipakcb @@ -217,15 +212,13 @@ def write_file(self, check=True): check ): # allows turning off package checks when writing files at model level self.check( - f="{}.chk".format(self.name[0]), + f=f"{self.name[0]}.chk", verbose=self.parent.verbose, level=1, ) f_ghb = open(self.fn_path, "w") - f_ghb.write("{}\n".format(self.heading)) - f_ghb.write( - "{:10d}{:10d}".format(self.stress_period_data.mxact, self.ipakcb) - ) + f_ghb.write(f"{self.heading}\n") + f_ghb.write(f"{self.stress_period_data.mxact:10d}{self.ipakcb:10d}") for option in self.options: f_ghb.write(" {}".format(option)) f_ghb.write("\n") @@ -236,7 +229,7 @@ def add_record(self, kper, index, values): try: self.stress_period_data.add_record(kper, index, values) except Exception as e: - raise Exception("mfghb error adding record to list: " + str(e)) + raise Exception(f"mfghb error adding record to list: {e!s}") @staticmethod def get_empty(ncells=0, aux_names=None, structured=True): @@ -307,7 +300,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None, check=True): """ if model.verbose: - sys.stdout.write("loading ghb package file...\n") + print("loading ghb package file...") return Package.load( f, diff --git a/dependencies/flopy/modflow/mfgmg.py b/dependencies/flopy/modflow/mfgmg.py index 3ade8fa..6e6e48c 100644 --- a/dependencies/flopy/modflow/mfgmg.py +++ b/dependencies/flopy/modflow/mfgmg.py @@ -7,7 +7,6 @@ `_. """ -import sys from ..pakbase import Package @@ -263,11 +262,7 @@ def __init__( ) raise Exception(err) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "gmg.htm" self.mxiter = mxiter @@ -296,26 +291,22 @@ def write_file(self): """ f_gmg = open(self.fn_path, "w") - f_gmg.write("%s\n" % self.heading) + f_gmg.write(f"{self.heading}\n") # dataset 0 f_gmg.write( - "{} {} {} {}\n".format( - self.rclose, self.iiter, self.hclose, self.mxiter - ) + f"{self.rclose} {self.iiter} {self.hclose} {self.mxiter}\n" ) # dataset 1 f_gmg.write( - "{} {} {} {}\n".format( - self.damp, self.iadamp, self.ioutgmg, self.iunitmhc - ) + f"{self.damp} {self.iadamp} {self.ioutgmg} {self.iunitmhc}\n" ) # dataset 2 - f_gmg.write("{} {} ".format(self.ism, self.isc)) + f_gmg.write(f"{self.ism} {self.isc} ") if self.iadamp == 2: - f_gmg.write("{} {} {}".format(self.dup, self.dlow, self.chglimit)) + f_gmg.write(f"{self.dup} {self.dlow} {self.chglimit}") f_gmg.write("\n") # dataset 3 - f_gmg.write("{}\n".format(self.relax)) + f_gmg.write(f"{self.relax}\n") f_gmg.close() @classmethod @@ -351,7 +342,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading gmg package file...\n") + print("loading gmg package file...") openfile = not hasattr(f, "read") if openfile: diff --git a/dependencies/flopy/modflow/mfhfb.py b/dependencies/flopy/modflow/mfhfb.py index 30ad445..9670703 100644 --- a/dependencies/flopy/modflow/mfhfb.py +++ b/dependencies/flopy/modflow/mfhfb.py @@ -7,7 +7,6 @@ `_. """ -import sys import numpy as np from ..pakbase import Package from .mfparbc import ModflowParBc as mfparbc @@ -143,11 +142,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "hfb6.htm" self.nphfb = nphfb @@ -203,10 +198,8 @@ def write_file(self): """ f_hfb = open(self.fn_path, "w") - f_hfb.write("{}\n".format(self.heading)) - f_hfb.write( - "{:10d}{:10d}{:10d}".format(self.nphfb, self.mxfb, self.nhfbnp) - ) + f_hfb.write(f"{self.heading}\n") + f_hfb.write(f"{self.nphfb:10d}{self.mxfb:10d}{self.nhfbnp:10d}") for option in self.options: f_hfb.write(" {}".format(option)) f_hfb.write("\n") @@ -216,7 +209,7 @@ def write_file(self): a[0] + 1, a[1] + 1, a[2] + 1, a[3] + 1, a[4] + 1, a[5] ) ) - f_hfb.write("{:10d}".format(self.nacthfb)) + f_hfb.write(f"{self.nacthfb:10d}") f_hfb.close() @staticmethod @@ -291,7 +284,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading hfb6 package file...\n") + print("loading hfb6 package file...") openfile = not hasattr(f, "read") if openfile: diff --git a/dependencies/flopy/modflow/mfhob.py b/dependencies/flopy/modflow/mfhob.py index 1d058e3..85e53d8 100755 --- a/dependencies/flopy/modflow/mfhob.py +++ b/dependencies/flopy/modflow/mfhob.py @@ -1,5 +1,3 @@ -import sys -import collections import numpy as np from ..pakbase import Package from ..utils.recarray_utils import create_empty_recarray @@ -149,11 +147,7 @@ def __init__( ) self.url = "hob.htm" - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.iuhobsv = iuhobsv self.hobdry = hobdry @@ -199,8 +193,8 @@ def _set_dimensions(self): for idx, obs in enumerate(self.obs_data): if not isinstance(obs, HeadObservation): msg += ( - "ModflowHob: obs_data entry {} ".format(idx) - + "is not a HeadObservation instance.\n" + f"ModflowHob: obs_data entry {idx} " + "is not a HeadObservation instance.\n" ) continue self.nh += obs.nobs @@ -227,20 +221,20 @@ def write_file(self): f = open(self.fn_path, "w") # write dataset 0 - f.write("{}\n".format(self.heading)) + f.write(f"{self.heading}\n") # write dataset 1 - f.write("{:10d}".format(self.nh)) - f.write("{:10d}".format(self.mobs)) - f.write("{:10d}".format(self.maxm)) - f.write("{:10d}".format(self.iuhobsv)) - f.write("{:10.4g}".format(self.hobdry)) + f.write(f"{self.nh:10d}") + f.write(f"{self.mobs:10d}") + f.write(f"{self.maxm:10d}") + f.write(f"{self.iuhobsv:10d}") + f.write(f"{self.hobdry:10.4g}") if self.no_print or "NOPRINT" in self.options: f.write("{: >10}".format("NOPRINT")) f.write("\n") # write dataset 2 - f.write("{:10.4g}\n".format(self.tomulth)) + f.write(f"{self.tomulth:10.4g}\n") # write datasets 3-6 for idx, obs in enumerate(self.obs_data): @@ -248,44 +242,44 @@ def write_file(self): obsname = obs.obsname if isinstance(obsname, bytes): obsname = obsname.decode("utf-8") - line = "{:12s} ".format(obsname) + line = f"{obsname:12s} " layer = obs.layer if layer >= 0: layer += 1 - line += "{:10d} ".format(layer) - line += "{:10d} ".format(obs.row + 1) - line += "{:10d} ".format(obs.column + 1) + line += f"{layer:10d} " + line += f"{obs.row + 1:10d} " + line += f"{obs.column + 1:10d} " irefsp = obs.irefsp if irefsp >= 0: irefsp += 1 - line += "{:10d} ".format(irefsp) + line += f"{irefsp:10d} " if obs.nobs == 1: toffset = obs.time_series_data[0]["toffset"] hobs = obs.time_series_data[0]["hobs"] else: toffset = 0.0 hobs = 0.0 - line += "{:20} ".format(toffset) - line += "{:10.4f} ".format(obs.roff) - line += "{:10.4f} ".format(obs.coff) - line += "{:10.4f} ".format(hobs) - line += " # DATASET 3 - Observation {}".format(idx + 1) - f.write("{}\n".format(line)) + line += f"{toffset:20} " + line += f"{obs.roff:10.4f} " + line += f"{obs.coff:10.4f} " + line += f"{hobs:10.4f} " + line += f" # DATASET 3 - Observation {idx + 1}" + f.write(f"{line}\n") # dataset 4 if len(obs.mlay.keys()) > 1: line = "" for key, value in iter(obs.mlay.items()): - line += "{:5d}{:10.4f}".format(key + 1, value) - line += " # DATASET 4 - Observation {}".format(idx + 1) - f.write("{}\n".format(line)) + line += f"{key + 1:5d}{value:10.4f}" + line += f" # DATASET 4 - Observation {idx + 1}" + f.write(f"{line}\n") # dataset 5 if irefsp < 0: - line = "{:10d}".format(obs.itt) + line = f"{obs.itt:10d}" line += 103 * " " - line += " # DATASET 5 - Observation {}".format(idx + 1) - f.write("{}\n".format(line)) + line += f" # DATASET 5 - Observation {idx + 1}" + f.write(f"{line}\n") # dataset 6: if obs.nobs > 1: @@ -293,15 +287,13 @@ def write_file(self): obsname = t["obsname"] if isinstance(obsname, bytes): obsname = obsname.decode("utf-8") - line = "{:12s} ".format(obsname) - line += "{:10d} ".format(t["irefsp"] + 1) - line += "{:20} ".format(t["toffset"]) - line += "{:10.4f} ".format(t["hobs"]) + line = f"{obsname:12s} " + line += f"{t['irefsp'] + 1:10d} " + line += f"{t['toffset']:20} " + line += f"{t['hobs']:10.4f} " line += 55 * " " - line += " # DATASET 6 - " + "Observation {}.{}".format( - idx + 1, jdx + 1 - ) - f.write("{}\n".format(line)) + line += f" # DATASET 6 - Observation {idx + 1}.{jdx + 1}" + f.write(f"{line}\n") # close the hob package file f.close() @@ -344,7 +336,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): """ if model.verbose: - sys.stdout.write("loading hob package file...\n") + print("loading hob package file...") openfile = not hasattr(f, "read") if openfile: @@ -378,7 +370,8 @@ def load(cls, f, model, ext_unit_dict=None, check=True): nobs = 0 # set to False for 1st call to ensure that totim cache is updated - use_cached_totim = False + tmax = model.dis.get_final_totim() + use_cached_totim = True while True: # read dataset 3 @@ -401,7 +394,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): else: line = f.readline() t = line.strip().split() - mlay = collections.OrderedDict() + mlay = {} if len(t) >= abs(layer) * 2: for j in range(0, abs(layer) * 2, 2): k = int(t[j]) - 1 @@ -438,7 +431,6 @@ def load(cls, f, model, ext_unit_dict=None, check=True): names = [obsnam] tsd = [totim, hob] nobs += 1 - use_cached_totim = True else: names = [] tsd = [] @@ -459,7 +451,6 @@ def load(cls, f, model, ext_unit_dict=None, check=True): hob = float(t[3]) tsd.append([totim, hob]) nobs += 1 - use_cached_totim = True obs_data.append( HeadObservation( @@ -473,6 +464,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): obsname=obsnam, mlay=mlay, itt=itt, + tmax=tmax, time_series_data=tsd, names=names, ) @@ -550,6 +542,9 @@ class HeadObservation: observations. itt = 1 specified for heads and itt = 2 specified if initial value is head and subsequent changes in head. Only specified if irefsp is < 0. Default is 1. + tmax : float + Maximum simulation time calculated using get_final_totim function of + ModflowDis. Added to avoid repetitive calls. mlay : dictionary of length (abs(irefsp)) Key represents zero-based layer numbers for multilayer observations and value represents the fractional value for each layer of multilayer @@ -595,6 +590,7 @@ def __init__( roff=0.0, coff=0.0, itt=1, + tmax=None, mlay=None, time_series_data=None, names=None, @@ -634,12 +630,13 @@ def __init__( for key, value in self.mlay.items(): tot += value if not (np.isclose(tot, 1.0, rtol=0)): - msg = ( + raise ValueError( "sum of dataset 4 proportions must equal 1.0 - " - + "sum of dataset 4 proportions = {tot} for " - + "observation name {obsname}." - ).format(tot=tot, obsname=self.obsname) - raise ValueError(msg) + "sum of dataset 4 proportions = {tot} for " + "observation name {obsname}.".format( + tot=tot, obsname=self.obsname + ) + ) # convert passed time_series_data to a numpy array if isinstance(time_series_data, list): @@ -651,7 +648,8 @@ def __init__( time_series_data = np.reshape(time_series_data, (1, 2)) # find indices of time series data that are valid - tmax = model.dis.get_final_totim() + if tmax is None: + tmax = model.dis.get_final_totim() keep_idx = time_series_data[:, 0] <= tmax time_series_data = time_series_data[keep_idx, :] @@ -666,42 +664,35 @@ def __init__( else: names = [] for idx in range(self.nobs): - names.append("{}.{}".format(obsname, idx + 1)) + names.append(f"{obsname}.{idx + 1}") # make sure the length of names is greater than or equal to nobs else: if isinstance(names, str): names = [names] elif not isinstance(names, list): - msg = ( + raise ValueError( "HeadObservation names must be a " - + "string or a list of strings" + "string or a list of strings" ) - raise ValueError(msg) if len(names) < self.nobs: - msg = ( - "a name must be specified for every valid " - + "observation - {} ".format(len(names)) - + "names were passed but at least " - + "{} names are required.".format(self.nobs) + raise ValueError( + "a name must be specified for every valid observation " + "- {} names were passed but at least " + "{} names are required.".format(len(names), self.nobs) ) - raise ValueError(msg) - - # set use_cached_totim to False first to ensure totim is updated - use_cached_totim = False # create time_series_data self.time_series_data = self._get_empty(ncells=shape[0]) for idx in range(self.nobs): t = time_series_data[idx, 0] kstp, kper, toffset = model.dis.get_kstp_kper_toffset( - t, use_cached_totim + t, use_cached_totim=True ) self.time_series_data[idx]["totim"] = t self.time_series_data[idx]["irefsp"] = kper self.time_series_data[idx]["toffset"] = toffset / tomulth self.time_series_data[idx]["hobs"] = time_series_data[idx, 1] self.time_series_data[idx]["obsname"] = names[idx] - use_cached_totim = True if self.nobs > 1: self.irefsp = -self.nobs diff --git a/dependencies/flopy/modflow/mfhyd.py b/dependencies/flopy/modflow/mfhyd.py index 5379270..5c3fc9c 100644 --- a/dependencies/flopy/modflow/mfhyd.py +++ b/dependencies/flopy/modflow/mfhyd.py @@ -7,8 +7,6 @@ `_. """ -import sys - import numpy as np from ..pakbase import Package @@ -173,11 +171,7 @@ def __init__( ) nrow, ncol, nlay, nper = self.parent.nrow_ncol_nlay_nper - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "hyd.htm" self.nhyd = nhyd @@ -188,10 +182,10 @@ def __init__( obs = ModflowHyd.get_empty(nhyd) if isinstance(obsdata, list): if len(obsdata) != nhyd: - e = "ModflowHyd: nhyd ({}) does not equal ".format( - nhyd - ) + "length of obsdata ({}).".format(len(obsdata)) - raise RuntimeError(e) + raise RuntimeError( + f"ModflowHyd: nhyd ({nhyd}) does not equal " + f"length of obsdata ({len(obsdata)})." + ) for idx in range(nhyd): obs["pckg"][idx] = obsdata[idx][0] obs["arr"][idx] = obsdata[idx][1] @@ -244,21 +238,17 @@ def write_file(self): f = open(self.fn_path, "w") # write dataset 1 - f.write( - "{} {} {} {}\n".format( - self.nhyd, self.ihydun, self.hydnoh, self.heading - ) - ) + f.write(f"{self.nhyd} {self.ihydun} {self.hydnoh} {self.heading}\n") # write dataset 2 for idx in range(self.nhyd): - f.write("{} ".format(self.obsdata["pckg"][idx].decode())) - f.write("{} ".format(self.obsdata["arr"][idx].decode())) - f.write("{} ".format(self.obsdata["intyp"][idx].decode())) - f.write("{} ".format(self.obsdata["klay"][idx] + 1)) - f.write("{} ".format(self.obsdata["xl"][idx])) - f.write("{} ".format(self.obsdata["yl"][idx])) - f.write("{} ".format(self.obsdata["hydlbl"][idx].decode())) + f.write(f"{self.obsdata['pckg'][idx].decode()} ") + f.write(f"{self.obsdata['arr'][idx].decode()} ") + f.write(f"{self.obsdata['intyp'][idx].decode()} ") + f.write(f"{self.obsdata['klay'][idx] + 1} ") + f.write(f"{self.obsdata['xl'][idx]} ") + f.write(f"{self.obsdata['yl'][idx]} ") + f.write(f"{self.obsdata['hydlbl'][idx].decode()} ") f.write("\n") # close hydmod file @@ -319,7 +309,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading hydmod package file...\n") + print("loading hydmod package file...") openfile = not hasattr(f, "read") if openfile: @@ -329,7 +319,7 @@ def load(cls, f, model, ext_unit_dict=None): # --read dataset 1 # NHYD IHYDUN HYDNOH if model.verbose: - sys.stdout.write(" loading hydmod dataset 1\n") + print(" loading hydmod dataset 1") line = f.readline() t = line.strip().split() nhyd = int(t[0]) diff --git a/dependencies/flopy/modflow/mflak.py b/dependencies/flopy/modflow/mflak.py index acfeab3..02b72d4 100644 --- a/dependencies/flopy/modflow/mflak.py +++ b/dependencies/flopy/modflow/mflak.py @@ -7,7 +7,6 @@ `_. """ -import sys import numpy as np from ..pakbase import Package from ..utils.util_array import Transient3d @@ -279,7 +278,7 @@ def __init__( filenames=None, options=None, lwrt=0, - **kwargs + **kwargs, ): """ Package constructor. @@ -325,16 +324,16 @@ def __init__( # make sure the number of tabfiles is equal to the number of lakes if len(tab_files) < nlakes: msg = ( - "a tabfile must be specified for each lake" - + "{} tabfiles specified ".format(len(tab_files)) - + "instead of {} tabfiles".format(nlakes) + "a tabfile must be specified for each lake " + "{} tabfiles specified " + "instead of {} tabfiles".format(len(tab_files), nlakes) ) # make sure tab_files are not None for idx, fname in enumerate(tab_files): if fname is None: msg = ( "a filename must be specified for the " - + "tabfile for lake {}".format(idx + 1) + "tabfile for lake {}".format(idx + 1) ) raise ValueError(msg) # set unit for tab files if not passed to __init__ @@ -365,11 +364,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "lak.htm" if options is None: @@ -391,9 +386,7 @@ def __init__( elif isinstance(stages, list): stages = np.array(stages) if stages.shape[0] != nlakes: - err = "stages shape should be " + "({}) but is only ({}).".format( - nlakes, stages.shape[0] - ) + err = f"stages shape should be ({nlakes}) but is only ({stages.shape[0]})." raise Exception(err) self.stages = stages if stage_range is None: @@ -404,20 +397,15 @@ def __init__( if isinstance(stage_range, list): stage_range = np.array(stage_range) elif isinstance(stage_range, float): - err = ( - "stage_range should be a list or " - + "array of size ({}, 2)".format(nlakes) + raise Exception( + f"stage_range should be a list or array of size ({nlakes}, 2)" ) - raise Exception(err) if self.parent.dis.steady[0]: if stage_range.shape != (nlakes, 2): - err = ( - "stages shape should be " - + "({},2) but is only {}.".format( - nlakes, stage_range.shape - ) + raise Exception( + "stages shape should be ({},2) but is only " + "{}.".format(nlakes, stage_range.shape) ) - raise Exception(err) self.stage_range = stage_range # tabfile data @@ -458,11 +446,9 @@ def __init__( td[k] = value[k, :].tolist() flux_data[key] = td if len(list(flux_data.keys())) != nlakes: - err = ( - "flux_data dictionary must " - + "have {} entries".format(nlakes) + raise Exception( + f"flux_data dictionary must have {nlakes} entries" ) - raise Exception(err) elif isinstance(value, float) or isinstance(value, int): td = {} for k in range(self.nlakes): @@ -479,14 +465,11 @@ def __init__( for k in range(self.nlakes): td = value[k] if len(td) < nlen: - err = ( - "flux_data entry for stress period".format( - key + 1 - ) - + "has {} entries but ".format(nlen) - + "should have {} entries".format(len(td)) + raise Exception( + "flux_data entry for stress period {} " + "has {} entries but should have " + "{} entries".format(key + 1, nlen, len(td)) ) - raise Exception(err) self.flux_data = flux_data self.sill_data = sill_data @@ -519,10 +502,8 @@ def write_file(self): """ f = open(self.fn_path, "w") # dataset 0 - self.heading = "# {} package for ".format( - self.name[0] - ) + "{}, generated by Flopy.".format(self.parent.version) - f.write("{0}\n".format(self.heading)) + if self.parent.version != "mf2k": + f.write(f"{self.heading}\n") # dataset 1a if len(self.options) > 0: @@ -584,7 +565,7 @@ def write_file(self): else: tmplwrt = self.lwrt t = [itmp, itmp2, tmplwrt] - comment = "Stress period {}".format(kper + 1) + comment = f"Stress period {kper + 1}" f.write( write_fixed_var( t, free=self.parent.free_format_input, comment=comment @@ -683,7 +664,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading lak package file...\n") + print("loading lak package file...") openfile = not hasattr(f, "read") if openfile: @@ -774,8 +755,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): for iper in range(nper): if model.verbose: print( - " reading lak dataset 4 - " - + "for stress period {}".format(iper + 1) + f" reading lak dataset 4 - for stress period {iper + 1}" ) line = f.readline().rstrip() if model.array_free_format: @@ -788,19 +768,17 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): if itmp > 0: if model.verbose: print( - " reading lak dataset 5 - " - + "for stress period {}".format(iper + 1) + f" reading lak dataset 5 - for stress period {iper + 1}" ) - name = "LKARR_StressPeriod_{}".format(iper) + name = f"LKARR_StressPeriod_{iper}" lakarr = Util3d.load( f, model, (nlay, nrow, ncol), np.int32, name, ext_unit_dict ) if model.verbose: print( - " reading lak dataset 6 - " - + "for stress period {}".format(iper + 1) + f" reading lak dataset 6 - for stress period {iper + 1}" ) - name = "BDLKNC_StressPeriod_{}".format(iper) + name = f"BDLKNC_StressPeriod_{iper}" bdlknc = Util3d.load( f, model, @@ -815,8 +793,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): if model.verbose: print( - " reading lak dataset 7 - " - + "for stress period {}".format(iper + 1) + f" reading lak dataset 7 - for stress period {iper + 1}" ) line = f.readline().rstrip() t = line.split() @@ -825,8 +802,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): if nslms > 0: if model.verbose: print( - " reading lak dataset 8 - " - + "for stress period {}".format(iper + 1) + f" reading lak dataset 8 - for stress period {iper + 1}" ) for i in range(nslms): line = f.readline().rstrip() @@ -852,8 +828,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): if itmp1 >= 0: if model.verbose: print( - " reading lak dataset 9 - " - + "for stress period {}".format(iper + 1) + f" reading lak dataset 9 - for stress period {iper + 1}" ) ds9 = {} for n in range(nlakes): diff --git a/dependencies/flopy/modflow/mflmt.py b/dependencies/flopy/modflow/mflmt.py index 5ad5f06..fd99822 100644 --- a/dependencies/flopy/modflow/mflmt.py +++ b/dependencies/flopy/modflow/mflmt.py @@ -8,7 +8,7 @@ """ import os -import sys + from ..pakbase import Package @@ -116,11 +116,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "lmt.htm" self.output_file_name = output_file_name self.output_file_unit = output_file_unit @@ -140,19 +136,11 @@ def write_file(self): """ f = open(self.fn_path, "w") - f.write("{}\n".format(self.heading)) - f.write("{:20s}\n".format("OUTPUT_FILE_NAME " + self.output_file_name)) - f.write( - "{:20s} {:10d}\n".format( - "OUTPUT_FILE_UNIT ", self.output_file_unit - ) - ) - f.write( - "{:20s}\n".format("OUTPUT_FILE_HEADER " + self.output_file_header) - ) - f.write( - "{:20s}\n".format("OUTPUT_FILE_FORMAT " + self.output_file_format) - ) + f.write(f"{self.heading}\n") + f.write(f"OUTPUT_FILE_NAME {self.output_file_name:20s}\n") + f.write(f"OUTPUT_FILE_UNIT {self.output_file_unit:10d}\n") + f.write(f"OUTPUT_FILE_HEADER {self.output_file_header:20s}\n") + f.write(f"OUTPUT_FILE_FORMAT {self.output_file_format:20s}\n") if self.package_flows: # check that the list is not empty # Generate a string to write pckgs = "" @@ -165,8 +153,7 @@ def write_file(self): if "all" in [x.lower() for x in self.package_flows]: pckgs += "ALL" - line = "PACKAGE_FLOWS " + pckgs - f.write("%s\n" % (line)) + f.write(f"PACKAGE_FLOWS {pckgs}\n") f.close() @@ -204,7 +191,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading lmt package file...\n") + print("loading lmt package file...") openfile = not hasattr(f, "read") if openfile: @@ -218,9 +205,9 @@ def load(cls, f, model, ext_unit_dict=None): # set default values if filename: prefix = os.path.splitext(os.path.basename(filename))[0] - output_file_name = prefix + ".ftl" + output_file_name = f"{prefix}.ftl" else: - output_file_name = model.name + ".ftl" + output_file_name = f"{model.name}.ftl" output_file_unit = 333 output_file_header = "standard" output_file_format = "unformatted" diff --git a/dependencies/flopy/modflow/mflpf.py b/dependencies/flopy/modflow/mflpf.py index 5521284..e58df37 100644 --- a/dependencies/flopy/modflow/mflpf.py +++ b/dependencies/flopy/modflow/mflpf.py @@ -7,9 +7,6 @@ `_. """ - -import sys - import numpy as np from .mfpar import ModflowPar as mfpar @@ -255,11 +252,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "lpf.htm" nrow, ncol, nlay, nper = self.parent.nrow_ncol_nlay_nper @@ -379,7 +372,7 @@ def write_file(self, check=True, f=None): # allows turning off package checks when writing files at model level if check: self.check( - f="{}.chk".format(self.name[0]), + f=f"{self.name[0]}.chk", verbose=self.parent.verbose, level=1, ) @@ -395,7 +388,7 @@ def write_file(self, check=True, f=None): f = open(self.fn_path, "w") # Item 0: text - f.write("{}\n".format(self.heading)) + f.write(f"{self.heading}\n") # Item 1: IBCFCB, HDRY, NPLPF, , OPTIONS if self.parent.version == "mfusg" and self.parent.structured == False: @@ -410,9 +403,7 @@ def write_file(self, check=True, f=None): ) else: f.write( - "{0:10d}{1:10.6G}{2:10d} {3:s}\n".format( - self.ipakcb, self.hdry, self.nplpf, self.options - ) + f"{self.ipakcb:10d}{self.hdry:10.6G}{self.nplpf:10d} {self.options}\n" ) # LAYTYP array f.write(self.laytyp.string) @@ -427,11 +418,7 @@ def write_file(self, check=True, f=None): # Item 7: WETFCT, IWETIT, IHDWET iwetdry = self.laywet.sum() if iwetdry > 0: - f.write( - "{0:10f}{1:10d}{2:10d}\n".format( - self.wetfct, self.iwetit, self.ihdwet - ) - ) + f.write(f"{self.wetfct:10f}{self.iwetit:10d}{self.ihdwet:10d}\n") transient = not dis.steady.all() for k in range(nlay): f.write(self.hk[k].get_file_entry()) @@ -485,7 +472,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): """ if model.verbose: - sys.stdout.write("loading lpf package file...\n") + print("loading lpf package file...") openfile = not hasattr(f, "read") if openfile: @@ -604,7 +591,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # hk if model.verbose: - print(" loading hk layer {0:3d}...".format(k + 1)) + print(f" loading hk layer {k + 1:3d}...") if "hk" not in par_types: t = Util2d.load( f, model, (nrow, ncol), np.float32, "hk", ext_unit_dict @@ -619,7 +606,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # hani if chani[k] <= 0.0: if model.verbose: - print(" loading hani layer {0:3d}...".format(k + 1)) + print(f" loading hani layer {k + 1:3d}...") if "hani" not in par_types: t = Util2d.load( f, @@ -638,7 +625,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # vka if model.verbose: - print(" loading vka layer {0:3d}...".format(k + 1)) + print(f" loading vka layer {k + 1:3d}...") key = "vk" if layvka[k] != 0: key = "vani" @@ -661,7 +648,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # ss if model.verbose: - print(" loading ss layer {0:3d}...".format(k + 1)) + print(f" loading ss layer {k + 1:3d}...") if "ss" not in par_types: t = Util2d.load( f, model, (nrow, ncol), np.float32, "ss", ext_unit_dict @@ -676,7 +663,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # sy if laytyp[k] != 0: if model.verbose: - print(" loading sy layer {0:3d}...".format(k + 1)) + print(f" loading sy layer {k + 1:3d}...") if "sy" not in par_types: t = Util2d.load( f, @@ -696,7 +683,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # vkcb if dis.laycbd[k] > 0: if model.verbose: - print(" loading vkcb layer {0:3d}...".format(k + 1)) + print(f" loading vkcb layer {k + 1:3d}...") if "vkcb" not in par_types: t = Util2d.load( f, @@ -716,7 +703,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # wetdry if laywet[k] != 0 and laytyp[k] != 0: if model.verbose: - print(" loading wetdry layer {0:3d}...".format(k + 1)) + print(f" loading wetdry layer {k + 1:3d}...") t = Util2d.load( f, model, (nrow, ncol), np.float32, "wetdry", ext_unit_dict ) @@ -769,7 +756,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): ) if check: lpf.check( - f="{}.chk".format(lpf.name[0]), + f=f"{lpf.name[0]}.chk", verbose=lpf.parent.verbose, level=0, ) diff --git a/dependencies/flopy/modflow/mfmlt.py b/dependencies/flopy/modflow/mfmlt.py index 6f61fa1..884752d 100644 --- a/dependencies/flopy/modflow/mfmlt.py +++ b/dependencies/flopy/modflow/mfmlt.py @@ -7,9 +7,6 @@ `_. """ -import collections -import sys - import numpy as np from ..pakbase import Package @@ -99,11 +96,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "mult.htm" self.nml = 0 @@ -167,7 +160,7 @@ def load(cls, f, model, nrow=None, ncol=None, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading mult package file...\n") + print("loading mult package file...") openfile = not hasattr(f, "read") if openfile: @@ -188,7 +181,7 @@ def load(cls, f, model, nrow=None, ncol=None, ext_unit_dict=None): nrow, ncol, nlay, nper = model.get_nrow_ncol_nlay_nper() # read zone data - mult_dict = collections.OrderedDict() + mult_dict = {} for n in range(nml): line = f.readline() t = line.strip().split() @@ -197,9 +190,7 @@ def load(cls, f, model, nrow=None, ncol=None, ext_unit_dict=None): else: mltnam = t[0].lower() if model.verbose: - sys.stdout.write( - ' reading data for "{:<10s}" mult\n'.format(mltnam) - ) + print(f' reading data for "{mltnam:<10s}" mult') readArray = True kwrd = None if len(t) > 1: @@ -273,8 +264,7 @@ def mult_function(mult_dict, line): elif op == "^": multarray = multarray ** atemp else: - s = "Invalid MULT operation {}".format(op) - raise Exception(s) + raise Exception(f"Invalid MULT operation {op}") return multarray @staticmethod diff --git a/dependencies/flopy/modflow/mfmnw1.py b/dependencies/flopy/modflow/mfmnw1.py index 0e2d324..141eca7 100644 --- a/dependencies/flopy/modflow/mfmnw1.py +++ b/dependencies/flopy/modflow/mfmnw1.py @@ -1,4 +1,3 @@ -import sys import re import numpy as np from ..pakbase import Package @@ -132,11 +131,7 @@ def __init__( self.url = "mnw1.htm" self.nper = self.parent.nrow_ncol_nlay_nper[-1] - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.mxmnw = ( mxmnw # -maximum number of multi-node wells to be simulated ) @@ -213,7 +208,7 @@ def get_default_dtype(structured=True): def load(cls, f, model, nper=None, gwt=False, nsol=1, ext_unit_dict=None): if model.verbose: - sys.stdout.write("loading mnw1 package file...\n") + print("loading mnw1 package file...") structured = model.structured if nper is None: diff --git a/dependencies/flopy/modflow/mfmnw2.py b/dependencies/flopy/modflow/mfmnw2.py index 5dc4863..1fcb4cd 100644 --- a/dependencies/flopy/modflow/mfmnw2.py +++ b/dependencies/flopy/modflow/mfmnw2.py @@ -1,5 +1,4 @@ import os -import sys import warnings import numpy as np @@ -559,11 +558,10 @@ def get_default_spd_dtype(structured=True): ] ) else: - msg = ( + raise NotImplementedError( "Mnw2: get_default_spd_dtype not implemented for " - + "unstructured grids" + "unstructured grids" ) - raise NotImplementedError(msg) @staticmethod def get_item2_names(mnw2obj=None, node_data=None): @@ -848,16 +846,14 @@ def _getloc(n): if self.pumploc > 0: f_mnw.write( indent - + "{:.0f} {:.0f} {:.0f}\n".format( - self.pumplay, self.pumprow, self.pumpcol - ) + + f"{self.pumplay:.0f} {self.pumprow:.0f} {self.pumpcol:.0f}\n" ) elif self.pumploc < 0: - fmt = indent + "{}\n".format(float_format) + fmt = indent + f"{float_format}\n" f_mnw.write(fmt.format(self.zpump)) # dataset 2f if self.qlimit > 0: - fmt = indent + "{} ".format(float_format) + "{:.0f}" + fmt = indent + f"{float_format} " + "{:.0f}" f_mnw.write(fmt.format(self.hlim, self.qcut)) if self.qcut != 0: fmt = " {0} {0}".format(float_format) @@ -1065,11 +1061,7 @@ def __init__( self.structured = self.parent.structured # Dataset 0 - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() # Dataset 1 # maximum number of multi-node wells to be simulated self.mnwmax = int(mnwmax) @@ -1353,7 +1345,7 @@ def load(cls, f, model, nper=None, gwt=False, nsol=1, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading mnw2 package file...\n") + print("loading mnw2 package file...") structured = model.structured if nper is None: @@ -1769,13 +1761,13 @@ def _write_1(self, f_mnw): None """ - f_mnw.write("{:.0f} ".format(self.mnwmax)) + f_mnw.write(f"{self.mnwmax:.0f} ") if self.mnwmax < 0: - f_mnw.write("{:.0f} ".format(self.nodtot)) - f_mnw.write("{:.0f} {:.0f}".format(self.ipakcb, self.mnwprnt)) + f_mnw.write(f"{self.nodtot:.0f} ") + f_mnw.write(f"{self.ipakcb:.0f} {self.mnwprnt:.0f}") if len(self.aux) > 0: for abc in self.aux: - f_mnw.write(" aux {}".format(abc)) + f_mnw.write(f" aux {abc}") f_mnw.write("\n") def write_file( @@ -1806,7 +1798,7 @@ def write_file( f_mnw = open(self.fn_path, "w") # dataset 0 (header) - f_mnw.write("{0}\n".format(self.heading)) + f_mnw.write(f"{self.heading}\n") # dataset 1 self._write_1(f_mnw) @@ -1825,11 +1817,7 @@ def write_file( # dataset 3 for per in range(self.nper): - f_mnw.write( - "{:.0f} Stress Period {:.0f}\n".format( - self.itmp[per], per + 1 - ) - ) + f_mnw.write(f"{self.itmp[per]:.0f} Stress Period {per + 1}\n") if self.itmp[per] > 0: for n in range(self.itmp[per]): @@ -1928,10 +1916,8 @@ def _parse_2(f): line = line_parse(get_next_line(f)) if len(line) > 2: warnings.warn( - "MNW2: {}\n".format(line) - + "Extra items in Dataset 2a!" - + "Check for WELLIDs with space " - + "but not enclosed in quotes." + "MNW2: {}\nExtra items in Dataset 2a! Check for WELLIDs with " + "space but not enclosed in quotes.".format(line) ) wellid = pop_item(line).lower() nnodes = pop_item(line, int) @@ -2192,10 +2178,8 @@ def __init__(self, itmp, nactivewells): self.nactivewells = nactivewells def __str__(self): - s = ( - "\n\nItmp value of {} ".format(self.itmp) - + "is positive but does not equal the number of active wells " - + "specified ({}). ".format(self.nactivewells) - + "See MNW2 package documentation for details." + return ( + "\n\nItmp value of {} is positive but does not equal the number " + "of active wells specified ({}). See MNW2 package documentation " + "for details.".format(self.itmp, self.nactivewells) ) - return s diff --git a/dependencies/flopy/modflow/mfmnwi.py b/dependencies/flopy/modflow/mfmnwi.py index 820a506..73a51f1 100644 --- a/dependencies/flopy/modflow/mfmnwi.py +++ b/dependencies/flopy/modflow/mfmnwi.py @@ -1,5 +1,3 @@ -import sys - from ..utils.flopy_io import line_parse, pop_item from ..pakbase import Package @@ -137,7 +135,7 @@ def __init__( model.add_output_file( iu, fname=fname, - extension="{:04d}.mnwobs".format(iu), + extension=f"{iu:04d}.mnwobs", binflag=False, package=ModflowMnwi._ftype(), ) @@ -162,11 +160,7 @@ def __init__( ) self.url = "mnwi.htm" - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() # integer flag indicating output to be written for each MNW node at # the end of each stress period self.wel1flag = wel1flag @@ -197,7 +191,7 @@ def __init__( if len(self.wellid_unit_qndflag_qhbflag_concflag) != self.mnwobs: print( "WARNING: number of listed well ids to be " - + "monitored does not match MNWOBS." + "monitored does not match MNWOBS." ) self.parent.add_package(self) @@ -206,7 +200,7 @@ def __init__( def load(cls, f, model, nper=None, gwt=False, nsol=1, ext_unit_dict=None): if model.verbose: - sys.stdout.write("loading mnw2 package file...\n") + print("loading mnw2 package file...") structured = model.structured if nper is None: @@ -348,13 +342,13 @@ def write_file(self): # f.write('{}\n'.format(self.heading)) # dataset 1 - WEL1flag QSUMflag SYNDflag - line = "{:10d}".format(self.wel1flag) - line += "{:10d}".format(self.qsumflag) - line += "{:10d}\n".format(self.byndflag) + line = f"{self.wel1flag:10d}" + line += f"{self.qsumflag:10d}" + line += f"{self.byndflag:10d}\n" f.write(line) # dataset 2 - MNWOBS - f.write("{:10d}\n".format(self.mnwobs)) + f.write(f"{self.mnwobs:10d}\n") # dataset 3 - WELLID UNIT QNDflag QBHflag {CONCflag} # (Repeat MNWOBS times) @@ -370,10 +364,10 @@ def write_file(self): assert ( qhbflag >= 0 ), "QHBflag must be greater than or equal to zero." - line = "{:20s} ".format(wellid) - line += "{:5d} ".format(unit) - line += "{:5d} ".format(qndflag) - line += "{:5d} ".format(qhbflag) + line = f"{wellid:20s} " + line += f"{unit:5d} " + line += f"{qndflag:5d} " + line += f"{qhbflag:5d} " if nitems == 5: concflag = t[4] assert ( @@ -382,7 +376,7 @@ def write_file(self): assert isinstance( concflag, int ), "CONCflag must be an integer between 0 and 3." - line += "{:5d} ".format(concflag) + line += f"{concflag:5d} " line += "\n" f.write(line) diff --git a/dependencies/flopy/modflow/mfnwt.py b/dependencies/flopy/modflow/mfnwt.py index 1f22e81..8d414b7 100644 --- a/dependencies/flopy/modflow/mfnwt.py +++ b/dependencies/flopy/modflow/mfnwt.py @@ -7,8 +7,6 @@ `_. """ - -import sys from ..pakbase import Package @@ -272,11 +270,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "nwt_newton_solver.htm" self.headtol = headtol self.fluxtol = fluxtol @@ -327,7 +321,7 @@ def write_file(self): """ # Open file for writing f = open(self.fn_path, "w") - f.write("%s\n" % self.heading) + f.write(f"{self.heading}\n") f.write( "{:10.3e}{:10.3e}{:10d}{:10.3e}{:10d}{:10d}{:10d}".format( self.headtol, @@ -345,33 +339,33 @@ def write_file(self): if option.lower() == "specified": isspecified = True if isspecified: - f.write("{0:10.4g}".format(self.dbdtheta)) - f.write("{0:10.4g}".format(self.dbdkappa)) - f.write("{0:10.4g}".format(self.dbdgamma)) - f.write("{0:10.4g}".format(self.momfact)) - f.write("{0:10d}".format(self.backflag)) + f.write(f"{self.dbdtheta:10.4g}") + f.write(f"{self.dbdkappa:10.4g}") + f.write(f"{self.dbdgamma:10.4g}") + f.write(f"{self.momfact:10.4g}") + f.write(f"{self.backflag:10d}") if self.backflag > 0: - f.write("{0:10d}".format(self.maxbackiter)) - f.write("{0:10.4g}".format(self.backtol)) - f.write("{0:10.4g}".format(self.backreduce)) + f.write(f"{self.maxbackiter:10d}") + f.write(f"{self.backtol:10.4g}") + f.write(f"{self.backreduce:10.4g}") f.write("\n") if self.linmeth == 1: - f.write("{0:10d}".format(self.maxitinner)) - f.write("{0:10d}".format(self.ilumethod)) - f.write("{0:10d}".format(self.levfill)) - f.write("{0:10.4g}".format(self.stoptol)) - f.write("{0:10d}".format(self.msdr)) + f.write(f"{self.maxitinner:10d}") + f.write(f"{self.ilumethod:10d}") + f.write(f"{self.levfill:10d}") + f.write(f"{self.stoptol:10.4g}") + f.write(f"{self.msdr:10d}") elif self.linmeth == 2: - f.write("{0:10d}".format(self.iacl)) - f.write("{0:10d}".format(self.norder)) - f.write("{0:10d}".format(self.level)) - f.write("{0:10d}".format(self.north)) - f.write("{0:10d}".format(self.iredsys)) - f.write("{0:10.4g}".format(self.rrctols)) - f.write("{0:10d}".format(self.idroptol)) - f.write("{0:10.4g}".format(self.epsrn)) - f.write("{0:10.4g}".format(self.hclosexmd)) - f.write("{0:10d}".format(self.mxiterxmd)) + f.write(f"{self.iacl:10d}") + f.write(f"{self.norder:10d}") + f.write(f"{self.level:10d}") + f.write(f"{self.north:10d}") + f.write(f"{self.iredsys:10d}") + f.write(f"{self.rrctols:10.4g}") + f.write(f"{self.idroptol:10d}") + f.write(f"{self.epsrn:10.4g}") + f.write(f"{self.hclosexmd:10.4g}") + f.write(f"{self.mxiterxmd:10d}") f.write("\n") @@ -408,19 +402,14 @@ def load(cls, f, model, ext_unit_dict=None): >>> nwt = flopy.modflow.ModflowPcg.load('test.nwt', m) """ - import collections - if model.verbose: - sys.stdout.write("loading nwt package file...\n") + print("loading nwt package file...") if model.version != "mfnwt": - msg = ( - "Warning: model version was reset from " - + "'{}' to 'mfnwt' in order to load a NWT file".format( - model.version - ) + print( + "Warning: model version was reset from '{}' to 'mfnwt' in " + "order to load a NWT file".format(model.version) ) - print(msg) model.version = "mfnwt" openfile = not hasattr(f, "read") @@ -443,18 +432,17 @@ def load(cls, f, model, ext_unit_dict=None): # dataset 1 ifrfm = True # model.free_format_input - vars = ( - ("headtol", float), - ("fluxtol", float), - ("maxiterout", int), - ("thickfact", float), - ("linmeth", int), - ("iprnwt", int), - ("ibotav", int), - ("options", str), - ("Continue", str), - ) - vars = collections.OrderedDict(vars) + vars = { + "headtol": float, + "fluxtol": float, + "maxiterout": int, + "thickfact": float, + "linmeth": int, + "iprnwt": int, + "ibotav": int, + "options": str, + "Continue": str, + } kwargs = {} if ifrfm: t = line.split() @@ -479,17 +467,16 @@ def load(cls, f, model, ext_unit_dict=None): else: kwargs.pop("Continue") - specdict = ( - ("dbdtheta", float), - ("dbdkappa", float), - ("dbdgamma", float), - ("momfact", float), - ("backflag", int), - ("maxbackiter", int), - ("backtol", float), - ("backreduce", float), - ) - specdict = collections.OrderedDict(specdict) + specdict = { + "dbdtheta": float, + "dbdkappa": float, + "dbdgamma": float, + "momfact": float, + "backflag": int, + "maxbackiter": int, + "backtol": float, + "backreduce": float, + } ipos = len(kwargs) if kwargs["options"].lower().strip() == "specified": for (k, c) in specdict.items(): @@ -511,27 +498,26 @@ def load(cls, f, model, ext_unit_dict=None): lindict = {} if kwargs["linmeth"] == 1: - lindict = ( - ("maxitinner", int), - ("ilumethod", int), - ("levfill", int), - ("stoptol", float), - ("msdr", int), - ) + lindict = { + "maxitinner": int, + "ilumethod": int, + "levfill": int, + "stoptol": float, + "msdr": int, + } elif kwargs["linmeth"] == 2: - lindict = ( - ("iacl", int), - ("norder", int), - ("level", int), - ("north", int), - ("iredsys", int), - ("rrctols", float), - ("idroptol", int), - ("epsrn", float), - ("hclosexmd", float), - ("mxiterxmd", int), - ) - lindict = collections.OrderedDict(lindict) + lindict = { + "iacl": int, + "norder": int, + "level": int, + "north": int, + "iredsys": int, + "rrctols": float, + "idroptol": int, + "epsrn": float, + "hclosexmd": float, + "mxiterxmd": int, + } if ifrfm: t = line.split() else: diff --git a/dependencies/flopy/modflow/mfoc.py b/dependencies/flopy/modflow/mfoc.py index 54a96af..4cfecd7 100644 --- a/dependencies/flopy/modflow/mfoc.py +++ b/dependencies/flopy/modflow/mfoc.py @@ -8,7 +8,6 @@ """ import os -import sys from ..pakbase import Package @@ -155,7 +154,7 @@ def __init__( unitnumber=None, filenames=None, label="LABEL", - **kwargs + **kwargs, ): """ @@ -315,11 +314,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "oc.htm" self.ihedfm = ihedfm @@ -397,15 +392,13 @@ def check(self, f=None, verbose=True, level=1, checktype=None): chk._add_to_summary( "Warning", package="OC", # value=kperkstp, - desc="action {!r} ignored; too few words".format( - action - ), + desc=f"action {action!r} ignored; too few words", ) elif words[0:2] not in expected_actions: chk._add_to_summary( "Warning", package="OC", # value=kperkstp, - desc="action {!r} ignored".format(action), + desc=f"action {action!r} ignored", ) # TODO: check data list of layers for some actions for kperkstp in keys: @@ -429,37 +422,31 @@ def write_file(self): """ f_oc = open(self.fn_path, "w") - f_oc.write("{}\n".format(self.heading)) + f_oc.write(f"{self.heading}\n") # write options - line = "HEAD PRINT FORMAT {0:3.0f}\n".format(self.ihedfm) + line = f"HEAD PRINT FORMAT {self.ihedfm:3.0f}\n" f_oc.write(line) if self.chedfm is not None: - line = "HEAD SAVE FORMAT {0:20s} {1}\n".format( - self.chedfm, self.label - ) + line = f"HEAD SAVE FORMAT {self.chedfm:20s} {self.label}\n" f_oc.write(line) if self.savehead: - line = "HEAD SAVE UNIT {0:5.0f}\n".format(self.iuhead) + line = f"HEAD SAVE UNIT {self.iuhead:5.0f}\n" f_oc.write(line) - f_oc.write("DRAWDOWN PRINT FORMAT {0:3.0f}\n".format(self.iddnfm)) + f_oc.write(f"DRAWDOWN PRINT FORMAT {self.iddnfm:3.0f}\n") if self.cddnfm is not None: - line = "DRAWDOWN SAVE FORMAT {0:20s} {1}\n".format( - self.cddnfm, self.label - ) + line = f"DRAWDOWN SAVE FORMAT {self.cddnfm:20s} {self.label}\n" f_oc.write(line) if self.saveddn: - line = "DRAWDOWN SAVE UNIT {0:5.0f}\n".format(self.iuddn) + line = f"DRAWDOWN SAVE UNIT {self.iuddn:5.0f}\n" f_oc.write(line) if self.saveibnd: if self.cboufm is not None: - line = "IBOUND SAVE FORMAT {0:20s} {1}\n".format( - self.cboufm, self.label - ) + line = f"IBOUND SAVE FORMAT {self.cboufm:20s} {self.label}\n" f_oc.write(line) - line = "IBOUND SAVE UNIT {0:5.0f}\n".format(self.iuibnd) + line = f"IBOUND SAVE UNIT {self.iuibnd:5.0f}\n" f_oc.write(line) if self.compact: @@ -495,13 +482,9 @@ def write_file(self): if "DDREFERENCE" in item.upper(): ddnref = item.lower() else: - lines += " {}\n".format(item) + lines += f" {item}\n" if len(lines) > 0: - f_oc.write( - "period {} step {} {}\n".format( - kper + 1, kstp + 1, ddnref - ) - ) + f_oc.write(f"period {kper + 1} step {kstp + 1} {ddnref}\n") f_oc.write(lines) f_oc.write("\n") ddnref = "" @@ -782,18 +765,17 @@ def load( """ if model.verbose: - sys.stdout.write("loading oc package file...\n") + print("loading oc package file...") # set nper if nper is None or nlay is None: nrow, ncol, nlay, nper = model.get_nrow_ncol_nlay_nper() if nper == 0 or nlay == 0: - msg = ( + raise ValueError( "discretization package not defined for the model, " - + "nper and nlay must be provided to the .load() method" + "nper and nlay must be provided to the .load() method" ) - raise ValueError(msg) # set nstp if nstp is None: @@ -801,11 +783,10 @@ def load( if dis is None: dis = model.get_package("DISU") if dis is None: - msg = ( + raise ValueError( "discretization package not defined for the model, " - + "a nstp list must be provided to the .load() method" + "a nstp list must be provided to the .load() method" ) - raise ValueError(msg) nstp = list(dis.nstp.array) else: if isinstance(nstp, (int, float)): @@ -813,10 +794,10 @@ def load( # validate the size of nstp if len(nstp) != nper: - msg = "nstp must be a list with {} entries, ".format( - nper - ) + "provided nstp list has {} entries.".format(len(nstp)) - raise IOError(msg) + raise OSError( + f"nstp must be a list with {nper} entries, " + f"provided nstp list has {len(nstp)} entries." + ) # initialize ihedfm = 0 @@ -909,21 +890,21 @@ def load( hdpr, ddpr = int(lnlst[0]), int(lnlst[1]) hdsv, ddsv = int(lnlst[2]), int(lnlst[3]) if hdpr != 0: - headprint += " {}".format(k + 1) + headprint += f" {k + 1}" if ddpr != 0: - ddnprint += " {}".format(k + 1) + ddnprint += f" {k + 1}" if hdsv != 0: - headsave += " {}".format(k + 1) + headsave += f" {k + 1}" if ddsv != 0: - ddnsave += " {}".format(k + 1) + ddnsave += f" {k + 1}" if len(headprint) > 0: - lines.append("PRINT HEAD" + headprint) + lines.append(f"PRINT HEAD{headprint}") if len(ddnprint) > 0: - lines.append("PRINT DRAWDOWN" + ddnprint) + lines.append(f"PRINT DRAWDOWN{ddnprint}") if len(headsave) > 0: - lines.append("SAVE HEAD" + headsave) + lines.append(f"SAVE HEAD{headsave}") if len(ddnsave) > 0: - lines.append("SAVE DRAWDOWN" + ddnsave) + lines.append(f"SAVE DRAWDOWN{ddnsave}") stress_period_data[(iperoc, itsoc)] = list(lines) else: iperoc, itsoc = 0, 0 @@ -1030,13 +1011,9 @@ def load( stress_period_data[kperkstp] = [] # dataset 3 elif "PRINT" in lnlst[0].upper(): - lines.append( - "{} {}".format(lnlst[0].lower(), lnlst[1].lower()) - ) + lines.append(f"{lnlst[0].lower()} {lnlst[1].lower()}") elif "SAVE" in lnlst[0].upper(): - lines.append( - "{} {}".format(lnlst[0].lower(), lnlst[1].lower()) - ) + lines.append(f"{lnlst[0].lower()} {lnlst[1].lower()}") else: print("Error encountered in OC import.") print("Creating default OC package.") diff --git a/dependencies/flopy/modflow/mfpar.py b/dependencies/flopy/modflow/mfpar.py index d8b93b6..b7e15e0 100644 --- a/dependencies/flopy/modflow/mfpar.py +++ b/dependencies/flopy/modflow/mfpar.py @@ -4,8 +4,6 @@ """ - -import sys import numpy as np from .mfzon import ModflowZon from .mfpval import ModflowPval @@ -76,17 +74,11 @@ def set_zone(self, model, ext_unit_dict): zone.filename, model, ext_unit_dict=ext_unit_dict ) if model.verbose: - sys.stdout.write( - " {} package load...success\n".format( - self.zone.name[0] - ) - ) + print(f" {self.zone.name[0]} package load...success") ext_unit_dict.pop(zone_key) model.remove_package("ZONE") except BaseException as o: - sys.stdout.write( - " {} package load...failed\n {!s}".format("ZONE", o) - ) + print(f" ZONE package load...failed\n {o!s}") return def set_mult(self, model, ext_unit_dict): @@ -127,17 +119,11 @@ def set_mult(self, model, ext_unit_dict): mult.filename, model, ext_unit_dict=ext_unit_dict ) if model.verbose: - sys.stdout.write( - " {} package load...success\n".format( - self.mult.name[0] - ) - ) + print(f" {self.mult.name[0]} package load...success") ext_unit_dict.pop(mult_key) model.remove_package("MULT") except BaseException as o: - sys.stdout.write( - " {} package load...failed\n {!s}".format("MULT", o) - ) + print(f" MULT package load...failed\n {o!s}") return @@ -179,17 +165,11 @@ def set_pval(self, model, ext_unit_dict): pval.filename, model, ext_unit_dict=ext_unit_dict ) if model.verbose: - sys.stdout.write( - " {} package load...success\n".format( - self.pval.name[0] - ) - ) + print(f" {self.pval.name[0]} package load...success") ext_unit_dict.pop(pval_key) model.remove_package("PVAL") except BaseException as o: - sys.stdout.write( - " {} package load...failed\n {!s}".format("PVAL", o) - ) + print(f" PVAL package load...failed\n {o!s}") return @@ -229,7 +209,7 @@ def load(f, npar, verbose=False): t = line.strip().split() parnam = t[0].lower() if verbose: - print(' loading parameter "{}"...'.format(parnam)) + print(f' loading parameter "{parnam}"...') partyp = t[1].lower() if partyp not in par_types: par_types.append(partyp) diff --git a/dependencies/flopy/modflow/mfparbc.py b/dependencies/flopy/modflow/mfparbc.py index f8f6657..87671f9 100644 --- a/dependencies/flopy/modflow/mfparbc.py +++ b/dependencies/flopy/modflow/mfparbc.py @@ -82,7 +82,7 @@ def load(cls, f, npar, dt, model, ext_unit_dict=None, verbose=False): if parnam.endswith("'"): parnam = parnam[:-1] if verbose: - print(' loading parameter "{}"...'.format(parnam)) + print(f' loading parameter "{parnam}"...') partyp = t[1].lower() parval = t[2] nlst = int(t[3]) @@ -153,7 +153,7 @@ def loadarray(f, npar, verbose=False): t = line.strip().split() parnam = t[0].lower() if verbose: - print(' loading parameter "{}"...'.format(parnam)) + print(f' loading parameter "{parnam}"...') partyp = t[1].lower() parval = t[2] nclu = int(t[3]) diff --git a/dependencies/flopy/modflow/mfpbc.py b/dependencies/flopy/modflow/mfpbc.py index a3fef51..b3c8d72 100644 --- a/dependencies/flopy/modflow/mfpbc.py +++ b/dependencies/flopy/modflow/mfpbc.py @@ -26,28 +26,22 @@ def __init__( Package.__init__( self, model, extension, ModflowPbc._ftype(), unitnumber ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.mxactp = 0 if layer_row_column_data is None: if layer_row_column_shead_ehead is not None: - msg = ( + print( "\nWARNING: ModflowPbc - Do not use " - + "layer_row_column_shead_ehead!\n" + "layer_row_column_shead_ehead!\n" + 22 * " " + "Use layer_row_column_data instead." ) - print(msg) layer_row_column_data = layer_row_column_shead_ehead else: - e = ( + raise Exception( "Failed to specify layer_row_column_shead_ehead " - + "or layer_row_column_data." + "or layer_row_column_data." ) - raise Exception(e) ( self.mxactp, @@ -109,18 +103,15 @@ def write_file(self): ctmp = c.shape[0] else: ctmp = -1 - f_pbc.write("{:10d}{:10d}{:10d}\n".format(itmp, ctmp, self.np)) + f_pbc.write(f"{itmp:10d}{ctmp:10d}{self.np:10d}\n") if n < len(self.layer_row_column_data): for b in a: - line = "{:10d}{:10d}{:10d}{:10d}{:10d}\n".format( - b[0], b[1], b[2], b[3], b[4] + f_pbc.write( + f"{b[0]:10d}{b[1]:10d}{b[2]:10d}{b[3]:10d}{b[4]:10d}\n" ) - f_pbc.write(line) if n < len(self.cosines): for d in c: - f_pbc.write( - "{:10g}{:10g}{:10g}\n".format(d[0], d[1], d[2]) - ) + f_pbc.write(f"{d[0]:10g}{d[1]:10g}{d[2]:10g}\n") f_pbc.close() @staticmethod diff --git a/dependencies/flopy/modflow/mfpcg.py b/dependencies/flopy/modflow/mfpcg.py index 7cee565..8658bd7 100644 --- a/dependencies/flopy/modflow/mfpcg.py +++ b/dependencies/flopy/modflow/mfpcg.py @@ -7,8 +7,6 @@ `_. """ -import sys - from ..pakbase import Package from ..utils.flopy_io import line_parse @@ -153,11 +151,7 @@ def __init__( ) raise Exception(err) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "pcg.htm" self.mxiter = mxiter self.iter1 = iter1 @@ -183,39 +177,39 @@ def write_file(self): """ f = open(self.fn_path, "w") - f.write("{}\n".format(self.heading)) + f.write(f"{self.heading}\n") ifrfm = self.parent.get_ifrefm() if ifrfm: - f.write("{} ".format(self.mxiter)) - f.write("{} ".format(self.iter1)) - f.write("{} ".format(self.npcond)) - f.write("{}".format(self.ihcofadd)) + f.write(f"{self.mxiter} ") + f.write(f"{self.iter1} ") + f.write(f"{self.npcond} ") + f.write(f"{self.ihcofadd}") f.write("\n") - f.write("{} ".format(self.hclose)) - f.write("{} ".format(self.rclose)) - f.write("{} ".format(self.relax)) - f.write("{} ".format(self.nbpol)) - f.write("{} ".format(self.iprpcg)) - f.write("{} ".format(self.mutpcg)) - f.write("{} ".format(self.damp)) + f.write(f"{self.hclose} ") + f.write(f"{self.rclose} ") + f.write(f"{self.relax} ") + f.write(f"{self.nbpol} ") + f.write(f"{self.iprpcg} ") + f.write(f"{self.mutpcg} ") + f.write(f"{self.damp} ") if self.damp < 0: - f.write("{}".format(self.dampt)) + f.write(f"{self.dampt}") f.write("\n") else: - f.write(" {0:9d}".format(self.mxiter)) - f.write(" {0:9d}".format(self.iter1)) - f.write(" {0:9d}".format(self.npcond)) - f.write(" {0:9d}".format(self.ihcofadd)) + f.write(f" {self.mxiter:9d}") + f.write(f" {self.iter1:9d}") + f.write(f" {self.npcond:9d}") + f.write(f" {self.ihcofadd:9d}") f.write("\n") - f.write(" {0:9.3e}".format(self.hclose)) - f.write(" {0:9.3e}".format(self.rclose)) - f.write(" {0:9.3e}".format(self.relax)) - f.write(" {0:9d}".format(self.nbpol)) - f.write(" {0:9d}".format(self.iprpcg)) - f.write(" {0:9d}".format(self.mutpcg)) - f.write(" {0:9.3e}".format(self.damp)) + f.write(f" {self.hclose:9.3e}") + f.write(f" {self.rclose:9.3e}") + f.write(f" {self.relax:9.3e}") + f.write(f" {self.nbpol:9d}") + f.write(f" {self.iprpcg:9d}") + f.write(f" {self.mutpcg:9d}") + f.write(f" {self.damp:9.3e}") if self.damp < 0: - f.write(" {0:9.3e}".format(self.dampt)) + f.write(f" {self.dampt:9.3e}") f.write("\n") f.close() @@ -252,7 +246,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading pcg package file...\n") + print("loading pcg package file...") openfile = not hasattr(f, "read") if openfile: diff --git a/dependencies/flopy/modflow/mfpcgn.py b/dependencies/flopy/modflow/mfpcgn.py index a1b23c7..4d32f44 100644 --- a/dependencies/flopy/modflow/mfpcgn.py +++ b/dependencies/flopy/modflow/mfpcgn.py @@ -7,8 +7,6 @@ `_. """ - -import sys from ..pakbase import Package @@ -279,16 +277,12 @@ def __init__( # check if a valid model version has been specified if model.version == "mfusg": - err = "Error: cannot use {} package ".format( - self.name - ) + "with model version {}".format(model.version) - raise Exception(err) - - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + raise Exception( + f"Error: cannot use {self.name} package " + f"with model version {model.version}" + ) + + self._generate_heading() self.url = "pcgn.htm" self.iter_mo = iter_mo self.iter_mi = iter_mi @@ -310,11 +304,10 @@ def __init__( self.ipunit = ipunit # error trapping if self.ifill < 0 or self.ifill > 1: - e = ( + raise TypeError( "PCGN: ifill must be 0 or 1 - an ifill value of " - + "{} was specified".format(self.ifill) + "{} was specified".format(self.ifill) ) - raise TypeError(e) # add package self.parent.add_package(self) @@ -329,38 +322,38 @@ def write_file(self): """ # Open file for writing f = open(self.fn_path, "w") - f.write("{0:s}\n".format(self.heading)) + f.write(f"{self.heading}\n") ifrfm = self.parent.get_ifrefm() if ifrfm: # dataset 1 - line = "{} ".format(self.iter_mo) - line += "{} ".format(self.iter_mi) - line += "{} ".format(self.close_r) - line += "{}\n".format(self.close_h) + line = f"{self.iter_mo} " + line += f"{self.iter_mi} " + line += f"{self.close_r} " + line += f"{self.close_h}\n" f.write(line) # dataset 2 - line = "{} ".format(self.relax) - line += "{} ".format(self.ifill) - line += "{} ".format(self.unit_pc) - line += "{}\n".format(self.unit_ts) + line = f"{self.relax} " + line += f"{self.ifill} " + line += f"{self.unit_pc} " + line += f"{self.unit_ts}\n" f.write(line) # dataset 3 - line = "{} ".format(self.adamp) - line += "{} ".format(self.damp) - line += "{} ".format(self.damp_lb) - line += "{} ".format(self.rate_d) - line += "{}\n".format(self.chglimit) + line = f"{self.adamp} " + line += f"{self.damp} " + line += f"{self.damp_lb} " + line += f"{self.rate_d} " + line += f"{self.chglimit}\n" f.write(line) # dataset 4 - line = "{} ".format(self.acnvg) - line += "{} ".format(self.cnvg_lb) - line += "{} ".format(self.mcnvg) - line += "{} ".format(self.rate_c) - line += "{}\n".format(self.ipunit) + line = f"{self.acnvg} " + line += f"{self.cnvg_lb} " + line += f"{self.mcnvg} " + line += f"{self.rate_c} " + line += f"{self.ipunit}\n" f.write(line) else: @@ -426,7 +419,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading pcgn package file...\n") + print("loading pcgn package file...") openfile = not hasattr(f, "read") if openfile: diff --git a/dependencies/flopy/modflow/mfpks.py b/dependencies/flopy/modflow/mfpks.py index d0c4310..8e31467 100644 --- a/dependencies/flopy/modflow/mfpks.py +++ b/dependencies/flopy/modflow/mfpks.py @@ -3,7 +3,6 @@ the ModflowPks class as `flopy.modflow.ModflowPks`. """ -import sys from ..pakbase import Package @@ -143,11 +142,7 @@ def __init__( ) raise Exception(err) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "pks.htm" self.mxiter = mxiter self.innerit = innerit @@ -188,39 +183,39 @@ def write_file(self): """ # Open file for writing f = open(self.fn_path, "w") - f.write("%s\n" % self.heading) - f.write("MXITER {0}\n".format(self.mxiter)) - f.write("INNERIT {0}\n".format(self.innerit)) - f.write("ISOLVER {0}\n".format(self.isolver)) - f.write("NPC {0}\n".format(self.npc)) - f.write("ISCL {0}\n".format(self.iscl)) - f.write("IORD {0}\n".format(self.iord)) + f.write(f"{self.heading}\n") + f.write(f"MXITER {self.mxiter}\n") + f.write(f"INNERIT {self.innerit}\n") + f.write(f"ISOLVER {self.isolver}\n") + f.write(f"NPC {self.npc}\n") + f.write(f"ISCL {self.iscl}\n") + f.write(f"IORD {self.iord}\n") if self.ncoresm > 1: - f.write("NCORESM {0}\n".format(self.ncoresm)) + f.write(f"NCORESM {self.ncoresm}\n") if self.ncoresv > 1: - f.write("NCORESV {0}\n".format(self.ncoresv)) - f.write("DAMP {0}\n".format(self.damp)) - f.write("DAMPT {0}\n".format(self.dampt)) + f.write(f"NCORESV {self.ncoresv}\n") + f.write(f"DAMP {self.damp}\n") + f.write(f"DAMPT {self.dampt}\n") if self.npc > 0: - f.write("RELAX {0}\n".format(self.relax)) + f.write(f"RELAX {self.relax}\n") if self.npc == 3: - f.write("IFILL {0}\n".format(self.ifill)) - f.write("DROPTOL {0}\n".format(self.droptol)) - f.write("HCLOSEPKS {0}\n".format(self.hclose)) - f.write("RCLOSEPKS {0}\n".format(self.rclose)) + f.write(f"IFILL {self.ifill}\n") + f.write(f"DROPTOL {self.droptol}\n") + f.write(f"HCLOSEPKS {self.hclose}\n") + f.write(f"RCLOSEPKS {self.rclose}\n") if self.l2norm != None: if self.l2norm.lower() == "l2norm" or self.l2norm == "1": f.write("L2NORM\n") elif self.l2norm.lower() == "rl2norm" or self.l2norm == "2": f.write("RELATIVE-L2NORM\n") - f.write("IPRPKS {0}\n".format(self.iprpks)) - f.write("MUTPKS {0}\n".format(self.mutpks)) + f.write(f"IPRPKS {self.iprpks}\n") + f.write(f"MUTPKS {self.mutpks}\n") # MPI if self.mpi: - f.write("PARTOPT {0}\n".format(self.partopt)) - f.write("NOVLAPIMPSOL {0}\n".format(self.novlapimpsol)) - f.write("STENIMPSOL {0}\n".format(self.stenimpsol)) - f.write("VERBOSE {0}\n".format(self.verbose)) + f.write(f"PARTOPT {self.partopt}\n") + f.write(f"NOVLAPIMPSOL {self.novlapimpsol}\n") + f.write(f"STENIMPSOL {self.stenimpsol}\n") + f.write(f"VERBOSE {self.verbose}\n") if self.partopt == 1 | 2: pass # to be implemented @@ -261,7 +256,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading pks package file...\n") + print("loading pks package file...") openfile = not hasattr(f, "read") if openfile: @@ -270,11 +265,10 @@ def load(cls, f, model, ext_unit_dict=None): # dataset 0 -- header - msg = ( - 3 * " " - + "Warning: load method not completed. default pks object created." + print( + " Warning: " + "load method not completed. default pks object created." ) - print(msg) if openfile: f.close() diff --git a/dependencies/flopy/modflow/mfpval.py b/dependencies/flopy/modflow/mfpval.py index 6dfd13d..88c7412 100644 --- a/dependencies/flopy/modflow/mfpval.py +++ b/dependencies/flopy/modflow/mfpval.py @@ -7,7 +7,6 @@ `_. """ -import sys from ..pakbase import Package @@ -100,11 +99,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "parameter_value_file.htm" self.npval = 0 @@ -172,7 +167,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading pval package file...\n") + print("loading pval package file...") openfile = not hasattr(f, "read") if openfile: @@ -191,9 +186,7 @@ def load(cls, f, model, ext_unit_dict=None): npval = int(t[0]) if model.verbose: - sys.stdout.write( - ' reading parameter values from "{:<10s}"\n'.format(filename) - ) + print(f' reading parameter values from "{filename}"') # read PVAL data pval_dict = dict() diff --git a/dependencies/flopy/modflow/mfrch.py b/dependencies/flopy/modflow/mfrch.py index ace67a5..2fc1540 100644 --- a/dependencies/flopy/modflow/mfrch.py +++ b/dependencies/flopy/modflow/mfrch.py @@ -7,8 +7,6 @@ `_. """ - -import sys import numpy as np from ..pakbase import Package from ..utils import Util2d, Transient2d @@ -149,11 +147,7 @@ def __init__( ) nrow, ncol, nlay, nper = self.parent.nrow_ncol_nlay_nper - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "rch.htm" self.nrchop = nrchop @@ -271,32 +265,31 @@ def check( if len(lessthan) > 0: txt = ( - "\r Mean R/T ratio < checker warning " - + "threshold of {}".format(RTmin) + "\r Mean R/T ratio < checker warning threshold of " + "{} for {} stress periods".format(RTmin, len(lessthan)) ) - txt += " for {} stress periods".format(len(lessthan)) chk._add_to_summary( type="Warning", value=R_T.min(), desc=txt ) chk.remove_passed( - "Mean R/T is between {} and {}".format(RTmin, RTmax) + f"Mean R/T is between {RTmin} and {RTmax}" ) if len(greaterthan) > 0: txt = ( "\r Mean R/T ratio > checker warning " - + "threshold of {}".format(RTmax) + "threshold of {} for " + "{} stress periods".format(RTmax, len(greaterthan)) ) - txt += " for {} stress periods".format(len(greaterthan)) chk._add_to_summary( type="Warning", value=R_T.max(), desc=txt ) chk.remove_passed( - "Mean R/T is between {} and {}".format(RTmin, RTmax) + f"Mean R/T is between {RTmin} and {RTmax}" ) elif len(lessthan) == 0 and len(greaterthan) == 0: chk.append_passed( - "Mean R/T is between {} and {}".format(RTmin, RTmax) + f"Mean R/T is between {RTmin} and {RTmax}" ) # check for NRCHOP values != 3 @@ -339,7 +332,7 @@ def write_file(self, check=True, f=None): # allows turning off package checks when writing files at model level if check: self.check( - f="{}.chk".format(self.name[0]), + f=f"{self.name[0]}.chk", verbose=self.parent.verbose, level=1, ) @@ -349,8 +342,8 @@ def write_file(self, check=True, f=None): f_rch = f else: f_rch = open(self.fn_path, "w") - f_rch.write("{0:s}\n".format(self.heading)) - f_rch.write("{0:10d}{1:10d}\n".format(self.nrchop, self.ipakcb)) + f_rch.write(f"{self.heading}\n") + f_rch.write(f"{self.nrchop:10d}{self.ipakcb:10d}\n") if self.nrchop == 2: irch = {} @@ -370,7 +363,7 @@ def write_file(self, check=True, f=None): for kper, u2d in self.irch.transient_2ds.items() ] ) - f_rch.write("{0:10d}\n".format(mxndrch)) + f_rch.write(f"{mxndrch:10d}\n") for kper in range(nper): inrech, file_entry_rech = self.rech.get_kper_entry(kper) @@ -381,9 +374,7 @@ def write_file(self, check=True, f=None): else: inirch = -1 f_rch.write( - "{0:10d}{1:10d} # {2:s}\n".format( - inrech, inirch, "Stress period " + str(kper + 1) - ) + f"{inrech:10d}{inirch:10d} # Stress period {kper + 1}\n" ) if inrech >= 0: f_rch.write(file_entry_rech) @@ -430,7 +421,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None, check=True): """ if model.verbose: - sys.stdout.write("loading rch package file...\n") + print("loading rch package file...") openfile = not hasattr(f, "read") if openfile: @@ -448,12 +439,9 @@ def load(cls, f, model, nper=None, ext_unit_dict=None, check=True): npar = int(raw[1]) if npar > 0: if model.verbose: - txt = ( - 3 * " " - + "Parameters detected. Number of " - + "parameters = {}".format(npar) + print( + f" Parameters detected. Number of parameters = {npar}" ) - print(txt) line = f.readline() # dataset 2 t = line_parse(line) @@ -501,12 +489,9 @@ def load(cls, f, model, nper=None, ext_unit_dict=None, check=True): if inrech >= 0: if npar == 0: if model.verbose: - txt = ( - 3 * " " - + "loading rech stress " - + "period {0:3d}...".format(iper + 1) + print( + f" loading rech stress period {iper + 1:3d}..." ) - print(txt) t = Util2d.load( f, model, @@ -540,12 +525,9 @@ def load(cls, f, model, nper=None, ext_unit_dict=None, check=True): if nrchop == 2: if inirch >= 0: if model.verbose: - txt = ( - 3 * " " - + "loading irch stress " - + "period {0:3d}...".format(iper + 1) + print( + f" loading irch stress period {iper + 1:3d}..." ) - print(txt) t = Util2d.load( f, model, u2d_shape, np.int32, "irch", ext_unit_dict ) @@ -582,7 +564,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None, check=True): ) if check: rch.check( - f="{}.chk".format(rch.name[0]), + f=f"{rch.name[0]}.chk", verbose=rch.parent.verbose, level=0, ) diff --git a/dependencies/flopy/modflow/mfriv.py b/dependencies/flopy/modflow/mfriv.py index 263d121..99f6101 100644 --- a/dependencies/flopy/modflow/mfriv.py +++ b/dependencies/flopy/modflow/mfriv.py @@ -7,7 +7,6 @@ `_. """ -import sys import numpy as np from ..pakbase import Package from ..utils import MfList @@ -123,7 +122,7 @@ def __init__( options=None, unitnumber=None, filenames=None, - **kwargs + **kwargs, ): """ Package constructor. @@ -171,11 +170,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "riv.htm" self.ipakcb = ipakcb @@ -238,10 +233,13 @@ def check(self, f=None, verbose=True, level=1, checktype=None): # check that river stage and bottom are above model cell # bottoms also checks for nan values - botms = self.parent.dis.botm.array[inds] + if self.parent.structured: + botms = self.parent.dis.botm.array[inds] + else: + botms = self.parent.disu.bot.array[inds] for elev in ["stage", "rbot"]: - txt = "{} below cell bottom".format(elev) + txt = f"{elev} below cell bottom" chk.stress_period_data_values( spd, spd[elev] < botms, @@ -328,15 +326,13 @@ def write_file(self, check=True): # allows turning off package checks when writing files at model level if check: self.check( - f="{}.chk".format(self.name[0]), + f=f"{self.name[0]}.chk", verbose=self.parent.verbose, level=1, ) f_riv = open(self.fn_path, "w") - f_riv.write("{0}\n".format(self.heading)) - line = "{0:10d}{1:10d}".format( - self.stress_period_data.mxact, self.ipakcb - ) + f_riv.write(f"{self.heading}\n") + line = f"{self.stress_period_data.mxact:10d}{self.ipakcb:10d}" for opt in self.options: line += " " + str(opt) line += "\n" @@ -348,7 +344,7 @@ def add_record(self, kper, index, values): try: self.stress_period_data.add_record(kper, index, values) except Exception as e: - raise Exception("mfriv error adding record to list: " + str(e)) + raise Exception(f"mfriv error adding record to list: {e!s}") @classmethod def load(cls, f, model, nper=None, ext_unit_dict=None, check=True): @@ -389,7 +385,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None, check=True): """ if model.verbose: - sys.stdout.write("loading riv package file...\n") + print("loading riv package file...") return Package.load( f, diff --git a/dependencies/flopy/modflow/mfsfr2.py b/dependencies/flopy/modflow/mfsfr2.py index 3e93fbd..485ef85 100644 --- a/dependencies/flopy/modflow/mfsfr2.py +++ b/dependencies/flopy/modflow/mfsfr2.py @@ -1,6 +1,5 @@ __author__ = "aleaf" -import sys import os import numpy as np import warnings @@ -11,26 +10,12 @@ from ..utils.flopy_io import line_parse from ..utils.recarray_utils import create_empty_recarray from ..utils.optionblock import OptionBlock -from collections import OrderedDict try: import pandas as pd except: pd = False -try: - from numpy.lib import NumpyVersion - - numpy114 = NumpyVersion(np.__version__) >= "1.14.0" -except ImportError: - numpy114 = False -if numpy114: - # use numpy's floating-point formatter (Dragon4) - default_float_format = "{!s}" -else: - # single-precision floats have ~7.2 decimal digits - default_float_format = "{:.8g}" - class ModflowSfr2(Package): """ @@ -281,7 +266,7 @@ class ModflowSfr2(Package): """ - _options = OrderedDict( + _options = dict( [ ("reachinput", OptionBlock.simple_flag), ("transroute", OptionBlock.simple_flag), @@ -317,9 +302,6 @@ class ModflowSfr2(Package): ) nsfrpar = 0 - heading = ( - "# Streamflow-Routing (SFR2) file for MODFLOW, generated by Flopy" - ) default_value = 0.0 # LENUNI = {"u": 0, "f": 1, "m": 2, "c": 3} len_const = {1: 1.486, 2: 1.0, 3: 100.0} @@ -398,7 +380,7 @@ def __init__( ext = "bin" fname = filenames[2] if fname is None: - fname = model.name + ".sfr.{}".format(ext) + fname = f"{model.name}.sfr.{ext}" model.add_output_file( abs(istcb2), fname=fname, @@ -431,11 +413,7 @@ def __init__( self._graph = None # dict of routing connections # Dataset 0 - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() # Dataset 1a and 1b self.reachinput = reachinput @@ -838,7 +816,7 @@ def get_default_segment_dtype(): def load(cls, f, model, nper=None, gwt=False, nsol=1, ext_unit_dict=None): if model.verbose: - sys.stdout.write("loading sfr2 package file...\n") + print("loading sfr2 package file...") tabfiles = False tabfiles_dict = {} @@ -1144,7 +1122,7 @@ def check(self, f=None, verbose=True, level=1, checktype=None): if isinstance(f, str): pth = os.path.join(self.parent.model_ws, f) f = open(pth, "w") - f.write("{}\n".format(chk.txt)) + f.write(f"{chk.txt}\n") # f.close() return chk @@ -1491,7 +1469,7 @@ def get_variable_by_stress_period(self, varname): for per in range(self.nper): inds = self.segment_data[per].nseg - 1 all_data[inds, per] = self.segment_data[per][varname] - dtype.append(("{}{}".format(varname, per), float)) + dtype.append((f"{varname}{per}", float)) isvar = all_data.sum(axis=1) != 0 ra = np.core.records.fromarrays( all_data[isvar].transpose().copy(), dtype=dtype @@ -1627,11 +1605,9 @@ def plot_path(self, start_seg=None, end_seg=0, plot_segment_lines=True): try: import matplotlib.pyplot as plt except: - err_msg = ( - "matplotlib must be installed to use " - + "ModflowSfr2.plot_path()" + raise ImportError( + "matplotlib must be installed to use ModflowSfr2.plot_path()" ) - raise ImportError(err_msg) if not pd: err_msg = "ModflowSfr2.plot_path: pandas not available" raise ImportError(err_msg) @@ -1662,7 +1638,7 @@ def plot_path(self, start_seg=None, end_seg=0, plot_segment_lines=True): ax.plot(dist, tops, label="Model top") ax.plot(dist, tmp.strtop, label="Streambed top") ax.set_xlabel("Distance along path, in miles") - ax.set_ylabel("Elevation, in {}".format(mfunits)) + ax.set_ylabel(f"Elevation, in {mfunits}") ymin, ymax = ax.get_ylim() plt.autoscale(False) @@ -1685,7 +1661,7 @@ def plot_path(self, start_seg=None, end_seg=0, plot_segment_lines=True): xlocs = dist[inds] pad = 0.04 * (ymax - ymin) for x, sn in zip(xlocs, plot_segnumbers): - ax.text(x, ymin + pad, "{}".format(sn), va="top") + ax.text(x, ymin + pad, str(sn), va="top") ax.text( xlocs[0], ymin + pad * 1.2, @@ -1693,9 +1669,7 @@ def plot_path(self, start_seg=None, end_seg=0, plot_segment_lines=True): va="bottom", fontweight="bold", ) - ax.text( - dist[-1], ymin + pad, "{}".format(end_seg), ha="center", va="top" - ) + ax.text(dist[-1], ymin + pad, str(end_seg), ha="center", va="top") return ax def _get_headwaters(self, per=0): @@ -1806,37 +1780,31 @@ def _write_1c(self, f_sfr): self.nstrm = abs( self.nstrm ) # see explanation for dataset 1c in online guide - f_sfr.write("{:.0f} ".format(self.isfropt)) + f_sfr.write(f"{self.isfropt:.0f} ") if self.isfropt > 1: f_sfr.write( - "{:.0f} {:.0f} {:.0f} ".format( - self.nstrail, self.isuzn, self.nsfrsets - ) + f"{self.nstrail:.0f} {self.isuzn:.0f} {self.nsfrsets:.0f} " ) if self.nstrm < 0: - f_sfr.write("{:.0f} ".format(self.isfropt)) + f_sfr.write(f"{self.isfropt:.0f} ") if self.isfropt > 1: f_sfr.write( - "{:.0f} {:.0f} {:.0f} ".format( - self.nstrail, self.isuzn, self.nsfrsets - ) + f"{self.nstrail:.0f} {self.isuzn:.0f} {self.nsfrsets:.0f} " ) if self.nstrm < 0 or self.transroute: - f_sfr.write("{:.0f} ".format(self.irtflg)) + f_sfr.write(f"{self.irtflg:.0f} ") if self.irtflg > 0: f_sfr.write( - "{:.0f} {:.8f} {:.8f} ".format( - self.numtim, self.weight, self.flwtol - ) + f"{self.numtim:.0f} {self.weight:.8f} {self.flwtol:.8f} " ) f_sfr.write("\n") def _write_reach_data(self, f_sfr): # Write the recarray (data) to the file (or file handle) f - assert isinstance(self.reach_data, np.recarray), ( - "MfList.__tofile() data arg " + "not a recarray" - ) + assert isinstance( + self.reach_data, np.recarray + ), "MfList.__tofile() data arg not a recarray" # decide which columns to write # columns = self._get_item2_names() @@ -2053,7 +2021,7 @@ def write_file(self, filename=None): f_sfr = open(self.fn_path, "w") # Item 0 -- header - f_sfr.write("{0}\n".format(self.heading)) + f_sfr.write(f"{self.heading}\n") # Item 1 if ( @@ -2103,14 +2071,14 @@ def write_file(self, filename=None): for d in self.channel_geometry_data[i][nseg][ k ]: - f_sfr.write("{:.2f} ".format(d)) + f_sfr.write(f"{d:.2f} ") f_sfr.write("\n") if icalc == 4: # nstrpts = self.segment_data[i][j][5] for k in range(3): for d in self.channel_flow_data[i][nseg][k]: - f_sfr.write("{:.2f} ".format(d)) + f_sfr.write(f"{d:.2f} ") f_sfr.write("\n") if self.tabfiles and i == 0: for j in sorted(self.tabfiles_dict.keys()): @@ -2294,7 +2262,7 @@ def __init__(self, sfrpackage, verbose=True, level=1): self.passed = [] self.warnings = [] self.errors = [] - self.txt = "\n{} ERRORS:\n".format(self.sfr.name[0]) + self.txt = f"\n{self.sfr.name[0]} ERRORS:\n" self.summary_array = None def _boolean_compare( @@ -2418,15 +2386,15 @@ def for_nans(self): isnan = np.any(np.isnan(np.array(self.reach_data.tolist())), axis=1) nanreaches = self.reach_data[isnan] if np.any(isnan): - txt += "Found {} reachs with nans:\n".format(len(nanreaches)) + txt += f"Found {len(nanreaches)} reachs with nans:\n" if self.level == 1: txt += _print_rec_array(nanreaches, delimiter=" ") for per, sd in self.segment_data.items(): isnan = np.any(np.isnan(np.array(sd.tolist())), axis=1) nansd = sd[isnan] if np.any(isnan): - txt += "Per {}: found {} segments with nans:\n".format( - per, len(nanreaches) + txt += ( + f"Per {per}: found {len(nanreaches)} segments with nans:\n" ) if self.level == 1: txt += _print_rec_array(nansd, delimiter=" ") @@ -2463,7 +2431,7 @@ def numbering(self): len(reaches), reaches, level=self.level, datatype="reach" ) if len(t) > 0: - txt += "Segment {} has {}".format(segment, t) + txt += f"Segment {segment} has {t}" if txt == "": passed = True self._txt_footer( @@ -2493,7 +2461,7 @@ def numbering(self): txt += "nseg outseg\n" t = "" for nseg, outseg in decreases: - t += "{} {}\n".format(nseg, outseg) + t += f"{nseg} {outseg}\n" txt += t # '\n'.join(textwrap.wrap(t, width=10)) if len(t) == 0: passed = True @@ -2526,7 +2494,7 @@ def routing(self): np.savetxt( f, circular_segs, fmt="%d", delimiter=",", header=txt ) - txt += "See {} for details.".format(f) + txt += f"See {f} for details." if self.verbose: print(txt) self._txt_footer(headertxt, txt, "circular routing", warning=False) @@ -2575,8 +2543,8 @@ def routing(self): segments_with_breaks = set(breaks_reach_data.iseg) if len(breaks) > 0: txt += ( - "{0} segments ".format(len(segments_with_breaks)) - + "with non-adjacent reaches found.\n" + f"{len(segments_with_breaks)} segments " + "with non-adjacent reaches found.\n" ) if self.level == 1: txt += "At segments:\n" @@ -2589,7 +2557,7 @@ def routing(self): with open(fpath, "w") as fp: fp.write(",".join(rd.dtype.names) + "\n") np.savetxt(fp, rd, "%s", ",") - txt += "See {} for details.".format(fpath) + txt += f"See {fpath} for details." if self.verbose: print(txt) self._txt_footer( @@ -2598,7 +2566,7 @@ def routing(self): else: txt += ( "No DIS package or SpatialReference object; cannot " - + "check reach proximities." + "check reach proximities." ) self._txt_footer(headertxt, txt, "") @@ -2610,7 +2578,7 @@ def overlapping_conductance(self, tol=1e-6): """ headertxt = ( "Checking for model cells with multiple non-zero " - + "SFR conductances...\n" + "SFR conductances...\n" ) txt = "" if self.verbose: @@ -2662,10 +2630,9 @@ def overlapping_conductance(self, tol=1e-6): if len(nodes_with_multiple_conductance) > 0: txt += ( - "{} model cells with multiple non-zero SFR conductances found.\n" - "This may lead to circular routing between collocated reaches.\n".format( - len(nodes_with_multiple_conductance) - ) + f"{len(nodes_with_multiple_conductance)} model cells with " + "multiple non-zero SFR conductances found.\n" + "This may lead to circular routing between collocated reaches.\n" ) if self.level == 1: txt += "Nodes with overlapping conductances:\n" @@ -2717,8 +2684,7 @@ def elevations(self, min_strtop=-10, max_strtop=15000): """ headertxt = ( - "Checking for streambed tops of less " - + "than {}...\n".format(min_strtop) + f"Checking for streambed tops of less than {min_strtop}...\n" ) txt = "" if self.verbose: @@ -2741,15 +2707,12 @@ def elevations(self, min_strtop=-10, max_strtop=15000): if len(txt) == 0: passed = True else: - txt += "strtop not specified for isfropt={}\n".format( - self.sfr.isfropt - ) + txt += f"strtop not specified for isfropt={self.sfr.isfropt}\n" passed = True self._txt_footer(headertxt, txt, "minimum streambed top", passed) headertxt = ( - "Checking for streambed tops of " - + "greater than {}...\n".format(max_strtop) + f"Checking for streambed tops of greater than {max_strtop}...\n" ) txt = "" if self.verbose: @@ -2760,15 +2723,15 @@ def elevations(self, min_strtop=-10, max_strtop=15000): if np.diff(self.reach_data.strtop).max() == 0: txt += ( "isfropt setting of 1,2 or 3 " - + "requires strtop information!\n" + "requires strtop information!\n" ) else: is_greater = self.reach_data.strtop > max_strtop if np.any(is_greater): above_max = self.reach_data[is_greater] txt += ( - "{} instances ".format(len(above_max)) - + "of streambed top above the maximum found.\n" + f"{len(above_max)} instances " + "of streambed top above the maximum found.\n" ) if self.level == 1: txt += "Reaches with high strtop:\n" @@ -2776,15 +2739,13 @@ def elevations(self, min_strtop=-10, max_strtop=15000): if len(txt) == 0: passed = True else: - txt += "strtop not specified for isfropt={}\n".format( - self.sfr.isfropt - ) + txt += f"strtop not specified for isfropt={self.sfr.isfropt}\n" passed = True self._txt_footer(headertxt, txt, "maximum streambed top", passed) headertxt = ( "Checking segment_data for " - + "downstream rises in streambed elevation...\n" + "downstream rises in streambed elevation...\n" ) txt = "" if self.verbose: @@ -2811,7 +2772,7 @@ def elevations(self, min_strtop=-10, max_strtop=15000): if len(t) > 0: txt += ( "Elevation check requires " - + "consecutive segment numbering." + "consecutive segment numbering." ) self._txt_footer(headertxt, txt, "") return @@ -2827,7 +2788,7 @@ def elevations(self, min_strtop=-10, max_strtop=15000): ], col1="d_elev", col2=np.zeros(len(segment_data)), - level0txt="Stress Period {}: ".format(per + 1) + level0txt=f"Stress Period {per + 1}: " + "{} segments encountered with elevdn > elevup.", level1txt="Backwards segments:", ) @@ -2865,7 +2826,7 @@ def elevations(self, min_strtop=-10, max_strtop=15000): ], col1="d_elev2", col2=np.zeros(len(non_outlets_seg_data)), - level0txt="Stress Period {}: ".format(per + 1) + level0txt=f"Stress Period {per + 1}: " + "{} segments encountered with segments encountered " "with outseg elevup > elevdn.", level1txt="Backwards segment connections:", @@ -2875,18 +2836,15 @@ def elevations(self, min_strtop=-10, max_strtop=15000): passed = True else: txt += ( - "Segment elevup and elevdn not " - + "specified for nstrm=" - + "{} and isfropt={}\n".format( - self.sfr.nstrm, self.sfr.isfropt - ) + "Segment elevup and elevdn not specified for nstrm={} " + "and isfropt={}\n".format(self.sfr.nstrm, self.sfr.isfropt) ) passed = True self._txt_footer(headertxt, txt, "segment elevations", passed) headertxt = ( "Checking reach_data for " - + "downstream rises in streambed elevation...\n" + "downstream rises in streambed elevation...\n" ) txt = "" if self.verbose: @@ -3067,7 +3025,7 @@ def elevations(self, min_strtop=-10, max_strtop=15000): headertxt = ( "Checking segment_data for inconsistencies " - + "between segment end elevations and the model grid...\n" + "between segment end elevations and the model grid...\n" ) txt = "" if self.verbose: @@ -3151,9 +3109,7 @@ def slope(self, minimum_slope=1e-4, maximum_slope=1.0): where stage is computed. """ headertxt = ( - "Checking for streambed slopes of less than {}...\n".format( - minimum_slope - ) + f"Checking for streambed slopes of less than {minimum_slope}...\n" ) txt = "" if self.verbose: @@ -3178,17 +3134,11 @@ def slope(self, minimum_slope=1e-4, maximum_slope=1.0): if len(txt) == 0: passed = True else: - txt += "slope not specified for isfropt={}\n".format( - self.sfr.isfropt - ) + txt += f"slope not specified for isfropt={self.sfr.isfropt}\n" passed = True self._txt_footer(headertxt, txt, "minimum slope", passed) - headertxt = ( - "Checking for streambed slopes of greater than {}...\n".format( - maximum_slope - ) - ) + headertxt = f"Checking for streambed slopes of greater than {maximum_slope}...\n" txt = "" if self.verbose: print(headertxt.strip()) @@ -3213,9 +3163,7 @@ def slope(self, minimum_slope=1e-4, maximum_slope=1.0): if len(txt) == 0: passed = True else: - txt += "slope not specified for isfropt={}\n".format( - self.sfr.isfropt - ) + txt += f"slope not specified for isfropt={self.sfr.isfropt}\n" passed = True self._txt_footer(headertxt, txt, "maximum slope", passed) @@ -3241,14 +3189,14 @@ def _check_numbers(n, numbers, level=1, datatype="reach"): txt = "" num_range = np.arange(1, n + 1) if not np.array_equal(num_range, numbers): - txt += "Invalid {} numbering\n".format(datatype) + txt += f"Invalid {datatype} numbering\n" if level == 1: # consistent dimension for boolean array non_consecutive = np.append(np.diff(numbers) != 1, False) gaps = num_range[non_consecutive] + 1 if len(gaps) > 0: gapstr = " ".join(map(str, gaps)) - txt += "Gaps in numbering at positions {}\n".format(gapstr) + txt += f"Gaps in numbering at positions {gapstr}\n" return txt @@ -3340,7 +3288,7 @@ def _get_item2_names(nstrm, reachinput, isfropt, structured=False): return names -def _fmt_string_list(array, float_format=default_float_format): +def _fmt_string_list(array, float_format="{!s}"): fmt_list = [] for name in array.dtype.names: vtype = array.dtype[name].str[1].lower() @@ -3359,19 +3307,15 @@ def _fmt_string_list(array, float_format=default_float_format): "recarray to file - change to 'object' type".format(name) ) else: - raise ValueError( - "unknown dtype for {!r}: {!r}".format(name, vtype) - ) + raise ValueError(f"unknown dtype for {name!r}: {vtype!r}") return fmt_list -def _fmt_string(array, float_format=default_float_format): +def _fmt_string(array, float_format="{!s}"): return " ".join(_fmt_string_list(array, float_format)) -def _print_rec_array( - array, cols=None, delimiter=" ", float_format=default_float_format -): +def _print_rec_array(array, cols=None, delimiter=" ", float_format="{!s}"): """ Print out a numpy record array to string, with column names. diff --git a/dependencies/flopy/modflow/mfsip.py b/dependencies/flopy/modflow/mfsip.py index 92e1111..98db739 100644 --- a/dependencies/flopy/modflow/mfsip.py +++ b/dependencies/flopy/modflow/mfsip.py @@ -7,9 +7,6 @@ `_. """ - -import sys - from ..pakbase import Package @@ -132,16 +129,12 @@ def __init__( # check if a valid model version has been specified if model.version == "mfusg": - err = "Error: cannot use {} package ".format( - self.name - ) + "with model version {}".format(model.version) - raise Exception(err) - - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + raise Exception( + f"Error: cannot use {self.name} package " + f"with model version {model.version}" + ) + + self._generate_heading() self.url = "sip.htm" self.mxiter = mxiter @@ -164,21 +157,15 @@ def write_file(self): """ # Open file for writing f = open(self.fn_path, "w") - f.write("{}\n".format(self.heading)) + f.write(f"{self.heading}\n") ifrfm = self.parent.get_ifrefm() if ifrfm: - f.write("{} {}\n".format(self.mxiter, self.nparm)) + f.write(f"{self.mxiter} {self.nparm}\n") f.write( - "{} {} {} {} {}\n".format( - self.accl, - self.hclose, - self.ipcalc, - self.wseed, - self.iprsip, - ) + f"{self.accl} {self.hclose} {self.ipcalc} {self.wseed} {self.iprsip}\n" ) else: - f.write("{:10d}{:10d}\n".format(self.mxiter, self.nparm)) + f.write(f"{self.mxiter:10d}{self.nparm:10d}\n") f.write( "{:10.3f}{:10.3g}{:10d}{:10.3f}{:10d}\n".format( self.accl, @@ -223,7 +210,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading sip package file...\n") + print("loading sip package file...") openfile = not hasattr(f, "read") if openfile: diff --git a/dependencies/flopy/modflow/mfsms.py b/dependencies/flopy/modflow/mfsms.py index 3a183ae..090931e 100644 --- a/dependencies/flopy/modflow/mfsms.py +++ b/dependencies/flopy/modflow/mfsms.py @@ -5,9 +5,6 @@ """ - -import sys - from ..pakbase import Package from ..utils.flopy_io import line_parse @@ -303,11 +300,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = " " self.hclose = hclose self.hiclose = hiclose @@ -357,7 +350,7 @@ def write_file(self): """ f = open(self.fn_path, "w") - f.write("{}\n".format(self.heading)) + f.write(f"{self.heading}\n") nopt = len(self.options) if nopt > 0: f.write(" ".join(self.options) + "\n") @@ -445,16 +438,13 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading sms package file...\n") + print("loading sms package file...") if model.version != "mfusg": - msg = ( - "Warning: model version was reset from " - + "'{}' to 'mfusg' in order to load a SMS file".format( - model.version - ) + print( + "Warning: model version was reset from '{}' to 'mfusg' " + "in order to load a SMS file".format(model.version) ) - print(msg) model.version = "mfusg" openfile = not hasattr(f, "read") @@ -481,12 +471,10 @@ def load(cls, f, model, ext_unit_dict=None): # Record 1b -- line will have already been read if model.verbose: - msg = ( - 3 * " " - + " loading HCLOSE HICLOSE MXITER ITER1 " - + "IPRSMS NONLINMETH LINMETH..." + print( + " loading HCLOSE HICLOSE MXITER ITER1 " + "IPRSMS NONLINMETH LINMETH..." ) - print(msg) ll = line_parse(line) hclose = float(ll.pop(0)) hiclose = float(ll.pop(0)) @@ -496,13 +484,13 @@ def load(cls, f, model, ext_unit_dict=None): nonlinmeth = int(ll.pop(0)) linmeth = int(ll.pop(0)) if model.verbose: - print(" HCLOSE {}".format(hclose)) - print(" HICLOSE {}".format(hiclose)) - print(" MXITER {}".format(mxiter)) - print(" ITER1 {}".format(iter1)) - print(" IPRSMS {}".format(iprsms)) - print(" NONLINMETH {}".format(nonlinmeth)) - print(" LINMETH {}".format(linmeth)) + print(f" HCLOSE {hclose}") + print(f" HICLOSE {hiclose}") + print(f" MXITER {mxiter}") + print(f" ITER1 {iter1}") + print(f" IPRSMS {iprsms}") + print(f" NONLINMETH {nonlinmeth}") + print(f" LINMETH {linmeth}") # Record 2 theta = None @@ -515,12 +503,10 @@ def load(cls, f, model, ext_unit_dict=None): reslim = None if nonlinmeth != 0 and nopt == 0: if model.verbose: - msg = ( - 3 * " " - + "loading THETA AKAPPA GAMMA AMOMENTUM " - + "NUMTRACK BTOL BREDUC RESLIM..." + print( + " loading THETA AKAPPA GAMMA AMOMENTUM " + "NUMTRACK BTOL BREDUC RESLIM..." ) - print(msg) while True: line = f.readline() if line[0] != "#": @@ -535,14 +521,14 @@ def load(cls, f, model, ext_unit_dict=None): breduc = float(ll.pop(0)) reslim = float(ll.pop(0)) if model.verbose: - print(" THETA {}".format(theta)) - print(" AKAPPA {}".format(akappa)) - print(" GAMMA {}".format(gamma)) - print(" AMOMENTUM {}".format(amomentum)) - print(" NUMTRACK {}".format(numtrack)) - print(" BTOL {}".format(btol)) - print(" BREDUC {}".format(breduc)) - print(" RESLIM {}".format(reslim)) + print(f" THETA {theta}") + print(f" AKAPPA {akappa}") + print(f" GAMMA {gamma}") + print(f" AMOMENTUM {amomentum}") + print(f" NUMTRACK {numtrack}") + print(f" BTOL {btol}") + print(f" BREDUC {breduc}") + print(f" RESLIM {reslim}") iacl = None norder = None @@ -554,12 +540,10 @@ def load(cls, f, model, ext_unit_dict=None): epsrn = None if linmeth == 1 and nopt == 0: if model.verbose: - msg = ( - 3 * " " - + "loading IACL NORDER LEVEL NORTH " - + "IREDSYS RRCTOL IDROPTOL EPSRN" + print( + " loading IACL NORDER LEVEL NORTH " + "IREDSYS RRCTOL IDROPTOL EPSRN" ) - print(msg) while True: line = f.readline() if line[0] != "#": @@ -574,14 +558,14 @@ def load(cls, f, model, ext_unit_dict=None): idroptol = int(ll.pop(0)) epsrn = float(ll.pop(0)) if model.verbose: - print(" IACL {}".format(iacl)) - print(" NORDER {}".format(norder)) - print(" LEVEL {}".format(level)) - print(" NORTH {}".format(north)) - print(" IREDSYS {}".format(iredsys)) - print(" RRCTOL {}".format(rrctol)) - print(" IDROPTOL {}".format(idroptol)) - print(" EPSRN {}".format(epsrn)) + print(f" IACL {iacl}") + print(f" NORDER {norder}") + print(f" LEVEL {level}") + print(f" NORTH {north}") + print(f" IREDSYS {iredsys}") + print(f" RRCTOL {rrctol}") + print(f" IDROPTOL {idroptol}") + print(f" EPSRN {epsrn}") clin = None ipc = None @@ -591,12 +575,7 @@ def load(cls, f, model, ext_unit_dict=None): relaxpcgu = None if linmeth == 2 and nopt == 0: if model.verbose: - msg = ( - 3 * " " - + "loading [CLIN] IPC ISCL IORD " - + "RCLOSEPCGU [RELAXPCGU]" - ) - print(msg) + print(" loading [CLIN] IPC ISCL IORD RCLOSEPCGU [RELAXPCGU]") while True: line = f.readline() if line[0] != "#": @@ -611,12 +590,12 @@ def load(cls, f, model, ext_unit_dict=None): if len(ll) > 0: relaxpcgu = float(ll.pop(0)) if model.verbose: - print(" CLIN {}".format(clin)) - print(" IPC {}".format(ipc)) - print(" ISCL {}".format(iscl)) - print(" IORD {}".format(iord)) - print(" RCLOSEPCGU {}".format(rclosepcgu)) - print(" RELAXPCGU {}".format(relaxpcgu)) + print(f" CLIN {clin}") + print(f" IPC {ipc}") + print(f" ISCL {iscl}") + print(f" IORD {iord}") + print(f" RCLOSEPCGU {rclosepcgu}") + print(f" RELAXPCGU {relaxpcgu}") if openfile: f.close() diff --git a/dependencies/flopy/modflow/mfsor.py b/dependencies/flopy/modflow/mfsor.py index bf54f2a..1595de2 100644 --- a/dependencies/flopy/modflow/mfsor.py +++ b/dependencies/flopy/modflow/mfsor.py @@ -7,9 +7,6 @@ `_. """ - -import sys - from ..pakbase import Package @@ -116,16 +113,12 @@ def __init__( # check if a valid model version has been specified if model.version != "mf2k": - err = "Error: cannot use {} ".format( - self.name - ) + "package with model version {}".format(model.version) - raise Exception(err) - - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + raise Exception( + f"Error: cannot use {self.name} " + f"package with model version {model.version}" + ) + + self._generate_heading() self.url = "sor.htm" self.mxiter = mxiter self.accl = accl @@ -144,11 +137,9 @@ def write_file(self): """ # Open file for writing f = open(self.fn_path, "w") - f.write("{}\n".format(self.heading)) - f.write("{:10d}\n".format(self.mxiter)) - line = "{:10.4g}{:10.4g}{:10d}\n".format( - self.accl, self.hclose, self.iprsor - ) + f.write(f"{self.heading}\n") + f.write(f"{self.mxiter:10d}\n") + line = f"{self.accl:10.4g}{self.hclose:10.4g}{self.iprsor:10d}\n" f.write(line) f.close() @@ -185,7 +176,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading sor package file...\n") + print("loading sor package file...") openfile = not hasattr(f, "read") if openfile: @@ -194,12 +185,10 @@ def load(cls, f, model, ext_unit_dict=None): # dataset 0 -- header - msg = ( - 3 * " " - + "Warning: load method not completed. " - + "Default sor object created." + print( + " Warning: load method not completed. " + "Default sor object created." ) - print(msg) if openfile: f.close() diff --git a/dependencies/flopy/modflow/mfstr.py b/dependencies/flopy/modflow/mfstr.py index 6a9cebf..0e395e2 100644 --- a/dependencies/flopy/modflow/mfstr.py +++ b/dependencies/flopy/modflow/mfstr.py @@ -7,8 +7,6 @@ `_. """ -import sys - import numpy as np from ..utils import MfList from ..pakbase import Package @@ -242,7 +240,7 @@ def __init__( unitnumber=None, filenames=None, options=None, - **kwargs + **kwargs, ): """ Package constructor. @@ -305,11 +303,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "str.htm" self.mxacts = mxacts self.nss = nss @@ -324,7 +318,7 @@ def __init__( if ntrib > 10: raise Exception( "ModflowStr error: ntrib must be less that 10: " - + "specified value = {}".format(ntrib) + "specified value = {}".format(ntrib) ) if options is None: @@ -405,11 +399,8 @@ def __init__( d = np.array(d) if isinstance(d, np.recarray): e = ( - "ModflowStr error: recarray dtype: " - + str(d.dtype) - + " does not match " - + "self dtype: " - + str(self.dtype) + "ModflowStr error: recarray dtype: {} does not match " + "self dtype: {}".format(d.dtype, self.dtype) ) assert d.dtype == self.dtype, e elif isinstance(d, np.ndarray): @@ -419,26 +410,17 @@ def __init__( elif isinstance(d, int): if model.verbose: if d < 0: - msg = ( - 3 * " " - + "reusing str data from previous stress period" + print( + " reusing str data from previous " + "stress period" ) - print(msg) elif d == 0: - msg = ( - 3 * " " - + "no str data for stress " - + "period {}".format(key) - ) - print(msg) + print(f" no str data for stress period {key}") else: - e = ( + raise Exception( "ModflowStr error: unsupported data type: " - + str(type(d)) - + " at kper " - + "{0:d}".format(key) + "{} at kper {}".format(type(d), key) ) - raise Exception(e) # add stress_period_data to package self.stress_period_data = MfList(self, stress_period_data) @@ -450,11 +432,8 @@ def __init__( d = np.array(d) if isinstance(d, np.recarray): e = ( - "ModflowStr error: recarray dtype: " - + str(d.dtype) - + " does not match " - + "self dtype: " - + str(self.dtype2) + "ModflowStr error: recarray dtype: {} does not match " + "self dtype: {}".format(d.dtype, self.dtype2) ) assert d.dtype == self.dtype2, e elif isinstance(d, np.ndarray): @@ -464,27 +443,19 @@ def __init__( elif isinstance(d, int): if model.verbose: if d < 0: - msg = ( - 3 * " " - + "reusing str segment data " - + "from previous stress period" + print( + " reusing str segment data " + "from previous stress period" ) - print(msg) elif d == 0: - msg = ( - 3 * " " - + "no str segment data for " - + "stress period {}".format(key) + print( + f" no str segment data for stress period {key}" ) - print(msg) else: - e = ( + raise Exception( "ModflowStr error: unsupported data type: " - + str(type(d)) - + " at kper " - + "{0:d}".format(key) + "{} at kper {}".format(type(d), key) ) - raise Exception(e) # add segment_data to package self.segment_data = segment_data @@ -585,7 +556,7 @@ def write_file(self): f_str = open(self.fn_path, "w") # dataset 0 - f_str.write("{0}\n".format(self.heading)) + f_str.write(f"{self.heading}\n") # dataset 1 - parameters not supported on write @@ -638,11 +609,8 @@ def write_file(self): itmp = -1 else: itmp = tdata.shape[0] - line = ( - "{:10d}".format(itmp) - + "{:10d}".format(self.irdflg[iper]) - + "{:10d}".format(self.iptflg[iper]) - + " # stress period {}\n".format(iper + 1) + line = "{:10d}{:10d}{:10d} # stress period {}\n".format( + itmp, self.irdflg[iper], self.iptflg[iper], iper + 1 ) f_str.write(line) if itmp > 0: @@ -743,7 +711,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): fmt9 = [5] if model.verbose: - sys.stdout.write("loading str package file...\n") + print("loading str package file...") openfile = not hasattr(f, "read") if openfile: @@ -761,7 +729,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): t = line.strip().split() if t[0].lower() == "parameter": if model.verbose: - sys.stdout.write(" loading str dataset 1\n") + print(" loading str dataset 1") npstr = np.int32(t[1]) mxl = np.int32(t[2]) @@ -770,7 +738,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): # data set 2 if model.verbose: - sys.stdout.write(" loading str dataset 2\n") + print(" loading str dataset 2") t = read_fixed_var(line, ipos=fmt2, free=free) mxacts = np.int32(t[0]) nss = np.int32(t[1]) @@ -787,14 +755,14 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): model.add_pop_key_list(istcb1) except: if model.verbose: - print(" could not remove unit number {}".format(istcb1)) + print(f" could not remove unit number {istcb1}") try: if istcb2 != 0: ipakcb = 53 model.add_pop_key_list(istcb2) except: if model.verbose: - print(" could not remove unit number {}".format(istcb2)) + print(f" could not remove unit number {istcb2}") options = [] aux_names = [] @@ -827,11 +795,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): segment_data = {} for iper in range(nper): if model.verbose: - print( - " loading " - + str(ModflowStr) - + " for kper {0:5d}".format(iper + 1) - ) + print(f" loading {ModflowStr} for kper {iper + 1:5d}") line = f.readline() if line == "": break @@ -877,8 +841,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): except: if model.verbose: print( - " implicit static instance for " - + "parameter {}".format(pname) + f" implicit static instance for parameter {pname}" ) par_dict, current_dict = pak_parms.get(pname) diff --git a/dependencies/flopy/modflow/mfsub.py b/dependencies/flopy/modflow/mfsub.py index a0fe752..d978376 100644 --- a/dependencies/flopy/modflow/mfsub.py +++ b/dependencies/flopy/modflow/mfsub.py @@ -7,8 +7,6 @@ `_. """ -import sys - import numpy as np from ..pakbase import Package @@ -336,11 +334,7 @@ def __init__( nrow, ncol, nlay, nper = self.parent.nrow_ncol_nlay_nper - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "sub.htm" self.ipakcb = ipakcb @@ -504,39 +498,30 @@ def write_file(self, check=False, f=None): if f is None: f = open(self.fn_path, "w") # First line: heading - f.write("{}\n".format(self.heading)) + f.write(f"{self.heading}\n") # write dataset 1 f.write( - "{} {} {} {} {} {} ".format( - self.ipakcb, - self.isuboc, - self.nndb, - self.ndb, - self.nmz, - self.nn, - ) + f"{self.ipakcb} {self.isuboc} {self.nndb} {self.ndb} {self.nmz} {self.nn} " ) f.write( - "{} {} {} {} {}".format( - self.ac1, self.ac2, self.itmin, self.idsave, self.idrest - ) + f"{self.ac1} {self.ac2} {self.itmin} {self.idsave} {self.idrest}" ) line = "" if self.idbit is not None: - line += " {}".format(self.idbit) + line += f" {self.idbit}" line += "\n" f.write(line) if self.nndb > 0: t = self.ln.array for tt in t: - f.write("{} ".format(tt + 1)) + f.write(f"{tt + 1} ") f.write("\n") if self.ndb > 0: t = self.ldn.array for tt in t: - f.write("{} ".format(tt + 1)) + f.write(f"{tt + 1} ") f.write("\n") # write dataset 4 @@ -555,9 +540,10 @@ def write_file(self, check=False, f=None): # write dataset 9 if self.ndb > 0: for k in range(self.nmz): - line = "{:15.6g} {:15.6g} {:15.6g}".format( - self.dp[k, 0], self.dp[k, 1], self.dp[k, 2] - ) + " #material zone {} data\n".format(k + 1) + line = ( + f"{self.dp[k, 0]:15.6g} {self.dp[k, 1]:15.6g} " + f"{self.dp[k, 2]:15.6g} #material zone {k + 1} data\n" + ) f.write(line) # write dataset 10 to 14 if self.ndb > 0: @@ -572,7 +558,7 @@ def write_file(self, check=False, f=None): if self.isuboc > 0: # dataset 15 for i in self.ids15: - f.write("{} ".format(i)) + f.write(f"{i} ") f.write(" #dataset 15\n") # dataset 16 @@ -580,8 +566,8 @@ def write_file(self, check=False, f=None): t = self.ids16[k, :] t[0:4] += 1 for i in t: - f.write("{} ".format(i)) - f.write(" #dataset 16 isuboc {}\n".format(k + 1)) + f.write(f"{i} ") + f.write(f" #dataset 16 isuboc {k + 1}\n") # close sub file f.close() @@ -619,7 +605,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading sub package file...\n") + print("loading sub package file...") openfile = not hasattr(f, "read") if openfile: @@ -636,7 +622,7 @@ def load(cls, f, model, ext_unit_dict=None): # read dataset 1 if model.verbose: - sys.stdout.write(" loading sub dataset 1\n") + print(" loading sub dataset 1") t = line.strip().split() ipakcb, isuboc, nndb, ndb, nmz, nn = ( int(t[0]), @@ -660,19 +646,19 @@ def load(cls, f, model, ext_unit_dict=None): ln = None if nndb > 0: if model.verbose: - sys.stdout.write(" loading sub dataset 2\n") + print(" loading sub dataset 2") ln = np.empty((nndb), dtype=np.int32) ln = read1d(f, ln) - 1 ldn = None if ndb > 0: if model.verbose: - sys.stdout.write(" loading sub dataset 3\n") + print(" loading sub dataset 3") ldn = np.empty((ndb), dtype=np.int32) ldn = read1d(f, ldn) - 1 rnb = None if ndb > 0: if model.verbose: - sys.stdout.write(" loading sub dataset 4\n") + print(" loading sub dataset 4") rnb = [0] * ndb for k in range(ndb): t = Util2d.load( @@ -680,7 +666,7 @@ def load(cls, f, model, ext_unit_dict=None): model, (nrow, ncol), np.float32, - "rnb delay bed {}".format(k + 1), + f"rnb delay bed {k + 1}", ext_unit_dict, ) rnb[k] = t @@ -697,57 +683,49 @@ def load(cls, f, model, ext_unit_dict=None): kk = ln[k] + 1 # hc if model.verbose: - sys.stdout.write( - " loading sub dataset 5 for layer {}\n".format(kk) - ) + print(f" loading sub dataset 5 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "hc layer {}".format(kk), + f"hc layer {kk}", ext_unit_dict, ) hc[k] = t # sfe if model.verbose: - sys.stdout.write( - " loading sub dataset 6 for layer {}\n".format(kk) - ) + print(f" loading sub dataset 6 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "sfe layer {}".format(kk), + f"sfe layer {kk}", ext_unit_dict, ) sfe[k] = t # sfv if model.verbose: - sys.stdout.write( - " loading sub dataset 7 for layer {}\n".format(kk) - ) + print(f" loading sub dataset 7 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "sfv layer {}".format(kk), + f"sfv layer {kk}", ext_unit_dict, ) sfv[k] = t # com if model.verbose: - sys.stdout.write( - " loading sub dataset 8 for layer {}\n".format(kk) - ) + print(f" loading sub dataset 8 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "com layer {}".format(kk), + f"com layer {kk}", ext_unit_dict, ) com[k] = t @@ -758,12 +736,7 @@ def load(cls, f, model, ext_unit_dict=None): dp = np.zeros((nmz, 3), dtype=np.float32) for k in range(nmz): if model.verbose: - msg = ( - 2 * " " - + "loading sub dataset 9 for material " - + "zone {}\n".format(k + 1) - ) - sys.stdout.write(msg) + print(f" loading sub dataset 9 for material zone {k + 1}") line = f.readline() t = line.strip().split() dp[k, :] = float(t[0]), float(t[1]), float(t[2]) @@ -783,86 +756,61 @@ def load(cls, f, model, ext_unit_dict=None): kk = ldn[k] + 1 # dstart if model.verbose: - msg = ( - 2 * " " - + "loading sub dataset 10 for " - + "layer {}\n".format(kk) - ) - sys.stdout.write(msg) + print(f" loading sub dataset 10 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "dstart layer {}".format(kk), + f"dstart layer {kk}", ext_unit_dict, ) dstart[k] = t # dhc if model.verbose: - msg = ( - 2 * " " - + "loading sub dataset 11 for " - + "layer {}\n".format(kk) - ) - sys.stdout.write(msg) + print(f" loading sub dataset 11 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "dhc layer {}".format(kk), + f"dhc layer {kk}", ext_unit_dict, ) dhc[k] = t # dcom if model.verbose: - msg = ( - 2 * " " - + "loading sub dataset 12 for " - + "layer {}\n".format(kk) - ) - sys.stdout.write(msg) + print(f" loading sub dataset 12 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "dcom layer {}".format(kk), + f"dcom layer {kk}", ext_unit_dict, ) dcom[k] = t # dz if model.verbose: - msg = ( - 2 * " " - + "loading sub dataset 13 for " - + "layer {}\n".format(kk) - ) - sys.stdout.write(msg) + print(f" loading sub dataset 13 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "dz layer {}".format(kk), + f"dz layer {kk}", ext_unit_dict, ) dz[k] = t # nz if model.verbose: - msg = ( - 2 * " " - + "loading sub dataset 14 for " - + "layer {}\n".format(kk) - ) - sys.stdout.write(msg) + print(f" loading sub dataset 14 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.int32, - "nz layer {}".format(kk), + f"nz layer {kk}", ext_unit_dict, ) nz[k] = t @@ -872,24 +820,14 @@ def load(cls, f, model, ext_unit_dict=None): if isuboc > 0: # dataset 15 if model.verbose: - msg = ( - 2 * " " - + "loading sub dataset 15 for " - + "layer {}\n".format(kk) - ) - sys.stdout.write(msg) + print(f" loading sub dataset 15 for layer {kk}") ids15 = np.empty(12, dtype=np.int32) ids15 = read1d(f, ids15) # dataset 16 ids16 = [0] * isuboc for k in range(isuboc): if model.verbose: - msg = ( - 2 * " " - + "loading sub dataset 16 for " - + "isuboc {}\n".format(k + 1) - ) - sys.stdout.write(msg) + print(f" loading sub dataset 16 for isuboc {k + 1}") t = np.empty(17, dtype=np.int32) t = read1d(f, t) t[0:4] -= 1 diff --git a/dependencies/flopy/modflow/mfswi2.py b/dependencies/flopy/modflow/mfswi2.py index c3ecb67..bba78f1 100644 --- a/dependencies/flopy/modflow/mfswi2.py +++ b/dependencies/flopy/modflow/mfswi2.py @@ -5,8 +5,6 @@ MODFLOW Guide `_. """ -import sys - import numpy as np from ..pakbase import Package @@ -274,26 +272,23 @@ def __init__( if obslrc.ndim == 1 and obslrc.size == 3: obslrc = obslrc.reshape((1, 3)) else: - errmsg = ( - "ModflowSwi2: obslrc must be a tuple or " - + "list of tuples." + raise Exception( + "ModflowSwi2: obslrc must be a tuple or list of tuples." ) - raise Exception(errmsg) nobs = obslrc.shape[0] if obsnam is None: obsnam = [] for n in range(nobs): - obsnam.append("Obs{:03}".format(n + 1)) + obsnam.append(f"Obs{n + 1:03}") else: if not isinstance(obsnam, list): obsnam = [obsnam] if len(obsnam) != nobs: - errmsg = ( + raise Exception( "ModflowSwi2: obsnam must be a list with a " - + "length of {} not {}.".format(nobs, len(obsnam)) + "length of {} not {}.".format(nobs, len(obsnam)) ) - raise Exception(errmsg) if nobs > 0: binflag = False @@ -339,11 +334,7 @@ def __init__( ) nrow, ncol, nlay, nper = self.parent.nrow_ncol_nlay_nper - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() # options self.fsssopt, self.adaptive = False, False @@ -405,7 +396,7 @@ def __init__( (nlay, nrow, ncol), np.float32, zeta[i], - name="zeta_" + str(i + 1), + name=f"zeta_{i + 1}", ) ) self.ssz = Util3d( @@ -441,9 +432,7 @@ def write_file(self, check=True, f=None): f = open(self.fn_path, "w") # First line: heading - f.write( - "{}\n".format(self.heading) - ) # Writing heading not allowed in SWI??? + f.write(f"{self.heading}\n") # Writing heading not allowed in SWI??? # write dataset 1 f.write("# Dataset 1\n") @@ -466,39 +455,33 @@ def write_file(self, check=True, f=None): # write dataset 2a f.write("# Dataset 2a\n") - f.write( - "{:10d}{:10d}{:10d}\n".format( - self.nsolver, self.iprsol, self.mutsol - ) - ) + f.write(f"{self.nsolver:10d}{self.iprsol:10d}{self.mutsol:10d}\n") # write dataset 2b if self.nsolver == 2: f.write("# Dataset 2b\n") - f.write("{:10d}".format(self.solver2params["mxiter"])) - f.write("{:10d}".format(self.solver2params["iter1"])) - f.write("{:10d}".format(self.solver2params["npcond"])) - f.write("{:14.6g}".format(self.solver2params["zclose"])) - f.write("{:14.6g}".format(self.solver2params["rclose"])) - f.write("{:14.6g}".format(self.solver2params["relax"])) - f.write("{:10d}".format(self.solver2params["nbpol"])) - f.write("{:14.6g}".format(self.solver2params["damp"])) - f.write("{:14.6g}\n".format(self.solver2params["dampt"])) + f.write(f"{self.solver2params['mxiter']:10d}") + f.write(f"{self.solver2params['iter1']:10d}") + f.write(f"{self.solver2params['npcond']:10d}") + f.write(f"{self.solver2params['zclose']:14.6g}") + f.write(f"{self.solver2params['rclose']:14.6g}") + f.write(f"{self.solver2params['relax']:14.6g}") + f.write(f"{self.solver2params['nbpol']:10d}") + f.write(f"{self.solver2params['damp']:14.6g}") + f.write(f"{self.solver2params['dampt']:14.6g}\n") # write dataset 3a f.write("# Dataset 3a\n") - f.write("{:14.6g}{:14.6g}".format(self.toeslope, self.tipslope)) + f.write(f"{self.toeslope:14.6g}{self.tipslope:14.6g}") if self.alpha is not None: - f.write("{:14.6g}{:14.6g}".format(self.alpha, self.beta)) + f.write(f"{self.alpha:14.6g}{self.beta:14.6g}") f.write("\n") # write dataset 3b if self.adaptive is True: f.write("# Dataset 3b\n") f.write( - "{:10d}{:10d}{:14.6g}\n".format( - self.nadptmx, self.nadptmn, self.adptfct - ) + f"{self.nadptmx:10d}{self.nadptmn:10d}{self.adptfct:14.6g}\n" ) # write dataset 4 f.write("# Dataset 4\n") @@ -523,9 +506,9 @@ def write_file(self, check=True, f=None): f.write("# Dataset 8\n") for i in range(self.nobs): # f.write(self.obsnam[i] + 3 * '%10i' % self.obslrc + '\n') - f.write("{} ".format(self.obsnam[i])) + f.write(f"{self.obsnam[i]} ") for v in self.obslrc[i, :]: - f.write("{:10d}".format(v + 1)) + f.write(f"{v + 1:10d}") f.write("\n") # close swi2 file @@ -562,7 +545,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading swi2 package file...\n") + print("loading swi2 package file...") openfile = not hasattr(f, "read") if openfile: @@ -579,7 +562,7 @@ def load(cls, f, model, ext_unit_dict=None): # --read dataset 1 if model.verbose: - sys.stdout.write(" loading swi2 dataset 1\n") + print(" loading swi2 dataset 1") t = line.strip().split() nsrf = int(t[0]) istrat = int(t[1]) @@ -607,7 +590,7 @@ def load(cls, f, model, ext_unit_dict=None): # read dataset 2a if model.verbose: - sys.stdout.write(" loading swi2 dataset 2a\n") + print(" loading swi2 dataset 2a") while True: line = f.readline() if line[0] != "#": @@ -621,7 +604,7 @@ def load(cls, f, model, ext_unit_dict=None): solver2params = {} if nsolver == 2: if model.verbose: - sys.stdout.write(" loading swi2 dataset 2b\n") + print(" loading swi2 dataset 2b") while True: line = f.readline() if line[0] != "#": @@ -639,7 +622,7 @@ def load(cls, f, model, ext_unit_dict=None): # read dataset 3a if model.verbose: - sys.stdout.write(" loading swi2 dataset 3a\n") + print(" loading swi2 dataset 3a") while True: line = f.readline() if line[0] != "#": @@ -661,7 +644,7 @@ def load(cls, f, model, ext_unit_dict=None): nadptmx, nadptmn, adptfct = None, None, None if adaptive: if model.verbose: - sys.stdout.write(" loading swi2 dataset 3b\n") + print(" loading swi2 dataset 3b") while True: line = f.readline() if line[0] != "#": @@ -697,7 +680,7 @@ def load(cls, f, model, ext_unit_dict=None): break zeta = [] for n in range(nsrf): - ctxt = "zeta_surf{:02d}".format(n + 1) + ctxt = f"zeta_surf{n + 1:02d}" zeta.append( Util3d.load( f, diff --git a/dependencies/flopy/modflow/mfswr1.py b/dependencies/flopy/modflow/mfswr1.py index 8d2cafe..edd6ad2 100644 --- a/dependencies/flopy/modflow/mfswr1.py +++ b/dependencies/flopy/modflow/mfswr1.py @@ -7,7 +7,6 @@ `_. """ -import sys from ..pakbase import Package @@ -99,11 +98,7 @@ def __init__( ) raise Exception(err) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "swr1.htm" self.parent.add_package(self) @@ -160,7 +155,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading swr1 process file...\n") + print("loading swr1 process file...") # todo: everything diff --git a/dependencies/flopy/modflow/mfswt.py b/dependencies/flopy/modflow/mfswt.py index 642c707..0147fdd 100644 --- a/dependencies/flopy/modflow/mfswt.py +++ b/dependencies/flopy/modflow/mfswt.py @@ -7,8 +7,6 @@ `_. """ -import sys - import numpy as np from ..pakbase import Package @@ -243,7 +241,7 @@ def write_file(self, f=None): if f is None: f = open(self.fn_path, "w") # First line: heading - f.write("{}\n".format(self.heading)) + f.write(f"{self.heading}\n") # write dataset 1 f.write( "{} {} {} {} {} {} {}\n".format( @@ -259,7 +257,7 @@ def write_file(self, f=None): # write dataset 2 t = self.lnwt.array for tt in t: - f.write("{} ".format(tt + 1)) + f.write(f"{tt + 1} ") f.write("\n") # write dataset 3 @@ -310,7 +308,7 @@ def write_file(self, f=None): if self.iswtoc > 0: # dataset 16 for i in self.ids16: - f.write("{} ".format(i)) + f.write(f"{i} ") f.write(" #dataset 16\n") # dataset 17 @@ -318,8 +316,8 @@ def write_file(self, f=None): t = self.ids17[k, :].copy() t[0:4] += 1 for i in t: - f.write("{} ".format(i)) - f.write(" #dataset 17 iswtoc {}\n".format(k + 1)) + f.write(f"{i} ") + f.write(f" #dataset 17 iswtoc {k + 1}\n") # close swt file f.close() @@ -443,11 +441,7 @@ def __init__( nrow, ncol, nlay, nper = self.parent.nrow_ncol_nlay_nper - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "swt.htm" self.ipakcb = ipakcb @@ -632,7 +626,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading swt package file...\n") + print("loading swt package file...") openfile = not hasattr(f, "read") if openfile: @@ -649,7 +643,7 @@ def load(cls, f, model, ext_unit_dict=None): # read dataset 1 if model.verbose: - sys.stdout.write(" loading swt dataset 1\n") + print(" loading swt dataset 1") t = line.strip().split() ipakcb, iswtoc, nsystm, ithk, ivoid, istpcs, icrcc = ( int(t[0]), @@ -668,13 +662,13 @@ def load(cls, f, model, ext_unit_dict=None): lnwt = None if nsystm > 0: if model.verbose: - sys.stdout.write(" loading swt dataset 2\n") + print(" loading swt dataset 2") lnwt = np.empty((nsystm), dtype=np.int32) lnwt = read1d(f, lnwt) - 1 # read dataset 3 if model.verbose: - sys.stdout.write(" loading swt dataset 3\n") + print(" loading swt dataset 3") line = f.readline() t = line.strip().split() ( @@ -703,21 +697,21 @@ def load(cls, f, model, ext_unit_dict=None): # read dataset 4 if model.verbose: - sys.stdout.write(" loading swt dataset 4") + print(" loading swt dataset 4") gl0 = Util2d.load( f, model, (nrow, ncol), np.float32, "gl0", ext_unit_dict ) # read dataset 5 if model.verbose: - sys.stdout.write(" loading swt dataset 5") + print(" loading swt dataset 5") sgm = Util2d.load( f, model, (nrow, ncol), np.float32, "sgm", ext_unit_dict ) # read dataset 6 if model.verbose: - sys.stdout.write(" loading swt dataset 6") + print(" loading swt dataset 6") sgs = Util2d.load( f, model, (nrow, ncol), np.float32, "sgs", ext_unit_dict ) @@ -741,101 +735,87 @@ def load(cls, f, model, ext_unit_dict=None): kk = lnwt[k] + 1 # thick if model.verbose: - sys.stdout.write( - " loading swt dataset 7 for layer {}\n".format(kk) - ) + print(f" loading swt dataset 7 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "thick layer {}".format(kk), + f"thick layer {kk}", ext_unit_dict, ) thick[k] = t if icrcc != 0: # sse if model.verbose: - sys.stdout.write( - " loading swt dataset 8 for layer {}\n".format(kk) - ) + print(f" loading swt dataset 8 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "sse layer {}".format(kk), + f"sse layer {kk}", ext_unit_dict, ) sse[k] = t # ssv if model.verbose: - sys.stdout.write( - " loading swt dataset 9 for layer {}\n".format(kk) - ) + print(f" loading swt dataset 9 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "sse layer {}".format(kk), + f"sse layer {kk}", ext_unit_dict, ) ssv[k] = t else: # cr if model.verbose: - sys.stdout.write( - " loading swt dataset 10 for layer {}\n".format(kk) - ) + print(f" loading swt dataset 10 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "cr layer {}".format(kk), + f"cr layer {kk}", ext_unit_dict, ) cr[k] = t # cc if model.verbose: - sys.stdout.write( - " loading swt dataset 11 for layer {}\n".format(kk) - ) + print(f" loading swt dataset 11 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "cc layer {}".format(kk), + f"cc layer {kk}", ext_unit_dict, ) cc[k] = t # void if model.verbose: - sys.stdout.write( - " loading swt dataset 12 for layer {}\n".format(kk) - ) + print(f" loading swt dataset 12 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "void layer {}".format(kk), + f"void layer {kk}", ext_unit_dict, ) void[k] = t # sub if model.verbose: - sys.stdout.write( - " loading swt dataset 13 for layer {}\n".format(kk) - ) + print(f" loading swt dataset 13 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "sub layer {}".format(kk), + f"sub layer {kk}", ext_unit_dict, ) sub[k] = t @@ -850,29 +830,25 @@ def load(cls, f, model, ext_unit_dict=None): for k in range(nlay): if istpcs != 0: if model.verbose: - sys.stdout.write( - " loading swt dataset 14 for layer {}\n".format(kk) - ) + print(f" loading swt dataset 14 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "pcsoff layer {}".format(k + 1), + f"pcsoff layer {k + 1}", ext_unit_dict, ) pcsoff[k] = t else: if model.verbose: - sys.stdout.write( - " loading swt dataset 15 for layer {}\n".format(kk) - ) + print(f" loading swt dataset 15 for layer {kk}") t = Util2d.load( f, model, (nrow, ncol), np.float32, - "pcs layer {}".format(k + 1), + f"pcs layer {k + 1}", ext_unit_dict, ) pcs[k] = t @@ -882,9 +858,7 @@ def load(cls, f, model, ext_unit_dict=None): if iswtoc > 0: # dataset 16 if model.verbose: - sys.stdout.write( - " loading swt dataset 15 for layer {}\n".format(kk) - ) + print(f" loading swt dataset 15 for layer {kk}") ids16 = np.empty(26, dtype=np.int32) ids16 = read1d(f, ids16) # for k in range(1, 26, 2): @@ -894,12 +868,7 @@ def load(cls, f, model, ext_unit_dict=None): ids17 = [0] * iswtoc for k in range(iswtoc): if model.verbose: - msg = ( - 2 * " " - + "loading swt dataset 17 for " - + "iswtoc {}\n".format(k + 1) - ) - sys.stdout.write(msg) + print(f" loading swt dataset 17 for iswtoc {k + 1}") t = np.empty(30, dtype=np.int32) t = read1d(f, t) t[0:4] -= 1 diff --git a/dependencies/flopy/modflow/mfupw.py b/dependencies/flopy/modflow/mfupw.py index f2cf46c..43c469c 100644 --- a/dependencies/flopy/modflow/mfupw.py +++ b/dependencies/flopy/modflow/mfupw.py @@ -7,8 +7,6 @@ `_. """ - -import sys import numpy as np from .mfpar import ModflowPar as mfpar from ..pakbase import Package @@ -162,11 +160,10 @@ def __init__( ): if model.version != "mfnwt": - err = ( + raise Exception( "Error: model version must be mfnwt to use " - + "{} package".format(ModflowUpw._ftype()) + "{} package".format(ModflowUpw._ftype()) ) - raise Exception(err) # set default unit number of one is not specified if unitnumber is None: @@ -210,11 +207,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "upw_upstream_weighting_package.htm" nrow, ncol, nlay, nper = self.parent.nrow_ncol_nlay_nper @@ -308,7 +301,7 @@ def write_file(self, check=True, f=None): # allows turning off package checks when writing files at model level if check: self.check( - f="{}.chk".format(self.name[0]), + f=f"{self.name[0]}.chk", verbose=self.parent.verbose, level=1, ) @@ -318,7 +311,7 @@ def write_file(self, check=True, f=None): else: f_upw = open(self.fn_path, "w") # Item 0: text - f_upw.write("{}\n".format(self.heading)) + f_upw.write(f"{self.heading}\n") # Item 1: IBCFCB, HDRY, NPLPF f_upw.write( "{0:10d}{1:10.3G}{2:10d}{3:10d}{4:s}\n".format( @@ -391,16 +384,13 @@ def load(cls, f, model, ext_unit_dict=None, check=True): """ if model.verbose: - sys.stdout.write("loading upw package file...\n") + print("loading upw package file...") if model.version != "mfnwt": - msg = ( - "Warning: model version was reset from " - + "'{}' to 'mfnwt' in order to load a UPW file".format( - model.version - ) + print( + "Warning: model version was reset from '{}' to 'mfnwt' " + "in order to load a UPW file".format(model.version) ) - print(msg) model.version = "mfnwt" openfile = not hasattr(f, "read") @@ -486,7 +476,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # hk if model.verbose: - print(" loading hk layer {0:3d}...".format(k + 1)) + print(f" loading hk layer {k + 1:3d}...") if "hk" not in par_types: t = Util2d.load( f, model, (nrow, ncol), np.float32, "hk", ext_unit_dict @@ -501,7 +491,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # hani if chani[k] < 0: if model.verbose: - print(" loading hani layer {0:3d}...".format(k + 1)) + print(f" loading hani layer {k + 1:3d}...") if "hani" not in par_types: t = Util2d.load( f, @@ -520,7 +510,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # vka if model.verbose: - print(" loading vka layer {0:3d}...".format(k + 1)) + print(f" loading vka layer {k + 1:3d}...") key = "vk" if layvka[k] != 0: key = "vani" @@ -540,7 +530,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # ss if model.verbose: - print(" loading ss layer {0:3d}...".format(k + 1)) + print(f" loading ss layer {k + 1:3d}...") if "ss" not in par_types: t = Util2d.load( f, model, (nrow, ncol), np.float32, "ss", ext_unit_dict @@ -555,7 +545,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # sy if laytyp[k] != 0: if model.verbose: - print(" loading sy layer {0:3d}...".format(k + 1)) + print(f" loading sy layer {k + 1:3d}...") if "sy" not in par_types: t = Util2d.load( f, @@ -575,7 +565,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): # vkcb if model.get_package("DIS").laycbd[k] > 0: if model.verbose: - print(" loading vkcb layer {0:3d}...".format(k + 1)) + print(f" loading vkcb layer {k + 1:3d}...") if "vkcb" not in par_types: t = Util2d.load( f, @@ -631,7 +621,7 @@ def load(cls, f, model, ext_unit_dict=None, check=True): ) if check: upw.check( - f="{}.chk".format(upw.name[0]), + f=f"{upw.name[0]}.chk", verbose=upw.parent.verbose, level=0, ) diff --git a/dependencies/flopy/modflow/mfuzf1.py b/dependencies/flopy/modflow/mfuzf1.py index 42764d7..b29a757 100644 --- a/dependencies/flopy/modflow/mfuzf1.py +++ b/dependencies/flopy/modflow/mfuzf1.py @@ -7,14 +7,11 @@ `_. """ - -import sys import numpy as np from ..utils.flopy_io import pop_item, line_parse from ..pakbase import Package from ..utils import Util2d, Transient2d from ..utils.optionblock import OptionBlock -from collections import OrderedDict import warnings @@ -318,7 +315,7 @@ class ModflowUzf1(Package): """ - _options = OrderedDict( + _options = dict( [ ("specifythtr", OptionBlock.simple_flag), ("specifythti", OptionBlock.simple_flag), @@ -342,7 +339,7 @@ class ModflowUzf1(Package): OptionBlock.dtype: np.bool_, OptionBlock.nested: True, OptionBlock.n_nested: 2, - OptionBlock.vars: OrderedDict( + OptionBlock.vars: dict( [ ("unitrech", OptionBlock.simple_int), ("unitdis", OptionBlock.simple_int), @@ -450,7 +447,7 @@ def __init__( for key, value in uzgag.items(): fname = filenames[ipos] iu = abs(key) - uzgagext = "uzf{}.out".format(iu) + uzgagext = f"uzf{iu}.out" model.add_output_file( iu, fname=fname, @@ -490,24 +487,18 @@ def __init__( self.parent.get_package("RCH") != None or self.parent.get_package("EVT") != None ): - msg = ( + print( "WARNING!\n The RCH and EVT packages should not be " - + "active when the UZF1 package is active!" + "active when the UZF1 package is active!" ) - print(msg) if self.parent.version == "mf2000": - msg = ( + print( "WARNING!\nThe UZF1 package is only compatible " - + "with MODFLOW-2005 and MODFLOW-NWT!" + "with MODFLOW-2005 and MODFLOW-NWT!" ) - print(msg) nrow, ncol, nlay, nper = self.parent.nrow_ncol_nlay_nper - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "uzf_unsaturated_zone_flow_pack.htm" # Data Set 1a @@ -533,11 +524,10 @@ def __init__( try: float(etsquare) except: - msg = ( + print( "etsquare must be specified by entering a real " - + "number for smoothfact." + "number for smoothfact." ) - print(msg) self.etsquare = True self.smoothfact = etsquare self.netflux = False @@ -665,12 +655,10 @@ def __init__( def __setattr__(self, key, value): if key == "uzgag": - msg = ( - "Uzgag must be set by the constructor" - + "modifying this attribute requires creating a " - + "new ModflowUzf1 instance" + print( + "Uzgag must be set by the constructor modifying this " + "attribute requires creating a new ModflowUzf1 instance" ) - print(msg) else: super().__setattr__(key, value) @@ -739,7 +727,7 @@ def _write_1a(self, f_uzf): if self.nosurfleak > 0: specify_temp += "NOSURFLEAK" if (self.specifythtr + self.specifythti + self.nosurfleak) > 0: - f_uzf.write("{}\n".format(specify_temp)) + f_uzf.write(f"{specify_temp}\n") del specify_temp else: txt = "options\n" @@ -753,11 +741,11 @@ def _write_1a(self, f_uzf): ]: value = self.__dict__[var] if int(value) > 0: - txt += "{}\n".format(var) + txt += f"{var}\n" if self.etsquare: - txt += "etsquare {}\n".format(self.smoothfact) + txt += f"etsquare {self.smoothfact}\n" if self.netflux: - txt += "netflux {} {}\n".format(self.unitrech, self.unitdis) + txt += f"netflux {self.unitrech} {self.unitdis}\n" txt += "end\n" f_uzf.write(txt) @@ -779,7 +767,7 @@ def write_file(self, f=None): f_uzf = f else: f_uzf = open(self.fn_path, "w") - f_uzf.write("{}\n".format(self.heading)) + f_uzf.write(f"{self.heading}\n") # Dataset 1a if ( @@ -867,18 +855,18 @@ def write_file(self, f=None): comment = " #IUZROW IUZCOL IFTUNIT IUZOPT" values.insert(2, iftunit) for v in values: - f_uzf.write("{:10d}".format(v)) - f_uzf.write("{}\n".format(comment)) + f_uzf.write(f"{v:10d}") + f_uzf.write(f"{comment}\n") else: comment = " #IFTUNIT" - f_uzf.write("{:10d}".format(iftunit)) - f_uzf.write("{}\n".format(comment)) + f_uzf.write(f"{iftunit:10d}") + f_uzf.write(f"{comment}\n") def write_transient(name): invar, var = self.__dict__[name].get_kper_entry(n) - comment = " #{} for stress period ".format(name) + str(n + 1) - f_uzf.write("{0:10d}{1:20s}\n".format(invar, comment)) + comment = f" #{name} for stress period {n + 1}" + f_uzf.write(f"{invar:10d}{comment:20s}\n") if invar >= 0: f_uzf.write(var) @@ -929,7 +917,7 @@ def load(cls, f, model, ext_unit_dict=None, check=False): """ if model.verbose: - sys.stdout.write("loading uzf package file...\n") + print("loading uzf package file...") openfile = not hasattr(f, "read") if openfile: @@ -1019,7 +1007,7 @@ def load(cls, f, model, ext_unit_dict=None, check=False): } def load_util2d(name, dtype, per=None): - print(" loading {} array...".format(name)) + print(f" loading {name} array...") if per is not None: arrays[name][per] = Util2d.load( f, model, (nrow, ncol), dtype, name, ext_unit_dict @@ -1073,7 +1061,7 @@ def load_util2d(name, dtype, per=None): # dataset 9 for per in range(nper): - print("stress period {}:".format(per + 1)) + print(f"stress period {per + 1}:") line = line_parse(f.readline()) nuzf1 = pop_item(line, int) @@ -1178,7 +1166,7 @@ def load_util2d(name, dtype, per=None): unitnumber=unitnumber, filenames=filenames, options=options, - **arrays + **arrays, ) @staticmethod diff --git a/dependencies/flopy/modflow/mfwel.py b/dependencies/flopy/modflow/mfwel.py index 22fa8cc..8345da2 100644 --- a/dependencies/flopy/modflow/mfwel.py +++ b/dependencies/flopy/modflow/mfwel.py @@ -7,14 +7,11 @@ `_. """ - -import sys import numpy as np from ..utils import MfList from ..pakbase import Package from ..utils.recarray_utils import create_empty_recarray from ..utils.optionblock import OptionBlock -from collections import OrderedDict import warnings @@ -111,7 +108,7 @@ class ModflowWel(Package): """ - _options = OrderedDict( + _options = dict( [ ( "specify", @@ -119,12 +116,12 @@ class ModflowWel(Package): OptionBlock.dtype: np.bool_, OptionBlock.nested: True, OptionBlock.n_nested: 2, - OptionBlock.vars: OrderedDict( + OptionBlock.vars: dict( [ ("phiramp", OptionBlock.simple_float), ( "iunitramp", - OrderedDict( + dict( [ (OptionBlock.dtype, int), (OptionBlock.nested, False), @@ -198,11 +195,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "wel.htm" self.ipakcb = ipakcb @@ -252,7 +245,7 @@ def __init__( ladd = False break if ladd: - options.append("aux {} ".format(name)) + options.append(f"aux {name} ") if isinstance(self.options, OptionBlock): if not self.options.auxillary: @@ -267,30 +260,6 @@ def __init__( self.parent.add_package(self) - @property - def phiramp_unit(self): - """Get phiramp unit - - Returns - ------- - iunitramp: int - unit number of phiramp file - - """ - err = "phiramp_unit will be replaced " "with iunitramp for consistency" - warnings.warn(err, DeprecationWarning) - return self.iunitramp - - @phiramp_unit.setter - def phiramp_unit(self, phiramp_unit): - """Set phiramp unit - - Returns - ------- - - """ - self.iunitramp = phiramp_unit - def _ncells(self): """Maximum number of cells that have wells (developed for MT3DMS SSM package). @@ -323,7 +292,7 @@ def write_file(self, f=None): else: f_wel = open(self.fn_path, "w") - f_wel.write("%s\n" % self.heading) + f_wel.write(f"{self.heading}\n") if ( isinstance(self.options, OptionBlock) @@ -334,9 +303,7 @@ def write_file(self, f=None): if self.options.block: self.options.write_options(f_wel) - line = " {0:9d} {1:9d} ".format( - self.stress_period_data.mxact, self.ipakcb - ) + line = f" {self.stress_period_data.mxact:9d} {self.ipakcb:9d} " if isinstance(self.options, OptionBlock): if self.options.noprint: @@ -365,9 +332,7 @@ def write_file(self, f=None): else: if self.specify and self.parent.version == "mfnwt": f_wel.write( - "SPECIFY {0:10.5g} {1:10d}\n".format( - self.phiramp, self.iunitramp - ) + f"SPECIFY {self.phiramp:10.5g} {self.iunitramp:10d}\n" ) self.stress_period_data.write_transient(f_wel) @@ -377,7 +342,7 @@ def add_record(self, kper, index, values): try: self.stress_period_data.add_record(kper, index, values) except Exception as e: - raise Exception("mfwel error adding record to list: " + str(e)) + raise Exception(f"mfwel error adding record to list: {e!s}") @staticmethod def get_default_dtype(structured=True): @@ -443,7 +408,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None, check=True): """ if model.verbose: - sys.stdout.write("loading wel package file...\n") + print("loading wel package file...") return Package.load( f, diff --git a/dependencies/flopy/modflow/mfzon.py b/dependencies/flopy/modflow/mfzon.py index d6cc335..f9ba153 100644 --- a/dependencies/flopy/modflow/mfzon.py +++ b/dependencies/flopy/modflow/mfzon.py @@ -7,8 +7,6 @@ `_. """ -import sys -import collections import numpy as np from ..pakbase import Package from ..utils import Util2d @@ -103,11 +101,7 @@ def __init__( filenames=fname, ) - self.heading = ( - "# {} package for ".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() self.url = "zone.htm" self.nzn = 0 @@ -170,7 +164,7 @@ def load(cls, f, model, nrow=None, ncol=None, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading zone package file...\n") + print("loading zone package file...") openfile = not hasattr(f, "read") if openfile: @@ -191,7 +185,7 @@ def load(cls, f, model, nrow=None, ncol=None, ext_unit_dict=None): nrow, ncol, nlay, nper = model.get_nrow_ncol_nlay_nper() # read zone data - zone_dict = collections.OrderedDict() + zone_dict = {} for n in range(nzn): line = f.readline() t = line.strip().split() @@ -200,9 +194,7 @@ def load(cls, f, model, nrow=None, ncol=None, ext_unit_dict=None): else: zonnam = t[0].lower() if model.verbose: - sys.stdout.write( - ' reading data for "{:<10s}" zone\n'.format(zonnam) - ) + print(f' reading data for "{zonnam:<10s}" zone') # load data t = Util2d.load( f, model, (nrow, ncol), np.int32, zonnam, ext_unit_dict diff --git a/dependencies/flopy/modflowlgr/mflgr.py b/dependencies/flopy/modflowlgr/mflgr.py index 360a5ae..2d4dd24 100644 --- a/dependencies/flopy/modflowlgr/mflgr.py +++ b/dependencies/flopy/modflowlgr/mflgr.py @@ -5,7 +5,6 @@ """ import os -import sys from ..mbase import BaseModel from ..modflow import Modflow @@ -124,7 +123,7 @@ def __init__( model_ws=".", external_path=None, verbose=False, - **kwargs + **kwargs, ): super().__init__( modelname, @@ -133,7 +132,7 @@ def __init__( model_ws, structured=True, verbose=verbose, - **kwargs + **kwargs, ) self.version_types = {"mflgr": "MODFLOW-LGR"} @@ -183,11 +182,7 @@ def __init__( if external_path is not None: if os.path.exists(os.path.join(model_ws, external_path)): - print( - "Note: external_path " - + str(external_path) - + " already exists" - ) + print(f"Note: external_path {external_path} already exists") else: os.makedirs(os.path.join(model_ws, external_path)) self.external_path = external_path @@ -195,7 +190,7 @@ def __init__( return def __repr__(self): - return "MODFLOW-LGR model with {} grids".format(self.ngrids) + return f"MODFLOW-LGR model with {self.ngrids} grids" @property def ngrids(self): @@ -240,10 +235,10 @@ def write_input(self, SelPackList=False, check=False): def _padline(self, line, comment=None, line_len=79): if len(line) < line_len: - fmt = "{:" + "{}".format(line_len) + "s}" + fmt = "{:" + str(line_len) + "s}" line = fmt.format(line) if comment is not None: - line += " # {}\n".format(comment) + line += f" # {comment}\n" return line def _get_path(self, bpth, pth, fpth=""): @@ -256,11 +251,11 @@ def _get_path(self, bpth, pth, fpth=""): rpth = os.path.join(rpth, fpth) msg = ( "namefiles must be in the same directory as " - + "the lgr control file\n" + "the lgr control file\n" ) - msg += "Control file path: {}\n".format(lpth) - msg += "Namefile path: {}\n".format(mpth) - msg += "Relative path: {}\n".format(rpth) + msg += f"Control file path: {lpth}\n" + msg += f"Namefile path: {mpth}\n" + msg += f"Relative path: {rpth}\n" raise ValueError(msg) return rpth @@ -294,14 +289,14 @@ def write_name_file(self): """ fn_path = os.path.join(self.model_ws, self.namefile) f = open(fn_path, "w") - f.write("{}\n".format(self.heading)) + f.write(f"{self.heading}\n") # dataset 1 line = self._padline("LGR", comment="data set 1") f.write(line) # dataset 2 - line = "{}".format(self.ngrids) + line = str(self.ngrids) line = self._padline(line, comment="data set 2 - ngridsS") f.write(line) @@ -317,7 +312,7 @@ def write_name_file(self): f.write(line) # dataset 5 - line = "{} {}".format(self.iupbhsv, self.iupbfsv) + line = f"{self.iupbhsv} {self.iupbfsv}" line = self._padline(line, comment="data set 5 - iupbhsv, iupbfsv") f.write(line) @@ -329,12 +324,12 @@ def write_name_file(self): pth = self._get_path( self._model_ws, child._model_ws, fpth=child.namefile ) - comment = "data set 6 - child {} namefile".format(idx + 1) + comment = f"data set 6 - child {idx + 1} namefile" line = self._padline(pth, comment=comment) f.write(line) # dataset 7 - comment = "data set 7 - child {} gridstatus".format(idx + 1) + comment = f"data set 7 - child {idx + 1} gridstatus" line = self._padline("CHILDONLY", comment=comment) f.write(line) @@ -346,34 +341,26 @@ def write_name_file(self): child_data.iucbfsv, ) comment = ( - "data set 8 - child {} ".format(idx + 1) - + "ishflg, ibflg, iucbhsv, iucbfsv" + f"data set 8 - child {idx + 1} ishflg, ibflg, iucbhsv, iucbfsv" ) line = self._padline(line, comment=comment) f.write(line) # dataset 9 - line = "{} {}".format(child_data.mxlgriter, child_data.ioutlgr) - comment = ( - "data set 9 - child {} ".format(idx + 1) + "mxlgriter, ioutlgr" - ) + line = f"{child_data.mxlgriter} {child_data.ioutlgr}" + comment = f"data set 9 - child {idx + 1} mxlgriter, ioutlgr" line = self._padline(line, comment=comment) f.write(line) # dataset 10 - line = "{} {}".format(child_data.relaxh, child_data.relaxf) - comment = ( - "data set 10 - child {} ".format(idx + 1) + "relaxh, relaxf" - ) + line = f"{child_data.relaxh} {child_data.relaxf}" + comment = f"data set 10 - child {idx + 1} relaxh, relaxf" line = self._padline(line, comment=comment) f.write(line) # dataset 11 - line = "{} {}".format(child_data.hcloselgr, child_data.fcloselgr) - comment = ( - "data set 11 - child {} ".format(idx + 1) - + "hcloselgr, fcloselgr" - ) + line = f"{child_data.hcloselgr} {child_data.fcloselgr}" + comment = f"data set 11 - child {idx + 1} hcloselgr, fcloselgr" line = self._padline(line, comment=comment) f.write(line) @@ -383,10 +370,7 @@ def write_name_file(self): child_data.nprbeg + 1, child_data.npcbeg + 1, ) - comment = ( - "data set 12 - child {} ".format(idx + 1) - + "nplbeg, nprbeg, npcbeg" - ) + comment = f"data set 12 - child {idx + 1} nplbeg, nprbeg, npcbeg" line = self._padline(line, comment=comment) f.write(line) @@ -396,24 +380,21 @@ def write_name_file(self): child_data.nprend + 1, child_data.npcend + 1, ) - comment = ( - "data set 13 - child {} ".format(idx + 1) - + "nplend, nprend, npcend" - ) + comment = f"data set 13 - child {idx + 1} nplend, nprend, npcend" line = self._padline(line, comment=comment) f.write(line) # dataset 14 - line = "{}".format(child_data.ncpp) - comment = "data set 14 - child {} ".format(idx + 1) + "ncpp" + line = str(child_data.ncpp) + comment = f"data set 14 - child {idx + 1} ncpp" line = self._padline(line, comment=comment) f.write(line) # dataset 15 line = "" for ndx in child_data.ncppl: - line += "{} ".format(ndx) - comment = "data set 15 - child {} ".format(idx + 1) + "ncppl" + line += f"{ndx} " + comment = f"data set 15 - child {idx + 1} ncppl" line = self._padline(line, comment=comment) f.write(line) @@ -443,21 +424,20 @@ def change_model_ws(self, new_pth=None, reset_external=False): new_pth = os.getcwd() if not os.path.exists(new_pth): try: - sys.stdout.write( - "\ncreating model workspace...\n {}\n".format(new_pth) - ) + print(f"\ncreating model workspace...\n {new_pth}") os.makedirs(new_pth) except: - line = "\n{} not valid, workspace-folder ".format( - new_pth - ) + "was changed to {}\n".format(os.getcwd()) - print(line) + not_valid = new_pth new_pth = os.getcwd() + print( + "\n{} not valid, workspace-folder was changed to {}" + "\n".format(not_valid, new_pth) + ) # --reset the model workspace old_pth = self._model_ws self._model_ws = new_pth - line = "\nchanging model workspace...\n {}\n".format(new_pth) - sys.stdout.write(line) + if self.verbose: + print(f"\nchanging model workspace...\n {new_pth}") # reset model_ws for the parent lpth = os.path.abspath(old_pth) @@ -545,7 +525,7 @@ def load( # dataset 1 ds1 = line.split()[0].lower() msg = "LGR must be entered as the first item in dataset 1\n" - msg += " {}\n".format(header) + msg += f" {header}\n" assert ds1 == "lgr", msg # dataset 2 @@ -580,12 +560,10 @@ def load( # non-zero values for IUPBHSV and IUPBFSV in dataset 5 are not # supported if iupbhsv + iupbfsv > 0: - msg = ( - "nonzero values for IUPBHSV () ".format(iupbhsv) - + "and IUPBFSV ({}) ".format(iupbfsv) - + "are not supported." + raise ValueError( + "nonzero values for IUPBHSV ({}) and IUPBFSV ({}) are not " + "supported.".format(iupbhsv, iupbfsv) ) - raise ValueError(msg) # load the parent model parent = Modflow.load( diff --git a/dependencies/flopy/modpath/mp6.py b/dependencies/flopy/modpath/mp6.py index 1bda65c..87e7c11 100644 --- a/dependencies/flopy/modpath/mp6.py +++ b/dependencies/flopy/modpath/mp6.py @@ -99,8 +99,8 @@ def __init__( self.__mf = modflowmodel self.lst = Modpath6List(self, listunit=listunit) - self.mpnamefile = "{}.{}".format(self.name, namefile_ext) - self.mpbas_file = "{}.mpbas".format(modelname) + self.mpnamefile = f"{self.name}.{namefile_ext}" + self.mpbas_file = f"{modelname}.mpbas" if self.__mf is not None: # ensure that user-specified files are used iu = self.__mf.oc.iuhead @@ -111,11 +111,10 @@ def __init__( if p is None: p = self.__mf.get_package("UPW") if p is None: - msg = ( + raise Exception( "LPF, BCF6, or UPW packages must be included in the " - + "passed MODFLOW model" + "passed MODFLOW model" ) - raise Exception(msg) iu = p.ipakcb budget_file = self.__mf.get_output(unit=iu) dis_file = ( @@ -128,23 +127,20 @@ def __init__( self.dis_unit = dis_unit # make sure the valid files are available if self.head_file is None: - msg = ( + raise ValueError( "the head file in the MODFLOW model or passed " - + "to __init__ cannot be None" + "to __init__ cannot be None" ) - raise ValueError(msg) if self.budget_file is None: - msg = ( + raise ValueError( "the budget file in the MODFLOW model or passed " - + "to __init__ cannot be None" + "to __init__ cannot be None" ) - raise ValueError(msg) if self.dis_file is None: - msg = ( + raise ValueError( "the dis file in the MODFLOW model or passed " - + "to __init__ cannot be None" + "to __init__ cannot be None" ) - raise ValueError(msg) # set the rest of the attributes self.__sim = None @@ -193,17 +189,17 @@ def write_name_file(self): """ fn_path = os.path.join(self.model_ws, self.mpnamefile) f_nam = open(fn_path, "w") - f_nam.write("%s\n" % (self.heading)) + f_nam.write(f"{self.heading}\n") if self.mpbas_file is not None: - f_nam.write("%s %3i %s\n" % ("MPBAS", 86, self.mpbas_file)) + f_nam.write(f"MPBAS 86 {self.mpbas_file}\n") if self.dis_file is not None: - f_nam.write("%s %3i %s\n" % ("DIS", self.dis_unit, self.dis_file)) + f_nam.write(f"DIS {self.dis_unit:3} {self.dis_file}\n") if self.head_file is not None: - f_nam.write("%s %3i %s\n" % ("HEAD", 88, self.head_file)) + f_nam.write(f"HEAD 88 {self.head_file}\n") if self.budget_file is not None: - f_nam.write("%s %3i %s\n" % ("BUDGET", 89, self.budget_file)) + f_nam.write(f"BUDGET 89 {self.budget_file}\n") for u, f in zip(self.external_units, self.external_fnames): - f_nam.write("DATA {0:3d} ".format(u) + f + "\n") + f_nam.write(f"DATA {u:3d} {f}\n") f_nam.close() sim = property(getsim) # Property has no setter, so read-only @@ -327,7 +323,7 @@ def create_mpsim( for j in range(ncol): if arr[k, i, j] < 1: continue - group_name.append("wc{}".format(icnt)) + group_name.append(f"wc{icnt}") group_placement.append( [ Grid, @@ -368,7 +364,7 @@ def append_node(ifaces_well, wellid, node_number, k, i, j): else: ifaces.append(default_ifaces) face_ct.append(len(default_ifaces)) - group_name.append("{}{}".format(wellid, node_number)) + group_name.append(f"{wellid}{node_number}") group_placement.append( [ Grid, @@ -442,15 +438,13 @@ def append_node(ifaces_well, wellid, node_number, k, i, j): "detected a particle starting locations file in packages" ) assert len(packages) == 1, ( - "if a particle starting locations file is passed" - + ", other packages cannot be specified" + "if a particle starting locations file is passed, " + "other packages cannot be specified" ) ParticleGenerationOption = 2 strt_file = package else: - raise Exception( - "package '{0}' not supported".format(package) - ) + raise Exception(f"package '{package}' not supported") SimulationType = 1 if simtype.lower() == "endpoint": diff --git a/dependencies/flopy/modpath/mp6bas.py b/dependencies/flopy/modpath/mp6bas.py index 829bca4..9e682c6 100644 --- a/dependencies/flopy/modpath/mp6bas.py +++ b/dependencies/flopy/modpath/mp6bas.py @@ -137,13 +137,13 @@ def write_file(self): ModflowDis = self.parent.mf.get_package("DIS") # Open file for writing f_bas = open(self.fn_path, "w") - f_bas.write("#{0:s}\n#{1:s}\n".format(self.heading1, self.heading2)) - f_bas.write("{0:16.6f} {1:16.6f}\n".format(self.hnoflo, self.hdry)) - f_bas.write("{0:4d}\n".format(self.def_face_ct)) + f_bas.write(f"#{self.heading1}\n#{self.heading2}\n") + f_bas.write(f"{self.hnoflo:16.6f} {self.hdry:16.6f}\n") + f_bas.write(f"{self.def_face_ct:4d}\n") if self.def_face_ct > 0: for i in range(self.def_face_ct): - f_bas.write("{0:20s}\n".format(self.bud_label[i])) - f_bas.write("{0:2d}\n".format(self.def_iface[i])) + f_bas.write(f"{self.bud_label[i]:20s}\n") + f_bas.write(f"{self.def_iface[i]:2d}\n") # f_bas.write('\n') flow_package = self.parent.mf.get_package("BCF6") diff --git a/dependencies/flopy/modpath/mp6sim.py b/dependencies/flopy/modpath/mp6sim.py index 5630896..15c34e7 100644 --- a/dependencies/flopy/modpath/mp6sim.py +++ b/dependencies/flopy/modpath/mp6sim.py @@ -88,8 +88,8 @@ def __init__( self.heading1 = "# MPSIM for Modpath, generated by Flopy." self.heading2 = "#" - self.mp_name_file = "{}.{}".format(model.name, "mpnam") - self.mp_list_file = "{}.{}".format(model.name, "mplst") + self.mp_name_file = f"{model.name}.mpnam" + self.mp_list_file = f"{model.name}.mplst" options_list = [ "SimulationType", "TrackingDirection", @@ -107,10 +107,10 @@ def __init__( self.option_flags = option_flags options_dict = dict(list(zip(options_list, option_flags))) self.options_dict = options_dict - self.endpoint_file = "{}.{}".format(model.name, "mpend") - self.pathline_file = "{}.{}".format(model.name, "mppth") - self.time_ser_file = "{}.{}".format(model.name, "mp.tim_ser") - self.advobs_file = "{}.{}".format(model.name, ".mp.advobs") + self.endpoint_file = f"{model.name}.mpend" + self.pathline_file = f"{model.name}.mppth" + self.time_ser_file = f"{model.name}.mp.tim_ser" + self.advobs_file = f"{model.name}.mp.advobs" self.ref_time = ref_time self.ref_time_per_stp = ref_time_per_stp self.stop_time = stop_time @@ -125,7 +125,7 @@ def __init__( self.face_ct = face_ct self.ifaces = ifaces self.part_ct = part_ct - self.strt_file = "{}.{}".format(model.name, "loc") + self.strt_file = f"{model.name}.loc" if strt_file is not None: self.strt_file = strt_file self.time_ct = time_ct @@ -134,7 +134,7 @@ def __init__( self.particle_cell_cnt = particle_cell_cnt self.cell_bd_ct = cell_bd_ct self.bud_loc = bud_loc - self.trace_file = "{}.{}".format(model.name, "trace_file.txt") + self.trace_file = f"{model.name}.trace_file.txt" self.trace_id = trace_id self.stop_zone = stop_zone self.zone = Util3d( @@ -218,53 +218,49 @@ def write_file(self): f_sim = open(self.fn_path, "w") # item 0 - f_sim.write("#{0:s}\n#{1:s}\n".format(self.heading1, self.heading2)) + f_sim.write(f"#{self.heading1}\n#{self.heading2}\n") # item 1 - f_sim.write("{0:s}\n".format(self.mp_name_file)) + f_sim.write(f"{self.mp_name_file}\n") # item 2 - f_sim.write("{0:s}\n".format(self.mp_list_file)) + f_sim.write(f"{self.mp_list_file}\n") # item 3 for i in range(12): - f_sim.write("{0:4d}".format(self.option_flags[i])) + f_sim.write(f"{self.option_flags[i]:4d}") f_sim.write("\n") # item 4 - f_sim.write("{0:s}\n".format(self.endpoint_file)) + f_sim.write(f"{self.endpoint_file}\n") # item 5 if self.options_dict["SimulationType"] == 2: - f_sim.write("{0:s}\n".format(self.pathline_file)) + f_sim.write(f"{self.pathline_file}\n") # item 6 if self.options_dict["SimulationType"] == 3: - f_sim.write("{0:s}\n".format(self.time_ser_file)) + f_sim.write(f"{self.time_ser_file}\n") # item 7 if ( self.options_dict["AdvectiveObservationsOption"] == 2 and self.option_dict["SimulationType"] == 3 ): - f_sim.write("{0:s}\n".format(self.advobs_file)) + f_sim.write(f"{self.advobs_file}\n") # item 8 if self.options_dict["ReferenceTimeOption"] == 1: - f_sim.write("{0:f}\n".format(self.ref_time)) + f_sim.write(f"{self.ref_time:f}\n") # item 9 if self.options_dict["ReferenceTimeOption"] == 2: Period, Step, TimeFraction = self.ref_time_per_stp - f_sim.write( - "{0:d} {1:d} {2:f}\n".format( - Period + 1, Step + 1, TimeFraction - ) - ) + f_sim.write(f"{Period + 1} {Step + 1} {TimeFraction:f}\n") # item 10 if self.options_dict["StopOption"] == 3: - f_sim.write("{0:f}\n".format(self.stop_time)) + f_sim.write(f"{self.stop_time:f}\n") if self.options_dict["ParticleGenerationOption"] == 1: # item 11 - f_sim.write("{0:d}\n".format(self.group_ct)) + f_sim.write(f"{self.group_ct}\n") for i in range(self.group_ct): # item 12 - f_sim.write("{0:s}\n".format(self.group_name[i])) + f_sim.write(f"{self.group_name[i]}\n") # item 13 ( Grid, @@ -291,9 +287,7 @@ def write_file(self): ReleaseEventCount, ) = self.release_times[i] f_sim.write( - "{0:f} {1:d}\n".format( - ReleasePeriodLength, ReleaseEventCount - ) + f"{ReleasePeriodLength:f} {ReleaseEventCount}\n" ) # item 15 if GridCellRegionOption == 1: @@ -320,12 +314,12 @@ def write_file(self): f_sim.write(self.mask_nlay[i].get_file_entry()) # item 17 if GridCellRegionOption == 3: - f_sim.write("{0:s}\n".format(self.mask_layer[i])) + f_sim.write(f"{self.mask_layer[i]}\n") # item 18 f_sim.write(self.mask_1lay[i].get_file_entry()) # item 19 and 20 if PlacementOption == 1: - f_sim.write("{0:d}\n".format(self.face_ct[i])) + f_sim.write(f"{self.face_ct[i]}\n") # item 20 for j in range(self.face_ct[i]): ( @@ -334,9 +328,7 @@ def write_file(self): ParticleColumnCount, ) = self.ifaces[i][j] f_sim.write( - "{0:d} {1:d} {2:d} \n".format( - IFace, ParticleRowCount, ParticleColumnCount - ) + f"{IFace} {ParticleRowCount} {ParticleColumnCount}\n" ) # item 21 elif PlacementOption == 2: @@ -355,7 +347,7 @@ def write_file(self): # item 22 if self.options_dict["ParticleGenerationOption"] == 2: - f_sim.write("{0:s}\n".format(self.strt_file)) + f_sim.write(f"{self.strt_file}\n") if self.options_dict["TimePointOption"] != 1: # item 23 @@ -363,14 +355,14 @@ def write_file(self): self.options_dict["TimePointOption"] == 2 or self.options_dict["TimePointOption"] == 3 ): - f_sim.write("{0:d}\n".format(self.time_ct)) + f_sim.write(f"{self.time_ct}\n") # item 24 if self.options_dict["TimePointOption"] == 2: - f_sim.write("{0:f}\n".format(self.release_time_incr)) + f_sim.write(f"{self.release_time_incr:f}\n") # item 25 if self.options_dict["TimePointOption"] == 3: for r in range(self.time_ct): - f_sim.write("{0:f}\n".format(self.time_pts[r])) + f_sim.write(f"{self.time_pts[r]:f}\n") if ( self.options_dict["BudgetOutputOption"] != 1 @@ -378,24 +370,22 @@ def write_file(self): ): # item 26 if self.options_dict["BudgetOutputOption"] == 3: - f_sim.write("{0:d}\n".format(self.cell_bd_ct)) + f_sim.write(f"{self.cell_bd_ct}\n") # item 27 for k in range(self.cell_bd_ct): Grid, Layer, Row, Column = self.bud_loc[k] f_sim.write( - "{0:d} {1:d} {2:d} {3:d} \n".format( - Grid, Layer + 1, Row + 1, Column + 1 - ) + f"{Grid} {Layer + 1} {Row + 1} {Column + 1} \n" ) if self.options_dict["BudgetOutputOption"] == 4: # item 28 - f_sim.write("{0:s}\n".format(self.trace_file)) + f_sim.write(f"{self.trace_file}\n") # item 29 - f_sim.write("{0:s}\n".format(self.trace_id)) + f_sim.write(f"{self.trace_id}\n") if self.options_dict["ZoneArrayOption"] != 1: # item 30 - f_sim.write("{0:d}\n".format(self.stop_zone)) + f_sim.write(f"{self.stop_zone}\n") # item 31 f_sim.write(self.zone.get_file_entry()) @@ -500,18 +490,18 @@ def write_file(self, data=None, float_format="{:.8f}"): data["i0"] += 1 data["j0"] += 1 with open(self.fn_path, "w") as output: - output.write("{}\n".format(self.heading)) - output.write("{:d}\n".format(self.input_style)) + output.write(f"{self.heading}\n") + output.write(f"{self.input_style}\n") groups = np.unique(data.groupname) ngroups = len(groups) - output.write("{:d}\n".format(ngroups)) + output.write(f"{ngroups}\n") for g in groups: npt = len(data[data.groupname == g]) - output.write("{}\n{:d}\n".format(g.decode(), npt)) + output.write(f"{g.decode()}\n{npt}\n") txt = "" for p in data: txt += "{:d} {:d} {:d} {:d} {:d} {:d}".format(*list(p)[:6]) fmtstr = " {0} {0} {0} {0} ".format(float_format) txt += fmtstr.format(*list(p)[6:10]) - txt += "{}\n".format(p[10].decode()) + txt += f"{p[10].decode()}\n" output.write(txt) diff --git a/dependencies/flopy/modpath/mp7.py b/dependencies/flopy/modpath/mp7.py index 2a340a0..d940403 100644 --- a/dependencies/flopy/modpath/mp7.py +++ b/dependencies/flopy/modpath/mp7.py @@ -108,16 +108,15 @@ def __init__( self.lst = Modpath7List(self) - self.mpnamefile = "{}.{}".format(self.name, namefile_ext) - self.mpbas_file = "{}.mpbas".format(modelname) + self.mpnamefile = f"{self.name}.{namefile_ext}" + self.mpbas_file = f"{modelname}.mpbas" if not isinstance(flowmodel, (Modflow, MFModel)): - msg = ( + raise TypeError( "Modpath7: flow model is not an instance of " - + "flopy.modflow.Modflow or flopy.mf6.MFModel. " - + "Passed object of type {}".format(type(flowmodel)) + "flopy.modflow.Modflow or flopy.mf6.MFModel. " + "Passed object of type {}".format(type(flowmodel)) ) - raise TypeError(msg) # if a MFModel instance ensure flowmodel is a MODFLOW 6 GWF model if isinstance(flowmodel, MFModel): @@ -125,11 +124,10 @@ def __init__( flowmodel.model_type != "gwf" and flowmodel.model_type != "gwf6" ): - msg = ( + raise TypeError( "Modpath7: flow model type must be gwf. " - + "Passed model_type is {}.".format(flowmodel.model_type) + "Passed model_type is {}.".format(flowmodel.model_type) ) - raise TypeError(msg) # set flowmodel and flow_version attributes self.flowmodel = flowmodel @@ -140,11 +138,10 @@ def __init__( ibound = None dis = self.flowmodel.get_package("DIS") if dis is None: - msg = ( + raise Exception( "DIS, DISV, or DISU packages must be " - + "included in the passed MODFLOW 6 model" + "included in the passed MODFLOW 6 model" ) - raise Exception(msg) else: if dis.package_name.lower() == "dis": nlay, nrow, ncol = ( @@ -162,20 +159,18 @@ def __init__( nodes, ) else: - msg = ( + raise TypeError( "DIS, DISV, or DISU packages must be " - + "included in the passed MODFLOW 6 model" + "included in the passed MODFLOW 6 model" ) - raise TypeError(msg) # terminate (for now) if mf6 model does not use dis or disv if len(shape) < 2: - msg = ( + raise TypeError( "DIS and DISV are currently the only supported " - + "MODFLOW 6 discretization packages that can be " - + "used with MODPATH 7" + "MODFLOW 6 discretization packages that can be " + "used with MODPATH 7" ) - raise TypeError(msg) # set ib ib = dis.idomain.array @@ -185,16 +180,15 @@ def __init__( # set dis and grbdis file name dis_file = None - grbdis_file = dis.filename + ".grb" - grbtag = "GRB{}".format(dis.package_name.upper()) + grbdis_file = f"{dis.filename}.grb" + grbtag = f"GRB{dis.package_name.upper()}" tdis = self.flowmodel.simulation.get_package("TDIS") if tdis is None: - msg = ( + raise Exception( "TDIS package must be " - + "included in the passed MODFLOW 6 model" + "included in the passed MODFLOW 6 model" ) - raise Exception(msg) tdis_file = tdis.filename # get stress period data @@ -230,23 +224,20 @@ def __init__( nlay, nrow, ncol = dis.nlay, dis.nrow, dis.ncol shape = (nlay, nrow, ncol) if dis is None: - msg = ( + raise Exception( "DIS, or DISU packages must be " - + "included in the passed MODFLOW model" + "included in the passed MODFLOW model" ) - raise Exception(msg) elif dis is not None and shape is None: nlay, nodes = dis.nlay, dis.nodes shape = (nodes,) # terminate (for now) if mf6 model does not use dis if len(shape) != 3: - msg = ( + raise Exception( "DIS currently the only supported MODFLOW " - + "discretization package that can be used with " - + "MODPATH 7" + "discretization package that can be used with MODPATH 7" ) - raise Exception(msg) # get stress period data nper = dis.nper @@ -275,11 +266,10 @@ def __init__( if p is None: p = self.flowmodel.get_package("UPW") if p is None: - msg = ( + raise Exception( "LPF, BCF6, or UPW packages must be " - + "included in the passed MODFLOW model" + "included in the passed MODFLOW model" ) - raise Exception(msg) # set budget file name if budgetfilename is None: @@ -318,23 +308,20 @@ def __init__( # make sure the valid files are available if self.headfilename is None: - msg = ( + raise ValueError( "the head file in the MODFLOW model or passed " - + "to __init__ cannot be None" + "to __init__ cannot be None" ) - raise ValueError(msg) if self.budgetfilename is None: - msg = ( + raise ValueError( "the budget file in the MODFLOW model or passed " - + "to __init__ cannot be None" + "to __init__ cannot be None" ) - raise ValueError(msg) if self.dis_file is None and self.grbdis_file is None: - msg = ( + raise ValueError( "the dis file in the MODFLOW model or passed " - + "to __init__ cannot be None" + "to __init__ cannot be None" ) - raise ValueError(msg) # set ib and ibound self.ib = ib @@ -391,19 +378,19 @@ def write_name_file(self): """ fpth = os.path.join(self.model_ws, self.mpnamefile) f = open(fpth, "w") - f.write("{}\n".format(self.heading)) + f.write(f"{self.heading}\n") if self.mpbas_file is not None: - f.write("{:10s} {}\n".format("MPBAS", self.mpbas_file)) + f.write(f"MPBAS {self.mpbas_file}\n") if self.dis_file is not None: - f.write("{:10s} {}\n".format("DIS", self.dis_file)) + f.write(f"DIS {self.dis_file}\n") if self.grbdis_file is not None: - f.write("{:10s} {}\n".format(self.grbtag, self.grbdis_file)) + f.write(f"{self.grbtag:10s} {self.grbdis_file}\n") if self.tdis_file is not None: - f.write("{:10s} {}\n".format("TDIS", self.tdis_file)) + f.write(f"TDIS {self.tdis_file}\n") if self.headfilename is not None: - f.write("{:10s} {}\n".format("HEAD", self.headfilename)) + f.write(f"HEAD {self.headfilename}\n") if self.budgetfilename is not None: - f.write("{:10s} {}\n".format("BUDGET", self.budgetfilename)) + f.write(f"BUDGET {self.budgetfilename}\n") f.close() @classmethod diff --git a/dependencies/flopy/modpath/mp7bas.py b/dependencies/flopy/modpath/mp7bas.py index c766e62..f47b424 100644 --- a/dependencies/flopy/modpath/mp7bas.py +++ b/dependencies/flopy/modpath/mp7bas.py @@ -56,11 +56,7 @@ def __init__( else: shape3d = (1, 1, shape[0]) - self.heading = ( - "# {} package for".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() if model.flowmodel.version == "mf6": self.laytyp = Util2d( @@ -104,21 +100,18 @@ def __init__( defaultifacecount = 0 else: if not isinstance(defaultiface, dict): - msg = ( + raise ValueError( "defaultiface must be a dictionary with package " - + "name keys and values between 0 and 6" + "name keys and values between 0 and 6" ) - raise ValueError(msg) defaultifacecount = len(defaultiface.keys()) for key, value in defaultiface.items(): # check iface value if value < 0 or value > 6: - msg = ( - "defaultiface for package {}".format(key) - + "must be between 0 and 1 " - + "({} specified)".format(value) + raise ValueError( + "defaultiface for package {} must be between 0 and 1 " + "({} specified)".format(key, value) ) - raise ValueError(msg) self.defaultifacecount = defaultifacecount self.defaultiface = defaultiface @@ -141,18 +134,16 @@ def write_file(self, check=False): """ # Open file for writing f = open(self.fn_path, "w") - f.write("# {}\n".format(self.heading)) + f.write(f"# {self.heading}\n") if self.parent.flowmodel.version != "mf6": - f.write("{:g} {:g}\n".format(self.parent.hnoflo, self.parent.hdry)) + f.write(f"{self.parent.hnoflo:g} {self.parent.hdry:g}\n") # default IFACE - f.write( - "{:<20d}{}\n".format(self.defaultifacecount, "# DEFAULTIFACECOUNT") - ) + f.write(f"{self.defaultifacecount:<20d}# DEFAULTIFACECOUNT\n") if self.defaultifacecount > 0: for key, value in self.defaultiface.items(): - f.write("{:20s}{}\n".format(key, "# PACKAGE LABEL")) - f.write("{:<20d}{}\n".format(value, "# DEFAULT IFACE VALUE")) + f.write(f"{key:20s}# PACKAGE LABEL\n") + f.write(f"{value:<20d}# DEFAULT IFACE VALUE\n") # laytyp if self.parent.flow_version != "mf6": diff --git a/dependencies/flopy/modpath/mp7particledata.py b/dependencies/flopy/modpath/mp7particledata.py index 6962751..d63c666 100644 --- a/dependencies/flopy/modpath/mp7particledata.py +++ b/dependencies/flopy/modpath/mp7particledata.py @@ -125,18 +125,16 @@ def __init__( if alllsttup: alllen3 = all(len(el) == 3 for el in partlocs) if not alllen3: - msg = ( - "{}: all partlocs entries ".format(self.name) - + " must have 3 items for structured particle data" + raise ValueError( + "{}: all partlocs entries must have 3 items for " + "structured particle data".format(self.name) ) - raise ValueError(msg) else: - msg = ( - "{}: partlocs list or tuple ".format(self.name) - + "for structured particle data should " - + "contain list or tuple entries" + raise ValueError( + "{}: partlocs list or tuple " + "for structured particle data should " + "contain list or tuple entries".format(self.name) ) - raise ValueError(msg) else: allint = all( isinstance(el, (int, np.int32, np.int64)) @@ -154,19 +152,16 @@ def __init__( if alllsttup: alllen1 = all(len(el) == 1 for el in partlocs) if not alllen1: - msg = ( - "{}: all entries of ".format(self.name) - + "partlocs must have 1 items " - + "for unstructured particle data" + raise ValueError( + "{}: all entries of partlocs must have 1 items " + "for unstructured particle data".format(self.name) ) - raise ValueError(msg) else: - msg = ( - "{}: partlocs list or tuple ".format(self.name) - + "for unstructured particle data should " - + "contain integers or a list or tuple with one entry" + raise ValueError( + "{}: partlocs list or tuple for unstructured particle " + "data should contain integers or a list or tuple with " + "one entry".format(self.name) ) - raise ValueError(msg) # convert partlocs composed of a lists/tuples of lists/tuples # to a numpy array @@ -176,11 +171,9 @@ def __init__( if dtypein != dtype: partlocs = np.array(partlocs, dtype=dtype) else: - msg = ( - "{}: partlocs must be a list or ".format(self.name) - + "tuple with lists or tuples" + raise ValueError( + f"{self.name}: partlocs must be a list or tuple with lists or tuples" ) - raise ValueError(msg) # localx if localx is None: @@ -192,13 +185,12 @@ def __init__( localx = np.array(localx, dtype=np.float32) if isinstance(localx, np.ndarray): if localx.shape[0] != partlocs.shape[0]: - msg = ( - "{}:".format(self.name) - + "shape of localx ({}) ".format(localx.shape[0]) - + "is not equal to the shape " - + "of partlocs ({}).".format(partlocs.shape[0]) + raise ValueError( + "{}:shape of localx ({}) is not equal to the shape " + "of partlocs ({}).".format( + self.name, localx.shape[0], partlocs.shape[0] + ) ) - raise ValueError(msg) # localy if localy is None: @@ -210,13 +202,12 @@ def __init__( localy = np.array(localy, dtype=np.float32) if isinstance(localy, np.ndarray): if localy.shape[0] != partlocs.shape[0]: - msg = ( - "{}:".format(self.name) - + "shape of localy ({}) ".format(localy.shape[0]) - + "is not equal to the shape " - + "of partlocs ({}).".format(partlocs.shape[0]) + raise ValueError( + "{}:shape of localy ({}) is not equal to the shape " + "of partlocs ({}).".format( + self.name, localy.shape[0], partlocs.shape[0] + ) ) - raise ValueError(msg) # localz if localz is None: @@ -228,13 +219,12 @@ def __init__( localz = np.array(localz, dtype=np.float32) if isinstance(localz, np.ndarray): if localz.shape[0] != partlocs.shape[0]: - msg = ( - "{}:".format(self.name) - + "shape of localz ({}) ".format(localz.shape[0]) - + "is not equal to the shape " - + "of partlocs ({}).".format(partlocs.shape[0]) + raise ValueError( + "{}:shape of localz ({}) is not equal to the shape " + "of partlocs ({}).".format( + self.name, localz.shape[0], partlocs.shape[0] + ) ) - raise ValueError(msg) # timeoffset if timeoffset is None: timeoffset = 0.0 @@ -247,14 +237,12 @@ def __init__( timeoffset = np.array(timeoffset, dtype=np.float32) if isinstance(timeoffset, np.ndarray): if timeoffset.shape[0] != partlocs.shape[0]: - msg = ( - "{}:".format(self.name) - + "shape of timeoffset " - + "({}) ".format(timeoffset.shape[0]) - + "is not equal to the shape " - + "of partlocs ({}).".format(partlocs.shape[0]) + raise ValueError( + "{}:shape of timeoffset ({}) is not equal to the " + "shape of partlocs ({}).".format( + self.name, timeoffset.shape[0], partlocs.shape[0] + ) ) - raise ValueError(msg) # drape if drape is None: @@ -266,13 +254,12 @@ def __init__( drape = np.array(drape, dtype=np.int32) if isinstance(drape, np.ndarray): if drape.shape[0] != partlocs.shape[0]: - msg = ( - "{}:".format(self.name) - + "shape of drape ({}) ".format(drape.shape[0]) - + "is not equal to the shape " - + "of partlocs ({}).".format(partlocs.shape[0]) + raise ValueError( + "{}:shape of drape ({}) is not equal to the shape " + "of partlocs ({}).".format( + self.name, drape.shape[0], partlocs.shape[0] + ) ) - raise ValueError(msg) # particleids if particleids is None: @@ -282,26 +269,23 @@ def __init__( particleid = True particleidoption = 1 if isinstance(particleids, (int, float)): - msg = ( - "{}:".format(self.name) - + "A particleid must be provided for each partloc " - + "as a list/tuple/np.ndarray of size " - + "{}. ".format(partlocs.shape[0]) - + "A single particleid has been provided." + raise TypeError( + "{}:A particleid must be provided for each partloc " + "as a list/tuple/np.ndarray of size {}. " + "A single particleid has been provided.".format( + self.name, partlocs.shape[0] + ) ) - raise TypeError(msg) elif isinstance(particleids, (list, tuple)): particleids = np.array(particleids, dtype=np.int32) if isinstance(particleids, np.ndarray): if particleids.shape[0] != partlocs.shape[0]: - msg = ( - "{}:".format(self.name) - + "shape of particleids " - + "({}) ".format(particleids.shape[0]) - + "is not equal to the shape " - + "of partlocs ({}).".format(partlocs.shape[0]) + raise ValueError( + "{}:shape of particleids ({}) is not equal to the " + "shape of partlocs ({}).".format( + self.name, particleids.shape[0], partlocs.shape[0] + ) ) - raise ValueError(msg) # create empty particle ncells = partlocs.shape[0] @@ -346,20 +330,26 @@ def write(self, f=None): """ # validate that a valid file object was passed if not hasattr(f, "write"): - msg = ( - "{}: cannot write data for template ".format(self.name) - + "without passing a valid file object ({}) ".format(f) - + "open for writing" + raise ValueError( + "{}: cannot write data for template without passing a valid " + "file object ({}) open for writing".format(self.name, f) ) - raise ValueError(msg) # particle data item 4 and 5 d = np.recarray.copy(self.particledata) lnames = [name.lower() for name in d.dtype.names] # Add one to the kij and node indices - for idx in ["k", "i", "j", "node", "id"]: + for idx in ( + "k", + "i", + "j", + "node", + ): if idx in lnames: d[idx] += 1 + # Add one to the particle id if required + if self.particleidoption == 0 and "id" in lnames: + d["id"] += 1 # write the particle data fmt = self._fmt_string + "\n" @@ -441,18 +431,15 @@ def _fmt_string(self): elif vtype == "o": fmts.append("{:9s}") elif vtype == "s": - msg = ( - "Particles.fmt_string error: 'str' " - + "type found in dtype. This gives unpredictable " - + "results when recarray to file - change to 'object' type" + raise TypeError( + "Particles.fmt_string error: 'str' type found in dtype. " + "This gives unpredictable results when recarray to file - " + "change to 'object' type" ) - raise TypeError(msg) else: - msg = ( - "MfList.fmt_string error: unknown vtype in " - + "field: {}".format(field) + raise TypeError( + f"MfList.fmt_string error: unknown vtype in field: {field}" ) - raise TypeError(msg) return " " + " ".join(fmts) @@ -569,12 +556,11 @@ def write(self, f=None): """ # validate that a valid file object was passed if not hasattr(f, "write"): - msg = ( - "{}: cannot write data for template ".format(self.name) - + "without passing a valid file object ({}) ".format(f) - + "open for writing" + raise ValueError( + "{}: cannot write data for template " + "without passing a valid file object ({}) " + "open for writing".format(self.name, f) ) - raise ValueError(msg) # item 4 fmt = 12 * " {}" + "\n" @@ -665,12 +651,11 @@ def write(self, f=None): """ # validate that a valid file object was passed if not hasattr(f, "write"): - msg = ( - "{}: cannot write data for template ".format(self.name) - + "without passing a valid file object ({}) ".format(f) - + "open for writing" + raise ValueError( + "{}: cannot write data for template " + "without passing a valid file object ({}) " + "open for writing".format(self.name, f) ) - raise ValueError(msg) # item 5 fmt = " {} {} {}\n" @@ -734,12 +719,12 @@ def __init__(self, subdivisiondata=None, lrcregions=None): for idx, fd in enumerate(subdivisiondata): if not isinstance(fd, (CellDataType, FaceDataType)): - msg = ( - "{}: facedata item {} ".format(self.name, idx) - + "is of type {} ".format(type(fd)) - + "instead of an instance of CellDataType or FaceDataType" + raise TypeError( + "{}: facedata item {} is of type {} instead of an " + "instance of CellDataType or FaceDataType".format( + self.name, idx, type(fd) + ) ) - raise TypeError(msg) # validate lrcregions data if isinstance(lrcregions, (list, tuple)): @@ -748,32 +733,27 @@ def __init__(self, subdivisiondata=None, lrcregions=None): isinstance(el, (list, tuple, np.ndarray)) for el in lrcregions ) if not alllsttup: - msg = ( - "{}: lrcregions should be ".format(self.name) - + "a list with lists, tuples, or arrays" + raise TypeError( + "{}: lrcregions should be " + "a list with lists, tuples, or arrays".format(self.name) ) - raise TypeError(msg) t = [] for lrcregion in lrcregions: t.append(np.array(lrcregion, dtype=np.int32)) lrcregions = t else: - msg = ( - "{}: lrcregions should be ".format(self.name) - + "a list of lists, tuples, or arrays " - + "not a {}.".format(type(lrcregions)) + raise TypeError( + "{}: lrcregions should be a list of lists, tuples, or arrays " + "not a {}.".format(self.name, type(lrcregions)) ) - raise TypeError(msg) # validate size of nodes relative to subdivisiondata shape = len(subdivisiondata) if len(lrcregions) != shape: - msg = ( - "{}: lrcregions data must have ".format(self.name) - + "{} rows but a total of ".format(shape) - + "{} rows were provided.".format(lrcregions.shape[0]) + raise ValueError( + "{}: lrcregions data must have {} rows but a total of {} rows " + "were provided.".format(self.name, shape, lrcregions.shape[0]) ) - raise ValueError(msg) # validate that there are 6 columns in each lrcregions entry for idx, lrcregion in enumerate(lrcregions): @@ -782,12 +762,11 @@ def __init__(self, subdivisiondata=None, lrcregions=None): lrcregions[idx] = lrcregion.reshape(1, shapel) shapel = lrcregion[idx].shape if shapel[1] != 6: - msg = ( - "{}: Each lrcregions entry must ".format(self.name) - + "have 6 columns passed lrcregions has " - + "{} columns".format(shapel[1]) + raise ValueError( + "{}: Each lrcregions entry must " + "have 6 columns passed lrcregions has " + "{} columns".format(self.name, shapel[1]) ) - raise ValueError(msg) # totalcellregioncount = 0 @@ -815,26 +794,19 @@ def write(self, f=None): """ # validate that a valid file object was passed if not hasattr(f, "write"): - msg = ( - "{}: cannot write data for template ".format(self.name) - + "without passing a valid file object ({}) ".format(f) - + "open for writing" + raise ValueError( + "{}: cannot write data for template " + "without passing a valid file object ({}) " + "open for writing".format(self.name, f) ) - raise ValueError(msg) # item 2 - f.write( - "{} {}\n".format( - self.particletemplatecount, self.totalcellregioncount - ) - ) + f.write(f"{self.particletemplatecount} {self.totalcellregioncount}\n") for sd, lrcregion in zip(self.subdivisiondata, self.lrcregions): # item 3 f.write( - "{} {} {}\n".format( - sd.templatesubdivisiontype, lrcregion.shape[0], sd.drape - ) + f"{sd.templatesubdivisiontype} {lrcregion.shape[0]} {sd.drape}\n" ) # item 4 or 5 @@ -844,7 +816,7 @@ def write(self, f=None): for row in lrcregion: line = "" for lrc in row: - line += "{} ".format(lrc + 1) + line += f"{lrc + 1} " line += "\n" f.write(line) @@ -899,20 +871,19 @@ def __init__(self, subdivisiondata=None, nodes=None): if isinstance(nodes, (int, np.int32, np.int64)): nodes = [(nodes,)] elif isinstance(nodes, (float, np.float32, np.float64)): - msg = ( - "{}: nodes is of type {} ".format(self.name, type(nodes)) - + "but must be an int if a single value is passed" + raise TypeError( + "{}: nodes is of type {} but must be an int if a " + "single value is passed".format(self.name, type(nodes)) ) - raise TypeError(msg) for idx, fd in enumerate(subdivisiondata): if not isinstance(fd, (CellDataType, FaceDataType)): - msg = ( - "{}: facedata item {} ".format(self.name, idx) - + "is of type {} ".format(type(fd)) - + "instead of an instance of CellDataType or FaceDataType" + raise TypeError( + "{}: facedata item {} is of type {} instead of an " + "instance of CellDataType or FaceDataType".format( + self.name, idx, type(fd) + ) ) - raise TypeError(msg) # validate nodes data if isinstance(nodes, np.ndarray): @@ -934,33 +905,28 @@ def __init__(self, subdivisiondata=None, nodes=None): isinstance(el, (list, tuple, np.ndarray)) for el in nodes ) if not alllsttup: - msg = ( - "{}: nodes should be ".format(self.name) - + "a list or tuple with lists or tuple if a single " - + "int or numpy array is not provided" + raise TypeError( + "{}: nodes should be " + "a list or tuple with lists or tuple if a single " + "int or numpy array is not provided".format(self.name) ) - raise TypeError(msg) t = [] for idx in range(len(nodes)): t.append(np.array(nodes[idx], dtype=np.int32)) nodes = t else: - msg = ( - "{}: nodes should be ".format(self.name) - + "a single integer, a numpy array, or a " - + "list/tuple or lists/tuples." + raise TypeError( + "{}: nodes should be a single integer, a numpy array, or a " + "list/tuple or lists/tuples.".format(self.name) ) - raise TypeError(msg) # validate size of nodes relative to subdivisiondata shape = len(subdivisiondata) if len(nodes) != shape: - msg = ( - "{}: node data must have ".format(self.name) - + "{} rows but a total of ".format(shape) - + "{} rows were provided.".format(nodes.shape[0]) + raise ValueError( + "{}: node data must have {} rows but a total of {} rows were " + "provided.".format(self.name, shape, nodes.shape[0]) ) - raise ValueError(msg) totalcellcount = 0 for t in nodes: @@ -987,24 +953,19 @@ def write(self, f=None): """ # validate that a valid file object was passed if not hasattr(f, "write"): - msg = ( - "{}: cannot write data for template ".format(self.name) - + "without passing a valid file object ({}) ".format(f) - + "open for writing" + raise ValueError( + "{}: cannot write data for template " + "without passing a valid file object ({}) " + "open for writing".format(self.name, f) ) - raise ValueError(msg) # item 2 - f.write( - "{} {}\n".format(self.particletemplatecount, self.totalcellcount) - ) + f.write(f"{self.particletemplatecount} {self.totalcellcount}\n") for sd, nodes in zip(self.subdivisiondata, self.nodedata): # item 3 f.write( - "{} {} {}\n".format( - sd.templatesubdivisiontype, nodes.shape[0], sd.drape - ) + f"{sd.templatesubdivisiontype} {nodes.shape[0]} {sd.drape}\n" ) # item 4 or 5 @@ -1013,7 +974,7 @@ def write(self, f=None): # item 6 line = "" for idx, node in enumerate(nodes): - line += " {}".format(node + 1) + line += f" {node + 1}" lineend = False if idx > 0: if idx % 10 == 0 or idx == nodes.shape[0] - 1: diff --git a/dependencies/flopy/modpath/mp7particlegroup.py b/dependencies/flopy/modpath/mp7particlegroup.py index 5209e6c..cfa4dc1 100644 --- a/dependencies/flopy/modpath/mp7particlegroup.py +++ b/dependencies/flopy/modpath/mp7particlegroup.py @@ -48,11 +48,10 @@ def __init__(self, particlegroupname, filename, releasedata): self.external = True if releasedata is None: - msg = ( + raise ValueError( "releasedata must be provided to instantiate " - + "a MODPATH 7 particle group" + "a MODPATH 7 particle group" ) - raise ValueError(msg) # convert releasedata to a list, if required if isinstance(releasedata, (float, int)): @@ -86,17 +85,14 @@ def __init__(self, particlegroupname, filename, releasedata): ): releasedata[1] = np.array(releasedata[1]) if releasedata[1].shape[0] != releasetimecount: - msg = ( - "The number of releasetimes data " - + "({}) ".format(releasedata[1].shape[0]) - + "is not equal to releasetimecount " - + "({}).".format(releasetimecount) + raise ValueError( + "The number of releasetimes data ({}) " + "is not equal to releasetimecount " + "({}).".format(releasedata[1].shape[0], releasetimecount) ) - raise ValueError(msg) releasetimes = np.array(releasedata[1], dtype=np.float32) else: - msg = "releasedata must have 1, 2, or 3 entries" - raise ValueError(msg) + raise ValueError("releasedata must have 1, 2, or 3 entries") # set release data self.releaseoption = releaseoption @@ -122,23 +118,22 @@ def write(self, fp=None, ws="."): # validate that a valid file object was passed if not hasattr(fp, "write"): - msg = ( - "Cannot write data for particle group " - + "{} ".format(self.particlegroupname) - + "without passing a valid file object ({}) ".format(fp) - + "open for writing" + raise ValueError( + "Cannot write data for particle group {} without passing a " + "valid file object ({}) open for writing".format( + self.particlegroupname, fp + ) ) - raise ValueError(msg) # item 26 - fp.write("{}\n".format(self.particlegroupname)) + fp.write(f"{self.particlegroupname}\n") # item 27 - fp.write("{}\n".format(self.releaseoption)) + fp.write(f"{self.releaseoption}\n") if self.releaseoption == 1: # item 28 - fp.write("{}\n".format(self.releasetimes[0])) + fp.write(f"{self.releasetimes[0]}\n") elif self.releaseoption == 2: # item 29 fp.write( @@ -150,7 +145,7 @@ def write(self, fp=None, ws="."): ) elif self.releaseoption == 3: # item 30 - fp.write("{}\n".format(self.releasetimecount)) + fp.write(f"{self.releasetimecount}\n") # item 31 tp = self.releasetimes v = Util2d( @@ -160,7 +155,7 @@ def write(self, fp=None, ws="."): # item 32 if self.external: - line = "EXTERNAL {}\n".format(self.filename) + line = f"EXTERNAL {self.filename}\n" else: line = "INTERNAL\n" fp.write(line) @@ -230,10 +225,10 @@ def __init__( # convert particledata to a list if a ParticleData type if not isinstance(particledata, ParticleData): - msg = "{}: particledata must be a".format( - self.name - ) + " ParticleData instance not a {}".format(type(particledata)) - raise TypeError(msg) + raise TypeError( + f"{self.name}: particledata must be a " + f"ParticleData instance not a {type(particledata)}" + ) # set attributes self.inputstyle = 1 @@ -271,13 +266,13 @@ def write(self, fp=None, ws="."): f = fp # particle data item 1 - f.write("{}\n".format(self.inputstyle)) + f.write(f"{self.inputstyle}\n") # particle data item 2 - f.write("{}\n".format(self.locationstyle)) + f.write(f"{self.locationstyle}\n") # particle data item 3 - f.write("{} {}\n".format(self.particlecount, self.particleidoption)) + f.write(f"{self.particlecount} {self.particleidoption}\n") # particle data item 4 and 5 # call the write method in ParticleData @@ -395,13 +390,10 @@ def write(self, fp=None, ws="."): """ # validate that a valid file object was passed if not hasattr(fp, "write"): - msg = ( - "{}: cannot write data for ".format(self.name) - + "template without passing a valid file object " - + "({}) ".format(fp) - + "open for writing" + raise ValueError( + "{}: cannot write data for template without passing a valid " + "file object ({}) open for writing".format(self.name, fp) ) - raise ValueError(msg) # call base class write method to write common data _Modpath7ParticleGroup.write(self, fp, ws) @@ -414,7 +406,7 @@ def write(self, fp=None, ws="."): f = fp # item 1 - f.write("{}\n".format(self.inputstyle)) + f.write(f"{self.inputstyle}\n") # items 2, 3, 4 or 5, and 6 self.particledata.write(f) @@ -496,13 +488,10 @@ def write(self, fp=None, ws="."): """ # validate that a valid file object was passed if not hasattr(fp, "write"): - msg = ( - "{}: cannot write data for ".format(self.name) - + "template without passing a valid file object " - + "({}) ".format(fp) - + "open for writing" + raise ValueError( + "{}: cannot write data for template without passing a valid " + "file object ({}) open for writing".format(self.name, fp) ) - raise ValueError(msg) # call base class write method to write common data _Modpath7ParticleGroup.write(self, fp, ws) @@ -515,7 +504,7 @@ def write(self, fp=None, ws="."): f = fp # item 1 - f.write("{}\n".format(self.inputstyle)) + f.write(f"{self.inputstyle}\n") # items 2, 3, 4 or 5, and 6 self.particledata.write(f) diff --git a/dependencies/flopy/modpath/mp7sim.py b/dependencies/flopy/modpath/mp7sim.py index e4b1fdb..8a04915 100644 --- a/dependencies/flopy/modpath/mp7sim.py +++ b/dependencies/flopy/modpath/mp7sim.py @@ -36,11 +36,11 @@ def sim_enum_error(v, s, e): ------- """ - msg = "Invalid {} ({})".format(v, s) + ". Valid types are " + msg = f"Invalid {v} ({s}). Valid types are " for i, c in enumerate(e): if i > 0: msg += ", " - msg += '"{}"'.format(c.name) + msg += f'"{c.name}"' raise ValueError(msg) @@ -278,30 +278,26 @@ def __init__( # Call ancestor's init to set self.parent, extension, name and unit number Package.__init__(self, model, extension, "MPSIM", unitnumber) - self.heading = ( - "# {} package for".format(self.name[0]) - + " {}, ".format(model.version_types[model.version]) - + "generated by Flopy." - ) + self._generate_heading() # set file names if mpnamefilename is None: - mpnamefilename = "{}.{}".format(model.name, "mpnam") + mpnamefilename = f"{model.name}.mpnam" self.mp_name_file = mpnamefilename if listingfilename is None: - listingfilename = "{}.{}".format(model.name, "mplst") + listingfilename = f"{model.name}.mplst" self.listingfilename = listingfilename if endpointfilename is None: - endpointfilename = "{}.{}".format(model.name, "mpend") + endpointfilename = f"{model.name}.mpend" self.endpointfilename = endpointfilename if pathlinefilename is None: - pathlinefilename = "{}.{}".format(model.name, "mppth") + pathlinefilename = f"{model.name}.mppth" self.pathlinefilename = pathlinefilename if timeseriesfilename is None: - timeseriesfilename = "{}.{}".format(model.name, "timeseries") + timeseriesfilename = f"{model.name}.timeseries" self.timeseriesfilename = timeseriesfilename if tracefilename is None: - tracefilename = "{}.{}".format(model.name, "trace") + tracefilename = f"{model.name}.trace" self.tracefilename = tracefilename try: @@ -335,36 +331,30 @@ def __init__( tracemode = 1 if isinstance(traceparticledata, (list, tuple)): if len(traceparticledata) != 2: - msg = ( + raise ValueError( "traceparticledata must be a list or tuple " - + "with 2 items (a integer and an integer). " - + "Passed item {}.".format(traceparticledata) + "with 2 items (a integer and an integer). " + "Passed item {}.".format(traceparticledata) ) - raise ValueError(msg) try: traceparticlegroup = int(traceparticledata[0]) except: - msg = ( - "traceparticledata[0] " - + "({}) ".format(traceparticledata[0]) - + "cannot be converted to a integer." + raise ValueError( + "traceparticledata[0] ({}) cannot be converted to a " + "integer.".format(traceparticledata[0]) ) - raise ValueError(msg) try: traceparticleid = int(traceparticledata[1]) except: - msg = ( - "traceparticledata[1] " - + "({}) ".format(traceparticledata[0]) - + "cannot be converted to a integer." + raise ValueError( + "traceparticledata[1] ({}) cannot be converted to a " + "integer.".format(traceparticledata[0]) ) - raise ValueError(msg) else: - msg = ( + raise ValueError( "traceparticledata must be a list or " - + "tuple with 2 items (a integer and an integer)." + "tuple with 2 items (a integer and an integer)." ) - raise ValueError(msg) # set tracemode, traceparticlegroup, and traceparticleid self.tracemode = tracemode @@ -384,14 +374,13 @@ def __init__( if cell < 0 or cell >= ncells: if msg == "": msg = ( - "Specified cell number(s) exceed the " - + "number of cells in the model " - + "(Valid cells = 0-{}). ".format(ncells - 1) - + "Invalid cells are: " + "Specified cell number(s) exceed the number of " + "cells in the model (Valid cells = 0-{}). " + "Invalid cells are: ".format(ncells - 1) ) else: msg += ", " - msg += "{}".format(cell) + msg += str(cell) if msg != "": raise ValueError(msg) # create Util2d object @@ -417,59 +406,46 @@ def __init__( # validate referencetime data t = referencetime[0] if t < 0.0 or t > self.parent.time_end: - msg = ( - "referencetime must be between 0. and " - + "{} ".format(self.parent.time_end) - + "(specified value = {}).".format(t) + raise ValueError( + "referencetime must be between 0. and {} " + "(specified value = {}).".format(self.parent.time_end, t) ) - raise ValueError(msg) elif len(referencetime) == 3: referencetimeOption = 2 # validate referencetime data # StressPeriod iper = referencetime[0] if iper < 0 or iper >= self.parent.nper: - msg = ( - "StressPeriod must be between 0 and " - + "{} ".format(self.parent.nper - 1) - + "(specified value = {}).".format(iper) + raise ValueError( + "StressPeriod must be between 0 and {} (specified value " + "= {}).".format(self.parent.nper - 1, iper) ) - raise ValueError(msg) # TimeStep istp = referencetime[1] maxstp = self.parent.nstp[iper] + 1 if istp < 0 or istp >= maxstp: - msg = ( - "TimeStep for StressPeriod {} ".format(iper) - + "must be between 0 and " - + "{} ".format(maxstp - 1) - + "(specified value = {}).".format(istp) + raise ValueError( + "TimeStep for StressPeriod {} must be between 0 and {} " + "(specified value = {}).".format(iper, maxstp - 1, istp) ) - raise ValueError(msg) # TimeFraction tf = referencetime[2] if tf < 0.0 or tf > 1.0: - msg = ( + raise ValueError( "TimeFraction value must be between 0 and 1 " - + "(specified value={}).".format(tf) + "(specified value={}).".format(tf) ) - raise ValueError(msg) else: - msg = ( + raise ValueError( "referencetime must be a float (referencetime) or " - + "a list with one item [referencetime] or three items " - + "[StressPeriod, TimeStep, TimeFraction]. " - + "{}".format(len(referencetime)) - + " items were passed as referencetime [" + "a list with one item [referencetime] or three items " + "[StressPeriod, TimeStep, TimeFraction]. " + "{} items were passed as referencetime {}.".format( + len(referencetime), referencetime + ) ) - for i, v in enumerate(referencetime): - if i > 0: - msg += ", " - msg += "{}".format(v) - msg += "]." - raise ValueError(msg) self.referencetimeOption = referencetimeOption self.referencetime = referencetime @@ -494,15 +470,13 @@ def __init__( # timepointdata if timepointdata is not None: if not isinstance(timepointdata, (list, tuple)): - msg = "timepointdata must be a list or tuple" - raise ValueError(msg) + raise ValueError("timepointdata must be a list or tuple") else: if len(timepointdata) != 2: - msg = ( + raise ValueError( "timepointdata must be a have 2 entries " - + "({} provided)".format(len(timepointdata)) + "({} provided)".format(len(timepointdata)) ) - raise ValueError(msg) else: if isinstance(timepointdata[1], (list, tuple)): timepointdata[1] = np.array(timepointdata[1]) @@ -511,13 +485,12 @@ def __init__( if timepointdata[1].shape[0] == timepointdata[0]: timepointoption = 2 elif timepointdata[1].shape[0] > 1: - msg = ( - "The number of TimePoint data " - + "({}) ".format(timepointdata[1].shape[0]) - + "is not equal to TimePointCount " - + "({}).".format(timepointdata[0]) + raise ValueError( + "The number of TimePoint data ({}) is not equal " + "to TimePointCount ({}).".format( + timepointdata[1].shape[0], timepointdata[0] + ) ) - raise ValueError(msg) else: timepointoption = 1 else: @@ -536,15 +509,14 @@ def __init__( if stopzone is None: stopzone = -1 if stopzone < -1: - msg = ( - "Specified stopzone value ({}) ".format(stopzone) - + "must be greater than 0." + raise ValueError( + f"Specified stopzone value ({stopzone}) must be greater than 0." ) - raise ValueError(msg) self.stopzone = stopzone if zones is None: - msg = "zones must be specified if zonedataoption='on'." - raise ValueError(msg) + raise ValueError( + "zones must be specified if zonedataoption='on'." + ) self.zones = Util3d( model, self.parent.shape, @@ -565,11 +537,10 @@ def __init__( ) if self.retardationfactoroption == 2: if retardation is None: - msg = ( + raise ValueError( "retardation must be specified if " - + "retardationfactoroption='on'." + "retardationfactoroption='on'." ) - raise ValueError(msg) self.retardation = Util3d( model, self.parent.shape, @@ -611,11 +582,11 @@ def write_file(self, check=False): f = open(self.fn_path, "w") # item 0 - f.write("{}\n".format(self.heading)) + f.write(f"{self.heading}\n") # item 1 - f.write("{}\n".format(self.mp_name_file)) + f.write(f"{self.mp_name_file}\n") # item 2 - f.write("{}\n".format(self.listingfilename)) + f.write(f"{self.listingfilename}\n") # item 3 f.write( "{} {} {} {} {} {}\n".format( @@ -628,23 +599,21 @@ def write_file(self, check=False): ) ) # item 4 - f.write("{}\n".format(self.endpointfilename)) + f.write(f"{self.endpointfilename}\n") # item 5 if self.simulationtype == 2 or self.simulationtype == 4: - f.write("{}\n".format(self.pathlinefilename)) + f.write(f"{self.pathlinefilename}\n") # item 6 if self.simulationtype == 3 or self.simulationtype == 4: - f.write("{}\n".format(self.timeseriesfilename)) + f.write(f"{self.timeseriesfilename}\n") # item 7 and 8 if self.tracemode == 1: - f.write("{}\n".format(self.tracefilename)) + f.write(f"{self.tracefilename}\n") f.write( - "{} {}\n".format( - self.traceparticlegroup + 1, self.traceparticleid + 1 - ) + f"{self.traceparticlegroup + 1} {self.traceparticleid + 1}\n" ) # item 9 - f.write("{}\n".format(self.BudgetCellCount)) + f.write(f"{self.BudgetCellCount}\n") # item 10 if self.BudgetCellCount > 0: v = Util2d( @@ -658,10 +627,10 @@ def write_file(self, check=False): f.write(v.string) # item 11 - f.write("{}\n".format(self.referencetimeOption)) + f.write(f"{self.referencetimeOption}\n") if self.referencetimeOption == 1: # item 12 - f.write("{:g}\n".format(self.referencetime[0])) + f.write(f"{self.referencetime[0]:g}\n") elif self.referencetimeOption == 2: # item 13 f.write( @@ -672,24 +641,22 @@ def write_file(self, check=False): ) ) # item 14 - f.write("{}\n".format(self.stoptimeoption)) + f.write(f"{self.stoptimeoption}\n") if self.stoptimeoption == 3: # item 15 - f.write("{:g}\n".format(self.stoptime + 1)) + f.write(f"{self.stoptime + 1:g}\n") # item 16 if self.simulationtype == 3 or self.simulationtype == 4: - f.write("{}\n".format(self.timepointoption)) + f.write(f"{self.timepointoption}\n") if self.timepointoption == 1: # item 17 f.write( - "{} {}\n".format( - self.timepointdata[0], self.timepointdata[1][0] - ) + f"{self.timepointdata[0]} {self.timepointdata[1][0]}\n" ) elif self.timepointoption == 2: # item 18 - f.write("{}\n".format(self.timepointdata[0])) + f.write(f"{self.timepointdata[0]}\n") # item 19 tp = self.timepointdata[1] v = Util2d( @@ -703,21 +670,21 @@ def write_file(self, check=False): f.write(v.string) # item 20 - f.write("{}\n".format(self.zonedataoption)) + f.write(f"{self.zonedataoption}\n") if self.zonedataoption == 2: # item 21 - f.write("{}\n".format(self.stopzone)) + f.write(f"{self.stopzone}\n") # item 22 f.write(self.zones.get_file_entry()) # item 23 - f.write("{}\n".format(self.retardationfactoroption)) + f.write(f"{self.retardationfactoroption}\n") if self.retardationfactoroption == 2: # item 24 f.write(self.retardation.get_file_entry()) # item 25 - f.write("{}\n".format(len(self.particlegroups))) + f.write(f"{len(self.particlegroups)}\n") for pg in self.particlegroups: pg.write(f, ws=self.parent.model_ws) diff --git a/dependencies/flopy/mt3d/mt.py b/dependencies/flopy/mt3d/mt.py index 6905648..531dd37 100644 --- a/dependencies/flopy/mt3d/mt.py +++ b/dependencies/flopy/mt3d/mt.py @@ -1,5 +1,4 @@ import os -import sys import numpy as np from ..mbase import BaseModel from ..pakbase import Package @@ -149,12 +148,10 @@ def __init__( # Check whether specified ftlfile exists in model directory; if not, # warn user if os.path.isfile( - os.path.join(self.model_ws, str(modelname + "." + namefile_ext)) + os.path.join(self.model_ws, f"{modelname}.{namefile_ext}") ): with open( - os.path.join( - self.model_ws, str(modelname + "." + namefile_ext) - ) + os.path.join(self.model_ws, f"{modelname}.{namefile_ext}") ) as nm_file: for line in nm_file: if line[0:3] == "FTL": @@ -183,17 +180,13 @@ def __init__( ): pass else: - msg = ( + print( "Specified value of ftlfree conflicts with FTL " - + "file format" + "file format" ) - print(msg) - msg = ( - "Switching ftlfree from " - + "{} ".format(str(self.ftlfree)) - + "to {}".format(str(not self.ftlfree)) + print( + f"Switching ftlfree from {self.ftlfree} to {not self.ftlfree}" ) - print(msg) self.ftlfree = not self.ftlfree # Flip the bool # external option stuff @@ -212,11 +205,7 @@ def __init__( # external_path = os.path.join(model_ws, external_path) if os.path.exists(external_path): - print( - "Note: external_path " - + str(external_path) - + " already exists" - ) + print(f"Note: external_path {external_path} already exists") # assert os.path.exists(external_path),'external_path does not exist' else: os.mkdir(external_path) @@ -410,7 +399,7 @@ def write_name_file(self): """ fn_path = os.path.join(self.model_ws, self.namefile) f_nam = open(fn_path, "w") - f_nam.write("{}\n".format(self.heading)) + f_nam.write(f"{self.heading}\n") f_nam.write( "{:14s} {:5d} {}\n".format( self.lst.name[0], @@ -423,16 +412,14 @@ def write_name_file(self): if self.ftlfree: ftlfmt = "FREE" f_nam.write( - "{:14s} {:5d} {} {}\n".format( - "FTL", self.ftlunit, self.ftlfilename, ftlfmt - ) + f"{'FTL':14s} {self.ftlunit:5d} {self.ftlfilename} {ftlfmt}\n" ) # write file entries in name file - f_nam.write("{}".format(self.get_name_file_entries())) + f_nam.write(str(self.get_name_file_entries())) # write the external files for u, f in zip(self.external_units, self.external_fnames): - f_nam.write("DATA {0:5d} ".format(u) + f + "\n") + f_nam.write(f"DATA {u:5d} {f}\n") # write the output files for u, f, b in zip( @@ -441,11 +428,9 @@ def write_name_file(self): if u == 0: continue if b: - f_nam.write( - "DATA(BINARY) {0:5d} ".format(u) + f + " REPLACE\n" - ) + f_nam.write(f"DATA(BINARY) {u:5d} {f} REPLACE\n") else: - f_nam.write("DATA {0:5d} ".format(u) + f + "\n") + f_nam.write(f"DATA {u:5d} {f}\n") f_nam.close() return @@ -512,11 +497,7 @@ def load( modelname_extension = ext[1:] # without '.' if verbose: - sys.stdout.write( - "\nCreating new model with name: {}\n{}\n\n".format( - modelname, 50 * "-" - ) - ) + print(f"\nCreating new model with name: {modelname}\n{50 * '-'}\n") mt = cls( modelname=modelname, namefile_ext=modelname_extension, @@ -532,7 +513,7 @@ def load( # read name file namefile_path = os.path.join(mt.model_ws, f) if not os.path.isfile(namefile_path): - raise IOError("cannot find name file: " + str(namefile_path)) + raise FileNotFoundError(f"cannot find name file: {namefile_path}") try: ext_unit_dict = mfreadnam.parsenamefile( namefile_path, mt.mfnam_packages, verbose=verbose @@ -542,7 +523,7 @@ def load( # print(str(e)) # return None raise Exception( - "error loading name file entries from file:\n" + str(e) + f"error loading name file entries from file:\n{e!s}" ) if mt.verbose: @@ -593,12 +574,10 @@ def load( btn.filename, mt, ext_unit_dict=ext_unit_dict ) except Exception as e: - raise Exception("error loading BTN: {0}".format(str(e))) + raise Exception(f"error loading BTN: {e!s}") files_successfully_loaded.append(btn.filename) if mt.verbose: - sys.stdout.write( - " {:4s} package load...success\n".format(pck.name[0]) - ) + print(f" {pck.name[0]:4s} package load...success") ext_unit_dict.pop(btn_key).filehandle.close() ncomp = mt.btn.ncomp # reserved unit numbers for .ucn, s.ucn, .obs, .mas, .cnf @@ -647,17 +626,14 @@ def load( ) files_successfully_loaded.append(item.filename) if mt.verbose: - sys.stdout.write( - " {:4s} package load...success\n".format( - pck.name[0] - ) + print( + f" {pck.name[0]:4s} package load...success" ) except BaseException as o: if mt.verbose: - sys.stdout.write( - " {:4s} package load...failed\n {!s}\n".format( - item.filetype, o - ) + print( + f" {item.filetype:4s} package load" + f"...failed\n {o!s}" ) files_not_loaded.append(item.filename) else: @@ -666,31 +642,21 @@ def load( ) files_successfully_loaded.append(item.filename) if mt.verbose: - sys.stdout.write( - " {:4s} package load...success\n".format( - pck.name[0] - ) + print( + f" {pck.name[0]:4s} package load...success" ) else: if mt.verbose: - sys.stdout.write( - " {:4s} package load...skipped\n".format( - item.filetype - ) - ) + print(f" {item.filetype:4s} package load...skipped") files_not_loaded.append(item.filename) elif "data" not in item.filetype.lower(): files_not_loaded.append(item.filename) if mt.verbose: - sys.stdout.write( - " {:4s} package load...skipped\n".format( - item.filetype - ) - ) + print(f" {item.filetype:4s} package load...skipped") elif "data" in item.filetype.lower(): if mt.verbose: - sys.stdout.write( - " {} file load...skipped\n {}\n".format( + print( + " {} file load...skipped\n {}".format( item.filetype, os.path.basename(item.filename) ) ) @@ -718,28 +684,27 @@ def load( item.filehandle.close() except KeyError: if mt.verbose: - msg = ( + print( "\nWARNING:\n External file unit " - + "{} does not exist in ext_unit_dict.\n".format(key) + f"{key} does not exist in ext_unit_dict." ) - sys.stdout.write(msg) # write message indicating packages that were successfully loaded if mt.verbose: - print(1 * "\n") - s = " The following {0} packages were successfully loaded.".format( - len(files_successfully_loaded) + print( + "\n The following {0} packages were " + "successfully loaded.".format(len(files_successfully_loaded)) ) - print(s) for fname in files_successfully_loaded: - print(" " + os.path.basename(fname)) + print(f" {os.path.basename(fname)}") if len(files_not_loaded) > 0: - s = " The following {0} packages were not loaded.".format( - len(files_not_loaded) + print( + " The following {0} packages were not loaded.".format( + len(files_not_loaded) + ) ) - print(s) for fname in files_not_loaded: - print(" " + os.path.basename(fname)) + print(f" {os.path.basename(fname)}") print("\n") # return model object @@ -761,7 +726,7 @@ def load_mas(fname): """ if not os.path.isfile(fname): - raise Exception("Could not find file: {}".format(fname)) + raise Exception(f"Could not find file: {fname}") dtype = [ ("time", float), ("total_in", float), @@ -798,19 +763,16 @@ def load_obs(fname): obs = [] if not os.path.isfile(fname): - raise Exception("Could not find file: {}".format(fname)) + raise Exception(f"Could not find file: {fname}") with open(fname, "r") as f: line = f.readline() if line.strip() != firstline: - msg = "First line in file must be \n{}\nFound {}".format( - firstline, line.strip() - ) - msg += ( - "\n{} does not appear to be a valid MT3D OBS file".format( - fname + raise Exception( + "First line in file must be \n{}\nFound {}\n" + "{} does not appear to be a valid MT3D OBS file".format( + firstline, line.strip(), fname ) ) - raise Exception(msg) # Read obs names (when break, line will have first data line) nlineperrec = 0 @@ -824,7 +786,7 @@ def load_obs(fname): k = int(ll.pop(0)) i = int(ll.pop(0)) j = int(ll.pop(0)) - obsnam = "({}, {}, {})".format(k, i, j) + obsnam = f"({k}, {i}, {j})" if obsnam in obs: obsnam += str(len(obs) + 1) # make obs name unique obs.append(obsnam) diff --git a/dependencies/flopy/mt3d/mtadv.py b/dependencies/flopy/mt3d/mtadv.py index 43f4d91..c044b09 100644 --- a/dependencies/flopy/mt3d/mtadv.py +++ b/dependencies/flopy/mt3d/mtadv.py @@ -1,4 +1,3 @@ -import sys from ..pakbase import Package @@ -308,7 +307,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading adv package file...\n") + print("loading adv package file...") # Open file, if necessary openfile = not hasattr(f, "read") @@ -336,10 +335,10 @@ def load(cls, f, model, ext_unit_dict=None): if len(line[30:40].strip()) > 0: nadvfd = int(line[30:40]) if model.verbose: - print(" MIXELM {}".format(mixelm)) - print(" PERCEL {}".format(nadvfd)) - print(" MXPART {}".format(mxpart)) - print(" NADVFD {}".format(nadvfd)) + print(f" MIXELM {mixelm}") + print(f" PERCEL {nadvfd}") + print(f" MXPART {mxpart}") + print(f" NADVFD {nadvfd}") # Item B2: ITRACK WD itrack = None @@ -351,8 +350,8 @@ def load(cls, f, model, ext_unit_dict=None): itrack = int(line[0:10]) wd = float(line[10:20]) if model.verbose: - print(" ITRACK {}".format(itrack)) - print(" WD {}".format(wd)) + print(f" ITRACK {itrack}") + print(f" WD {wd}") # Item B3: DCEPS, NPLANE, NPL, NPH, NPMIN, NPMAX dceps = None @@ -372,12 +371,12 @@ def load(cls, f, model, ext_unit_dict=None): npmin = int(line[40:50]) npmax = int(line[50:60]) if model.verbose: - print(" DCEPS {}".format(dceps)) - print(" NPLANE {}".format(nplane)) - print(" NPL {}".format(npl)) - print(" NPH {}".format(nph)) - print(" NPMIN {}".format(npmin)) - print(" NPMAX {}".format(npmax)) + print(f" DCEPS {dceps}") + print(f" NPLANE {nplane}") + print(f" NPL {npl}") + print(f" NPH {nph}") + print(f" NPMIN {npmin}") + print(f" NPMAX {npmax}") # Item B4: INTERP, NLSINK, NPSINK interp = None @@ -391,9 +390,9 @@ def load(cls, f, model, ext_unit_dict=None): nlsink = int(line[10:20]) npsink = int(line[20:30]) if model.verbose: - print(" INTERP {}".format(interp)) - print(" NLSINK {}".format(nlsink)) - print(" NPSINK {}".format(npsink)) + print(f" INTERP {interp}") + print(f" NLSINK {nlsink}") + print(f" NPSINK {npsink}") # Item B5: DCHMOC dchmoc = None @@ -403,7 +402,7 @@ def load(cls, f, model, ext_unit_dict=None): line = f.readline() dchmoc = float(line[0:10]) if model.verbose: - print(" DCHMOC {}".format(dchmoc)) + print(f" DCHMOC {dchmoc}") if openfile: f.close() diff --git a/dependencies/flopy/mt3d/mtbtn.py b/dependencies/flopy/mt3d/mtbtn.py index ad2198d..47b6a5c 100644 --- a/dependencies/flopy/mt3d/mtbtn.py +++ b/dependencies/flopy/mt3d/mtbtn.py @@ -228,7 +228,7 @@ def __init__( extension="btn", unitnumber=None, filenames=None, - **kwargs + **kwargs, ): if unitnumber is None: @@ -370,16 +370,14 @@ def __init__( self.sconc.append(u3d) if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "sconc" + str(icomp) + name = f"sconc{icomp}" val = 0.0 if name in kwargs: val = kwargs.pop(name) else: print( - "BTN: setting sconc for component " - + str(icomp) - + " to zero, kwarg name " - + name + f"BTN: setting sconc for component {icomp} " + f"to zero, kwarg name {name}" ) u3d = Util3d( model, @@ -395,8 +393,7 @@ def __init__( # Check to make sure that all kwargs have been consumed if len(list(kwargs.keys())) > 0: raise Exception( - "BTN error: unrecognized kwargs: " - + " ".join(list(kwargs.keys())) + f"BTN error: unrecognized kwargs: {' '.join(list(kwargs.keys()))}" ) # Finally add self to parent's package list and return @@ -691,7 +688,7 @@ def write_file(self): f_btn = open(self.fn_path, "w") # A1,2 - f_btn.write("#{0:s}\n#{1:s}\n".format(self.heading1, self.heading2)) + f_btn.write(f"#{self.heading1}\n#{self.heading2}\n") # A3; Keywords # Build a string of the active keywords @@ -727,9 +724,7 @@ def write_file(self): ) # A4 - f_btn.write( - "{0:4s}{1:4s}{2:4s}\n".format(self.tunit, self.lunit, self.munit) - ) + f_btn.write(f"{self.tunit:4s}{self.lunit:4s}{self.munit:4s}\n") # A5 if self.parent.adv != None: @@ -782,25 +777,23 @@ def write_file(self): f_btn.write(self.sconc[s].get_file_entry()) # A14 - f_btn.write("{0:10.0E}{1:10.2E}\n".format(self.cinact, self.thkmin)) + f_btn.write(f"{self.cinact:10.0E}{self.thkmin:10.2E}\n") # A15 f_btn.write( - "{0:10d}{1:10d}{2:10d}{3:10d}".format( - self.ifmtcn, self.ifmtnp, self.ifmtrf, self.ifmtdp - ) + f"{self.ifmtcn:10d}{self.ifmtnp:10d}{self.ifmtrf:10d}{self.ifmtdp:10d}" ) if self.savucn == True: ss = "T" else: ss = "F" - f_btn.write("{0:>10s}\n".format(ss)) + f_btn.write(f"{ss:>10s}\n") # A16, A17 if self.timprs is None: - f_btn.write("{0:10d}\n".format(self.nprs)) + f_btn.write(f"{self.nprs:10d}\n") else: - f_btn.write("{0:10d}\n".format(len(self.timprs))) + f_btn.write(f"{len(self.timprs):10d}\n") timprs = Util2d( self.parent, (len(self.timprs),), @@ -814,10 +807,10 @@ def write_file(self): # A18, A19 if self.obs is None: - f_btn.write("{0:10d}{1:10d}\n".format(0, self.nprobs)) + f_btn.write(f"{0:10d}{self.nprobs:10d}\n") else: nobs = self.obs.shape[0] - f_btn.write("{0:10d}{1:10d}\n".format(nobs, self.nprobs)) + f_btn.write(f"{nobs:10d}{self.nprobs:10d}\n") for i in range(nobs): f_btn.write( "{0:10d}{1:10d}{2:10d}\n".format( @@ -832,13 +825,11 @@ def write_file(self): ss = "T" else: ss = "F" - f_btn.write("{0:>10s}{1:10d}\n".format(ss, self.nprmas)) + f_btn.write(f"{ss:>10s}{self.nprmas:10d}\n") # A21, 22, 23 PERLEN, NSTP, TSMULT for t in range(self.nper): - s = "{0:10G}{1:10d}{2:10G}".format( - self.perlen[t], self.nstp[t], self.tsmult[t] - ) + s = f"{self.perlen[t]:10G}{self.nstp[t]:10d}{self.tsmult[t]:10G}" if self.ssflag is not None: s += " " + self.ssflag[t] s += "\n" @@ -919,7 +910,7 @@ def load(cls, f, model, ext_unit_dict=None): m_arr[0].strip().isdigit() is not True ): # If m_arr[0] is not a digit, it is a keyword if model.verbose: - print(" loading optional keywords: {}".format(line.strip())) + print(f" loading optional keywords: {line.strip()}") for i in range(0, len(m_arr)): if m_arr[i].upper() == "MODFLOWSTYLEARRAYS": MFStyleArr = True @@ -958,12 +949,12 @@ def load(cls, f, model, ext_unit_dict=None): except: mcomp = 1 if model.verbose: - print(" NLAY {}".format(nlay)) - print(" NROW {}".format(nrow)) - print(" NCOL {}".format(ncol)) - print(" NPER {}".format(nper)) - print(" NCOMP {}".format(ncomp)) - print(" MCOMP {}".format(mcomp)) + print(f" NLAY {nlay}") + print(f" NROW {nrow}") + print(f" NCOL {ncol}") + print(f" NPER {nper}") + print(f" NCOMP {ncomp}") + print(f" MCOMP {mcomp}") if model.verbose: print(" loading TUNIT, LUNIT, MUNIT...") @@ -972,21 +963,21 @@ def load(cls, f, model, ext_unit_dict=None): lunit = line[4:8] munit = line[8:12] if model.verbose: - print(" TUNIT {}".format(tunit)) - print(" LUNIT {}".format(lunit)) - print(" MUNIT {}".format(munit)) + print(f" TUNIT {tunit}") + print(f" LUNIT {lunit}") + print(f" MUNIT {munit}") if model.verbose: print(" loading TRNOP...") trnop = f.readline()[:20].strip().split() if model.verbose: - print(" TRNOP {}".format(trnop)) + print(f" TRNOP {trnop}") if model.verbose: print(" loading LAYCON...") laycon = Util2d.load_txt((nlay,), f, np.int32, "(40I2)") if model.verbose: - print(" LAYCON {}".format(laycon)) + print(f" LAYCON {laycon}") if model.verbose: print(" loading DELR...") @@ -1000,7 +991,7 @@ def load(cls, f, model, ext_unit_dict=None): array_format="mt3d", ) if model.verbose: - print(" DELR {}".format(delr)) + print(f" DELR {delr}") if model.verbose: print(" loading DELC...") @@ -1014,7 +1005,7 @@ def load(cls, f, model, ext_unit_dict=None): array_format="mt3d", ) if model.verbose: - print(" DELC {}".format(delc)) + print(f" DELC {delc}") if model.verbose: print(" loading HTOP...") @@ -1028,7 +1019,7 @@ def load(cls, f, model, ext_unit_dict=None): array_format="mt3d", ) if model.verbose: - print(" HTOP {}".format(htop)) + print(f" HTOP {htop}") if model.verbose: print(" loading DZ...") @@ -1042,7 +1033,7 @@ def load(cls, f, model, ext_unit_dict=None): array_format="mt3d", ) if model.verbose: - print(" DZ {}".format(dz)) + print(f" DZ {dz}") if model.verbose: print(" loading PRSITY...") @@ -1056,7 +1047,7 @@ def load(cls, f, model, ext_unit_dict=None): array_format="mt3d", ) if model.verbose: - print(" PRSITY {}".format(prsity)) + print(f" PRSITY {prsity}") if model.verbose: print(" loading ICBUND...") @@ -1070,7 +1061,7 @@ def load(cls, f, model, ext_unit_dict=None): array_format="mt3d", ) if model.verbose: - print(" ICBUND {}".format(icbund)) + print(f" ICBUND {icbund}") if model.verbose: print(" loading SCONC...") @@ -1086,9 +1077,9 @@ def load(cls, f, model, ext_unit_dict=None): ) if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "sconc" + str(icomp) + name = f"sconc{icomp}" if model.verbose: - print(" loading {}...".format(name)) + print(f" loading {name}...") u3d = Util3d.load( f, model, @@ -1100,7 +1091,7 @@ def load(cls, f, model, ext_unit_dict=None): ) kwargs[name] = u3d if model.verbose: - print(" SCONC {}".format(sconc)) + print(f" SCONC {sconc}") if model.verbose: print(" loading CINACT, THCKMIN...") @@ -1111,8 +1102,8 @@ def load(cls, f, model, ext_unit_dict=None): except: thkmin = 0.01 if model.verbose: - print(" CINACT {}".format(cinact)) - print(" THKMIN {}".format(thkmin)) + print(f" CINACT {cinact}") + print(f" THKMIN {thkmin}") if model.verbose: print(" loading IFMTCN, IFMTNP, IFMTRF, IFMTDP, SAVUCN...") @@ -1125,18 +1116,18 @@ def load(cls, f, model, ext_unit_dict=None): if "t" in line[40:50].lower(): savucn = True if model.verbose: - print(" IFMTCN {}".format(ifmtcn)) - print(" IFMTNP {}".format(ifmtnp)) - print(" IFMTRF {}".format(ifmtrf)) - print(" IFMTDP {}".format(ifmtdp)) - print(" SAVUCN {}".format(savucn)) + print(f" IFMTCN {ifmtcn}") + print(f" IFMTNP {ifmtnp}") + print(f" IFMTRF {ifmtrf}") + print(f" IFMTDP {ifmtdp}") + print(f" SAVUCN {savucn}") if model.verbose: print(" loading NPRS...") line = f.readline() nprs = int(line[0:10]) if model.verbose: - print(" NPRS {}".format(nprs)) + print(f" NPRS {nprs}") timprs = None if nprs > 0: @@ -1144,7 +1135,7 @@ def load(cls, f, model, ext_unit_dict=None): print(" loading TIMPRS...") timprs = Util2d.load_txt((nprs,), f, np.float32, "(8F10.0)") if model.verbose: - print(" TIMPRS {}".format(timprs)) + print(f" TIMPRS {timprs}") if model.verbose: print(" loading NOBS, NPROBS...") @@ -1155,8 +1146,8 @@ def load(cls, f, model, ext_unit_dict=None): except: nprobs = 1 if model.verbose: - print(" NOBS {}".format(nobs)) - print(" NPROBS {}".format(nprobs)) + print(f" NOBS {nobs}") + print(f" NPROBS {nprobs}") obs = None if nobs > 0: @@ -1171,7 +1162,7 @@ def load(cls, f, model, ext_unit_dict=None): obs.append([k, i, j]) obs = np.array(obs) - 1 if model.verbose: - print(" OBS {}".format(obs)) + print(f" OBS {obs}") if model.verbose: print(" loading CHKMAS, NPRMAS...") @@ -1184,8 +1175,8 @@ def load(cls, f, model, ext_unit_dict=None): except: nprmas = 1 if model.verbose: - print(" CHKMAS {}".format(chkmas)) - print(" NPRMAS {}".format(nprmas)) + print(f" CHKMAS {chkmas}") + print(f" NPRMAS {nprmas}") if model.verbose: print( @@ -1221,15 +1212,15 @@ def load(cls, f, model, ext_unit_dict=None): ttsmax.append(float(line[30:40])) if model.verbose: - print(" PERLEN {}".format(perlen)) - print(" NSTP {}".format(nstp)) - print(" TSMULT {}".format(tsmult)) - print(" SSFLAG {}".format(ssflag)) - print(" TSLNGH {}".format(tslngh)) - print(" DT0 {}".format(dt0)) - print(" MXSTRN {}".format(mxstrn)) - print(" TTSMULT {}".format(ttsmult)) - print(" TTSMAX {}".format(ttsmax)) + print(f" PERLEN {perlen}") + print(f" NSTP {nstp}") + print(f" TSMULT {tsmult}") + print(f" SSFLAG {ssflag}") + print(f" TSLNGH {tslngh}") + print(f" DT0 {dt0}") + print(f" MXSTRN {mxstrn}") + print(f" TTSMULT {ttsmult}") + print(f" TTSMAX {ttsmax}") if openfile: f.close() @@ -1291,7 +1282,7 @@ def load(cls, f, model, ext_unit_dict=None): ttsmax=ttsmax, unitnumber=unitnumber, filenames=filenames, - **kwargs + **kwargs, ) @staticmethod diff --git a/dependencies/flopy/mt3d/mtdsp.py b/dependencies/flopy/mt3d/mtdsp.py index 22e56e0..bdd1d29 100644 --- a/dependencies/flopy/mt3d/mtdsp.py +++ b/dependencies/flopy/mt3d/mtdsp.py @@ -1,4 +1,3 @@ -import sys import numpy as np from ..pakbase import Package from ..utils import Util2d, Util3d @@ -113,7 +112,7 @@ def __init__( multiDiff=False, unitnumber=None, filenames=None, - **kwargs + **kwargs, ): if unitnumber is None: @@ -200,16 +199,14 @@ def __init__( ) self.dmcoef.append(u2or3) for icomp in range(2, nmcomp + 1): - name = "dmcoef" + str(icomp) + name = f"dmcoef{icomp}" val = 0.0 if name in list(kwargs.keys()): val = kwargs.pop(name) else: print( - "DSP: setting dmcoef for component " - + str(icomp) - + " to zero, kwarg name " - + name + "DSP: setting dmcoef for component {} " + "to zero, kwarg name {}".format(icomp, name) ) u2or3 = utype( model, @@ -307,7 +304,7 @@ def load( """ if model.verbose: - sys.stdout.write("loading dsp package file...\n") + print("loading dsp package file...") # Set dimensions if necessary if nlay is None: @@ -403,7 +400,7 @@ def load( ) if model.mcomp > 1: for icomp in range(2, model.mcomp + 1): - name = "dmcoef" + str(icomp) + name = f"dmcoef{icomp}" u3d = Util3d.load( f, model, @@ -452,7 +449,7 @@ def load( multiDiff=multiDiff, unitnumber=unitnumber, filenames=filenames, - **kwargs + **kwargs, ) @staticmethod diff --git a/dependencies/flopy/mt3d/mtgcg.py b/dependencies/flopy/mt3d/mtgcg.py index a6d883e..ab2a413 100644 --- a/dependencies/flopy/mt3d/mtgcg.py +++ b/dependencies/flopy/mt3d/mtgcg.py @@ -1,4 +1,3 @@ -import sys from ..pakbase import Package @@ -144,12 +143,8 @@ def write_file(self): """ # Open file for writing f_gcg = open(self.fn_path, "w") - f_gcg.write( - "{} {} {} {}\n".format( - self.mxiter, self.iter1, self.isolve, self.ncrs - ) - ) - f_gcg.write("{} {} {}\n".format(self.accl, self.cclose, self.iprgcg)) + f_gcg.write(f"{self.mxiter} {self.iter1} {self.isolve} {self.ncrs}\n") + f_gcg.write(f"{self.accl} {self.cclose} {self.iprgcg}\n") f_gcg.close() return @@ -187,7 +182,7 @@ def load(cls, f, model, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading gcg package file...\n") + print("loading gcg package file...") # Open file, if necessary openfile = not hasattr(f, "read") @@ -210,10 +205,10 @@ def load(cls, f, model, ext_unit_dict=None): isolve = int(t[2]) ncrs = int(t[3]) if model.verbose: - print(" MXITER {}".format(mxiter)) - print(" ITER1 {}".format(iter1)) - print(" ISOLVE {}".format(isolve)) - print(" NCRS {}".format(ncrs)) + print(f" MXITER {mxiter}") + print(f" ITER1 {iter1}") + print(f" ISOLVE {isolve}") + print(f" NCRS {ncrs}") # Item F2: ACCL, CCLOSE, IPRGCG if model.verbose: @@ -224,9 +219,9 @@ def load(cls, f, model, ext_unit_dict=None): cclose = float(t[1]) iprgcg = int(t[2]) if model.verbose: - print(" ACCL {}".format(accl)) - print(" CCLOSE {}".format(cclose)) - print(" IPRGCG {}".format(iprgcg)) + print(f" ACCL {accl}") + print(f" CCLOSE {cclose}") + print(f" IPRGCG {iprgcg}") if openfile: f.close() diff --git a/dependencies/flopy/mt3d/mtlkt.py b/dependencies/flopy/mt3d/mtlkt.py index 4b53bdf..a0c1e8d 100644 --- a/dependencies/flopy/mt3d/mtlkt.py +++ b/dependencies/flopy/mt3d/mtlkt.py @@ -1,4 +1,3 @@ -import sys import numpy as np from ..pakbase import Package @@ -117,7 +116,7 @@ def __init__( unitnumber=None, filenames=None, iprn=-1, - **kwargs + **kwargs, ): # set default unit number of one is not specified @@ -146,9 +145,9 @@ def __init__( ): # already has extension fname = "{}.{}".format(*filenames[1].split(".", 1)) else: - fname = "{}.{}".format(filenames[1], ext) + fname = f"{filenames[1]}.{ext}" else: - fname = "{}.{}".format(model.name, ext) + fname = f"{model.name}.{ext}" model.add_output_file( icbclk, fname=fname, @@ -208,14 +207,13 @@ def __init__( if ncomp > 1: for icomp in range(2, ncomp + 1): for base_name, attr in zip(["coldlak"], [self.coldlak]): - name = "{0}{1}".format(base_name, icomp) + name = f"{base_name}{icomp}" if name in kwargs: val = kwargs.pop(name) else: print( - "LKT: setting {0} for component {1} to zero, kwarg name {2}".format( - base_name, icomp, name - ) + f"LKT: setting {base_name} for component {icomp} " + f"to zero, kwarg name {name}" ) val = 0.0 u2d = Util2d( @@ -292,7 +290,7 @@ def write_file(self): f_lkt, single_per=kper ) else: - f_lkt.write("{}\n".format(0)) + f_lkt.write("0\n") f_lkt.close() return @@ -341,7 +339,7 @@ def load( """ if model.verbose: - sys.stdout.write("loading lkt package file...\n") + print("loading lkt package file...") openfile = not hasattr(f, "read") if openfile: @@ -380,10 +378,10 @@ def load( ietlak = int(vals[3]) if model.verbose: - print(" NLKINIT {}".format(nlkinit)) - print(" MXLKBC {}".format(mxlkbc)) - print(" ICBCLK {}".format(icbclk)) - print(" IETLAK {}".format(ietlak)) + print(f" NLKINIT {nlkinit}") + print(f" MXLKBC {mxlkbc}") + print(f" ICBCLK {icbclk}") + print(f" IETLAK {ietlak}") if ietlak == 0: print( " Mass does not exit the model via simulated lake evaporation " @@ -420,9 +418,9 @@ def load( if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "coldlak" + str(icomp) + name = f"coldlak{icomp}" if model.verbose: - print(" loading {}...".format(name)) + print(f" loading {name}...") u2d = Util2d.load( f, model, @@ -443,9 +441,7 @@ def load( for iper in range(nper): if model.verbose: print( - " loading lkt boundary condition data for kper {0:5d}".format( - iper + 1 - ) + f" loading lkt boundary condition data for kper {iper + 1:5d}" ) # Item 3: NTMP: An integer value corresponding to the number of @@ -457,10 +453,7 @@ def load( vals = line.strip().split() ntmp = int(vals[0]) if model.verbose: - print( - " {0:5d}".format(ntmp) - + " lkt boundary conditions specified " - ) + print(f" {ntmp:5d} lkt boundary conditions specified ") if (iper == 0) and (ntmp < 0): print(" ntmp < 0 not allowed for first stress period ") if (iper > 0) and (ntmp < 0): @@ -522,7 +515,7 @@ def load( lk_stress_period_data=lk_stress_period_data, unitnumber=unitnumber, filenames=filenames, - **kwargs + **kwargs, ) @staticmethod @@ -538,7 +531,7 @@ def get_default_dtype(ncomp=1): ] if ncomp > 1: for icomp in range(2, ncomp + 1): - comp_name = "cbclk({0:02d})".format(icomp) + comp_name = f"cbclk({icomp:02d})" type_list.append((comp_name, np.float32)) dtype = np.dtype(type_list) return dtype diff --git a/dependencies/flopy/mt3d/mtrct.py b/dependencies/flopy/mt3d/mtrct.py index e9f5580..03d2527 100644 --- a/dependencies/flopy/mt3d/mtrct.py +++ b/dependencies/flopy/mt3d/mtrct.py @@ -1,4 +1,3 @@ -import sys import numpy as np from ..pakbase import Package from ..utils import Util3d @@ -173,7 +172,7 @@ def __init__( extension="rct", unitnumber=None, filenames=None, - **kwargs + **kwargs, ): """ Package constructor. @@ -263,16 +262,14 @@ def __init__( self.srconc.append(u3d) if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "srconc" + str(icomp) + name = f"srconc{icomp}" val = 0.0 if name in kwargs: val = kwargs.pop(name) else: print( - "RCT: setting srconc for component " - + str(icomp) - + " to zero, kwarg name " - + name + f"RCT: setting srconc for component {icomp} to zero, " + f"kwarg name {name}" ) u3d = Util3d( model, @@ -301,16 +298,14 @@ def __init__( self.sp1.append(u3d) if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "sp1" + str(icomp) + name = f"sp1{icomp}" val = 0.0 if name in kwargs: val = kwargs.pop(name) else: print( - "RCT: setting sp1 for component " - + str(icomp) - + " to zero, kwarg name " - + name + "RCT: setting sp1 for component {} to zero, " + "kwarg name {}".format(icomp, name) ) u3d = Util3d( model, @@ -339,16 +334,14 @@ def __init__( self.sp2.append(u3d) if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "sp2" + str(icomp) + name = f"sp2{icomp}" val = 0.0 if name in kwargs: val = kwargs.pop(name) else: print( - "RCT: setting sp2 for component " - + str(icomp) - + " to zero, kwarg name " - + name + "RCT: setting sp2 for component {} to zero, " + "kwarg name {}".format(icomp, name) ) u3d = Util3d( model, @@ -377,16 +370,14 @@ def __init__( self.rc1.append(u3d) if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "rc1" + str(icomp) + name = f"rc1{icomp}" val = 0.0 if name in kwargs: val = kwargs.pop(name) else: print( - "RCT: setting rc1 for component " - + str(icomp) - + " to zero, kwarg name " - + name + "RCT: setting rc1 for component {} to zero, " + "kwarg name {}".format(icomp, name) ) u3d = Util3d( model, @@ -415,16 +406,14 @@ def __init__( self.rc2.append(u3d) if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "rc2" + str(icomp) + name = f"rc2{icomp}" val = 0.0 if name in kwargs: val = kwargs.pop(name) else: print( - "RCT: setting rc2 for component " - + str(icomp) - + " to zero, kwarg name " - + name + "RCT: setting rc2 for component {} to zero, " + "kwarg name {}".format(icomp, name) ) u3d = Util3d( model, @@ -542,7 +531,7 @@ def load( """ if model.verbose: - sys.stdout.write("loading rct package file...\n") + print("loading rct package file...") # Open file, if necessary openfile = not hasattr(f, "read") @@ -578,10 +567,10 @@ def load( except: igetsc = 0 if model.verbose: - print(" ISOTHM {}".format(isothm)) - print(" IREACT {}".format(ireact)) - print(" IRCTOP {}".format(irctop)) - print(" IGETSC {}".format(igetsc)) + print(f" ISOTHM {isothm}") + print(f" IREACT {ireact}") + print(f" IRCTOP {irctop}") + print(f" IGETSC {igetsc}") # Item E2A: RHOB rhob = None @@ -598,7 +587,7 @@ def load( array_format="mt3d", ) if model.verbose: - print(" RHOB {}".format(rhob)) + print(f" RHOB {rhob}") # Item E2A: PRSITY2 prsity2 = None @@ -615,7 +604,7 @@ def load( array_format="mt3d", ) if model.verbose: - print(" PRSITY2 {}".format(prsity2)) + print(f" PRSITY2 {prsity2}") # Item E2C: SRCONC srconc = None @@ -632,12 +621,12 @@ def load( array_format="mt3d", ) if model.verbose: - print(" SRCONC {}".format(srconc)) + print(f" SRCONC {srconc}") if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "srconc" + str(icomp) + name = f"srconc{icomp}" if model.verbose: - print(" loading {}...".format(name)) + print(f" loading {name}...") u3d = Util3d.load( f, model, @@ -649,7 +638,7 @@ def load( ) kwargs[name] = u3d if model.verbose: - print(" SRCONC{} {}".format(icomp, u3d)) + print(f" SRCONC{icomp} {u3d}") # Item E3: SP1 sp1 = None @@ -666,12 +655,12 @@ def load( array_format="mt3d", ) if model.verbose: - print(" SP1 {}".format(sp1)) + print(f" SP1 {sp1}") if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "sp1" + str(icomp) + name = f"sp1{icomp}" if model.verbose: - print(" loading {}...".format(name)) + print(f" loading {name}...") u3d = Util3d.load( f, model, @@ -683,7 +672,7 @@ def load( ) kwargs[name] = u3d if model.verbose: - print(" SP1{} {}".format(icomp, u3d)) + print(f" SP1{icomp} {u3d}") # Item E4: SP2 sp2 = None @@ -700,12 +689,12 @@ def load( array_format="mt3d", ) if model.verbose: - print(" SP2 {}".format(sp2)) + print(f" SP2 {sp2}") if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "sp2" + str(icomp) + name = f"sp2{icomp}" if model.verbose: - print(" loading {}...".format(name)) + print(f" loading {name}...") u3d = Util3d.load( f, model, @@ -717,7 +706,7 @@ def load( ) kwargs[name] = u3d if model.verbose: - print(" SP2{} {}".format(icomp, u3d)) + print(f" SP2{icomp} {u3d}") # Item E5: RC1 rc1 = None @@ -734,12 +723,12 @@ def load( array_format="mt3d", ) if model.verbose: - print(" RC1 {}".format(rc1)) + print(f" RC1 {rc1}") if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "rc1" + str(icomp) + name = f"rc1{icomp}" if model.verbose: - print(" loading {}...".format(name)) + print(f" loading {name}...") u3d = Util3d.load( f, model, @@ -751,7 +740,7 @@ def load( ) kwargs[name] = u3d if model.verbose: - print(" RC1{} {}".format(icomp, u3d)) + print(f" RC1{icomp} {u3d}") # Item E6: RC2 rc2 = None @@ -768,12 +757,12 @@ def load( array_format="mt3d", ) if model.verbose: - print(" RC2 {}".format(rc2)) + print(f" RC2 {rc2}") if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "rc2" + str(icomp) + name = f"rc2{icomp}" if model.verbose: - print(" loading {}...".format(name)) + print(f" loading {name}...") u3d = Util3d.load( f, model, @@ -785,7 +774,7 @@ def load( ) kwargs[name] = u3d if model.verbose: - print(" RC2{} {}".format(icomp, u3d)) + print(f" RC2{icomp} {u3d}") if openfile: f.close() @@ -813,7 +802,7 @@ def load( rc2=rc2, unitnumber=unitnumber, filenames=filenames, - **kwargs + **kwargs, ) @staticmethod diff --git a/dependencies/flopy/mt3d/mtsft.py b/dependencies/flopy/mt3d/mtsft.py index 85273d4..b14c759 100644 --- a/dependencies/flopy/mt3d/mtsft.py +++ b/dependencies/flopy/mt3d/mtsft.py @@ -1,4 +1,3 @@ -import sys import numpy as np from ..pakbase import Package @@ -205,7 +204,7 @@ def __init__( filenames=None, dtype=None, extension="sft", - **kwargs + **kwargs, ): # set default unit number of one is not specified @@ -234,9 +233,9 @@ def __init__( ): # already has extension fname = "{}.{}".format(*filenames[1].split(".", 1)) else: - fname = "{}.{}".format(filenames[1], ext) + fname = f"{filenames[1]}.{ext}" else: - fname = "{}.{}".format(model.name, ext) + fname = f"{model.name}.{ext}" model.add_output_file( abs(ioutobs), fname=fname, @@ -319,7 +318,7 @@ def __init__( for base_name, attr in zip( ["coldsf", "dispsf"], [self.coldsf, self.dispsf] ): - name = "{0}{1}".format(base_name, icomp) + name = f"{base_name}{icomp}" if name in kwargs: val = kwargs.pop(name) else: @@ -373,7 +372,7 @@ def get_default_dtype(ncomp=1): ] if ncomp > 1: for icomp in range(1, ncomp): - comp_name = "cbcsf{0:d}".format(icomp) + comp_name = f"cbcsf{icomp}" type_list.append((comp_name, np.float32)) dtype = np.dtype(type_list) return dtype @@ -439,15 +438,14 @@ def write_file(self): f.write(dispsf.get_file_entry()) # Item 5 - f.write("{0:10d} # nobssf\n".format(self.nobssf)) + f.write(f"{self.nobssf:10d} # nobssf\n") # Item 6 if self.nobssf != 0: for iobs in self.obs_sf: line = ( - "{0:10d}".format(iobs) - + 26 * " " - + "# location of obs as given by position in irch list\n" + f"{iobs:10d} " + "# location of obs as given by position in irch list\n" ) f.write(line) @@ -463,7 +461,7 @@ def write_file(self): if self.sf_stress_period_data is not None: self.sf_stress_period_data.write_transient(f, single_per=kper) else: - f.write("{0:10d} # ntmp - SP {1:5d}\n".format(0, kper)) + f.write(f"{0:10d} # ntmp - SP {kper:5d}\n") f.close() return @@ -533,7 +531,7 @@ def load( """ if model.verbose: - sys.stdout.write("loading sft package file...\n") + print("loading sft package file...") openfile = not hasattr(f, "read") if openfile: @@ -575,11 +573,11 @@ def load( ietsfr = int(vals[4]) if model.verbose: - print(" NSFINIT {}".format(nsfinit)) - print(" MXSFBC {}".format(mxsfbc)) - print(" ICBCSF {}".format(icbcsf)) - print(" IOUTOBS {}".format(ioutobs)) - print(" IETSFR {}".format(ietsfr)) + print(f" NSFINIT {nsfinit}") + print(f" MXSFBC {mxsfbc}") + print(f" ICBCSF {icbcsf}") + print(f" IOUTOBS {ioutobs}") + print(f" IETSFR {ietsfr}") if ietsfr == 0: print( " Mass does not exit the model via simulated " @@ -617,13 +615,13 @@ def load( print(" In version 1.0 of MT3D-USGS, isfsov=1 is only option") if model.verbose: - print(" ISFSOLV {}".format(isfsolv)) - print(" WIMP {}".format(wimp)) - print(" WUPS {}".format(wups)) - print(" CCLOSESF {}".format(cclosesf)) - print(" MXITERSF {}".format(mxitersf)) - print(" CRNTSF {}".format(crntsf)) - print(" IPRTXMD {}".format(iprtxmd)) + print(f" ISFSOLV {isfsolv}") + print(f" WIMP {wimp}") + print(f" WUPS {wups}") + print(f" CCLOSESF {cclosesf}") + print(f" MXITERSF {mxitersf}") + print(f" CRNTSF {crntsf}") + print(f" IPRTXMD {iprtxmd}") # Item 3 (COLDSF(NRCH)) Initial concentration if model.verbose: @@ -653,9 +651,9 @@ def load( kwargs = {} if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "coldsf" + str(icomp) + name = f"coldsf{icomp}" if model.verbose: - print(" loading {}...".format(name)) + print(f" loading {name}...") u2d = Util2d.load( f, model, @@ -691,9 +689,9 @@ def load( ) if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "dispsf" + str(icomp) + name = f"dispsf{icomp}" if model.verbose: - print(" loading {}...".format(name)) + print(f" loading {name}...") u2d = Util2d.load( f, model, @@ -712,7 +710,7 @@ def load( m_arr = line.strip().split() nobssf = int(m_arr[0]) if model.verbose: - print(" NOBSSF {}".format(nobssf)) + print(f" NOBSSF {nobssf}") # If NOBSSF > 0, store observation segment & reach (Item 6) obs_sf = [] @@ -731,8 +729,8 @@ def load( print(" Surface water concentration observation locations:") text = "" for o in obs_sf: - text += "{} ".format(o) - print(" {}\n".format(text)) + text += f"{o} " + print(f" {text}\n") else: if model.verbose: print(" No observation points specified.") @@ -743,11 +741,7 @@ def load( # Item 7 NTMP (Transient data) if model.verbose: - print( - " loading NTMP...stress period {} of {}".format( - iper + 1, nper - ) - ) + print(f" loading NTMP...stress period {iper + 1} of {nper}") line = f.readline() m_arr = line.strip().split() ntmp = int(m_arr[0]) @@ -822,7 +816,7 @@ def load( sf_stress_period_data=sf_stress_period_data, unitnumber=unitnumber, filenames=filenames, - **kwargs + **kwargs, ) @staticmethod diff --git a/dependencies/flopy/mt3d/mtssm.py b/dependencies/flopy/mt3d/mtssm.py index 8c28002..c220834 100644 --- a/dependencies/flopy/mt3d/mtssm.py +++ b/dependencies/flopy/mt3d/mtssm.py @@ -1,4 +1,3 @@ -import sys import numpy as np import warnings from ..pakbase import Package @@ -165,7 +164,7 @@ def __init__( extension="ssm", unitnumber=None, filenames=None, - **kwargs + **kwargs, ): if unitnumber is None: @@ -202,10 +201,8 @@ def __init__( for key in kwargs: if key in deprecated_kwargs: warnings.warn( - "Deprecation Warning: Keyword argument '" - + key - + "' no longer supported. Use " - + "'stress_period_data' instead.", + "Deprecation Warning: Keyword argument '{}' no longer " + "supported. Use 'stress_period_data' instead.".format(key), category=UserWarning, ) @@ -243,13 +240,10 @@ def __init__( ) if mxss is None and mf is None: - wmsg = ( - "SSM Package: mxss is None and modflowmodel is None. " - + "Cannot calculate max number of sources and sinks. " - + "Estimating from stress_period_data. " - ) warnings.warn( - wmsg, + "SSM Package: mxss is None and modflowmodel is None. " + "Cannot calculate max number of sources and sinks. " + "Estimating from stress_period_data.", category=UserWarning, ) @@ -308,15 +302,13 @@ def __init__( if ncomp > 1: for icomp in range(2, ncomp + 1): val = 0.0 - name = "crch" + str(icomp) + name = f"crch{icomp}" if name in list(kwargs.keys()): val = kwargs.pop(name) else: print( - "SSM: setting crch for component " - + str(icomp) - + " to zero. kwarg name " - + name + "SSM: setting crch for component {} to zero. " + "kwarg name {}".format(icomp, name) ) t2d = Transient2d( model, @@ -370,16 +362,14 @@ def __init__( if ncomp > 1: for icomp in range(2, ncomp + 1): val = 0.0 - name = "cevt" + str(icomp) + name = f"cevt{icomp}" if name in list(kwargs.keys()): val = kwargs[name] kwargs.pop(name) else: print( - "SSM: setting cevt for component " - + str(icomp) - + " to zero, kwarg name " - + name + "SSM: setting cevt for component {} to zero, " + "kwarg name {}".format(icomp, name) ) t2d = Transient2d( model, @@ -453,7 +443,7 @@ def get_default_dtype(ncomp=1): ] if ncomp > 1: for comp in range(1, ncomp + 1): - comp_name = "cssm({0:02d})".format(comp) + comp_name = f"cssm({comp:02d})" type_list.append((comp_name, np.float32)) dtype = np.dtype(type_list) return dtype @@ -475,7 +465,7 @@ def write_file(self): f_ssm.write(" F F F F F F F F F F\n") - f_ssm.write("{:10d}\n".format(self.mxss)) + f_ssm.write(f"{self.mxss:10d}\n") # Loop through each stress period and write ssm information nper = self.parent.nper @@ -493,7 +483,7 @@ def write_file(self): incrch = max(incrch, incrchicomp) if incrch == 1: break - f_ssm.write("{:10d}\n".format(incrch)) + f_ssm.write(f"{incrch:10d}\n") if incrch == 1: for t2d in self.crch: u2d = t2d[kper] @@ -509,7 +499,7 @@ def write_file(self): incevt = max(incevt, incevticomp) if incevt == 1: break - f_ssm.write("{:10d}\n".format(incevt)) + f_ssm.write(f"{incevt:10d}\n") if incevt == 1: for t2d in self.cevt: u2d = t2d[kper] @@ -569,7 +559,7 @@ def load( """ if model.verbose: - sys.stdout.write("loading ssm package file...\n") + print("loading ssm package file...") # Open file, if necessary openfile = not hasattr(f, "read") @@ -627,16 +617,16 @@ def load( else: fnew4 = "F" if model.verbose: - print(" FWEL {}".format(fwel)) - print(" FDRN {}".format(fdrn)) - print(" FRCH {}".format(frch)) - print(" FEVT {}".format(fevt)) - print(" FRIV {}".format(friv)) - print(" FGHB {}".format(fghb)) - print(" FNEW1 {}".format(fnew1)) - print(" FNEW2 {}".format(fnew2)) - print(" FNEW3 {}".format(fnew3)) - print(" FNEW4 {}".format(fnew4)) + print(f" FWEL {fwel}") + print(f" FDRN {fdrn}") + print(f" FRCH {frch}") + print(f" FEVT {fevt}") + print(f" FRIV {friv}") + print(f" FGHB {fghb}") + print(f" FNEW1 {fnew1}") + print(f" FNEW2 {fnew2}") + print(f" FNEW3 {fnew3}") + print(f" FNEW4 {fnew4}") # Override the logical settings at top of ssm file using the # modflowmodel, if it is attached to parent @@ -659,8 +649,8 @@ def load( except: issgout = 0 if model.verbose: - print(" MXSS {}".format(mxss)) - print(" ISSGOUT {}".format(issgout)) + print(f" MXSS {mxss}") + print(f" ISSGOUT {issgout}") # kwargs needed to construct crch2, crch3, etc. for multispecies kwargs = {} @@ -671,7 +661,7 @@ def load( crch = {0: t2d} if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "crch" + str(icomp) + name = f"crch{icomp}" t2d = 0.0 kwargs[name] = {0: t2d} @@ -681,7 +671,7 @@ def load( cevt = {0: t2d} if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "cevt" + str(icomp) + name = f"cevt{icomp}" t2d = 0.0 kwargs[name] = {0: t2d} @@ -690,7 +680,7 @@ def load( for iper in range(nper): if model.verbose: - print(" loading ssm for kper {0:5d}".format(iper + 1)) + print(f" loading ssm for kper {iper + 1:5d}") # Item D3: INCRCH incrch = -1 @@ -717,9 +707,9 @@ def load( # Load each multispecies array if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "crch" + str(icomp) + name = f"crch{icomp}" if model.verbose: - print(" loading {}...".format(name)) + print(f" loading {name}...") t = Util2d.load( f, model, @@ -757,9 +747,9 @@ def load( # Load each multispecies array if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "cevt" + str(icomp) + name = f"cevt{icomp}" if model.verbose: - print(" loading {}...".format(name)) + print(f" loading {name}...") t = Util2d.load( f, model, @@ -778,7 +768,7 @@ def load( line = f.readline() nss = int(line[0:10]) if model.verbose: - print(" NSS {}".format(nss)) + print(f" NSS {nss}") # Item D8: KSS, ISS, JSS, CSS, ITYPE, (CSSMS(n),n=1,NCOMP) if model.verbose: @@ -830,7 +820,7 @@ def load( stress_period_data=stress_period_data, unitnumber=unitnumber, filenames=filenames, - **kwargs + **kwargs, ) @staticmethod diff --git a/dependencies/flopy/mt3d/mtuzt.py b/dependencies/flopy/mt3d/mtuzt.py index 3f4115d..acee737 100644 --- a/dependencies/flopy/mt3d/mtuzt.py +++ b/dependencies/flopy/mt3d/mtuzt.py @@ -144,7 +144,7 @@ def __init__( extension="uzt", unitnumber=None, filenames=None, - **kwargs + **kwargs, ): # set default unit number of one is not specified @@ -243,15 +243,13 @@ def __init__( if ncomp > 1: for icomp in range(2, ncomp + 1): val = 0.0 - name = "cuzinf" + str(icomp) + name = f"cuzinf{icomp}" if name in list(kwargs.keys()): val = kwargs.pop(name) else: print( "UZT: setting cuzinf for component " - + str(icomp) - + " to zero. kwarg name " - + name + f"{icomp} to zero. kwarg name {name}" ) t2d = Transient2d( @@ -278,15 +276,13 @@ def __init__( if ncomp > 1: for icomp in range(2, ncomp + 1): val = 0.0 - name = "cuzet" + str(icomp) + name = f"cuzet{icomp}" if name in list(kwargs.keys()): val = kwargs.pop(name) else: print( "UZT: setting cuzet for component " - + str(icomp) - + " to zero. kwarg name " - + name + f"{icomp} to zero. kwarg name {name}" ) t2d = Transient2d( @@ -313,15 +309,13 @@ def __init__( if ncomp > 1: for icomp in range(2, ncomp + 1): val = 0.0 - name = "cgwet" + str(icomp) + name = f"cgwet{icomp}" if name in list(kwargs.keys()): val = kwargs.pop(name) else: print( "UZT: setting cgwet for component " - + str(icomp) - + " to zero. kwarg name " - + name + f"{icomp} to zero. kwarg name {name}" ) t2d = Transient2d( @@ -351,13 +345,11 @@ def write_file(self): f_uzt = open(self.fn_path, "w") # Write header - f_uzt.write("#{0:s}\n".format(self.heading1)) + f_uzt.write(f"#{self.heading1}\n") # Item 2 f_uzt.write( - "{0:10d}{1:10d} #ICBCUZ, IET\n".format( - self.icbcuz, self.iet - ) + f"{self.icbcuz:10d}{self.iet:10d} #ICBCUZ, IET\n" ) # Item 3 @@ -381,9 +373,7 @@ def write_file(self): if incuzinf == 1: break f_uzt.write( - "{0:10d} # INCUZINF - SP {1:5d}\n".format( - incuzinf, kper + 1 - ) + f"{incuzinf:10d} # INCUZINF - SP {kper + 1:5d}\n" ) if incuzinf == 1: for t2d in self.cuzinf: @@ -402,9 +392,7 @@ def write_file(self): if incuzet == 1: break f_uzt.write( - "{0:10d} # INCUZET - SP {1:5d}\n".format( - incuzet, kper + 1 - ) + f"{incuzet:10d} # INCUZET - SP {kper + 1:5d}\n" ) if incuzet == 1: for t2d in self.cuzet: @@ -422,9 +410,7 @@ def write_file(self): if incgwet == 1: break f_uzt.write( - "{0:10d} # INCGWET - SP {1:5d}\n".format( - incgwet, kper + 1 - ) + f"{incgwet:10d} # INCGWET - SP {kper + 1:5d}\n" ) if incgwet == 1: for t2d in self.cgwet: @@ -507,7 +493,7 @@ def load( while line[0:1] == "#": i = 1 if model.verbose: - print(" Comment Line " + str(i) + ": ".format(line.strip())) + print(f" Comment Line {i}: {line.strip()}") i += 1 line = f.readline() @@ -537,7 +523,7 @@ def load( cuzinf = {0: t2d} if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "cuzinf" + str(icomp) + name = f"cuzinf{icomp}" t2d = Transient2d( model, (nrow, ncol), np.float32, 0.0, name=name, locat=0 ) @@ -552,7 +538,7 @@ def load( cuzet = {0: t2d} if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "cuzet" + str(icomp) + name = f"cuzet{icomp}" t2d = Transient2d( model, (nrow, ncol), @@ -571,7 +557,7 @@ def load( cgwet = {0: t2d} if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "cgwet" + str(icomp) + name = f"cgwet{icomp}" t2d = Transient2d( model, (nrow, ncol), @@ -589,7 +575,7 @@ def load( for iper in range(nper): if model.verbose: - print(" loading UZT data for kper {0:5d}".format(iper + 1)) + print(f" loading UZT data for kper {iper + 1:5d}") # Item 4 (INCUZINF) line = f.readline() @@ -599,10 +585,7 @@ def load( # Item 5 (CUZINF) if incuzinf >= 0: if model.verbose: - print( - " Reading CUZINF array for kper " - "{0:5d}".format(iper + 1) - ) + print(f" Reading CUZINF array for kper {iper + 1:5d}") t = Util2d.load( f, model, (nrow, ncol), np.float32, "cuzinf", ext_unit_dict ) @@ -611,9 +594,9 @@ def load( # Load each multispecies array if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "cuzinf" + str(icomp) + name = f"cuzinf{icomp}" if model.verbose: - print(" loading {}...".format(name)) + print(f" loading {name}...") t = Util2d.load( f, model, @@ -640,9 +623,8 @@ def load( elif incuzinf < 0 and iper > 0: if model.verbose: print( - " Reusing CUZINF array from kper " - "{0:5d}".format(iper) + " in kper " - "{0:5d}".format(iper + 1) + f" Reusing CUZINF array from kper {iper:5d}" + f" in kper {iper + 1:5d}" ) if iet != 0: @@ -654,10 +636,7 @@ def load( # Item 7 (CUZET) if incuzet >= 0: if model.verbose: - print( - " Reading CUZET array for kper " - "{0:5d}".format(iper + 1) - ) + print(f" Reading CUZET array for kper {iper + 1:5d}") t = Util2d.load( f, model, @@ -671,9 +650,9 @@ def load( # Load each multispecies array if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "cuzet" + str(icomp) + name = f"cuzet{icomp}" if model.verbose: - print(" loading {}".format(name)) + print(f" loading {name}") t = Util2d.load( f, model, @@ -699,9 +678,8 @@ def load( else: if model.verbose: print( - " Reusing CUZET array from kper " - "{0:5d}".format(iper) + " in kper " - "{0:5d}".format(iper + 1) + f" Reusing CUZET array from kper {iper:5d}" + f" in kper {iper + 1:5d}" ) # Item 8 (INCGWET) @@ -712,10 +690,7 @@ def load( # Item 9 (CGWET) if model.verbose: if incuzet >= 0: - print( - " Reading CGWET array for kper " - "{0:5d}".format(iper + 1) - ) + print(f" Reading CGWET array for kper {iper + 1:5d}") t = Util2d.load( f, model, @@ -729,9 +704,9 @@ def load( # Load each multispecies array if ncomp > 1: for icomp in range(2, ncomp + 1): - name = "cgwet" + str(icomp) + name = f"cgwet{icomp}" if model.verbose: - print(" loading {}...".format(name)) + print(f" loading {name}...") t = Util2d.load( f, model, @@ -758,9 +733,8 @@ def load( elif incgwet < 0 and iper > 0: if model.verbose: print( - " Reusing CGWET array from kper " - "{0:5d}".format(iper) + " in kper " - "{0:5d}".format(iper + 1) + f" Reusing CGWET array from kper {iper:5d}" + f" in kper {iper + 1:5d}" ) if openfile: @@ -789,7 +763,7 @@ def load( cgwet=cgwet, unitnumber=unitnumber, filenames=filenames, - **kwargs + **kwargs, ) @staticmethod diff --git a/dependencies/flopy/pakbase.py b/dependencies/flopy/pakbase.py index b04dc68..f8019c0 100644 --- a/dependencies/flopy/pakbase.py +++ b/dependencies/flopy/pakbase.py @@ -4,9 +4,6 @@ all of the other packages inherit from. """ - -from __future__ import print_function - import abc import os import webbrowser as wb @@ -25,35 +22,35 @@ class PackageInterface: @abc.abstractmethod def name(self): raise NotImplementedError( - "must define name in child " "class to use this base class" + "must define name in child class to use this base class" ) @name.setter @abc.abstractmethod def name(self, name): raise NotImplementedError( - "must define name in child " "class to use this base class" + "must define name in child class to use this base class" ) @property @abc.abstractmethod def parent(self): raise NotImplementedError( - "must define parent in child " "class to use this base class" + "must define parent in child class to use this base class" ) @parent.setter @abc.abstractmethod def parent(self, name): raise NotImplementedError( - "must define parent in child " "class to use this base class" + "must define parent in child class to use this base class" ) @property @abc.abstractmethod def package_type(self): raise NotImplementedError( - "must define package_type in child " "class to use this base class" + "must define package_type in child class to use this base class" ) @property @@ -61,20 +58,20 @@ def package_type(self): def data_list(self): # [data_object, data_object, ...] raise NotImplementedError( - "must define data_list in child " "class to use this base class" + "must define data_list in child class to use this base class" ) @abc.abstractmethod def export(self, f, **kwargs): raise NotImplementedError( - "must define export in child " "class to use this base class" + "must define export in child class to use this base class" ) @property @abc.abstractmethod def plottable(self): raise NotImplementedError( - "must define plottable in child " "class to use this base class" + "must define plottable in child class to use this base class" ) @property @@ -88,13 +85,13 @@ def _check_thresholds(chk, array, active, thresholds, name): chk.values( array, active & (array < mn), - "{} values below checker threshold of {}".format(name, mn), + f"{name} values below checker threshold of {mn}", "Warning", ) chk.values( array, active & (array > mx), - "{} values above checker threshold of {}".format(name, mx), + f"{name} values above checker threshold of {mx}", "Warning", ) @@ -246,7 +243,7 @@ def _check_flowp(self, f=None, verbose=True, level=1, checktype=None): chk.values( self.__dict__[kp].array, active & (self.__dict__[kp].array <= 0), - "zero or negative {} values".format(name), + f"zero or negative {name} values", "Error", ) @@ -338,9 +335,7 @@ def check(self, f=None, verbose=True, level=1, checktype=None): storage_coeff = False self._check_storage(chk, storage_coeff) else: - txt = "check method not implemented for " + "{} Package.".format( - self.name[0] - ) + txt = f"check method not implemented for {self.name[0]} Package." if f is not None: if isinstance(f, str): pth = os.path.join(self.parent.model_ws, f) @@ -360,9 +355,8 @@ def _check_storage(self, chk, storage_coeff): # convert to specific for checking if storage_coeff: desc = ( - "\r STORAGECOEFFICIENT option is " - + "activated, storage values are read " - + "storage coefficients" + "\r STORAGECOEFFICIENT option is activated, " + "storage values are read storage coefficients" ) chk._add_to_summary(type="Warning", desc=desc) chk.values( @@ -380,6 +374,7 @@ def _check_storage(self, chk, storage_coeff): ) # only check specific yield for convertible layers + skip_sy_check = False if "laytyp" in self.__dict__: inds = np.array( [ @@ -389,25 +384,28 @@ def _check_storage(self, chk, storage_coeff): for l in self.laytyp ] ) - if self.ss.shape[1] is None: - # unstructured; build flat nodal property array slicers (by layer) - node_to = np.cumsum([s.array.size for s in self.ss]) - node_from = np.array([0] + list(node_to[:-1])) - node_k_slices = np.array( - [ - np.s_[n_from:n_to] - for n_from, n_to in zip(node_from, node_to) - ] - )[inds] - sarrays["sy"] = np.asarray( - [sarrays["sy"][sl] for sl in node_k_slices] - ).flatten() - active = np.asarray( - [active[sl] for sl in node_k_slices] - ).flatten() + if inds.any(): + if self.sy.shape[1] is None: + # unstructured; build flat nodal property array slicers (by layer) + node_to = np.cumsum([s.array.size for s in self.ss]) + node_from = np.array([0] + list(node_to[:-1])) + node_k_slices = np.array( + [ + np.s_[n_from:n_to] + for n_from, n_to in zip(node_from, node_to) + ] + )[inds] + sarrays["sy"] = np.concatenate( + [sarrays["sy"][sl] for sl in node_k_slices] + ).flatten() + active = np.concatenate( + [active[sl] for sl in node_k_slices] + ).flatten() + else: + sarrays["sy"] = sarrays["sy"][inds, :, :] + active = active[inds, :, :] else: - sarrays["sy"] = sarrays["sy"][inds, :, :] - active = active[inds, :, :] + skip_sy_check = True else: iconvert = self.iconvert.array for ishape in np.ndindex(active.shape): @@ -415,19 +413,20 @@ def _check_storage(self, chk, storage_coeff): active[ishape] = ( iconvert[ishape] > 0 or iconvert[ishape] < 0 ) - chk.values( - sarrays["sy"], - active & (sarrays["sy"] < 0), - "zero or negative specific yield values", - "Error", - ) - self._check_thresholds( - chk, - sarrays["sy"], - active, - chk.property_threshold_values["sy"], - "specific yield", - ) + if not skip_sy_check: + chk.values( + sarrays["sy"], + active & (sarrays["sy"] < 0), + "zero or negative specific yield values", + "Error", + ) + self._check_thresholds( + chk, + sarrays["sy"], + active, + chk.property_threshold_values["sy"], + "specific yield", + ) class Package(PackageInterface): @@ -458,7 +457,7 @@ def __init__( self.file_name = [] for idx, e in enumerate(extension): self.extension.append(e) - file_name = self.parent.name + "." + e + file_name = f"{self.parent.name}.{e}" if filenames is not None: if idx < len(filenames): if filenames[idx] is not None: @@ -490,21 +489,13 @@ def __repr__(self): if not (attr in exclude_attributes): if isinstance(value, list): if len(value) == 1: - s += " {:s} = {:s}\n".format(attr, str(value[0])) + s += f" {attr} = {value[0]!s}\n" else: - s += " {:s} ".format( - attr - ) + "(list, items = {:d})\n".format(len(value)) + s += f" {attr} (list, items = {len(value)})\n" elif isinstance(value, np.ndarray): - s += " {:s} (array, shape = ".format( - attr - ) + "{:s})\n".format(value.shape.__str__()[1:-1]) + s += f" {attr} (array, shape = {str(value.shape)[1:-1]})\n" else: - s += ( - " {:s} = ".format(attr) - + "{:s} ".format(str(value)) - + "({:s})\n".format(str(type(value))[7:-2]) - ) + s += f" {attr} = {value!s} ({str(type(value))[7:-2]})\n" return s def __getitem__(self, item): @@ -515,26 +506,19 @@ def __getitem__(self, item): if isinstance(item, MfList): if not isinstance(item, list) and not isinstance(item, tuple): msg = ( - "package.__getitem__() kper " - + str(item) - + " not in data.keys()" + f"package.__getitem__() kper {item} not in data.keys()" ) assert item in list(spd.data.keys()), msg return spd[item] if item[1] not in self.dtype.names: - msg = ( - "package.__getitem(): item " - + str(item) - + " not in dtype names " - + str(self.dtype.names) + raise Exception( + "package.__getitem(): item {} not in dtype names " + "{}".format(item, self.dtype.names) ) - raise Exception(msg) msg = ( - "package.__getitem__() kper " - + str(item[0]) - + " not in data.keys()" + f"package.__getitem__() kper {item[0]} not in data.keys()" ) assert item[0] in list(spd.data.keys()), msg @@ -680,6 +664,17 @@ def export(self, f, **kwargs): return export.utils.package_export(f, self, **kwargs) + def _generate_heading(self): + """Generate heading.""" + from flopy import __version__ + + parent = self.parent + self.heading = ( + f"# {self.name[0]} package for " + f"{parent.version_types[parent.version]} " + f"generated by Flopy {__version__}" + ) + @staticmethod def add_to_dtype(dtype, field_names, field_types): """ @@ -727,7 +722,7 @@ def _confined_layer_check(self, chk): if confined and l > 0: desc = ( "\r LAYTYP: unconfined (convertible) " - + "layer below confined layer" + "layer below confined layer" ) chk._add_to_summary(type="Warning", desc=desc) @@ -739,30 +734,17 @@ def level1_arraylist(self, idx, v, name, txt): if k > kon: kon = k tag = name[k].lower().replace(" layer ", "") - txt += ( - " {:>10s}".format("layer") - + "{:>10s}".format("row") - + "{:>10s}".format("column") - + "{:>15s}\n".format(tag) - ) - txt += " {:10d}{:10d}{:10d}{:15.7g}\n".format( - k + 1, i + 1, j + 1, v[k, i, j] - ) + txt += f" {'layer':>10s}{'row':>10s}{'column':>10s}{tag:>15s}\n" + txt += f" {k + 1:10d}{i + 1:10d}{j + 1:10d}{v[k, i, j]:15.7g}\n" elif ndim == 2: tag = name[0].lower().replace(" layer ", "") - txt += ( - " {:>10s}".format("row") - + "{:>10s}".format("column") - + "{:>15s}\n".format(tag) - ) + txt += f" {'row':>10s}{'column':>10s}{tag:>15s}\n" for [i, j] in idx: - txt += " {:10d}{:10d}{:15.7g}\n".format( - i + 1, j + 1, v[i, j] - ) + txt += f" {i + 1:10d}{j + 1:10d}{v[i, j]:15.7g}\n" elif ndim == 1: - txt += " {:>10s}{:>15s}\n".format("number", name[0]) + txt += f" {'number':>10s}{name[0]:>15s}\n" for i in idx: - txt += " {:10d}{:15.7g}\n".format(i + 1, v[i]) + txt += f" {i + 1:10d}{v[i]:15.7g}\n" return txt def plot(self, **kwargs): @@ -811,7 +793,7 @@ def plot(self, **kwargs): from flopy.plot import PlotUtilities if not self.plottable: - raise TypeError("Package {} is not plottable".format(self.name)) + raise TypeError(f"Package {self.name} is not plottable") axes = PlotUtilities._plot_package_helper(self, **kwargs) return axes @@ -850,20 +832,11 @@ def to_shapefile(self, filename, **kwargs): def webdoc(self): if self.parent.version == "mf2k": - wa = ( - "http://water.usgs.gov/nrp/gwsoftware/modflow2000/Guide/" - + self.url - ) + wa = f"http://water.usgs.gov/nrp/gwsoftware/modflow2000/Guide/{self.url}" elif self.parent.version == "mf2005": - wa = ( - "http://water.usgs.gov/ogw/modflow/MODFLOW-2005-Guide/" - + self.url - ) + wa = f"http://water.usgs.gov/ogw/modflow/MODFLOW-2005-Guide/{self.url}" elif self.parent.version == "ModflowNwt": - wa = ( - "http://water.usgs.gov/ogw/modflow-nwt/MODFLOW-NWT-Guide/" - + self.url - ) + wa = f"http://water.usgs.gov/ogw/modflow-nwt/MODFLOW-NWT-Guide/{self.url}" else: wa = None @@ -934,12 +907,9 @@ def load(f, model, pak_type, ext_unit_dict=None, **kwargs): if nppak > 0: mxl = int(t[2]) if model.verbose: - msg = ( - 3 * " " - + "Parameters detected. Number of " - + "parameters = {}".format(nppak) + print( + f" Parameters detected. Number of parameters = {nppak}" ) - print(msg) line = f.readline() # dataset 2a @@ -950,26 +920,21 @@ def load(f, model, pak_type, ext_unit_dict=None, **kwargs): ipakcb = int(t[1]) except: if model.verbose: - msg = 3 * " " + "implicit ipakcb in {}".format(filename) - print(msg) + print(f" implicit ipakcb in {filename}") if "modflowdrt" in pak_type_str: try: nppak = int(t[2]) imax += 1 except: if model.verbose: - msg = 3 * " " + "implicit nppak in {}".format(filename) - print(msg) + print(f" implicit nppak in {filename}") if nppak > 0: mxl = int(t[3]) imax += 1 if model.verbose: - msg = ( - 3 * " " - + "Parameters detected. Number of " - + "parameters = {}".format(nppak) + print( + f" Parameters detected. Number of parameters = {nppak}" ) - print(msg) options = [] aux_names = [] @@ -986,13 +951,14 @@ def load(f, model, pak_type, ext_unit_dict=None, **kwargs): it += 1 # add auxillary information to nwt options - if nwt_options is not None and options: - if options[0] == "noprint": - nwt_options.noprint = True - if len(options) > 1: - nwt_options.auxillary = options[1:] - else: - nwt_options.auxillary = options + if nwt_options is not None: + if options: + if options[0] == "noprint": + nwt_options.noprint = True + if len(options) > 1: + nwt_options.auxillary = options[1:] + else: + nwt_options.auxillary = options options = nwt_options @@ -1047,11 +1013,7 @@ def load(f, model, pak_type, ext_unit_dict=None, **kwargs): current = None for iper in range(nper): if model.verbose: - msg = ( - " loading " - + str(pak_type) - + " for kper {:5d}".format(iper + 1) - ) + msg = f" loading {pak_type} for kper {iper + 1:5d}" print(msg) line = f.readline() if line == "": @@ -1063,7 +1025,7 @@ def load(f, model, pak_type, ext_unit_dict=None, **kwargs): itmpp = int(t[1]) except: if model.verbose: - print(" implicit itmpp in {}".format(filename)) + print(f" implicit itmpp in {filename}") if itmp == 0: bnd_output = None @@ -1106,8 +1068,7 @@ def load(f, model, pak_type, ext_unit_dict=None, **kwargs): except: if model.verbose: print( - " implicit static instance for " - + "parameter {}".format(pname) + f" implicit static instance for parameter {pname}" ) par_dict, current_dict = pak_parms.get(pname) @@ -1187,7 +1148,7 @@ def load(f, model, pak_type, ext_unit_dict=None, **kwargs): ) if check: pak.check( - f="{}.chk".format(pak.name[0]), + f=f"{pak.name[0]}.chk", verbose=pak.parent.verbose, level=0, ) diff --git a/dependencies/flopy/pest/params.py b/dependencies/flopy/pest/params.py index 94d2121..7dc2535 100644 --- a/dependencies/flopy/pest/params.py +++ b/dependencies/flopy/pest/params.py @@ -1,4 +1,3 @@ -from __future__ import print_function import numpy as np @@ -76,7 +75,7 @@ def zonearray2params( for i, iz in enumerate(parzones): span = {} span["idx"] = np.where(zonearray == iz) - parname = partype + "_" + str(iz) + parname = f"{partype}_{iz}" startvalue = parvals[i] p = Params( mfpackage, diff --git a/dependencies/flopy/pest/templatewriter.py b/dependencies/flopy/pest/templatewriter.py index 6ee6755..fcbb80e 100644 --- a/dependencies/flopy/pest/templatewriter.py +++ b/dependencies/flopy/pest/templatewriter.py @@ -1,4 +1,3 @@ -from __future__ import print_function from ..pest import tplarray as tplarray @@ -43,7 +42,7 @@ def write_template(self): try: pak = self.model.get_package(ftype) except: - raise Exception("Package type {} not found.".format(ftype)) + raise Exception(f"Package type {ftype} not found.") # Check to make sure pak has p.type as an attribute if not hasattr(pak, p.type.lower()): @@ -57,10 +56,7 @@ def write_template(self): ftypelist.append(ftype) # Print a list of packages that will be parameterized - print( - "The following packages will be parameterized: " - "{}\n".format(ftypelist) - ) + print(f"The following packages will be parameterized: {ftypelist}\n") # Go through each package, and then through each parameter and make # the substitution. Then write the template file. diff --git a/dependencies/flopy/pest/tplarray.py b/dependencies/flopy/pest/tplarray.py index 8d4657a..c07156a 100644 --- a/dependencies/flopy/pest/tplarray.py +++ b/dependencies/flopy/pest/tplarray.py @@ -1,4 +1,3 @@ -from __future__ import print_function import numpy as np from ..utils.util_array import Util3d as Util3d from ..utils.util_array import Transient2d as Transient2d @@ -31,18 +30,14 @@ def add_parameter(self, p): """ # Verify parameter span contents if "kpers" not in p.span: - raise Exception( - "Parameter {} span does not contain kper.".format(p.name) - ) + raise Exception(f"Parameter {p.name} span does not contain kper.") if "idx" not in p.span: - raise Exception( - "Parameter {} span does not contain idx.".format(p.name) - ) + raise Exception(f"Parameter {p.name} span does not contain idx.") if p.span["idx"] is None: # Multiplier parameter is when p.span['idx'] is None for kper in p.span["kpers"]: - self.multipliers[kper] = "~ {0:^13s} ~".format(p.name) + self.multipliers[kper] = f"~ {p.name:^13s} ~" else: # Index parameter otherwise for kper in p.span["kpers"]: @@ -76,7 +71,7 @@ def get_kper_entry(self, kper): if kper in self.params: for p in self.params[kper]: idx = p.span["idx"] - chararray[idx] = "~{0:^13s}~".format(p.name) + chararray[idx] = f"~{p.name:^13s}~" u2dtpl = Util2dTpl(chararray, u2d.name, multiplier, indexed_param) return (1, u2dtpl.get_file_entry()) else: @@ -126,19 +121,18 @@ def add_parameter(self, p): if "layers" in p.span and "idx" in p.span: if p.span["idx"] is not None: - e = ( + raise Exception( "For a Util3d object, cannot have layers and " - + "idx in parameter.span" + "idx in parameter.span" ) - raise Exception(e) if "layers" in p.span: for l in p.span["layers"]: - self.multipliers[l] = "~ {0:^13s} ~".format(p.name) + self.multipliers[l] = f"~ {p.name:^13s} ~" if "idx" in p.span and p.span["idx"] is not None: idx = p.span["idx"] - self.chararray[idx] = "~{0:^13s}~".format(p.name) + self.chararray[idx] = f"~{p.name:^13s}~" self.indexed_params = True return @@ -179,18 +173,18 @@ def get_file_entry(self): ncol = self.chararray.shape[-1] au = np.unique(self.chararray) if au.shape[0] == 1 and self.multiplier is None: - file_entry = "CONSTANT {0} #{1}\n".format(au[0], self.name) + file_entry = f"CONSTANT {au[0]} #{self.name}\n" else: mult = 1.0 if self.multiplier is not None: mult = self.multiplier - cr = "INTERNAL {0} (FREE) -1 #{1}\n".format(mult, self.name) + cr = f"INTERNAL {mult} (FREE) -1 #{self.name}\n" astring = "" icount = 0 for i in range(self.chararray.shape[0]): for j in range(self.chararray.shape[1]): icount += 1 - astring += " {0:>15s}".format(self.chararray[i, j]) + astring += f" {self.chararray[i, j]:>15s}" if icount == 10 or j == ncol - 1: astring += "\n" icount = 0 diff --git a/dependencies/flopy/plot/__init__.py b/dependencies/flopy/plot/__init__.py index e6da91d..016fdc8 100644 --- a/dependencies/flopy/plot/__init__.py +++ b/dependencies/flopy/plot/__init__.py @@ -26,6 +26,6 @@ shapefile_extents, PlotUtilities, ) -from .map import ModelMap, PlotMapView -from .crosssection import ModelCrossSection, PlotCrossSection +from .map import PlotMapView +from .crosssection import PlotCrossSection from .styles import styles diff --git a/dependencies/flopy/plot/crosssection.py b/dependencies/flopy/plot/crosssection.py index 06d8a90..49b213e 100644 --- a/dependencies/flopy/plot/crosssection.py +++ b/dependencies/flopy/plot/crosssection.py @@ -4,7 +4,7 @@ import matplotlib.pyplot as plt import matplotlib.colors from matplotlib.patches import Polygon -except (ImportError, ModuleNotFoundError): +except (ImportError, ModuleNotFoundError, RuntimeError): plt = None from flopy.plot import plotutil @@ -57,11 +57,10 @@ def __init__( self.ax = ax self.geographic_coords = geographic_coords if plt is None: - s = ( + raise ImportError( "Could not import matplotlib. Must install matplotlib " - + " in order to use ModelCrossSection method" + "in order to use ModelCrossSection method" ) - raise ImportError(s) self.model = model @@ -88,7 +87,7 @@ def __init__( "dictionary keys specified: " ) for k in line.keys(): - s += "{} ".format(k) + s += f"{k} " raise AssertionError(s) if ax is None: @@ -180,7 +179,7 @@ def __init__( if len(self.xypts) < 2: s = "cross-section cannot be created\n." s += " less than 2 points intersect the model grid\n" - s += " {} points intersect the grid.".format(len(self.xypts)) + s += f" {len(self.xypts)} points intersect the grid." raise Exception(s) if self.geographic_coords: @@ -431,7 +430,7 @@ def plot_fill_between( colors=("blue", "red"), masked_values=None, head=None, - **kwargs + **kwargs, ): """ Plot a three-dimensional array as lines. @@ -506,9 +505,7 @@ def contour_array(self, a, masked_values=None, head=None, **kwargs): """ if plt is None: - err_msg = ( - "matplotlib must be installed to " + "use contour_array()" - ) + err_msg = "matplotlib must be installed to use contour_array()" raise ImportError(err_msg) else: import matplotlib.tri as tri @@ -649,7 +646,7 @@ def plot_ibound( color_ch="blue", color_vpt="red", head=None, - **kwargs + **kwargs, ): """ Make a plot of ibound. If not specified, then pull ibound from the @@ -703,7 +700,7 @@ def plot_ibound( head=head, cmap=cmap, norm=norm, - **kwargs + **kwargs, ) return patches @@ -790,7 +787,7 @@ def plot_bc( mflist = pp.stress_period_data.array[kper] except Exception as e: raise Exception( - "Not a list-style boundary package: " + str(e) + f"Not a list-style boundary package: {e!s}" ) if mflist is None: return @@ -813,7 +810,7 @@ def plot_bc( mflist = p.stress_period_data[kper] except Exception as e: raise Exception( - "Not a list-style boundary package: " + str(e) + f"Not a list-style boundary package: {e!s}" ) if mflist is None: return @@ -849,7 +846,7 @@ def plot_bc( head=head, cmap=cmap, norm=norm, - **kwargs + **kwargs, ) return patches @@ -864,7 +861,7 @@ def plot_vector( hstep=1, normalize=False, masked_values=None, - **kwargs + **kwargs, ): """ Plot a vector. @@ -995,198 +992,6 @@ def plot_vector( return quiver - def plot_specific_discharge( - self, spdis, head=None, kstep=1, hstep=1, normalize=False, **kwargs - ): - """ - DEPRECATED. Use plot_vector() instead, which should follow after - postprocessing.get_specific_discharge(). - - Use quiver to plot vectors. - - Parameters - ---------- - spdis : np.recarray - numpy recarray of specific discharge information. This - can be grabbed directly from the CBC file if - SAVE_SPECIFIC_DISCHARGE is used in the MF6 NPF file. - head : numpy.ndarray - MODFLOW's head array. If not provided, then the quivers will be - plotted in the cell center. - kstep : int - layer frequency to plot. (Default is 1.) - hstep : int - horizontal frequency to plot. (Default is 1.) - normalize : bool - boolean flag used to determine if discharge vectors should - be normalized using the magnitude of the specific discharge in each - cell. (default is False) - kwargs : dictionary - Keyword arguments passed to plt.quiver() - - Returns - ------- - quiver : matplotlib.pyplot.quiver - Vectors - - """ - import warnings - - warnings.warn( - "plot_specific_discharge() has been deprecated and will be" - "removed in version 3.3.5. Use plot_vector() instead, which " - "should follow after postprocessing.get_specific_discharge()", - DeprecationWarning, - ) - - if isinstance(spdis, list): - print( - "Warning: Selecting the final stress period from Specific" - " Discharge list" - ) - spdis = spdis[-1] - - ncpl = self._ncpl - nlay = self._nlay - - qx = np.zeros((nlay * ncpl)) - qy = np.zeros((nlay * ncpl)) - qz = np.zeros((nlay * ncpl)) - - idx = np.array(spdis["node"]) - 1 - qx[idx] = spdis["qx"] - qy[idx] = spdis["qy"] - qz[idx] = spdis["qz"] - - return self.plot_vector( - qx, - qy, - qz, - head=head, - kstep=kstep, - hstep=hstep, - normalize=normalize, - **kwargs - ) - - def plot_discharge( - self, - frf, - fff, - flf=None, - head=None, - kstep=1, - hstep=1, - normalize=False, - **kwargs - ): - """ - DEPRECATED. Use plot_vector() instead, which should follow after - postprocessing.get_specific_discharge(). - - Use quiver to plot vectors. - - Parameters - ---------- - frf : numpy.ndarray - MODFLOW's 'flow right face' - fff : numpy.ndarray - MODFLOW's 'flow front face' - flf : numpy.ndarray - MODFLOW's 'flow lower face' (Default is None.) - head : numpy.ndarray - MODFLOW's head array. If not provided, then will assume confined - conditions in order to calculated saturated thickness. - kstep : int - layer frequency to plot. (Default is 1.) - hstep : int - horizontal frequency to plot. (Default is 1.) - normalize : bool - boolean flag used to determine if discharge vectors should - be normalized using the magnitude of the specific discharge in each - cell. (default is False) - kwargs : dictionary - Keyword arguments passed to plt.quiver() - - Returns - ------- - quiver : matplotlib.pyplot.quiver - Vectors - - """ - import warnings - - warnings.warn( - "plot_discharge() has been deprecated and will be removed in" - "version 3.3.5. Use plot_vector() instead, which should follow " - "after postprocessing.get_specific_discharge()", - DeprecationWarning, - ) - - if self.mg.grid_type != "structured": - err_msg = "Use plot_specific_discharge for " "{} grids".format( - self.mg.grid_type - ) - raise NotImplementedError(err_msg) - - else: - delr = self.mg.delr - delc = self.mg.delc - top = self.mg.top - botm = self.mg.botm - if not np.all(self.active == 1): - botm = botm[self.active == 1] - nlay = botm.shape[0] - laytyp = None - hnoflo = 999.0 - hdry = 999.0 - - if self.model is not None: - if self.model.laytyp is not None: - laytyp = self.model.laytyp - - if self.model.hnoflo is not None: - hnoflo = self.model.hnoflo - - if self.model.hdry is not None: - hdry = self.model.hdry - - # If no access to head or laytyp, then calculate confined saturated - # thickness by setting laytyp to zeros - if head is None or laytyp is None: - head = np.zeros(botm.shape, np.float32) - laytyp = np.zeros((nlay,), dtype=int) - head[0, :, :] = top - if nlay > 1: - head[1:, :, :] = botm[:-1, :, :] - - sat_thk = plotutil.PlotUtilities.saturated_thickness( - head, top, botm, laytyp, [hnoflo, hdry] - ) - - # Calculate specific discharge - qx, qy, qz = plotutil.PlotUtilities.centered_specific_discharge( - frf, fff, flf, delr, delc, sat_thk - ) - - if qz is None: - qz = np.zeros(qx.shape, dtype=float) - - qx = qx.ravel() - qy = qy.ravel() - qz = qz.ravel() - - return self.plot_vector( - qx, - qy, - qz, - head=head, - kstep=kstep, - hstep=hstep, - normalize=normalize, - **kwargs - ) - def plot_pathline( self, pl, travel_time=None, method="cell", head=None, **kwargs ): @@ -1345,7 +1150,7 @@ def plot_endpoint( selection_direction=None, method="cell", head=None, - **kwargs + **kwargs, ): """ @@ -1702,112 +1507,3 @@ def get_grid_patch_collection( patches = None return patches - - -class DeprecatedCrossSection(PlotCrossSection): - """ - Deprecation handler for the PlotCrossSection class - - Parameters - ---------- - ax : matplotlib.pyplot.axes object - model : flopy.modflow.Modflow object - modelgrid : flopy.discretization.Grid object - line : dict - Dictionary with either "row", "column", or "line" key. If key - is "row" or "column" key value should be the zero-based row or - column index for cross-section. If key is "line" value should - be an array of (x, y) tuples with vertices of cross-section. - Vertices should be in map coordinates consistent with xul, - yul, and rotation. - extent : tuple of floats - (xmin, xmax, ymin, ymax) will be used to specify axes limits. If None - then these will be calculated based on grid, coordinates, and rotation. - - """ - - def __init__( - self, ax=None, model=None, modelgrid=None, line=None, extent=None - ): - super().__init__( - ax=ax, model=model, modelgrid=modelgrid, line=line, extent=extent - ) - - -class ModelCrossSection: - """ - DEPRECATED. Class to create a cross section of the model. - - Parameters - ---------- - ax : matplotlib.pyplot axis - The plot axis. If not provided it, plt.gca() will be used. - model : flopy.modflow object - flopy model object. (Default is None) - dis : flopy.modflow.ModflowDis object - flopy discretization object. (Default is None) - line : dict - Dictionary with either "row", "column", or "line" key. If key - is "row" or "column" key value should be the zero-based row or - column index for cross-section. If key is "line" value should - be an array of (x, y) tuples with vertices of cross-section. - Vertices should be in map coordinates consistent with xul, - yul, and rotation. - xul : float - x coordinate for upper left corner - yul : float - y coordinate for upper left corner. The default is the sum of the - delc array. - rotation : float - Angle of grid rotation around the upper left corner. A positive value - indicates clockwise rotation. Angles are in degrees. Default is None - extent : tuple of floats - (xmin, xmax, ymin, ymax) will be used to specify axes limits. If None - then these will be calculated based on grid, coordinates, and rotation. - - """ - - def __new__( - cls, - ax=None, - model=None, - dis=None, - line=None, - xul=None, - yul=None, - rotation=None, - extent=None, - ): - - from flopy.discretization import StructuredGrid - - err_msg = ( - "ModelCrossSection is Deprecated and has been replaced by " - "PlotCrossSection(). ModelCrossSection will be removed in " - "version 3.3.5, Calling PlotCrossSection()" - ) - warnings.warn(err_msg, DeprecationWarning) - - modelgrid = None - if model is not None: - if (xul, yul, rotation) != (None, None, None): - modelgrid = plotutil._set_coord_info( - model.modelgrid, xul, yul, None, None, rotation - ) - - elif dis is not None: - modelgrid = StructuredGrid( - delr=dis.delr.array, - delc=dis.delc.array, - top=dis.top.array, - botm=dis.botm.array, - ) - - if (xul, yul, rotation) != (None, None, None): - modelgrid = plotutil._set_coord_info( - modelgrid, xul, yul, None, None, rotation - ) - - return DeprecatedCrossSection( - ax=ax, model=model, modelgrid=modelgrid, line=line, extent=extent - ) diff --git a/dependencies/flopy/plot/map.py b/dependencies/flopy/plot/map.py index 6f7dbf2..0ea4440 100644 --- a/dependencies/flopy/plot/map.py +++ b/dependencies/flopy/plot/map.py @@ -7,7 +7,7 @@ import matplotlib.colors from matplotlib.collections import PathCollection, LineCollection from matplotlib.path import Path -except (ImportError, ModuleNotFoundError): +except (ImportError, ModuleNotFoundError, RuntimeError): plt = None from . import plotutil @@ -48,11 +48,10 @@ def __init__( ): if plt is None: - s = ( + raise ImportError( "Could not import matplotlib. Must install matplotlib " - + " in order to use ModelMap method" + "in order to use ModelMap method" ) - raise ImportError(s) self.model = model self.layer = layer @@ -304,7 +303,7 @@ def plot_ibound( color_noflow="black", color_ch="blue", color_vpt="red", - **kwargs + **kwargs, ): """ Make a plot of ibound. If not specified, then pull ibound from the @@ -390,7 +389,7 @@ def plot_bc( kper=0, color=None, plotAll=False, - **kwargs + **kwargs, ): """ Plot boundary conditions locations for a specific boundary @@ -447,7 +446,7 @@ def plot_bc( mflist = pp.stress_period_data.array[kper] except Exception as e: raise Exception( - "Not a list-style boundary package: " + str(e) + f"Not a list-style boundary package: {e!s}" ) if mflist is None: return @@ -470,7 +469,7 @@ def plot_bc( mflist = p.stress_period_data[kper] except Exception as e: raise Exception( - "Not a list-style boundary package: " + str(e) + f"Not a list-style boundary package: {e!s}" ) if mflist is None: return @@ -487,8 +486,10 @@ def plot_bc( pa[tuple(idx[1:])] = 1 for k in range(nlay): plotarray[k] = pa.copy() - else: + elif len(self.mg.shape) > 1: plotarray[tuple(idx)] = 1 + else: + plotarray[idx] = 1 # mask the plot array plotarray = np.ma.masked_equal(plotarray, 0) @@ -626,7 +627,7 @@ def plot_vector( jstep=1, normalize=False, masked_values=None, - **kwargs + **kwargs, ): """ Plot a vector. @@ -714,179 +715,6 @@ def plot_vector( quiver = ax.quiver(x, y, urot, vrot, pivot=pivot, **kwargs) return quiver - def plot_specific_discharge( - self, spdis, istep=1, jstep=1, normalize=False, **kwargs - ): - """ - DEPRECATED. Use plot_vector() instead, which should follow after - postprocessing.get_specific_discharge(). - - Method to plot specific discharge from discharge vectors - provided by the cell by cell flow output file. In MODFLOW-6 - this option is controled in the NPF options block. This method - uses matplotlib quiver to create a matplotlib plot of the output. - - Parameters - ---------- - spdis : np.recarray - specific discharge recarray from cbc file - istep : int - row frequency to plot. (Default is 1.) - jstep : int - column frequency to plot. (Default is 1.) - normalize : bool - boolean flag used to determine if discharge vectors should - be normalized using the magnitude of the specific discharge in each - cell. (default is False) - kwargs : matplotlib.pyplot keyword arguments for the - plt.quiver method. - - Returns - ------- - quiver : matplotlib.pyplot.quiver - quiver plot of discharge vectors - - """ - warnings.warn( - "plot_specific_discharge() has been deprecated and will be " - "removed in version 3.3.5. Use plot_vector() instead, which " - "should follow after postprocessing.get_specific_discharge()", - DeprecationWarning, - ) - - if isinstance(spdis, list): - print( - "Warning: Selecting the final stress period from Specific" - " Discharge list" - ) - spdis = spdis[-1] - - nodes = self.mg.nnodes - - qx = np.zeros(nodes) - qy = np.zeros(nodes) - - idx = np.array(spdis["node"]) - 1 - qx[idx] = spdis["qx"] - qy[idx] = spdis["qy"] - - return self.plot_vector(qx, qy, istep, jstep, normalize, **kwargs) - - def plot_discharge( - self, - frf=None, - fff=None, - flf=None, - head=None, - istep=1, - jstep=1, - normalize=False, - **kwargs - ): - """ - DEPRECATED. Use plot_vector() instead, which should follow after - postprocessing.get_specific_discharge(). - - Use quiver to plot vectors. - - Parameters - ---------- - frf : numpy.ndarray - MODFLOW's 'flow right face' - fff : numpy.ndarray - MODFLOW's 'flow front face' - flf : numpy.ndarray - MODFLOW's 'flow lower face' (Default is None.) - head : numpy.ndarray - MODFLOW's head array. If not provided, then will assume confined - conditions in order to calculated saturated thickness. - istep : int - row frequency to plot. (Default is 1.) - jstep : int - column frequency to plot. (Default is 1.) - normalize : bool - boolean flag used to determine if discharge vectors should - be normalized using the magnitude of the specific discharge in each - cell. (default is False) - kwargs : dictionary - Keyword arguments passed to plt.quiver() - - Returns - ------- - quiver : matplotlib.pyplot.quiver - Vectors of specific discharge. - - """ - warnings.warn( - "plot_discharge() has been deprecated and will be replaced " - "in version 3.3.5. Use plot_vector() instead, which should " - "follow after postprocessing.get_specific_discharge()", - DeprecationWarning, - ) - - if self.mg.grid_type != "structured": - err_msg = "Use plot_specific_discharge for " "{} grids".format( - self.mg.grid_type - ) - raise NotImplementedError(err_msg) - - else: - if self.mg.top is None: - err = ( - "StructuredGrid must have top and " - "botm defined to use plot_discharge()" - ) - raise AssertionError(err) - - delr = self.mg.delr - delc = self.mg.delc - top = np.copy(self.mg.top) - botm = np.copy(self.mg.botm) - laytyp = None - hnoflo = 999.0 - hdry = 999.0 - laycbd = None - - if self.model is not None: - if self.model.laytyp is not None: - laytyp = self.model.laytyp - - if self.model.hnoflo is not None: - hnoflo = self.model.hnoflo - - if self.model.hdry is not None: - hdry = self.model.hdry - - if self.model.laycbd is not None: - laycbd = self.model.laycbd - - if laycbd is not None and 1 in laycbd: - active = np.ones((botm.shape[0],), dtype=int) - kon = 0 - for cbd in laycbd: - if cbd > 0: - kon += 1 - active[kon] = 0 - botm = botm[active == 1] - - # If no access to head or laytyp, then calculate confined saturated - # thickness by setting laytyp to zeros - if head is None or laytyp is None: - head = np.zeros(botm.shape, np.float32) - laytyp = np.zeros((botm.shape[0],), dtype=int) - - # calculate the saturated thickness - sat_thk = plotutil.PlotUtilities.saturated_thickness( - head, top, botm, laytyp, [hnoflo, hdry] - ) - - # Calculate specific discharge - qx, qy, qz = plotutil.PlotUtilities.centered_specific_discharge( - frf, fff, flf, delr, delc, sat_thk - ) - - return self.plot_vector(qx, qy, istep, jstep, normalize, **kwargs) - def plot_pathline(self, pl, travel_time=None, **kwargs): """ Plot the MODPATH pathlines. @@ -1034,7 +862,7 @@ def plot_endpoint( direction="ending", selection=None, selection_direction=None, - **kwargs + **kwargs, ): """ Plot the MODPATH endpoints. @@ -1112,233 +940,3 @@ def plot_endpoint( cb = plt.colorbar(sp, ax=ax, shrink=shrink) cb.set_label(colorbar_label) return sp - - -class DeprecatedMapView(PlotMapView): - """ - Deprecation handler for the PlotMapView class - - Parameters - ---------- - model : flopy.modflow.Modflow object - modelgrid : flopy.discretization.Grid object - ax : matplotlib.pyplot.axes object - layer : int - model layer to plot, default is layer 1 - extent : tuple of floats - (xmin, xmax, ymin, ymax) will be used to specify axes limits. If None - then these will be calculated based on grid, coordinates, and rotation. - - """ - - def __init__( - self, model=None, modelgrid=None, ax=None, layer=0, extent=None - ): - super().__init__( - model=model, modelgrid=modelgrid, ax=ax, layer=layer, extent=extent - ) - - def plot_discharge( - self, - frf, - fff, - dis=None, - flf=None, - head=None, - istep=1, - jstep=1, - normalize=False, - **kwargs - ): - """ - Use quiver to plot vectors. Deprecated method that uses - the old function call to pass the method to PlotMapView - - Parameters - ---------- - frf : numpy.ndarray - MODFLOW's 'flow right face' - fff : numpy.ndarray - MODFLOW's 'flow front face' - dis : flopy.modflow.ModflowDis package - Depricated parameter - flf : numpy.ndarray - MODFLOW's 'flow lower face' (Default is None.) - head : numpy.ndarray - MODFLOW's head array. If not provided, then will assume confined - conditions in order to calculated saturated thickness. - istep : int - row frequency to plot. (Default is 1.) - jstep : int - column frequency to plot. (Default is 1.) - normalize : bool - boolean flag used to determine if discharge vectors should - be normalized using the magnitude of the specific discharge in each - cell. (default is False) - kwargs : dictionary - Keyword arguments passed to plt.quiver() - - Returns - ------- - quiver : matplotlib.pyplot.quiver - Vectors of specific discharge. - - """ - - if dis is not None: - self.mg = plotutil._depreciated_dis_handler( - modelgrid=self.mg, dis=dis - ) - - super().plot_discharge( - frf=frf, - fff=fff, - flf=flf, - head=head, - istep=1, - jstep=1, - normalize=normalize, - **kwargs - ) - - -class ModelMap: - """ - DEPRECATED. ModelMap acts as a PlotMapView factory - object. Please migrate to PlotMapView for plotting - functionality and future code compatibility - - Parameters - ---------- - sr : flopy.utils.reference.SpatialReference - The spatial reference class (Default is None) - ax : matplotlib.pyplot axis - The plot axis. If not provided it, plt.gca() will be used. - If there is not a current axis then a new one will be created. - model : flopy.modflow object - flopy model object. (Default is None) - dis : flopy.modflow.ModflowDis object - flopy discretization object. (Default is None) - layer : int - Layer to plot. Default is 0. Must be between 0 and nlay - 1. - xul : float - x coordinate for upper left corner - yul : float - y coordinate for upper left corner. The default is the sum of the - delc array. - rotation : float - Angle of grid rotation around the upper left corner. A positive value - indicates clockwise rotation. Angles are in degrees. - extent : tuple of floats - (xmin, xmax, ymin, ymax) will be used to specify axes limits. If None - then these will be calculated based on grid, coordinates, and rotation. - length_multiplier : float - scaling factor for conversion from model units to another unit - length base ex. ft to m. - - Notes - ----- - ModelMap must know the position and rotation of the grid in order to make - the plot. This information is contained in the SpatialReference class - (sr), which can be passed. If sr is None, then it looks for sr in dis. - If dis is None, then it looks for sr in model.dis. If all of these - arguments are none, then it uses xul, yul, and rotation. If none of these - arguments are provided, then it puts the lower-left-hand corner of the - grid at (0, 0). - """ - - def __new__( - cls, - sr=None, - ax=None, - model=None, - dis=None, - layer=0, - extent=None, - xul=None, - yul=None, - xll=None, - yll=None, - rotation=None, - length_multiplier=None, - ): - - from ..utils.reference import SpatialReferenceUnstructured - - err_msg = ( - "ModelMap is deprecated and has been replaced by " - "PlotMapView(). ModelMap will be removed in version 3.3.5; " - "Calling PlotMapView()" - ) - warnings.warn(err_msg, DeprecationWarning) - - modelgrid = None - if model is not None: - if (xul, yul, xll, yll, rotation) != ( - None, - None, - None, - None, - None, - ): - modelgrid = plotutil._set_coord_info( - model.modelgrid, xul, yul, xll, yll, rotation - ) - elif sr is not None: - if length_multiplier is not None: - sr.length_multiplier = length_multiplier - - if (xul, yul, xll, yll, rotation) != ( - None, - None, - None, - None, - None, - ): - sr.set_spatialreference(xul, yul, xll, yll, rotation) - - if isinstance(sr, SpatialReferenceUnstructured): - if dis is not None: - modelgrid = UnstructuredGrid( - vertices=sr.verts, - iverts=sr.iverts, - xcenters=sr.xc, - ycenters=sr.yc, - top=dis.top.array, - botm=dis.botm.array, - ncpl=sr.ncpl, - ) - else: - modelgrid = UnstructuredGrid( - vertices=sr.verts, - iverts=sr.iverts, - xcenters=sr.xc, - ycenters=sr.yc, - ncpl=sr.ncpl, - ) - - elif dis is not None: - modelgrid = StructuredGrid( - delc=sr.delc, - delr=sr.delr, - top=dis.top.array, - botm=dis.botm.array, - xoff=sr.xll, - yoff=sr.yll, - angrot=sr.rotation, - ) - else: - modelgrid = StructuredGrid( - delc=sr.delc, - delr=sr.delr, - xoff=sr.xll, - yoff=sr.yll, - angrot=sr.rotation, - ) - - else: - pass - - return DeprecatedMapView( - model=model, modelgrid=modelgrid, ax=ax, layer=layer, extent=extent - ) diff --git a/dependencies/flopy/plot/plotutil.py b/dependencies/flopy/plot/plotutil.py index dd97d6f..fa1f436 100644 --- a/dependencies/flopy/plot/plotutil.py +++ b/dependencies/flopy/plot/plotutil.py @@ -4,10 +4,7 @@ shapefiles are also included. """ -from __future__ import print_function import os -import sys -import math import numpy as np import warnings from ..utils import Util3d @@ -20,7 +17,7 @@ try: import matplotlib.pyplot as plt -except ImportError: +except (ImportError, RuntimeError): plt = None warnings.simplefilter("ignore", RuntimeWarning) @@ -39,11 +36,6 @@ } -class PlotException(Exception): - def __init__(self, message): - super().__init__(message) - - class PlotUtilities: """ Class which groups a collection of plotting utilities @@ -117,7 +109,7 @@ def _plot_simulation_helper(simulation, model_list, SelPackList, **kwargs): model_filename_base = None if filename_base is not None: - model_filename_base = filename_base + "_" + model_name + model_filename_base = f"{filename_base}_{model_name}" if model.verbose: print(" Plotting Model: ", model_name) @@ -132,7 +124,7 @@ def _plot_simulation_helper(simulation, model_list, SelPackList, **kwargs): key=defaults["key"], initial_fig=ifig, model_name=model_name, - **kwargs + **kwargs, ) if isinstance(caxs, list): @@ -408,7 +400,7 @@ def _plot_package_helper(package, **kwargs): fignum=fignum, colorbar=colorbar, modelgrid=defaults["modelgrid"], - **kwargs + **kwargs, ) if ax is not None: @@ -536,7 +528,7 @@ def _plot_mflist_helper( filename_base=None, file_extension=None, mflay=None, - **kwargs + **kwargs, ): """ Plot stress period boundary condition (MfList) data for a specified @@ -656,20 +648,17 @@ def _plot_mflist_helper( filenames=filenames, mflay=mflay, modelgrid=modelgrid, - **kwargs + **kwargs, ) else: arr_dict = mflist.to_array(kper, mask=True) try: arr = arr_dict[key] - except: - err_msg = "Cannot find key to plot\n" - err_msg += " Provided key={}\n Available keys=".format(key) - for name, arr in arr_dict.items(): - err_msg += "{}, ".format(name) - err_msg += "\n" - raise PlotException(err_msg) + except KeyError: + err_msg = f'Cannot find key "{key}" to plot\n Available keys=' + err_msg += ", ".join(str(k) for k in arr_dict.keys()) + raise KeyError(err_msg) axes = PlotUtilities._plot_array_helper( arr, @@ -678,7 +667,7 @@ def _plot_mflist_helper( filenames=filenames, mflay=mflay, modelgrid=modelgrid, - **kwargs + **kwargs, ) return axes @@ -689,7 +678,7 @@ def _plot_util2d_helper( filename_base=None, file_extension=None, fignum=None, - **kwargs + **kwargs, ): """ Plot 2-D model input data @@ -752,7 +741,7 @@ def _plot_util2d_helper( modelgrid = kwargs.pop("modelgrid") if title is None: - title = "{}{}".format(model_name, util2d.name) + title = f"{model_name}{util2d.name}" if file_extension is not None: fext = file_extension @@ -761,7 +750,7 @@ def _plot_util2d_helper( filename = None if filename_base is not None: - filename = "{}_{}.{}".format(filename_base, util2d.name, fext) + filename = f"{filename_base}_{util2d.name}.{fext}" axes = PlotUtilities._plot_array_helper( util2d.array, @@ -770,7 +759,7 @@ def _plot_util2d_helper( filenames=filename, fignum=fignum, modelgrid=modelgrid, - **kwargs + **kwargs, ) return axes @@ -781,7 +770,7 @@ def _plot_util3d_helper( file_extension=None, mflay=None, fignum=None, - **kwargs + **kwargs, ): """ Plot 3-D model input data @@ -860,7 +849,7 @@ def _plot_util3d_helper( name = [name] * nplottable_layers names = [ - "{}{} layer {}".format(model_name, name[k], k + 1) + f"{model_name}{name[k]} layer {k + 1}" for k in range(nplottable_layers) ] @@ -868,7 +857,7 @@ def _plot_util3d_helper( if filename_base is not None: # build filenames, use local "name" variable (flopy6 adaptation) filenames = [ - "{}_{}_Layer{}.{}".format(filename_base, name[k], k + 1, fext) + f"{filename_base}_{name[k]}_Layer{k + 1}.{fext}" for k in range(nplottable_layers) ] @@ -880,7 +869,7 @@ def _plot_util3d_helper( mflay=mflay, fignum=fignum, modelgrid=modelgrid, - **kwargs + **kwargs, ) return axes @@ -891,7 +880,7 @@ def _plot_transient2d_helper( file_extension=None, kper=0, fignum=None, - **kwargs + **kwargs, ): """ Plot transient 2-D model input data @@ -990,7 +979,7 @@ def _plot_transient2d_helper( ) if filename_base is not None: - filename = filename_base + "_{:05d}.{}".format(kper + 1, fext) + filename = f"{filename_base}_{kper + 1:05d}.{fext}" else: filename = None @@ -1002,7 +991,7 @@ def _plot_transient2d_helper( filenames=filename, fignum=fignum[idx], modelgrid=modelgrid, - **kwargs + **kwargs, ) ) return axes @@ -1042,10 +1031,10 @@ def _plot_scalar_helper( if "modelgrid" in kwargs: modelgrid = kwargs.pop("modelgrid") - title = "{}".format(scalar.name.replace("_", "").upper()) + title = scalar.name.replace("_", "").upper() if filename_base is not None: - filename = filename_base + ".{}".format(fext) + filename = f"{filename_base}.{fext}" else: filename = None @@ -1055,7 +1044,7 @@ def _plot_scalar_helper( names=title, filenames=filename, modelgrid=modelgrid, - **kwargs + **kwargs, ) return axes @@ -1069,7 +1058,7 @@ def _plot_array_helper( filenames=None, fignum=None, mflay=None, - **kwargs + **kwargs, ): """ Helper method to plot array objects @@ -1120,12 +1109,10 @@ def _plot_array_helper( # check that matplotlib is installed if plt is None: - err_msg = ( - "Could not import matplotlib. " - "Must install matplotlib " - + " in order to plot LayerFile data." + raise ImportError( + "Could not import matplotlib. Must install matplotlib " + "in order to plot LayerFile data." ) - raise PlotException(err_msg) for key in defaults: if key in kwargs: @@ -1190,7 +1177,7 @@ def _plot_array_helper( plotarray, masked_values=defaults["masked_values"], ax=axes[idx], - **kwargs + **kwargs, ) if defaults["colorbar"]: @@ -1206,7 +1193,7 @@ def _plot_array_helper( ax=axes[idx], colors=defaults["colors"], levels=defaults["levels"], - **kwargs + **kwargs, ) if defaults["clabel"]: axes[idx].clabel(cl, fmt=defaults["fmt"], **kwargs) @@ -1225,9 +1212,7 @@ def _plot_array_helper( for idx, k in enumerate(range(i0, i1)): fig = plt.figure(num=fignum[idx]) fig.savefig(filenames[idx], dpi=defaults["dpi"]) - print( - " created...{}".format(os.path.basename(filenames[idx])) - ) + print(f" created...{os.path.basename(filenames[idx])}") # there will be nothing to return when done axes = None plt.close("all") @@ -1243,7 +1228,7 @@ def _plot_bc_helper( filenames=None, fignum=None, mflay=None, - **kwargs + **kwargs, ): """ Helper method to plot bc objects from flopy packages @@ -1275,11 +1260,10 @@ def _plot_bc_helper( from .map import PlotMapView if plt is None: - s = ( + raise ImportError( "Could not import matplotlib. Must install matplotlib " - + " in order to plot boundary condition data." + "in order to plot boundary condition data." ) - raise PlotException(s) defaults = { "figsize": None, @@ -1345,9 +1329,7 @@ def _plot_bc_helper( fig = plt.figure(num=fignum[idx]) fig.savefig(filenames[idx], dpi=defaults["dpi"]) plt.close(fignum[idx]) - print( - " created...{}".format(os.path.basename(filenames[idx])) - ) + print(f" created...{os.path.basename(filenames[idx])}") # there will be nothing to return when done axes = None plt.close("all") @@ -1408,13 +1390,10 @@ def _set_names(names, maxlay): if names is not None: if not isinstance(names, list): if maxlay > 1: - names = [ - "{} layer {}".format(names, i + 1) - for i in range(maxlay) - ] + names = [f"{names} layer {i + 1}" for i in range(maxlay)] else: names = [names] - msg = "{} /= {}: {}".format(len(names), maxlay, names) + msg = f"{len(names)} /= {maxlay}: {names}" assert len(names) == maxlay, msg return names @@ -1444,7 +1423,7 @@ def _set_fignum(fignum, maxlay, i0, i1): if fignum is not None: if not isinstance(fignum, list): fignum = [fignum] - msg = "{} /= {}".format(len(fignum), maxlay) + msg = f"{len(fignum)} /= {maxlay}" assert len(fignum) == maxlay, msg # check for existing figures f0 = fignum[0] @@ -1508,7 +1487,7 @@ def _set_axes(axes, mflay, maxlay, i0, i1, defaults, names, fignum): klay = k if mflay is not None: klay = int(mflay) - title = "{} Layer {}".format("data", klay + 1) + title = f"data Layer {klay + 1}" ax.set_title(title) axes.append(ax) @@ -1955,7 +1934,7 @@ def __init__(self, model=None, botm=None, istrat=1, nu=None): try: dis = model.get_package("DIS") except: - sys.stdout.write("Error: DIS package not available.\n") + print("Error: DIS package not available.") self.__botm = np.zeros((dis.nlay + 1, dis.nrow, dis.ncol), float) self.__botm[0, :, :] = dis.top.array self.__botm[1:, :, :] = dis.botm.array @@ -1965,7 +1944,7 @@ def __init__(self, model=None, botm=None, istrat=1, nu=None): self.__istrat = swi.istrat self.__nsrf = swi.nsrf except (AttributeError, ValueError): - sys.stdout.write("Error: SWI2 package not available...\n") + print("Error: SWI2 package not available...") self.__nlay = self.__botm.shape[0] - 1 self.__nrow = self.__botm[0, :, :].shape[0] self.__ncol = self.__botm[0, :, :].shape[1] @@ -2042,8 +2021,10 @@ def shapefile_extents(shp): """ if shapefile is None: - s = "Could not import shapefile. Must install pyshp in order to plot shapefiles." - raise PlotException(s) + raise ImportError( + "Could not import shapefile. " + "Must install pyshp in order to plot shapefiles." + ) sf = shapefile.Reader(shp) shapes = sf.shapes() @@ -2084,8 +2065,10 @@ def shapefile_get_vertices(shp): """ if shapefile is None: - s = "Could not import shapefile. Must install pyshp in order to plot shapefiles." - raise PlotException(s) + raise ImportError( + "Could not import shapefile. " + "Must install pyshp in order to plot shapefiles." + ) sf = shapefile.Reader(shp) shapes = sf.shapes() @@ -2135,17 +2118,15 @@ def shapefile_to_patch_collection(shp, radius=500.0, idx=None): """ if shapefile is None: - s = ( - "Could not import shapefile. Must install pyshp " - "in order to plot shapefiles." + raise ImportError( + "Could not import shapefile. " + "Must install pyshp in order to plot shapefiles." ) - raise PlotException(s) if plt is None: - err_msg = ( + raise ImportError( "matplotlib must be installed to " - + "use shapefile_to_patch_collection()" + "use shapefile_to_patch_collection()" ) - raise ImportError(err_msg) else: from matplotlib.patches import Polygon, Circle, PathPatch import matplotlib.path as MPath @@ -2245,7 +2226,7 @@ def plot_shapefile( a=None, masked_values=None, idx=None, - **kwargs + **kwargs, ): """ Generic function for plotting a shapefile. @@ -2285,11 +2266,10 @@ def plot_shapefile( """ if shapefile is None: - s = ( - "Could not import shapefile. Must install pyshp in " - "order to plot shapefiles." + raise ImportError( + "Could not import shapefile. " + "Must install pyshp in order to plot shapefiles." ) - raise PlotException(s) vmin = kwargs.pop("vmin", None) vmax = kwargs.pop("vmax", None) @@ -2345,11 +2325,9 @@ def cvfd_to_patch_collection(verts, iverts): ) if plt is None: - err_msg = ( - "matplotlib must be installed to " - + "use cvfd_to_patch_collection()" + raise ImportError( + "matplotlib must be installed to use cvfd_to_patch_collection()" ) - raise ImportError(err_msg) else: from matplotlib.patches import Polygon from matplotlib.collections import PatchCollection @@ -2378,7 +2356,7 @@ def plot_cvfd( facecolor="scaled", a=None, masked_values=None, - **kwargs + **kwargs, ): """ Generic function for plotting a control volume finite difference grid of @@ -2537,10 +2515,6 @@ def _set_coord_info(mg, xul, yul, xll, yll, rotation): import warnings if xul is not None and yul is not None: - warnings.warn( - "xul/yul have been deprecated. Use xll/yll instead.", - DeprecationWarning, - ) if rotation is not None: mg._angrot = rotation @@ -2649,7 +2623,7 @@ def advanced_package_bc_helper(pkg, modelgrid, kper): idx = np.array(idx) else: raise NotImplementedError( - "Pkg {} not implemented for bc plotting".format(pkg.package_type) + f"Pkg {pkg.package_type} not implemented for bc plotting" ) return idx @@ -2682,14 +2656,12 @@ def filter_modpath_by_travel_time(recarray, travel_time): time = float(travel_time) idx = recarray["time"] <= time except (ValueError, KeyError): - errmsg = ( - "flopy.map.plot_pathline travel_time " - + "variable cannot be parsed. " - + "Acceptable logical variables are , " - + "<=, <, >=, and >. " - + "You passed {}".format(travel_time) + raise Exception( + "flopy.map.plot_pathline travel_time variable cannot " + "be parsed. Acceptable logical variables are , " + "<=, <, >=, and >. " + "You passed {}".format(travel_time) ) - raise Exception(errmsg) else: time = float(travel_time) idx = recarray["time"] <= time @@ -2971,21 +2943,17 @@ def parse_modpath_selection_options( idx = (ep[ksel] == k) & (ep[isel] == i) & (ep[jsel] == j) tep = ep[idx] else: - errmsg = ( - "plot_endpoint selection must be " - + "a zero-based layer, row, column tuple " - + "(l, r, c) or node number (MODPATH 7) of " - + "the location to evaluate (i.e., well location)." + raise Exception( + "plot_endpoint selection must be a zero-based layer, row, " + "column tuple (l, r, c) or node number (MODPATH 7) of " + "the location to evaluate (i.e., well location)." ) - raise Exception(errmsg) except (ValueError, KeyError, IndexError): - errmsg = ( - "plot_endpoint selection must be a " - + "zero-based layer, row, column tuple (l, r, c) " - + "or node number (MODPATH 7) of the location " - + "to evaluate (i.e., well location)." + raise Exception( + "plot_endpoint selection must be a zero-based layer, row, " + "column tuple (l, r, c) or node number (MODPATH 7) of the " + "location to evaluate (i.e., well location)." ) - raise Exception(errmsg) else: tep = ep.copy() diff --git a/dependencies/flopy/plot/styles.py b/dependencies/flopy/plot/styles.py index a1a88e0..0eaee18 100644 --- a/dependencies/flopy/plot/styles.py +++ b/dependencies/flopy/plot/styles.py @@ -1,7 +1,7 @@ try: import matplotlib.pyplot as plt import matplotlib as mpl -except (ImportError, ModuleNotFoundError): +except (ImportError, ModuleNotFoundError, RuntimeError): plt = None import os @@ -54,7 +54,7 @@ def set_font_type(cls, family, fontname): None """ mpl.rcParams["font.family"] = family - mpl.rcParams["font." + family] = fontname + mpl.rcParams[f"font.{family}"] = fontname return mpl.rcParams @classmethod @@ -112,7 +112,7 @@ def heading( letter = letter.rstrip() if not letter.endswith("."): letter += "." - text = letter + " " + heading + text = f"{letter} {heading}" else: text = heading @@ -267,7 +267,7 @@ def add_text( fontsize=9, ha="left", va="bottom", - **kwargs + **kwargs, ): """Add USGS-style text to a axis object @@ -324,7 +324,7 @@ def add_text( ha=ha, fontdict=font, transform=transform, - **kwargs + **kwargs, ) return text_obj @@ -340,7 +340,7 @@ def add_annotation( fontsize=9, ha="left", va="bottom", - **kwargs + **kwargs, ): """Add an annotation to a axis object @@ -436,7 +436,7 @@ def __set_fontspec(cls, bold=True, italic=True, fontsize=9, family=False): dict """ family = mpl.rcParams["font.family"][0] - font = mpl.rcParams["font." + family][0] + font = mpl.rcParams[f"font.{family}"][0] if bold: weight = "bold" diff --git a/dependencies/flopy/seawat/swt.py b/dependencies/flopy/seawat/swt.py index 86397e8..9ea83a2 100644 --- a/dependencies/flopy/seawat/swt.py +++ b/dependencies/flopy/seawat/swt.py @@ -140,17 +140,13 @@ def __init__( # the starting external data unit number self._next_ext_unit = 3000 if external_path is not None: - assert model_ws == ".", ( - "ERROR: external cannot be used " + "with model_ws" - ) + assert ( + model_ws == "." + ), "ERROR: external cannot be used with model_ws" # external_path = os.path.join(model_ws, external_path) if os.path.exists(external_path): - print( - "Note: external_path " - + str(external_path) - + " already exists" - ) + print(f"Note: external_path {external_path} already exists") # assert os.path.exists(external_path),'external_path does not exist' else: os.mkdir(external_path) @@ -328,7 +324,7 @@ def write_name_file(self): # open and write header fn_path = os.path.join(self.model_ws, self.namefile) f_nam = open(fn_path, "w") - f_nam.write("{}\n".format(self.heading)) + f_nam.write(f"{self.heading}\n") # Write global file entry if self.glo is not None: @@ -350,7 +346,7 @@ def write_name_file(self): ) # Write SEAWAT entries and close - f_nam.write("{}".format(self.get_name_file_entries())) + f_nam.write(str(self.get_name_file_entries())) if self._mf is not None: # write the external files @@ -362,7 +358,7 @@ def write_name_file(self): tag = "DATA" if b: tag = "DATA(BINARY)" - f_nam.write("{0:14s} {1:5d} {2}\n".format(tag, u, f)) + f_nam.write(f"{tag:14s} {u:5d} {f}\n") # write the output files for u, f, b in zip( @@ -373,11 +369,9 @@ def write_name_file(self): if u == 0: continue if b: - f_nam.write( - "DATA(BINARY) {0:5d} ".format(u) + f + " REPLACE\n" - ) + f_nam.write(f"DATA(BINARY) {u:5d} {f} REPLACE\n") else: - f_nam.write("DATA {0:5d} ".format(u) + f + "\n") + f_nam.write(f"DATA {u:5d} {f}\n") if self._mt is not None: # write the external files @@ -389,7 +383,7 @@ def write_name_file(self): tag = "DATA" if b: tag = "DATA(BINARY)" - f_nam.write("{0:14s} {1:5d} {2}\n".format(tag, u, f)) + f_nam.write(f"{tag:14s} {u:5d} {f}\n") # write the output files for u, f, b in zip( @@ -400,11 +394,9 @@ def write_name_file(self): if u == 0: continue if b: - f_nam.write( - "DATA(BINARY) {0:5d} ".format(u) + f + " REPLACE\n" - ) + f_nam.write(f"DATA(BINARY) {u:5d} {f} REPLACE\n") else: - f_nam.write("DATA {0:5d} ".format(u) + f + "\n") + f_nam.write(f"DATA {u:5d} {f}\n") # write the external files for b, u, f in zip( @@ -413,7 +405,7 @@ def write_name_file(self): tag = "DATA" if b: tag = "DATA(BINARY)" - f_nam.write("{0:14s} {1:5d} {2}\n".format(tag, u, f)) + f_nam.write(f"{tag:14s} {u:5d} {f}\n") # write the output files for u, f, b in zip( @@ -422,11 +414,9 @@ def write_name_file(self): if u == 0: continue if b: - f_nam.write( - "DATA(BINARY) {0:5d} ".format(u) + f + " REPLACE\n" - ) + f_nam.write(f"DATA(BINARY) {u:5d} {f} REPLACE\n") else: - f_nam.write("DATA {0:5d} ".format(u) + f + "\n") + f_nam.write(f"DATA {u:5d} {f}\n") f_nam.close() return diff --git a/dependencies/flopy/seawat/swtvdf.py b/dependencies/flopy/seawat/swtvdf.py index a2ab3d6..1109871 100644 --- a/dependencies/flopy/seawat/swtvdf.py +++ b/dependencies/flopy/seawat/swtvdf.py @@ -1,4 +1,3 @@ -import sys import numpy as np from ..pakbase import Package from ..utils import Util2d, Util3d @@ -205,7 +204,7 @@ def __init__( extension="vdf", unitnumber=None, filenames=None, - **kwargs + **kwargs, ): if unitnumber is None: @@ -381,7 +380,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading vdf package file...\n") + print("loading vdf package file...") # Open file, if necessary openfile = not hasattr(f, "read") @@ -409,10 +408,10 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): nswtcpl = int(t[2]) iwtable = int(t[3]) if model.verbose: - print(" MT3DRHOFLG {}".format(mt3drhoflg)) - print(" MFNADVFD {}".format(mfnadvfd)) - print(" NSWTCPL {}".format(nswtcpl)) - print(" IWTABLE {}".format(iwtable)) + print(f" MT3DRHOFLG {mt3drhoflg}") + print(f" MFNADVFD {mfnadvfd}") + print(f" NSWTCPL {nswtcpl}") + print(f" IWTABLE {iwtable}") # Item 2 -- DENSEMIN DENSEMAX if model.verbose: @@ -491,15 +490,14 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): if model.verbose: print( - " loading INDENSE " - "for stress period {}...".format(iper + 1) + f" loading INDENSE for stress period {iper + 1}..." ) line = f.readline() t = line.strip().split() indense = int(t[0]) if indense > 0: - name = "DENSE_StressPeriod_{}".format(iper) + name = f"DENSE_StressPeriod_{iper}" t = Util3d.load( f, model, diff --git a/dependencies/flopy/seawat/swtvsc.py b/dependencies/flopy/seawat/swtvsc.py index ad48811..70baec3 100644 --- a/dependencies/flopy/seawat/swtvsc.py +++ b/dependencies/flopy/seawat/swtvsc.py @@ -1,4 +1,3 @@ -import sys import numpy as np from ..pakbase import Package from ..utils import Util3d, Transient3d @@ -145,7 +144,7 @@ def __init__( extension="vsc", unitnumber=None, filenames=None, - **kwargs + **kwargs, ): if len(list(kwargs.keys())) > 0: @@ -231,21 +230,19 @@ def write_file(self): f_vsc = open(self.fn_path, "w") # item 1 - f_vsc.write("{}\n".format(self.mt3dmuflg)) + f_vsc.write(f"{self.mt3dmuflg}\n") # item 2 - f_vsc.write("{} {}\n".format(self.viscmin, self.viscmax)) + f_vsc.write(f"{self.viscmin} {self.viscmax}\n") # item 3 if self.mt3dmuflg >= 0: - f_vsc.write( - "{} {} {}\n".format(self.viscref, self.dmudc, self.cmuref) - ) + f_vsc.write(f"{self.viscref} {self.dmudc} {self.cmuref}\n") # item 3a-d if self.mt3dmuflg == -1: - f_vsc.write("{}\n".format(self.viscref)) - f_vsc.write("{} {}\n".format(self.nsmueos, self.mutempopt)) + f_vsc.write(f"{self.viscref}\n") + f_vsc.write(f"{self.nsmueos} {self.mutempopt}\n") # if self.nsmueos == 1: # f_vsc.write('{} {} {}\n'.format(self.mtmuspec, self.dmudc, # self.cmuref)) @@ -257,16 +254,12 @@ def write_file(self): if self.nsmueos > 0: for iwr in range(self.nsmueos): f_vsc.write( - "{} {} {}\n".format( - self.mtmuspec[iwr], - self.dmudc[iwr], - self.cmuref[iwr], - ) + f"{self.mtmuspec[iwr]} {self.dmudc[iwr]} {self.cmuref[iwr]}\n" ) # item 3d if self.mutempopt > 0: - s = "{} ".format(self.mtmutempspec) + s = f"{self.mtmutempspec} " for a in tuple(self.amucoeff): s += "{} ".format(a) f_vsc.write(s + "\n") @@ -281,11 +274,11 @@ def write_file(self): # item 4 (and possibly 5) if itmp > 0: - f_vsc.write("{}\n".format(self.invisc)) + f_vsc.write(f"{self.invisc}\n") f_vsc.write(file_entry_visc) else: - f_vsc.write("{}\n".format(itmp)) + f_vsc.write(f"{itmp}\n") f_vsc.close() return @@ -330,7 +323,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): """ if model.verbose: - sys.stdout.write("loading vsc package file...\n") + print("loading vsc package file...") # Open file, if necessary openfile = not hasattr(f, "read") @@ -353,7 +346,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): t = line.strip().split() mt3dmuflg = int(t[0]) if model.verbose: - print(" MT3DMUFLG {}".format(mt3dmuflg)) + print(f" MT3DMUFLG {mt3dmuflg}") # Item 2 -- VISCMIN VISCMAX if model.verbose: @@ -363,8 +356,8 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): viscmin = float(t[0]) viscmax = float(t[1]) if model.verbose: - print(" VISCMIN {}".format(viscmin)) - print(" VISCMAX {}".format(viscmax)) + print(f" VISCMIN {viscmin}") + print(f" VISCMAX {viscmax}") # Item 3 -- VISCREF NSMUEOS MUTEMPOPT MTMUSPEC DMUDC CMUREF nsmueos = None @@ -384,9 +377,9 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): cmuref = float(t[2]) nsmueos = 1 if model.verbose: - print(" VISCREF {}".format(viscref)) - print(" DMUDC {}".format(dmudc)) - print(" CMUREF {}".format(cmuref)) + print(f" VISCREF {viscref}") + print(f" DMUDC {dmudc}") + print(f" CMUREF {cmuref}") else: # Item 3a if model.verbose: @@ -395,7 +388,7 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): t = line.strip().split() viscref = float(t[0]) if model.verbose: - print(" VISCREF {}".format(viscref)) + print(f" VISCREF {viscref}") # Item 3b if model.verbose: @@ -413,8 +406,8 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): else: muncoeff = None if model.verbose: - print(" NSMUEOS {}".format(nsmueos)) - print(" MUTEMPOPT {}".format(mutempopt)) + print(f" NSMUEOS {nsmueos}") + print(f" MUTEMPOPT {mutempopt}") # Item 3c if model.verbose: @@ -429,9 +422,9 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): dmudc.append(float(t[1])) cmuref.append(float(t[2])) if model.verbose: - print(" MTMUSPEC {}".format(mtmuspec)) - print(" DMUDC {}".format(dmudc)) - print(" CMUREF {}".format(cmuref)) + print(f" MTMUSPEC {mtmuspec}") + print(f" DMUDC {dmudc}") + print(f" CMUREF {cmuref}") # Item 3d if mutempopt > 0: @@ -444,8 +437,8 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): for i in range(muncoeff): amucoeff.append(float(t[i + 1])) if model.verbose: - print(" MTMUTEMSPEC {}".format(mtmutempspec)) - print(" AMUCOEFF {}".format(amucoeff)) + print(f" MTMUTEMSPEC {mtmutempspec}") + print(f" AMUCOEFF {amucoeff}") # Items 4 and 5 -- INVISC VISC invisc = None @@ -458,16 +451,13 @@ def load(cls, f, model, nper=None, ext_unit_dict=None): for iper in range(nper): if model.verbose: - print( - " loading INVISC " - "for stress period {}...".format(iper + 1) - ) + print(f" loading INVISC for stress period {iper + 1}...") line = f.readline() t = line.strip().split() invisc = int(t[0]) if invisc > 0: - name = "VISC_StressPeriod_{}".format(iper) + name = f"VISC_StressPeriod_{iper}" t = Util3d.load( f, model, diff --git a/dependencies/flopy/utils/__init__.py b/dependencies/flopy/utils/__init__.py index 211c0c3..22d5768 100644 --- a/dependencies/flopy/utils/__init__.py +++ b/dependencies/flopy/utils/__init__.py @@ -53,11 +53,8 @@ from .flopy_io import read_fixed_var, write_fixed_var from .zonbud import ( ZoneBudget, - read_zbarray, - write_zbarray, ZoneFile6, ZoneBudget6, - ZoneBudgetOutput, ZBNetOutput, ) from .postprocessing import get_transmissivities, get_specific_discharge @@ -67,4 +64,3 @@ from .optionblock import OptionBlock from .rasters import Raster from .gridintersect import GridIntersect, ModflowGridIndices -from .binarygrid_util import MfGrdFile diff --git a/dependencies/flopy/utils/binaryfile.py b/dependencies/flopy/utils/binaryfile.py index 6e690b5..f04b2ac 100755 --- a/dependencies/flopy/utils/binaryfile.py +++ b/dependencies/flopy/utils/binaryfile.py @@ -8,10 +8,8 @@ * CellBudgetFile (Binary cell-by-cell flow file) """ -from __future__ import print_function import numpy as np import warnings -from collections import OrderedDict from ..utils.datafile import Header, LayerFile @@ -56,18 +54,19 @@ def set_values(self, **kwargs): try: self.header[0][k] = int(kwargs[k]) except: - msg = "{0} key not available in {1} header " - "dtype".format(k, self.header_type) - print(msg) + print( + f"{k} key not available in {self.header_type} " + "header dtype" + ) for k in fkey: if k in kwargs.keys(): try: self.header[0][k] = float(kwargs[k]) except: - msg = "{} key not available ".format( - k - ) + "in {} header dtype".format(self.header_type) - print(msg) + print( + f"{k} key not available " + f"in {self.header_type} header dtype" + ) for k in ckey: if k in kwargs.keys(): # Convert to upper case to be consistent case used by MODFLOW @@ -219,7 +218,7 @@ def get_headfile_precision(filename): f.seek(0, 0) # reset to beginning assert f.tell() == 0 if totalbytes == 0: - raise IOError("datafile error: file is empty: " + str(filename)) + raise ValueError(f"datafile error: file is empty: {filename}") # first try single vartype = [ @@ -261,11 +260,9 @@ def get_headfile_precision(filename): result = "double" except: f.close() - e = ( - "Could not determine the precision of " - + "the headfile {}".format(filename) + raise ValueError( + f"Could not determine the precision of the headfile {filename}" ) - raise IOError(e) # close and return result f.close() @@ -485,9 +482,7 @@ def __init__( if precision == "auto": precision = get_headfile_precision(filename) if precision == "unknown": - s = "Error. Precision could not be determined for {}".format( - filename - ) + s = f"Error. Precision could not be determined for {filename}" print(s) raise Exception() self.header_dtype = BinaryHeader.set_dtype( @@ -549,15 +544,13 @@ def __init__( text="concentration", precision="auto", verbose=False, - **kwargs + **kwargs, ): self.text = text.encode() if precision == "auto": precision = get_headfile_precision(filename) if precision == "unknown": - s = "Error. Precision could not be determined for {}".format( - filename - ) + s = f"Error. Precision could not be determined for {filename}" print(s) raise Exception() self.header_dtype = BinaryHeader.set_dtype( @@ -617,7 +610,7 @@ def __init__(self, filename, precision="auto", verbose=False, **kwargs): self.file.seek(0, 0) # reset to beginning assert self.file.tell() == 0 if totalbytes == 0: - raise IOError("datafile error: file is empty: " + str(filename)) + raise ValueError(f"datafile error: file is empty: {filename}") self.nrow = 0 self.ncol = 0 self.nlay = 0 @@ -665,7 +658,7 @@ def __init__(self, filename, precision="auto", verbose=False, **kwargs): self.modelgrid = kwargs.pop("modelgrid") if len(kwargs.keys()) > 0: args = ",".join(kwargs.keys()) - raise Exception("LayerFile error: unrecognized kwargs: " + args) + raise Exception(f"LayerFile error: unrecognized kwargs: {args}") if precision == "auto": success = self._set_precision("single") @@ -679,13 +672,12 @@ def __init__(self, filename, precision="auto", verbose=False, **kwargs): elif precision == "double": success = self._set_precision(precision) else: - raise Exception("Unknown precision specified: " + precision) + raise Exception(f"Unknown precision specified: {precision}") if not success: - s = "Budget file could not be read using {} " "precision".format( - precision + raise Exception( + f"Budget file could not be read using {precision} precision" ) - raise Exception(s) return @@ -808,7 +800,7 @@ def _build_index(self): self.file.seek(0, 2) self.totalbytes = self.file.tell() self.file.seek(0, 0) - self.recorddict = OrderedDict() + self.recorddict = {} ipos = 0 while ipos < self.totalbytes: self.iposheader.append(ipos) @@ -864,7 +856,7 @@ def _build_index(self): s = header[itxt] if isinstance(s, bytes): s = s.decode() - print(itxt + ": " + str(s)) + print(f"{itxt}: {s}") print("file position: ", ipos) if ( int(header["imeth"]) != 5 @@ -948,7 +940,7 @@ def _skip_record(self, header): + naux * self.realtype(1).nbytes ) else: - raise Exception("invalid method code " + str(imeth)) + raise Exception(f"invalid method code {imeth}") if nbytes != 0: self.file.seek(nbytes, 1) return @@ -1019,11 +1011,10 @@ def _find_paknam(self, paknam): paknam16 = t break if paknam16 is None: - errmsg = ( + raise Exception( "The specified package name string is not " - + "in the budget file." + "in the budget file." ) - raise Exception(errmsg) return paknam16 def list_records(self): @@ -1045,7 +1036,7 @@ def list_unique_records(self): for rec, imeth in zip(self.textlist, self.imethlist): if isinstance(rec, bytes): rec = rec.decode() - print("{:16} {:5d}".format(rec.strip(), imeth)) + print(f"{rec.strip():16} {imeth:5d}") return def list_unique_packages(self): @@ -1370,11 +1361,10 @@ def get_ts(self, idx, text=None, times=None): """ # issue exception if text not provided if text is None: - etxt = ( + raise Exception( "text keyword must be provided to CellBudgetFile " - + "get_ts() method." + "get_ts() method." ) - raise Exception(etxt) kijlist = self._build_kijlist(idx) nstation = self._get_nstation(idx, kijlist) @@ -1391,12 +1381,11 @@ def get_ts(self, idx, text=None, times=None): if isinstance(times, np.ndarray): times = times.tolist() if len(times) != len(kk): - etxt = ( + raise Exception( "times passed to CellBudgetFile get_ts() " - + "method must be equal to {} ".format(len(kk)) - + "not {}".format(len(times)) + "method must be equal to {} " + "not {}".format(len(kk), len(times)) ) - raise Exception(etxt) timesint = times for idx, t in enumerate(timesint): result[idx, 0] = t @@ -1456,12 +1445,6 @@ def _build_kijlist(self, idx): # the seek approach won't work. Can't use k = -1, for example. for k, i, j in kijlist: fail = False - errmsg = ( - "Invalid cell index. Cell " - + str((k, i, j)) - + " not within model grid: " - + str((self.nlay, self.nrow, self.ncol)) - ) if k < 0 or k > self.nlay - 1: fail = True if i < 0 or i > self.nrow - 1: @@ -1469,7 +1452,10 @@ def _build_kijlist(self, idx): if j < 0 or j > self.ncol - 1: fail = True if fail: - raise Exception(errmsg) + raise Exception( + "Invalid cell index. Cell {} not within model grid: " + "{}".format((k, i, j), (self.nlay, self.nrow, self.ncol)) + ) return kijlist def _get_nstation(self, idx, kijlist): @@ -1533,7 +1519,7 @@ def get_record(self, idx, full3D=False): t = header["text"][0] if isinstance(t, bytes): t = t.decode("utf-8") - s = "Returning " + str(t).strip() + " as " + s = f"Returning {t.strip()} as " nlay = abs(header["nlay"][0]) nrow = header["nrow"][0] @@ -1542,7 +1528,7 @@ def get_record(self, idx, full3D=False): # default method if imeth == 0: if self.verbose: - s += "an array of shape " + str((nlay, nrow, ncol)) + s += f"an array of shape {(nlay, nrow, ncol)}" print(s) return binaryread( self.file, self.realtype(1), shape=(nlay, nrow, ncol) @@ -1550,7 +1536,7 @@ def get_record(self, idx, full3D=False): # imeth 1 elif imeth == 1: if self.verbose: - s += "an array of shape " + str((nlay, nrow, ncol)) + s += f"an array of shape {(nlay, nrow, ncol)}" print(s) return binaryread( self.file, self.realtype(1), shape=(nlay, nrow, ncol) @@ -1562,11 +1548,9 @@ def get_record(self, idx, full3D=False): dtype = np.dtype([("node", np.int32), ("q", self.realtype)]) if self.verbose: if full3D: - s += "a numpy masked array of size ({},{},{})".format( - nlay, nrow, ncol - ) + s += f"a numpy masked array of size ({nlay}, {nrow}, {ncol})" else: - s += "a numpy recarray of size (" + str(nlist) + ", 2)" + s += f"a numpy recarray of size ({nlist}, 2)" print(s) data = binaryread(self.file, dtype, shape=(nlist,)) if full3D: @@ -1580,17 +1564,15 @@ def get_record(self, idx, full3D=False): data = binaryread(self.file, self.realtype(1), shape=(nrow, ncol)) if self.verbose: if full3D: - s += "a numpy masked array of size ({},{},{})".format( - nlay, nrow, ncol - ) + s += f"a numpy masked array of size ({nlay}, {nrow}, {ncol})" else: - s += "a list of two 2D numpy arrays. " s += ( - "The first is an integer layer array of shape " - + str((nrow, ncol)) - ) - s += "The second is real data array of shape " + str( - (nrow, ncol) + "a list of two 2D numpy arrays. " + "The first is an integer layer array of shape {}. " + "The second is real data array of shape {}".format( + (nrow, ncol), + (nrow, ncol), + ) ) print(s) if full3D: @@ -1605,7 +1587,7 @@ def get_record(self, idx, full3D=False): # imeth 4 elif imeth == 4: if self.verbose: - s += "a 2d numpy array of size ({},{})".format(nrow, ncol) + s += f"a 2d numpy array of size ({nrow}, {ncol})" print(s) return binaryread(self.file, self.realtype(1), shape=(nrow, ncol)) @@ -1624,18 +1606,12 @@ def get_record(self, idx, full3D=False): data = binaryread(self.file, dtype, shape=(nlist,)) if full3D: if self.verbose: - s += "a list array of shape ({},{},{})".format( - nlay, nrow, ncol - ) + s += f"a list array of shape ({nlay}, {nrow}, {ncol})" print(s) return self.create3D(data, nlay, nrow, ncol) else: if self.verbose: - s += ( - "a numpy recarray of size (" - + str(nlist) - + ", {})".format(2 + naux) - ) + s += f"a numpy recarray of size ({nlist}, {2 + naux})" print(s) return data.view(np.recarray) @@ -1655,22 +1631,17 @@ def get_record(self, idx, full3D=False): data = binaryread(self.file, dtype, shape=(nlist,)) if self.verbose: if full3D: - s += ( - "full 3D arrays not supported for " - + "imeth = {}".format(imeth) - ) + s += f"full 3D arrays not supported for imeth = {imeth}" else: - s += "a numpy recarray of size (" + str(nlist) + ", 2)" + s += f"a numpy recarray of size ({nlist}, 2)" print(s) if full3D: - s += "full 3D arrays not supported for " + "imeth = {}".format( - imeth - ) + s += f"full 3D arrays not supported for imeth = {imeth}" raise ValueError(s) else: return data.view(np.recarray) else: - raise ValueError("invalid imeth value - {}".format(imeth)) + raise ValueError(f"invalid imeth value - {imeth}") # should not reach this point return @@ -1763,7 +1734,7 @@ def get_residual(self, totim, scaled=False): for i in select_indices: text = self.recordarray[i]["text"].decode() if self.verbose: - print("processing {}".format(text)) + print(f"processing {text}") flow = self.get_record(idx=i, full3D=True) if ncol > 1 and "RIGHT FACE" in text: residual -= flow[:, :, :] @@ -1882,9 +1853,7 @@ def __init__( if precision == "auto": precision = get_headfile_precision(filename) if precision == "unknown": - s = "Error. Precision could not be determined for {}".format( - filename - ) + s = f"Error. Precision could not be determined for {filename}" print(s) raise Exception() self.header_dtype = BinaryHeader.set_dtype( @@ -1903,7 +1872,7 @@ def _get_data_array(self, totim=0.0): if totim >= 0.0: keyindices = np.where((self.recordarray["totim"] == totim))[0] if len(keyindices) == 0: - msg = "totim value ({}) not found in file...".format(totim) + msg = f"totim value ({totim}) not found in file..." raise Exception(msg) else: raise Exception("Data not found...") @@ -1917,10 +1886,7 @@ def _get_data_array(self, totim=0.0): nend = self.recordarray["nrow"][idx] npl = nend - nstrt + 1 if self.verbose: - msg = "Byte position in file: {} for ".format( - ipos - ) + "layer {}".format(ilay) - print(msg) + print(f"Byte position in file: {ipos} for layer {ilay}") self.file.seek(ipos, 0) data[ilay - 1] = binaryread(self.file, self.realtype, shape=(npl,)) return data diff --git a/dependencies/flopy/utils/binarygrid_util.py b/dependencies/flopy/utils/binarygrid_util.py deleted file mode 100644 index 67dccd2..0000000 --- a/dependencies/flopy/utils/binarygrid_util.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -Deprecated version of module to read MODFLOW 6 binary grid files (*.grb) that -define the model grid binary output files. This function imports the current -version of MfGrdFile from ..mf6.utils and returns the instantiated object. -This version is deprecated and will be removed. - -""" - -import warnings - -warnings.simplefilter("always", DeprecationWarning) - - -def MfGrdFile(filename, precision="double", verbose=False): - """ - The deprecated MfGrdFile class. - - Parameters - ---------- - filename : str - Name of the MODFLOW 6 binary grid file - precision : string - 'single' or 'double'. Default is 'double'. - verbose : bool - Write information to the screen. Default is False. - - Returns - ------- - mfg : MfGrdFile - MfGrdFile object instantiated using flopy.mf6.utils.MfGrdFile - - """ - - warnings.warn( - "flopy.utils.MfGrdFile has been deprecated and will be " - "removed in version 3.3.5. Use flopy.mf6.utils.MfGrdFile instead.", - category=DeprecationWarning, - ) - - from ..mf6.utils import MfGrdFile as deprecated_MfGrdFile - - return deprecated_MfGrdFile(filename, precision=precision, verbose=verbose) diff --git a/dependencies/flopy/utils/check.py b/dependencies/flopy/utils/check.py index 683f7e4..3a62a81 100644 --- a/dependencies/flopy/utils/check.py +++ b/dependencies/flopy/utils/check.py @@ -97,12 +97,10 @@ def __init__( # if isinstance(package, BaseModel): didn't work if hasattr(package, "parent"): self.model = package.parent - self.prefix = "{} PACKAGE DATA VALIDATION".format(package.name[0]) + self.prefix = f"{package.name[0]} PACKAGE DATA VALIDATION" else: self.model = package - self.prefix = "{} MODEL DATA VALIDATION SUMMARY".format( - self.model.name - ) + self.prefix = f"{self.model.name} MODEL DATA VALIDATION SUMMARY" self.package = package if "structured" in self.model.__dict__: self.structured = self.model.structured @@ -125,7 +123,7 @@ def __init__( self.f = open(self.summaryfile, "w") else: self.f = f - self.txt = "\n{}:\n".format(self.prefix) + self.txt = f"\n{self.prefix}:\n" def _add_to_summary( self, @@ -338,9 +336,9 @@ def _stress_period_data_inactivecells(self, stress_period_data): self.summary_array = np.append(self.summary_array, sa).view( np.recarray ) - self.remove_passed(msg + "s") + self.remove_passed(f"{msg}s") else: - self.append_passed(msg + "s") + self.append_passed(f"{msg}s") def _list_spd_check_violations( self, @@ -437,7 +435,7 @@ def get_active(self, include_cbd=False): """ mg = self.model.modelgrid if mg.grid_type == "structured": - nlaycbd = mg._StructuredGrid__laycbd.sum() if include_cbd else 0 + nlaycbd = mg.laycbd.sum() if include_cbd else 0 inds = (mg.nlay + nlaycbd, mg.nrow, mg.ncol) elif mg.grid_type == "vertex": inds = (mg.nlay, mg.ncpl) @@ -558,7 +556,7 @@ def summarize(self): packages = self.summary_array.package desc = self.summary_array.desc self.summary_array["desc"] = [ - "\r {} package: {}".format(packages[i], d.strip()) + f"\r {packages[i]} package: {d.strip()}" if packages[i] != "model" else d for i, d in enumerate(desc) @@ -569,15 +567,15 @@ def summarize(self): desc = a.desc t = "" if len(a) > 0: - t += " {} {}s:\n".format(len(a), etype) + t += f" {len(a)} {etype}s:\n" if len(a) == 1: t = t.replace("s", "") # grammar for e in np.unique(desc): n = np.sum(desc == e) if n > 1: - t += " {} instances of {}\n".format(n, e) + t += f" {n} instances of {e}\n" else: - t += " {} instance of {}\n".format(n, e) + t += f" {n} instance of {e}\n" txt += t if txt == "": txt += " No errors or warnings encountered.\n" @@ -587,20 +585,20 @@ def summarize(self): and self.verbose and self.summary_array.shape[0] > 0 ): - txt += " see {} for details.\n".format(self.summaryfile) + txt += f" see {self.summaryfile} for details.\n" # print checks that passed for higher levels if len(self.passed) > 0 and self.level > 0: txt += "\n Checks that passed:\n" for chkname in self.passed: - txt += " {}\n".format(chkname) + txt += f" {chkname}\n" self.txt += txt # for level 2, print the whole summary table at the bottom if self.level > 1: # kludge to improve screen printing self.summary_array["package"] = [ - "{} ".format(s) for s in self.summary_array["package"] + f"{s} " for s in self.summary_array["package"] ] self.txt += "\nDETAILED SUMMARY:\n{}".format( self.print_summary(float_format="{:.2e}", delimiter="\t") @@ -611,7 +609,7 @@ def summarize(self): elif self.summary_array.shape[0] > 0 and self.level > 0: print("Errors and/or Warnings encountered.") if self.f is not None: - print(" see {} for details.\n".format(self.summaryfile)) + print(f" see {self.summaryfile} for details.\n") # start of older model specific code def _has_cell_indices(self, stress_period_data): @@ -747,13 +745,13 @@ def _fmt_string_list(array, float_format="{}"): fmt_string += ["{}"] elif vtype == "s": raise Exception( - "MfList error: 'str' type found in dtype." - + " This gives unpredictable results when " - + "recarray to file - change to 'object' type" + "MfList error: 'str' type found in dtype. " + "This gives unpredictable results when " + "recarray to file - change to 'object' type" ) else: raise Exception( - "MfList.fmt_string error: unknown vtype " + "in dtype:" + vtype + f"MfList.fmt_string error: unknown vtype in dtype:{vtype}" ) return fmt_string @@ -889,7 +887,7 @@ def _has_cell_indices(self, stress_period_data): ) and "cellid1" not in set(stress_period_data.dtype.names): self._add_to_summary( type="Error", - desc="\r Stress period data missing " "cellid.", + desc="\r Stress period data missing cellid.", ) return False return True diff --git a/dependencies/flopy/utils/cvfdutil.py b/dependencies/flopy/utils/cvfdutil.py index 10b738f..e31a1d7 100644 --- a/dependencies/flopy/utils/cvfdutil.py +++ b/dependencies/flopy/utils/cvfdutil.py @@ -1,4 +1,3 @@ -from collections import OrderedDict import numpy as np @@ -174,18 +173,16 @@ def to_cvfd( # First create vertexdict {(x1, y1): ivert1, (x2, y2): ivert2, ...} and # vertexlist [[ivert1, ivert2, ...], [ivert9, ivert10, ...], ...] # In the process, filter out any duplicate vertices - vertexdict = OrderedDict() + vertexdict = {} vertexlist = [] xcyc = np.empty((ncells, 2), dtype=float) iv = 0 nvertstart = 0 if verbose: print("Converting vertdict to cvfd representation.") - print("Number of cells in vertdict is: {}".format(len(vertdict))) + print(f"Number of cells in vertdict is: {len(vertdict)}") print( - "Cell {} up to {} (but not including) will be processed.".format( - nodestart, nodestop - ) + f"Cell {nodestart} up to {nodestop} (but not including) will be processed." ) for icell in range(nodestart, nodestop): points = vertdict[icell] @@ -204,20 +201,18 @@ def to_cvfd( iv += 1 ivertlist.append(ivert) if ivertlist[0] != ivertlist[-1]: - raise Exception("Cell {} not closed".format(icell)) + raise Exception(f"Cell {icell} not closed") vertexlist.append(ivertlist) # next create vertex_cell_dict = {}; for each vertex, store list of cells # that use it nvert = len(vertexdict) if verbose: - print("Started with {} vertices.".format(nvertstart)) - print("Ended up with {} vertices.".format(nvert)) - print( - "Reduced total number of vertices by {}".format(nvertstart - nvert) - ) + print(f"Started with {nvertstart} vertices.") + print(f"Ended up with {nvert} vertices.") + print(f"Reduced total number of vertices by {nvertstart - nvert}") print("Creating dict of vertices with their associated cells") - vertex_cell_dict = OrderedDict() + vertex_cell_dict = {} for icell in range(nodestart, nodestop): ivertlist = vertexlist[icell] for ivert in ivertlist: @@ -271,7 +266,7 @@ def to_cvfd( def shapefile_to_cvfd(shp, **kwargs): import shapefile - print("Translating shapefile ({}) into cvfd format".format(shp)) + print(f"Translating shapefile ({shp}) into cvfd format") sf = shapefile.Reader(shp) shapes = sf.shapes() vertdict = {} @@ -300,7 +295,7 @@ def shapefile_to_xcyc(shp): """ import shapefile - print("Translating shapefile ({}) into cell centroids".format(shp)) + print(f"Translating shapefile ({shp}) into cell centroids") sf = shapefile.Reader(shp) shapes = sf.shapes() ncells = len(shapes) diff --git a/dependencies/flopy/utils/datafile.py b/dependencies/flopy/utils/datafile.py index 6648f9e..04749dc 100755 --- a/dependencies/flopy/utils/datafile.py +++ b/dependencies/flopy/utils/datafile.py @@ -3,7 +3,6 @@ abstract classes that should not be directly accessed. """ -from __future__ import print_function import numpy as np import flopy.utils from ..discretization.structuredgrid import StructuredGrid @@ -116,13 +115,12 @@ def __init__(self, filetype=None, precision="single"): else: self.dtype = None self.header = None - msg = ( - "Specified {} ".format(self.header_type) - + "type is not available. Available types are:" + print( + "Specified {} type is not available. " + "Available types are:".format(self.header_type) ) - print(msg) for idx, t in enumerate(self.header_types): - print(" {0} {1}".format(idx + 1, t)) + print(f" {idx + 1} {t}") return def get_dtype(self): @@ -166,7 +164,7 @@ def __init__(self, filename, precision, verbose, kwargs): self.file.seek(0, 0) # reset to beginning assert self.file.tell() == 0 if totalbytes == 0: - raise IOError("datafile error: file is empty: " + str(filename)) + raise ValueError(f"datafile error: file is empty: {filename}") self.nrow = 0 self.ncol = 0 self.nlay = 0 @@ -180,7 +178,7 @@ def __init__(self, filename, precision, verbose, kwargs): elif precision == "double": self.realtype = np.float64 else: - raise Exception("Unknown precision specified: " + precision) + raise Exception(f"Unknown precision specified: {precision}") self.model = None self.dis = None @@ -196,7 +194,7 @@ def __init__(self, filename, precision, verbose, kwargs): self.mg = kwargs.pop("modelgrid") if len(kwargs.keys()) > 0: args = ",".join(kwargs.keys()) - raise Exception("LayerFile error: unrecognized kwargs: " + args) + raise Exception(f"LayerFile error: unrecognized kwargs: {args}") # read through the file and build the pointer index self._build_index() @@ -267,13 +265,11 @@ def to_shapefile( ).transpose() ).transpose() if mflay != None: - attrib_dict = { - attrib_name + "{}".format(mflay): plotarray[0, :, :] - } + attrib_dict = {f"{attrib_name}{mflay}": plotarray[0, :, :]} else: attrib_dict = {} for k in range(plotarray.shape[0]): - name = attrib_name + "{}".format(k) + name = f"{attrib_name}{k}" attrib_dict[name] = plotarray[k] from ..export.shapefile_utils import write_grid_shapefile @@ -287,7 +283,7 @@ def plot( totim=None, mflay=None, filename_base=None, - **kwargs + **kwargs, ): """ Plot 3-D model output data in a specific location @@ -376,8 +372,7 @@ def plot( i0 = 0 i1 = self.nlay filenames = [ - "{}_Layer{}.{}".format(filename_base, k + 1, fext) - for k in range(i0, i1) + f"{filename_base}_Layer{k + 1}.{fext}" for k in range(i0, i1) ] # make sure we have a (lay,row,col) shape plotarray @@ -396,7 +391,7 @@ def plot( filenames=filenames, mflay=mflay, modelgrid=self.mg, - **kwargs + **kwargs, ) def _build_index(self): @@ -404,11 +399,10 @@ def _build_index(self): Build the recordarray and iposarray, which maps the header information to the position in the formatted file. """ - e = ( + raise Exception( "Abstract method _build_index called in LayerFile. " - + "This method needs to be overridden." + "This method needs to be overridden." ) - raise Exception(e) def list_records(self): """ @@ -430,7 +424,7 @@ def _get_data_array(self, totim=0): if totim >= 0.0: keyindices = np.where((self.recordarray["totim"] == totim))[0] if len(keyindices) == 0: - msg = "totim value ({}) not found in file...".format(totim) + msg = f"totim value ({totim}) not found in file..." raise Exception(msg) else: raise Exception("Data not found...") @@ -445,9 +439,7 @@ def _get_data_array(self, totim=0): ipos = self.iposarray[idx] ilay = self.recordarray["ilay"][idx] if self.verbose: - msg = "Byte position in file: {} for ".format( - ipos - ) + "layer {}".format(ilay) + msg = f"Byte position in file: {ipos} for layer {ilay}" print(msg) self.file.seek(ipos, 0) nrow = self.recordarray["nrow"][idx] @@ -527,7 +519,7 @@ def get_data(self, kstpkper=None, idx=None, totim=None, mflay=None): ) if idx[0].shape[0] == 0: raise Exception( - "get_data() error: kstpkper not found:{0}".format(kstpkper) + f"get_data() error: kstpkper not found:{kstpkper}" ) totim1 = self.recordarray[idx]["totim"][0] elif totim is not None: @@ -586,11 +578,10 @@ def _read_data(self, shp): Read data from file """ - e = ( + raise Exception( "Abstract method _read_data called in LayerFile. " - + "This method needs to be overridden." + "This method needs to be overridden." ) - raise Exception(e) def _build_kijlist(self, idx): if isinstance(idx, list): @@ -604,12 +595,6 @@ def _build_kijlist(self, idx): # the seek approach won't work. Can't use k = -1, for example. for k, i, j in kijlist: fail = False - errmsg = ( - "Invalid cell index. Cell " - + str((k, i, j)) - + " not within model grid: " - + str((self.nlay, self.nrow, self.ncol)) - ) if k < 0 or k > self.nlay - 1: fail = True if i < 0 or i > self.nrow - 1: @@ -617,7 +602,10 @@ def _build_kijlist(self, idx): if j < 0 or j > self.ncol - 1: fail = True if fail: - raise Exception(errmsg) + raise Exception( + "Invalid cell index. Cell {} not within model grid: " + "{}".format((k, i, j), (self.nlay, self.nrow, self.ncol)) + ) return kijlist def _get_nstation(self, idx, kijlist): diff --git a/dependencies/flopy/utils/datautil.py b/dependencies/flopy/utils/datautil.py index 08c2fdf..71bf50e 100644 --- a/dependencies/flopy/utils/datautil.py +++ b/dependencies/flopy/utils/datautil.py @@ -260,6 +260,13 @@ def array_comp(self, first_array, second_array): return False return True + def riv_array_comp(self, first_array, second_array): + for line_first, line_second in zip(first_array, second_array): + diff = np.abs(line_first[0][2] - line_second[0][2]) + if diff > self.max_error: + return False + return True + @staticmethod def reset_delimiter_used(): PyListUtil.delimiter_used = None @@ -344,14 +351,10 @@ def split_data_line(line, external_file=False, delimiter_conf_length=15): if index < len_cl: item = clean_line[index] if item[-1] in PyListUtil.quote_list: - arr_fixed_line[-1] = "{} {}".format( - arr_fixed_line[-1], item[:-1] - ) + arr_fixed_line[-1] += f" {item[:-1]}" break else: - arr_fixed_line[-1] = "{} {}".format( - arr_fixed_line[-1], item - ) + arr_fixed_line[-1] += f" {item}" else: # no quote, just append arr_fixed_line.append(item) @@ -392,13 +395,13 @@ def save_array_diff( def save_array(self, filename, multi_array): file_path = os.path.join(self.path, filename) with open(file_path, "w") as outfile: - outfile.write("{}\n".format(str(multi_array.shape))) + outfile.write(f"{multi_array.shape}\n") if len(multi_array.shape) == 4: for slice in multi_array: for second_slice in slice: for third_slice in second_slice: for item in third_slice: - outfile.write(" {:10.3e}".format(item)) + outfile.write(f" {item:10.3e}") outfile.write("\n") outfile.write("\n") outfile.write("\n") @@ -594,7 +597,7 @@ def nth_index(self, n): aii = ArrayIndexIter(self.list_shape, True) index_num = 0 while index_num <= n: - index = aii.next() + index = next(aii) index_num += 1 return index @@ -651,8 +654,6 @@ def __next__(self): self.current_index -= 1 raise StopIteration() - next = __next__ # Python 2 support - class MultiListIter: def __init__(self, multi_list, detailed_info=False, iter_leaf_lists=False): @@ -673,8 +674,6 @@ def __next__(self): else: return next_val[0] - next = __next__ # Python 2 support - class ConstIter: def __init__(self, value): @@ -686,8 +685,6 @@ def __iter__(self): def __next__(self): return self.value - next = __next__ # Python 2 support - class FileIter: def __init__(self, file_path): @@ -729,8 +726,6 @@ def _next_line(self): return self._current_data = PyListUtil.split_data_line(data_line) - next = __next__ # Python 2 support - class NameIter: def __init__(self, name, first_not_numbered=True): @@ -746,9 +741,7 @@ def __next__(self): if self.iter_num == 0 and self.first_not_numbered: return self.name else: - return "{}_{}".format(self.name, self.iter_num) - - next = __next__ # Python 2 support + return f"{self.name}_{self.iter_num}" class PathIter: @@ -760,6 +753,4 @@ def __iter__(self): return self def __next__(self): - return self.path[0:-1] + (self.name_iter.__next__(),) - - next = __next__ # Python 2 support + return self.path[0:-1] + (next(self.name_iter),) diff --git a/dependencies/flopy/utils/flopy_io.py b/dependencies/flopy/utils/flopy_io.py index 017bb81..eb96d09 100755 --- a/dependencies/flopy/utils/flopy_io.py +++ b/dependencies/flopy/utils/flopy_io.py @@ -33,18 +33,18 @@ def _fmt_string(array, float_format="{}"): if vtype == "i": fmt_string += "{:.0f} " elif vtype == "f": - fmt_string += "{} ".format(float_format) + fmt_string += f"{float_format} " elif vtype == "o": fmt_string += "{} " elif vtype == "s": raise Exception( - "MfList error: 'str' type found in dtype." - + " This gives unpredictable results when " - + "recarray to file - change to 'object' type" + "MfList error: 'str' type found in dtype. " + "This gives unpredictable results when " + "recarray to file - change to 'object' type" ) else: raise Exception( - "MfList.fmt_string error: unknown vtype " + "in dtype:" + vtype + f"MfList.fmt_string error: unknown vtype in dtype:{vtype}" ) return fmt_string @@ -176,32 +176,34 @@ def write_fixed_var(v, length=10, ipos=None, free=False, comment=None): elif isinstance(ipos, int): ipos = [ipos] if len(ipos) < ncol: - err = ( - "user provided ipos length ({})".format(len(ipos)) - + "should be greater than or equal " - + "to the length of v ({})".format(ncol) + raise Exception( + "user provided ipos length ({}) should be greater than or " + "equal to the length of v ({})".format(len(ipos), ncol) ) - raise Exception(err) out = "" for n in range(ncol): 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".{decimal}f" + # evaluate if the fixed format value will exceed width + if len(f"{{:>{width}{ctype}}}".format(v[n])) > width: + ctype = f".{decimal}g" # preserve precision elif isinstance(v[n], (int, np.int32, np.int64)): ctype = "d" else: ctype = "" - write_fmt = "{{:>{}{}}}".format(ipos[n], ctype) + write_fmt = f"{{:>{width}{ctype}}}" out += write_fmt.format(v[n]) if comment is not None: - out += " # {}".format(comment) + out += f" # {comment}" out += "\n" return out @@ -425,15 +427,15 @@ def ulstrd(f, nlist, ra, model, sfac_columns, ext_unit_dict): # check for external if line.strip().lower().startswith("external"): inunit = int(line_list[1]) - errmsg = "Could not find a file for unit {}".format(inunit) + errmsg = f"Could not find a file for unit {inunit}" if ext_unit_dict is not None: if inunit in ext_unit_dict: namdata = ext_unit_dict[inunit] file_handle = namdata.filehandle else: - raise IOError(errmsg) + raise OSError(errmsg) else: - raise IOError(errmsg) + raise OSError(errmsg) if namdata.filetype == "DATA(BINARY)": binary = True if not binary: @@ -451,11 +453,7 @@ def ulstrd(f, nlist, ra, model, sfac_columns, ext_unit_dict): raw = [fname] fname = os.path.join(*raw) oc_filename = os.path.join(model.model_ws, fname) - msg = ( - "Package.load() error: open/close filename " - + oc_filename - + " not found" - ) + msg = f"Package.load() error: open/close filename {oc_filename} not found" assert os.path.exists(oc_filename), msg if "(binary)" in line.lower(): binary = True diff --git a/dependencies/flopy/utils/formattedfile.py b/dependencies/flopy/utils/formattedfile.py index 35efc8f..df8a966 100644 --- a/dependencies/flopy/utils/formattedfile.py +++ b/dependencies/flopy/utils/formattedfile.py @@ -68,8 +68,8 @@ def read_header(self, text_file): and arrheader[4].upper() != self.text_ident.upper() ): raise Exception( - "Expected header not found. Make sure the file being processed includes headers " - + "(LABEL output control option): " + "Expected header not found. Make sure the file being " + "processed includes headers (LABEL output control option): " + header_text ) if ( @@ -83,7 +83,7 @@ def read_header(self, text_file): or not is_int(arrheader[7]) ): raise Exception( - "Unexpected format for FHDTextHeader: " + header_text + f"Unexpected format for FHDTextHeader: {header_text}" ) headerinfo = np.empty([8], dtype=self.dtype) @@ -178,7 +178,7 @@ def _get_text_header(self): """ raise Exception( "Abstract method _get_text_header called in FormattedLayerFile. " - + "This method needs to be overridden." + "This method needs to be overridden." ) def _read_data(self, shp): @@ -203,7 +203,7 @@ def _read_data(self, shp): if not is_float(val): raise Exception( "Invalid data encountered while reading data file." - + " Unable to convert data to float." + " Unable to convert data to float." ) result[current_row, current_col] = float(val) current_col += 1 @@ -234,7 +234,7 @@ def _read_val(self, i): if not is_float(val): raise Exception( "Invalid data encountered while reading data file." - + " Unable to convert data to float." + " Unable to convert data to float." ) result = float(val) current_col = current_col + 1 @@ -369,7 +369,7 @@ def __init__( text="head", precision="single", verbose=False, - **kwargs + **kwargs, ): self.text = text super().__init__(filename, precision, verbose, kwargs) @@ -396,12 +396,10 @@ def _get_data_size(self, header): data_count += len(arr_column_data) if data_count != header["ncol"]: - e = ( - "Unexpected data formatting in head file. Expected " - + "{:d} columns, ".format(header["ncol"]) - + "but found {:d}.".format(data_count) + raise Exception( + "Unexpected data formatting in head file. Expected {:d} " + "columns, but found {:d}.".format(header["ncol"], data_count) ) - raise Exception(e) # Calculate seek distance based on data size stop_pos = self.file.tell() diff --git a/dependencies/flopy/utils/geometry.py b/dependencies/flopy/utils/geometry.py index 42c0f7c..7f3eca1 100644 --- a/dependencies/flopy/utils/geometry.py +++ b/dependencies/flopy/utils/geometry.py @@ -173,7 +173,7 @@ def __init__(self, geometries=()): super().__init__(geometries) def __repr__(self): - return "Shapes: {}".format(list(self)) + return f"Shapes: {list(self)}" @property def __geo_interface__(self): @@ -238,7 +238,7 @@ def __init__(self, polygons=()): super().__init__(polygons) def __repr__(self): - return "MultiPolygon: {}".format(list(self)) + return f"MultiPolygon: {list(self)}" @property def __geo_interface__(self): @@ -266,7 +266,7 @@ def __init__(self, linestrings=()): super().__init__(linestrings) def __repr__(self): - return "LineString: {}".format(list(self)) + return f"LineString: {list(self)}" @property def __geo_interface__(self): @@ -294,7 +294,7 @@ def __init__(self, points=()): super().__init__(points) def __repr__(self): - return "MultiPoint: {}".format(list(self)) + return f"MultiPoint: {list(self)}" @property def __geo_interface__(self): @@ -701,42 +701,6 @@ def transform( return xrot, yrot -def shape(pyshp_shpobj): - """ - Convert a pyshp geometry object to a flopy geometry object. - - Parameters - ---------- - pyshp_shpobj : shapefile._Shape instance - - Returns - ------- - shape : flopy.utils.geometry Polygon, Linestring, or Point - - Notes - ----- - Currently only regular Polygons, LineStrings and Points (pyshp types 5, 3, 1) supported. - - Examples - -------- - >>> import shapefile as sf - >>> from flopy.utils.geometry import shape - >>> sfobj = sf.Reader('shapefile.shp') - >>> flopy_geom = shape(list(sfobj.iterShapes())[0]) - - """ - import warnings - - warnings.warn( - "Method will be Deprecated, calling GeoSpatialUtil", - DeprecationWarning, - ) - - from .geospatial_utils import GeoSpatialUtil - - return GeoSpatialUtil(pyshp_shpobj).flopy_geometry - - def get_polygon_area(geom): """ Calculate the area of a closed polygon diff --git a/dependencies/flopy/utils/gridgen.py b/dependencies/flopy/utils/gridgen.py index 0751e8c..d20f198 100644 --- a/dependencies/flopy/utils/gridgen.py +++ b/dependencies/flopy/utils/gridgen.py @@ -1,4 +1,3 @@ -from __future__ import print_function import os import numpy as np import subprocess @@ -73,7 +72,7 @@ def features_to_shapefile(features, featuretype, filename): "linestring", "polygon", ]: - raise Exception("Unrecognized feature type: {}".format(featuretype)) + raise Exception(f"Unrecognized feature type: {featuretype}") if featuretype.lower() in ("line", "linestring"): wr = shapefile.Writer(filename, shapeType=shapefile.POLYLINE) @@ -107,12 +106,12 @@ def ndarray_to_asciigrid(fname, a, extent, nodata=1.0e30): dx = (xmax - xmin) / ncol assert dx == (ymax - ymin) / nrow # header - header = "ncols {}\n".format(ncol) - header += "nrows {}\n".format(nrow) - header += "xllcorner {}\n".format(xmin) - header += "yllcorner {}\n".format(ymin) - header += "cellsize {}\n".format(dx) - header += "NODATA_value {}\n".format(float(nodata)) + header = f"ncols {ncol}\n" + header += f"nrows {nrow}\n" + header += f"xllcorner {xmin}\n" + header += f"yllcorner {ymin}\n" + header += f"cellsize {dx}\n" + header += f"NODATA_value {float(nodata)}\n" # replace nan with nodata idx = np.isnan(a) a[idx] = float(nodata) @@ -308,7 +307,7 @@ def set_surface_interpolation( "ymin, ymax: {}".format(elev_extent) ) - nm = "_gridgen.lay{}.asc".format(isurf) + nm = f"_gridgen.lay{isurf}.asc" fname = os.path.join(self.model_ws, nm) ndarray_to_asciigrid(fname, elev, elev_extent) self._asciigrid_dict[isurf] = nm @@ -355,7 +354,7 @@ def add_active_domain(self, feature, layers): self.nja = 0 # Create shapefile or set shapefile to feature - adname = "ad{}".format(len(self._addict)) + adname = f"ad{len(self._addict)}" if isinstance(feature, list): # Create a shapefile adname_w_path = os.path.join(self.model_ws, adname) @@ -365,8 +364,8 @@ def add_active_domain(self, feature, layers): shapefile = feature self._addict[adname] = shapefile - sn = os.path.join(self.model_ws, shapefile + ".shp") - assert os.path.isfile(sn), "Shapefile does not exist: {}".format(sn) + sn = os.path.join(self.model_ws, f"{shapefile}.shp") + assert os.path.isfile(sn), f"Shapefile does not exist: {sn}" for k in layers: self._active_domain[k] = adname @@ -405,7 +404,7 @@ def add_refinement_features(self, features, featuretype, level, layers): self.nja = 0 # Create shapefile or set shapefile to feature - rfname = "rf{}".format(len(self._rfdict)) + rfname = f"rf{len(self._rfdict)}" if isinstance(features, list): rfname_w_path = os.path.join(self.model_ws, rfname) features_to_shapefile(features, featuretype, rfname_w_path) @@ -414,8 +413,8 @@ def add_refinement_features(self, features, featuretype, level, layers): shapefile = features self._rfdict[rfname] = [shapefile, featuretype, level] - sn = os.path.join(self.model_ws, shapefile + ".shp") - assert os.path.isfile(sn), "Shapefile does not exist: {}".format(sn) + sn = os.path.join(self.model_ws, f"{shapefile}.shp") + assert os.path.isfile(sn), f"Shapefile does not exist: {sn}" for k in layers: self._refinement_features[k].append(rfname) @@ -550,7 +549,7 @@ def export(self, verbose=False): f.close() assert os.path.isfile( fname - ), "Could not create export dfn file: {}".format(fname) + ), f"Could not create export dfn file: {fname}" # Export shapefiles cmds = [ @@ -646,7 +645,7 @@ def plot( cmap="Dark2", a=None, masked_values=None, - **kwargs + **kwargs, ): """ Plot the grid. This method will plot the grid using the shapefile @@ -684,7 +683,7 @@ def plot( try: import matplotlib.pyplot as plt except: - err_msg = "matplotlib must be installed to " + "use gridgen.plot()" + err_msg = "matplotlib must be installed to use gridgen.plot()" raise ImportError(err_msg) from ..plot import plot_shapefile, shapefile_extents @@ -705,7 +704,7 @@ def plot( a=a, masked_values=masked_values, idx=idx, - **kwargs + **kwargs, ) plt.xlim(xmin, xmax) plt.ylim(ymin, ymax) @@ -808,9 +807,7 @@ def get_disu( # top top = [0] * nlay for k in range(nlay): - fname = os.path.join( - self.model_ws, "quadtreegrid.top{}.dat".format(k + 1) - ) + fname = os.path.join(self.model_ws, f"quadtreegrid.top{k + 1}.dat") f = open(fname, "r") tpk = np.empty((nodelay[k]), dtype=np.float32) tpk = read1d(f, tpk) @@ -823,16 +820,14 @@ def get_disu( (nodelay[k],), np.float32, np.reshape(tpk, (nodelay[k],)), - name="top {}".format(k + 1), + name=f"top {k + 1}", ) top[k] = tpk # bot bot = [0] * nlay for k in range(nlay): - fname = os.path.join( - self.model_ws, "quadtreegrid.bot{}.dat".format(k + 1) - ) + fname = os.path.join(self.model_ws, f"quadtreegrid.bot{k + 1}.dat") f = open(fname, "r") btk = np.empty((nodelay[k]), dtype=np.float32) btk = read1d(f, btk) @@ -845,7 +840,7 @@ def get_disu( (nodelay[k],), np.float32, np.reshape(btk, (nodelay[k],)), - name="bot {}".format(k + 1), + name=f"bot {k + 1}", ) bot[k] = btk @@ -868,7 +863,7 @@ def get_disu( (nodelay[k],), np.float32, np.reshape(ark, (nodelay[k],)), - name="area layer {}".format(k + 1), + name=f"area layer {k + 1}", ) area[k] = ark istart = istop @@ -1012,9 +1007,7 @@ def get_top(self): istart = 0 for k in range(nlay): istop = istart + nodelay[k] - fname = os.path.join( - self.model_ws, "quadtreegrid.top{}.dat".format(k + 1) - ) + fname = os.path.join(self.model_ws, f"quadtreegrid.top{k + 1}.dat") f = open(fname, "r") tpk = np.empty((nodelay[k]), dtype=np.float32) tpk = read1d(f, tpk) @@ -1040,9 +1033,7 @@ def get_bot(self): istart = 0 for k in range(nlay): istop = istart + nodelay[k] - fname = os.path.join( - self.model_ws, "quadtreegrid.bot{}.dat".format(k + 1) - ) + fname = os.path.join(self.model_ws, f"quadtreegrid.bot{k + 1}.dat") f = open(fname, "r") btk = np.empty((nodelay[k]), dtype=np.float32) btk = read1d(f, btk) @@ -1380,13 +1371,6 @@ def get_cellxy(self, ncells): cellxy[n, 1] = y return cellxy - def get_gridprops(self): - msg = ( - "Use: " - "get_gridprops_disu5, get_gridprops_disu6, get_gridprops_disv" - ) - raise DeprecationWarning(msg) - @staticmethod def gridarray_to_flopyusg_gridarray(nodelay, a): nlay = nodelay.shape[0] @@ -1681,16 +1665,6 @@ def get_gridprops_unstructuredgrid(self): return gridprops - def to_disu6(self, fname, writevertices=True): - msg = ( - "Use: " "flopy.mf6.ModflowGwfdisu(gwf, **g.get_gridprops_disu6())" - ) - raise DeprecationWarning(msg) - - def to_disv6(self, fname, verbose=False): - msg = "Use: " "flopy.mf6.ModflowGwfdisv(gwf, **g.get_gridprops_disv())" - raise DeprecationWarning(msg) - def intersect(self, features, featuretype, layer): """ Parameters @@ -1712,15 +1686,15 @@ def intersect(self, features, featuretype, layer): ifname = "intersect_feature" if isinstance(features, list): ifname_w_path = os.path.join(self.model_ws, ifname) - if os.path.exists(ifname_w_path + ".shp"): - os.remove(ifname_w_path + ".shp") + if os.path.exists(f"{ifname_w_path}.shp"): + os.remove(f"{ifname_w_path}.shp") features_to_shapefile(features, featuretype, ifname_w_path) shapefile = ifname else: shapefile = features - sn = os.path.join(self.model_ws, shapefile + ".shp") - assert os.path.isfile(sn), "Shapefile does not exist: {}".format(sn) + sn = os.path.join(self.model_ws, f"{shapefile}.shp") + assert os.path.isfile(sn), f"Shapefile does not exist: {sn}" fname = os.path.join(self.model_ws, "_intersect.dfn") if os.path.isfile(fname): @@ -1770,13 +1744,13 @@ def intersect(self, features, featuretype, layer): def _intersection_block(self, shapefile, featuretype, layer): s = "" - s += "BEGIN GRID_INTERSECTION intersect" + "\n" + s += "BEGIN GRID_INTERSECTION intersect\n" s += " GRID = quadtreegrid\n" - s += " LAYER = {}\n".format(layer + 1) - s += " SHAPEFILE = {}\n".format(shapefile) - s += " FEATURE_TYPE = {}\n".format(featuretype) - s += " OUTPUT_FILE = {}\n".format("intersection.ifo") - s += "END GRID_INTERSECTION intersect" + "\n" + s += f" LAYER = {layer + 1}\n" + s += f" SHAPEFILE = {shapefile}\n" + s += f" FEATURE_TYPE = {featuretype}\n" + s += " OUTPUT_FILE = intersection.ifo\n" + s += "END GRID_INTERSECTION intersect\n" return s def _mfgrid_block(self): @@ -1788,18 +1762,18 @@ def _mfgrid_block(self): angrot = self.modelgrid.angrot s = "" - s += "BEGIN MODFLOW_GRID basegrid" + "\n" - s += " ROTATION_ANGLE = {}\n".format(angrot) - s += " X_OFFSET = {}\n".format(xoff) - s += " Y_OFFSET = {}\n".format(yoff) - s += " NLAY = {}\n".format(self.nlay) - s += " NROW = {}\n".format(self.nrow) - s += " NCOL = {}\n".format(self.ncol) + s += "BEGIN MODFLOW_GRID basegrid\n" + s += f" ROTATION_ANGLE = {angrot}\n" + s += f" X_OFFSET = {xoff}\n" + s += f" Y_OFFSET = {yoff}\n" + s += f" NLAY = {self.nlay}\n" + s += f" NROW = {self.nrow}\n" + s += f" NCOL = {self.ncol}\n" # delr delr = self.dis.delr.array if delr.min() == delr.max(): - s += " DELR = CONSTANT {}\n".format(delr.min()) + s += f" DELR = CONSTANT {delr.min()}\n" else: s += " DELR = OPEN/CLOSE delr.dat\n" fname = os.path.join(self.model_ws, "delr.dat") @@ -1808,7 +1782,7 @@ def _mfgrid_block(self): # delc delc = self.dis.delc.array if delc.min() == delc.max(): - s += " DELC = CONSTANT {}\n".format(delc.min()) + s += f" DELC = CONSTANT {delc.min()}\n" else: s += " DELC = OPEN/CLOSE delc.dat\n" fname = os.path.join(self.model_ws, "delc.dat") @@ -1817,7 +1791,7 @@ def _mfgrid_block(self): # top top = self.dis.top.array if top.min() == top.max(): - s += " TOP = CONSTANT {}\n".format(top.min()) + s += f" TOP = CONSTANT {top.min()}\n" else: s += " TOP = OPEN/CLOSE top.dat\n" fname = os.path.join(self.model_ws, "top.dat") @@ -1831,27 +1805,25 @@ def _mfgrid_block(self): else: bot = botm[k] if bot.min() == bot.max(): - s += " BOTTOM LAYER {} = CONSTANT {}\n".format( - k + 1, bot.min() - ) + s += f" BOTTOM LAYER {k + 1} = CONSTANT {bot.min()}\n" else: s += " BOTTOM LAYER {0} = OPEN/CLOSE bot{0}.dat\n".format( k + 1 ) - fname = os.path.join(self.model_ws, "bot{}.dat".format(k + 1)) + fname = os.path.join(self.model_ws, f"bot{k + 1}.dat") np.savetxt(fname, bot) - s += "END MODFLOW_GRID" + "\n" + s += "END MODFLOW_GRID\n" return s def _rf_blocks(self): s = "" for rfname, rf in self._rfdict.items(): shapefile, featuretype, level = rf - s += "BEGIN REFINEMENT_FEATURES {}\n".format(rfname) - s += " SHAPEFILE = {}\n".format(shapefile) - s += " FEATURE_TYPE = {}\n".format(featuretype) - s += " REFINEMENT_LEVEL = {}\n".format(level) + s += f"BEGIN REFINEMENT_FEATURES {rfname}\n" + s += f" SHAPEFILE = {shapefile}\n" + s += f" FEATURE_TYPE = {featuretype}\n" + s += f" REFINEMENT_LEVEL = {level}\n" s += "END REFINEMENT_FEATURES\n" s += 2 * "\n" return s @@ -1859,10 +1831,10 @@ def _rf_blocks(self): def _ad_blocks(self): s = "" for adname, shapefile in self._addict.items(): - s += "BEGIN ACTIVE_DOMAIN {}\n".format(adname) - s += " SHAPEFILE = {}\n".format(shapefile) - s += " FEATURE_TYPE = {}\n".format("polygon") - s += " INCLUDE_BOUNDARY = {}\n".format("True") + s += f"BEGIN ACTIVE_DOMAIN {adname}\n" + s += f" SHAPEFILE = {shapefile}\n" + s += " FEATURE_TYPE = polygon\n" + s += " INCLUDE_BOUNDARY = True\n" s += "END ACTIVE_DOMAIN\n" s += 2 * "\n" return s @@ -1875,15 +1847,15 @@ def _builder_block(self): for k, adk in enumerate(self._active_domain): if adk is None: continue - s += " ACTIVE_DOMAIN LAYER {} = {}\n".format(k + 1, adk) + s += f" ACTIVE_DOMAIN LAYER {k + 1} = {adk}\n" # Write refinement feature information for k, rfkl in enumerate(self._refinement_features): if len(rfkl) == 0: continue - s += " REFINEMENT_FEATURES LAYER {} = ".format(k + 1) + s += f" REFINEMENT_FEATURES LAYER {k + 1} = " for rf in rfkl: - s += rf + " " + s += f"{rf} " s += "\n" s += " SMOOTHING = full\n" @@ -1893,18 +1865,14 @@ def _builder_block(self): grd = self._asciigrid_dict[k] else: grd = "basename" - s += " TOP LAYER {} = {} {}\n".format( - k + 1, self.surface_interpolation[k], grd - ) + s += f" TOP LAYER {k + 1} = {self.surface_interpolation[k]} {grd}\n" for k in range(self.nlay): if self.surface_interpolation[k + 1] == "ASCIIGRID": grd = self._asciigrid_dict[k + 1] else: grd = "basename" - s += " BOTTOM LAYER {} = {} {}\n".format( - k + 1, self.surface_interpolation[k + 1], grd - ) + s += f" BOTTOM LAYER {k + 1} = {self.surface_interpolation[k + 1]} {grd}\n" s += " GRID_DEFINITION_FILE = quadtreegrid.dfn\n" s += "END QUADTREE_BUILDER\n" @@ -1926,9 +1894,7 @@ def _grid_export_blocks(self): s += "BEGIN GRID_TO_USGDATA grid_to_usgdata\n" s += " GRID = quadtreegrid\n" s += " USG_DATA_PREFIX = qtg\n" - s += " VERTICAL_PASS_THROUGH = {0}\n".format( - self.vertical_pass_through - ) + s += f" VERTICAL_PASS_THROUGH = {self.vertical_pass_through}\n" s += "END GRID_TO_USGDATA\n" s += "\n" s += "BEGIN GRID_TO_VTKFILE grid_to_vtk\n" @@ -1959,7 +1925,7 @@ def _mkvertdict(self): fname = os.path.join(self.model_ws, "qtg.nod") if not os.path.isfile(fname): raise Exception( - "File {} should have been created by gridgen.".format(fname) + f"File {fname} should have been created by gridgen." ) f = open(fname, "r") line = f.readline() diff --git a/dependencies/flopy/utils/gridintersect.py b/dependencies/flopy/utils/gridintersect.py index 9eaddc1..af6651b 100644 --- a/dependencies/flopy/utils/gridintersect.py +++ b/dependencies/flopy/utils/gridintersect.py @@ -2,7 +2,7 @@ try: import matplotlib.pyplot as plt -except ImportError: +except (ImportError, RuntimeError): plt = None from .geometry import transform @@ -29,17 +29,21 @@ import warnings from distutils.version import LooseVersion +NUMPY_GE_121 = str(np.__version__) >= LooseVersion("1.21") + try: import shapely SHAPELY_GE_20 = str(shapely.__version__) >= LooseVersion("2.0") -except: + SHAPELY_LT_18 = str(shapely.__version__) < LooseVersion("1.8") +except ImportError: shapely = None SHAPELY_GE_20 = False + SHAPELY_LT_18 = False try: from shapely.errors import ShapelyDeprecationWarning as shapely_warning -except: +except ImportError: shapely_warning = None if shapely_warning is not None and not SHAPELY_GE_20: @@ -47,7 +51,32 @@ @contextlib.contextmanager def ignore_shapely_warnings_for_object_array(): with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=shapely_warning) + warnings.filterwarnings( + "ignore", + "Iteration|The array interface|__len__", + shapely_warning, + ) + if NUMPY_GE_121: + # warning from numpy for existing Shapely releases (this is + # fixed with Shapely 1.8) + warnings.filterwarnings( + "ignore", + "An exception was ignored while fetching", + DeprecationWarning, + ) + yield + + +elif SHAPELY_LT_18 and NUMPY_GE_121: + + @contextlib.contextmanager + def ignore_shapely_warnings_for_object_array(): + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", + "An exception was ignored while fetching", + DeprecationWarning, + ) yield @@ -234,7 +263,7 @@ def intersect(self, shp, **kwargs): else: rec = self._intersect_polygon_shapely(shp, sort_by_cellid) else: - err = "Shapetype {} is not supported".format(gu.shapetype) + err = f"Shapetype {gu.shapetype} is not supported" raise TypeError(err) return rec @@ -291,7 +320,7 @@ def _vtx_grid_to_shape_generator(self): for icell in self.mfgrid._cell2d.icell2d: points = [] icverts = [ - "icvert_{}".format(i) + f"icvert_{i}" for i in range(self.mfgrid._cell2d["ncvert"][icell]) ] for iv in self.mfgrid._cell2d[icverts][icell]: @@ -1459,7 +1488,7 @@ def plot_polygon(rec, ax=None, **kwargs): if plt is None: msg = ( "matplotlib and descartes packages needed for " - + "plotting polygons" + "plotting polygons" ) raise ImportError(msg) @@ -1474,14 +1503,14 @@ def plot_polygon(rec, ax=None, **kwargs): if "facecolor" in kwargs: fc = kwargs.pop("facecolor") else: - fc = "C{}".format(i % 10) + fc = f"C{i % 10}" ppi = PolygonPatch(ishp, facecolor=fc, **kwargs) ax.add_patch(ppi) return ax @staticmethod - def plot_linestring(rec, ax=None, **kwargs): + def plot_linestring(rec, ax=None, cmap=None, **kwargs): """method to plot the linestring intersection results from the resulting numpy.recarray. @@ -1494,6 +1523,8 @@ def plot_linestring(rec, ax=None, **kwargs): (the resulting shapes) ax : matplotlib.pyplot.axes, optional axes to plot onto, if not provided, creates a new figure + cmap : str + matplotlib colormap **kwargs: passed to the plot function @@ -1509,13 +1540,24 @@ def plot_linestring(rec, ax=None, **kwargs): if ax is None: _, ax = plt.subplots() + specified_color = True + if "c" in kwargs: + c = kwargs.pop("c") + elif "color" in kwargs: + c = kwargs.pop("color") + else: + specified_color = False + + if cmap is not None: + colormap = plt.get_cmap(cmap) + colors = colormap(np.linspace(0, 1, rec.shape[0])) + for i, ishp in enumerate(rec.ixshapes): - if "c" in kwargs: - c = kwargs.pop("c") - elif "color" in kwargs: - c = kwargs.pop("color") - else: - c = "C{}".format(i % 10) + if not specified_color: + if cmap is None: + c = f"C{i % 10}" + else: + c = colors[i] if ishp.type == "MultiLineString": for part in ishp: ax.plot(part.xy[0], part.xy[1], ls="-", c=c, **kwargs) diff --git a/dependencies/flopy/utils/mflistfile.py b/dependencies/flopy/utils/mflistfile.py index 01fa5e6..3af271a 100644 --- a/dependencies/flopy/utils/mflistfile.py +++ b/dependencies/flopy/utils/mflistfile.py @@ -5,7 +5,6 @@ """ -import collections import os import re import numpy as np @@ -45,9 +44,7 @@ class ListBudget: def __init__(self, file_name, budgetkey=None, timeunit="days"): # Set up file reading - assert os.path.exists(file_name), "file_name {0} not found".format( - file_name - ) + assert os.path.exists(file_name), f"file_name {file_name} not found" self.file_name = file_name self.f = open(file_name, "r", encoding="ascii", errors="replace") @@ -413,16 +410,14 @@ def get_data(self, kstpkper=None, idx=None, totim=None, incremental=False): ipos = self.get_kstpkper().index(kstpkper) except: print( - " could not retrieve kstpkper " - + "{} from the lst file".format(kstpkper) + f" could not retrieve kstpkper {kstpkper} from the lst file" ) elif totim is not None: try: ipos = self.get_times().index(totim) except: print( - " could not retrieve totime " - + "{} from the lst file".format(totim) + f" could not retrieve totime {totim} from the lst file" ) elif idx is not None: ipos = idx @@ -431,8 +426,8 @@ def get_data(self, kstpkper=None, idx=None, totim=None, incremental=False): if ipos is None: print("Could not find specified condition.") - print(" kstpkper = {}".format(kstpkper)) - print(" totim = {}".format(totim)) + print(f" kstpkper = {kstpkper}") + print(f" totim = {totim}") # TODO: return zero-length array, or update docstring return type return None @@ -482,7 +477,7 @@ def get_dataframes(self, start_datetime="1-1-1970", diff=False): try: import pandas as pd except Exception as e: - msg = "ListBudget.get_dataframe(): requires pandas: " + str(e) + msg = f"ListBudget.get_dataframe(): requires pandas: {e!s}" raise ImportError(msg) if not self._isvalid: @@ -506,8 +501,8 @@ def get_dataframes(self, start_datetime="1-1-1970", diff=False): base_names = [name.replace("_IN", "") for name in in_names] for name in base_names: - in_name = name + "_IN" - out_name = name + "_OUT" + in_name = f"{name}_IN" + out_name = f"{name}_OUT" df_flux.loc[:, name.lower()] = ( df_flux.loc[:, in_name] - df_flux.loc[:, out_name] ) @@ -560,7 +555,7 @@ def get_reduced_pumping(self): # to list file check_str = ( "WELLS WITH REDUCED PUMPING WILL BE REPORTED " - + "TO THE MAIN LISTING FILE" + "TO THE MAIN LISTING FILE" ) check_str_ag = "AG WELLS WITH REDUCED PUMPING FOR STRESS PERIOD" @@ -593,25 +588,23 @@ def get_reduced_pumping(self): pump_reduction_flag = True if int(line.strip().split()[-1]) != list_unit: - err = ( + raise AssertionError( "Pumping reductions not written to list file. " "External pumping reduction files can be " "read using: flopy.utils.observationfile." "get_pumping_reduction(, structured=False)" ) - raise AssertionError(err) if not pump_reduction_flag: raise AssertionError("Auto pumping reductions not active.") else: - msg = ( + raise NotImplementedError( "get_reduced_pumping() is only implemented for the " - + "MfListBudget or MfusgListBudget classes. Please " - + "feel free to expand the functionality to other " - + "ListBudget classes." + "MfListBudget or MfusgListBudget classes. Please " + "feel free to expand the functionality to other " + "ListBudget classes." ) - raise NotImplementedError(msg) return get_reduced_pumping(self.f.name, structured) @@ -677,7 +670,7 @@ def _set_entries(self): if len(self.idx_map) < 1: return None, None if len(self.entries) > 0: - raise Exception("entries already set:" + str(self.entries)) + raise Exception(f"entries already set:{self.entries}") if not self.idx_map: raise Exception("must call build_index before call set_entries") try: @@ -690,9 +683,9 @@ def _set_entries(self): "entry in list file" ) self.entries = incdict.keys() - null_entries = collections.OrderedDict() - incdict = collections.OrderedDict() - cumdict = collections.OrderedDict() + null_entries = {} + incdict = {} + cumdict = {} for entry in self.entries: incdict[entry] = [] cumdict[entry] = [] @@ -769,8 +762,8 @@ def _get_sp(self, ts, sp, seekpoint): break tag = "IN" - incdict = collections.OrderedDict() - cumdict = collections.OrderedDict() + incdict = {} + cumdict = {} entrydict = {} while True: @@ -816,10 +809,10 @@ def _get_sp(self, ts, sp, seekpoint): if entry in entrydict: entrydict[entry] += 1 inum = entrydict[entry] - entry = "{}{}".format(entry, inum + 1) + entry = f"{entry}{inum + 1}" else: entrydict[entry] = 0 - key = "{}_{}".format(entry, tag) + key = f"{entry}_{tag}" incdict[key] = flux cumdict[key] = cumu else: diff --git a/dependencies/flopy/utils/mfreadnam.py b/dependencies/flopy/utils/mfreadnam.py index 1f74e67..27b29f4 100644 --- a/dependencies/flopy/utils/mfreadnam.py +++ b/dependencies/flopy/utils/mfreadnam.py @@ -8,12 +8,6 @@ """ import os -import sys - -if sys.version_info < (3, 6): - from collections import OrderedDict - - dict = OrderedDict class NamData: @@ -71,9 +65,7 @@ def __init__(self, pkgtype, name, handle, packages): self.package = packages[self.filetype.lower()] def __repr__(self): - return "filename:{0}, filetype:{1}".format( - self.filename, self.filetype - ) + return f"filename:{self.filename}, filetype:{self.filetype}" def getfiletypeunit(nf, filetype): @@ -93,7 +85,7 @@ def getfiletypeunit(nf, filetype): for cunit, cvals in nf.items(): if cvals.filetype.lower() == filetype.lower(): return cunit - print('Name file does not contain file of type "{0}"'.format(filetype)) + print(f'Name file does not contain file of type "{filetype}"') return None @@ -113,32 +105,30 @@ def parsenamefile(namfilename, packages, verbose=True): Returns ------- - dict or OrderedDict + dict For each file listed in the name file, a :class:`flopy.utils.mfreadnam.NamData` instance - is stored in the returned dict keyed by unit number. Prior to Python - version 3.6 the return object is an OrderedDict to retain the order - of items in the nam file. + is stored in the returned dict keyed by unit number. Raises ------ - IOError: + FileNotFoundError If namfilename does not exist in the directory. - ValueError: + ValueError For lines that cannot be parsed. """ - # initiate the ext_unit_dict ordered dictionary - ext_unit_dict = dict() + # initiate the ext_unit_dict dictionary + ext_unit_dict = {} if verbose: - print("Parsing the namefile --> {0:s}".format(namfilename)) + print(f"Parsing the namefile --> {namfilename}") if not os.path.isfile(namfilename): # help diagnose the namfile and directory - e = "Could not find {} ".format( - namfilename - ) + "in directory {}".format(os.path.dirname(namfilename)) - raise IOError(e) + raise FileNotFoundError( + f"Could not find {namfilename} " + f"in directory {os.path.dirname(namfilename)}" + ) with open(namfilename, "r") as fp: lines = fp.readlines() @@ -150,7 +140,7 @@ def parsenamefile(namfilename, packages, verbose=True): items = line.split() # ensure we have at least three items if len(items) < 3: - e = "line number {} has fewer than 3 items: {}".format(ln, line) + e = f"line number {ln} has fewer than 3 items: {line}" raise ValueError(e) ftype, key, fpath = items[0:3] ftype = ftype.upper() @@ -189,9 +179,9 @@ def parsenamefile(namfilename, packages, verbose=True): kwargs["errors"] = "replace" try: filehandle = open(fname, openmode, **kwargs) - except IOError: + except OSError: if verbose: - print("could not set filehandle to {0:s}".format(fpath)) + print(f"could not set filehandle to {fpath}") filehandle = None # be sure the second value is an integer try: @@ -240,33 +230,31 @@ def attribs_from_namfile_header(namefile): xll = float(item.split(":")[1]) defaults["xll"] = xll except: - print(" could not parse xll " + "in {}".format(namefile)) + print(f" could not parse xll in {namefile}") elif "yll" in item.lower(): try: yll = float(item.split(":")[1]) defaults["yll"] = yll except: - print(" could not parse yll " + "in {}".format(namefile)) + print(f" could not parse yll in {namefile}") elif "xul" in item.lower(): try: xul = float(item.split(":")[1]) defaults["xul"] = xul except: - print(" could not parse xul " + "in {}".format(namefile)) + print(f" could not parse xul in {namefile}") elif "yul" in item.lower(): try: yul = float(item.split(":")[1]) defaults["yul"] = yul except: - print(" could not parse yul " + "in {}".format(namefile)) + print(f" could not parse yul in {namefile}") elif "rotation" in item.lower(): try: angrot = float(item.split(":")[1]) defaults["rotation"] = angrot except: - print( - " could not parse rotation " + "in {}".format(namefile) - ) + print(f" could not parse rotation in {namefile}") elif "proj4_str" in item.lower(): try: proj4 = ":".join(item.split(":")[1:]).strip() @@ -274,13 +262,11 @@ def attribs_from_namfile_header(namefile): proj4 = None defaults["proj4_str"] = proj4 except: - print( - " could not parse proj4_str " + "in {}".format(namefile) - ) + print(f" could not parse proj4_str in {namefile}") elif "start" in item.lower(): try: start_datetime = item.split(":")[1].strip() defaults["start_datetime"] = start_datetime except: - print(" could not parse start " + "in {}".format(namefile)) + print(f" could not parse start in {namefile}") return defaults diff --git a/dependencies/flopy/utils/modpathfile.py b/dependencies/flopy/utils/modpathfile.py index ff50c5d..326a305 100644 --- a/dependencies/flopy/utils/modpathfile.py +++ b/dependencies/flopy/utils/modpathfile.py @@ -8,8 +8,6 @@ """ import itertools -import collections -import warnings import numpy as np from numpy.lib.recfunctions import append_fields, stack_arrays @@ -58,13 +56,10 @@ def _build_index(self): if isinstance(line, bytes): line = line.decode() if self.skiprows < 1: - if ( - "MODPATH_{}_FILE 6".format(self.output_type) - in line.upper() - ): + if f"MODPATH_{self.output_type}_FILE 6" in line.upper(): self.version = 6 elif ( - "MODPATH_{}_FILE 7".format(self.output_type) + f"MODPATH_{self.output_type}_FILE 7" in line.upper() ): self.version = 7 @@ -204,7 +199,8 @@ def get_destination_data(self, dest_cells, to_recarray=True): Parameters ---------- dest_cells : list or array of tuples - (k, i, j) of each destination cell (zero-based) + (k, i, j) of each destination cell for MODPATH versions less than + MODPATH 7 or node number of each destination cell. (zero based) to_recarray : bool Boolean that controls returned series. If to_recarray is True, a single recarray with all of the pathlines that intersect @@ -216,7 +212,8 @@ def get_destination_data(self, dest_cells, to_recarray=True): ------- series : np.recarray Slice of data array (e.g. PathlineFile._data, TimeseriesFile._data) - containing only pathlines with final k,i,j in dest_cells. + containing endpoint, pathline, or timeseries data that intersect + (k,i,j) or (node) dest_cells. """ @@ -229,11 +226,10 @@ def get_destination_data(self, dest_cells, to_recarray=True): try: raslice = ra[["k", "i", "j"]] except (KeyError, ValueError): - msg = ( + raise KeyError( "could not extract 'k', 'i', and 'j' keys " - + "from {} data".format(self.output_type.lower()) + "from {} data".format(self.output_type.lower()) ) - raise KeyError(msg) else: try: raslice = ra[["node"]] @@ -279,8 +275,7 @@ def write_shapefile( shpname="endpoints.shp", mg=None, epsg=None, - sr=None, - **kwargs + **kwargs, ): """ Write pathlines or timeseries to a shapefile @@ -329,20 +324,8 @@ def write_shapefile( series = series.copy() series.sort(order=["particleid", "time"]) - if mg is None and sr.__class__.__name__ == "SpatialReference": - warnings.warn( - "Deprecation warning: SpatialReference is deprecated." - "Use the Grid class instead.", - DeprecationWarning, - ) - mg = StructuredGrid(sr.delc, sr.delr) - mg.set_coord_info( - xoff=sr.xll, - yoff=sr.yll, - angrot=sr.rotation, - epsg=sr.epsg, - proj4=sr.proj4_str, - ) + if mg is None: + raise ValueError("A modelgrid object was not provided.") if epsg is None: epsg = mg.epsg @@ -531,11 +514,10 @@ def _get_dtypes(self): ] ) elif self.version == 7: - msg = ( + raise TypeError( "_get_dtypes() should not be called for " - + "MODPATH 7 pathline files" + "MODPATH 7 pathline files" ) - raise TypeError(msg) return dtype def _get_mp7data(self): @@ -574,7 +556,7 @@ def _get_mp7data(self): ] ) idx = 0 - part_dict = collections.OrderedDict() + part_dict = {} ndata = 0 while True: if idx == 0: @@ -721,12 +703,13 @@ def get_alldata(self, totim=None, ge=True): def get_destination_pathline_data(self, dest_cells, to_recarray=False): """ - Get pathline data for set of destination cells. + Get pathline data that pass through a set of destination cells. Parameters ---------- dest_cells : list or array of tuples - (k, i, j) of each destination cell (zero-based) + (k, i, j) of each destination cell for MODPATH versions less than + MODPATH 7 or node number of each destination cell. (zero based) to_recarray : bool Boolean that controls returned pthldest. If to_recarray is True, a single recarray with all of the pathlines that intersect @@ -738,7 +721,8 @@ def get_destination_pathline_data(self, dest_cells, to_recarray=False): ------- pthldest : np.recarray Slice of pathline data array (e.g. PathlineFile._data) - containing only pathlines with final k,i,j in dest_cells. + containing only pathlines that pass through (k,i,j) or (node) + dest_cells. Examples -------- @@ -761,8 +745,7 @@ def write_shapefile( shpname="pathlines.shp", mg=None, epsg=None, - sr=None, - **kwargs + **kwargs, ): """ Write pathlines to a shapefile @@ -800,8 +783,7 @@ def write_shapefile( shpname=shpname, mg=mg, epsg=epsg, - sr=sr, - **kwargs + **kwargs, ) @@ -893,9 +875,7 @@ def _build_index(self): else: self.version = None if self.version is None: - errmsg = "{} is not a valid endpoint file".format( - self.fname - ) + errmsg = f"{self.fname} is not a valid endpoint file" raise Exception(errmsg) self.skiprows += 1 if self.version == 6 or self.version == 7: @@ -912,7 +892,7 @@ def _build_index(self): self.file.seek(0) if self.verbose: - print("MODPATH version {} endpoint file".format(self.version)) + print(f"MODPATH version {self.version} endpoint file") def _get_dtypes(self): """ @@ -1026,57 +1006,8 @@ def _add_particleid(self): shaped = self._data.shape[0] pids = np.arange(1, shaped + 1, 1, dtype=np.int32) - # determine numpy version - npv = np.__version__ - v = [int(s) for s in npv.split(".")] - if self.verbose: - print("numpy version {}".format(npv)) - # for numpy version 1.14 and higher - if v[0] > 1 or (v[0] == 1 and v[1] > 13): - self._data = append_fields(self._data, "particleid", pids) - # numpy versions prior to 1.14 - else: - if self.verbose: - print(self._data.dtype) - - # convert pids to structured array - pids = np.array( - pids, dtype=np.dtype([("particleid", np.int32)]) - ) - - # create new dtype - dtype = self._get_mp35_dtype(add_id=True) - if self.verbose: - print(dtype) - - # create new array with new dtype and fill with available data - data = np.zeros(shaped, dtype=dtype) - if self.verbose: - print("new data shape {}".format(data.shape)) - print("\nFilling new structured data array") - - # add particle id to new array - if self.verbose: - msg = ( - "writing particleid (pids) to new " - + "structured data array" - ) - print(msg) - data["particleid"] = pids["particleid"] - - # add remaining data to the new array - if self.verbose: - msg = ( - "writing remaining data to new " - + "structured data array" - ) - print(msg) - for name in self._data.dtype.names: - data[name] = self._data[name] - if self.verbose: - print("replacing data with copy of new data array") - self._data = data.copy() + self._data = append_fields(self._data, "particleid", pids) return def get_maxid(self): @@ -1181,12 +1112,13 @@ def get_alldata(self): def get_destination_endpoint_data(self, dest_cells, source=False): """ - Get endpoint data for set of destination cells. + Get endpoint data that terminate in a set of destination cells. Parameters ---------- dest_cells : list or array of tuples - (k, i, j) or (node,) of each destination cell (zero-based) + (k, i, j) of each destination cell for MODPATH versions less than + MODPATH 7 or node number of each destination cell. (zero based) source : bool Boolean to specify is dest_cells applies to source or destination cells (default is False). @@ -1195,7 +1127,8 @@ def get_destination_endpoint_data(self, dest_cells, source=False): ------- epdest : np.recarray Slice of endpoint data array (e.g. EndpointFile.get_alldata) - containing only data with final k,i,j in dest_cells. + containing only endpoint data with final locations in (k,i,j) or + (node) dest_cells. Examples -------- @@ -1220,14 +1153,11 @@ def get_destination_endpoint_data(self, dest_cells, source=False): try: raslice = ra_slice(ra, keys) except (KeyError, ValueError): - msg = ( - "could not extract" - + "'" + raise KeyError( + "could not extract " + "', '".join(keys) - + "'" - + "from endpoint data." + + " from endpoint data." ) - raise KeyError(msg) else: if source: keys = ["node0"] @@ -1236,10 +1166,7 @@ def get_destination_endpoint_data(self, dest_cells, source=False): try: raslice = ra_slice(ra, keys) except (KeyError, ValueError): - msg = ( - "could not extract '{}' ".format(keys[0]) - + "key from endpoint data" - ) + msg = f"could not extract '{keys[0]}' key from endpoint data" raise KeyError(msg) if isinstance(dest_cells, (list, tuple)): allint = all(isinstance(el, int) for el in dest_cells) @@ -1266,8 +1193,7 @@ def write_shapefile( direction="ending", mg=None, epsg=None, - sr=None, - **kwargs + **kwargs, ): """ Write particle starting / ending locations to shapefile. @@ -1304,25 +1230,12 @@ def write_shapefile( elif direction.lower() == "starting": xcol, ycol, zcol = "x0", "y0", "z0" else: - errmsg = ( + raise Exception( 'flopy.map.plot_endpoint direction must be "ending" ' - + 'or "starting".' - ) - raise Exception(errmsg) - if mg is None and sr.__class__.__name__ == "SpatialReference": - warnings.warn( - "Deprecation warning: SpatialReference is deprecated." - "Use the Grid class instead.", - DeprecationWarning, - ) - mg = StructuredGrid(sr.delc, sr.delr) - mg.set_coord_info( - xoff=sr.xll, - yoff=sr.yll, - angrot=sr.rotation, - epsg=sr.epsg, - proj4=sr.proj4_str, + 'or "starting".' ) + if mg is None: + raise ValueError("A modelgrid object was not provided.") if epsg is None: epsg = mg.epsg @@ -1431,11 +1344,9 @@ def _build_index(self): else: self.version = None if self.version is None: - errmsg = ( - "{} ".format(self.fname) - + "is not a valid timeseries file" + raise Exception( + f"{self.fname} is not a valid timeseries file" ) - raise Exception(errmsg) self.skiprows += 1 if self.version == 6 or self.version == 7: if "end header" in line.lower(): @@ -1637,18 +1548,20 @@ def get_alldata(self, totim=None, ge=True): def get_destination_timeseries_data(self, dest_cells): """ - Get timeseries data for set of destination cells. + Get timeseries data that pass through a set of destination cells. Parameters ---------- dest_cells : list or array of tuples - (k, i, j) or nodes of each destination cell (zero-based) + (k, i, j) of each destination cell for MODPATH versions less than + MODPATH 7 or node number of each destination cell. (zero based) Returns ------- tsdest : np.recarray Slice of timeseries data array (e.g. TmeseriesFile._data) - containing only pathlines with final k,i,j in dest_cells. + containing only timeseries that pass through (k,i,j) or + (node) dest_cells. Examples -------- @@ -1669,8 +1582,7 @@ def write_shapefile( shpname="pathlines.shp", mg=None, epsg=None, - sr=None, - **kwargs + **kwargs, ): """ Write pathlines to a shapefile @@ -1708,6 +1620,5 @@ def write_shapefile( shpname=shpname, mg=mg, epsg=epsg, - sr=sr, - **kwargs + **kwargs, ) diff --git a/dependencies/flopy/utils/mtlistfile.py b/dependencies/flopy/utils/mtlistfile.py index 0e8e4c7..31cb63a 100644 --- a/dependencies/flopy/utils/mtlistfile.py +++ b/dependencies/flopy/utils/mtlistfile.py @@ -81,8 +81,7 @@ def parse( try: import pandas as pd except: - msg = "MtListBudget.parse: pandas not available" - raise ImportError(msg) + raise ImportError("MtListBudget.parse: pandas not available") self.gw_data = {} self.sw_data = {} @@ -192,8 +191,7 @@ def _diff(self, df): try: import pandas as pd except: - msg = "MtListBudget._diff: pandas not available" - raise ImportError(msg) + raise ImportError("MtListBudget._diff: pandas not available") out_cols = [ c for c in df.columns if "_out" in c and not c.startswith("net_") @@ -267,9 +265,7 @@ def _parse_gw(self, f, line): totim = float(line.split()[-2]) except Exception as e: raise Exception( - "error parsing totim on line {0}: {1}".format( - self.lcount, str(e) - ) + f"error parsing totim on line {self.lcount}: {e!s}" ) for _ in range(3): @@ -286,14 +282,12 @@ def _parse_gw(self, f, line): tkstp = int(tkstp_str) except Exception as e: raise Exception( - "error parsing time step info on line {0}: {1}".format( - self.lcount, str(e) - ) + f"error parsing time step info on line {self.lcount}: {e!s}" ) for lab, val in zip( ["totim", "kper", "kstp", "tkstp"], [totim, kper, kstp, tkstp] ): - lab += "_{0}".format(comp) + lab += f"_{comp}" if lab not in self.gw_data.keys(): self.gw_data[lab] = [] self.gw_data[lab].append(val) @@ -317,9 +311,7 @@ def _parse_gw(self, f, line): item, ival, oval = self._parse_gw_line(line) except Exception as e: raise Exception( - "error parsing GW items on line {0}: {1}".format( - self.lcount, str(e) - ) + f"error parsing GW items on line {self.lcount}: {e!s}" ) self._add_to_gw_data(item, ival, oval, comp) if break_next: @@ -346,8 +338,7 @@ def _parse_gw(self, f, line): item, ival, oval = self._parse_gw_line(line) except Exception as e: raise Exception( - "error parsing GW items " - "on line {0}: {1}".format(self.lcount, str(e)) + f"error parsing GW items on line {self.lcount}: {e!s}" ) self._add_to_gw_data(item, ival, oval, comp) if "discrepancy" in item: @@ -360,7 +351,7 @@ def _parse_gw_line(self, line): idx_ival = 0 idx_oval = 1 if self.imm: - item = "imm_" + item + item = f"imm_{item}" if "TOTAL" in item.upper(): idx_oval += 1 # to deal with the units in the total string # net (in-out) and discrepancy will only have 1 entry @@ -373,7 +364,7 @@ def _parse_gw_line(self, line): return item, ival, oval def _add_to_gw_data(self, item, ival, oval, comp): - item += "_{0}".format(comp) + item += f"_{comp}" if oval is None: lab_val = zip([""], [ival], [""]) else: @@ -396,12 +387,10 @@ def _parse_sw(self, f, line): tkstp = int(tkstp_str) except Exception as e: raise Exception( - "error parsing time step info on line {0}: {1}".format( - self.lcount, str(e) - ) + f"error parsing time step info on line {self.lcount}: {e!s}" ) for lab, val in zip(["kper", "kstp", "tkstp"], [kper, kstp, tkstp]): - lab += "_{0}".format(comp) + lab += f"_{comp}" if lab not in self.sw_data.keys(): self.sw_data[lab] = [] self.sw_data[lab].append(val) @@ -421,10 +410,9 @@ def _parse_sw(self, f, line): try: item, cval, fval = self._parse_sw_line(line) except Exception as e: - msg = "error parsing 'in' SW items on line {}: " + "{}".format( - self.lcount, str(e) + raise Exception( + f"error parsing 'in' SW items on line {self.lcount}: {e!s}" ) - raise Exception(msg) self._add_to_sw_data("in", item, cval, fval, comp) if break_next: break @@ -444,9 +432,7 @@ def _parse_sw(self, f, line): item, cval, fval = self._parse_sw_line(line) except Exception as e: raise Exception( - "error parsing 'out' SW items on line {0}: {1}".format( - self.lcount, str(e) - ) + f"error parsing 'out' SW items on line {self.lcount}: {e!s}" ) self._add_to_sw_data("out", item, cval, fval, comp) if break_next: @@ -469,9 +455,7 @@ def _parse_sw(self, f, line): item, cval, fval = self._parse_sw_line(line) except Exception as e: raise Exception( - "error parsing 'out' SW items on line {0}: {1}".format( - self.lcount, str(e) - ) + f"error parsing 'out' SW items on line {self.lcount}: {e!s}" ) self._add_to_sw_data("net", item, cval, fval, comp) # out_tots = self._parse_sw_line(line) @@ -491,9 +475,9 @@ def _parse_sw_line(self, line): return citem, cval, fval def _add_to_sw_data(self, inout, item, cval, fval, comp): - item += "_{0}".format(comp) + item += f"_{comp}" if inout.lower() in set(["in", "out"]): - item += "_{0}".format(inout) + item += f"_{inout}" if fval is None: lab_val = zip([""], [cval]) else: diff --git a/dependencies/flopy/utils/observationfile.py b/dependencies/flopy/utils/observationfile.py index a463e0a..85a9172 100644 --- a/dependencies/flopy/utils/observationfile.py +++ b/dependencies/flopy/utils/observationfile.py @@ -178,7 +178,7 @@ def get_dataframe( import pandas as pd from ..utils.utils_def import totim_to_datetime except Exception as e: - msg = "ObsFiles.get_dataframe() error import pandas: " + str(e) + msg = f"ObsFiles.get_dataframe() error import pandas: {e!s}" raise ImportError(msg) i0 = 0 @@ -294,7 +294,7 @@ def __init__(self, filename, verbose=False, isBinary="auto"): isBinary = True else: err = "Could not determine if file is binary or ascii" - raise IOError(err) + raise ValueError(err) if isBinary: # --open binary head file self.file = open(filename, "rb") @@ -574,9 +574,9 @@ def get_selection(data, names): for name in names: if name not in data.dtype.names: ierr += 1 - print("Error: {} is not a valid column name".format(name)) + print(f"Error: {name} is not a valid column name") if ierr > 0: - raise Exception("Error: {} names did not match".format(ierr)) + raise Exception(f"Error: {ierr} names did not match") # Valid list of names so make a selection dtype2 = np.dtype({name: data.dtype.fields[name] for name in names}) diff --git a/dependencies/flopy/utils/optionblock.py b/dependencies/flopy/utils/optionblock.py index a0b5a17..427616f 100644 --- a/dependencies/flopy/utils/optionblock.py +++ b/dependencies/flopy/utils/optionblock.py @@ -1,4 +1,3 @@ -from collections import OrderedDict import numpy as np from ..utils import flopy_io @@ -27,27 +26,19 @@ class OptionBlock: vars = "vars" optional = "optional" - simple_flag = OrderedDict( - [(dtype, np.bool_), (nested, False), (optional, False)] - ) - simple_str = OrderedDict( - [(dtype, str), (nested, False), (optional, False)] - ) - simple_float = OrderedDict( - [(dtype, float), (nested, False), (optional, False)] - ) - simple_int = OrderedDict( - [(dtype, int), (nested, False), (optional, False)] - ) + simple_flag = dict([(dtype, np.bool_), (nested, False), (optional, False)]) + simple_str = dict([(dtype, str), (nested, False), (optional, False)]) + simple_float = dict([(dtype, float), (nested, False), (optional, False)]) + simple_int = dict([(dtype, int), (nested, False), (optional, False)]) - simple_tabfile = OrderedDict( + simple_tabfile = dict( [ (dtype, np.bool_), (nested, True), (n_nested, 2), ( vars, - OrderedDict([("numtab", simple_int), ("maxval", simple_int)]), + dict([("numtab", simple_int), ("maxval", simple_int)]), ), ] ) @@ -282,7 +273,7 @@ def _set_attributes(self): ix += 1 else: - err_msg = "Option: {} not a valid option".format(t[ix]) + err_msg = f"Option: {t[ix]} not a valid option" raise KeyError(err_msg) else: @@ -359,12 +350,10 @@ def load_options(cls, options, package): if openfile: try: options = open(options, "r") - except IOError: - err_msg = ( - "Unrecognized type for options" - " variable: {}".format(type(options)) + except OSError: + raise TypeError( + f"Unrecognized type for options variable: {type(options)}" ) - raise TypeError(err_msg) option_line = "" while True: @@ -398,10 +387,7 @@ def load_options(cls, options, package): valid = True if not valid: - err_msg = ( - "Invalid type set to variable " - "{} in option block".format(k) - ) + err_msg = f"Invalid type set to variable {k} in option block" raise TypeError(err_msg) option_line += t[ix] + " " @@ -488,10 +474,7 @@ def isvalid(dtype, val): pass if not valid: - err_msg = ( - "Invalid type set to variable " - "{} in option block".format(val) - ) + err_msg = f"Invalid type set to variable {val} in option block" raise TypeError(err_msg) return valid diff --git a/dependencies/flopy/utils/postprocessing.py b/dependencies/flopy/utils/postprocessing.py index 64a4608..ed02ead 100644 --- a/dependencies/flopy/utils/postprocessing.py +++ b/dependencies/flopy/utils/postprocessing.py @@ -167,74 +167,6 @@ def get_water_table(heads, nodata, per_idx=None): return np.squeeze(wt) -def get_saturated_thickness(heads, m, nodata, per_idx=None): - """ - Calculates the saturated thickness for each cell from the heads - array for each stress period. - - Parameters - ---------- - heads : 3 or 4-D np.ndarray - Heads array. - m : flopy.modflow.Modflow object - Must have a flopy.modflow.ModflowDis object attached. - nodata : float, list - HDRY value indicating dry cells and/or HNOFLO values. - per_idx : int or sequence of ints - stress periods to return. If None, - returns all stress periods (default). - - Returns - ------- - sat_thickness : 3 or 4-D np.ndarray - Array of saturated thickness - """ - warnings.warn( - "postprocessing.get_saturated_thickness will be deprecated and " - "removed in version 3.3.5. Use grid.saturated_thick(heads).", - PendingDeprecationWarning, - ) - - if not isinstance(nodata, list): - nodata = [nodata] - heads = np.array(heads, ndmin=4) - for mv in nodata: - heads[heads == mv] = np.nan - - top = m.dis.top.array - botm = m.dis.botm.array - top.shape = (1,) + botm.shape[1:] - top = np.concatenate((top, botm[0:-1]), axis=0) - thickness = m.modelgrid.thick - nper, nlay, nrow, ncol = heads.shape - if per_idx is None: - per_idx = list(range(nper)) - elif np.isscalar(per_idx): - per_idx = [per_idx] - - # get confined or unconfined/convertible info - laytyp = m.laytyp - if len(laytyp.shape) == 1: - laytyp.shape = (m.nlay, 1, 1) - is_conf = np.logical_and( - (laytyp == 0), np.full(m.modelgrid.shape, True) - ) - else: - is_conf = laytyp == 0 - - # calculate saturated thickness - sat_thickness = [] - for per in per_idx: - hds = heads[per] - hds = np.where(hds < botm, botm, hds) # for NWT when hds < botm - unconf_thickness = np.where(hds > top, top - botm, hds - botm) - perthickness = np.where(is_conf, thickness, unconf_thickness) - sat_thickness.append(perthickness) - sat_thickness = np.squeeze(sat_thickness) - - return sat_thickness - - def get_gradients(heads, m, nodata, per_idx=None): """ Calculates the hydraulic gradients from the heads @@ -422,7 +354,7 @@ def get_extended_budget( # need calculated heads for some stresses and to check hnoflo and hdry if hdsfile is None: raise ValueError( - "hdsfile must be provided when using " "boundary_ifaces" + "hdsfile must be provided when using boundary_ifaces" ) if isinstance(hdsfile, (bf.HeadFile, fm.FormattedHeadFile)): hds = hdsfile @@ -436,7 +368,7 @@ def get_extended_budget( # get hnoflo and hdry values if model is None: raise ValueError( - "model must be provided when using " "boundary_ifaces" + "model must be provided when using boundary_ifaces" ) noflo_or_dry = np.logical_or(head == model.hnoflo, head == model.hdry) @@ -445,8 +377,7 @@ def get_extended_budget( matched_name = [s for s in rec_names if budget_term in s] if not matched_name: raise RuntimeError( - "Budget term " + budget_term + " not found" - ' in "' + cbcfile + '" file.' + f'Budget term {budget_term} not found in "{cbcfile}" file.' ) if len(matched_name) > 1: raise RuntimeError( @@ -515,8 +446,7 @@ def get_extended_budget( raise ValueError( "This function imposes the use of a " "unique iface (normally = 6) for the " - + budget_term - + " budget term." + "{} budget term.".format(budget_term) ) # loop through boundary cells @@ -604,7 +534,7 @@ def get_extended_budget( Qz_ext[lay, row, col] -= Q_stress_cell else: raise TypeError( - "boundary_ifaces value must be either " "int or list." + "boundary_ifaces value must be either int or list." ) return Qx_ext, Qy_ext, Qz_ext @@ -708,12 +638,13 @@ def get_specific_discharge( if classical_budget: # get saturated thickness (head - bottom elev for unconfined layer) if head is None: - sat_thk = modelgrid.thick + sat_thk = modelgrid.remove_confining_beds(modelgrid.thick) else: sat_thk = modelgrid.saturated_thick( head, mask=[model.hdry, model.hnoflo] ) - sat_thk.shape = model.modelgrid.shape + + sat_thk.shape = modelgrid.shape # inform modelgrid of no-flow and dry cells modelgrid = model.modelgrid @@ -764,9 +695,7 @@ def get_specific_discharge( qy = tqy / cross_area_y qz = tqz / cross_area_z else: - raise ValueError( - '"' + position + '" is not a valid value for ' "position" - ) + raise ValueError(f'"{position}" is not a valid value for position') if position == "vertices": qx = modelgrid.array_at_verts(qx) qy = modelgrid.array_at_verts(qy) diff --git a/dependencies/flopy/utils/rasters.py b/dependencies/flopy/utils/rasters.py index a51dcf9..53f4a17 100644 --- a/dependencies/flopy/utils/rasters.py +++ b/dependencies/flopy/utils/rasters.py @@ -440,23 +440,40 @@ def resample_to_grid( if multithread: q = queue.Queue() container = threading.BoundedSemaphore(thread_pool) - threads = [] - for node in range(ncpl): - t = threading.Thread( - target=self.__threaded_resampling, - args=(modelgrid, node, band, method, container, q), - ) - threads.append(t) - - for thread in threads: - thread.daemon = True - thread.start() - for thread in threads: - thread.join() - - for _ in range(len(threads)): - node, val = q.get() - data[node] = val + + # determine the number of thread pairs required to + # fill the grid + nthreadpairs = int(ncpl / thread_pool) + if ncpl % thread_pool != 0: + nthreadpairs += 1 + + # iterate over the tread pairs + for idx in range(nthreadpairs): + i0 = idx * thread_pool + nthreads = thread_pool + if i0 + thread_pool > ncpl: + nthreads = ncpl - i0 + i1 = i0 + nthreads + threads = [] + for node in range(i0, i1): + t = threading.Thread( + target=self.__threaded_resampling, + args=(modelgrid, node, band, method, container, q), + ) + threads.append(t) + + # start the threads + for thread in threads: + thread.daemon = True + thread.start() + + # wait until all threads are terminated + for thread in threads: + thread.join() + + for idx in range(nthreads): + node, val = q.get() + data[node] = val else: for node in range(ncpl): @@ -472,7 +489,7 @@ def resample_to_grid( data[node] = val else: - raise TypeError("{} method not supported".format(method)) + raise TypeError(f"{method} method not supported") if extrapolate_edges and method != "nearest": xc = modelgrid.xcellcenters @@ -924,7 +941,7 @@ def plot(self, ax=None, contour=False, **kwargs): ax=ax, contour=contour, transform=self._meta["transform"], - **kwargs + **kwargs, ) return ax diff --git a/dependencies/flopy/utils/reference.py b/dependencies/flopy/utils/reference.py index 03da820..0fc85c7 100755 --- a/dependencies/flopy/utils/reference.py +++ b/dependencies/flopy/utils/reference.py @@ -2,1956 +2,9 @@ Module spatial referencing for flopy model objects """ -import json -import numpy as np -import os -import warnings - -from collections import OrderedDict - __all__ = ["TemporalReference"] # all other classes and methods in this module are deprecated -# web address of spatial reference dot org -srefhttp = "https://spatialreference.org" - - -class SpatialReference: - """ - a class to locate a structured model grid in x-y space - - .. deprecated:: 3.2.11 - This class will be removed in version 3.3.5. Use - :py:class:`flopy.discretization.structuredgrid.StructuredGrid` instead. - - Parameters - ---------- - - delr : numpy ndarray - the model discretization delr vector - (An array of spacings along a row) - delc : numpy ndarray - the model discretization delc vector - (An array of spacings along a column) - lenuni : int - the length units flag from the discretization package - (default 2) - xul : float - the x coordinate of the upper left corner of the grid - Enter either xul and yul or xll and yll. - yul : float - the y coordinate of the upper left corner of the grid - Enter either xul and yul or xll and yll. - xll : float - the x coordinate of the lower left corner of the grid - Enter either xul and yul or xll and yll. - yll : float - the y coordinate of the lower left corner of the grid - Enter either xul and yul or xll and yll. - rotation : float - the counter-clockwise rotation (in degrees) of the grid - - proj4_str: str - a PROJ4 string that identifies the grid in space. warning: case - sensitive! - - units : string - Units for the grid. Must be either feet or meters - - epsg : int - EPSG code that identifies the grid in space. Can be used in lieu of - proj4. PROJ4 attribute will auto-populate if there is an internet - connection(via get_proj4 method). - See https://www.epsg-registry.org/ or spatialreference.org - - length_multiplier : float - multiplier to convert model units to spatial reference units. - delr and delc above will be multiplied by this value. (default=1.) - - Attributes - ---------- - xedge : ndarray - array of column edges - - yedge : ndarray - array of row edges - - xgrid : ndarray - numpy meshgrid of xedges - - ygrid : ndarray - numpy meshgrid of yedges - - xcenter : ndarray - array of column centers - - ycenter : ndarray - array of row centers - - xcentergrid : ndarray - numpy meshgrid of column centers - - ycentergrid : ndarray - numpy meshgrid of row centers - - vertices : 1D array - 1D array of cell vertices for whole grid in C-style (row-major) order - (same as np.ravel()) - - - Notes - ----- - - xul and yul can be explicitly (re)set after SpatialReference - instantiation, but only before any of the other attributes and methods are - accessed - - """ - - xul, yul = None, None - xll, yll = None, None - rotation = 0.0 - length_multiplier = 1.0 - origin_loc = "ul" # or ll - - defaults = { - "xul": None, - "yul": None, - "rotation": 0.0, - "proj4_str": None, - "units": None, - "lenuni": 2, - "length_multiplier": None, - "source": "defaults", - } - - lenuni_values = {"undefined": 0, "feet": 1, "meters": 2, "centimeters": 3} - lenuni_text = {v: k for k, v in lenuni_values.items()} - - def __init__( - self, - delr=np.array([]), - delc=np.array([]), - lenuni=2, - xul=None, - yul=None, - xll=None, - yll=None, - rotation=0.0, - proj4_str=None, - epsg=None, - prj=None, - units=None, - length_multiplier=None, - ): - warnings.warn( - "SpatialReference has been deprecated and will be removed in " - "version 3.3.5. Use StructuredGrid instead.", - category=DeprecationWarning, - ) - - for delrc in [delr, delc]: - if isinstance(delrc, float) or isinstance(delrc, int): - msg = ( - "delr and delcs must be an array or sequences equal in " - "length to the number of rows/columns." - ) - raise TypeError(msg) - - self.delc = np.atleast_1d(np.array(delc)).astype( - np.float64 - ) # * length_multiplier - self.delr = np.atleast_1d(np.array(delr)).astype( - np.float64 - ) # * length_multiplier - - if self.delr.sum() == 0 or self.delc.sum() == 0: - if xll is None or yll is None: - msg = ( - "Warning: no grid spacing or lower-left corner " - "supplied. Setting the offset with xul, yul requires " - "arguments for delr and delc. Origin will be set to " - "zero." - ) - print(msg) - xll, yll = 0, 0 - xul, yul = None, None - - self._lenuni = lenuni - self._proj4_str = proj4_str - - self._epsg = epsg - if epsg is not None: - self._proj4_str = getproj4(self._epsg) - self.prj = prj - self._wkt = None - self.crs = crs(prj=prj, epsg=epsg) - - self.supported_units = ["feet", "meters"] - self._units = units - self._length_multiplier = length_multiplier - self._reset() - self.set_spatialreference(xul, yul, xll, yll, rotation) - - @property - def xll(self): - if self.origin_loc == "ll": - xll = self._xll if self._xll is not None else 0.0 - elif self.origin_loc == "ul": - # calculate coords for lower left corner - xll = self._xul - ( - np.sin(self.theta) * self.yedge[0] * self.length_multiplier - ) - return xll - - @property - def yll(self): - if self.origin_loc == "ll": - yll = self._yll if self._yll is not None else 0.0 - elif self.origin_loc == "ul": - # calculate coords for lower left corner - yll = self._yul - ( - np.cos(self.theta) * self.yedge[0] * self.length_multiplier - ) - return yll - - @property - def xul(self): - if self.origin_loc == "ll": - # calculate coords for upper left corner - xul = self._xll + ( - np.sin(self.theta) * self.yedge[0] * self.length_multiplier - ) - if self.origin_loc == "ul": - # calculate coords for lower left corner - xul = self._xul if self._xul is not None else 0.0 - return xul - - @property - def yul(self): - if self.origin_loc == "ll": - # calculate coords for upper left corner - yul = self._yll + ( - np.cos(self.theta) * self.yedge[0] * self.length_multiplier - ) - - if self.origin_loc == "ul": - # calculate coords for lower left corner - yul = self._yul if self._yul is not None else 0.0 - return yul - - @property - def proj4_str(self): - proj4_str = None - if self._proj4_str is not None: - if "epsg" in self._proj4_str.lower(): - proj4_str = self._proj4_str - # set the epsg if proj4 specifies it - tmp = [ - i for i in self._proj4_str.split() if "epsg" in i.lower() - ] - self._epsg = int(tmp[0].split(":")[1]) - else: - proj4_str = self._proj4_str - elif self.epsg is not None: - proj4_str = "epsg:{}".format(self.epsg) - return proj4_str - - @property - def epsg(self): - # don't reset the proj4 string here - # because proj4 attribute may already be populated - # (with more details than getproj4 would return) - # instead reset proj4 when epsg is set - # (on init or setattr) - return self._epsg - - @property - def wkt(self): - if self._wkt is None: - if self.prj is not None: - with open(self.prj) as src: - wkt = src.read() - elif self.epsg is not None: - wkt = getprj(self.epsg) - else: - return None - return wkt - else: - return self._wkt - - @property - def lenuni(self): - return self._lenuni - - def _parse_units_from_proj4(self): - units = None - try: - # need this because preserve_units doesn't seem to be - # working for complex proj4 strings. So if an - # epsg code was passed, we have no choice, but if a - # proj4 string was passed, we can just parse it - if "EPSG" in self.proj4_str.upper(): - import pyproj - - crs = pyproj.Proj(self.proj4_str, preserve_units=True) - proj_str = crs.srs - else: - proj_str = self.proj4_str - # http://proj4.org/parameters.html#units - # from proj4 source code - # "us-ft", "0.304800609601219", "U.S. Surveyor's Foot", - # "ft", "0.3048", "International Foot", - if "units=m" in proj_str: - units = "meters" - elif ( - "units=ft" in proj_str - or "units=us-ft" in proj_str - or "to_meter=0.3048" in proj_str - ): - units = "feet" - return units - except: - if self.proj4_str is not None: - print( - " could not parse units from {}".format(self.proj4_str) - ) - - @property - def units(self): - if self._units is not None: - units = self._units.lower() - else: - units = self._parse_units_from_proj4() - if units is None: - # print("warning: assuming SpatialReference units are meters") - units = "meters" - assert units in self.supported_units - return units - - @property - def length_multiplier(self): - """ - Attempt to identify multiplier for converting from - model units to sr units, defaulting to 1. - """ - lm = None - if self._length_multiplier is not None: - lm = self._length_multiplier - else: - if self.model_length_units == "feet": - if self.units == "meters": - lm = 0.3048 - elif self.units == "feet": - lm = 1.0 - elif self.model_length_units == "meters": - if self.units == "feet": - lm = 1 / 0.3048 - elif self.units == "meters": - lm = 1.0 - elif self.model_length_units == "centimeters": - if self.units == "meters": - lm = 1 / 100.0 - elif self.units == "feet": - lm = 1 / 30.48 - else: # model units unspecified; default to 1 - lm = 1.0 - return lm - - @property - def model_length_units(self): - return self.lenuni_text[self.lenuni] - - @property - def bounds(self): - """ - Return bounding box in shapely order. - """ - xmin, xmax, ymin, ymax = self.get_extent() - return xmin, ymin, xmax, ymax - - @classmethod - def load(cls, namefile=None, reffile="usgs.model.reference"): - """ - Attempts to load spatial reference information from - the following files (in order): - 1) usgs.model.reference - 2) NAM file (header comment) - 3) SpatialReference.default dictionary - """ - reffile = os.path.join(os.path.split(namefile)[0], reffile) - d = SpatialReference.read_usgs_model_reference_file(reffile) - if d is not None: - return d - d = SpatialReference.attribs_from_namfile_header(namefile) - if d is not None: - return d - else: - return SpatialReference.defaults - - @staticmethod - def attribs_from_namfile_header(namefile): - # check for reference info in the nam file header - d = SpatialReference.defaults.copy() - d["source"] = "namfile" - if namefile is None: - return None - header = [] - with open(namefile, "r") as f: - for line in f: - if not line.startswith("#"): - break - header.extend(line.strip().replace("#", "").split(";")) - - for item in header: - if "xul" in item.lower(): - try: - d["xul"] = float(item.split(":")[1]) - except: - print(" could not parse xul " + "in {}".format(namefile)) - elif "yul" in item.lower(): - try: - d["yul"] = float(item.split(":")[1]) - except: - print(" could not parse yul " + "in {}".format(namefile)) - elif "rotation" in item.lower(): - try: - d["rotation"] = float(item.split(":")[1]) - except: - print( - " could not parse rotation " - + "in {}".format(namefile) - ) - elif "proj4_str" in item.lower(): - try: - proj4_str = ":".join(item.split(":")[1:]).strip() - if proj4_str.lower() == "none": - proj4_str = None - d["proj4_str"] = proj4_str - except: - print( - " could not parse proj4_str " - + "in {}".format(namefile) - ) - elif "start" in item.lower(): - try: - d["start_datetime"] = item.split(":")[1].strip() - except: - print( - " could not parse start " + "in {}".format(namefile) - ) - - # spatial reference length units - elif "units" in item.lower(): - d["units"] = item.split(":")[1].strip() - # model length units - elif "lenuni" in item.lower(): - d["lenuni"] = int(item.split(":")[1].strip()) - # multiplier for converting from model length units to sr length units - elif "length_multiplier" in item.lower(): - d["length_multiplier"] = float(item.split(":")[1].strip()) - return d - - @staticmethod - def read_usgs_model_reference_file(reffile="usgs.model.reference"): - """ - read spatial reference info from the usgs.model.reference file - https://water.usgs.gov/ogw/policy/gw-model/modelers-setup.html - """ - - ITMUNI = { - 0: "undefined", - 1: "seconds", - 2: "minutes", - 3: "hours", - 4: "days", - 5: "years", - } - itmuni_values = {v: k for k, v in ITMUNI.items()} - - d = SpatialReference.defaults.copy() - d["source"] = "usgs.model.reference" - # discard default to avoid confusion with epsg code if entered - d.pop("proj4_str") - if os.path.exists(reffile): - with open(reffile) as fref: - for line in fref: - if len(line) > 1: - if line.strip()[0] != "#": - info = line.strip().split("#")[0].split() - if len(info) > 1: - d[info[0].lower()] = " ".join(info[1:]) - d["xul"] = float(d["xul"]) - d["yul"] = float(d["yul"]) - d["rotation"] = float(d["rotation"]) - - # convert the model.reference text to a lenuni value - # (these are the model length units) - if "length_units" in d.keys(): - d["lenuni"] = SpatialReference.lenuni_values[d["length_units"]] - if "time_units" in d.keys(): - d["itmuni"] = itmuni_values[d["time_units"]] - if "start_date" in d.keys(): - start_datetime = d.pop("start_date") - if "start_time" in d.keys(): - start_datetime += " {}".format(d.pop("start_time")) - d["start_datetime"] = start_datetime - if "epsg" in d.keys(): - try: - d["epsg"] = int(d["epsg"]) - except Exception as e: - raise Exception( - "error reading epsg code from file:\n" + str(e) - ) - # this prioritizes epsg over proj4 if both are given - # (otherwise 'proj4' entry will be dropped below) - elif "proj4" in d.keys(): - d["proj4_str"] = d["proj4"] - - # drop any other items that aren't used in sr class - d = { - k: v - for k, v in d.items() - if k.lower() in SpatialReference.defaults.keys() - or k.lower() in {"epsg", "start_datetime", "itmuni", "source"} - } - return d - else: - return None - - def __setattr__(self, key, value): - reset = True - if key == "delr": - super().__setattr__("delr", np.atleast_1d(np.array(value))) - elif key == "delc": - super().__setattr__("delc", np.atleast_1d(np.array(value))) - elif key == "xul": - super().__setattr__("_xul", float(value)) - self.origin_loc = "ul" - elif key == "yul": - super().__setattr__("_yul", float(value)) - self.origin_loc = "ul" - elif key == "xll": - super().__setattr__("_xll", float(value)) - self.origin_loc = "ll" - elif key == "yll": - super().__setattr__("_yll", float(value)) - self.origin_loc = "ll" - elif key == "length_multiplier": - super().__setattr__("_length_multiplier", float(value)) - # self.set_origin(xul=self.xul, yul=self.yul, xll=self.xll, - # yll=self.yll) - elif key == "rotation": - super().__setattr__("rotation", float(value)) - # self.set_origin(xul=self.xul, yul=self.yul, xll=self.xll, - # yll=self.yll) - elif key == "lenuni": - super().__setattr__("_lenuni", int(value)) - # self.set_origin(xul=self.xul, yul=self.yul, xll=self.xll, - # yll=self.yll) - elif key == "units": - value = value.lower() - assert value in self.supported_units - super().__setattr__("_units", value) - elif key == "proj4_str": - super().__setattr__("_proj4_str", value) - # reset the units and epsg - units = self._parse_units_from_proj4() - if units is not None: - self._units = units - self._epsg = None - elif key == "epsg": - super().__setattr__("_epsg", value) - # reset the units and proj4 - self._units = None - self._proj4_str = getproj4(self._epsg) - self.crs = crs(epsg=value) - elif key == "prj": - super().__setattr__("prj", value) - # translation to proj4 strings in crs class not robust yet - # leave units and proj4 alone for now. - self.crs = crs(prj=value, epsg=self.epsg) - else: - super().__setattr__(key, value) - reset = False - if reset: - self._reset() - - def reset(self, **kwargs): - for key, value in kwargs.items(): - setattr(self, key, value) - return - - def _reset(self): - self._xgrid = None - self._ygrid = None - self._ycentergrid = None - self._xcentergrid = None - self._vertices = None - return - - @property - def nrow(self): - return self.delc.shape[0] - - @property - def ncol(self): - return self.delr.shape[0] - - def __eq__(self, other): - if not isinstance(other, SpatialReference): - return False - if other.xul != self.xul: - return False - if other.yul != self.yul: - return False - if other.rotation != self.rotation: - return False - if other.proj4_str != self.proj4_str: - return False - return True - - @classmethod - def from_namfile(cls, namefile): - attribs = SpatialReference.attribs_from_namfile_header(namefile) - try: - attribs.pop("start_datetime") - except: - print(" could not remove start_datetime") - - return cls(**attribs) - - @classmethod - def from_gridspec(cls, gridspec_file, lenuni=0): - f = open(gridspec_file, "r") - raw = f.readline().strip().split() - nrow = int(raw[0]) - ncol = int(raw[1]) - raw = f.readline().strip().split() - xul, yul, rot = float(raw[0]), float(raw[1]), float(raw[2]) - delr = [] - j = 0 - while j < ncol: - raw = f.readline().strip().split() - for r in raw: - if "*" in r: - rraw = r.split("*") - for n in range(int(rraw[0])): - delr.append(float(rraw[1])) - j += 1 - else: - delr.append(float(r)) - j += 1 - delc = [] - i = 0 - while i < nrow: - raw = f.readline().strip().split() - for r in raw: - if "*" in r: - rraw = r.split("*") - for n in range(int(rraw[0])): - delc.append(float(rraw[1])) - i += 1 - else: - delc.append(float(r)) - i += 1 - f.close() - return cls( - np.array(delr), - np.array(delc), - lenuni, - xul=xul, - yul=yul, - rotation=rot, - ) - - @property - def attribute_dict(self): - return { - "xul": self.xul, - "yul": self.yul, - "rotation": self.rotation, - "proj4_str": self.proj4_str, - } - - def set_spatialreference( - self, xul=None, yul=None, xll=None, yll=None, rotation=0.0 - ): - """ - set spatial reference - can be called from model instance - - """ - if xul is not None and xll is not None: - msg = ( - "Both xul and xll entered. Please enter either xul, yul or " - "xll, yll." - ) - raise ValueError(msg) - if yul is not None and yll is not None: - msg = ( - "Both yul and yll entered. Please enter either xul, yul or " - "xll, yll." - ) - raise ValueError(msg) - # set the origin priority based on the left corner specified - # (the other left corner will be calculated). If none are specified - # then default to upper left - if xul is None and yul is None and xll is None and yll is None: - self.origin_loc = "ul" - xul = 0.0 - yul = self.delc.sum() - elif xll is not None: - self.origin_loc = "ll" - else: - self.origin_loc = "ul" - - self.rotation = rotation - self._xll = xll if xll is not None else 0.0 - self._yll = yll if yll is not None else 0.0 - self._xul = xul if xul is not None else 0.0 - self._yul = yul if yul is not None else 0.0 - # self.set_origin(xul, yul, xll, yll) - return - - def __repr__(self): - s = "xul:{0:<.10G}; yul:{1:<.10G}; rotation:{2: ".format(interval) - + "maxlevels = {}".format(maxlevels) - ) - assert nlevels < maxlevels, msg - levels = np.arange(vmin, vmax, interval) - fig, ax = plt.subplots() - ctr = self.contour_array(ax, a, levels=levels) - self.export_contours(filename, ctr, fieldname, epsg, prj, **kwargs) - plt.close() - - def contour_array(self, ax, a, **kwargs): - """ - Create a QuadMesh plot of the specified array using pcolormesh - - Parameters - ---------- - ax : matplotlib.axes.Axes - ax to add the contours - - a : np.ndarray - array to contour - - Returns - ------- - contour_set : ContourSet - - """ - from flopy.plot import ModelMap - - kwargs["ax"] = ax - mm = ModelMap(sr=self) - contour_set = mm.contour_array(a=a, **kwargs) - - return contour_set - - @property - def vertices(self): - """ - Returns a list of vertices for - """ - if self._vertices is None: - self._set_vertices() - return self._vertices - - def _set_vertices(self): - """ - Populate vertices for the whole grid - """ - jj, ii = np.meshgrid(range(self.ncol), range(self.nrow)) - jj, ii = jj.ravel(), ii.ravel() - self._vertices = self.get_vertices(ii, jj) - - def interpolate(self, a, xi, method="nearest"): - """ - Use the griddata method to interpolate values from an array onto the - points defined in xi. For any values outside of the grid, use - 'nearest' to find a value for them. - - Parameters - ---------- - a : numpy.ndarray - array to interpolate from. It must be of size nrow, ncol - xi : numpy.ndarray - array containing x and y point coordinates of size (npts, 2). xi - also works with broadcasting so that if a is a 2d array, then - xi can be passed in as (xgrid, ygrid). - method : {'linear', 'nearest', 'cubic'} - method to use for interpolation (default is 'nearest') - - Returns - ------- - b : numpy.ndarray - array of size (npts) - - """ - try: - from scipy.interpolate import griddata - except: - print("scipy not installed\ntry pip install scipy") - return None - - # Create a 2d array of points for the grid centers - points = np.empty((self.ncol * self.nrow, 2)) - points[:, 0] = self.xcentergrid.flatten() - points[:, 1] = self.ycentergrid.flatten() - - # Use the griddata function to interpolate to the xi points - b = griddata(points, a.flatten(), xi, method=method, fill_value=np.nan) - - # if method is linear or cubic, then replace nan's with a value - # interpolated using nearest - if method != "nearest": - bn = griddata(points, a.flatten(), xi, method="nearest") - idx = np.isnan(b) - b[idx] = bn[idx] - - return b - - def get_2d_vertex_connectivity(self): - """ - Create the cell 2d vertices array and the iverts index array. These - are the same form as the ones used to instantiate an unstructured - spatial reference. - - Returns - ------- - - verts : ndarray - array of x and y coordinates for the grid vertices - - iverts : list - a list with a list of vertex indices for each cell in clockwise - order starting with the upper left corner - - """ - x = self.xgrid.flatten() - y = self.ygrid.flatten() - nrowvert = self.nrow + 1 - ncolvert = self.ncol + 1 - npoints = nrowvert * ncolvert - verts = np.empty((npoints, 2), dtype=float) - verts[:, 0] = x - verts[:, 1] = y - iverts = [] - for i in range(self.nrow): - for j in range(self.ncol): - iv1 = i * ncolvert + j # upper left point number - iv2 = iv1 + 1 - iv4 = (i + 1) * ncolvert + j - iv3 = iv4 + 1 - iverts.append([iv1, iv2, iv3, iv4]) - return verts, iverts - - def get_3d_shared_vertex_connectivity(self, nlay, botm, ibound=None): - - # get the x and y points for the grid - x = self.xgrid.flatten() - y = self.ygrid.flatten() - - # set the size of the vertex grid - nrowvert = self.nrow + 1 - ncolvert = self.ncol + 1 - nlayvert = nlay + 1 - nrvncv = nrowvert * ncolvert - npoints = nrvncv * nlayvert - - # create and fill a 3d points array for the grid - verts = np.empty((npoints, 3), dtype=float) - verts[:, 0] = np.tile(x, nlayvert) - verts[:, 1] = np.tile(y, nlayvert) - istart = 0 - istop = nrvncv - for k in range(nlay + 1): - verts[istart:istop, 2] = self.interpolate( - botm[k], verts[istart:istop, :2], method="linear" - ) - istart = istop - istop = istart + nrvncv - - # create the list of points comprising each cell. points must be - # listed a specific way according to vtk requirements. - iverts = [] - for k in range(nlay): - koffset = k * nrvncv - for i in range(self.nrow): - for j in range(self.ncol): - if ibound is not None: - if ibound[k, i, j] == 0: - continue - iv1 = i * ncolvert + j + koffset - iv2 = iv1 + 1 - iv4 = (i + 1) * ncolvert + j + koffset - iv3 = iv4 + 1 - iverts.append( - [ - iv4 + nrvncv, - iv3 + nrvncv, - iv1 + nrvncv, - iv2 + nrvncv, - iv4, - iv3, - iv1, - iv2, - ] - ) - - # renumber and reduce the vertices if ibound_filter - if ibound is not None: - - # go through the vertex list and mark vertices that are used - ivertrenum = np.zeros(npoints, dtype=int) - for vlist in iverts: - for iv in vlist: - # mark vertices that are actually used - ivertrenum[iv] = 1 - - # renumber vertices that are used, skip those that are not - inum = 0 - for i in range(npoints): - if ivertrenum[i] > 0: - inum += 1 - ivertrenum[i] = inum - ivertrenum -= 1 - - # reassign the vertex list using the new vertex numbers - iverts2 = [] - for vlist in iverts: - vlist2 = [] - for iv in vlist: - vlist2.append(ivertrenum[iv]) - iverts2.append(vlist2) - iverts = iverts2 - idx = np.where(ivertrenum >= 0) - verts = verts[idx] - - return verts, iverts - - def get_3d_vertex_connectivity(self, nlay, top, bot, ibound=None): - if ibound is None: - ncells = nlay * self.nrow * self.ncol - ibound = np.ones((nlay, self.nrow, self.ncol), dtype=int) - else: - ncells = (ibound != 0).sum() - npoints = ncells * 8 - verts = np.empty((npoints, 3), dtype=float) - iverts = [] - ipoint = 0 - for k in range(nlay): - for i in range(self.nrow): - for j in range(self.ncol): - if ibound[k, i, j] == 0: - continue - - ivert = [] - pts = self.get_vertices(i, j) - pt0, pt1, pt2, pt3, pt0 = pts - - z = bot[k, i, j] - - verts[ipoint, 0:2] = np.array(pt1) - verts[ipoint, 2] = z - ivert.append(ipoint) - ipoint += 1 - - verts[ipoint, 0:2] = np.array(pt2) - verts[ipoint, 2] = z - ivert.append(ipoint) - ipoint += 1 - - verts[ipoint, 0:2] = np.array(pt0) - verts[ipoint, 2] = z - ivert.append(ipoint) - ipoint += 1 - - verts[ipoint, 0:2] = np.array(pt3) - verts[ipoint, 2] = z - ivert.append(ipoint) - ipoint += 1 - - z = top[k, i, j] - - verts[ipoint, 0:2] = np.array(pt1) - verts[ipoint, 2] = z - ivert.append(ipoint) - ipoint += 1 - - verts[ipoint, 0:2] = np.array(pt2) - verts[ipoint, 2] = z - ivert.append(ipoint) - ipoint += 1 - - verts[ipoint, 0:2] = np.array(pt0) - verts[ipoint, 2] = z - ivert.append(ipoint) - ipoint += 1 - - verts[ipoint, 0:2] = np.array(pt3) - verts[ipoint, 2] = z - ivert.append(ipoint) - ipoint += 1 - - iverts.append(ivert) - - return verts, iverts - - -class SpatialReferenceUnstructured(SpatialReference): - """ - a class to locate an unstructured model grid in x-y space - - .. deprecated:: 3.2.11 - This class will be removed in version 3.3.5. Use - :py:class:`flopy.discretization.vertexgrid.VertexGrid` instead. - - Parameters - ---------- - - verts : ndarray - 2d array of x and y points. - - iverts : list of lists - should be of len(ncells) with a list of vertex numbers for each cell - - ncpl : ndarray - array containing the number of cells per layer. ncpl.sum() must be - equal to the total number of cells in the grid. - - layered : boolean - flag to indicated that the grid is layered. In this case, the vertices - define the grid for single layer, and all layers use this same grid. - In this case the ncpl value for each layer must equal len(iverts). - If not layered, then verts and iverts are specified for all cells and - all layers in the grid. In this case, npcl.sum() must equal - len(iverts). - - lenuni : int - the length units flag from the discretization package - - proj4_str: str - a PROJ4 string that identifies the grid in space. warning: case - sensitive! - - units : string - Units for the grid. Must be either feet or meters - - epsg : int - EPSG code that identifies the grid in space. Can be used in lieu of - proj4. PROJ4 attribute will auto-populate if there is an internet - connection(via get_proj4 method). - See https://www.epsg-registry.org/ or spatialreference.org - - length_multiplier : float - multiplier to convert model units to spatial reference units. - delr and delc above will be multiplied by this value. (default=1.) - - Attributes - ---------- - xcenter : ndarray - array of x cell centers - - ycenter : ndarray - array of y cell centers - - Notes - ----- - - """ - - def __init__( - self, - xc, - yc, - verts, - iverts, - ncpl, - layered=True, - lenuni=1, - proj4_str=None, - epsg=None, - units=None, - length_multiplier=1.0, - ): - warnings.warn( - "SpatialReferenceUnstructured has been deprecated and will be " - "removed in version 3.3.5. Use VertexGrid instead.", - category=DeprecationWarning, - ) - self.xc = xc - self.yc = yc - self.verts = verts - self.iverts = iverts - self.ncpl = ncpl - self.layered = layered - self._lenuni = lenuni - self._proj4_str = proj4_str - self._epsg = epsg - if epsg is not None: - self._proj4_str = getproj4(epsg) - self.supported_units = ["feet", "meters"] - self._units = units - self._length_multiplier = length_multiplier - - # set defaults - self._xul = 0.0 - self._yul = 0.0 - self.rotation = 0.0 - - if self.layered: - assert all([n == len(iverts) for n in ncpl]) - assert self.xc.shape[0] == self.ncpl[0] - assert self.yc.shape[0] == self.ncpl[0] - else: - msg = "Length of iverts must equal ncpl.sum " "({} {})".format( - len(iverts), ncpl - ) - assert len(iverts) == ncpl.sum(), msg - assert self.xc.shape[0] == self.ncpl.sum() - assert self.yc.shape[0] == self.ncpl.sum() - return - - @property - def grid_type(self): - return "unstructured" - - def write_shapefile(self, filename="grid.shp"): - """ - Write shapefile of the grid - - Parameters - ---------- - filename : string - filename for shapefile - - Returns - ------- - - """ - raise NotImplementedError() - return - - def write_gridSpec(self, filename): - """ - Write a PEST-style grid specification file - - Parameters - ---------- - filename : string - filename for grid specification file - - Returns - ------- - - """ - raise NotImplementedError() - return - - @classmethod - def from_gridspec(cls, fname): - """ - Create a new SpatialReferenceUnstructured grid from an PEST - grid specification file - - Parameters - ---------- - fname : string - File name for grid specification file - - Returns - ------- - sru : flopy.utils.reference.SpatialReferenceUnstructured - - """ - raise NotImplementedError() - return - - @classmethod - def from_argus_export(cls, fname, nlay=1): - """ - Create a new SpatialReferenceUnstructured grid from an Argus One - Trimesh file - - Parameters - ---------- - fname : string - File name - - nlay : int - Number of layers to create - - Returns - ------- - sru : flopy.utils.reference.SpatialReferenceUnstructured - - """ - from ..utils.geometry import get_polygon_centroid - - f = open(fname, "r") - line = f.readline() - ll = line.split() - ncells, nverts = ll[0:2] - ncells = int(ncells) - nverts = int(nverts) - verts = np.empty((nverts, 2), dtype=float) - xc = np.empty((ncells), dtype=float) - yc = np.empty((ncells), dtype=float) - - # read the vertices - f.readline() - for ivert in range(nverts): - line = f.readline() - ll = line.split() - c, iv, x, y = ll[0:4] - verts[ivert, 0] = x - verts[ivert, 1] = y - - # read the cell information and create iverts, xc, and yc - iverts = [] - for icell in range(ncells): - line = f.readline() - ll = line.split() - ivlist = [] - for ic in ll[2:5]: - ivlist.append(int(ic) - 1) - if ivlist[0] != ivlist[-1]: - ivlist.append(ivlist[0]) - iverts.append(ivlist) - xc[icell], yc[icell] = get_polygon_centroid(verts[ivlist, :]) - - # close file and return spatial reference - f.close() - return cls(xc, yc, verts, iverts, np.array(nlay * [len(iverts)])) - - def __setattr__(self, key, value): - super(SpatialReference, self).__setattr__(key, value) - return - - def get_extent(self): - """ - Get the extent of the grid - - Returns - ------- - extent : tuple - min and max grid coordinates - - """ - xmin = self.verts[:, 0].min() - xmax = self.verts[:, 0].max() - ymin = self.verts[:, 1].min() - ymax = self.verts[:, 1].max() - return (xmin, xmax, ymin, ymax) - - def get_xcenter_array(self): - """ - Return a numpy one-dimensional float array that has the cell center x - coordinate for every cell in the grid in model space - not offset or - rotated. - - """ - return self.xc - - def get_ycenter_array(self): - """ - Return a numpy one-dimensional float array that has the cell center x - coordinate for every cell in the grid in model space - not offset of - rotated. - - """ - return self.yc - - def plot_array(self, a, ax=None): - """ - Create a QuadMesh plot of the specified array using patches - - Parameters - ---------- - a : np.ndarray - - Returns - ------- - pc : matplotlib.collections.PatchCollection - - """ - from ..plot import ModelMap - - pmv = ModelMap(sr=self, ax=ax) - pc = pmv.plot_array(a) - - return pc - - def get_grid_line_collection(self, **kwargs): - """ - Get a patch collection of the grid - - """ - from ..plot import ModelMap - - ax = kwargs.pop("ax", None) - pmv = ModelMap(sr=self, ax=ax) - pc = pmv.plot_grid(**kwargs) - return pc - - def contour_array(self, ax, a, **kwargs): - """ - Create a QuadMesh plot of the specified array using pcolormesh - - Parameters - ---------- - ax : matplotlib.axes.Axes - ax to add the contours - - a : np.ndarray - array to contour - - Returns - ------- - contour_set : ContourSet - - """ - contour_set = ax.tricontour(self.xcenter, self.ycenter, a, **kwargs) - return contour_set - class TemporalReference: """ @@ -1979,431 +32,3 @@ def __init__(self, itmuni=4, start_datetime=None): @property def model_time_units(self): return self.itmuni_text[self.itmuni] - - -class epsgRef: - """ - Sets up a local database of text representations of coordinate reference - systems, keyed by EPSG code. - - The database is epsgref.json, located in the user's data directory. If - optional 'appdirs' package is available, this is in the platform-dependent - user directory, otherwise in the user's 'HOME/.flopy' directory. - - .. deprecated:: 3.2.11 - This class will be removed in version 3.3.5. - """ - - def __init__(self): - warnings.warn( - "epsgRef has been deprecated and will be removed in version " - "3.3.5.", - category=DeprecationWarning, - ) - try: - from appdirs import user_data_dir - except ImportError: - user_data_dir = None - if user_data_dir: - datadir = user_data_dir("flopy") - else: - # if appdirs is not installed, use user's home directory - datadir = os.path.join(os.path.expanduser("~"), ".flopy") - if not os.path.isdir(datadir): - os.makedirs(datadir) - dbname = "epsgref.json" - self.location = os.path.join(datadir, dbname) - - def to_dict(self): - """ - Returns dict with EPSG code integer key, and WKT CRS text - """ - data = OrderedDict() - if os.path.exists(self.location): - with open(self.location, "r") as f: - loaded_data = json.load(f, object_pairs_hook=OrderedDict) - # convert JSON key from str to EPSG integer - for key, value in loaded_data.items(): - try: - data[int(key)] = value - except ValueError: - data[key] = value - return data - - def _write(self, data): - with open(self.location, "w") as f: - json.dump(data, f, indent=0) - f.write("\n") - - def reset(self, verbose=True): - if os.path.exists(self.location): - os.remove(self.location) - if verbose: - print("Resetting {}".format(self.location)) - - def add(self, epsg, prj): - """ - add an epsg code to epsgref.json - """ - data = self.to_dict() - data[epsg] = prj - self._write(data) - - def get(self, epsg): - """ - returns prj from a epsg code, otherwise None if not found - """ - data = self.to_dict() - return data.get(epsg) - - def remove(self, epsg): - """ - removes an epsg entry from epsgref.json - """ - data = self.to_dict() - if epsg in data: - del data[epsg] - self._write(data) - - @staticmethod - def show(): - ep = epsgRef() - prj = ep.to_dict() - for k, v in prj.items(): - print("{}:\n{}\n".format(k, v)) - - -class crs: - """ - Container to parse and store coordinate reference system parameters, - and translate between different formats. - - .. deprecated:: 3.2.11 - This class will be removed in version 3.3.5. Use - :py:class:`flopy.export.shapefile_utils.CRS` instead. - """ - - def __init__(self, prj=None, esri_wkt=None, epsg=None): - warnings.warn( - "crs has been deprecated and will be removed in version 3.3.5. " - "Use CRS in shapefile_utils instead.", - category=DeprecationWarning, - ) - self.wktstr = None - if prj is not None: - with open(prj) as fprj: - self.wktstr = fprj.read() - elif esri_wkt is not None: - self.wktstr = esri_wkt - elif epsg is not None: - wktstr = getprj(epsg) - if wktstr is not None: - self.wktstr = wktstr - if self.wktstr is not None: - self.parse_wkt() - - @property - def crs(self): - """ - Dict mapping crs attributes to proj4 parameters - """ - proj = None - if self.projcs is not None: - # projection - if "mercator" in self.projcs.lower(): - if ( - "transverse" in self.projcs.lower() - or "tm" in self.projcs.lower() - ): - proj = "tmerc" - else: - proj = "merc" - elif ( - "utm" in self.projcs.lower() and "zone" in self.projcs.lower() - ): - proj = "utm" - elif "stateplane" in self.projcs.lower(): - proj = "lcc" - elif "lambert" and "conformal" and "conic" in self.projcs.lower(): - proj = "lcc" - elif "albers" in self.projcs.lower(): - proj = "aea" - elif self.projcs is None and self.geogcs is not None: - proj = "longlat" - - # datum - datum = None - if ( - "NAD" in self.datum.lower() - or "north" in self.datum.lower() - and "america" in self.datum.lower() - ): - datum = "nad" - if "83" in self.datum.lower(): - datum += "83" - elif "27" in self.datum.lower(): - datum += "27" - elif "84" in self.datum.lower(): - datum = "wgs84" - - # ellipse - ellps = None - if "1866" in self.spheroid_name: - ellps = "clrk66" - elif "grs" in self.spheroid_name.lower(): - ellps = "grs80" - elif "wgs" in self.spheroid_name.lower(): - ellps = "wgs84" - - # prime meridian - pm = self.primem[0].lower() - - return { - "proj": proj, - "datum": datum, - "ellps": ellps, - "a": self.semi_major_axis, - "rf": self.inverse_flattening, - "lat_0": self.latitude_of_origin, - "lat_1": self.standard_parallel_1, - "lat_2": self.standard_parallel_2, - "lon_0": self.central_meridian, - "k_0": self.scale_factor, - "x_0": self.false_easting, - "y_0": self.false_northing, - "units": self.projcs_unit, - "zone": self.utm_zone, - } - - @property - def grid_mapping_attribs(self): - """ - Map parameters for CF Grid Mappings - http://http://cfconventions.org/cf-conventions/cf-conventions.html, - Appendix F: Grid Mappings - """ - if self.wktstr is not None: - sp = [ - p - for p in [self.standard_parallel_1, self.standard_parallel_2] - if p is not None - ] - sp = sp if len(sp) > 0 else None - proj = self.crs["proj"] - names = { - "aea": "albers_conical_equal_area", - "aeqd": "azimuthal_equidistant", - "laea": "lambert_azimuthal_equal_area", - "longlat": "latitude_longitude", - "lcc": "lambert_conformal_conic", - "merc": "mercator", - "tmerc": "transverse_mercator", - "utm": "transverse_mercator", - } - attribs = { - "grid_mapping_name": names[proj], - "semi_major_axis": self.crs["a"], - "inverse_flattening": self.crs["rf"], - "standard_parallel": sp, - "longitude_of_central_meridian": self.crs["lon_0"], - "latitude_of_projection_origin": self.crs["lat_0"], - "scale_factor_at_projection_origin": self.crs["k_0"], - "false_easting": self.crs["x_0"], - "false_northing": self.crs["y_0"], - } - return {k: v for k, v in attribs.items() if v is not None} - - @property - def proj4(self): - """ - Not implemented yet - """ - return None - - def parse_wkt(self): - - self.projcs = self._gettxt('PROJCS["', '"') - self.utm_zone = None - if self.projcs is not None and "utm" in self.projcs.lower(): - self.utm_zone = self.projcs[-3:].lower().strip("n").strip("s") - self.geogcs = self._gettxt('GEOGCS["', '"') - self.datum = self._gettxt('DATUM["', '"') - tmp = self._getgcsparam("SPHEROID") - self.spheroid_name = tmp.pop(0) - self.semi_major_axis = tmp.pop(0) - self.inverse_flattening = tmp.pop(0) - self.primem = self._getgcsparam("PRIMEM") - self.gcs_unit = self._getgcsparam("UNIT") - self.projection = self._gettxt('PROJECTION["', '"') - self.latitude_of_origin = self._getvalue("latitude_of_origin") - self.central_meridian = self._getvalue("central_meridian") - self.standard_parallel_1 = self._getvalue("standard_parallel_1") - self.standard_parallel_2 = self._getvalue("standard_parallel_2") - self.scale_factor = self._getvalue("scale_factor") - self.false_easting = self._getvalue("false_easting") - self.false_northing = self._getvalue("false_northing") - self.projcs_unit = self._getprojcs_unit() - - def _gettxt(self, s1, s2): - s = self.wktstr.lower() - strt = s.find(s1.lower()) - if strt >= 0: # -1 indicates not found - strt += len(s1) - end = s[strt:].find(s2.lower()) + strt - return self.wktstr[strt:end] - - def _getvalue(self, k): - s = self.wktstr.lower() - strt = s.find(k.lower()) - if strt >= 0: - strt += len(k) - end = s[strt:].find("]") + strt - try: - return float(self.wktstr[strt:end].split(",")[1]) - except: - print(" could not typecast wktstr to a float") - - def _getgcsparam(self, txt): - nvalues = 3 if txt.lower() == "spheroid" else 2 - tmp = self._gettxt('{}["'.format(txt), "]") - if tmp is not None: - tmp = tmp.replace('"', "").split(",") - name = tmp[0:1] - values = list(map(float, tmp[1:nvalues])) - return name + values - else: - return [None] * nvalues - - def _getprojcs_unit(self): - if self.projcs is not None: - tmp = self.wktstr.lower().split('unit["')[-1] - uname, ufactor = tmp.strip().strip("]").split('",')[0:2] - ufactor = float(ufactor.split("]")[0].split()[0].split(",")[0]) - return uname, ufactor - return None, None - - -def getprj(epsg, addlocalreference=True, text="esriwkt"): - """ - Gets projection file (.prj) text for given epsg code from - spatialreference.org - - .. deprecated:: 3.2.11 - This function will be removed in version 3.3.5. Use - :py:class:`flopy.discretization.structuredgrid.StructuredGrid` instead. - - Parameters - ---------- - epsg : int - epsg code for coordinate system - addlocalreference : boolean - adds the projection file text associated with epsg to a local - database, epsgref.json, located in the user's data directory. - - References - ---------- - https://www.epsg-registry.org/ - - Returns - ------- - prj : str - text for a projection (*.prj) file. - - """ - warnings.warn( - "SpatialReference has been deprecated and will be removed in version " - "3.3.5. Use StructuredGrid instead.", - category=DeprecationWarning, - ) - epsgfile = epsgRef() - wktstr = epsgfile.get(epsg) - if wktstr is None: - wktstr = get_spatialreference(epsg, text=text) - if addlocalreference and wktstr is not None: - epsgfile.add(epsg, wktstr) - return wktstr - - -def get_spatialreference(epsg, text="esriwkt"): - """ - Gets text for given epsg code and text format from spatialreference.org - - Fetches the reference text using the url: - https://spatialreference.org/ref/epsg/// - - See: https://www.epsg-registry.org/ - - .. deprecated:: 3.2.11 - This function will be removed in version 3.3.5. Use - :py:class:`flopy.discretization.structuredgrid.StructuredGrid` instead. - - Parameters - ---------- - epsg : int - epsg code for coordinate system - text : str - string added to url - - Returns - ------- - url : str - - """ - from flopy.utils.flopy_io import get_url_text - - warnings.warn( - "SpatialReference has been deprecated and will be removed in version " - "3.3.5. Use StructuredGrid instead.", - category=DeprecationWarning, - ) - - epsg_categories = ["epsg", "esri"] - for cat in epsg_categories: - url = "{}/ref/{}/{}/{}/".format(srefhttp, cat, epsg, text) - result = get_url_text(url) - if result is not None: - break - if result is not None: - return result.replace("\n", "") - elif result is None and text != "epsg": - for cat in epsg_categories: - error_msg = ( - "No internet connection or " - + "epsg code {} ".format(epsg) - + "not found at {}/ref/".format(srefhttp) - + "{}/{}/{}".format(cat, cat, epsg) - ) - print(error_msg) - # epsg code not listed on spatialreference.org - # may still work with pyproj - elif text == "epsg": - return "epsg:{}".format(epsg) - - -def getproj4(epsg): - """ - Get projection file (.prj) text for given epsg code from - spatialreference.org. See: https://www.epsg-registry.org/ - - .. deprecated:: 3.2.11 - This function will be removed in version 3.3.5. Use - :py:class:`flopy.discretization.structuredgrid.StructuredGrid` instead. - - Parameters - ---------- - epsg : int - epsg code for coordinate system - - Returns - ------- - prj : str - text for a projection (*.prj) file. - - """ - warnings.warn( - "SpatialReference has been deprecated and will be removed in version " - "3.3.5. Use StructuredGrid instead.", - category=DeprecationWarning, - ) - - return get_spatialreference(epsg, text="proj4") diff --git a/dependencies/flopy/utils/sfroutputfile.py b/dependencies/flopy/utils/sfroutputfile.py index e2467d2..1cb50b2 100644 --- a/dependencies/flopy/utils/sfroutputfile.py +++ b/dependencies/flopy/utils/sfroutputfile.py @@ -80,9 +80,7 @@ def __init__(self, filename, geometries=None, verbose=False): break if not evaluated_format: raise ValueError( - "could not evaluate format of {!r} for SfrFile".format( - self.filename - ) + f"could not evaluate format of {self.filename!r} for SfrFile" ) # all outputs start with the same 15 columns self.names = [ @@ -259,5 +257,5 @@ def get_results(self, segment, reach): if len(srresults) > 0: results = results.append(srresults) else: - print("No results for segment {}, reach {}!".format(s, r)) + print(f"No results for segment {s}, reach {r}!") return results diff --git a/dependencies/flopy/utils/swroutputfile.py b/dependencies/flopy/utils/swroutputfile.py index 42f5ce6..fb4307a 100644 --- a/dependencies/flopy/utils/swroutputfile.py +++ b/dependencies/flopy/utils/swroutputfile.py @@ -1,6 +1,4 @@ -import sys import numpy as np -from collections import OrderedDict from ..utils.utils_def import FlopyBinaryData @@ -67,12 +65,9 @@ def __init__( if swrtype.lower() in self.types: self.type = swrtype.lower() else: - err = ( - "SWR type ({}) is not defined. ".format(type) - + "Available types are:\n" - ) + err = f"SWR type ({type}) is not defined. Available types are:\n" for t in self.types: - err = "{} {}\n".format(err, t) + err += f" {t}\n" raise Exception(err) # set data dtypes @@ -413,7 +408,7 @@ def _read_header(self): self.nitems = nitems except: if self.verbose: - sys.stdout.write("\nCould not read itemlist") + print("Could not read itemlist") return 0.0, 0.0, 0, 0, 0, False try: totim = self.read_real() @@ -600,11 +595,11 @@ def _build_index(self): """ self.file.seek(self.datastart) if self.verbose: - sys.stdout.write("Generating SWR binary data time list\n") + print("Generating SWR binary data time list") self._ntimes = 0 self._times = [] self._kswrkstpkper = [] - self.recorddict = OrderedDict() + self.recorddict = {} idx = 0 while True: @@ -614,7 +609,7 @@ def _build_index(self): if self.verbose: v = divmod(float(idx), 72.0) if v[1] == 0.0: - sys.stdout.write(".") + print(".", end="") # read header totim, dt, kper, kstp, kswr, success = self._read_header() if success: @@ -637,7 +632,7 @@ def _build_index(self): self._recordarray.append(header) else: if self.verbose: - sys.stdout.write("\n") + print() self._recordarray = np.array( self._recordarray, dtype=self.header_dtype ) diff --git a/dependencies/flopy/utils/triangle.py b/dependencies/flopy/utils/triangle.py index 5bb0156..181d553 100644 --- a/dependencies/flopy/utils/triangle.py +++ b/dependencies/flopy/utils/triangle.py @@ -151,21 +151,21 @@ def build(self, verbose=False): self.clean() # write the active domain to a file - fname = os.path.join(self.model_ws, self.file_prefix + ".0.node") + fname = os.path.join(self.model_ws, f"{self.file_prefix}.0.node") self._write_nodefile(fname) # poly file - fname = os.path.join(self.model_ws, self.file_prefix + ".0.poly") + fname = os.path.join(self.model_ws, f"{self.file_prefix}.0.poly") self._write_polyfile(fname) # Construct the triangle command cmds = [self.exe_name] if self.maximum_area is not None: - cmds.append("-a{}".format(self.maximum_area)) + cmds.append(f"-a{self.maximum_area}") else: cmds.append("-a") if self.angle is not None: - cmds.append("-q{}".format(self.angle)) + cmds.append(f"-q{self.angle}") if self.additional_args is not None: cmds += self.additional_args cmds.append("-A") # assign attributes @@ -174,7 +174,7 @@ def build(self, verbose=False): cmds.append("-D") # delaunay triangles for finite volume cmds.append("-e") # edge file cmds.append("-n") # neighbor file - cmds.append(self.file_prefix + ".0") # output file name + cmds.append(f"{self.file_prefix}.0") # output file name # run Triangle buff = subprocess.check_output(cmds, cwd=self.model_ws) @@ -205,7 +205,7 @@ def plot( cmap="Dark2", a=None, masked_values=None, - **kwargs + **kwargs, ): """ Plot the grid. This method will plot the grid using the shapefile @@ -262,7 +262,7 @@ def plot( masked_values=masked_values, cmap=cmap, edgecolor=edgecolor, - **kwargs + **kwargs, ) return pc @@ -310,11 +310,9 @@ def plot_boundary(self, ibm, ax=None, **kwargs): try: import matplotlib.pyplot as plt except: - err_msg = ( - "matplotlib must be installed to " - + "use triangle.plot_boundary()" + raise ImportError( + "matplotlib must be installed to use triangle.plot_boundary()" ) - raise ImportError(err_msg) if ax is None: ax = plt.gca() idx = np.where(self.edge["boundary_marker"] == ibm)[0] @@ -348,11 +346,9 @@ def plot_vertices(self, ax=None, **kwargs): try: import matplotlib.pyplot as plt except: - err_msg = ( - "matplotlib must be installed to " - + "use triangle.plot_vertices()" + raise ImportError( + "matplotlib must be installed to use triangle.plot_vertices()" ) - raise ImportError(err_msg) if ax is None: ax = plt.gca() ax.plot(self.node["x"], self.node["y"], lw=0, **kwargs) @@ -382,11 +378,9 @@ def label_vertices(self, ax=None, onebased=True, **kwargs): try: import matplotlib.pyplot as plt except: - err_msg = ( - "matplotlib must be installed to " - + "use triangle.label_vertices()" + raise ImportError( + "matplotlib must be installed to use triangle.label_vertices()" ) - raise ImportError(err_msg) if ax is None: ax = plt.gca() for i in range(self.verts.shape[0]): @@ -395,8 +389,7 @@ def label_vertices(self, ax=None, onebased=True, **kwargs): s = i if onebased: s += 1 - s = "{}".format(s) - ax.text(x, y, s, **kwargs) + ax.text(x, y, str(s), **kwargs) return def plot_centroids(self, ax=None, **kwargs): @@ -419,11 +412,9 @@ def plot_centroids(self, ax=None, **kwargs): try: import matplotlib.pyplot as plt except: - err_msg = ( - "matplotlib must be installed to " - + "use triangle.plot_centroids()" + raise ImportError( + "matplotlib must be installed to use triangle.plot_centroids()" ) - raise ImportError(err_msg) if ax is None: ax = plt.gca() @@ -455,11 +446,9 @@ def label_cells(self, ax=None, onebased=True, **kwargs): try: import matplotlib.pyplot as plt except: - err_msg = ( - "matplotlib must be installed to " - + "use triangle.lavel_cells()" + raise ImportError( + "matplotlib must be installed to use triangle.lavel_cells()" ) - raise ImportError(err_msg) if ax is None: ax = plt.gca() xcyc = self.get_xcyc() @@ -469,8 +458,7 @@ def label_cells(self, ax=None, onebased=True, **kwargs): s = i if onebased: s += 1 - s = "{}".format(s) - ax.text(x, y, s, **kwargs) + ax.text(x, y, str(s), **kwargs) return def get_xcyc(self): @@ -629,18 +617,18 @@ def clean(self): """ # remove input files for ext in ["poly", "node"]: - fname = os.path.join(self.model_ws, self.file_prefix + "0." + ext) + fname = os.path.join(self.model_ws, f"{self.file_prefix}0.{ext}") if os.path.isfile(fname): os.remove(fname) if os.path.isfile(fname): - print("Could not remove: {}".format(fname)) + print(f"Could not remove: {fname}") # remove output files for ext in ["poly", "ele", "node", "neigh", "edge"]: - fname = os.path.join(self.model_ws, self.file_prefix + "1." + ext) + fname = os.path.join(self.model_ws, f"{self.file_prefix}1.{ext}") if os.path.isfile(fname): os.remove(fname) if os.path.isfile(fname): - print("Could not remove: {}".format(fname)) + print(f"Could not remove: {fname}") return def _initialize_vars(self): @@ -661,7 +649,7 @@ def _load_results(self): # node file ext = "node" dt = [("ivert", int), ("x", float), ("y", float)] - fname = os.path.join(self.model_ws, self.file_prefix + ".1." + ext) + fname = os.path.join(self.model_ws, f"{self.file_prefix}.1.{ext}") setattr(self, ext, None) if os.path.isfile(fname): f = open(fname, "r") @@ -684,7 +672,7 @@ def _load_results(self): # ele file ext = "ele" dt = [("icell", int), ("iv1", int), ("iv2", int), ("iv3", int)] - fname = os.path.join(self.model_ws, self.file_prefix + ".1." + ext) + fname = os.path.join(self.model_ws, f"{self.file_prefix}.1.{ext}") setattr(self, ext, None) if os.path.isfile(fname): f = open(fname, "r") @@ -704,7 +692,7 @@ def _load_results(self): # edge file ext = "edge" dt = [("iedge", int), ("endpoint1", int), ("endpoint2", int)] - fname = os.path.join(self.model_ws, self.file_prefix + ".1." + ext) + fname = os.path.join(self.model_ws, f"{self.file_prefix}.1.{ext}") setattr(self, ext, None) if os.path.isfile(fname): f = open(fname, "r") @@ -727,7 +715,7 @@ def _load_results(self): ("neighbor2", int), ("neighbor3", int), ] - fname = os.path.join(self.model_ws, self.file_prefix + ".1." + ext) + fname = os.path.join(self.model_ws, f"{self.file_prefix}.1.{ext}") setattr(self, ext, None) if os.path.isfile(fname): f = open(fname, "r") @@ -750,19 +738,17 @@ def _write_nodefile(self, fname): nvert += len(p) if self._nodes is not None: nvert += self._nodes.shape[0] - s = "{} {} {} {}\n".format(nvert, 2, 0, 0) + s = f"{nvert} 2 0 0\n" f.write(s) ip = 0 for p in self._polygons: for vertex in p: - s = "{} {} {}\n".format(ip, vertex[0], vertex[1]) + s = f"{ip} {vertex[0]} {vertex[1]}\n" f.write(s) ip += 1 if self._nodes is not None: for i in range(self._nodes.shape[0]): - s = "{} {} {}\n".format( - ip, self._nodes[i, 0], self._nodes[i, 1] - ) + s = f"{ip} {self._nodes[i, 0]} {self._nodes[i, 1]}\n" f.write(s) ip += 1 f.close() @@ -779,7 +765,7 @@ def _write_polyfile(self, fname): for p in self._polygons: nseg += len(p) bm = 1 - s = "{} {}\n".format(nseg, bm) + s = f"{nseg} {bm}\n" f.write(s) iseg = 0 @@ -793,22 +779,22 @@ def _write_polyfile(self, fname): ep2 = 0 ep1 += ipstart ep2 += ipstart - s = "{} {} {} {}\n".format(iseg, ep1, ep2, iseg + 1) + s = f"{iseg} {ep1} {ep2} {iseg + 1}\n" f.write(s) iseg += 1 ipstart += len(p) # holes nholes = len(self._holes) - s = "{}\n".format(nholes) + s = f"{nholes}\n" f.write(s) for i, hole in enumerate(self._holes): - s = "{} {} {}\n".format(i, hole[0], hole[1]) + s = f"{i} {hole[0]} {hole[1]}\n" f.write(s) # regions nregions = len(self._regions) - s = "{}\n".format(nregions) + s = f"{nregions}\n" f.write(s) for i, region in enumerate(self._regions): pt = region[0] @@ -816,7 +802,7 @@ def _write_polyfile(self, fname): maxarea = region[2] if maxarea is None: maxarea = -1.0 - s = "{} {} {} {} {}\n".format(i, pt[0], pt[1], attribute, maxarea) + s = f"{i} {pt[0]} {pt[1]} {attribute} {maxarea}\n" f.write(s) f.close() diff --git a/dependencies/flopy/utils/util_array.py b/dependencies/flopy/utils/util_array.py index 2eefc90..7112747 100644 --- a/dependencies/flopy/utils/util_array.py +++ b/dependencies/flopy/utils/util_array.py @@ -5,8 +5,6 @@ instantiate these classes directly. """ -from __future__ import division, print_function - # from future.utils import with_metaclass import os @@ -78,7 +76,7 @@ def __init__(self, u2d, python=None, fortran=None, array_free_format=None): assert isinstance( u2d, Util2d - ), "ArrayFormat only supports Util2d," + "not {0}".format(type(u2d)) + ), f"ArrayFormat only supports Util2d, not {type(u2d)}" if len(u2d.shape) == 1: self._npl_full = u2d.shape[0] else: @@ -107,8 +105,8 @@ def __init__(self, u2d, python=None, fortran=None, array_free_format=None): if python is not None and fortran is not None: raise Exception( - "only one of [python,fortran] can be passed" - + "to ArrayFormat constructor" + "only one of [python,fortran] can be passed " + "to ArrayFormat constructor" ) if python is not None: @@ -139,14 +137,14 @@ def _set_defaults(self): else: raise Exception( "ArrayFormat._set_defaults() error: " - + "unsupported dtype: {0}".format(str(self.dtype)) + "unsupported dtype: {0}".format(str(self.dtype)) ) def __str__(self): s = "ArrayFormat: npl:{0},format:{1},width:{2},decimal{3}".format( self.npl, self.format, self.width, self.decimal ) - s += ",isfree:{0},isbinary:{1}".format(self._isfree, self._isbinary) + s += f",isfree:{self._isfree},isbinary:{self._isbinary}" return s @staticmethod @@ -158,7 +156,7 @@ def get_default_numpy_fmt(dtype): else: raise Exception( "ArrayFormat.get_default_numpy_fmt(): unrecognized " - + "dtype, must be np.int32 or np.float32" + "dtype, must be np.int32 or np.float32" ) @classmethod @@ -225,7 +223,7 @@ def __setattr__(self, key, value): elif self.dtype == np.float32 and width < self.default_float_width: print( "ArrayFormat warning:setting width less " - + "than default of {0}".format(self.default_float_width) + "than default of {0}".format(self.default_float_width) ) self._width = width elif key == "decimal": @@ -235,15 +233,14 @@ def __setattr__(self, key, value): value = int(value) if value < self.default_float_decimal: print( - "ArrayFormat warning: setting decimal " - + " less than default of " - + "{0}".format(self.default_float_decimal) + "ArrayFormat warning: setting decimal less than " + "default of {0}".format(self.default_float_decimal) ) if value < self.decimal: print( "ArrayFormat warning: setting decimal " - + " less than current value of " - + "{0}".format(self.default_float_decimal) + "less than current value of " + "{0}".format(self.default_float_decimal) ) self._decimal = int(value) else: @@ -301,7 +298,7 @@ def _get_python_format(self): else: raise Exception( "ArrayFormat._get_python_format() error: " - + "format is not 'free' and npl is not set" + "format is not 'free' and npl is not set" ) return (self.npl, pd) @@ -319,9 +316,9 @@ def _get_fortran_format(self): if self._isbinary: return "(BINARY)" - fd = "({0:d}{1:s}{2:d}".format(self.npl, self.format, self.width) + fd = f"({self.npl}{self.format}{self.width}" if self.decimal is not None: - fd += ".{0:d})".format(self.decimal) + fd += f".{self.decimal})" else: fd += ")" return fd @@ -362,7 +359,7 @@ def numpy(self): return self._get_numpy_format() def _get_numpy_format(self): - return "%{0}{1}.{2}".format(self.width, self.format, self.decimal) + return f"%{self.width}{self.format}.{self.decimal}" @staticmethod def decode_fortran_descriptor(fd): @@ -412,12 +409,7 @@ def decode_fortran_descriptor(fd): elif fmt == "EN": fmt = "E" return npl, fmt, width, decimal - raise Exception( - "Unrecognized format type: " - + str(fd) - + " looking for: " - + str(fmts) - ) + raise Exception(f"Unrecognized format type: {fd} looking for: {fmts}") def read1d(f, a): @@ -428,7 +420,7 @@ def read1d(f, a): """ if len(a.shape) != 1: raise ValueError( - "read1d: expected 1 dimension, found shape {0}".format(a.shape) + f"read1d: expected 1 dimension, found shape {a.shape}" ) values = [] while len(values) < a.shape[0]: @@ -561,7 +553,7 @@ def __init__( return if len(shape) != 3: raise ValueError( - "Util3d: expected 3 dimensions, found shape {0}".format(shape) + f"Util3d: expected 3 dimensions, found shape {shape}" ) self._model = model self.shape = shape @@ -584,7 +576,7 @@ def __init__( self.name_base.append(self.name[k]) else: if "Layer" not in self.name[k]: - self.name_base.append(self.name[k] + " Layer ") + self.name_base.append(f"{self.name[k]} Layer ") else: self.name_base.append(self.name[k]) self.fmtin = fmtin @@ -617,7 +609,7 @@ def __setitem__(self, k, value): self.util_2ds[k] = new_u2d(self.util_2ds[k], value) else: raise NotImplementedError( - "Util3d doesn't support setitem indices" + str(k) + f"Util3d doesn't support setitem indices: {k}" ) def __setattr__(self, key, value): @@ -665,45 +657,13 @@ def export(self, f, **kwargs): return export.utils.array3d_export(f, self, **kwargs) - def to_shapefile(self, filename): - """ - Export 3-D model data to shapefile (polygons). Adds an - attribute for each Util2d in self.u2ds - - Parameters - ---------- - filename : str - Shapefile name to write - - Returns - ---------- - None - - See Also - -------- - - Notes - ----- - - Examples - -------- - >>> import flopy - >>> ml = flopy.modflow.Modflow.load('test.nam') - >>> ml.lpf.hk.to_shapefile('test_hk.shp') - """ - warn( - "Deprecation warning: to_shapefile() is deprecated. use .export()", - DeprecationWarning, - ) - self.export(filename) - def plot( self, filename_base=None, file_extension=None, mflay=None, fignum=None, - **kwargs + **kwargs, ): """ Plot 3-D model input data @@ -774,7 +734,7 @@ def plot( file_extension=file_extension, mflay=mflay, fignum=fignum, - **kwargs + **kwargs, ) return axes @@ -786,7 +746,7 @@ def __getitem__(self, k): elif len(k) == 3: return self.array[k[0], k[1], k[2]] else: - raise Exception("Util3d error: unsupported indices:" + str(k)) + raise Exception(f"Util3d error: unsupported indices: {k}") def get_file_entry(self): s = "" @@ -838,20 +798,19 @@ def build_2d_instances(self): isinstance(self.__value, np.ndarray) and (self.__value.ndim == 1) ): - assert len(self.__value) == self.shape[0], ( - "length of 3d enumerable:" - + str(len(self.__value)) - + " != to shape[0]:" - + str(self.shape[0]) + assert ( + len(self.__value) == self.shape[0] + ), "length of 3d enumerable: {} != to shape[0]: {}".format( + len(self.__value), self.shape[0] ) for i, item in enumerate(self.__value): if isinstance(item, Util2d): # we need to reset the external name because most of the # load() methods don't use layer-specific names - item._ext_filename = self.ext_filename_base[ - i - ] + "{0}.ref".format(i + 1) + item._ext_filename = ( + f"{self.ext_filename_base[i]}{i + 1}.ref" + ) # reset the model instance in cases these Util2d's # came from another model instance item.model = self._model @@ -861,7 +820,7 @@ def build_2d_instances(self): ext_filename = None if self._model.external_path is not None: ext_filename = ( - self.ext_filename_base[i] + str(i + 1) + ".ref" + f"{self.ext_filename_base[i]}{i + 1}.ref" ) shape = self.shape[1:] if shape[0] is None: @@ -888,19 +847,15 @@ def build_2d_instances(self): else: raise Exception( "value shape[0] != to self.shape[0] and" - + "value.shape[[1,2]] != self.shape[[1,2]]" - + str(self.__value.shape) - + " " - + str(self.shape) + "value.shape[[1,2]] != self.shape[[1,2]] " + "{} {}".format(self.__value.shape, self.shape) ) for i, a in enumerate(self.__value): a = np.atleast_2d(a) ext_filename = None name = self.name_base[i] + str(i + 1) if self._model.external_path is not None: - ext_filename = ( - self.ext_filename_base[i] + str(i + 1) + ".ref" - ) + ext_filename = f"{self.ext_filename_base[i]}{i + 1}.ref" u2d = Util2d( self._model, self.shape[1:], @@ -917,8 +872,7 @@ def build_2d_instances(self): else: raise Exception( "util_array_3d: value attribute must be list " - + " or ndarray, not" - + str(type(self.__value)) + "or ndarray, not {}".format(type(self.__value)) ) return u2ds @@ -935,12 +889,12 @@ def load( ): if len(shape) != 3: raise ValueError( - "Util3d: expected 3 dimensions, found shape {0}".format(shape) + f"Util3d: expected 3 dimensions, found shape {shape}" ) nlay, nrow, ncol = shape u2ds = [] for k in range(nlay): - u2d_name = name + "_Layer_{0}".format(k) + u2d_name = f"{name}_Layer_{k}" if nrow is None: nr = 1 nc = ncol[k] @@ -1126,7 +1080,7 @@ def plottable(self): return False def get_zero_3d(self, kper): - name = self.name_base + str(kper + 1) + "(filled zero)" + name = f"{self.name_base}{kper + 1}(filled zero)" return Util3d( self._model, self.shape, @@ -1146,8 +1100,8 @@ def __getitem__(self, kper): if i in list(self.transient_3ds.keys()): return self.transient_3ds[i] raise Exception( - "Transient2d.__getitem__(): error:" - + " could not find an entry before kper {0:d}".format(kper) + "Transient2d.__getitem__(): error: " + f"could not find an entry before kper {kper}" ) def __setitem__(self, key, value): @@ -1156,13 +1110,13 @@ def __setitem__(self, key, value): except Exception as e: raise Exception( "Transient3d.__setitem__() error: " - + "'key'could not be cast to int:{0}".format(str(e)) + "'key'could not be cast to int:{0}".format(str(e)) ) nper = self._model.nper if key > self._model.nper or key < 0: raise Exception( "Transient3d.__setitem__() error: " - + "key {0} not in nper range {1}:{2}".format(key, 0, nper) + "key {0} not in nper range {1}:{2}".format(key, 0, nper) ) self.transient_3ds[key] = self.__get_3d_instance(key, value) @@ -1211,25 +1165,18 @@ def build_transient_sequence(self): key = int(key) except: raise Exception( - "Transient3d error: can't cast key: " - + str(key) - + " to kper integer" + f"Transient3d error: can't cast key: {key} to kper integer" ) if key < 0: raise Exception( - "Transient3d error: key can't be " - + " negative: " - + str(key) + f"Transient3d error: key can't be negative: {key}" ) try: u3d = self.__get_3d_instance(key, val) except Exception as e: raise Exception( - "Transient3d error building Util3d " - + " instance from value at kper: " - + str(key) - + "\n" - + str(e) + "Transient3d error building Util3d instance from " + "value at kper: {}\n{}".format(key, e) ) tran_seq[key] = u3d return tran_seq @@ -1251,20 +1198,18 @@ def build_transient_sequence(self): elif isinstance(self.__value, list): raise Exception( "Transient3d error: value cannot be a list " - + "anymore. try a dict{kper,value}" + "anymore. try a dict{kper,value}" ) else: raise Exception( - "Transient3d error: value type not " - + " recognized: " - + str(type(self.__value)) + f"Transient3d error: value type not recognized: {type(self.__value)}" ) def __get_3d_instance(self, kper, arg): """ parse an argument into a Util3d instance """ - name = "{}_period{}".format(self.name_base, kper + 1) + name = f"{self.name_base}_period{kper + 1}" u3d = Util3d( self._model, self.shape, @@ -1386,8 +1331,7 @@ def __init__( self._model = model if len(shape) != 2: raise ValueError( - "Transient2d: expected 2 dimensions (nrow, ncol), found " - "shape {0}".format(shape) + f"Transient2d: expected 2 dimensions (nrow, ncol), found shape {shape}" ) if shape[0] is None: # allow for unstructured so that ncol changes by layer @@ -1500,7 +1444,7 @@ def __setattr__(self, key, value): super().__setattr__(key, value) def get_zero_2d(self, kper): - name = self.name_base + str(kper + 1) + "(filled zero)" + name = f"{self.name_base}{kper + 1}(filled zero)" return Util2d( self._model, self.shape, @@ -1510,45 +1454,13 @@ def get_zero_2d(self, kper): array_free_format=self.array_free_format, ) - def to_shapefile(self, filename): - """ - Export transient 2D data to a shapefile (as polygons). Adds an - attribute for each unique Util2d instance in self.data - - Parameters - ---------- - filename : str - Shapefile name to write - - Returns - ---------- - None - - See Also - -------- - - Notes - ----- - - Examples - -------- - >>> import flopy - >>> ml = flopy.modflow.Modflow.load('test.nam') - >>> ml.rch.rech.as_shapefile('test_rech.shp') - """ - warn( - "Deprecation warning: to_shapefile() is deprecated. use .export()", - DeprecationWarning, - ) - self.export(filename) - def plot( self, filename_base=None, file_extension=None, kper=0, fignum=None, - **kwargs + **kwargs, ): """ Plot transient 2-D model input data @@ -1626,7 +1538,7 @@ def plot( file_extension=file_extension, kper=kper, fignum=fignum, - **kwargs + **kwargs, ) return axes @@ -1641,8 +1553,8 @@ def __getitem__(self, kper): if i in list(self.transient_2ds.keys()): return self.transient_2ds[i] raise Exception( - "Transient2d.__getitem__(): error:" - + " could not find an entry before kper {0:d}".format(kper) + "Transient2d.__getitem__(): error: " + f"could not find an entry before kper {kper}" ) def __setitem__(self, key, value): @@ -1651,13 +1563,13 @@ def __setitem__(self, key, value): except Exception as e: raise Exception( "Transient2d.__setitem__() error: " - + "'key'could not be cast to int:{0}".format(str(e)) + "'key'could not be cast to int:{0}".format(str(e)) ) nper = self._model.nper if key > self._model.nper or key < 0: raise Exception( "Transient2d.__setitem__() error: " - + "key {0} not in nper range {1}:{2}".format(key, 0, nper) + "key {0} not in nper range {1}:{2}".format(key, 0, nper) ) self.transient_2ds[key] = self.__get_2d_instance(key, value) @@ -1703,25 +1615,18 @@ def build_transient_sequence(self): key = int(key) except: raise Exception( - "Transient2d error: can't cast key: " - + str(key) - + " to kper integer" + f"Transient2d error: can't cast key: {key} to kper integer" ) if key < 0: raise Exception( - "Transient2d error: key can't be " - + " negative: " - + str(key) + f"Transient2d error: key can't be negative: {key}" ) try: u2d = self.__get_2d_instance(key, val) except Exception as e: raise Exception( - "Transient2d error building Util2d " - + " instance from value at kper: " - + str(key) - + "\n" - + str(e) + "Transient2d error building Util2d instance from " + "value at kper: {}\n{}".format(key, e) ) tran_seq[key] = u2d return tran_seq @@ -1743,13 +1648,11 @@ def build_transient_sequence(self): elif isinstance(self.__value, list): raise Exception( "Transient2d error: value cannot be a list " - + "anymore. try a dict{kper,value}" + "anymore. try a dict{kper,value}" ) else: raise Exception( - "Transient2d error: value type not " - + " recognized: " - + str(type(self.__value)) + f"Transient2d error: value type not recognized: {type(self.__value)}" ) def __get_2d_instance(self, kper, arg): @@ -1758,7 +1661,8 @@ def __get_2d_instance(self, kper, arg): """ ext_filename = None name = self.name_base + str(kper + 1) - ext_filename = self.ext_filename_base + str(kper) + ".ref" + # TODO: should ext_filename have "kper + 1" too? + ext_filename = f"{self.ext_filename_base}{kper}.ref" u2d = Util2d( self._model, self.shape, @@ -1926,13 +1830,12 @@ def __init__( if np.dtype(int).itemsize != 4: # show warning for platforms where int is not 4-bytes warn( - "Util2d: setting integer dtype from {} to int32 for array {}".format( - dtype, name - ) + f"Util2d: setting integer dtype from {dtype} to int32 " + f"for array {name}" ) dtype = np.int32 if dtype not in [np.int32, np.float32, bool]: - raise TypeError("Util2d:unsupported dtype: " + str(dtype)) + raise TypeError(f"Util2d:unsupported dtype: {dtype!s}") if name is not None: name = name.lower() @@ -2018,7 +1921,7 @@ def plot( filename_base=None, file_extension=None, fignum=None, - **kwargs + **kwargs, ): """ Plot 2-D model input data @@ -2089,7 +1992,7 @@ def plot( filename_base=filename_base, file_extension=file_extension, fignum=fignum, - **kwargs + **kwargs, ) return axes @@ -2098,38 +2001,6 @@ def export(self, f, **kwargs): return export.utils.array2d_export(f, self, **kwargs) - def to_shapefile(self, filename): - """ - Export 2-D model data to a shapefile (as polygons) of self.array - - Parameters - ---------- - filename : str - Shapefile name to write - - Returns - ---------- - None - - See Also - -------- - - Notes - ----- - - Examples - -------- - >>> import flopy - >>> ml = flopy.modflow.Modflow.load('test.nam') - >>> ml.dis.top.as_shapefile('test_top.shp') - """ - - warn( - "Deprecation warning: to_shapefile() is deprecated. use .export()", - DeprecationWarning, - ) - self.export(filename) - def set_fmtin(self, fmtin): self._format = ArrayFormat( self, @@ -2193,7 +2064,7 @@ def __getitem__(self, k): else: raise Exception( "Util2d.__getitem__() error: an integer was passed, " - + "self.shape > 1 in both dimensions" + "self.shape > 1 in both dimensions" ) else: if isinstance(k, tuple): @@ -2310,11 +2181,13 @@ def model_file_path(self): def get_constant_cr(self, value): if self.format.array_free_format: - lay_space = "{0:>27s}".format("") + lay_space = " " * 27 if self.vtype in [int, np.int32]: - lay_space = "{0:>32s}".format("") - cr = "CONSTANT " + self.format.py[1].format(value) - cr = "{0:s}{1:s}#{2:<30s}\n".format(cr, lay_space, self._name) + lay_space = " " * 32 + cr = ( + f"CONSTANT {self.format.py[1].format(value)}" + f"{lay_space}#{self._name:<30s}\n" + ) else: cr = self._get_fixed_cr(0, value=value) return cr @@ -2326,8 +2199,8 @@ def _get_fixed_cr(self, locat, value=None): if self.format.binary: if locat is None: raise Exception( - "Util2d._get_fixed_cr(): locat is None but" - + "format is binary" + "Util2d._get_fixed_cr(): locat is None but " + "format is binary" ) if not self.format.array_free_format: locat = -1 * np.abs(locat) @@ -2364,7 +2237,7 @@ def cnstnt_str(self): if isinstance(self.cnstnt, str): return self.cnstnt else: - return "{0:15.6G}".format(self.cnstnt) + return f"{self.cnstnt:15.6G}" def get_openclose_cr(self): cr = "OPEN/CLOSE {0:>30s} {1:15} {2:>10s} {3:2.0f} {4:<30s}\n".format( @@ -2403,11 +2276,7 @@ def get_file_entry(self, how=None): how = self._how if not self.format.array_free_format and self.format.free: - print( - "Util2d {0}: can't be free format...resetting".format( - self._name - ) - ) + print(f"Util2d {self._name}: can't be free format...resetting") self.format._isfree = False if ( @@ -2416,10 +2285,9 @@ def get_file_entry(self, how=None): and self.locat is None ): print( - "Util2d {0}: locat is None, but ".format(self._name) - + "model does not " - + "support free format and how is internal..." - + "resetting how = external" + "Util2d {0}: locat is None, but model does not " + "support free format and how is internal... " + "resetting how = external".format(self._name) ) how = "external" @@ -2427,26 +2295,23 @@ def get_file_entry(self, how=None): "constant", "internal", ]: - print( - "Util2d:{0}: ".format(self._name) - + "resetting 'how' to external" - ) + print(f"Util2d:{self._name}: resetting 'how' to external") if self.format.array_free_format: how = "openclose" else: how = "external" if how == "internal": - assert not self.format.binary, ( - "Util2d error: 'how' is internal, but" + "format is binary" - ) + assert ( + not self.format.binary + ), "Util2d error: 'how' is internal, but format is binary" cr = self.get_internal_cr() return cr + self.string elif how == "external" or how == "openclose": if how == "openclose": assert self.format.array_free_format, ( - "Util2d error: 'how' is openclose," - + "but model doesn't support free fmt" + "Util2d error: 'how' is openclose, " + "but model doesn't support free fmt" ) # write a file if needed @@ -2472,7 +2337,7 @@ def get_file_entry(self, how=None): if self._model.verbose: print( "Util2d warning: removing existing array " - + "file {0}".format(self.model_file_path) + "file {0}".format(self.model_file_path) ) try: os.remove(self.python_file_path) @@ -2487,7 +2352,7 @@ def get_file_entry(self, how=None): except Exception as e: raise Exception( "Util2d.get_file_array(): error copying " - + "{0} to {1}:{2}".format( + "{0} to {1}:{2}".format( self.__value, self.python_file_path, str(e) ) ) @@ -2499,10 +2364,9 @@ def get_file_entry(self, how=None): elif how == "constant": if self.vtype not in [np.int32, np.float32]: u = np.unique(self._array) - assert u.shape[0] == 1, ( - "Util2d error: 'how' is constant, but array " - + "is not uniform" - ) + assert ( + u.shape[0] == 1 + ), "Util2d error: 'how' is constant, but array is not uniform" value = u[0] else: value = self.__value @@ -2510,8 +2374,7 @@ def get_file_entry(self, how=None): else: raise Exception( - "Util2d.get_file_entry() error: " - + "unrecognized 'how':{0}".format(how) + f"Util2d.get_file_entry() error: unrecognized 'how':{how}" ) @property @@ -2548,7 +2411,7 @@ def array(self): """ if isinstance(self.cnstnt, str): - print("WARNING: cnstnt is str for {0}".format(self.name)) + print(f"WARNING: cnstnt is str for {self.name}") return self._array.astype(self.dtype) if isinstance(self.cnstnt, (int, np.int32)): cnstnt = self.cnstnt @@ -2613,9 +2476,7 @@ def load_block(shape, file_in, dtype): """ if len(shape) != 2: raise ValueError( - "Util2d.load_block(): expected 2 dimensions, found shape {0}".format( - shape - ) + f"Util2d.load_block(): expected 2 dimensions, found shape {shape}" ) nrow, ncol = shape data = np.ma.zeros(shape, dtype=dtype) @@ -2630,8 +2491,7 @@ def load_block(shape, file_in, dtype): raw = line.split() if len(raw) < 5: raise ValueError( - "Util2d.load_block(): expected 5 items, " - "found {0}: {1}".format(len(raw), line) + f"Util2d.load_block(): expected 5 items, found {len(raw)}: {line}" ) i1, i2 = int(raw[0]) - 1, int(raw[1]) j1, j2 = int(raw[2]) - 1, int(raw[3]) @@ -2672,9 +2532,7 @@ def load_txt(shape, file_in, dtype, fmtin): num_items = nrow * ncol else: raise ValueError( - "Util2d.load_txt(): expected 1 or 2 dimensions, found shape {0}".format( - shape - ) + f"Util2d.load_txt(): expected 1 or 2 dimensions, found shape {shape}" ) openfile = not hasattr(file_in, "read") if openfile: @@ -2765,11 +2623,9 @@ def array2string(shape, data, fortran_format="(FREE)", python_format=None): decimal, ) = ArrayFormat.decode_fortran_descriptor(fortran_format) if decimal is None: - output_fmt = "{0}0:{1}{2}{3}".format("{", width, "d", "}") + output_fmt = f"{{0:{width}d}}" else: - output_fmt = "{0}0:{1}.{2}{3}{4}".format( - "{", width, decimal, fmt, "}" - ) + output_fmt = f"{{0:{width}.{decimal}{fmt}}}" else: try: column_length, output_fmt = ( @@ -2778,11 +2634,11 @@ def array2string(shape, data, fortran_format="(FREE)", python_format=None): ) except: raise Exception( - "Util2d.write_txt: \nunable to parse" - + "python_format:\n {0}\n".format(python_format) - + " python_format should be a list with\n" - + " [column_length, fmt]\n" - + " e.g., [10, {0:10.2e}]" + "Util2d.write_txt: \nunable to parse " + "python_format:\n {0}\n" + " python_format should be a list with\n" + " [column_length, fmt]\n" + " e.g., [10, {0:10.2e}]".format(python_format) ) # write the array to a string len_data = data.size @@ -2831,11 +2687,7 @@ def load_bin(shape, file_in, dtype, bintype=None): dtype = np.dtype(dtype) if dtype.itemsize != 4: # show warning for platforms where int is not 4-bytes - warn( - "Util2d: setting integer dtype from {0} to int32".format( - dtype - ) - ) + warn(f"Util2d: setting integer dtype from {dtype} to int32") dtype = np.int32 openfile = not hasattr(file_in, "read") if openfile: @@ -2884,14 +2736,11 @@ def parse_value(self, value): except: raise Exception( - "Util2d:could not cast " - + 'boolean value to type "bool": ' - + str(value) + f'Util2d:could not cast boolean value to type "bool": {value}' ) else: raise Exception( - "Util2d:value type is bool, " - + " but dtype not set as bool" + "Util2d:value type is bool, but dtype not set as bool" ) elif isinstance(value, str): if os.path.exists(value): @@ -2903,7 +2752,7 @@ def parse_value(self, value): except: raise Exception( "Util2d error: str not a file and " - + "couldn't be cast to int: {0}".format(value) + "couldn't be cast to int: {0}".format(value) ) else: @@ -2912,7 +2761,7 @@ def parse_value(self, value): except: raise Exception( "Util2d error: str not a file and " - + "couldn't be cast to float: {0}".format(value) + "couldn't be cast to float: {0}".format(value) ) elif np.isscalar(value): @@ -2921,18 +2770,14 @@ def parse_value(self, value): self.__value = np.int32(value) except: raise Exception( - "Util2d:could not cast scalar " - + 'value to type "int": ' - + str(value) + f'Util2d:could not cast scalar value to type "int": {value}' ) elif self._dtype == np.float32: try: self.__value = np.float32(value) except: raise Exception( - "Util2d:could not cast " - + 'scalar value to type "float": ' - + str(value) + f'Util2d:could not cast scalar value to type "float": {value}' ) elif isinstance(value, np.ndarray): @@ -2942,10 +2787,8 @@ def parse_value(self, value): value = value[0] if self.shape != value.shape: raise Exception( - "Util2d:self.shape: " - + str(self.shape) - + " does not match value.shape: " - + str(value.shape) + "Util2d:self.shape: {} does not match value.shape: " + "{}".format(self.shape, value.shape) ) if self._dtype != value.dtype: value = value.astype(self._dtype) @@ -2953,7 +2796,7 @@ def parse_value(self, value): else: raise Exception( - "Util2d:unsupported type in util_array: " + str(type(value)) + f"Util2d:unsupported type in util_array: {type(value)}" ) @classmethod @@ -3024,12 +2867,9 @@ def load( fname = fname.replace("\\", os.path.sep) fname = os.path.join(model.model_ws, fname) # load_txt(shape, file_in, dtype, fmtin): - assert os.path.exists(fname), ( - "Util2d.load() error: open/close " - + "file " - + str(fname) - + " not found" - ) + assert os.path.exists( + fname + ), f"Util2d.load() error: open/close file {fname} not found" if str("binary") not in str(cr_dict["fmtin"].lower()): f = open(fname, "r") data = Util2d.load_txt( @@ -3071,10 +2911,9 @@ def load( elif cr_dict["type"] == "external": ext_unit = ext_unit_dict[cr_dict["nunit"]] if ext_unit.filehandle is None: - raise IOError( - "cannot read unit {0}, filename: {1}".format( - cr_dict["nunit"], ext_unit.filename - ) + raise OSError( + f"cannot read unit {cr_dict['nunit']}, " + f"filename: {ext_unit.filename}" ) elif "binary" not in str(cr_dict["fmtin"].lower()): assert cr_dict["nunit"] in list(ext_unit_dict.keys()) @@ -3163,8 +3002,7 @@ def parse_control_record( fname = ext_unit_dict[int(raw[1])].filename.strip() except: print( - " could not determine filename " - + "for unit {}".format(raw[1]) + f" could not determine filename for unit {raw[1]}" ) nunit = int(raw[1]) diff --git a/dependencies/flopy/utils/util_list.py b/dependencies/flopy/utils/util_list.py index b9f1bca..209afc9 100644 --- a/dependencies/flopy/utils/util_list.py +++ b/dependencies/flopy/utils/util_list.py @@ -7,21 +7,12 @@ some more info """ -from __future__ import division, print_function - import os import warnings import numpy as np from ..datbase import DataInterface, DataListInterface, DataType from ..utils.recarray_utils import create_empty_recarray -try: - from numpy.lib import NumpyVersion - - numpy114 = NumpyVersion(np.__version__) >= "1.14.0" -except ImportError: - numpy114 = False - class MfList(DataInterface, DataListInterface): """ @@ -153,10 +144,7 @@ def append(self, other): model=self._model, list_free_format=self.list_free_format, ) - msg = ( - "MfList.append(): other arg must be " - + "MfList or dict, not {0}".format(type(other)) - ) + msg = f"MfList.append(): other arg must be MfList or dict, not {type(other)}" assert isinstance(other, MfList), msg other_kpers = list(other.data.keys()) @@ -281,11 +269,7 @@ def fmt_string(self): fmts.append("%10d") elif vtype == "f": if use_free: - if numpy114: - # Use numpy's floating-point formatter (Dragon4) - fmts.append("%15s") - else: - fmts.append("%15.7E") + fmts.append("%15s") else: fmts.append("%10G") elif vtype == "o": @@ -302,8 +286,7 @@ def fmt_string(self): raise TypeError(msg) else: raise TypeError( - "MfList.fmt_string error: unknown vtype in " - "field: {}".format(field) + f"MfList.fmt_string error: unknown vtype in field: {field}" ) if use_free: fmt_string = " " + " ".join(fmts) @@ -322,7 +305,7 @@ def __cast_data(self, data): data = np.array(data) except Exception as e: raise Exception( - "MfList error: casting list to ndarray: " + str(e) + f"MfList error: casting list to ndarray: {e!s}" ) # If data is a dict, the we have to assume it is keyed on kper @@ -334,11 +317,8 @@ def __cast_data(self, data): kper = int(kper) except Exception as e: raise Exception( - "MfList error: data dict key " - + "{0:s} not integer: ".format(kper) - + str(type(kper)) - + "\n" - + str(e) + f"MfList error: data dict key {kper} not integer: " + f"{type(kper)}\n{e!s}" ) # Same as before, just try... if isinstance(d, list): @@ -348,9 +328,7 @@ def __cast_data(self, data): d = np.array(d) except Exception as e: raise Exception( - "MfList error: casting list " - + "to ndarray: " - + str(e) + f"MfList error: casting list to ndarray: {e}" ) # super hack - sick of recarrays already @@ -371,9 +349,7 @@ def __cast_data(self, data): else: raise Exception( "MfList error: unsupported data type: " - + str(type(d)) - + " at kper " - + "{0:d}".format(kper) + f"{type(d)} at kper {kper}" ) # A single recarray - same MfList for all stress periods @@ -387,16 +363,14 @@ def __cast_data(self, data): self.__cast_str(0, data) else: raise Exception( - "MfList error: unsupported data type: " + str(type(data)) + f"MfList error: unsupported data type: {type(data)}" ) def __cast_str(self, kper, d): # If d is a string, assume it is a filename and check that it exists assert os.path.exists(d), ( - "MfList error: dict filename (string) '" - + d - + "' value for " - + "kper {0:d} not found".format(kper) + f"MfList error: dict filename (string) '{d}' value for " + f"kper {kper} not found" ) self.__data[kper] = d self.__vtype[kper] = str @@ -418,11 +392,8 @@ def __cast_int(self, kper, d): def __cast_recarray(self, kper, d): assert d.dtype == self.__dtype, ( - "MfList error: recarray dtype: " - + str(d.dtype) - + " doesn't match " - + "self dtype: " - + str(self.dtype) + "MfList error: recarray dtype: {} doesn't match self dtype: " + "{}".format(d.dtype, self.dtype) ) self.__data[kper] = d self.__vtype[kper] = np.recarray @@ -431,12 +402,8 @@ def __cast_ndarray(self, kper, d): d = np.atleast_2d(d) if d.dtype != self.__dtype: assert d.shape[1] == len(self.dtype), ( - "MfList error: ndarray " - + "shape " - + str(d.shape) - + " doesn't match dtype " - + "len: " - + str(len(self.dtype)) + "MfList error: ndarray shape {} doesn't match dtype len: " + "{}".format(d.shape, len(self.dtype)) ) # warnings.warn("MfList: ndarray dtype does not match self " +\ # "dtype, trying to cast") @@ -446,7 +413,7 @@ def __cast_ndarray(self, kper, d): ) except Exception as e: raise Exception( - "MfList error: casting ndarray to recarray: " + str(e) + f"MfList error: casting ndarray to recarray: {e!s}" ) self.__vtype[kper] = np.recarray @@ -545,8 +512,8 @@ def add_record(self, kper, index, values): # The length of index + values must be equal to the number of names # in dtype assert len(index) + len(values) == len(self.dtype), ( - "MfList.add_record() error: length of index arg +" - + "length of value arg != length of self dtype" + "MfList.add_record() error: length of index arg + " + "length of value arg != length of self dtype" ) # If we already have something for this kper, then add to it if kper in list(self.__data.keys()): @@ -574,9 +541,7 @@ def add_record(self, kper, index, values): self.__data[kper][-1] = tuple(rec) except Exception as e: raise Exception( - "MfList.add_record() error: adding record to " - + "recarray: " - + str(e) + f"MfList.add_record() error: adding record to recarray: {e}" ) def __getitem__(self, kper): @@ -590,8 +555,7 @@ def __getitem__(self, kper): kper = int(kper) except Exception as e: raise Exception( - "MfList error: _getitem__() passed invalid kper index:" - + str(kper) + f"MfList error: _getitem__() passed invalid kper index: {kper}" ) if kper not in list(self.data.keys()): if kper == 0: @@ -611,7 +575,7 @@ def __getitem__(self, kper): def __setitem__(self, kper, data): if kper in list(self.__data.keys()): if self._model.verbose: - print("removing existing data for kper={}".format(kper)) + print(f"removing existing data for kper={kper}") self.data.pop(kper) # If data is a list, then all we can do is try to cast it to # an ndarray, then cast again to a recarray @@ -621,7 +585,7 @@ def __setitem__(self, kper, data): data = np.array(data) except Exception as e: raise Exception( - "MfList error: casting list to ndarray: " + str(e) + f"MfList error: casting list to ndarray: {e!s}" ) # cast data if isinstance(data, int): @@ -636,7 +600,7 @@ def __setitem__(self, kper, data): self.__cast_str(kper, data) else: raise Exception( - "MfList error: unsupported data type: " + str(type(data)) + f"MfList error: unsupported data type: {type(data)}" ) # raise NotImplementedError("MfList.__setitem__() not implemented") @@ -647,9 +611,7 @@ def __fromfile(self, f): d = np.genfromtxt(f, dtype=self.dtype) except Exception as e: raise Exception( - "MfList.__fromfile() error reading recarray " - + "from file " - + str(e) + f"MfList.__fromfile() error reading recarray from file {e!s}" ) return d @@ -673,7 +635,7 @@ def get_filenames(self): # py_filepath = '' # py_filepath = os.path.join(py_filepath, # self._model.external_path) - filename = self.package.name[0] + "_{0:04d}.dat".format(kper) + filename = f"{self.package.name[0]}_{kper:04d}.dat" filenames.append(filename) return filenames @@ -681,7 +643,7 @@ def get_filename(self, kper): ext = "dat" if self.binary: ext = "bin" - return self.package.name[0] + "_{0:04d}.{1}".format(kper, ext) + return f"{self.package.name[0]}_{kper:04d}.{ext}" @property def binary(self): @@ -692,9 +654,9 @@ def write_transient(self, f, single_per=None, forceInternal=False): # external arrays are not supported (oh hello MNW1!) # write the transient sequence described by the data dict nr, nc, nl, nper = self._model.get_nrow_ncol_nlay_nper() - assert hasattr(f, "read"), ( - "MfList.write() error: " + "f argument must be a file handle" - ) + assert hasattr( + f, "read" + ), "MfList.write() error: f argument must be a file handle" kpers = list(self.data.keys()) kpers.sort() first = kpers[0] @@ -727,11 +689,7 @@ def write_transient(self, f, single_per=None, forceInternal=False): itmp = -1 kper_vtype = int - f.write( - " {0:9d} {1:9d} # stress period {2:d}\n".format( - itmp, 0, kper + 1 - ) - ) + f.write(f" {itmp:9d} {0:9d} # stress period {kper + 1}\n") isExternal = False if ( @@ -764,7 +722,7 @@ def write_transient(self, f, single_per=None, forceInternal=False): if kper_vtype == np.recarray: name = f.name - if self.__binary or not numpy114: + if self.__binary: f.close() # switch file append mode to binary with open(name, "ab+") as f: @@ -774,16 +732,16 @@ def write_transient(self, f, single_per=None, forceInternal=False): else: self.__tofile(f, kper_data) elif kper_vtype == str: - f.write(" open/close " + kper_data) + f.write(f" open/close {kper_data}") if self.__binary: f.write(" (BINARY)") f.write("\n") def __tofile(self, f, data): # Write the recarray (data) to the file (or file handle) f - assert isinstance(data, np.recarray), ( - "MfList.__tofile() data arg " + "not a recarray" - ) + assert isinstance( + data, np.recarray + ), "MfList.__tofile() data arg not a recarray" # Add one to the kij indices lnames = [name.lower() for name in self.dtype.names] @@ -807,14 +765,13 @@ def check_kij(self): if ("k" not in names) or ("i" not in names) or ("j" not in names): warnings.warn( "MfList.check_kij(): index fieldnames 'k,i,j' " - + "not found in self.dtype names: " - + str(names) + "not found in self.dtype names: {}".format(names) ) return nr, nc, nl, nper = self._model.get_nrow_ncol_nlay_nper() if nl == 0: warnings.warn( - "MfList.check_kij(): unable to get dis info from " + "model" + "MfList.check_kij(): unable to get dis info from model" ) return for kper in list(self.data.keys()): @@ -837,9 +794,7 @@ def check_kij(self): if len(out_idx) > 0: warn_str = ( "MfList.check_kij(): warning the following " - + "indices are out of bounds in kper " - + str(kper) - + ":\n" + "indices are out of bounds in kper {}:\n".format(kper) ) for idx in out_idx: d = data[idx] @@ -917,7 +872,7 @@ def plot( filename_base=None, file_extension=None, mflay=None, - **kwargs + **kwargs, ): """ Plot stress period boundary condition (MfList) data for a specified @@ -998,7 +953,7 @@ def plot( filename_base=filename_base, file_extension=file_extension, mflay=mflay, - **kwargs + **kwargs, ) return axes @@ -1106,6 +1061,8 @@ def to_array(self, kper=0, mask=False): kper = self.__find_last_kper(kper) sarr = self.data[kper] + if isinstance(sarr, str): + sarr = self.__fromfile(sarr) if np.isscalar(sarr): # if there are no entries for this kper @@ -1243,8 +1200,7 @@ def masked4D_arrays_to_stress_period_data(dtype, m4ds): a2 = np.isnan(m4ds[key2]) if not np.array_equal(a1, a2): raise Exception( - "Transient2d error: masking not equal" - + " for {0} and {1}".format(key1, key2) + f"Transient2d error: masking not equal for {key1} and {key2}" ) sp_data = {} diff --git a/dependencies/flopy/utils/voronoi.py b/dependencies/flopy/utils/voronoi.py index d313876..2b89fa3 100644 --- a/dependencies/flopy/utils/voronoi.py +++ b/dependencies/flopy/utils/voronoi.py @@ -1,5 +1,4 @@ import numpy as np -import matplotlib.pyplot as plt from scipy.spatial import Voronoi from .cvfdutil import get_disv_gridprops @@ -282,11 +281,11 @@ def plot(self, ax=None, plot_title=True, **kwargs): axes that contains the voronoi model grid """ + import matplotlib.pyplot as plt + if ax is None: ax = plt.subplot(1, 1, 1, aspect="equal") pc = self.get_patch_collection(ax, **kwargs) if plot_title: - ax.set_title( - "ncells: {}; nverts: {}".format(self.ncpl, self.nverts) - ) + ax.set_title(f"ncells: {self.ncpl}; nverts: {self.nverts}") return ax diff --git a/dependencies/flopy/utils/zonbud.py b/dependencies/flopy/utils/zonbud.py index 587087d..f0b5cbc 100644 --- a/dependencies/flopy/utils/zonbud.py +++ b/dependencies/flopy/utils/zonbud.py @@ -2,11 +2,7 @@ import copy import numpy as np from itertools import groupby -from collections import OrderedDict from .utils_def import totim_to_datetime -import warnings - -warnings.simplefilter("once", PendingDeprecationWarning) class ZoneBudget: @@ -39,8 +35,8 @@ class ZoneBudget: Examples -------- - >>> from flopy.utils.zonbud import ZoneBudget, read_zbarray - >>> zon = read_zbarray('zone_input_file') + >>> from flopy.utils.zonbud import ZoneBudget + >>> zon = ZoneBudget.read_zone_file('zone_input_file') >>> zb = ZoneBudget('zonebudtest.cbc', zon, kstpkper=(0, 0)) >>> zb.to_csv('zonebudtest.csv') >>> zb_mgd = zb * 7.48052 / 1000000 @@ -54,7 +50,7 @@ def __init__( totim=None, aliases=None, verbose=False, - **kwargs + **kwargs, ): from .binaryfile import CellBudgetFile @@ -63,9 +59,7 @@ def __init__( elif isinstance(cbc_file, str) and os.path.isfile(cbc_file): self.cbc = CellBudgetFile(cbc_file) else: - raise Exception( - "Cannot load cell budget file: {}.".format(cbc_file) - ) + raise Exception(f"Cannot load cell budget file: {cbc_file}.") if isinstance(z, np.ndarray): assert np.issubdtype( @@ -90,12 +84,9 @@ def __init__( self.dis = self.model.dis if "dis" in kwargs.keys(): self.dis = kwargs.pop("dis") - if "sr" in kwargs.keys(): - kwargs.pop("sr") - warnings.warn("ignoring 'sr' parameter") if len(kwargs.keys()) > 0: args = ",".join(kwargs.keys()) - raise Exception("LayerFile error: unrecognized kwargs: " + args) + raise Exception(f"LayerFile error: unrecognized kwargs: {args}") # Check the shape of the cbc budget file arrays self.cbc_shape = self.cbc.get_data(idx=0, full3D=True)[0].shape @@ -109,10 +100,7 @@ def __init__( if isinstance(kstpkper, tuple): kstpkper = [kstpkper] for kk in kstpkper: - s = ( - "The specified time step/stress period " - "does not exist {}".format(kk) - ) + s = f"The specified time step/stress period does not exist {kk}" assert kk in self.cbc.get_kstpkper(), s self.kstpkper = kstpkper elif totim is not None: @@ -121,10 +109,7 @@ def __init__( elif isinstance(totim, int): totim = [float(totim)] for t in totim: - s = ( - "The specified simulation time " - "does not exist {}".format(t) - ) + s = f"The specified simulation time does not exist {t}" assert t in self.cbc.get_times(), s self.totim = totim else: @@ -153,14 +138,12 @@ def __init__( izone = np.zeros(self.cbc_shape, self.int_type) izone[:] = z[0, :, :] else: - e = "Shape of the zone array is not recognized: {}".format(z.shape) + e = f"Shape of the zone array is not recognized: {z.shape}" raise Exception(e) self.izone = izone self.allzones = np.unique(izone) - self._zonenamedict = OrderedDict( - [(z, "ZONE_{}".format(z)) for z in self.allzones] - ) + self._zonenamedict = {z: f"ZONE_{z}" for z in self.allzones} if aliases is not None: s = ( @@ -246,7 +229,7 @@ def __init__( elif self.totim is not None: for t in self.totim: if verbose: - s = "Computing the budget for time {}".format(t) + s = f"Computing the budget for time {t}" print(s) self._compute_budget(totim=t) @@ -1070,7 +1053,7 @@ def _accumulate_flow_ssst(self, recname, kstpkper, totim): else: # Should not happen raise Exception( - 'Unrecognized "imeth" for {} record: {}'.format(recname, imeth) + f'Unrecognized "imeth" for {recname} record: {imeth}' ) # Inflows @@ -1350,8 +1333,8 @@ def get_dataframes( Examples -------- - >>> from flopy.utils.zonbud import ZoneBudget, read_zbarray - >>> zon = read_zbarray('zone_input_file') + >>> from flopy.utils.zonbud import ZoneBudget + >>> zon = ZoneBudget.read_zone_file('zone_input_file') >>> zb = ZoneBudget('zonebudtest.cbc', zon, kstpkper=(0, 0)) >>> df = zb.get_dataframes() @@ -1527,9 +1510,7 @@ def read_zone_file(cls, fname): # READ EXTERNAL FILE fname = rowitems[0] if not os.path.isfile(fname): - errmsg = 'Could not find external file "{}"'.format( - fname - ) + errmsg = f'Could not find external file "{fname}"' raise Exception(errmsg) with open(fname, "r") as ext_f: ext_flines = ext_f.readlines() @@ -1546,7 +1527,7 @@ def read_zone_file(cls, fname): raise Exception(errmsg) else: # Should not get here - raise Exception("Locat not recognized: {}".format(locat)) + raise Exception(f"Locat not recognized: {locat}") # IGNORE COMPOSITE ZONES @@ -1611,9 +1592,7 @@ def write_zone_file(cls, fname, array, fmtin=None, iprn=None): array = b.copy() elif len(array.shape) < 2 or len(array.shape) > 3: raise Exception( - "Shape of the input array is not recognized: {}".format( - array.shape - ) + f"Shape of the input array is not recognized: {array.shape}" ) if np.ma.is_masked(array): array = np.ma.filled(array, 0) @@ -1632,18 +1611,14 @@ def write_zone_file(cls, fname, array, fmtin=None, iprn=None): if iprn is None or iprn <= iprnmin: iprn = iprnmin + 1 - formatter_str = "{{:>{iprn}}}".format(iprn=iprn) + formatter_str = f"{{:>{iprn}}}" formatter = formatter_str.format with open(fname, "w") as f: - header = "{nlay} {nrow} {ncol}\n".format( - nlay=nlay, nrow=nrow, ncol=ncol - ) + header = f"{nlay} {nrow} {ncol}\n" f.write(header) for lay in range(nlay): - record_2 = "INTERNAL\t({fmtin}I{iprn})\n".format( - fmtin=fmtin, iprn=iprn - ) + record_2 = f"INTERNAL\t({fmtin}I{iprn})\n" f.write(record_2) if fmtin < ncol: for row in range(nrow): @@ -1675,6 +1650,40 @@ def copy(self): """ return copy.deepcopy(self) + def export(self, f, ml, **kwargs): + """ + Method to export a netcdf file, or add zonebudget output to + an open netcdf file instance + + Parameters + ---------- + f : str or flopy.export.netcdf.NetCdf object + ml : flopy.modflow.Modflow or flopy.mf6.ModflowGwf object + **kwargs : + logger : flopy.export.netcdf.Logger instance + masked_vals : list + list of values to mask + + Returns + ------- + flopy.export.netcdf.NetCdf object + + """ + from flopy.export.utils import output_helper + + if isinstance(f, str): + if not f.endswith(".nc"): + raise AssertionError( + "File extension must end with .nc to " + "export a netcdf file" + ) + + zbncfobj = dataframe_to_netcdf_fmt( + self.get_dataframes(pivot=True), self.izone, flux=True + ) + oudic = {"zbud": zbncfobj} + return output_helper(f, ml, oudic, **kwargs) + def __deepcopy__(self, memo): """ Over-rides the default deepcopy behavior. Copy all attributes except @@ -1836,7 +1845,7 @@ def __setattr__(self, key, value): def __getattr__(self, item): if item in ("zon", "bud", "grb", "name", "model_ws"): - item = "_{}".format(item) + item = f"_{item}" return super().__getattribute__(item) def add_package(self, pkg_name, pkg): @@ -1857,7 +1866,7 @@ def add_package(self, pkg_name, pkg): pkg_name = "bud" else: raise KeyError( - "{} package is not valid for zonebudget".format(pkg_name) + f"{pkg_name} package is not valid for zonebudget" ) if isinstance(pkg, str): @@ -1873,7 +1882,7 @@ def add_package(self, pkg_name, pkg): else: pass - pkg_name = "_{}".format(pkg_name) + pkg_name = f"_{pkg_name}" self.__setattr__(pkg_name, pkg) if pkg is not None: self.package_dict[pkg_name[1:]] = pkg @@ -1904,9 +1913,7 @@ def change_model_name(self, name): """ self._name = name if self._zon is not None: - self._zon.filename = "{}.{}".format( - name, self._zon.filename.split(".")[-1] - ) + self._zon.filename = f"{name}.{self._zon.filename.split('.')[-1]}" def get_dataframes( self, @@ -1947,10 +1954,10 @@ def get_dataframes( Examples -------- - >>> from flopy.utils.zonbud import ZoneBudget, read_zbarray - >>> zon = read_zbarray('zone_input_file') - >>> zb = ZoneBudget('zonebudtest.cbc', zon, kstpkper=(0, 0)) - >>> df = zb.get_dataframes() + >>> from flopy.utils.zonbud import ZoneBudget6 + >>> zb6 = ZoneBudget6.load("my_nam_file", model_ws="my_model_ws") + >>> zb6.run_model() + >>> df = zb6.get_dataframes() """ recarray = self.get_budget( @@ -1996,7 +2003,7 @@ def get_budget( aliases = self._zon.aliases if f is None and self._recarray is None: - f = os.path.join(self._model_ws, self._name + ".csv") + f = os.path.join(self._model_ws, f"{self._name}.csv") self._recarray = _read_zb_csv2( f, add_prefix=False, aliases=aliases ) @@ -2069,7 +2076,7 @@ def write_input(self, line_length=20): else: path = pkg.filename pkg.write_input(line_length=line_length) - nam.append(" {} {}\n".format(pkg_nam.upper(), path)) + nam.append(f" {pkg_nam.upper()} {path}\n") path = os.path.join(self._model_ws, self._name + self._extension) with open(path, "w") as foo: @@ -2109,6 +2116,40 @@ def load(nam_file, model_ws="."): return zb6 + def export(self, f, ml, **kwargs): + """ + Method to export a netcdf file, or add zonebudget output to + an open netcdf file instance + + Parameters + ---------- + f : str or flopy.export.netcdf.NetCdf object + ml : flopy.modflow.Modflow or flopy.mf6.ModflowGwf object + **kwargs : + logger : flopy.export.netcdf.Logger instance + masked_vals : list + list of values to mask + + Returns + ------- + flopy.export.netcdf.NetCdf object + + """ + from flopy.export.utils import output_helper + + if isinstance(f, str): + if not f.endswith(".nc"): + raise AssertionError( + "File extension must end with .nc to " + "export a netcdf file" + ) + + zbncfobj = dataframe_to_netcdf_fmt( + self.get_dataframes(pivot=True), self._zon.izone, flux=True + ) + oudic = {"zbud": zbncfobj} + return output_helper(f, ml, oudic, **kwargs) + class ZoneFile6: """ @@ -2137,10 +2178,8 @@ def __init__(self, model, izone, extension=".zon", aliases=None): self._parent.add_package("zon", self) self.filename = self._parent.name + extension self.aliases = aliases - self.allzones = [int(zn) for zn in np.unique(izone) if zn != 0] - self._zonenamedict = OrderedDict( - [(zn, "ZONE_{}".format(zn)) for zn in self.allzones] - ) + self.allzones = [int(z) for z in np.unique(izone) if z != 0] + self._zonenamedict = {z: f"ZONE_{z}" for z in self.allzones} if aliases is not None: if not isinstance(aliases, dict): @@ -2153,7 +2192,7 @@ def __init__(self, model, izone, extension=".zon", aliases=None): self.aliases[zn] = "_".join(alias.split()) else: pop_list.append(zn) - print("warning: zone number {} not found".format(zn)) + print(f"warning: zone number {zn} not found") for p in pop_list: aliases.pop(p) @@ -2183,8 +2222,8 @@ def write_input(self, f=None, line_length=20): with open(f, "w") as foo: bfmt = [" {:d}"] foo.write( - "BEGIN DIMENSIONS\n NCELLS {:d}\n" - "END DIMENSIONS\n\n".format(self.ncells) + f"BEGIN DIMENSIONS\n NCELLS {self.ncells}\n" + "END DIMENSIONS\n\n" ) foo.write("BEGIN GRIDDATA\n IZONE\n") @@ -2332,11 +2371,11 @@ def _recarray_to_dataframe( try: import pandas as pd except Exception as e: - msg = "ZoneBudget.get_dataframes() error import pandas: " + str(e) + msg = f"ZoneBudget.get_dataframes() error import pandas: {e!s}" raise ImportError(msg) valid_index_keys = ["totim", "kstpkper"] - s = 'index_key "{}" is not valid.'.format(index_key) + s = f'index_key "{index_key}" is not valid.' assert index_key in valid_index_keys, s valid_timeunit = ["S", "M", "H", "D", "Y"] @@ -2353,8 +2392,7 @@ def _recarray_to_dataframe( timeunit = "Y" errmsg = ( - "Specified time units ({}) not recognized. " - "Please use one of ".format(timeunit) + f"Specified time units ({timeunit}) not recognized. Please use one of " ) assert timeunit in valid_timeunit, errmsg + ", ".join(valid_timeunit) + "." @@ -2556,50 +2594,6 @@ def _compute_net_budget(recarray, zonenamedict): return net_budget -def write_zbarray(fname, X, fmtin=None, iprn=None): - """ - Saves a numpy array in a format readable by the zonebudget program - executable. - - File format: - line 1: nlay, nrow, ncol - line 2: INTERNAL (format) - line 3: begin data - . - . - . - - example from NACP: - 19 250 500 - INTERNAL (10I8) - 199 199 199 199 199 199 199 199 199 199 - 199 199 199 199 199 199 199 199 199 199 - ... - INTERNAL (10I8) - 199 199 199 199 199 199 199 199 199 199 - 199 199 199 199 199 199 199 199 199 199 - ... - - Parameters - ---------- - X : array - The array of zones to be written. - fname : str - The path and name of the file to be written. - fmtin : int - The number of values to write to each line. - iprn : int - Padding space to add between each value. - - """ - warnings.warn( - "Deprecation planned in version" - " 3.3.5 Use ZoneBudget.write_zone_file()", - PendingDeprecationWarning, - ) - ZoneBudget.write_zone_file(fname, X, fmtin, iprn) - - def _read_zb_zblst(fname): """Method to read zonebudget zblst output @@ -2627,8 +2621,8 @@ def _read_zb_zblst(fname): line = foo.readline().strip() zones = [int(i) for i in line.split()] for zone in zones: - data["TO_ZONE_{}".format(zone)] = [] - data["FROM_ZONE_{}".format(zone)] = [] + data[f"TO_ZONE_{zone}"] = [] + data[f"FROM_ZONE_{zone}"] = [] if "FLOW BUDGET FOR ZONE" in line: flow_budget = True @@ -2662,9 +2656,9 @@ def _read_zb_zblst(fname): if "ZONE" in line: if prefix == "FROM_": zlist.append(int(label.split()[1])) - label = "FROM_ZONE_{}".format(label.split()[1]) + label = f"FROM_ZONE_{label.split()[1]}" else: - label = "TO_ZONE_{}".format(label.split()[-1]) + label = f"TO_ZONE_{label.split()[-1]}" elif "TOTAL" in line or "PERCENT DISCREPANCY" in line: label = "_".join(label.split()) @@ -2685,8 +2679,8 @@ def _read_zb_zblst(fname): for zone in zones: if zone in zlist: continue - data["FROM_ZONE_{}".format(zone)].append(0) - data["TO_ZONE_{}".format(zone)].append(0) + data[f"FROM_ZONE_{zone}"].append(0) + data[f"TO_ZONE_{zone}"].append(0) elif "OUT:" in line: prefix = "TO_" @@ -2883,9 +2877,9 @@ def _zb_dict_to_recarray(data, aliases=None): if zn in aliases: zone_dtypes.append((aliases[zn], float)) else: - zone_dtypes.append(("ZONE_{}".format(int(zn)), float)) + zone_dtypes.append((f"ZONE_{int(zn)}", float)) else: - zone_dtypes.append(("ZONE_{}".format(int(zn)), float)) + zone_dtypes.append((f"ZONE_{int(zn)}", float)) dtype = [ ("totim", float), @@ -2926,29 +2920,6 @@ def _zb_dict_to_recarray(data, aliases=None): return array.view(type=np.recarray) -def read_zbarray(fname): - """ - Reads an ascii array in a format readable by the zonebudget program - executable. - - Parameters - ---------- - fname : str - The path and name of the file to be written. - - Returns - ------- - zones : numpy ndarray - An integer array of the zones. - """ - warnings.warn( - "Deprecation planned for version 3.3.5, " - "use ZoneBudget.read_zone_file()", - PendingDeprecationWarning, - ) - return ZoneBudget.read_zone_file(fname) - - def _pivot_recarray(recarray): """ Method to pivot the zb output recarray to be compatible @@ -3069,7 +3040,6 @@ def _volumetric_flux(recarray, modeltime, extrapolate_kper=False): volumetric_data[key].append(zone) else: - t = temp[zix][key] tmp = np.nanmean(temp[zix][key]) vol = tmp * perlen[per] volumetric_data[key].append(vol) @@ -3107,219 +3077,56 @@ def _volumetric_flux(recarray, modeltime, extrapolate_kper=False): return pd.DataFrame.from_dict(volumetric_data) -class ZoneBudgetOutput: +def dataframe_to_netcdf_fmt(df, zone_array, flux=True): """ - DEPRECATED: Class method to process zonebudget output into - volumetric budgets + Method to transform a volumetric zonebudget dataframe into + array format for netcdf. + + time is on axis 0 + zone is on axis 1 Parameters ---------- - f : str - zonebudget output file path - dis : flopy.modflow.ModflowDis object - zones : np.ndarray - numpy array of zones - - """ - - def __init__(self, f, dis, zones=None): - import pandas as pd - from ..modflow import ModflowDis + df : pd.DataFrame + zone_array : np.ndarray + zonebudget zones array + flux : bool + boolean flag to indicate if budget data is a flux "L^3/T" (True, + default) or if the data have been processed to + volumetric values "L^3" (False) - warnings.warn( - "ZoneBudgetOutput will be deprecated in version 3.3.5," - "Use ZoneBudget.read_output(, pivot=True)" - " or ZoneBudget6.get_budget(, pivot=True)", - PendingDeprecationWarning, - ) + Returns + ------- + ZBNetOutput object - self._filename = f - self._otype = None - self._zones = zones - self.__pd = pd + """ + zones = np.sort(np.unique(df.zone.values)) + totim = np.sort(np.unique(df.totim.values)) - if isinstance(dis, ModflowDis): - add_prefix = True - model = dis.parent + data = {} + for col in df.columns: + if col in ("totim", "zone", "kper", "kstp", "perlen"): + pass else: - add_prefix = False - modelname = list(dis.model_or_sim.model_dict.keys())[0] - model = dis.model_or_sim.model_dict[modelname] - - self._modeltime = model.modeltime - self._data = ZoneBudget.read_output(f, add_prefix=add_prefix, net=True) - - def __repr__(self): - """ - String representation of the ZoneBudgetOutput class - - """ - zones = ", ".join([str(i) for i in self.zones]) - l = [ - "ZoneBudgetOutput Class", - "----------------------\n", - "Number of zones: {}".format(len(self.zones)), - "Unique zones: {}".format(zones), - "Number of buget records: {}".format(len(self.dataframe)), + data[col] = np.zeros((totim.size, zones.size), dtype=float) + + for i, time in enumerate(totim): + tdf = df.loc[ + df.totim.isin( + [ + time, + ] + ) ] + tdf = tdf.sort_values(by=["zone"]) - return "\n".join(l) - - @property - def zone_array(self): - """ - Property method to get the zone array - - """ - warnings.warn( - "ZoneBudgetOutput will be deprecated in version 3.3.5", - PendingDeprecationWarning, - ) - return np.asarray(self._zones, dtype=int) - - @property - def zones(self): - """ - Get a unique list of zones - - """ - warnings.warn( - "ZoneBudgetOutput will be deprecated in version 3.3.5", - PendingDeprecationWarning, - ) - return np.unique(self.zone_array) - - @property - def dataframe(self): - """ - Returns a net flux dataframe of the zonebudget output - - """ - warnings.warn( - "ZoneBudgetOutput will be deprecated in version 3.3.5", - PendingDeprecationWarning, - ) - data = _pivot_recarray(self._data) - return self.__pd.DataFrame.from_records(data) - - def export(self, f, ml, **kwargs): - """ - Method to export a netcdf file, or add zonebudget output to - an open netcdf file instance - - Parameters - ---------- - f : str or flopy.export.netcdf.NetCdf object - ml : flopy.modflow.Modflow or flopy.mf6.ModflowGwf object - **kwargs : - logger : flopy.export.netcdf.Logger instance - masked_vals : list - list of values to mask - - Returns - ------- - flopy.export.netcdf.NetCdf object - - """ - warnings.warn( - "ZoneBudgetOutput will be deprecated in version 3.3.5", - PendingDeprecationWarning, - ) - from flopy.export.utils import output_helper - - if isinstance(f, str): - if not f.endswith(".nc"): - raise AssertionError( - "File extension must end with .nc to " - "export a netcdf file" - ) - - zbncfobj = self.dataframe_to_netcdf_fmt(self.dataframe) - oudic = {"zbud": zbncfobj} - return output_helper(f, ml, oudic, **kwargs) - - def volumetric_flux(self, extrapolate_kper=False): - """ - Method to generate a volumetric budget table based on flux information - - Parameters - ---------- - extrapolate_kper : bool - flag to determine if we fill in data gaps with other - timestep information from the same stress period. - if True, we assume that flux is constant throughout a stress period - and the pandas dataframe returned contains a - volumetric budget per stress period - - if False, calculates volumes from available flux data - - Returns - ------- - pd.DataFrame - - """ - warnings.warn( - "ZoneBudgetOutput.volumetric_flux()" - " will be deprecated in version 3.3.5,", - PendingDeprecationWarning, - ) - recarray = _pivot_recarray(self._data) - return _volumetric_flux(recarray, self._modeltime, extrapolate_kper) - - def dataframe_to_netcdf_fmt(self, df, flux=True): - """ - Method to transform a volumetric zonebudget dataframe into - array format for netcdf. - - time is on axis 0 - zone is on axis 1 - - Parameters - ---------- - df : pd.DataFrame - flux : bool - boolean flag to indicate if budget data is a flux "L^3/T" (True, - default) or if the data have been processed to - volumetric values "L^3" (False) - zone_array : np.ndarray - zonebudget zones array - - Returns - ------- - ZBNetOutput object - - """ - warnings.warn( - "ZoneBudgetOutput will be deprecated in version 3.3.5", - PendingDeprecationWarning, - ) - zones = np.sort(np.unique(df.zone.values)) - totim = np.sort(np.unique(df.totim.values)) - - data = {} for col in df.columns: if col in ("totim", "zone", "kper", "kstp", "perlen"): pass else: - data[col] = np.zeros((totim.size, zones.size), dtype=float) - - for i, time in enumerate(totim): - tdf = df.loc[ - df.totim.isin( - [ - time, - ] - ) - ] - tdf = tdf.sort_values(by=["zone"]) - - for col in df.columns: - if col in ("totim", "zone", "kper", "kstp", "perlen"): - pass - else: - data[col][i, :] = tdf[col].values + data[col][i, :] = tdf[col].values - return ZBNetOutput(zones, totim, data, self.zone_array, flux=flux) + return ZBNetOutput(zones, totim, data, zone_array, flux=flux) class ZBNetOutput: diff --git a/dependencies/flopy/version.py b/dependencies/flopy/version.py index fbb9bb4..b402fdb 100644 --- a/dependencies/flopy/version.py +++ b/dependencies/flopy/version.py @@ -1,28 +1,30 @@ # flopy version file automatically created using...make-release.py -# created on...February 18, 2021 16:28:18 +# created on...August 07, 2021 08:14:57 major = 3 minor = 3 -micro = 4 -__version__ = "{:d}.{:d}.{:d}".format(major, minor, micro) +micro = 5 +__version__ = f"{major}.{minor}.{micro}" __pakname__ = "flopy" -# edit author dictionary as necessary +# edit author dictionary as necessary ( +# in order of commits after Bakker and Post author_dict = { "Mark Bakker": "mark.bakker@tudelft.nl", "Vincent Post": "Vincent.Post@bgr.de", - "Christian D. Langevin": "langevin@usgs.gov", "Joseph D. Hughes": "jdhughes@usgs.gov", - "Jeremy T. White": "jwhite@usgs.gov", + "Christian D. Langevin": "langevin@usgs.gov", + "Jeremy T. White": "jwhite@intera.com", "Andrew T. Leaf": "aleaf@usgs.gov", "Scott R. Paulinski": "spaulinski@usgs.gov", - "Joshua D. Larsen": "jlarsen@usgs.gov", - "Michael W. Toews": "M.Toews@gns.cri.nz", - "Eric D. Morway": "emorway@usgs.gov", "Jason C. Bellino": "jbellino@usgs.gov", - "Jon Jeffrey Starn": "jjstarn@usgs.gov", + "Eric D. Morway": "emorway@usgs.gov", + "Michael W. Toews": "M.Toews@gns.cri.nz", + "Joshua D. Larsen": "jlarsen@usgs.gov", "Michael N. Fienen": "mnfienen@usgs.gov", + "Jon Jeffrey Starn": "jjstarn@usgs.gov", + "Davíd Brakenhoff": "d.brakenhoff@artesia-water.nl", } __author__ = ", ".join(author_dict.keys()) __author_email__ = ", ".join(s for _, s in author_dict.items()) diff --git a/dependencies/pyemu/pst/pst_handler.py b/dependencies/pyemu/pst/pst_handler.py index 3cad4c2..edae067 100644 --- a/dependencies/pyemu/pst/pst_handler.py +++ b/dependencies/pyemu/pst/pst_handler.py @@ -1420,7 +1420,7 @@ def add_pi_equation( if len(fixed) > 0: raise Exception( "Pst.add_pi_equation(): the following pars " - + " were are fixed/tied: {0}".format(",".join(missing)) + + " were are fixed/tied: {0}".format(",".join(fixed)) ) eqs_str = "" sign = "" @@ -1507,9 +1507,13 @@ def ext_fmt(x): + "\n" ) - def sanity_checks(self): + def sanity_checks(self, forgive=False): """some basic check for strangeness + Args: + forgive (`bool`): flag to forgive (warn) for issues. Default is False + + Note: checks for duplicate names, atleast 1 adjustable parameter and at least 1 non-zero-weighted observation @@ -1527,17 +1531,25 @@ def sanity_checks(self): dups = self.parameter_data.parnme.value_counts() dups = dups.loc[dups > 1] if dups.shape[0] > 0: - warnings.warn( - "duplicate parameter names: {0}".format(",".join(list(dups.index))), - PyemuWarning, - ) + if forgive: + warnings.warn( + "duplicate parameter names: {0}".format(",".join(list(dups.index))), + PyemuWarning, + ) + else: + raise Exception("Pst.sanity_check() error: duplicate parameter names: {0}".format(",".join(list(dups.index)))) + dups = self.observation_data.obsnme.value_counts() dups = dups.loc[dups > 1] if dups.shape[0] > 0: - warnings.warn( - "duplicate observation names: {0}".format(",".join(list(dups.index))), - PyemuWarning, - ) + if forgive: + warnings.warn( + "duplicate observation names: {0}".format(",".join(list(dups.index))), + PyemuWarning, + ) + else: + raise Exception( + "Pst.sanity_check() error: duplicate observation names: {0}".format(",".join(list(dups.index)))) if self.npar_adj == 0: warnings.warn("no adjustable pars", PyemuWarning) @@ -1545,6 +1557,32 @@ def sanity_checks(self): if self.nnz_obs == 0: warnings.warn("no non-zero weight obs", PyemuWarning) + if self.tied is not None and len(self.tied) > 0: + sadj = set(self.adj_par_names) + spar = set(self.par_names) + + tpar_dict = self.parameter_data.partied.to_dict() + + for tpar,ptied in tpar_dict.items(): + if pd.isna(ptied): + continue + if tpar == ptied: + if forgive: + warnings.warn("tied parameter '{0}' tied to itself".format(tpar),PyemuWarning) + else: + raise Exception("Pst.sanity_check() error: tied parameter '{0}' tied to itself".format(tpar)) + elif ptied not in spar: + if forgive: + warnings.warn("tied parameter '{0}' tied to unknown parameter '{1}'".format(tpar,ptied),PyemuWarning) + else: + raise Exception("Pst.sanity_check() error: tied parameter '{0}' tied to unknown parameter '{1}'".format(tpar,ptied)) + elif ptied not in sadj: + if forgive: + warnings.warn("tied parameter '{0}' tied to non-adjustable parameter '{1}'".format(tpar,ptied),PyemuWarning) + else: + raise Exception("Pst.sanity_check() error: tied parameter '{0}' tied to non-adjustable parameter '{1}'".format(tpar,ptied)) + + # print("noptmax: {0}".format(self.control_data.noptmax)) def _write_version2(self, new_filename, use_pst_path=True, pst_rel_path="."): @@ -1559,6 +1597,7 @@ def _write_version2(self, new_filename, use_pst_path=True, pst_rel_path="."): self.new_filename = new_filename self.rectify_pgroups() self.rectify_pi() + self._rectify_parchglim() self._update_control_section() self.sanity_checks() @@ -1749,12 +1788,21 @@ def write(self, new_filename, version=None): "Pst.write() error: version must be 1 or 2, not '{0}'".format(version) ) + def _rectify_parchglim(self): + """private method to just fix the parchglim vs cross zero issue""" + par = self.parameter_data + need_fixing = par.loc[par.parubnd > 0,:].copy() + need_fixing = need_fixing.loc[par.parlbnd <= 0, "parnme"] + + self.parameter_data.loc[need_fixing,"parchglim"] = "relative" + def _write_version1(self, new_filename): """private method to write a version 1 pest control file""" self.new_filename = new_filename self.rectify_pgroups() self.rectify_pi() self._update_control_section() + self._rectify_parchglim() self.sanity_checks() f_out = open(new_filename, "w") @@ -3659,3 +3707,102 @@ def try_parse_name_metadata(self): df.loc[:, uk] = meta_dict.apply(lambda x: x.get(uk, np.NaN)) except Exception as e: print("error parsing metadata from '{0}', continuing".format(name)) + + def rename_parameters(self,name_dict,pst_path="."): + """rename parameters in the control and template files + + Args: + name_dict (`dict`): mapping of current to new names. + pst_path (str): the path to the control file from where python + is running. Default is "." (python is running in the + same directory as the control file) + + Note: + no attempt is made to maintain the length of the marker strings + in the template files, so if your model is sensitive + to changes in spacing in the template file(s), this + is not a method for you + + This does a lot of string compare, so its gonna be slow as... + + Example:: + + pst = pyemu.Pst(os.path.join("template","pest.pst")) + name_dict = {"par1":"par1_better_name"} + pst.rename_parameters(name_dict,pst_path="template") + + + + """ + + missing = set(name_dict.keys()) - set(self.par_names) + if len(missing) > 0: + raise Exception("Pst.rename_parameters(): the following parameters in 'name_dict'"+ + " are not in the control file:\n{0}".format(",".join(missing))) + + par = self.parameter_data + par.loc[:,"parnme"] = par.parnme.apply(lambda x: name_dict.get(x,x)) + par.index = par.parnme.values + + for idx,eq in zip(self.prior_information.index,self.prior_information.equation): + for old,new in name_dict.items(): + eq = eq.replace(old,new) + self.prior_information.loc[idx,"equation"] = eq + + + for tpl_file in self.model_input_data.pest_file: + sys_tpl_file = os.path.join(pst_path,tpl_file.replace("/",os.path.sep).replace("\\",os.path.sep)) + if not os.path.exists(sys_tpl_file): + warnings.warn("template file '{0}' not found, continuing...",PyemuWarning) + continue + lines = open(sys_tpl_file,'r').readlines() + with open(sys_tpl_file,'w') as f: + for line in lines: + for old,new in name_dict.items(): + if old in line: + line = line.replace(old,new) + f.write(line) + + def rename_observations(self, name_dict, pst_path="."): + """rename observations in the control and instruction files + + Args: + name_dict (`dict`): mapping of current to new names. + pst_path (str): the path to the control file from where python + is running. Default is "." (python is running in the + same directory as the control file) + + Note: + This does a lot of string compare, so its gonna be slow as... + + Example:: + + pst = pyemu.Pst(os.path.join("template","pest.pst")) + name_dict = {"obs1":"obs1_better_name"} + pst.rename_observations(name_dict,pst_path="template") + + + + """ + + missing = set(name_dict.keys()) - set(self.obs_names) + if len(missing) > 0: + raise Exception("Pst.rename_observations(): the following observations in 'name_dict'" + + " are not in the control file:\n{0}".format(",".join(missing))) + + obs = self.observation_data + obs.loc[:, "obsnme"] = obs.obsnme.apply(lambda x: name_dict.get(x, x)) + obs.index = obs.obsnme.values + + for ins_file in self.model_output_data.pest_file: + sys_ins_file = os.path.join(pst_path, ins_file.replace("/", os.path.sep).replace("\\", os.path.sep)) + if not os.path.exists(sys_ins_file): + warnings.warn("instruction file '{0}' not found, continuing...", PyemuWarning) + continue + lines = open(sys_ins_file, 'r').readlines() + with open(sys_ins_file, 'w') as f: + for line in lines: + for old, new in name_dict.items(): + if old in line: + line = line.replace(old, new) + f.write(line) diff --git a/dependencies/pyemu/pyemu_warnings.py b/dependencies/pyemu/pyemu_warnings.py index 7876baf..98d3140 100644 --- a/dependencies/pyemu/pyemu_warnings.py +++ b/dependencies/pyemu/pyemu_warnings.py @@ -1,5 +1,9 @@ import warnings +def warning_on_one_line(message, category, filename, lineno, file=None, line=None): + return '%s:%s: %s: %s\n' % (filename, lineno, category.__name__, message) -class PyemuWarning(RuntimeWarning): +warnings.formatwarning = warning_on_one_line + +class PyemuWarning(Warning): pass diff --git a/dependencies/pyemu/utils/gw_utils.py b/dependencies/pyemu/utils/gw_utils.py index 25bf3d6..9b83f75 100644 --- a/dependencies/pyemu/utils/gw_utils.py +++ b/dependencies/pyemu/utils/gw_utils.py @@ -2798,8 +2798,12 @@ def write_hfb_template(m): f_tpl.write("ptf ~\n") parnme, parval1, xs, ys = [], [], [], [] iis, jjs, kks = [], [], [] - xc = m.sr.xcentergrid - yc = m.sr.ycentergrid + try: + xc = m.sr.xcentergrid + yc = m.sr.ycentergrid + except AttributeError: + xc = m.modelgrid.xcellcenters + yc = m.modelgrid.ycellcenters while True: line = f_in.readline() diff --git a/dependencies/pyemu/utils/helpers.py b/dependencies/pyemu/utils/helpers.py index 0185980..c9f4d69 100644 --- a/dependencies/pyemu/utils/helpers.py +++ b/dependencies/pyemu/utils/helpers.py @@ -1556,6 +1556,16 @@ def __init__( kl_num_eig=100, kl_geostruct=None, ): + dep_warn = ( + "\n`PstFromFlopyModel()` method is getting old and may not" + "be kept in sync with changes to Flopy and MODFLOW.\n" + "Perhaps consider looking at `pyemu.utils.PstFrom()`," + "which is (aiming to be) much more general," + "forward model independent, and generally kicks ass.\n" + "Checkout: https://www.sciencedirect.com/science/article/abs/pii/S1364815221000657?via%3Dihub\n" + "and https://github.com/pypest/pyemu_pestpp_workflow for more info." + ) + warnings.warn(dep_warn, DeprecationWarning) self.logger = pyemu.logger.Logger("PstFromFlopyModel.log") self.log = self.logger.log @@ -1777,7 +1787,7 @@ def __init__( ) ) self.log("saving intermediate _setup_<> dfs into {0}".format(self.m.model_ws)) - + warnings.warn(dep_warn, DeprecationWarning) self.logger.statement("all done") def _setup_sfr_obs(self): @@ -1935,7 +1945,15 @@ def _setup_model(self, model, org_model_ws, new_model_ws): self.m = model self.org_model_ws = str(self.m.model_ws) self.new_model_ws = new_model_ws - + try: + self.sr = self.m.sr + except AttributeError: # if sr doesnt exist anymore! + # assume that we have switched to model grid + self.sr = SpatialReference.from_namfile( + os.path.join(self.org_model_ws, self.m.namefile), + delr=self.m.modelgrid.delr, + delc=self.m.modelgrid.delc + ) self.log("updating model attributes") self.m.array_free_format = True self.m.free_format_input = True @@ -2107,8 +2125,8 @@ def _write_grid_tpl(self, name, tpl_file, zn_array): ) parnme.append(pname) pname = " ~ {0} ~ ".format(pname) - x.append(self.m.sr.xcentergrid[i, j]) - y.append(self.m.sr.ycentergrid[i, j]) + x.append(self.sr.xcentergrid[i, j]) + y.append(self.sr.ycentergrid[i, j]) f.write(pname) f.write("\n") df = pd.DataFrame({"parnme": parnme, "x": x, "y": y}, index=parnme) @@ -2298,7 +2316,7 @@ def _pp_prep(self, mlt_df): ) ok_pp = pyemu.geostats.OrdinaryKrige(self.pp_geostruct, pp_df_k) ok_pp.calc_factors_grid( - self.m.sr, + self.sr, var_filename=var_file, zone_array=ib_k, num_threads=10, @@ -2413,7 +2431,7 @@ def _kl_prep(self, mlt_df): kl_df = kl_setup( self.kl_num_eig, - self.m.sr, + self.sr, self.kl_geostruct, kl_prefix, factors_file=fac_file, @@ -2496,7 +2514,7 @@ def _setup_array_pars(self): self.cn_suffix, self.m.bas6.ibound[layer].array, (self.m.nrow, self.m.ncol), - self.m.sr, + self.sr, ) except Exception as e: self.logger.lraise( @@ -2514,7 +2532,7 @@ def _setup_array_pars(self): self.gr_suffix, self.m.bas6.ibound[layer].array, (self.m.nrow, self.m.ncol), - self.m.sr, + self.sr, ) except Exception as e: self.logger.lraise( @@ -2550,7 +2568,7 @@ def _setup_array_pars(self): self.zn_suffix, k_zone_dict[layer], (self.m.nrow, self.m.ncol), - self.m.sr, + self.sr, ) except Exception as e: self.logger.lraise( @@ -3355,10 +3373,10 @@ def _setup_spatial_list_pars(self): parnme, pargp = [], [] # if pak != 'hfb6': x = df.apply( - lambda x: self.m.sr.xcentergrid[int(x.i), int(x.j)], axis=1 + lambda x: self.sr.xcentergrid[int(x.i), int(x.j)], axis=1 ).values y = df.apply( - lambda x: self.m.sr.ycentergrid[int(x.i), int(x.j)], axis=1 + lambda x: self.sr.ycentergrid[int(x.i), int(x.j)], axis=1 ).values # else: # # note -- for HFB6, only row and col for node 1 @@ -3611,6 +3629,9 @@ def apply_list_and_array_pars(arr_par_file="mult2model_info.csv", chunk_len=50): by `PstFrom.build_pst()` """ df = pd.read_csv(arr_par_file, index_col=0) + if "operator" not in df.columns: + df.loc[:,"operator"] = "m" + df.loc[pd.isna(df.operator),"operator"] = "m" arr_pars = df.loc[df.index_cols.isna()].copy() list_pars = df.loc[df.index_cols.notna()].copy() # extract lists from string in input df @@ -3636,6 +3657,8 @@ def _process_chunk_array_files(chunk, i, df): def _process_array_file(model_file, df): + if "operator" not in df.columns: + df.loc[:,"operator"] = "m" # find all mults that need to be applied to this array df_mf = df.loc[df.model_file == model_file, :] results = [] @@ -3645,7 +3668,7 @@ def _process_array_file(model_file, df): org_arr = np.loadtxt(org_file[0]) if "mlt_file" in df_mf.columns: - for mlt in df_mf.mlt_file: + for mlt,operator in zip(df_mf.mlt_file,df_mf.operator): if pd.isna(mlt): continue mlt_data = np.loadtxt(mlt) @@ -3655,7 +3678,12 @@ def _process_array_file(model_file, df): org_file, org_arr.shape, mlt, mlt_data.shape ) ) - org_arr *= np.loadtxt(mlt) + if operator == "*" or operator.lower()[0] == "m": + org_arr *= mlt_data + elif operator == "+" or operator.lower()[0] == "a": + org_arr += mlt_data + else: + raise Exception("unrecognized operator '{0}' for mlt file '{1}'".format(operator,mlt)) if "upper_bound" in df.columns: ub_vals = df_mf.upper_bound.value_counts().dropna().to_dict() if len(ub_vals) == 0: @@ -4250,9 +4278,17 @@ def _process_list_file(model_file, df): new_df.index.intersection(mlts.index).sort_values().drop_duplicates() ) mlt_cols = [str(col) for col in mlt.use_cols] - new_df.loc[common_idx, mlt_cols] = ( - new_df.loc[common_idx, mlt_cols] * mlts.loc[common_idx, mlt_cols] - ).values + operator = mlt.operator + if operator == "*" or operator.lower()[0] == "m": + new_df.loc[common_idx, mlt_cols] = ( + new_df.loc[common_idx, mlt_cols] * mlts.loc[common_idx, mlt_cols] + ).values + elif operator == "+" or operator.lower()[0] == "a": + new_df.loc[common_idx, mlt_cols] = ( + new_df.loc[common_idx, mlt_cols] + mlts.loc[common_idx, mlt_cols] + ).values + else: + raise Exception("unsupported operator '{0}' for mlt file '{1}'".format(operator,mlt.mlt_file)) # bring mult index back to columns AND re-order new_df = new_df.reset_index().set_index("oidx")[org_data.columns].sort_index() if "upper_bound" in df.columns: diff --git a/dependencies/pyemu/utils/os_utils.py b/dependencies/pyemu/utils/os_utils.py index 1141111..d7de2ac 100644 --- a/dependencies/pyemu/utils/os_utils.py +++ b/dependencies/pyemu/utils/os_utils.py @@ -361,6 +361,6 @@ def start_workers( worker_dirs.pop(worker_dirs.index(d)) # if successfully removed except Exception as e: warnings.warn( - "unable to remove slavr dir{0}:{1}".format(d, str(e)), + "unable to remove worker dir{0}:{1}".format(d, str(e)), PyemuWarning, ) diff --git a/dependencies/pyemu/utils/pp_utils.py b/dependencies/pyemu/utils/pp_utils.py index 0a2a988..b129a3f 100644 --- a/dependencies/pyemu/utils/pp_utils.py +++ b/dependencies/pyemu/utils/pp_utils.py @@ -34,6 +34,7 @@ def setup_pilotpoints_grid( tpl_dir=".", shapename="pp.shp", longnames=False, + pp_filename_dict = {} ): """setup a regularly-spaced (gridded) pilot point parameterization @@ -58,6 +59,10 @@ def setup_pilotpoints_grid( tpl_dir (`str`, optional): directory to write pilot point template file to. Default is '.' shapename (`str`, optional): name of shapefile to write that contains pilot point information. Default is "pp.shp" + longnames (`bool`): flag to use parameter names longer than 12 chars. Default is False + pp_filename_dict (`dict`): optional dict of prefix-pp filename pairs. prefix values must + match the values in `prefix_dict`. If None, then pp filenames are based on the + key values in `prefix_dict`. Default is None Returns: `pandas.DataFrame`: a dataframe summarizing pilot point information (same information @@ -76,7 +81,15 @@ def setup_pilotpoints_grid( except Exception as e: raise ImportError("error importing flopy: {0}".format(str(e))) assert isinstance(ml, flopy.modflow.Modflow) - sr = ml.sr + try: + sr = ml.sr + except AttributeError: + from pyemu.utils.helpers import SpatialReference + sr = SpatialReference.from_namfile( + os.path.join(ml.model_ws, ml.namefile), + delr=ml.modelgrid.delr, + delc=ml.modelgrid.delc + ) if ibound is None: ibound = ml.bas6.ibound.array # build a generic prefix_dict @@ -115,6 +128,17 @@ def setup_pilotpoints_grid( "from 'sr':{0}:{1}".format(str(e0), str(e1)) ) start = int(float(every_n_cell) / 2.0) + + # fix for x-section models + if xcentergrid.shape[0]==1 : + start_row = 0 + else : + start_row = start + + if xcentergrid.shape[1]==1 : + start_col = 0 + else : + start_col = start # check prefix_dict keys = list(prefix_dict.keys()) @@ -162,8 +186,8 @@ def setup_pilotpoints_grid( if k not in prefix_dict.keys(): continue # cycle through rows and cols - for i in range(start, ib.shape[0] - start, every_n_cell): - for j in range(start, ib.shape[1] - start, every_n_cell): + for i in range(start_row, ib.shape[0] - start_row, every_n_cell): + for j in range(start_col, ib.shape[1] - start_col, every_n_cell): # skip if this is an inactive cell if ib[i, j] <= 0: # this will account for MF6 style ibound as well continue @@ -204,7 +228,10 @@ def setup_pilotpoints_grid( ~np.any([prefix.startswith(p) for p in ibound.keys()]) and par == "general_zn" ): - base_filename = "{0}pp.dat".format(prefix.replace(":", "")) + if prefix in pp_filename_dict.keys(): + base_filename = pp_filename_dict[prefix].replace(":", "") + else: + base_filename = "{0}pp.dat".format(prefix.replace(":", "")) pp_filename = os.path.join(pp_dir, base_filename) # write the base pilot point file write_pp_file(pp_filename, pp_df) @@ -212,8 +239,7 @@ def setup_pilotpoints_grid( tpl_filename = os.path.join(tpl_dir, base_filename + ".tpl") # write the tpl file pilot_points_to_tpl( - pp_df, tpl_filename, name_prefix=prefix, longnames=longnames - ) + pp_df, tpl_filename, name_prefix=prefix, longnames=longnames) pp_df.loc[:, "tpl_filename"] = tpl_filename pp_df.loc[:, "pp_filename"] = pp_filename pp_df.loc[:, "pargp"] = prefix @@ -474,6 +500,8 @@ def pilot_points_to_tpl(pp_file, tpl_file=None, name_prefix=None, longnames=Fals pilot point parameters will be named "hk_0001","hk_0002", etc. If None, parameter names from `pp_df.name` are used. Default is None. + longnames (`bool`): flag to use parameter names longer than 12 chars. + Default is False Returns: `pandas.DataFrame`: a dataframe with pilot point information @@ -506,7 +534,7 @@ def pilot_points_to_tpl(pp_file, tpl_file=None, name_prefix=None, longnames=Fals ) elif "x" in pp_df.columns and "y" in pp_df.columns: pp_df.loc[:, "parnme"] = pp_df.apply( - lambda x: "{0}_x:{1}_y:{2}".format(name_prefix, x.x, x.y), + lambda x: "{0}_x:{1:0.2f}_y:{2:0.2f}".format(name_prefix, x.x, x.y), axis=1, ) else: diff --git a/dependencies/pyemu/utils/pst_from.py b/dependencies/pyemu/utils/pst_from.py index c382311..efadd27 100644 --- a/dependencies/pyemu/utils/pst_from.py +++ b/dependencies/pyemu/utils/pst_from.py @@ -65,6 +65,7 @@ class PstFrom(object): chunk_len (`int`): the size of each "chunk" of files to spawn a multiprocessing.Pool member to process. On windows, beware setting this much smaller than 50 because of the overhead associated with spawning the pool. This value is added to the call to `apply_list_and_array_pars`. Default is 50 + echo (`bool`): flag to echo logger messages to the screen. Default is True Note: This is the way... @@ -91,6 +92,7 @@ def __init__( start_datetime=None, tpl_subfolder=None, chunk_len=50, + echo=True, ): self.original_d = Path(original_d) @@ -137,7 +139,7 @@ def __init__( self.ins_filenames, self.output_filenames = [], [] self.longnames = bool(longnames) - self.logger = pyemu.Logger("PstFrom.log", echo=True) + self.logger = pyemu.Logger("PstFrom.log", echo=echo) self.logger.statement("starting PstFrom process") @@ -504,11 +506,9 @@ def draw(self, num_reals=100, sigma_range=6, use_specsim=False, scale_offset=Tru # (setup through add_parameters) for geostruct, par_df_l in struct_dict.items(): par_df = pd.concat(par_df_l) # force to single df - if ( - "i" in par_df.columns and par_df.partype[0] == "grid" - ): # need 'i' and 'j' for specsim - # grid par slicer - grd_p = pd.notna(par_df.i) # & (par_df.partype == 'grid') & + par_df = par_df.loc[par_df.partype == "grid", :] + if "i" in par_df.columns: # need 'i' and 'j' for specsim + grd_p = pd.notna(par_df.i) else: grd_p = np.array([0]) # if there are grid pars (also grid pars with i,j info) @@ -1084,7 +1084,7 @@ def _process_array_obs( """ if ofile_sep is not None: - self.logger.lrase( + self.logger.lraise( "array obs are currently only supported for whitespace delim" ) if not os.path.exists(self.new_d / out_filename): @@ -1137,7 +1137,7 @@ def _process_array_obs( continue if longnames: - oname = "arrobs_{0}_i:{1}_j:{2}".format(prefix, iidx, jr) + oname = "oname:{0}_otype:arr_i:{1}_j:{2}".format(prefix, iidx, jr) if zval is not None: oname += "_zone:{0}".format(zval) else: @@ -1288,6 +1288,8 @@ def add_observations( new_obs.loc[:, "obgnme"] = obsgp elif prefix is not None and len(prefix) != 0: # if prefix is passed new_obs.loc[:, "obgnme"] = prefix + elif self.longnames: + new_obs.loc[:, "obgnme"] = "oname:{0}_otype:arr".format(filenames) # else will default to `obgnme` self.logger.log( "adding observations from array output file '{0}'".format(filenames) @@ -1390,6 +1392,12 @@ def add_observations( else: obsgp = True # will use base of col obsgp = _check_var_len(obsgp, ncol, fill=fill) + nprefix = prefix + + if self.longnames: + if len(nprefix) == 0: + nprefix = filenames[0] + nprefix = "oname:{0}_otype:lst".format(nprefix) df_ins = pyemu.pst_utils.csv_to_ins_file( df.set_index("idx_str"), ins_filename=self.new_d / insfile, @@ -1398,7 +1406,7 @@ def add_observations( marker="~", includes_header=includes_header, includes_index=False, - prefix=prefix, + prefix=nprefix, longnames=self.longnames, head_lines_len=lenhead, sep=sep, @@ -1582,6 +1590,7 @@ def add_parameters( alt_inst_str="inst", comment_char=None, par_style="multiplier", + initial_value=None ): """ Add list or array style model input files to PstFrom object. @@ -1663,11 +1672,13 @@ def add_parameters( This is not additive with `mfile_skip` option. Warning: currently comment lines within list-like tabular data will be lost. - par_style (`str`): either "multiplier" or "direct" where the former setups - up a multiplier parameter process against the existing model input + par_style (`str`): either "m"/"mult"/"multiplier", "a"/"add"/"addend", or "d"/"direct" where the former setups + up a multiplier and addend parameters process against the existing model input array and the former setups a template file to write the model input file directly. Default is "multiplier". + initial_value (`float`): the value to set for the `parval1` value in the control file + Default is 1.0 Returns: `pandas.DataFrame`: dataframe with info for new parameters @@ -1699,7 +1710,6 @@ def add_parameters( transform ) ) - if transform == "fixed" and geostruct is not None: self.logger.lraise( "geostruct is not 'None', cant draw values for fixed pars" @@ -1707,12 +1717,34 @@ def add_parameters( # some checks for direct parameters par_style = par_style.lower() - if par_style not in ["multiplier", "direct"]: + if len(par_style) > 1: + par_style = par_style[0] + if par_style not in ["m", "d", "a"]: self.logger.lraise( - "add_parameters(): unrecognized 'style': {0}, should be either 'multiplier' or 'direct'".format( + "add_parameters(): unrecognized 'style': {0}, should be either 'm'/'mult'/'multiplier', 'a'/'add'/'addend' or 'd'/'direct'".format( par_style ) ) + + if initial_value is None: + if par_style == "m": + initial_value = 1.0 + elif par_style == 'a': + initial_value = 0.0 + lower_bound = -1.0e+10 + + if transform.lower == "log": + if upper_bound <= 0: + self.logger.lraise( + "transform is 'log' but bound_bound <= 0 for filenames {0}".format(",".join(filenames))) + if initial_value <= 0: + self.logger.lraise( + "transform is 'log' but initial_value <= 0 for filenames {0}".format(",".join(filenames))) + + if lower_bound <=0: + self.logger.lraise("transform is 'log' but lower_bound <= 0 for filenames {0}".format(",".join(filenames))) + + if isinstance(filenames, str) or isinstance(filenames, Path): filenames = [filenames] # data file paths relative to the pest parent directory @@ -1721,7 +1753,7 @@ def add_parameters( ] if len(filenames) == 0: self.logger.lraise("add_parameters(): filenames is empty") - if par_style == "direct": + if par_style == "d": if len(filenames) != 1: self.logger.lraise( "add_parameters(): 'filenames' arg for 'direct' style must contain " @@ -1828,7 +1860,7 @@ def add_parameters( if isinstance(par_name_base, str): par_name_base = [par_name_base] # if `use_cols` is passed check number of base names is the same as cols - if len(par_name_base) == 1: + if use_cols is None and len(par_name_base) == 1: pass elif use_cols is not None and len(par_name_base) == len(use_cols): pass @@ -1867,7 +1899,7 @@ def add_parameters( par_name_store = par_name_base[0].replace(":", "") # for os filename # Define requisite filenames - if par_style == "multiplier": + if par_style in ["m","a"]: mlt_filename = "{0}_{1}.csv".format(par_name_store, par_type) # pst input file (for tpl->in pair) is multfile (in mult dir) in_fileabs = self.mult_file_d / mlt_filename @@ -1943,7 +1975,8 @@ def add_parameters( zero_based=self.zero_based, input_filename=in_fileabs, par_style=par_style, - headerlines=headerlines, # only needed for direct pars + headerlines=headerlines, + fill_value=initial_value ) assert ( np.mod(len(df), len(use_cols)) == 0.0 @@ -1960,6 +1993,8 @@ def add_parameters( self.logger.log( "writing array-based template file '{0}'".format(tpl_filename) ) + if pargp is None: + pargp = par_name_base[0] shp = file_dict[list(file_dict.keys())[0]].shape # ARRAY constant, zones or grid (cell-by-cell) if par_type in {"constant", "zone", "grid"}: @@ -1995,7 +2030,7 @@ def add_parameters( "pilot-point", "pilot-points", }: - if par_style == "direct": + if par_style == "d": self.logger.lraise( "pilot points not supported for 'direct' par_style" ) @@ -2040,11 +2075,15 @@ def add_parameters( ) # (stolen from helpers.PstFromFlopyModel()._pp_prep()) # but only settting up one set of pps at a time - pp_dict = {0: par_name_base} + pnb = par_name_base[0] + if self.longnames: + pnb = "pname:{1}_ptype:pp_pstyle:{0}".format(par_style,pnb) + pp_dict = {0: pnb} pp_filename = "{0}pp.dat".format(par_name_store) # pst inputfile (for tpl->in pair) is # par_name_storepp.dat table (in pst ws) in_filepst = pp_filename + pp_filename_dict = {pnb:in_filepst} tpl_filename = self.tpl_d / (pp_filename + ".tpl") # tpl_filename = get_relative_filepath(self.new_d, tpl_filename) pp_locs = None @@ -2227,15 +2266,17 @@ def add_parameters( tpl_dir=self.tpl_d, shapename=str(self.new_d / "{0}.shp".format(par_name_store)), longnames=self.longnames, + pp_filename_dict=pp_filename_dict ) else: + df = pyemu.pp_utils.pilot_points_to_tpl( pp_locs, tpl_filename, - par_name_base[0], + pnb, longnames=self.longnames, ) - df.loc[:, "pargp"] = par_name_base[0] + df.loc[:, "pargp"] = pargp df.set_index("parnme", drop=False, inplace=True) # df includes most of the par info for par_dfs and also for @@ -2383,8 +2424,9 @@ def add_parameters( "head_rows": skip_dict[mod_file], "upper_bound": ult_ubound, "lower_bound": ult_lbound, + "operator":par_style } - if par_style == "multiplier": + if par_style in ["m","a"]: mult_dict["mlt_file"] = Path(self.mult_file_d.name, mlt_filename) if pp_filename is not None: @@ -2744,8 +2786,9 @@ def write_list_tpl( xy_in_idx=None, zero_based=True, input_filename=None, - par_style="multiplier", + par_style="m", headerlines=None, + fill_value=1.0 ): """Write template files for a list style input. @@ -2784,8 +2827,9 @@ def write_list_tpl( are NOT zero-based indicies (e.g. MODFLOW row/cols). If False 1 with be subtracted from `index_cols`. input_filename (`str`): Path to input file (paired with tpl file) - par_style (`str`): either 'direct' or 'multiplier' - + par_style (`str`): either 'd','a', or 'm' + headerlines ([`str`]): optional header lines in the original model file, used for + direct style parameters Returns: `pandas.DataFrame`: dataframe with info for the new parameters @@ -2795,7 +2839,7 @@ def write_list_tpl( """ # get dataframe with autogenerated parnames based on `name`, `index_cols`, # `use_cols`, `suffix` and `par_type` - if par_style == "direct": + if par_style == "d": df_tpl = _write_direct_df_tpl( filenames[0], tpl_filename, @@ -2829,6 +2873,8 @@ def write_list_tpl( ij_in_idx=ij_in_idx, xy_in_idx=xy_in_idx, zero_based=zero_based, + par_fill_value=fill_value, + par_style=par_style ) for col in use_cols: # corellations flagged using pargp @@ -2910,14 +2956,14 @@ def write_list_tpl( df_tpl.loc[:, use_col] = df_tpl.loc[:, use_col].apply( lambda x: "~ {0} ~".format(x) ) - if par_style == "multiplier": + if par_style in ["m","a"]: pyemu.helpers._write_df_tpl( filename=tpl_filename, df=df_tpl, sep=",", tpl_marker="~" ) if input_filename is not None: df_in = df_tpl.copy() - df_in.loc[:, use_cols] = 1.0 + df_in.loc[:, use_cols] = fill_value df_in.to_csv(input_filename) df_par.loc[:, "tpl_filename"] = tpl_filename df_par.loc[:, "input_filename"] = input_filename @@ -2997,7 +3043,7 @@ def _write_direct_df_tpl( df_ti, direct_tpl_df = _build_parnames( df_ti, typ, zone_array, index_cols, use_cols, name, gpname, suffix, longnames, - direct=True, init_df=df, init_fname=in_filename + par_style="d", init_df=df, init_fname=in_filename ) if isinstance(direct_tpl_df.columns[0], str): header = True @@ -3062,9 +3108,9 @@ def _getxy_from_idx(df, get_xy, xy_in_idx, ij_in_idx): def _build_parnames(df, typ, zone_array, index_cols, use_cols, basename, - gpname, suffix, longnames, direct=False, init_df=None, - init_fname=None): - if direct: + gpname, suffix, longnames, par_style, init_df=None, + init_fname=None,fill_value=1.0): + if par_style == "d": assert init_df is not None direct_tpl_df = init_df.copy() if typ == 'constant': @@ -3096,13 +3142,12 @@ def _build_parnames(df, typ, zone_array, index_cols, use_cols, basename, else: ngpname = gpname df.loc[:, "pargp{}".format(use_col)] = ngpname - df.loc[:, "parval1_{0}".format(use_col)] = 1.0 + df.loc[:, "parval1_{0}".format(use_col)] = fill_value if typ == "constant": # one par for entire use_col column if longnames: - fmtr = "{0}_usecol:{1}" - if direct: - fmtr += "_direct" + fmtr = "pname:{0}_ptype:cn_usecol:{1}" + fmtr += "_pstyle:{0}".format(par_style) if suffix != "": fmtr += f"_{suffix}" else: @@ -3110,19 +3155,21 @@ def _build_parnames(df, typ, zone_array, index_cols, use_cols, basename, if suffix != "": fmtr += suffix df.loc[:, use_col] = fmtr.format(nname, use_col) - if direct: + if par_style == "d": _check_diff(init_df.loc[:, use_col].values, init_fname) df.loc[:, "parval1_{0}".format(use_col)] = init_df.loc[:, use_col][0] elif typ == "zone": # one par for each zone if longnames: - fmtr = "{0}_usecol:{1}" - if direct: + fmtr = "pname:{0}_ptype:zn_usecol:{1}" + if par_style == "d": # todo raise NotImplementedError( "list-based direct zone-type parameters not implemented" ) - fmtr += "_direct" + fmtr += "_pstyle:d" + else: + fmtr += "_pstyle:m" if zone_array is not None: fmtr += "_zone:{2}" # df.loc[:, use_col] += df.zval.apply( @@ -3149,9 +3196,8 @@ def _build_parnames(df, typ, zone_array, index_cols, use_cols, basename, elif typ == "grid": # one par for each index if longnames: - fmtr = "{0}_usecol:{1}" - if direct: - fmtr += "_direct" + fmtr = "pname:{0}_ptype:gr_usecol:{1}" + fmtr += "_pstyle:{0}".format(par_style) if zone_array is not None: fmtr += "_zone:{2}_{3}" else: @@ -3175,7 +3221,7 @@ def _build_parnames(df, typ, zone_array, index_cols, use_cols, basename, df.loc[:, use_col] = df.idx_strs.apply( lambda x: fmtr.format(nname, use_col, x) ) - if direct: + if par_style == "d": df.loc[:, f"parval1_{use_col}"] = init_df.loc[:, use_col].values else: raise Exception( @@ -3191,11 +3237,11 @@ def _build_parnames(df, typ, zone_array, index_cols, use_cols, basename, print(too_long) raise ValueError("_get_tpl_or_ins_df(): " "couldn't form short par names") - if direct: + if par_style == "d": direct_tpl_df.loc[:, use_col] = ( df.loc[:, use_col].apply(lambda x: "~ {0} ~".format(x)).values ) - if direct: + if par_style == "d": return df, direct_tpl_df return df @@ -3214,6 +3260,8 @@ def _get_tpl_or_ins_df( xy_in_idx=None, zero_based=True, gpname=None, + par_fill_value=1.0, + par_style="m" ): """ Private method to auto-generate parameter or obs names from tabular @@ -3247,6 +3295,7 @@ def _get_tpl_or_ins_df( zero_based (`boolean`): IMPORTANT - pass as False if `index_cols` are NOT zero-based indicies (e.g. MODFLOW row/cols). If False 1 with be subtracted from `index_cols`.= + par_fill_value (float): value to use as `parval1`,Default is 1.0 Returns: if `typ`==`obs`: pandas.DataFrame with index strings for setting up obs @@ -3283,7 +3332,8 @@ def _get_tpl_or_ins_df( if typ == "obs": return df_ti #################### RETURN if OBS df_ti = _build_parnames(df_ti, typ, zone_array, index_cols, use_cols, - name, gpname, suffix, longnames) + name, gpname, suffix, longnames,par_style, + fill_value=par_fill_value) return df_ti @@ -3299,7 +3349,7 @@ def write_array_tpl( fill_value=1.0, get_xy=None, input_filename=None, - par_style="multiplier", + par_style="m", ): """ write a template file for a 2D array. @@ -3317,7 +3367,7 @@ def write_array_tpl( fill_value: get_xy: input_filename: - par_style (`str`): either 'direct' or 'multiplier' + par_style (`str`): either 'd','a', or 'm' Returns: df (`pandas.DataFrame`): a dataframe with parameter information @@ -3345,7 +3395,7 @@ def write_array_tpl( ) par_style = par_style.lower() - if par_style == "direct": + if par_style == "d": if not os.path.exists(input_filename): raise Exception( "write_grid_tpl() error: couldn't find input file " @@ -3365,17 +3415,19 @@ def write_array_tpl( zone_org_arr = org_arr.copy() zone_org_arr[zone_array != zval] = np.NaN _check_diff(zone_org_arr, input_filename, zval) - elif par_style == "multiplier": + elif par_style == "m": org_arr = np.ones(shape) + elif par_style == "a": + org_arr = np.zeros(shape) else: raise Exception( "write_grid_tpl() error: unrecognized 'par_style' {0} ".format(par_style) - + "should be 'direct' or 'multiplier'" + + "should be 'd','a', or 'm'" ) def constant_namer(i, j): if longnames: - pname = "{0}_const_{1}".format(par_style, name) + pname = "pname:{1}_ptype:cn_pstyle:{0}".format(par_style, name) if suffix != "": pname += "_{0}".format(suffix) else: @@ -3389,7 +3441,7 @@ def zone_namer(i, j): if zone_array is not None: zval = zone_array[i, j] if longnames: - pname = "{0}_{1}_zone:{2}".format(par_style, name, zval) + pname = "pname:{1}_ptype:zn_pstyle:{0}_zone:{2}".format(par_style, name, zval) if suffix != "": pname += "_{0}".format(suffix) else: @@ -3400,7 +3452,7 @@ def zone_namer(i, j): def grid_namer(i, j): if longnames: - pname = "{0}_{1}_i:{2}_j:{3}".format(par_style, name, i, j) + pname = "pname:{1}_ptype:gr_pstyle:{0}_i:{2}_j:{3}".format(par_style, name, i, j) if get_xy is not None: pname += "_x:{0:0.2f}_y:{1:0.2f}".format(*get_xy([i, j])) if zone_array is not None: @@ -3460,13 +3512,16 @@ def grid_namer(i, j): df.loc[:, "y"] = yy if gpname is None: gpname = name - df.loc[:, "pargp"] = "{0}_{1}_{2}".format( - gpname, suffix.replace("_", ""), par_style + df.loc[:, "pargp"] = "{0}_{1}".format( + gpname, suffix.replace("_", "") ).rstrip("_") df.loc[:, "tpl_filename"] = tpl_filename df.loc[:, "input_filename"] = input_filename if input_filename is not None: - arr = np.ones(shape) + if par_style in ['m','d']: + arr = np.ones(shape) + elif par_style == 'a': + arr = np.zeros(shape) np.savetxt(input_filename, arr, fmt="%2.1f") return df From 5e0ee3b9c00745c355cbd30f061576b1bb5e8b01 Mon Sep 17 00:00:00 2001 From: Mike Fienen Date: Thu, 23 Sep 2021 13:58:30 -0500 Subject: [PATCH 3/7] another merge conflict --- .../modflow_setup/0_well_preprocessing.ipynb | 566 ++++- notebooks/modflow_setup/1_preprocessing.ipynb | 1925 +++++++++++++++-- .../2_build_model_from_YML.ipynb | 1062 ++++++++- 3 files changed, 3254 insertions(+), 299 deletions(-) diff --git a/notebooks/modflow_setup/0_well_preprocessing.ipynb b/notebooks/modflow_setup/0_well_preprocessing.ipynb index 7069abd..9910ade 100644 --- a/notebooks/modflow_setup/0_well_preprocessing.ipynb +++ b/notebooks/modflow_setup/0_well_preprocessing.ipynb @@ -2,8 +2,8 @@ "cells": [ { "cell_type": "code", - "execution_count": null, - "id": "e2c23525", + "execution_count": 1, + "id": "c5bbc91a", "metadata": {}, "outputs": [], "source": [ @@ -16,18 +16,55 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "80760d9d", + "execution_count": 2, + "id": "eccee367", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loading simulation...\n", + " loading simulation name file...\n", + " loading tdis package...\n", + " loading model gwf6...\n", + " loading package disv...\n", + "WARNING: Unable to resolve dimension of ('gwf6', 'disv', 'cell2d', 'cell2d', 'icvert') based on shape \"ncvert\".\n", + " skipping package ic...\n", + " skipping package npf...\n", + " skipping package rch...\n", + " skipping package riv...\n", + " skipping package drn...\n", + " loading package wel...\n", + " skipping package ghb...\n", + " skipping package obs...\n", + " skipping package oc...\n", + " skipping package sto...\n", + " loading model gwt6...\n", + " loading package disv...\n", + "WARNING: Unable to resolve dimension of ('gwt6', 'disv', 'cell2d', 'cell2d', 'icvert') based on shape \"ncvert\".\n", + " skipping package ic...\n", + " skipping package adv...\n", + " skipping package dsp...\n", + " skipping package mst...\n", + " skipping package ssm...\n", + " skipping package oc...\n", + " skipping package cnc...\n", + " skipping package obs...\n", + " skipping package gwf6-gwt6...\n", + " skipping package ims6...\n", + " skipping package ims6...\n" + ] + } + ], "source": [ "sim = fp.mf6.MFSimulation.load(sim_ws = '../../models/sgn_model_3layer/', load_only=['wel'])" ] }, { "cell_type": "code", - "execution_count": null, - "id": "6089737c", + "execution_count": 3, + "id": "70ce4a69", "metadata": {}, "outputs": [], "source": [ @@ -36,18 +73,212 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "dc495b7c", + "execution_count": 4, + "id": "5459730c", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "rec.array([((0, 4736), 0. , 'well-p1_ln\\x00'),\n", + " ((0, 4735), 0. , 'well-p2_ln\\x00'),\n", + " ((0, 4742), 0. , 'well-p3_ln\\x00'),\n", + " ((0, 4739), 0. , 'well-p4_ln\\x00'),\n", + " ((0, 5138), 0. , 'well-p5_ln\\x00'),\n", + " ((0, 5561), 0. , 'well-p6_ln\\x00'),\n", + " ((0, 5991), 0. , 'well-p7_ln\\x00'),\n", + " ((0, 5977), 0. , 'well-p8_ln\\x00'),\n", + " ((0, 5547), 0. , 'well-p9_ln\\x00'),\n", + " ((0, 5544), 0. , 'well-p10_ln\\x00'),\n", + " ((0, 5527), 0. , 'well-p11_ln\\x00'),\n", + " ((0, 10012), 0. , 'well-r1_ln\\x00'),\n", + " ((0, 10025), 0. , 'well-r2_ln\\x00'),\n", + " ((0, 10543), 0. , 'well-r3_ln\\x00'),\n", + " ((0, 10555), 0. , 'well-r4_ln\\x00'),\n", + " ((0, 10568), 0. , 'well-r5_ln\\x00'),\n", + " ((0, 11076), 0. , 'well-r6_ln\\x00'),\n", + " ((0, 11083), 0. , 'well-r7_ln\\x00'),\n", + " ((0, 11096), 0. , 'well-r8_ln\\x00'),\n", + " ((0, 11595), 0. , 'well-r9_ln\\x00'),\n", + " ((0, 11602), 0. , 'well-r10_ln\\x00'),\n", + " ((0, 5112), 0. , 'well-p12_ln\\x00'),\n", + " ((0, 12784), 0. , 'well-s\\x00'),\n", + " ((0, 13252), 0. , 'well-p1_ex\\x00'),\n", + " ((0, 13253), 0. , 'well-p2_ex\\x00'),\n", + " ((0, 13253), 0. , 'well-p3_ex\\x00'),\n", + " ((0, 13254), 0. , 'well-p4_ex\\x00'),\n", + " ((0, 14502), 0. , 'well-r1_ex\\x00'),\n", + " ((0, 14505), 0. , 'well-r2_ex\\x00'),\n", + " ((0, 14505), 0. , 'well-r3_ex\\x00'),\n", + " ((0, 14504), 0. , 'well-r4_ex\\x00'),\n", + " ((0, 14507), 0. , 'well-r5_ex\\x00'),\n", + " ((0, 13676), 0. , 'well-p1_sky\\x00'),\n", + " ((0, 13679), 0. , 'well-p2_sky\\x00'),\n", + " ((0, 13680), 0. , 'well-p3_sky\\x00'),\n", + " ((0, 13245), 0. , 'well-p4_sky\\x00'),\n", + " ((0, 14486), 0. , 'well-r1_sky\\x00'),\n", + " ((0, 14855), 0. , 'well-r2_sky\\x00'),\n", + " ((0, 14854), 0. , 'well-r3_sky\\x00'),\n", + " ((0, 14857), 0. , 'well-r4_sky\\x00'),\n", + " ((0, 8333), 0. , 'well-b\\x00'),\n", + " ((0, 8330), 0. , 'well-a\\x00'),\n", + " ((0, 9875), 0. , 'well-pc2_ams\\x00'),\n", + " ((0, 10664), 0. , 'well-prof_p2\\x00'),\n", + " ((0, 10948), 0. , 'well-pc3_ams\\x00'),\n", + " ((0, 12783), 0. , 'well-p1_s1\\x00'),\n", + " ((0, 12783), 0. , 'well-p2_s1\\x00'),\n", + " ((0, 13230), 0. , 'well-p3_s1\\x00'),\n", + " ((0, 13230), 0. , 'well-p4_s1\\x00'),\n", + " ((0, 14082), 0. , 'well-r1_s1\\x00'),\n", + " ((0, 14082), 0. , 'well-r2_s1\\x00'),\n", + " ((0, 14080), 0. , 'well-r3_s1\\x00'),\n", + " ((0, 14080), 0. , 'well-r4_s1\\x00'),\n", + " ((0, 2196), -0.005 , 'well-636\\x00'),\n", + " ((2, 2196), -0.005 , 'well-636\\x00'),\n", + " ((0, 1936), -0.005 , 'well-637\\x00'),\n", + " ((2, 1936), -0.005 , 'well-637\\x00'),\n", + " ((0, 2217), -0.001 , 'well-808\\x00'),\n", + " ((0, 1796), -0.02 , 'well-826\\x00'),\n", + " ((2, 1796), -0.02 , 'well-826\\x00'),\n", + " ((0, 1438), -0.0214, 'well-828\\x00'),\n", + " ((0, 2672), -0.003 , 'well-830\\x00'),\n", + " ((0, 1710), -0.02 , 'well-832\\x00'),\n", + " ((0, 1623), -0.05 , 'well-833\\x00'),\n", + " ((2, 1623), -0.05 , 'well-833\\x00'),\n", + " ((0, 417), 0. , 'well-838\\x00'),\n", + " ((0, 3205), 0. , 'well-878\\x00'),\n", + " ((0, 5473), -0.005 , 'well-2503\\x00'),\n", + " ((0, 5878), 0. , 'well-2505\\x00'),\n", + " ((0, 1410), -0.01 , 'well-2550\\x00'),\n", + " ((0, 1581), -0.008 , 'well-2551\\x00'),\n", + " ((0, 1498), -0.012 , 'well-2559\\x00'),\n", + " ((0, 477), -0.0225, 'well-4740\\x00'),\n", + " ((0, 477), -0.0225, 'well-4741\\x00'),\n", + " ((0, 3841), 0. , 'well-5196\\x00'),\n", + " ((0, 6599), -0.008 , 'well-21/5\\x00'),\n", + " ((2, 6599), -0.008 , 'well-21/5\\x00'),\n", + " ((0, 6137), -0.008 , 'well-21/6\\x00'),\n", + " ((2, 6137), -0.008 , 'well-21/6\\x00'),\n", + " ((0, 7622), -0.008 , 'well-21/7\\x00'),\n", + " ((0, 655), -0.0121, 'well-24/8\\x00'),\n", + " ((2, 655), -0.0121, 'well-24/8\\x00'),\n", + " ((0, 563), -0.0121, 'well-24/9\\x00'),\n", + " ((2, 563), -0.0121, 'well-24/9\\x00'),\n", + " ((0, 735), -0.0121, 'well-24/10\\x00'),\n", + " ((2, 735), -0.0121, 'well-24/10\\x00'),\n", + " ((0, 996), -0.0121, 'well-24/11\\x00'),\n", + " ((0, 732), -0.0121, 'well-24/12\\x00'),\n", + " ((2, 732), -0.0121, 'well-24/12\\x00'),\n", + " ((0, 16479), 0. , 'well-5352/1-2\\x00'),\n", + " ((0, 2459), -0.0104, 'well-19/14\\x00'),\n", + " ((2, 2459), -0.0104, 'well-19/14\\x00'),\n", + " ((0, 2299), -0.0104, 'well-19/15\\x00'),\n", + " ((2, 2299), -0.0104, 'well-19/15\\x00'),\n", + " ((0, 7624), -0.008 , 'well-21/14\\x00'),\n", + " ((2, 7624), -0.008 , 'well-21/14\\x00'),\n", + " ((0, 8690), -0.008 , 'well-21/16\\x00'),\n", + " ((2, 8690), -0.008 , 'well-21/16\\x00'),\n", + " ((0, 907), -0.0121, 'well-24/13\\x00'),\n", + " ((2, 907), -0.0121, 'well-24/13\\x00'),\n", + " ((0, 1173), -0.0121, 'well-24/14\\x00'),\n", + " ((2, 1173), -0.0121, 'well-24/14\\x00'),\n", + " ((0, 560), -0.0121, 'well-24/19\\x00'),\n", + " ((2, 560), -0.0121, 'well-24/19\\x00'),\n", + " ((0, 1269), -0.0121, 'well-24/20\\x00'),\n", + " ((2, 1269), -0.0121, 'well-24/20\\x00'),\n", + " ((0, 14481), 0. , 'well-5257/1\\x00'),\n", + " ((0, 14855), 0. , 'well-5257/2\\x00'),\n", + " ((0, 7560), 0. , 'well-5426/p1-p2\\x00'),\n", + " ((0, 7565), 0. , 'well-5426/r1-r2-r3'),\n", + " ((0, 1361), -0.008 , 'well-5600/p1\\x00'),\n", + " ((0, 1448), -0.008 , 'well-5600/p2\\x00'),\n", + " ((0, 1534), -0.008 , 'well-5600/p3\\x00'),\n", + " ((0, 1530), 0.006 , 'well-5600/r1\\x00'),\n", + " ((0, 1530), 0.006 , 'well-5600/r2\\x00'),\n", + " ((0, 1620), 0.006 , 'well-5600/r3\\x00'),\n", + " ((0, 1620), 0.006 , 'well-5600/r4\\x00'),\n", + " ((0, 1792), 0.024 , 'well-5600/sca\\x00'),\n", + " ((0, 1612), -0.0214, 'well-5636/1\\x00'),\n", + " ((0, 1351), 0.0214, 'well-5636/2\\x00'),\n", + " ((0, 1522), 0.0214, 'well-5636/3\\x00'),\n", + " ((0, 1793), -0.006 , 'well-5686/p1\\x00'),\n", + " ((0, 1793), -0.006 , 'well-5686/p2\\x00'),\n", + " ((2, 1793), -0.006 , 'well-5686/p2\\x00'),\n", + " ((0, 1707), 0.006 , 'well-5686/r1\\x00'),\n", + " ((0, 1793), 0.006 , 'well-5686/r2\\x00'),\n", + " ((0, 1792), 0.012 , 'well-5686/sca\\x00'),\n", + " ((0, 1879), 0. , 'well-5700/p1\\x00'),\n", + " ((0, 1879), 0. , 'well-5700/r1\\x00'),\n", + " ((0, 1793), 0.008 , 'well-5700/sca\\x00'),\n", + " ((0, 4905), 0. , 'well-5740/p1\\x00'),\n", + " ((0, 4531), 0. , 'well-5740/p2\\x00'),\n", + " ((0, 4532), 0. , 'well-5740/p3\\x00'),\n", + " ((0, 4533), 0. , 'well-5740/p4\\x00'),\n", + " ((0, 4905), 0. , 'well-5740/p5\\x00'),\n", + " ((0, 4906), 0. , 'well-5740/p6\\x00'),\n", + " ((0, 7146), 0. , 'well-5740/r1\\x00'),\n", + " ((0, 7146), 0. , 'well-5740/r2\\x00'),\n", + " ((0, 7671), 0. , 'well-5740/r3\\x00'),\n", + " ((0, 7147), 0. , 'well-5740/r4\\x00'),\n", + " ((0, 7672), 0. , 'well-5740/r5\\x00'),\n", + " ((0, 7150), 0. , 'well-5740/r6\\x00'),\n", + " ((0, 7150), 0. , 'well-5740/r7\\x00'),\n", + " ((0, 7149), 0. , 'well-5740/r8\\x00'),\n", + " ((0, 12784), 0.006 , 'well-5883/sca\\x00'),\n", + " ((0, 1571), 0. , 'well-5884/2\\x00'),\n", + " ((0, 1571), 0. , 'well-5884/3\\x00'),\n", + " ((0, 370), 0. , 'well-80/1\\x00'),\n", + " ((0, 370), 0. , 'well-80/2\\x00'),\n", + " ((0, 460), 0. , 'well-80/3\\x00'),\n", + " ((0, 460), 0. , 'well-80/4\\x00'),\n", + " ((0, 461), 0. , 'well-80/5\\x00'),\n", + " ((0, 461), 0. , 'well-80/6\\x00'),\n", + " ((0, 461), 0. , 'well-80/7\\x00'),\n", + " ((0, 462), 0. , 'well-80/8\\x00'),\n", + " ((0, 1674), 0. , 'well-82/1\\x00'),\n", + " ((0, 1759), 0. , 'well-82/2\\x00'),\n", + " ((0, 1674), 0. , 'well-82/3\\x00'),\n", + " ((0, 1760), 0. , 'well-82/4\\x00'),\n", + " ((0, 5077), 0. , 'well-sc_bonf\\x00'),\n", + " ((0, 17298), 0. , 'well-6\\x00'),\n", + " ((0, 17035), 0. , 'well-77\\x00'),\n", + " ((0, 17204), 0. , 'well-78\\x00'),\n", + " ((0, 17117), 0. , 'well-81\\x00'),\n", + " ((0, 520), -0.0035, 'well-5814/1\\x00'),\n", + " ((0, 520), 0. , 'well-5814/2\\x00'),\n", + " ((0, 11332), 0. , 'well-p3_s2\\x00'),\n", + " ((0, 11332), 0. , 'well-p2_s2\\x00'),\n", + " ((0, 11332), 0. , 'well-p1_s2\\x00'),\n", + " ((0, 12319), 0. , 'well-r1_s2\\x00'),\n", + " ((0, 12319), 0. , 'well-r2_s2\\x00'),\n", + " ((0, 12319), 0. , 'well-r3_s2\\x00'),\n", + " ((0, 12318), 0. , 'well-r4_s2\\x00'),\n", + " ((0, 7584), -0.0095, 'well-19/16\\x00'),\n", + " ((2, 7584), -0.0095, 'well-19/16\\x00'),\n", + " ((0, 7039), -0.0095, 'well-19/18\\x00'),\n", + " ((2, 7039), -0.0095, 'well-19/18\\x00'),\n", + " ((0, 7590), -0.0095, 'well-19/19\\x00'),\n", + " ((2, 7590), -0.0095, 'well-19/19\\x00'),\n", + " ((0, 7057), -0.0095, 'well-19/20\\x00'),\n", + " ((2, 7057), -0.0095, 'well-19/20\\x00'),\n", + " ((0, 5637), -0.0095, 'well-19/21\\x00'),\n", + " ((2, 5637), -0.0095, 'well-19/21\\x00')],\n", + " dtype=[('cellid', 'O'), ('q', '\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
cellidqboundnamelaytoplaybotlayercelllaymidptrootname
0(0, 4736)0.0000p1_ln__0104.77359069.4628750473617.655357p1_ln
1(0, 4735)0.0000p2_ln__0104.72315269.4864880473517.618332p2_ln
2(0, 4742)0.0000p3_ln__0104.67920769.4591980474217.610004p3_ln
3(0, 4739)0.0000p4_ln__0104.63341569.5174030473917.558006p4_ln
4(0, 5138)0.0000p5_ln__0104.63870269.4211880513817.608757p5_ln
..............................
178(2, 7590)-0.009519/19__251.490337-8.5096632759030.00000019/19
179(0, 7057)-0.009519/20__0104.02419367.2917560705718.36621919/20
180(2, 7057)-0.009519/20__251.473099-8.5269012705730.00000019/20
181(0, 5637)-0.009519/21__0103.00206868.4939270563717.25407019/21
182(2, 5637)-0.009519/21__251.661217-8.3387832563730.00000019/21
\n", + "

183 rows × 9 columns

\n", + "" + ], + "text/plain": [ + " cellid q boundname laytop laybot layer cell \\\n", + "0 (0, 4736) 0.0000 p1_ln__0 104.773590 69.462875 0 4736 \n", + "1 (0, 4735) 0.0000 p2_ln__0 104.723152 69.486488 0 4735 \n", + "2 (0, 4742) 0.0000 p3_ln__0 104.679207 69.459198 0 4742 \n", + "3 (0, 4739) 0.0000 p4_ln__0 104.633415 69.517403 0 4739 \n", + "4 (0, 5138) 0.0000 p5_ln__0 104.638702 69.421188 0 5138 \n", + ".. ... ... ... ... ... ... ... \n", + "178 (2, 7590) -0.0095 19/19__2 51.490337 -8.509663 2 7590 \n", + "179 (0, 7057) -0.0095 19/20__0 104.024193 67.291756 0 7057 \n", + "180 (2, 7057) -0.0095 19/20__2 51.473099 -8.526901 2 7057 \n", + "181 (0, 5637) -0.0095 19/21__0 103.002068 68.493927 0 5637 \n", + "182 (2, 5637) -0.0095 19/21__2 51.661217 -8.338783 2 5637 \n", + "\n", + " laymidpt rootname \n", + "0 17.655357 p1_ln \n", + "1 17.618332 p2_ln \n", + "2 17.610004 p3_ln \n", + "3 17.558006 p4_ln \n", + "4 17.608757 p5_ln \n", + ".. ... ... \n", + "178 30.000000 19/19 \n", + "179 18.366219 19/20 \n", + "180 30.000000 19/20 \n", + "181 17.254070 19/21 \n", + "182 30.000000 19/21 \n", + "\n", + "[183 rows x 9 columns]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "spd" ] }, { "cell_type": "code", - "execution_count": null, - "id": "09d82a93", + "execution_count": 14, + "id": "77f90537", "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/modflow_setup/1_preprocessing.ipynb b/notebooks/modflow_setup/1_preprocessing.ipynb index 5e58f63..d8d8c1c 100644 --- a/notebooks/modflow_setup/1_preprocessing.ipynb +++ b/notebooks/modflow_setup/1_preprocessing.ipynb @@ -2,8 +2,8 @@ "cells": [ { "cell_type": "code", - "execution_count": null, - "id": "67d0c037", + "execution_count": 1, + "id": "ecbb7115", "metadata": {}, "outputs": [], "source": [ @@ -22,7 +22,7 @@ }, { "cell_type": "markdown", - "id": "02a58ec8", + "id": "070f0869", "metadata": {}, "source": [ "# Let's check out the proposed domain to get some coordiante information" @@ -30,8 +30,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "2731b2fd", + "execution_count": 2, + "id": "78dac6b7", "metadata": {}, "outputs": [], "source": [ @@ -40,8 +40,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "63ed9177", + "execution_count": 3, + "id": "2fa1b859", "metadata": {}, "outputs": [], "source": [ @@ -50,7 +50,7 @@ }, { "cell_type": "markdown", - "id": "ab335922", + "id": "471b54dc", "metadata": {}, "source": [ "### what's the projection?" @@ -58,17 +58,41 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "5d7fa3f2", - "metadata": {}, - "outputs": [], + "execution_count": 4, + "id": "752d3c21", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\n", + "Name: Monte Mario / Italy zone 1\n", + "Axis Info [cartesian]:\n", + "- X[east]: Easting (metre)\n", + "- Y[north]: Northing (metre)\n", + "Area of Use:\n", + "- name: Italy - onshore and offshore - west of 12°E.\n", + "- bounds: (5.94, 36.53, 12.0, 47.04)\n", + "Coordinate Operation:\n", + "- name: Italy zone 1\n", + "- method: Transverse Mercator\n", + "Datum: Monte Mario\n", + "- Ellipsoid: International 1924\n", + "- Prime Meridian: Greenwich" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "domain.crs" ] }, { "cell_type": "markdown", - "id": "493ee4a7", + "id": "1843f875", "metadata": {}, "source": [ "### and what are the bounding points? We can navigate this using min and max x and y points because we know the rotation is anticlockwise" @@ -76,8 +100,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "9fc7d696", + "execution_count": 5, + "id": "240cd48a", "metadata": {}, "outputs": [], "source": [ @@ -90,10 +114,33 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "dcf974f0", - "metadata": {}, - "outputs": [], + "execution_count": 6, + "id": "f05f197b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "ax = domain.plot(color=None)\n", "ax.plot(xul,yul, 'x')\n", @@ -104,7 +151,7 @@ }, { "cell_type": "markdown", - "id": "5e198542", + "id": "2e72ec9c", "metadata": {}, "source": [ "### calculate the angle of rotation from upper left and top vertices" @@ -112,8 +159,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "7debce4b", + "execution_count": 7, + "id": "310dbfb5", "metadata": {}, "outputs": [], "source": [ @@ -122,20 +169,42 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "515cec1d", + "execution_count": 8, + "id": "9883569d", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "0.2419218955996804" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "opp_over_hyp" ] }, { "cell_type": "code", - "execution_count": null, - "id": "b88e2c2b", + "execution_count": 9, + "id": "47ec2577", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "14.000000000000748" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "rot_angle = np.arcsin(opp_over_hyp)\n", "rot_angle = float(rot_angle * 180/np.pi)\n", @@ -144,7 +213,7 @@ }, { "cell_type": "markdown", - "id": "d1f56317", + "id": "99b6ee59", "metadata": {}, "source": [ "# calculate the total length and width" @@ -152,8 +221,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "9db83bba", + "execution_count": 10, + "id": "b5569266", "metadata": {}, "outputs": [], "source": [ @@ -163,7 +232,7 @@ }, { "cell_type": "markdown", - "id": "3bf0d903", + "id": "5129b580", "metadata": {}, "source": [ "### check out the recharge and geology" @@ -171,10 +240,21 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "69769458", + "execution_count": 11, + "id": "38d061cd", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['DESCR', 'RCH_mmy', 'geometry'], dtype='object')" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "rch = gp.read_file(datapath / 'shp' / 'Recharge_4.shp')\n", "rch.columns" @@ -182,17 +262,40 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "e44b81b5", - "metadata": {}, - "outputs": [], + "execution_count": 12, + "id": "73c935d7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "rch.plot(column = 'RCH_mmy', legend=True)\n" ] }, { "cell_type": "markdown", - "id": "99dbdafe", + "id": "02ff0c76", "metadata": {}, "source": [ "### it's easier if we burn this into a raster for `modflow-setup` to handle ATM" @@ -200,8 +303,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "7dcd4fbb", + "execution_count": 13, + "id": "bdee4d2e", "metadata": {}, "outputs": [], "source": [ @@ -213,8 +316,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "a5253122", + "execution_count": 14, + "id": "9c746ea1", "metadata": {}, "outputs": [], "source": [ @@ -232,10 +335,33 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "0c49e83d", - "metadata": {}, - "outputs": [], + "execution_count": 15, + "id": "0cfb508d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "# confirm we wrote this ok\n", "with rasterio.open(datapath/ 'raster' / 'rch.tif') as src:\n", @@ -247,7 +373,7 @@ }, { "cell_type": "markdown", - "id": "01beb655", + "id": "ca1eb43e", "metadata": {}, "source": [ "### now let's check out the geology" @@ -255,10 +381,21 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "f8ec10bf", + "execution_count": 16, + "id": "9d9c1209", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['COD', 'LITOLOGIA', 'geometry'], dtype='object')" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "geology = gp.read_file(datapath / 'shp' / 'Geology_250000_clip.shp')\n", "geology.columns" @@ -266,17 +403,40 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "6cbf05c8", - "metadata": {}, - "outputs": [], + "execution_count": 17, + "id": "120ff629", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "geology.plot(column = 'LITOLOGIA', legend=True)" ] }, { "cell_type": "markdown", - "id": "6fd6d676", + "id": "0603091f", "metadata": {}, "source": [ "### we can set starting Kh values as: \n", @@ -286,8 +446,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "38de76a4", + "execution_count": 18, + "id": "007edf6c", "metadata": {}, "outputs": [], "source": [ @@ -299,18 +459,41 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "34d628d4", - "metadata": {}, - "outputs": [], + "execution_count": 19, + "id": "c90b9dab", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "geology.plot(column='k', legend=True)" ] }, { "cell_type": "code", - "execution_count": null, - "id": "74e79349", + "execution_count": 20, + "id": "2fb6ed07", "metadata": {}, "outputs": [], "source": [ @@ -328,10 +511,33 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "26025438", - "metadata": {}, - "outputs": [], + "execution_count": 21, + "id": "996aca1e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "# confirm we wrote this ok\n", "with rasterio.open(datapath/ 'raster' / 'k_field0.tif') as src:\n", @@ -343,7 +549,7 @@ }, { "cell_type": "markdown", - "id": "9a41f856", + "id": "0f5fdd17", "metadata": {}, "source": [ "### for now, we will assign constant values to layers 2 and 3" @@ -351,8 +557,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "5b895118", + "execution_count": 22, + "id": "b2167dcc", "metadata": {}, "outputs": [], "source": [ @@ -362,8 +568,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "b9b597be", + "execution_count": 23, + "id": "6103c598", "metadata": {}, "outputs": [], "source": [ @@ -376,7 +582,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8bdc99fd", + "id": "7bc951be", "metadata": {}, "outputs": [], "source": [] @@ -384,14 +590,14 @@ { "cell_type": "code", "execution_count": null, - "id": "82363f35", + "id": "1b8ee70a", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", - "id": "096a8e01", + "id": "03ee5b2a", "metadata": {}, "source": [ "### and let's see where the river is" @@ -399,10 +605,57 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "eed3d91b", - "metadata": {}, - "outputs": [], + "execution_count": 24, + "id": "b49bd622", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
IdStagegeometry
00103.0LINESTRING (1519819.286 5034332.958, 1519820.9...
\n", + "
" + ], + "text/plain": [ + " Id Stage geometry\n", + "0 0 103.0 LINESTRING (1519819.286 5034332.958, 1519820.9..." + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "riv = gp.read_file(datapath / 'shp' / 'River_Lambro.shp')\n", "riv" @@ -410,10 +663,33 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "97befd29", - "metadata": {}, - "outputs": [], + "execution_count": 25, + "id": "77d1c4f5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "ax = geology.plot(column='k', legend=True)\n", "riv.plot(ax=ax)" @@ -421,7 +697,7 @@ }, { "cell_type": "markdown", - "id": "2b134f72", + "id": "b580d0e1", "metadata": {}, "source": [ "### we need to add some information to the river" @@ -429,7 +705,7 @@ }, { "cell_type": "markdown", - "id": "56bde4a2", + "id": "f95d9f4d", "metadata": {}, "source": [ "#### first break up into a handful of segments" @@ -437,8 +713,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "9c158997", + "execution_count": 26, + "id": "a61b543e", "metadata": {}, "outputs": [], "source": [ @@ -447,8 +723,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "094f31a2", + "execution_count": 27, + "id": "fd2b2045", "metadata": {}, "outputs": [], "source": [ @@ -462,8 +738,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "582af277", + "execution_count": 28, + "id": "7ac7feb3", "metadata": {}, "outputs": [], "source": [ @@ -482,8 +758,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "6783d0ac", + "execution_count": 29, + "id": "76ea68bc", "metadata": {}, "outputs": [], "source": [ @@ -494,17 +770,40 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "2d54082d", - "metadata": {}, - "outputs": [], + "execution_count": 30, + "id": "4e8be491", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "riv_divided.plot(column='segname', legend=True)" ] }, { "cell_type": "markdown", - "id": "26d54537", + "id": "cffaf6a6", "metadata": {}, "source": [ "#### now set up routing" @@ -512,8 +811,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "0929e1c6", + "execution_count": 31, + "id": "e97addc1", "metadata": {}, "outputs": [], "source": [ @@ -527,18 +826,162 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "c5aef3ec", - "metadata": {}, - "outputs": [], + "execution_count": 32, + "id": "16615a4c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
geometrysegnamefrom_idto_idstreamwid
0LINESTRING (1519819.286 5034482.958, 1519819.2...10010100215
1LINESTRING (1519937.256 5033937.494, 1519964.7...10021001100315
2LINESTRING (1520189.139 5033590.360, 1520233.5...10031002100415
3LINESTRING (1520433.615 5033207.666, 1520420.9...10041003100515
4LINESTRING (1520646.129 5033156.866, 1520692.6...10051004100615
5LINESTRING (1520884.254 5032717.868, 1520880.0...10061005100715
6LINESTRING (1520877.481 5032147.086, 1520871.5...10071006100815
7LINESTRING (1520909.654 5031715.286, 1520910.5...10081007100915
8LINESTRING (1521080.681 5031320.061, 1521118.7...10091008101015
9LINESTRING (1521434.589 5030483.891, 1521474.3...10101009015
\n", + "
" + ], + "text/plain": [ + " geometry segname from_id to_id \\\n", + "0 LINESTRING (1519819.286 5034482.958, 1519819.2... 1001 0 1002 \n", + "1 LINESTRING (1519937.256 5033937.494, 1519964.7... 1002 1001 1003 \n", + "2 LINESTRING (1520189.139 5033590.360, 1520233.5... 1003 1002 1004 \n", + "3 LINESTRING (1520433.615 5033207.666, 1520420.9... 1004 1003 1005 \n", + "4 LINESTRING (1520646.129 5033156.866, 1520692.6... 1005 1004 1006 \n", + "5 LINESTRING (1520884.254 5032717.868, 1520880.0... 1006 1005 1007 \n", + "6 LINESTRING (1520877.481 5032147.086, 1520871.5... 1007 1006 1008 \n", + "7 LINESTRING (1520909.654 5031715.286, 1520910.5... 1008 1007 1009 \n", + "8 LINESTRING (1521080.681 5031320.061, 1521118.7... 1009 1008 1010 \n", + "9 LINESTRING (1521434.589 5030483.891, 1521474.3... 1010 1009 0 \n", + "\n", + " streamwid \n", + "0 15 \n", + "1 15 \n", + "2 15 \n", + "3 15 \n", + "4 15 \n", + "5 15 \n", + "6 15 \n", + "7 15 \n", + "8 15 \n", + "9 15 " + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "riv_divided" ] }, { "cell_type": "code", - "execution_count": null, - "id": "3e4ebd25", + "execution_count": 33, + "id": "79a1ee82", "metadata": {}, "outputs": [], "source": [ @@ -547,7 +990,7 @@ }, { "cell_type": "markdown", - "id": "46880d41", + "id": "7ae26bfd", "metadata": {}, "source": [ "## let's take a quick look at the raster data" @@ -555,10 +998,33 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "582fa845", - "metadata": {}, - "outputs": [], + "execution_count": 34, + "id": "fd656156", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "with rasterio.open(datapath/ 'raster' / 'DTM_domain.tif') as src:\n", " modtop = src.read(1)\n", @@ -568,10 +1034,33 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "d9b11841", - "metadata": {}, - "outputs": [], + "execution_count": 35, + "id": "a6aceac9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "with rasterio.open(datapath/ 'raster' / 'Bott_L1_fix.tif') as src:\n", " bot1 = src.read(1)\n", @@ -581,10 +1070,33 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "af5da708", - "metadata": {}, - "outputs": [], + "execution_count": 36, + "id": "bdcacc96", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "with rasterio.open(datapath/ 'raster' / 'Bott_L2_fix.tif') as src:\n", " bot2 = src.read(1)\n", @@ -594,7 +1106,7 @@ }, { "cell_type": "markdown", - "id": "7b27d0b7", + "id": "bfe4f27a", "metadata": {}, "source": [ "### we need a raster of the bottom of layer 2 kicked down by 60m to make the bottom of layer 3" @@ -602,8 +1114,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "b27aeef1", + "execution_count": 37, + "id": "3046f53c", "metadata": {}, "outputs": [], "source": [ @@ -616,10 +1128,33 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "19c1449b", - "metadata": {}, - "outputs": [], + "execution_count": 38, + "id": "4ff6b8b6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "# now subtract 60m from layer 2 and write out layer 3\n", "bot3 = bot2-60.\n", @@ -629,8 +1164,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "f1d86397", + "execution_count": 39, + "id": "59294334", "metadata": {}, "outputs": [], "source": [ @@ -641,7 +1176,7 @@ }, { "cell_type": "markdown", - "id": "d866adeb", + "id": "07f3445d", "metadata": {}, "source": [ "### now a quick check reading back in to make sure that worked" @@ -649,10 +1184,33 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "f65117f1", - "metadata": {}, - "outputs": [], + "execution_count": 40, + "id": "2b221b25", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "with rasterio.open(datapath/ 'raster' / 'Bott_L3_fix.tif') as src:\n", " bot3 = src.read(1)\n", @@ -662,7 +1220,7 @@ }, { "cell_type": "markdown", - "id": "72a2b819", + "id": "05573cbf", "metadata": {}, "source": [ "### we need a csv file for the well package" @@ -670,8 +1228,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "f6ff554a", + "execution_count": 41, + "id": "8abae0b7", "metadata": {}, "outputs": [], "source": [ @@ -680,10 +1238,33 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "45a77a42", - "metadata": {}, - "outputs": [], + "execution_count": 42, + "id": "524ea6c6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "ax = domain.plot(facecolor=\"none\", edgecolor='black')\n", "wells.plot( ax=ax)" @@ -691,18 +1272,29 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "51093e2e", + "execution_count": 43, + "id": "e481ba60", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['WellName', 'X', 'Y', 'TopLayer', 'BottomLaye', 'DefaultQ', 'geometry'], dtype='object')" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "wells.columns" ] }, { "cell_type": "code", - "execution_count": null, - "id": "10250e0e", + "execution_count": 44, + "id": "6fd2378a", "metadata": {}, "outputs": [], "source": [ @@ -711,10 +1303,128 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "492e2783", - "metadata": {}, - "outputs": [], + "execution_count": 45, + "id": "7b35b4fc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
cellidqboundnamelaytoplaybotlayercelllaymidptrootname
0(0, 4736)0.0p1_ln__0104.77359069.4628750473617.655357p1_ln
1(0, 4735)0.0p2_ln__0104.72315269.4864880473517.618332p2_ln
2(0, 4742)0.0p3_ln__0104.67920769.4591980474217.610004p3_ln
3(0, 4739)0.0p4_ln__0104.63341569.5174030473917.558006p4_ln
4(0, 5138)0.0p5_ln__0104.63870269.4211880513817.608757p5_ln
\n", + "
" + ], + "text/plain": [ + " cellid q boundname laytop laybot layer cell laymidpt \\\n", + "0 (0, 4736) 0.0 p1_ln__0 104.773590 69.462875 0 4736 17.655357 \n", + "1 (0, 4735) 0.0 p2_ln__0 104.723152 69.486488 0 4735 17.618332 \n", + "2 (0, 4742) 0.0 p3_ln__0 104.679207 69.459198 0 4742 17.610004 \n", + "3 (0, 4739) 0.0 p4_ln__0 104.633415 69.517403 0 4739 17.558006 \n", + "4 (0, 5138) 0.0 p5_ln__0 104.638702 69.421188 0 5138 17.608757 \n", + "\n", + " rootname \n", + "0 p1_ln \n", + "1 p2_ln \n", + "2 p3_ln \n", + "3 p4_ln \n", + "4 p5_ln " + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "well_metadata = pd.read_csv(datapath / 'wells_with_elev.dat', index_col=0)\n", "well_metadata.head()" @@ -722,17 +1432,123 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "8a38b071", - "metadata": {}, - "outputs": [], + "execution_count": 46, + "id": "ac224869", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
WellNameXYTopLayerBottomLayeDefaultQgeometry
0p1_ln1.520070e+065.032527e+06110.0POINT (1520069.925 5032526.545)
1p2_ln1.520053e+065.032516e+06110.0POINT (1520053.252 5032516.080)
2p3_ln1.520072e+065.032513e+06110.0POINT (1520071.627 5032513.148)
3p4_ln1.520033e+065.032496e+06110.0POINT (1520033.339 5032495.666)
4p5_ln1.520070e+065.032489e+06110.0POINT (1520070.059 5032488.559)
\n", + "
" + ], + "text/plain": [ + " WellName X Y TopLayer BottomLaye DefaultQ \\\n", + "0 p1_ln 1.520070e+06 5.032527e+06 1 1 0.0 \n", + "1 p2_ln 1.520053e+06 5.032516e+06 1 1 0.0 \n", + "2 p3_ln 1.520072e+06 5.032513e+06 1 1 0.0 \n", + "3 p4_ln 1.520033e+06 5.032496e+06 1 1 0.0 \n", + "4 p5_ln 1.520070e+06 5.032489e+06 1 1 0.0 \n", + "\n", + " geometry \n", + "0 POINT (1520069.925 5032526.545) \n", + "1 POINT (1520053.252 5032516.080) \n", + "2 POINT (1520071.627 5032513.148) \n", + "3 POINT (1520033.339 5032495.666) \n", + "4 POINT (1520070.059 5032488.559) " + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "wells.head()" ] }, { "cell_type": "markdown", - "id": "32117d28", + "id": "d9dc819d", "metadata": {}, "source": [ "#### trim out the non pumping wells" @@ -740,20 +1556,42 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "3b757c52", + "execution_count": 47, + "id": "244e4b7e", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "183" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "len(well_metadata)" ] }, { "cell_type": "code", - "execution_count": null, - "id": "90bba90e", + "execution_count": 48, + "id": "e6436555", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "78" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "well_metadata = well_metadata.loc[well_metadata.q != 0]\n", "len(well_metadata)" @@ -761,18 +1599,136 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "df6b1a27", - "metadata": {}, - "outputs": [], + "execution_count": 49, + "id": "daca159d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
cellidqboundnamelaytoplaybotlayercelllaymidptrootname
53(0, 2196)-0.005636__0110.00199965.3533100219622.324345636
54(2, 2196)-0.005636__249.060505-10.9394952219630.000000636
55(0, 1936)-0.005637__0110.50396065.5599210193622.472019637
56(2, 1936)-0.005637__248.660793-11.3392072193630.000000637
57(0, 2217)-0.001808__0107.33423669.7463760221718.793930808
\n", + "
" + ], + "text/plain": [ + " cellid q boundname laytop laybot layer cell laymidpt \\\n", + "53 (0, 2196) -0.005 636__0 110.001999 65.353310 0 2196 22.324345 \n", + "54 (2, 2196) -0.005 636__2 49.060505 -10.939495 2 2196 30.000000 \n", + "55 (0, 1936) -0.005 637__0 110.503960 65.559921 0 1936 22.472019 \n", + "56 (2, 1936) -0.005 637__2 48.660793 -11.339207 2 1936 30.000000 \n", + "57 (0, 2217) -0.001 808__0 107.334236 69.746376 0 2217 18.793930 \n", + "\n", + " rootname \n", + "53 636 \n", + "54 636 \n", + "55 637 \n", + "56 637 \n", + "57 808 " + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "well_metadata.head()" ] }, { "cell_type": "code", - "execution_count": null, - "id": "b4e43e00", + "execution_count": 50, + "id": "bde5415d", "metadata": {}, "outputs": [], "source": [ @@ -781,18 +1737,259 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "86f56d08", - "metadata": {}, - "outputs": [], + "execution_count": 51, + "id": "d3388614", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
cellidqboundnamelaytoplaybotlayercelllaymidptrootnameXYWellName
0(0, 2196)-0.0050636__0110.00199965.3533100219622.3243456361.518019e+065.032596e+06636
1(2, 2196)-0.0050636__249.060505-10.9394952219630.0000006361.518019e+065.032596e+06636
2(0, 1936)-0.0050637__0110.50396065.5599210193622.4720196371.518020e+065.032742e+06637
3(2, 1936)-0.0050637__248.660793-11.3392072193630.0000006371.518020e+065.032742e+06637
4(0, 2217)-0.0010808__0107.33423669.7463760221718.7939308081.519055e+065.032822e+06808
.......................................
73(2, 7590)-0.009519/19__251.490337-8.5096632759030.00000019/191.520824e+065.032384e+0619/19
74(0, 7057)-0.009519/20__0104.02419367.2917560705718.36621919/201.520653e+065.032405e+0619/20
75(2, 7057)-0.009519/20__251.473099-8.5269012705730.00000019/201.520653e+065.032405e+0619/20
76(0, 5637)-0.009519/21__0103.00206868.4939270563717.25407019/211.520382e+065.032503e+0619/21
77(2, 5637)-0.009519/21__251.661217-8.3387832563730.00000019/211.520382e+065.032503e+0619/21
\n", + "

78 rows × 12 columns

\n", + "
" + ], + "text/plain": [ + " cellid q boundname laytop laybot layer cell \\\n", + "0 (0, 2196) -0.0050 636__0 110.001999 65.353310 0 2196 \n", + "1 (2, 2196) -0.0050 636__2 49.060505 -10.939495 2 2196 \n", + "2 (0, 1936) -0.0050 637__0 110.503960 65.559921 0 1936 \n", + "3 (2, 1936) -0.0050 637__2 48.660793 -11.339207 2 1936 \n", + "4 (0, 2217) -0.0010 808__0 107.334236 69.746376 0 2217 \n", + ".. ... ... ... ... ... ... ... \n", + "73 (2, 7590) -0.0095 19/19__2 51.490337 -8.509663 2 7590 \n", + "74 (0, 7057) -0.0095 19/20__0 104.024193 67.291756 0 7057 \n", + "75 (2, 7057) -0.0095 19/20__2 51.473099 -8.526901 2 7057 \n", + "76 (0, 5637) -0.0095 19/21__0 103.002068 68.493927 0 5637 \n", + "77 (2, 5637) -0.0095 19/21__2 51.661217 -8.338783 2 5637 \n", + "\n", + " laymidpt rootname X Y WellName \n", + "0 22.324345 636 1.518019e+06 5.032596e+06 636 \n", + "1 30.000000 636 1.518019e+06 5.032596e+06 636 \n", + "2 22.472019 637 1.518020e+06 5.032742e+06 637 \n", + "3 30.000000 637 1.518020e+06 5.032742e+06 637 \n", + "4 18.793930 808 1.519055e+06 5.032822e+06 808 \n", + ".. ... ... ... ... ... \n", + "73 30.000000 19/19 1.520824e+06 5.032384e+06 19/19 \n", + "74 18.366219 19/20 1.520653e+06 5.032405e+06 19/20 \n", + "75 30.000000 19/20 1.520653e+06 5.032405e+06 19/20 \n", + "76 17.254070 19/21 1.520382e+06 5.032503e+06 19/21 \n", + "77 30.000000 19/21 1.520382e+06 5.032503e+06 19/21 \n", + "\n", + "[78 rows x 12 columns]" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "well_data" ] }, { "cell_type": "code", - "execution_count": null, - "id": "8a41d894", + "execution_count": 52, + "id": "fb2e6198", "metadata": {}, "outputs": [], "source": [ @@ -801,8 +1998,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "8fcaa640", + "execution_count": 53, + "id": "acdb2b56", "metadata": {}, "outputs": [], "source": [ @@ -813,18 +2010,296 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "6e5b160e", - "metadata": {}, - "outputs": [], + "execution_count": 54, + "id": "c17fb538", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
cellidqboundnamescreen_topscreen_botmlayercelllaymidptrootnamexyWellNamedatetimeenddatetime
0(0, 2196)-0.0050636__0110.00199965.3533100219622.3243456361.518019e+065.032596e+066362021-01-012021-12-31
1(2, 2196)-0.0050636__249.060505-10.9394952219630.0000006361.518019e+065.032596e+066362021-01-012021-12-31
2(0, 1936)-0.0050637__0110.50396065.5599210193622.4720196371.518020e+065.032742e+066372021-01-012021-12-31
3(2, 1936)-0.0050637__248.660793-11.3392072193630.0000006371.518020e+065.032742e+066372021-01-012021-12-31
4(0, 2217)-0.0010808__0107.33423669.7463760221718.7939308081.519055e+065.032822e+068082021-01-012021-12-31
.............................................
73(2, 7590)-0.009519/19__251.490337-8.5096632759030.00000019/191.520824e+065.032384e+0619/192021-01-012021-12-31
74(0, 7057)-0.009519/20__0104.02419367.2917560705718.36621919/201.520653e+065.032405e+0619/202021-01-012021-12-31
75(2, 7057)-0.009519/20__251.473099-8.5269012705730.00000019/201.520653e+065.032405e+0619/202021-01-012021-12-31
76(0, 5637)-0.009519/21__0103.00206868.4939270563717.25407019/211.520382e+065.032503e+0619/212021-01-012021-12-31
77(2, 5637)-0.009519/21__251.661217-8.3387832563730.00000019/211.520382e+065.032503e+0619/212021-01-012021-12-31
\n", + "

78 rows × 14 columns

\n", + "
" + ], + "text/plain": [ + " cellid q boundname screen_top screen_botm layer cell \\\n", + "0 (0, 2196) -0.0050 636__0 110.001999 65.353310 0 2196 \n", + "1 (2, 2196) -0.0050 636__2 49.060505 -10.939495 2 2196 \n", + "2 (0, 1936) -0.0050 637__0 110.503960 65.559921 0 1936 \n", + "3 (2, 1936) -0.0050 637__2 48.660793 -11.339207 2 1936 \n", + "4 (0, 2217) -0.0010 808__0 107.334236 69.746376 0 2217 \n", + ".. ... ... ... ... ... ... ... \n", + "73 (2, 7590) -0.0095 19/19__2 51.490337 -8.509663 2 7590 \n", + "74 (0, 7057) -0.0095 19/20__0 104.024193 67.291756 0 7057 \n", + "75 (2, 7057) -0.0095 19/20__2 51.473099 -8.526901 2 7057 \n", + "76 (0, 5637) -0.0095 19/21__0 103.002068 68.493927 0 5637 \n", + "77 (2, 5637) -0.0095 19/21__2 51.661217 -8.338783 2 5637 \n", + "\n", + " laymidpt rootname x y WellName datetime \\\n", + "0 22.324345 636 1.518019e+06 5.032596e+06 636 2021-01-01 \n", + "1 30.000000 636 1.518019e+06 5.032596e+06 636 2021-01-01 \n", + "2 22.472019 637 1.518020e+06 5.032742e+06 637 2021-01-01 \n", + "3 30.000000 637 1.518020e+06 5.032742e+06 637 2021-01-01 \n", + "4 18.793930 808 1.519055e+06 5.032822e+06 808 2021-01-01 \n", + ".. ... ... ... ... ... ... \n", + "73 30.000000 19/19 1.520824e+06 5.032384e+06 19/19 2021-01-01 \n", + "74 18.366219 19/20 1.520653e+06 5.032405e+06 19/20 2021-01-01 \n", + "75 30.000000 19/20 1.520653e+06 5.032405e+06 19/20 2021-01-01 \n", + "76 17.254070 19/21 1.520382e+06 5.032503e+06 19/21 2021-01-01 \n", + "77 30.000000 19/21 1.520382e+06 5.032503e+06 19/21 2021-01-01 \n", + "\n", + " enddatetime \n", + "0 2021-12-31 \n", + "1 2021-12-31 \n", + "2 2021-12-31 \n", + "3 2021-12-31 \n", + "4 2021-12-31 \n", + ".. ... \n", + "73 2021-12-31 \n", + "74 2021-12-31 \n", + "75 2021-12-31 \n", + "76 2021-12-31 \n", + "77 2021-12-31 \n", + "\n", + "[78 rows x 14 columns]" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "well_data" ] }, { "cell_type": "code", - "execution_count": null, - "id": "0b852bdd", + "execution_count": 55, + "id": "b0e6c6d3", "metadata": {}, "outputs": [], "source": [ @@ -833,7 +2308,7 @@ }, { "cell_type": "markdown", - "id": "5c19fee2", + "id": "87d4ef56", "metadata": {}, "source": [ "# Now we write the blocks for the model-building YML configuration file" @@ -841,7 +2316,7 @@ }, { "cell_type": "markdown", - "id": "5eef221d", + "id": "6653bddf", "metadata": {}, "source": [ "# let's set a lateral discretization" @@ -849,8 +2324,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "a97412ed", + "execution_count": 56, + "id": "db00ac07", "metadata": {}, "outputs": [], "source": [ @@ -859,8 +2334,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "82581f6f", + "execution_count": 57, + "id": "10a6fdfd", "metadata": {}, "outputs": [], "source": [ @@ -876,8 +2351,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "67da9f9e", + "execution_count": 58, + "id": "19d59143", "metadata": {}, "outputs": [], "source": [ @@ -887,8 +2362,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "07d4fd90", + "execution_count": 59, + "id": "54ad59d8", "metadata": {}, "outputs": [], "source": [ @@ -905,8 +2380,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "4d27bdcf", + "execution_count": 60, + "id": "9944555b", "metadata": {}, "outputs": [], "source": [ @@ -929,8 +2404,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "93c6eef4", + "execution_count": 61, + "id": "e5690110", "metadata": {}, "outputs": [], "source": [ @@ -940,8 +2415,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "1273f50d", + "execution_count": 62, + "id": "4c11e8b1", "metadata": {}, "outputs": [], "source": [ @@ -955,8 +2430,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "04bfde52", + "execution_count": 63, + "id": "5fdffbce", "metadata": {}, "outputs": [], "source": [ @@ -966,8 +2441,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "528b4e89", + "execution_count": 64, + "id": "da0489af", "metadata": {}, "outputs": [], "source": [ @@ -992,8 +2467,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "60309029", + "execution_count": 65, + "id": "3c244df1", "metadata": {}, "outputs": [], "source": [ @@ -1019,8 +2494,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "5e669f42", + "execution_count": 66, + "id": "7fe8a664", "metadata": {}, "outputs": [], "source": [ @@ -1040,8 +2515,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "ce679ff4", + "execution_count": 67, + "id": "66483a1d", "metadata": {}, "outputs": [], "source": [ @@ -1054,8 +2529,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "84fa1d64", + "execution_count": 68, + "id": "7e99b678", "metadata": {}, "outputs": [], "source": [ @@ -1097,8 +2572,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "3a6d3c56", + "execution_count": 69, + "id": "74881bf6", "metadata": {}, "outputs": [], "source": [ @@ -1116,8 +2591,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "1c584b1f", + "execution_count": 70, + "id": "b2b07749", "metadata": {}, "outputs": [], "source": [ @@ -1136,8 +2611,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "7aa175af", + "execution_count": 71, + "id": "d55fb5cb", "metadata": {}, "outputs": [], "source": [ @@ -1162,6 +2637,7 @@ }, { "cell_type": "code", + "execution_count": null, "id": "8f52fc29", "metadata": {}, @@ -1177,6 +2653,7 @@ "id": "9be496f1", "metadata": {}, "outputs": [], + "source": [ "# for SFR observations, we need to make a CSV file with the segments identified\n", "inriv = gp.read_file(rivfile)\n", @@ -1196,8 +2673,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "c0269d6e", + "execution_count": 75, + "id": "841a61a0", "metadata": {}, "outputs": [], "source": [ @@ -1229,8 +2706,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "1fda6c14", + "execution_count": 76, + "id": "425bc8bd", "metadata": {}, "outputs": [], "source": [ @@ -1247,8 +2724,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "30f0a041", + "execution_count": 77, + "id": "e1cce203", "metadata": {}, "outputs": [], "source": [ @@ -1260,7 +2737,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f0a7124e", + "id": "d0776997", "metadata": {}, "outputs": [], "source": [] @@ -1290,7 +2767,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.2" + "version": "3.9.6" } }, "nbformat": 4, diff --git a/notebooks/modflow_setup/2_build_model_from_YML.ipynb b/notebooks/modflow_setup/2_build_model_from_YML.ipynb index 3f6dfe6..2b26843 100644 --- a/notebooks/modflow_setup/2_build_model_from_YML.ipynb +++ b/notebooks/modflow_setup/2_build_model_from_YML.ipynb @@ -2,10 +2,112 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "f96b3e8b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", + "/Users/JWhite/opt/miniconda3/envs/symple/lib/python3.9/site-packages/rasterstats/io.py:24: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.10 it will stop working\n", + " from collections import Iterable, Mapping\n", + "/Users/JWhite/opt/miniconda3/envs/symple/lib/python3.9/site-packages/rasterstats/io.py:24: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.10 it will stop working\n", + " from collections import Iterable, Mapping\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/gis.py:17: UserWarning: Automatic reprojection functionality requires gis-utils >= 0.2.2\n", + "Please pip install --upgrade gis-utils\n", + " warnings.warn('Automatic reprojection functionality requires gis-utils >= 0.2.2'\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:111: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " dtypes = {'rno': np.int, 'node': np.int, 'k': np.int, 'i': np.int, 'j': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:111: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " dtypes = {'rno': np.int, 'node': np.int, 'k': np.int, 'i': np.int, 'j': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:111: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " dtypes = {'rno': np.int, 'node': np.int, 'k': np.int, 'i': np.int, 'j': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:111: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " dtypes = {'rno': np.int, 'node': np.int, 'k': np.int, 'i': np.int, 'j': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:111: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " dtypes = {'rno': np.int, 'node': np.int, 'k': np.int, 'i': np.int, 'j': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:112: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " 'iseg': np.int, 'ireach': np.int, 'outreach': np.int, 'line_id': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:112: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " 'iseg': np.int, 'ireach': np.int, 'outreach': np.int, 'line_id': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:112: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " 'iseg': np.int, 'ireach': np.int, 'outreach': np.int, 'line_id': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:112: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " 'iseg': np.int, 'ireach': np.int, 'outreach': np.int, 'line_id': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:113: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " 'per': np.int, 'nseg': np.int, 'icalc': np.int, 'outseg': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:113: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " 'per': np.int, 'nseg': np.int, 'icalc': np.int, 'outseg': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:113: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " 'per': np.int, 'nseg': np.int, 'icalc': np.int, 'outseg': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:113: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " 'per': np.int, 'nseg': np.int, 'icalc': np.int, 'outseg': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:114: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " 'iupseg': np.int, 'iprior': np.int, 'nstrpts': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:114: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " 'iupseg': np.int, 'iprior': np.int, 'nstrpts': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:114: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " 'iupseg': np.int, 'iprior': np.int, 'nstrpts': np.int,\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:115: DeprecationWarning: `np.object` is a deprecated alias for the builtin `object`. To silence this warning, use `object` by itself. Doing this will not modify any behavior and is safe. \n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " 'name': np.object, 'geometry': np.object}\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:115: DeprecationWarning: `np.object` is a deprecated alias for the builtin `object`. To silence this warning, use `object` by itself. Doing this will not modify any behavior and is safe. \n", + "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", + " 'name': np.object, 'geometry': np.object}\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/mfsetup/mfmodel.py:57: UserWarning: Automatic reprojection functionality requires gis-utils >= 0.2.2\n", + "Please pip install --upgrade gis-utils\n", + " warnings.warn('Automatic reprojection functionality requires gis-utils >= 0.2.2'\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/mfsetup/mfmodel.py:60: UserWarning: sfr: sfrmaker_options: add_outlet functionality requires sfrmaker >= 0.6\n", + "Please pip install --upgrade sfrmaker\n", + " warnings.warn('sfr: sfrmaker_options: add_outlet functionality requires sfrmaker >= 0.6'\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", + "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", + " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n" + ] + } + ], "source": [ "import sys, os\n", "sys.path.append('../../dependencies/')\n", @@ -34,7 +136,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "972ea4f7", "metadata": {}, "outputs": [], @@ -45,22 +147,383 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "4e938b93", "metadata": { "scrolled": false }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loading configuration file sgn_config.yml...\n", + "\n", + "Setting up sgn_50 model from configuration in sgn_config.yml\n", + "\n", + "validating configuration...\n", + "DIS package\n", + "done with validation.\n", + "\n", + "setting up model grid...\n", + "wrote /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/sgn_50_grid.json\n", + "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_bbox.shp... Done\n", + "finished in 0.14s\n", + "\n", + "\n", + "Setting up TDIS package...\n", + "finished in 0.01s\n", + "\n", + "\n", + "Setting up IMS package...\n", + "finished in 0.00s\n", + "\n", + "\n", + "Setting up DIS package...\n", + "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/DTM_domain.tif...\n", + "finished in 0.08s\n", + "wrote ././top.dat, took 0.00s\n", + "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/Bott_L1_fix.tif...\n", + "finished in 0.16s\n", + "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/Bott_L2_fix.tif...\n", + "finished in 0.14s\n", + "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/Bott_L3_fix.tif...\n", + "finished in 0.15s\n", + "loading original/sgn_50_top.dat.original, shape=(96, 83), loading original/sgn_50_top.dat.original, shape=(96, 83), took 0.00s\n", + "computing cell thicknesses...\n", + "finished in 0.17s\n", + "\n", + "wrote ././top.dat, took 0.00s\n", + "wrote ././botm_000.dat, took 0.00s\n", + "wrote ././botm_001.dat, took 0.00s\n", + "wrote ././botm_002.dat, took 0.00s\n", + "wrote ././top.dat, took 0.00s\n", + "wrote ././idomain_000.dat, took 0.00s\n", + "wrote ././idomain_001.dat, took 0.00s\n", + "wrote ././idomain_002.dat, took 0.00s\n", + "(re)setting the idomain array...\n", + "computing cell thicknesses...\n", + "finished in 0.19s\n", + "\n", + "setting up model grid...\n", + "wrote /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/sgn_50_grid.json\n", + "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_bbox.shp... Done\n", + "finished in 0.11s\n", + "\n", + "wrote original/lakarr_000.dat, took 0.00s\n", + "wrote original/lakarr_001.dat, took 0.00s\n", + "wrote original/lakarr_002.dat, took 0.00s\n", + "loading original/sgn_50_top.dat.original, shape=(96, 83), took 0.00s\n", + "computing cell thicknesses...\n", + "finished in 0.22s\n", + "\n", + "wrote ././top.dat, took 0.00s\n", + "wrote ././botm_000.dat, took 0.00s\n", + "wrote ././botm_001.dat, took 0.00s\n", + "wrote ././botm_002.dat, took 0.00s\n", + "wrote ././top.dat, took 0.00s\n", + "wrote ././idomain_000.dat, took 0.00s\n", + "wrote ././idomain_001.dat, took 0.00s\n", + "wrote ././idomain_002.dat, took 0.00s\n", + "setting up model grid...\n", + "wrote /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/sgn_50_grid.json\n", + "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_bbox.shp... Done\n", + "finished in 0.13s\n", + "\n", + "wrote ././irch.dat, took 0.00s\n", + "finished in 1.54s\n", + "\n", + "\n", + "Setting up IC package...\n", + "wrote ././DTM_domain.tif, took 0.00s\n", + "wrote ././DTM_domain.tif, took 0.00s\n", + "wrote ././DTM_domain.tif, took 0.00s\n", + "finished in 0.02s\n", + "\n", + "\n", + "Setting up NPF package...\n", + "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/k_field0.tif...\n", + "finished in 0.15s\n", + "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/k_field1.tif...\n", + "finished in 0.13s\n", + "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/k_field2.tif...\n", + "finished in 0.14s\n", + "wrote ././k_000.dat, took 0.00s\n", + "wrote ././k_001.dat, took 0.00s\n", + "wrote ././k_002.dat, took 0.00s\n", + "No data were specified for npf package, variable k33\n", + "finished in 0.45s\n", + "\n", + "\n", + "Setting up RCH package...\n", + "wrote ././irch.dat, took 0.00s\n", + "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/rch.tif...\n", + "finished in 0.15s\n", + "wrote ././rch_000.dat, took 0.00s\n", + "finished in 0.17s\n", + "\n", + "\n", + "Setting up OC package...\n", + "finished in 0.00s\n", + "\n", + "\n", + "Setting up SFR package...\n", + "\n", + "reading /Users/JWhite/Dev/symple_flopy/data/sgn/shp/River_Lambro_segmented.shp...\n", + "filtering on bounding box 1516766.2711835166, 5028909.73961192, 1521954.2235464402, 5034571.134964784...\n", + "--> building dataframe... (may take a while for large shapefiles)\n", + "\n", + "SFRmaker version 0.post31.dev0+g191fdd7\n", + "\n", + "Creating sfr dataset...\n", + "\n", + "Creating grid class instance from flopy Grid instance...\n", + "grid class created in 0.23s\n", + "\n", + "Model grid information\n", + "structured grid\n", + "nnodes: 7,968\n", + "nlay: 1\n", + "nrow: 96\n", + "ncol: 83\n", + "model length units: undefined\n", + "crs: EPSG:3003\n", + "bounds: 1516766.27, 5028909.74, 1521954.22, 5034571.13\n", + "active area defined by: all cells\n", + "\n", + "/Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup\n", + "sgn_50 model version 0.post31.dev0+g191fdd7\n", + "3 layer(s), 96 row(s), 83 column(s)\n", + "delr: [50.00...50.00] meters\n", + "delc: [50.00...50.00] meters\n", + "CRS: EPSG:3003\n", + "length units: meters\n", + "xll: 1517927.496282395; yll: 5028909.73961192; rotation: 14.0\n", + "Bounds: (1516766.2711835166, 1521954.2235464402, 5028909.73961192, 5034571.134964784)\n", + "Packages: dis ic npf rcha_0 oc\n", + "1 period(s):\n", + " per start_datetime end_datetime perlen steady nstp\n", + " 0 2021-01-01 2022-01-01 01:06:40 31540000.0 True 1\n", + " ...\n", + " 0 2021-01-01 2022-01-01 01:06:40 31540000.0 True 1\n", + "\n", + "Culling hydrography to active area...\n", + "starting lines: 10\n", + "remaining lines: 10\n", + "finished in 0.00s\n", + "\n", + "\n", + "Intersecting 10 flowlines with 7,968 grid cells...\n", + "Intersecting 10 features...\n", + "10\n", + "finished in 0.17s\n", + "\n", + "Setting up reach data... (may take a few minutes for large grids)\n", + "finished in 0.02s\n", + "\n", + "Computing widths...\n", + "\n", + "Dropping 3 reaches with length < 2.50 meters...\n", + "\n", + "Repairing routing connections...\n", + "enforcing best segment numbering...\n", + "\n", + "Setting up segment data...\n", + "Model grid information\n", + "structured grid\n", + "nnodes: 7,968\n", + "nlay: 1\n", + "nrow: 96\n", + "ncol: 83\n", + "model length units: undefined\n", + "crs: EPSG:3003\n", + "bounds: 1516766.27, 5028909.74, 1521954.22, 5034571.13\n", + "active area defined by: all cells\n", + "\n", + "\n", + "Time to create sfr dataset: 0.61s\n", + "\n", + "running rasterstats.zonal_stats on buffered LineStrings...\n", + "finished in 0.24s\n", + "\n", + "\n", + "Smoothing elevations...\n", + "finished in 0.01s\n", + "wrote /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/tables/sgn_50_sfr_reach_data.csv\n", + "wrote /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/tables/sgn_50_sfr_segment_data.csv\n", + "converting segment data to period data...\n", + "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_sfr_cells.shp... Done\n", + "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_sfr_outlets.shp... Done\n", + "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_sfr_lines.shp... Done\n", + "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_sfr_routing.shp... Done\n", + "No period data to export!\n", + "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_sfr_observations.shp... Done\n", + "No non-zero values of flow to export!\n", + "converting reach and segment data to package data...\n", + "converting segment data to period data...\n", + "(re)setting the idomain array...\n", + "computing cell thicknesses...\n", + "finished in 0.18s\n", + "\n", + "wrote original/lakarr_000.dat, took 0.00s\n", + "wrote original/lakarr_001.dat, took 0.00s\n", + "wrote original/lakarr_002.dat, took 0.00s\n", + "loading original/sgn_50_top.dat.original, shape=(96, 83), took 0.00s\n", + "computing cell thicknesses...\n", + "finished in 0.19s\n", + "\n", + "wrote ././top.dat, took 0.00s\n", + "wrote ././botm_000.dat, took 0.00s\n", + "wrote ././botm_001.dat, took 0.00s\n", + "wrote ././botm_002.dat, took 0.00s\n", + "wrote ././top.dat, took 0.00s\n", + "wrote ././idomain_000.dat, took 0.00s\n", + "wrote ././idomain_001.dat, took 0.00s\n", + "wrote ././idomain_002.dat, took 0.00s\n", + "setting up model grid...\n", + "wrote /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/sgn_50_grid.json\n", + "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_bbox.shp... Done\n", + "finished in 0.11s\n", + "\n", + "wrote ././irch.dat, took 0.00s\n", + "finished in 2.21s\n", + "\n", + "\n", + "Setting up WEL package...\n", + "getting i, j locations...\n", + "finished in 0.00s\n", + "\n", + "finished in 0.11s\n", + "\n", + "finished setting up model in 4.73s\n", + "\n", + "sgn_50 model version 0.post31.dev0+g191fdd7\n", + "3 layer(s), 96 row(s), 83 column(s)\n", + "delr: [50.00...50.00] meters\n", + "delc: [50.00...50.00] meters\n", + "CRS: EPSG:3003\n", + "length units: meters\n", + "xll: 1517927.496282395; yll: 5028909.73961192; rotation: 14.0\n", + "Bounds: (1516766.2711835166, 1521954.2235464402, 5028909.73961192, 5034571.134964784)\n", + "Packages: dis ic npf rcha_0 oc sfr_0 wel_0\n", + "1 period(s):\n", + " per start_datetime end_datetime perlen steady nstp\n", + " 0 2021-01-01 2022-01-01 01:06:40 31540000.0 True 1\n", + " ...\n", + " 0 2021-01-01 2022-01-01 01:06:40 31540000.0 True 1\n" + ] + } + ], "source": [ "m = mfsetup.MF6model.setup_from_yaml('sgn_config.yml')" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "2f85d9d5", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "writing simulation...\n", + " writing simulation name file...\n", + " writing simulation tdis package...\n", + " writing ims package ims_-1...\n", + " writing model sgn_50...\n", + " writing model name file...\n", + " writing package dis...\n", + " writing package ic...\n", + " writing package npf...\n", + " writing package rcha_0...\n", + " writing package oc...\n", + " writing package sfr_0...\n", + " writing package wel_0...\n", + "INFORMATION: maxbound in ('gwf6', 'wel', 'dimensions') changed to 78 based on size of stress_period_data\n", + "SFRmaker v. 0.post31.dev0+g191fdd7\n", + "\n", + "Running Flopy v. 3.3.5 diagnostics...\n", + "passed.\n", + "\n", + "Checking for continuity in segment and reach numbering...\n", + "passed.\n", + "\n", + "Checking for increasing segment numbers in downstream direction...\n", + "passed.\n", + "\n", + "Checking for circular routing...\n", + "passed.\n", + "\n", + "Checking reach connections for proximity...\n", + "0 segments with non-adjacent reaches found.\n", + "At segments:\n", + "\n", + "\n", + "0 segments with non-adjacent reaches found.\n", + "At segments:\n", + "\n", + "\n", + "\n", + "Checking for model cells with multiple non-zero SFR conductances...\n", + "8 model cells with multiple non-zero SFR conductances found.\n", + "This may lead to circular routing between collocated reaches.\n", + "Nodes with overlapping conductances:\n", + "k\ti\tj\tiseg\tireach\trchlen\tstrthick\tstrhc1\n", + "0\t8\t63\t1\t10\t7.924251079559326\t1.0\t1.0\n", + "0\t8\t63\t2\t1\t47.34646224975586\t1.0\t1.0\n", + "0\t16\t66\t2\t14\t5.979315280914307\t1.0\t1.0\n", + "0\t16\t66\t3\t1\t41.623817443847656\t1.0\t1.0\n", + "0\t24\t69\t3\t12\t37.11835861206055\t1.0\t1.0\n", + "0\t24\t69\t4\t1\t16.12721824645996\t1.0\t1.0\n", + "0\t26\t73\t4\t11\t15.494623184204102\t1.0\t1.0\n", + "0\t26\t73\t5\t1\t29.43027687072754\t1.0\t1.0\n", + "0\t36\t75\t5\t19\t20.42424201965332\t1.0\t1.0\n", + "0\t36\t75\t6\t1\t31.1514949798584\t1.0\t1.0\n", + "0\t47\t72\t6\t14\t14.13512134552002\t1.0\t1.0\n", + "0\t47\t72\t7\t1\t29.998180389404297\t1.0\t1.0\n", + "0\t64\t72\t8\t10\t24.63616371154785\t1.0\t1.0\n", + "0\t64\t72\t9\t1\t26.59016227722168\t1.0\t1.0\n", + "0\t82\t75\t9\t22\t21.188451766967773\t1.0\t1.0\n", + "0\t82\t75\t10\t1\t30.045856475830078\t1.0\t1.0\n", + "\n", + "Checking for streambed tops of less than -10...\n", + "isfropt setting of 1,2 or 3 requires strtop information!\n", + "\n", + "\n", + "Checking for streambed tops of greater than 15000...\n", + "isfropt setting of 1,2 or 3 requires strtop information!\n", + "\n", + "\n", + "Checking segment_data for downstream rises in streambed elevation...\n", + "Segment elevup and elevdn not specified for nstrm=-137 and isfropt=1\n", + "passed.\n", + "\n", + "Checking reach_data for downstream rises in streambed elevation...\n", + "passed.\n", + "\n", + "Checking reach_data for inconsistencies between streambed elevations and the model grid...\n", + "passed.\n", + "\n", + "Checking segment_data for inconsistencies between segment end elevations and the model grid...\n", + "Segment elevup and elevdn not specified for nstrm=-137 and isfropt=1\n", + "passed.\n", + "\n", + "Checking for streambed slopes of less than 0.0001...\n", + "passed.\n", + "\n", + "Checking for streambed slopes of greater than 1.0...\n", + "passed.\n", + "\n", + "wrote sgn_50_SFR.chk\n", + "wrote sgn_50.sfr.obs\n", + "converting reach and segment data to package data...\n", + "wrote ././sgn_50_packagedata.dat\n", + "wrote ./sgn_50.sfr\n" + ] + } + ], "source": [ "m.write_input()" ] @@ -75,7 +538,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "06c36717", "metadata": {}, "outputs": [], @@ -93,10 +556,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "74784609", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/svg+xml": [ + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# read in the boundary polygon\n", "boundary = gp.read_file(datapath / 'shp' / 'Model_domain.shp')\n", @@ -108,7 +585,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "00fe3084", "metadata": {}, "outputs": [], @@ -119,10 +596,98 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "433def84", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
cellidsverticesareasixshapes
0(0, 0)[([(array([1516807.7649682]), array([5033525.9...1818.572486POLYGON ((1516807.764968205 5033525.973979044,...
1(0, 1)[([(array([1516818.50671796]), array([5033564....768.997804POLYGON ((1516818.506717961 5033564.332087163,...
2(0, 2)[([(array([1516867.02150427]), array([5033576....768.997804POLYGON ((1516867.021504275 5033576.428181943,...
3(0, 3)[([(array([1516915.53629059]), array([5033588....768.997804POLYGON ((1516915.536290589 5033588.524276723,...
4(0, 4)[([(array([1516964.0510769]), array([5033600.6...768.997804POLYGON ((1516964.051076903 5033600.620371503,...
\n", + "
" + ], + "text/plain": [ + " cellids vertices areas \\\n", + "0 (0, 0) [([(array([1516807.7649682]), array([5033525.9... 1818.572486 \n", + "1 (0, 1) [([(array([1516818.50671796]), array([5033564.... 768.997804 \n", + "2 (0, 2) [([(array([1516867.02150427]), array([5033576.... 768.997804 \n", + "3 (0, 3) [([(array([1516915.53629059]), array([5033588.... 768.997804 \n", + "4 (0, 4) [([(array([1516964.0510769]), array([5033600.6... 768.997804 \n", + "\n", + " ixshapes \n", + "0 POLYGON ((1516807.764968205 5033525.973979044,... \n", + "1 POLYGON ((1516818.506717961 5033564.332087163,... \n", + "2 POLYGON ((1516867.021504275 5033576.428181943,... \n", + "3 POLYGON ((1516915.536290589 5033588.524276723,... \n", + "4 POLYGON ((1516964.051076903 5033600.620371503,... " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "ix_df = pd.DataFrame.from_records(ix_boundary)\n", "ix_df.head()" @@ -130,10 +695,33 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "38616ea9", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "# read in the september 2019 measured heads to make the GHB data\n", "sep19_head = fu.Raster.load(datapath / 'raster' / 'heads_sep2019.asc')\n", @@ -143,7 +731,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "113499a4", "metadata": {}, "outputs": [], @@ -154,7 +742,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "a7f0101f", "metadata": {}, "outputs": [], @@ -171,7 +759,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "77e9d192", "metadata": {}, "outputs": [], @@ -184,47 +772,227 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "37dcb490", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "writing simulation...\n", + " writing simulation name file...\n", + " writing simulation tdis package...\n", + " writing ims package ims_-1...\n", + " writing model sgn_50...\n", + " writing model name file...\n", + " writing package dis...\n", + " writing package ic...\n", + " writing package npf...\n", + " writing package rcha_0...\n", + " writing package oc...\n", + " writing package sfr_0...\n", + " writing package wel_0...\n", + " writing package ghb_0...\n", + "INFORMATION: maxbound in ('gwf6', 'ghb', 'dimensions') changed to 708 based on size of stress_period_data\n", + "SFRmaker v. 0.post31.dev0+g191fdd7\n", + "\n", + "Running Flopy v. 3.3.5 diagnostics...\n", + "passed.\n", + "\n", + "Checking for continuity in segment and reach numbering...\n", + "passed.\n", + "\n", + "Checking for increasing segment numbers in downstream direction...\n", + "passed.\n", + "\n", + "Checking for circular routing...\n", + "passed.\n", + "\n", + "Checking reach connections for proximity...\n", + "0 segments with non-adjacent reaches found.\n", + "At segments:\n", + "\n", + "\n", + "0 segments with non-adjacent reaches found.\n", + "At segments:\n", + "\n", + "\n", + "\n", + "Checking for model cells with multiple non-zero SFR conductances...\n", + "8 model cells with multiple non-zero SFR conductances found.\n", + "This may lead to circular routing between collocated reaches.\n", + "Nodes with overlapping conductances:\n", + "k\ti\tj\tiseg\tireach\trchlen\tstrthick\tstrhc1\n", + "0\t8\t63\t1\t10\t7.924251079559326\t1.0\t1.0\n", + "0\t8\t63\t2\t1\t47.34646224975586\t1.0\t1.0\n", + "0\t16\t66\t2\t14\t5.979315280914307\t1.0\t1.0\n", + "0\t16\t66\t3\t1\t41.623817443847656\t1.0\t1.0\n", + "0\t24\t69\t3\t12\t37.11835861206055\t1.0\t1.0\n", + "0\t24\t69\t4\t1\t16.12721824645996\t1.0\t1.0\n", + "0\t26\t73\t4\t11\t15.494623184204102\t1.0\t1.0\n", + "0\t26\t73\t5\t1\t29.43027687072754\t1.0\t1.0\n", + "0\t36\t75\t5\t19\t20.42424201965332\t1.0\t1.0\n", + "0\t36\t75\t6\t1\t31.1514949798584\t1.0\t1.0\n", + "0\t47\t72\t6\t14\t14.13512134552002\t1.0\t1.0\n", + "0\t47\t72\t7\t1\t29.998180389404297\t1.0\t1.0\n", + "0\t64\t72\t8\t10\t24.63616371154785\t1.0\t1.0\n", + "0\t64\t72\t9\t1\t26.59016227722168\t1.0\t1.0\n", + "0\t82\t75\t9\t22\t21.188451766967773\t1.0\t1.0\n", + "0\t82\t75\t10\t1\t30.045856475830078\t1.0\t1.0\n", + "\n", + "Checking for streambed tops of less than -10...\n", + "isfropt setting of 1,2 or 3 requires strtop information!\n", + "\n", + "\n", + "Checking for streambed tops of greater than 15000...\n", + "isfropt setting of 1,2 or 3 requires strtop information!\n", + "\n", + "\n", + "Checking segment_data for downstream rises in streambed elevation...\n", + "Segment elevup and elevdn not specified for nstrm=-137 and isfropt=1\n", + "passed.\n", + "\n", + "Checking reach_data for downstream rises in streambed elevation...\n", + "passed.\n", + "\n", + "Checking reach_data for inconsistencies between streambed elevations and the model grid...\n", + "passed.\n", + "\n", + "Checking segment_data for inconsistencies between segment end elevations and the model grid...\n", + "Segment elevup and elevdn not specified for nstrm=-137 and isfropt=1\n", + "passed.\n", + "\n", + "Checking for streambed slopes of less than 0.0001...\n", + "passed.\n", + "\n", + "Checking for streambed slopes of greater than 1.0...\n", + "passed.\n", + "\n", + "wrote sgn_50_SFR.chk\n", + "wrote sgn_50.sfr.obs\n", + "converting reach and segment data to package data...\n", + "wrote ././sgn_50_packagedata.dat\n", + "wrote ./sgn_50.sfr\n" + ] + } + ], "source": [ "m.write_input()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "c6741479", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "sgn_50 model version 0.post31.dev0+g191fdd7\n", + "3 layer(s), 96 row(s), 83 column(s)\n", + "delr: [50.00...50.00] meters\n", + "delc: [50.00...50.00] meters\n", + "CRS: EPSG:3003\n", + "length units: meters\n", + "xll: 1517927.496282395; yll: 5028909.73961192; rotation: 14.0\n", + "Bounds: (1516766.2711835166, 1521954.2235464402, 5028909.73961192, 5034571.134964784)\n", + "Packages: dis ic npf rcha_0 oc sfr_0 wel_0 ghb_0\n", + "1 period(s):\n", + " per start_datetime end_datetime perlen steady nstp\n", + " 0 2021-01-01 2022-01-01 01:06:40 31540000.0 True 1\n", + " ...\n", + " 0 2021-01-01 2022-01-01 01:06:40 31540000.0 True 1" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "m" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "ea8eba2b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "wrote testgrid.shp\n" + ] + } + ], "source": [ "m.dis.export('testgrid.shp')" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "a621cc63", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " MODFLOW 6\n", + " U.S. GEOLOGICAL SURVEY MODULAR HYDROLOGIC MODEL\n", + " VERSION 6.3.0 release candidate 07/30/2021\n", + " ***DEVELOP MODE***\n", + "\n", + " MODFLOW 6 compiled Jul 31 2021 20:33:12 with IFORT compiler (ver. 19.10.3)\n", + "\n", + "This software is preliminary or provisional and is subject to \n", + "revision. It is being provided to meet the need for timely best \n", + "science. The software has not received final approval by the U.S. \n", + "Geological Survey (USGS). No warranty, expressed or implied, is made \n", + "by the USGS or the U.S. Government as to the functionality of the \n", + "software and related material nor shall the fact of release \n", + "constitute any such warranty. The software is provided on the \n", + "condition that neither the USGS nor the U.S. Government shall be held \n", + "liable for any damages resulting from the authorized or unauthorized \n", + "use of the software.\n", + "\n", + " \n", + " Run start date and time (yyyy/mm/dd hh:mm:ss): 2021/09/22 15:05:40\n", + " \n", + " Writing simulation list file: mfsim.lst\n", + " Using Simulation name file: mfsim.nam\n", + " \n", + " Solving: Stress period: 1 Time step: 1\n", + " \n", + " Run end date and time (yyyy/mm/dd hh:mm:ss): 2021/09/22 15:05:41\n", + " Elapsed run time: 0.757 Seconds\n", + " \n", + " Normal termination of simulation.\n" + ] + }, + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "os.system('mf6')" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "id": "05d6aa79", "metadata": {}, "outputs": [], @@ -234,17 +1002,40 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "id": "dddcf740", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "plt.imshow(top)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "id": "d2d29541", "metadata": {}, "outputs": [], @@ -254,10 +1045,33 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "id": "90faeb30", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "plt.imshow(np.squeeze(h)[0])\n", "plt.colorbar()" @@ -273,10 +1087,33 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "id": "935d533d", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "plt.imshow(top-np.squeeze(h)[0])\n", "plt.colorbar()" @@ -284,7 +1121,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "id": "f4cc1582", "metadata": {}, "outputs": [], @@ -294,20 +1131,165 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "id": "8b68b919", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
WEL_INGHB_INRCH_INSFR_INTOTAL_INWEL_OUTGHB_OUTRCH_OUTSFR_OUTTOTAL_OUTIN-OUTPERCENT_DISCREPANCY
1971-01-01 01:11:58.9453120.12887.18020.0676020.07.37660.76661.62110.04.98897.3766-0.000021-0.0
\n", + "
" + ], + "text/plain": [ + " WEL_IN GHB_IN RCH_IN SFR_IN TOTAL_IN \\\n", + "1971-01-01 01:11:58.945312 0.1288 7.1802 0.067602 0.0 7.3766 \n", + "\n", + " WEL_OUT GHB_OUT RCH_OUT SFR_OUT TOTAL_OUT \\\n", + "1971-01-01 01:11:58.945312 0.7666 1.6211 0.0 4.9889 7.3766 \n", + "\n", + " IN-OUT PERCENT_DISCREPANCY \n", + "1971-01-01 01:11:58.945312 -0.000021 -0.0 " + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "df1" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "id": "d592657b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
WEL_INGHB_INRCH_INSFR_INTOTAL_INWEL_OUTGHB_OUTRCH_OUTSFR_OUTTOTAL_OUTIN-OUTPERCENT_DISCREPANCY
1971-01-01 01:11:58.9453124062352.0226463072.02132160.250.0232657584.024178564.051130412.00.0157349280.0232658256.0-668.346008-0.0
\n", + "
" + ], + "text/plain": [ + " WEL_IN GHB_IN RCH_IN SFR_IN \\\n", + "1971-01-01 01:11:58.945312 4062352.0 226463072.0 2132160.25 0.0 \n", + "\n", + " TOTAL_IN WEL_OUT GHB_OUT RCH_OUT \\\n", + "1971-01-01 01:11:58.945312 232657584.0 24178564.0 51130412.0 0.0 \n", + "\n", + " SFR_OUT TOTAL_OUT IN-OUT \\\n", + "1971-01-01 01:11:58.945312 157349280.0 232658256.0 -668.346008 \n", + "\n", + " PERCENT_DISCREPANCY \n", + "1971-01-01 01:11:58.945312 -0.0 " + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "df2" ] @@ -345,7 +1327,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.2" + "version": "3.9.6" } }, "nbformat": 4, From 7b6594e6d1f84e6bc540e01b4c0327c62de64c85 Mon Sep 17 00:00:00 2001 From: jdub Date: Wed, 22 Sep 2021 21:51:04 -0600 Subject: [PATCH 4/7] check in --- notebooks/pstfrom/gv39.hob | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 notebooks/pstfrom/gv39.hob diff --git a/notebooks/pstfrom/gv39.hob b/notebooks/pstfrom/gv39.hob new file mode 100644 index 0000000..57e7e11 --- /dev/null +++ b/notebooks/pstfrom/gv39.hob @@ -0,0 +1,49 @@ +# MODFLOW2000 Head Observation File +# Groundwater Vistas also writes drawdown targets here + 45 0 0 500 -999 + 1.0 1.0 +PROF_11 1 129 53 1 9.900000 0.293600 0.023200 100.660000 1.000000 1 1 +PROF_21 1 173 41 1 9.900000 0.448800 -0.170400 100.200000 1.000000 1 1 +PROF_1 1 64 69 1 9.900000 -0.096800 -0.148800 101.160000 1.000000 1 1 +PROF_2 1 66 119 1 9.900000 0.332000 -0.109600 101.220000 0.100000 1 1 +PROF_3 1 59 89 1 9.900000 -0.159200 0.213600 101.220000 1.000000 1 1 +PROF_4 1 77 195 1 9.900000 0.472800 -0.498400 101.300000 1.000000 1 1 +PROF_5 1 155 161 1 9.900000 -0.159200 0.042400 100.380000 1.000000 1 1 +PROF_6 1 124 174 1 9.900000 0.100000 -0.469600 100.640000 1.000000 1 1 +P1002 1 103 70 1 9.900000 0.085600 -0.168000 100.800000 1.000000 1 1 +P1003 1 100 82 1 9.900000 0.186400 0.463200 100.860000 1.000000 1 1 +PC1_AMS_BIS 1 114 86 1 9.900000 -0.322400 -0.013600 100.790000 1.000000 1 1 +PC2_AMS 1 115 62 1 9.900000 -0.117600 0.206400 100.730000 1.000000 1 1 +PC3_AMS 1 132 70 1 9.900000 -0.226400 0.292000 100.670000 1.000000 1 1 +PC4_AMS 1 143 79 1 9.900000 0.055200 0.431200 100.590000 1.000000 1 1 +PIEZ1 1 159 68 1 9.900000 0.071200 0.328000 100.500000 1.000000 1 1 +PIEZ11 1 197 98 1 9.900000 0.308800 0.125600 99.670000 1.000000 1 1 +PIEZ13 1 200 106 1 9.900000 0.250000 0.364000 99.590000 1.000000 1 1 +PIEZ14 1 202 96 1 9.900000 0.282800 0.021600 99.570000 1.000000 1 1 +PIEZ15 1 204 88 1 9.900000 -0.230400 0.199200 99.610000 1.000000 1 1 +PIEZ16 1 205 81 1 9.900000 0.064400 0.055200 99.550000 1.000000 1 1 +PIEZ17 1 204 78 1 9.900000 -0.112800 0.112000 99.570000 1.000000 1 1 +PIEZ2 1 165 70 1 9.900000 -0.279200 0.309600 100.470000 1.000000 1 1 +PIEZ3 1 170 72 1 9.900000 -0.120800 0.270400 100.450000 1.000000 1 1 +PIEZ5 1 176 75 1 9.900000 -0.306400 0.222400 100.360000 1.000000 1 1 +PIEZ6 1 178 77 1 9.900000 -0.128000 0.275200 100.300000 0.100000 1 1 +PIEZ7 1 182 81 1 9.900000 0.132000 0.325600 100.150000 1.000000 1 1 +PIEZ8 1 186 87 1 9.900000 0.348000 0.064800 99.900000 1.000000 1 1 +PIEZ9 1 190 93 1 9.900000 -0.029600 -0.194400 99.840000 1.000000 1 1 +PIEZM1 1 159 75 1 9.900000 0.469600 0.112800 100.470000 1.000000 1 1 +PIEZM2 1 171 82 1 9.900000 -0.044000 0.277600 100.330000 1.000000 1 1 +PIEZM3 1 195 112 1 9.900000 -0.025600 -0.391200 99.750000 1.000000 1 1 +PIEZM5 1 199 97 1 9.900000 -0.212000 -0.010400 99.580000 1.000000 1 1 +PIEZM6 1 201 85 1 9.900000 -0.024400 -0.112800 99.500000 1.000000 1 1 +PIEZM7 1 176 92 1 9.900000 0.367200 0.444000 100.210000 1.000000 1 1 +PIEZM8 1 188 105 1 9.900000 -0.007200 0.276000 99.830000 0.100000 1 1 +PP202 1 90 71 1 9.900000 0.150400 0.192000 100.970000 1.000000 1 1 +PZ18 1 185 49 1 9.900000 0.348000 0.295200 100.910000 0.500000 1 1 +PZ20 1 189 37 1 9.900000 -0.025600 0.320000 99.400000 0.100000 1 1 +PZ4 1 103 56 1 9.900000 -0.191200 -0.064800 100.770000 1.000000 1 1 +PZ7 1 116 182 1 9.900000 0.029600 0.380000 100.820000 1.000000 1 1 +PZB 1 69 139 1 9.900000 -0.026400 0.170400 101.240000 0.100000 1 1 +PZP1_BIS 1 92 63 1 9.900000 -0.016000 -0.318400 100.890000 1.000000 1 1 +PZ_ALER 1 185 41 1 9.900000 -0.330400 0.443600 100.210000 1.000000 1 1 +PROF_22 1 184 46 1 9.900000 0.004800 -0.433600 100.280000 1.000000 1 1 +Sp1_PzEst 1 159 32 1 9.900000 -0.023200 -0.079600 100.420000 1.000000 1 1 From 1043257b25ef122b19e7f2d57a81b7511f2bcb39 Mon Sep 17 00:00:00 2001 From: jdub Date: Thu, 23 Sep 2021 12:06:42 -0600 Subject: [PATCH 5/7] more work on pstfrom notebook --- dependencies/pyemu/utils/geostats.py | 95 +++++++++++----------------- dependencies/pyemu/utils/pp_utils.py | 6 +- dependencies/pyemu/utils/pst_from.py | 3 +- 3 files changed, 43 insertions(+), 61 deletions(-) diff --git a/dependencies/pyemu/utils/geostats.py b/dependencies/pyemu/utils/geostats.py index 97ce286..dc056db 100644 --- a/dependencies/pyemu/utils/geostats.py +++ b/dependencies/pyemu/utils/geostats.py @@ -1365,20 +1365,20 @@ def _calc_factors_mp( if idx_vals is not None: df.index = [int(i) for i in idx_vals] print("starting interp point loop for {0} points".format(df.shape[0])) + # ensure same order as point data and just pass array + point_cov_data = self.point_cov_df.loc[self.point_data.name, + self.point_data.name].values + point_pairs = [(i, xx, yy) for i, (xx, yy) in enumerate(zip(x, y))] + idist = [[] for _ in x] + inames = [[] for _ in x] + ifacts = [[] for _ in x] + err_var = [np.NaN] * len(x) with mp.Manager() as manager: - - point_pairs = manager.list() - idist = manager.list() - inames = manager.list() - ifacts = manager.list() - err_var = manager.list() - # start = mp.Value('d',0) - for i, (xx, yy) in enumerate(zip(x, y)): - point_pairs.append((i, xx, yy)) - idist.append([]) - inames.append([]) - ifacts.append([]) - err_var.append([np.NaN]) + point_pairs = manager.list(point_pairs) + idist = manager.list(idist) + inames = manager.list(inames) + ifacts = manager.list(ifacts) + err_var = manager.list(err_var) lock = mp.Lock() procs = [] for i in range(num_threads): @@ -1386,14 +1386,13 @@ def _calc_factors_mp( p = mp.Process( target=OrdinaryKrige._worker, args=( - i, self.point_data, point_pairs, inames, idist, ifacts, err_var, - self.point_cov_df, + point_cov_data, self.geostruct, EPSILON, search_radius, @@ -1430,14 +1429,13 @@ def _calc_factors_mp( @staticmethod def _worker( - ithread, point_data, point_pairs, inames, idist, ifacts, err_var, - point_cov_df, + full_point_cov, geostruct, epsilon, search_radius, @@ -1471,28 +1469,25 @@ def _worker( # if idx % 1000 == 0 and idx != 0: # print (ithread, idx,"done",datetime.now()) if np.isnan(ix) or np.isnan(iy): # if nans, skip - # inames.append([]) - # idist.append([]) - # ifacts.append([]) - # err_var.append(np.NaN) - # err_var.insert(idx,np.NaN) ifacts[idx] = [[]] idist[idx] = [[]] inames[idx] = [[]] err_var[idx] = [np.NaN] continue - # calc dist from this interp point to all point data...slow - dist = pd.Series((ptx_array - ix) ** 2 + (pty_array - iy) ** 2, ptnames) - dist.sort_values(inplace=True) - dist = dist.loc[dist <= sqradius] + # calc dist from this interp point to all point data... + # can we just use a numpy approach...? + dist = (ptx_array - ix) ** 2 + (pty_array - iy) ** 2 + sortorder = np.argsort(dist) + dist = dist[sortorder] + pt_names = ptnames[sortorder] + trunc = dist <= sqradius + dist = dist[trunc] + pt_names = pt_names[trunc] + sortorder = sortorder[trunc] # if too few points were found, skip if len(dist) < minpts_interp: - # inames.append([]) - # idist.append([]) - # ifacts.append([]) - # err_var.append(sill) ifacts[idx] = [[]] idist[idx] = [[]] inames[idx] = [[]] @@ -1500,32 +1495,30 @@ def _worker( continue # only the maxpts_interp points - dist = dist.iloc[:maxpts_interp].apply(np.sqrt) - pt_names = dist.index.values + dist = np.sqrt(dist[: maxpts_interp]) + pt_names = pt_names[: maxpts_interp] + sortorder = sortorder[: maxpts_interp] + # if one of the points is super close, just use it and skip - if dist.min() <= epsilon: - # ifacts.append([1.0]) + if dist[0] <= epsilon: ifacts[idx] = [[1.0]] - # idist.append([epsilon]) idist[idx] = [[epsilon]] - # inames.append([dist.idxmin()]) - inames[idx] = [[dist.idxmin()]] - # err_var.append(geostruct.nugget) + inames[idx] = [[pt_names[0]]] err_var[idx] = [[geostruct.nugget]] continue # vextract the point-to-point covariance matrix - point_cov = point_cov_df.loc[pt_names, pt_names] - + # point_cov = full_point_cov.loc[pt_names, pt_names] + point_cov = full_point_cov[tuple([sortorder[:, None], sortorder])] # calc the interp point to points covariance interp_cov = geostruct.covariance_points( - ix, iy, point_data.loc[pt_names, "x"], point_data.loc[pt_names, "y"] + ix, iy, ptx_array[sortorder], pty_array[sortorder] ) # form the linear algebra parts and solve d = len(pt_names) + 1 # +1 for lagrange mult A = np.ones((d, d)) - A[:-1, :-1] = point_cov.values + A[:-1, :-1] = point_cov # .values A[-1, -1] = 0.0 # unbiaised constraint rhs = np.ones((d, 1)) rhs[:-1, 0] = interp_cov @@ -1538,26 +1531,14 @@ def _worker( print("dist:", dist) print("A:", A) print("rhs:", rhs) - - # inames.append([]) - # idist.append([]) - # ifacts.append([]) - # err_var.append(np.NaN) - # err_var.insert(np.NaN) continue assert len(facs) - 1 == len(dist) - # err_var.append(float(sill + facs[-1] - sum([f*c for f,c in zip(facs[:-1],interp_cov)]))) err_var[idx] = [float(sill + facs[-1] - sum([f * c for f, c in zip(facs[:-1], interp_cov)]))] - # inames.append(pt_names) - inames[idx] = [list(pt_names)] - - # idist.append(dist.values) - idist[idx] = [list(dist.values)] - - # ifacts.append(facs[:-1,0]) - ifacts[idx] = [list(facs[:-1, 0])] + inames[idx] = [pt_names.tolist()] + idist[idx] = [dist.tolist()] + ifacts[idx] = [facs[:-1, 0].tolist()] # if verbose == 2: # td = (datetime.now()-start).total_seconds() # print("...took {0}".format(td)) diff --git a/dependencies/pyemu/utils/pp_utils.py b/dependencies/pyemu/utils/pp_utils.py index b129a3f..bae1c3d 100644 --- a/dependencies/pyemu/utils/pp_utils.py +++ b/dependencies/pyemu/utils/pp_utils.py @@ -272,9 +272,9 @@ def setup_pilotpoints_grid( for name, dtype in par_info.dtypes.iteritems(): if dtype == object: shp.field(name=name, fieldType="C", size=50) - elif dtype in [int, np.int, np.int64, np.int32]: + elif dtype in [int, np.int64, np.int32]: shp.field(name=name, fieldType="N", size=50, decimal=0) - elif dtype in [float, np.float, np.float32, np.float64]: + elif dtype in [float, np.float32, np.float64]: shp.field(name=name, fieldType="N", size=50, decimal=10) else: raise Exception( @@ -446,7 +446,7 @@ def write_pp_shapfile(pp_df, shapename=None): shp.field(name=name, fieldType="C", size=50) elif dtype in [int, np.int, np.int64, np.int32]: shp.field(name=name, fieldType="N", size=50, decimal=0) - elif dtype in [float, np.float, np.float32, np.float32]: + elif dtype in [float, np.float32, np.float32]: shp.field(name=name, fieldType="N", size=50, decimal=8) else: raise Exception( diff --git a/dependencies/pyemu/utils/pst_from.py b/dependencies/pyemu/utils/pst_from.py index efadd27..4f43cfa 100644 --- a/dependencies/pyemu/utils/pst_from.py +++ b/dependencies/pyemu/utils/pst_from.py @@ -1731,7 +1731,8 @@ def add_parameters( initial_value = 1.0 elif par_style == 'a': initial_value = 0.0 - lower_bound = -1.0e+10 + if lower_bound >= 0.0: + lower_bound = -1. * upper_bound if transform.lower == "log": if upper_bound <= 0: From 60b8c549d53fff40bb66944614e8916654a79c6c Mon Sep 17 00:00:00 2001 From: Mike Fienen Date: Thu, 23 Sep 2021 13:54:20 -0500 Subject: [PATCH 6/7] merge conflict --- notebooks/modflow_setup/1_preprocessing.ipynb | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/notebooks/modflow_setup/1_preprocessing.ipynb b/notebooks/modflow_setup/1_preprocessing.ipynb index d8d8c1c..1dc5658 100644 --- a/notebooks/modflow_setup/1_preprocessing.ipynb +++ b/notebooks/modflow_setup/1_preprocessing.ipynb @@ -2399,7 +2399,7 @@ "config_data['model']['options']['print_input'] = True\n", "config_data['model']['options']['save_flows'] = True\n", "# packages block\n", - "config_data['model']['packages'] = ['dis', 'ims', 'ic', 'wel', 'oc', 'npf', 'rch', 'sfr']\n" + "config_data['model']['packages'] = ['dis', 'ims', 'ic', 'wel', 'oc', 'npf', 'rch', 'sfr', 'obs']\n" ] }, { @@ -2724,8 +2724,27 @@ }, { "cell_type": "code", - "execution_count": 77, - "id": "e1cce203", + "execution_count": null, + "id": "8316d3e2", + "metadata": {}, + "outputs": [], + "source": [ + "# add in head observations\n", + "config_data['obs'] = dict()\n", + "config_data['obs']['source_data'] = dict()\n", + "config_data['obs']['source_data']['filenames'] = '../../data/sgn/csv/heads_sep2019.csv'\n", + "config_data['obs']['source_data']['column_mappings'] = dict()\n", + "\n", + "config_data['obs']['source_data']['column_mappings']['obsname'] = 'ID'\n", + "config_data['obs']['source_data']['column_mappings']['x'] = 'X'\n", + "config_data['obs']['source_data']['column_mappings']['y'] = 'Y'\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30f0a041", "metadata": {}, "outputs": [], "source": [ From 5c11dea70b3585be59a69c6bd078adcfc06de00a Mon Sep 17 00:00:00 2001 From: Mike Fienen Date: Thu, 23 Sep 2021 13:59:56 -0500 Subject: [PATCH 7/7] merges rock: --- .../2_build_model_from_YML.ipynb | 1062 +---------------- 1 file changed, 40 insertions(+), 1022 deletions(-) diff --git a/notebooks/modflow_setup/2_build_model_from_YML.ipynb b/notebooks/modflow_setup/2_build_model_from_YML.ipynb index 2b26843..3f6dfe6 100644 --- a/notebooks/modflow_setup/2_build_model_from_YML.ipynb +++ b/notebooks/modflow_setup/2_build_model_from_YML.ipynb @@ -2,112 +2,10 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "f96b3e8b", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", - "/Users/JWhite/opt/miniconda3/envs/symple/lib/python3.9/site-packages/rasterstats/io.py:24: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.10 it will stop working\n", - " from collections import Iterable, Mapping\n", - "/Users/JWhite/opt/miniconda3/envs/symple/lib/python3.9/site-packages/rasterstats/io.py:24: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.10 it will stop working\n", - " from collections import Iterable, Mapping\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/gis.py:17: UserWarning: Automatic reprojection functionality requires gis-utils >= 0.2.2\n", - "Please pip install --upgrade gis-utils\n", - " warnings.warn('Automatic reprojection functionality requires gis-utils >= 0.2.2'\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:111: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " dtypes = {'rno': np.int, 'node': np.int, 'k': np.int, 'i': np.int, 'j': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:111: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " dtypes = {'rno': np.int, 'node': np.int, 'k': np.int, 'i': np.int, 'j': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:111: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " dtypes = {'rno': np.int, 'node': np.int, 'k': np.int, 'i': np.int, 'j': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:111: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " dtypes = {'rno': np.int, 'node': np.int, 'k': np.int, 'i': np.int, 'j': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:111: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " dtypes = {'rno': np.int, 'node': np.int, 'k': np.int, 'i': np.int, 'j': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:112: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " 'iseg': np.int, 'ireach': np.int, 'outreach': np.int, 'line_id': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:112: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " 'iseg': np.int, 'ireach': np.int, 'outreach': np.int, 'line_id': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:112: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " 'iseg': np.int, 'ireach': np.int, 'outreach': np.int, 'line_id': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:112: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " 'iseg': np.int, 'ireach': np.int, 'outreach': np.int, 'line_id': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:113: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " 'per': np.int, 'nseg': np.int, 'icalc': np.int, 'outseg': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:113: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " 'per': np.int, 'nseg': np.int, 'icalc': np.int, 'outseg': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:113: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " 'per': np.int, 'nseg': np.int, 'icalc': np.int, 'outseg': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:113: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " 'per': np.int, 'nseg': np.int, 'icalc': np.int, 'outseg': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:114: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " 'iupseg': np.int, 'iprior': np.int, 'nstrpts': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:114: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " 'iupseg': np.int, 'iprior': np.int, 'nstrpts': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:114: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.\n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " 'iupseg': np.int, 'iprior': np.int, 'nstrpts': np.int,\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:115: DeprecationWarning: `np.object` is a deprecated alias for the builtin `object`. To silence this warning, use `object` by itself. Doing this will not modify any behavior and is safe. \n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " 'name': np.object, 'geometry': np.object}\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/sfrmaker/sfrdata.py:115: DeprecationWarning: `np.object` is a deprecated alias for the builtin `object`. To silence this warning, use `object` by itself. Doing this will not modify any behavior and is safe. \n", - "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", - " 'name': np.object, 'geometry': np.object}\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/mfsetup/mfmodel.py:57: UserWarning: Automatic reprojection functionality requires gis-utils >= 0.2.2\n", - "Please pip install --upgrade gis-utils\n", - " warnings.warn('Automatic reprojection functionality requires gis-utils >= 0.2.2'\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/mfsetup/mfmodel.py:60: UserWarning: sfr: sfrmaker_options: add_outlet functionality requires sfrmaker >= 0.6\n", - "Please pip install --upgrade sfrmaker\n", - " warnings.warn('sfr: sfrmaker_options: add_outlet functionality requires sfrmaker >= 0.6'\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n", - "/Users/JWhite/Dev/symple_flopy/notebooks/modflow_setup/../../dependencies/gisutils/__init__.py:14: DeprecationWarning: The 'project' module was renamed to 'projection' to avoid confusion with the project() function.\n", - " warnings.warn(\"The 'project' module was renamed to 'projection' \"\n" - ] - } - ], + "outputs": [], "source": [ "import sys, os\n", "sys.path.append('../../dependencies/')\n", @@ -136,7 +34,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "972ea4f7", "metadata": {}, "outputs": [], @@ -147,383 +45,22 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "4e938b93", "metadata": { "scrolled": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "loading configuration file sgn_config.yml...\n", - "\n", - "Setting up sgn_50 model from configuration in sgn_config.yml\n", - "\n", - "validating configuration...\n", - "DIS package\n", - "done with validation.\n", - "\n", - "setting up model grid...\n", - "wrote /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/sgn_50_grid.json\n", - "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_bbox.shp... Done\n", - "finished in 0.14s\n", - "\n", - "\n", - "Setting up TDIS package...\n", - "finished in 0.01s\n", - "\n", - "\n", - "Setting up IMS package...\n", - "finished in 0.00s\n", - "\n", - "\n", - "Setting up DIS package...\n", - "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/DTM_domain.tif...\n", - "finished in 0.08s\n", - "wrote ././top.dat, took 0.00s\n", - "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/Bott_L1_fix.tif...\n", - "finished in 0.16s\n", - "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/Bott_L2_fix.tif...\n", - "finished in 0.14s\n", - "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/Bott_L3_fix.tif...\n", - "finished in 0.15s\n", - "loading original/sgn_50_top.dat.original, shape=(96, 83), loading original/sgn_50_top.dat.original, shape=(96, 83), took 0.00s\n", - "computing cell thicknesses...\n", - "finished in 0.17s\n", - "\n", - "wrote ././top.dat, took 0.00s\n", - "wrote ././botm_000.dat, took 0.00s\n", - "wrote ././botm_001.dat, took 0.00s\n", - "wrote ././botm_002.dat, took 0.00s\n", - "wrote ././top.dat, took 0.00s\n", - "wrote ././idomain_000.dat, took 0.00s\n", - "wrote ././idomain_001.dat, took 0.00s\n", - "wrote ././idomain_002.dat, took 0.00s\n", - "(re)setting the idomain array...\n", - "computing cell thicknesses...\n", - "finished in 0.19s\n", - "\n", - "setting up model grid...\n", - "wrote /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/sgn_50_grid.json\n", - "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_bbox.shp... Done\n", - "finished in 0.11s\n", - "\n", - "wrote original/lakarr_000.dat, took 0.00s\n", - "wrote original/lakarr_001.dat, took 0.00s\n", - "wrote original/lakarr_002.dat, took 0.00s\n", - "loading original/sgn_50_top.dat.original, shape=(96, 83), took 0.00s\n", - "computing cell thicknesses...\n", - "finished in 0.22s\n", - "\n", - "wrote ././top.dat, took 0.00s\n", - "wrote ././botm_000.dat, took 0.00s\n", - "wrote ././botm_001.dat, took 0.00s\n", - "wrote ././botm_002.dat, took 0.00s\n", - "wrote ././top.dat, took 0.00s\n", - "wrote ././idomain_000.dat, took 0.00s\n", - "wrote ././idomain_001.dat, took 0.00s\n", - "wrote ././idomain_002.dat, took 0.00s\n", - "setting up model grid...\n", - "wrote /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/sgn_50_grid.json\n", - "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_bbox.shp... Done\n", - "finished in 0.13s\n", - "\n", - "wrote ././irch.dat, took 0.00s\n", - "finished in 1.54s\n", - "\n", - "\n", - "Setting up IC package...\n", - "wrote ././DTM_domain.tif, took 0.00s\n", - "wrote ././DTM_domain.tif, took 0.00s\n", - "wrote ././DTM_domain.tif, took 0.00s\n", - "finished in 0.02s\n", - "\n", - "\n", - "Setting up NPF package...\n", - "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/k_field0.tif...\n", - "finished in 0.15s\n", - "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/k_field1.tif...\n", - "finished in 0.13s\n", - "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/k_field2.tif...\n", - "finished in 0.14s\n", - "wrote ././k_000.dat, took 0.00s\n", - "wrote ././k_001.dat, took 0.00s\n", - "wrote ././k_002.dat, took 0.00s\n", - "No data were specified for npf package, variable k33\n", - "finished in 0.45s\n", - "\n", - "\n", - "Setting up RCH package...\n", - "wrote ././irch.dat, took 0.00s\n", - "reading data from /Users/JWhite/Dev/symple_flopy/data/sgn/raster/rch.tif...\n", - "finished in 0.15s\n", - "wrote ././rch_000.dat, took 0.00s\n", - "finished in 0.17s\n", - "\n", - "\n", - "Setting up OC package...\n", - "finished in 0.00s\n", - "\n", - "\n", - "Setting up SFR package...\n", - "\n", - "reading /Users/JWhite/Dev/symple_flopy/data/sgn/shp/River_Lambro_segmented.shp...\n", - "filtering on bounding box 1516766.2711835166, 5028909.73961192, 1521954.2235464402, 5034571.134964784...\n", - "--> building dataframe... (may take a while for large shapefiles)\n", - "\n", - "SFRmaker version 0.post31.dev0+g191fdd7\n", - "\n", - "Creating sfr dataset...\n", - "\n", - "Creating grid class instance from flopy Grid instance...\n", - "grid class created in 0.23s\n", - "\n", - "Model grid information\n", - "structured grid\n", - "nnodes: 7,968\n", - "nlay: 1\n", - "nrow: 96\n", - "ncol: 83\n", - "model length units: undefined\n", - "crs: EPSG:3003\n", - "bounds: 1516766.27, 5028909.74, 1521954.22, 5034571.13\n", - "active area defined by: all cells\n", - "\n", - "/Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup\n", - "sgn_50 model version 0.post31.dev0+g191fdd7\n", - "3 layer(s), 96 row(s), 83 column(s)\n", - "delr: [50.00...50.00] meters\n", - "delc: [50.00...50.00] meters\n", - "CRS: EPSG:3003\n", - "length units: meters\n", - "xll: 1517927.496282395; yll: 5028909.73961192; rotation: 14.0\n", - "Bounds: (1516766.2711835166, 1521954.2235464402, 5028909.73961192, 5034571.134964784)\n", - "Packages: dis ic npf rcha_0 oc\n", - "1 period(s):\n", - " per start_datetime end_datetime perlen steady nstp\n", - " 0 2021-01-01 2022-01-01 01:06:40 31540000.0 True 1\n", - " ...\n", - " 0 2021-01-01 2022-01-01 01:06:40 31540000.0 True 1\n", - "\n", - "Culling hydrography to active area...\n", - "starting lines: 10\n", - "remaining lines: 10\n", - "finished in 0.00s\n", - "\n", - "\n", - "Intersecting 10 flowlines with 7,968 grid cells...\n", - "Intersecting 10 features...\n", - "10\n", - "finished in 0.17s\n", - "\n", - "Setting up reach data... (may take a few minutes for large grids)\n", - "finished in 0.02s\n", - "\n", - "Computing widths...\n", - "\n", - "Dropping 3 reaches with length < 2.50 meters...\n", - "\n", - "Repairing routing connections...\n", - "enforcing best segment numbering...\n", - "\n", - "Setting up segment data...\n", - "Model grid information\n", - "structured grid\n", - "nnodes: 7,968\n", - "nlay: 1\n", - "nrow: 96\n", - "ncol: 83\n", - "model length units: undefined\n", - "crs: EPSG:3003\n", - "bounds: 1516766.27, 5028909.74, 1521954.22, 5034571.13\n", - "active area defined by: all cells\n", - "\n", - "\n", - "Time to create sfr dataset: 0.61s\n", - "\n", - "running rasterstats.zonal_stats on buffered LineStrings...\n", - "finished in 0.24s\n", - "\n", - "\n", - "Smoothing elevations...\n", - "finished in 0.01s\n", - "wrote /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/tables/sgn_50_sfr_reach_data.csv\n", - "wrote /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/tables/sgn_50_sfr_segment_data.csv\n", - "converting segment data to period data...\n", - "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_sfr_cells.shp... Done\n", - "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_sfr_outlets.shp... Done\n", - "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_sfr_lines.shp... Done\n", - "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_sfr_routing.shp... Done\n", - "No period data to export!\n", - "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_sfr_observations.shp... Done\n", - "No non-zero values of flow to export!\n", - "converting reach and segment data to package data...\n", - "converting segment data to period data...\n", - "(re)setting the idomain array...\n", - "computing cell thicknesses...\n", - "finished in 0.18s\n", - "\n", - "wrote original/lakarr_000.dat, took 0.00s\n", - "wrote original/lakarr_001.dat, took 0.00s\n", - "wrote original/lakarr_002.dat, took 0.00s\n", - "loading original/sgn_50_top.dat.original, shape=(96, 83), took 0.00s\n", - "computing cell thicknesses...\n", - "finished in 0.19s\n", - "\n", - "wrote ././top.dat, took 0.00s\n", - "wrote ././botm_000.dat, took 0.00s\n", - "wrote ././botm_001.dat, took 0.00s\n", - "wrote ././botm_002.dat, took 0.00s\n", - "wrote ././top.dat, took 0.00s\n", - "wrote ././idomain_000.dat, took 0.00s\n", - "wrote ././idomain_001.dat, took 0.00s\n", - "wrote ././idomain_002.dat, took 0.00s\n", - "setting up model grid...\n", - "wrote /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/sgn_50_grid.json\n", - "writing /Users/JWhite/Dev/symple_flopy/models/sgn_mfsetup/postproc/shps/sgn_50_bbox.shp... Done\n", - "finished in 0.11s\n", - "\n", - "wrote ././irch.dat, took 0.00s\n", - "finished in 2.21s\n", - "\n", - "\n", - "Setting up WEL package...\n", - "getting i, j locations...\n", - "finished in 0.00s\n", - "\n", - "finished in 0.11s\n", - "\n", - "finished setting up model in 4.73s\n", - "\n", - "sgn_50 model version 0.post31.dev0+g191fdd7\n", - "3 layer(s), 96 row(s), 83 column(s)\n", - "delr: [50.00...50.00] meters\n", - "delc: [50.00...50.00] meters\n", - "CRS: EPSG:3003\n", - "length units: meters\n", - "xll: 1517927.496282395; yll: 5028909.73961192; rotation: 14.0\n", - "Bounds: (1516766.2711835166, 1521954.2235464402, 5028909.73961192, 5034571.134964784)\n", - "Packages: dis ic npf rcha_0 oc sfr_0 wel_0\n", - "1 period(s):\n", - " per start_datetime end_datetime perlen steady nstp\n", - " 0 2021-01-01 2022-01-01 01:06:40 31540000.0 True 1\n", - " ...\n", - " 0 2021-01-01 2022-01-01 01:06:40 31540000.0 True 1\n" - ] - } - ], + "outputs": [], "source": [ "m = mfsetup.MF6model.setup_from_yaml('sgn_config.yml')" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "2f85d9d5", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "writing simulation...\n", - " writing simulation name file...\n", - " writing simulation tdis package...\n", - " writing ims package ims_-1...\n", - " writing model sgn_50...\n", - " writing model name file...\n", - " writing package dis...\n", - " writing package ic...\n", - " writing package npf...\n", - " writing package rcha_0...\n", - " writing package oc...\n", - " writing package sfr_0...\n", - " writing package wel_0...\n", - "INFORMATION: maxbound in ('gwf6', 'wel', 'dimensions') changed to 78 based on size of stress_period_data\n", - "SFRmaker v. 0.post31.dev0+g191fdd7\n", - "\n", - "Running Flopy v. 3.3.5 diagnostics...\n", - "passed.\n", - "\n", - "Checking for continuity in segment and reach numbering...\n", - "passed.\n", - "\n", - "Checking for increasing segment numbers in downstream direction...\n", - "passed.\n", - "\n", - "Checking for circular routing...\n", - "passed.\n", - "\n", - "Checking reach connections for proximity...\n", - "0 segments with non-adjacent reaches found.\n", - "At segments:\n", - "\n", - "\n", - "0 segments with non-adjacent reaches found.\n", - "At segments:\n", - "\n", - "\n", - "\n", - "Checking for model cells with multiple non-zero SFR conductances...\n", - "8 model cells with multiple non-zero SFR conductances found.\n", - "This may lead to circular routing between collocated reaches.\n", - "Nodes with overlapping conductances:\n", - "k\ti\tj\tiseg\tireach\trchlen\tstrthick\tstrhc1\n", - "0\t8\t63\t1\t10\t7.924251079559326\t1.0\t1.0\n", - "0\t8\t63\t2\t1\t47.34646224975586\t1.0\t1.0\n", - "0\t16\t66\t2\t14\t5.979315280914307\t1.0\t1.0\n", - "0\t16\t66\t3\t1\t41.623817443847656\t1.0\t1.0\n", - "0\t24\t69\t3\t12\t37.11835861206055\t1.0\t1.0\n", - "0\t24\t69\t4\t1\t16.12721824645996\t1.0\t1.0\n", - "0\t26\t73\t4\t11\t15.494623184204102\t1.0\t1.0\n", - "0\t26\t73\t5\t1\t29.43027687072754\t1.0\t1.0\n", - "0\t36\t75\t5\t19\t20.42424201965332\t1.0\t1.0\n", - "0\t36\t75\t6\t1\t31.1514949798584\t1.0\t1.0\n", - "0\t47\t72\t6\t14\t14.13512134552002\t1.0\t1.0\n", - "0\t47\t72\t7\t1\t29.998180389404297\t1.0\t1.0\n", - "0\t64\t72\t8\t10\t24.63616371154785\t1.0\t1.0\n", - "0\t64\t72\t9\t1\t26.59016227722168\t1.0\t1.0\n", - "0\t82\t75\t9\t22\t21.188451766967773\t1.0\t1.0\n", - "0\t82\t75\t10\t1\t30.045856475830078\t1.0\t1.0\n", - "\n", - "Checking for streambed tops of less than -10...\n", - "isfropt setting of 1,2 or 3 requires strtop information!\n", - "\n", - "\n", - "Checking for streambed tops of greater than 15000...\n", - "isfropt setting of 1,2 or 3 requires strtop information!\n", - "\n", - "\n", - "Checking segment_data for downstream rises in streambed elevation...\n", - "Segment elevup and elevdn not specified for nstrm=-137 and isfropt=1\n", - "passed.\n", - "\n", - "Checking reach_data for downstream rises in streambed elevation...\n", - "passed.\n", - "\n", - "Checking reach_data for inconsistencies between streambed elevations and the model grid...\n", - "passed.\n", - "\n", - "Checking segment_data for inconsistencies between segment end elevations and the model grid...\n", - "Segment elevup and elevdn not specified for nstrm=-137 and isfropt=1\n", - "passed.\n", - "\n", - "Checking for streambed slopes of less than 0.0001...\n", - "passed.\n", - "\n", - "Checking for streambed slopes of greater than 1.0...\n", - "passed.\n", - "\n", - "wrote sgn_50_SFR.chk\n", - "wrote sgn_50.sfr.obs\n", - "converting reach and segment data to package data...\n", - "wrote ././sgn_50_packagedata.dat\n", - "wrote ./sgn_50.sfr\n" - ] - } - ], + "outputs": [], "source": [ "m.write_input()" ] @@ -538,7 +75,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "06c36717", "metadata": {}, "outputs": [], @@ -556,24 +93,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "74784609", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# read in the boundary polygon\n", "boundary = gp.read_file(datapath / 'shp' / 'Model_domain.shp')\n", @@ -585,7 +108,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "00fe3084", "metadata": {}, "outputs": [], @@ -596,98 +119,10 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "433def84", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellidsverticesareasixshapes
0(0, 0)[([(array([1516807.7649682]), array([5033525.9...1818.572486POLYGON ((1516807.764968205 5033525.973979044,...
1(0, 1)[([(array([1516818.50671796]), array([5033564....768.997804POLYGON ((1516818.506717961 5033564.332087163,...
2(0, 2)[([(array([1516867.02150427]), array([5033576....768.997804POLYGON ((1516867.021504275 5033576.428181943,...
3(0, 3)[([(array([1516915.53629059]), array([5033588....768.997804POLYGON ((1516915.536290589 5033588.524276723,...
4(0, 4)[([(array([1516964.0510769]), array([5033600.6...768.997804POLYGON ((1516964.051076903 5033600.620371503,...
\n", - "
" - ], - "text/plain": [ - " cellids vertices areas \\\n", - "0 (0, 0) [([(array([1516807.7649682]), array([5033525.9... 1818.572486 \n", - "1 (0, 1) [([(array([1516818.50671796]), array([5033564.... 768.997804 \n", - "2 (0, 2) [([(array([1516867.02150427]), array([5033576.... 768.997804 \n", - "3 (0, 3) [([(array([1516915.53629059]), array([5033588.... 768.997804 \n", - "4 (0, 4) [([(array([1516964.0510769]), array([5033600.6... 768.997804 \n", - "\n", - " ixshapes \n", - "0 POLYGON ((1516807.764968205 5033525.973979044,... \n", - "1 POLYGON ((1516818.506717961 5033564.332087163,... \n", - "2 POLYGON ((1516867.021504275 5033576.428181943,... \n", - "3 POLYGON ((1516915.536290589 5033588.524276723,... \n", - "4 POLYGON ((1516964.051076903 5033600.620371503,... " - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ix_df = pd.DataFrame.from_records(ix_boundary)\n", "ix_df.head()" @@ -695,33 +130,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "38616ea9", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# read in the september 2019 measured heads to make the GHB data\n", "sep19_head = fu.Raster.load(datapath / 'raster' / 'heads_sep2019.asc')\n", @@ -731,7 +143,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "113499a4", "metadata": {}, "outputs": [], @@ -742,7 +154,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "a7f0101f", "metadata": {}, "outputs": [], @@ -759,7 +171,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "77e9d192", "metadata": {}, "outputs": [], @@ -772,227 +184,47 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "37dcb490", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "writing simulation...\n", - " writing simulation name file...\n", - " writing simulation tdis package...\n", - " writing ims package ims_-1...\n", - " writing model sgn_50...\n", - " writing model name file...\n", - " writing package dis...\n", - " writing package ic...\n", - " writing package npf...\n", - " writing package rcha_0...\n", - " writing package oc...\n", - " writing package sfr_0...\n", - " writing package wel_0...\n", - " writing package ghb_0...\n", - "INFORMATION: maxbound in ('gwf6', 'ghb', 'dimensions') changed to 708 based on size of stress_period_data\n", - "SFRmaker v. 0.post31.dev0+g191fdd7\n", - "\n", - "Running Flopy v. 3.3.5 diagnostics...\n", - "passed.\n", - "\n", - "Checking for continuity in segment and reach numbering...\n", - "passed.\n", - "\n", - "Checking for increasing segment numbers in downstream direction...\n", - "passed.\n", - "\n", - "Checking for circular routing...\n", - "passed.\n", - "\n", - "Checking reach connections for proximity...\n", - "0 segments with non-adjacent reaches found.\n", - "At segments:\n", - "\n", - "\n", - "0 segments with non-adjacent reaches found.\n", - "At segments:\n", - "\n", - "\n", - "\n", - "Checking for model cells with multiple non-zero SFR conductances...\n", - "8 model cells with multiple non-zero SFR conductances found.\n", - "This may lead to circular routing between collocated reaches.\n", - "Nodes with overlapping conductances:\n", - "k\ti\tj\tiseg\tireach\trchlen\tstrthick\tstrhc1\n", - "0\t8\t63\t1\t10\t7.924251079559326\t1.0\t1.0\n", - "0\t8\t63\t2\t1\t47.34646224975586\t1.0\t1.0\n", - "0\t16\t66\t2\t14\t5.979315280914307\t1.0\t1.0\n", - "0\t16\t66\t3\t1\t41.623817443847656\t1.0\t1.0\n", - "0\t24\t69\t3\t12\t37.11835861206055\t1.0\t1.0\n", - "0\t24\t69\t4\t1\t16.12721824645996\t1.0\t1.0\n", - "0\t26\t73\t4\t11\t15.494623184204102\t1.0\t1.0\n", - "0\t26\t73\t5\t1\t29.43027687072754\t1.0\t1.0\n", - "0\t36\t75\t5\t19\t20.42424201965332\t1.0\t1.0\n", - "0\t36\t75\t6\t1\t31.1514949798584\t1.0\t1.0\n", - "0\t47\t72\t6\t14\t14.13512134552002\t1.0\t1.0\n", - "0\t47\t72\t7\t1\t29.998180389404297\t1.0\t1.0\n", - "0\t64\t72\t8\t10\t24.63616371154785\t1.0\t1.0\n", - "0\t64\t72\t9\t1\t26.59016227722168\t1.0\t1.0\n", - "0\t82\t75\t9\t22\t21.188451766967773\t1.0\t1.0\n", - "0\t82\t75\t10\t1\t30.045856475830078\t1.0\t1.0\n", - "\n", - "Checking for streambed tops of less than -10...\n", - "isfropt setting of 1,2 or 3 requires strtop information!\n", - "\n", - "\n", - "Checking for streambed tops of greater than 15000...\n", - "isfropt setting of 1,2 or 3 requires strtop information!\n", - "\n", - "\n", - "Checking segment_data for downstream rises in streambed elevation...\n", - "Segment elevup and elevdn not specified for nstrm=-137 and isfropt=1\n", - "passed.\n", - "\n", - "Checking reach_data for downstream rises in streambed elevation...\n", - "passed.\n", - "\n", - "Checking reach_data for inconsistencies between streambed elevations and the model grid...\n", - "passed.\n", - "\n", - "Checking segment_data for inconsistencies between segment end elevations and the model grid...\n", - "Segment elevup and elevdn not specified for nstrm=-137 and isfropt=1\n", - "passed.\n", - "\n", - "Checking for streambed slopes of less than 0.0001...\n", - "passed.\n", - "\n", - "Checking for streambed slopes of greater than 1.0...\n", - "passed.\n", - "\n", - "wrote sgn_50_SFR.chk\n", - "wrote sgn_50.sfr.obs\n", - "converting reach and segment data to package data...\n", - "wrote ././sgn_50_packagedata.dat\n", - "wrote ./sgn_50.sfr\n" - ] - } - ], + "outputs": [], "source": [ "m.write_input()" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "c6741479", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "sgn_50 model version 0.post31.dev0+g191fdd7\n", - "3 layer(s), 96 row(s), 83 column(s)\n", - "delr: [50.00...50.00] meters\n", - "delc: [50.00...50.00] meters\n", - "CRS: EPSG:3003\n", - "length units: meters\n", - "xll: 1517927.496282395; yll: 5028909.73961192; rotation: 14.0\n", - "Bounds: (1516766.2711835166, 1521954.2235464402, 5028909.73961192, 5034571.134964784)\n", - "Packages: dis ic npf rcha_0 oc sfr_0 wel_0 ghb_0\n", - "1 period(s):\n", - " per start_datetime end_datetime perlen steady nstp\n", - " 0 2021-01-01 2022-01-01 01:06:40 31540000.0 True 1\n", - " ...\n", - " 0 2021-01-01 2022-01-01 01:06:40 31540000.0 True 1" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "m" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "id": "ea8eba2b", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "wrote testgrid.shp\n" - ] - } - ], + "outputs": [], "source": [ "m.dis.export('testgrid.shp')" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "a621cc63", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " MODFLOW 6\n", - " U.S. GEOLOGICAL SURVEY MODULAR HYDROLOGIC MODEL\n", - " VERSION 6.3.0 release candidate 07/30/2021\n", - " ***DEVELOP MODE***\n", - "\n", - " MODFLOW 6 compiled Jul 31 2021 20:33:12 with IFORT compiler (ver. 19.10.3)\n", - "\n", - "This software is preliminary or provisional and is subject to \n", - "revision. It is being provided to meet the need for timely best \n", - "science. The software has not received final approval by the U.S. \n", - "Geological Survey (USGS). No warranty, expressed or implied, is made \n", - "by the USGS or the U.S. Government as to the functionality of the \n", - "software and related material nor shall the fact of release \n", - "constitute any such warranty. The software is provided on the \n", - "condition that neither the USGS nor the U.S. Government shall be held \n", - "liable for any damages resulting from the authorized or unauthorized \n", - "use of the software.\n", - "\n", - " \n", - " Run start date and time (yyyy/mm/dd hh:mm:ss): 2021/09/22 15:05:40\n", - " \n", - " Writing simulation list file: mfsim.lst\n", - " Using Simulation name file: mfsim.nam\n", - " \n", - " Solving: Stress period: 1 Time step: 1\n", - " \n", - " Run end date and time (yyyy/mm/dd hh:mm:ss): 2021/09/22 15:05:41\n", - " Elapsed run time: 0.757 Seconds\n", - " \n", - " Normal termination of simulation.\n" - ] - }, - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "os.system('mf6')" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "id": "05d6aa79", "metadata": {}, "outputs": [], @@ -1002,40 +234,17 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "id": "dddcf740", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "plt.imshow(top)" ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "id": "d2d29541", "metadata": {}, "outputs": [], @@ -1045,33 +254,10 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "id": "90faeb30", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "plt.imshow(np.squeeze(h)[0])\n", "plt.colorbar()" @@ -1087,33 +273,10 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "id": "935d533d", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "plt.imshow(top-np.squeeze(h)[0])\n", "plt.colorbar()" @@ -1121,7 +284,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "id": "f4cc1582", "metadata": {}, "outputs": [], @@ -1131,165 +294,20 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "id": "8b68b919", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
WEL_INGHB_INRCH_INSFR_INTOTAL_INWEL_OUTGHB_OUTRCH_OUTSFR_OUTTOTAL_OUTIN-OUTPERCENT_DISCREPANCY
1971-01-01 01:11:58.9453120.12887.18020.0676020.07.37660.76661.62110.04.98897.3766-0.000021-0.0
\n", - "
" - ], - "text/plain": [ - " WEL_IN GHB_IN RCH_IN SFR_IN TOTAL_IN \\\n", - "1971-01-01 01:11:58.945312 0.1288 7.1802 0.067602 0.0 7.3766 \n", - "\n", - " WEL_OUT GHB_OUT RCH_OUT SFR_OUT TOTAL_OUT \\\n", - "1971-01-01 01:11:58.945312 0.7666 1.6211 0.0 4.9889 7.3766 \n", - "\n", - " IN-OUT PERCENT_DISCREPANCY \n", - "1971-01-01 01:11:58.945312 -0.000021 -0.0 " - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df1" ] }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "id": "d592657b", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
WEL_INGHB_INRCH_INSFR_INTOTAL_INWEL_OUTGHB_OUTRCH_OUTSFR_OUTTOTAL_OUTIN-OUTPERCENT_DISCREPANCY
1971-01-01 01:11:58.9453124062352.0226463072.02132160.250.0232657584.024178564.051130412.00.0157349280.0232658256.0-668.346008-0.0
\n", - "
" - ], - "text/plain": [ - " WEL_IN GHB_IN RCH_IN SFR_IN \\\n", - "1971-01-01 01:11:58.945312 4062352.0 226463072.0 2132160.25 0.0 \n", - "\n", - " TOTAL_IN WEL_OUT GHB_OUT RCH_OUT \\\n", - "1971-01-01 01:11:58.945312 232657584.0 24178564.0 51130412.0 0.0 \n", - "\n", - " SFR_OUT TOTAL_OUT IN-OUT \\\n", - "1971-01-01 01:11:58.945312 157349280.0 232658256.0 -668.346008 \n", - "\n", - " PERCENT_DISCREPANCY \n", - "1971-01-01 01:11:58.945312 -0.0 " - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df2" ] @@ -1327,7 +345,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.6" + "version": "3.9.2" } }, "nbformat": 4,