From c519140041b60912b46f7b00a69177750b268b7c Mon Sep 17 00:00:00 2001 From: Mike Taves Date: Fri, 4 Aug 2023 23:45:24 +1200 Subject: [PATCH 1/2] refactor(expired deprecation): remaining references to SpatialReference --- autotest/test_export.py | 10 +++--- autotest/test_modflow.py | 2 +- docs/flopy_method_dependencies.md | 6 ++-- flopy/discretization/grid.py | 8 ----- flopy/export/shapefile_utils.py | 20 +++++++---- flopy/mbase.py | 33 +++++++++--------- flopy/modflow/mfdis.py | 58 +------------------------------ flopy/modflow/mfsfr2.py | 2 +- flopy/mt3d/mt.py | 6 ---- flopy/pakbase.py | 2 -- flopy/plot/plotutil.py | 2 +- flopy/utils/binaryfile.py | 20 ----------- flopy/utils/reference.py | 5 +-- 13 files changed, 43 insertions(+), 131 deletions(-) diff --git a/autotest/test_export.py b/autotest/test_export.py index 379353be18..51e238f398 100644 --- a/autotest/test_export.py +++ b/autotest/test_export.py @@ -198,7 +198,7 @@ def test_freyberg_export(function_tmpdir, example_data_path): verbose=False, load_only=["DIS", "BAS6", "NWT", "OC", "RCH", "WEL", "DRN", "UPW"], ) - # test export without instantiating an sr + # test export without instantiating a modelgrid m.modelgrid.crs = None shape = function_tmpdir / f"{name}_drn_sparse.shp" m.drn.stress_period_data.export(shape, sparse=True) @@ -211,7 +211,7 @@ def test_freyberg_export(function_tmpdir, example_data_path): m.modelgrid = StructuredGrid( delc=m.dis.delc.array, delr=m.dis.delr.array, crs=3070 ) - # test export with an sr, regardless of whether or not wkt was found + # test export with a modelgrid, regardless of whether or not wkt was found m.drn.stress_period_data.export(shape, sparse=True) for suffix in [".dbf", ".prj", ".shp", ".shx"]: part = shape.with_suffix(suffix) @@ -221,16 +221,16 @@ def test_freyberg_export(function_tmpdir, example_data_path): m.modelgrid = StructuredGrid( delc=m.dis.delc.array, delr=m.dis.delr.array, crs=3070 ) - # verify that attributes have same sr as parent + # verify that attributes have same modelgrid as parent assert m.drn.stress_period_data.mg.crs == m.modelgrid.crs assert m.drn.stress_period_data.mg.xoffset == m.modelgrid.xoffset assert m.drn.stress_period_data.mg.yoffset == m.modelgrid.yoffset assert m.drn.stress_period_data.mg.angrot == m.modelgrid.angrot - # get wkt text was fetched from spatialreference.org + # get wkt text from pyproj wkt = m.modelgrid.crs.to_wkt() - # if wkt text was fetched from spatialreference.org + # if wkt text was fetched from pyproj if wkt is not None: # test default package export shape = function_tmpdir / f"{name}_dis.shp" diff --git a/autotest/test_modflow.py b/autotest/test_modflow.py index a1e0c149fa..d19a255d37 100644 --- a/autotest/test_modflow.py +++ b/autotest/test_modflow.py @@ -560,7 +560,7 @@ def test_namfile_readwrite(function_tmpdir, example_data_path): angrot=30, ) - # test reading and writing of SR information to namfile + # test reading and writing of modelgrid information to namfile m.write_input() m2 = Modflow.load("junk.nam", model_ws=ws) diff --git a/docs/flopy_method_dependencies.md b/docs/flopy_method_dependencies.md index 72841add05..aa1ac03687 100644 --- a/docs/flopy_method_dependencies.md +++ b/docs/flopy_method_dependencies.md @@ -7,10 +7,10 @@ Additional dependencies to use optional FloPy helper methods are listed below. | `.export(*.shp)` | **Pyshp** >= 2.0.0 | | `.export(*.nc)` | **netcdf4** >= 1.1, and **python-dateutil** >= 2.4.0 | | `.export(*.tif)` | **rasterio** | -| `.export(*.asc)` in `flopy.utils.reference` `SpatialReference` class | **scipy.ndimage** | -| `.interpolate()` in `flopy.utils.reference` `SpatialReference` class | **scipy.interpolate** | +| `.export_array(*.asc)` in `flopy.export.utils` | **scipy.ndimage** | +| `.resample_to_grid()` in `flopy.utils.rasters` | **scipy.interpolate** | | `.interpolate()` in `flopy.mf6.utils.reference` `StructuredSpatialReference` class | **scipy.interpolate** | -| `._parse_units_from_proj4()` in `flopy.utils.reference` `SpatialReference` class | **pyproj** | +| `.get_authority_crs()` in `flopy.utils.crs` | **pyproj** >= 2.2.0 | | `.generate_classes()` in `flopy.mf6.utils` | [**modflow-devtools**](https://github.com/MODFLOW-USGS/modflow-devtools) | | `GridIntersect()` in `flopy.utils.gridintersect` | **shapely** | | `GridIntersect().plot_polygon()` in `flopy.utils.gridintersect` | **shapely** and **descartes** | diff --git a/flopy/discretization/grid.py b/flopy/discretization/grid.py index 39d8bcfbe9..0fe69caf55 100644 --- a/flopy/discretization/grid.py +++ b/flopy/discretization/grid.py @@ -1193,14 +1193,6 @@ def _yul_to_yll(self, yul, angrot=None): else: return yul - (np.cos(self.angrot_radians) * yext) - def _set_sr_coord_info(self, sr): - self._xoff = sr.xll - self._yoff = sr.yll - self._angrot = sr.rotation - self._epsg = sr.epsg - self._proj4 = sr.proj4_str - self._require_cache_updates() - def _require_cache_updates(self): for cache_data in self._cache_dict.values(): cache_data.out_of_date = True diff --git a/flopy/export/shapefile_utils.py b/flopy/export/shapefile_utils.py index 87184b74fd..ffe8f527e1 100644 --- a/flopy/export/shapefile_utils.py +++ b/flopy/export/shapefile_utils.py @@ -15,6 +15,7 @@ import numpy as np from ..datbase import DataInterface, DataType +from ..discretization.grid import Grid from ..utils import Util3d, flopy_io, import_optional_dependency from ..utils.crs import get_crs @@ -28,7 +29,8 @@ def write_gridlines_shapefile(filename: Union[str, os.PathLike], mg): ---------- filename : str or PathLike path of the shapefile to write - mg : model grid + mg : flopy.discretization.grid.Grid object + flopy model grid Returns ------- @@ -36,6 +38,10 @@ def write_gridlines_shapefile(filename: Union[str, os.PathLike], mg): """ shapefile = import_optional_dependency("shapefile") + if not isinstance(mg, Grid): + raise ValueError( + f"'mg' must be a flopy Grid subclass instance; found '{type(mg)}'" + ) wr = shapefile.Writer(str(filename), shapeType=shapefile.POLYLINE) wr.field("number", "N", 18, 0) grid_lines = mg.grid_lines @@ -68,7 +74,7 @@ def write_grid_shapefile( ---------- path : str or PathLike shapefile file path - mg : flopy.discretization.Grid object + mg : flopy.discretization.grid.Grid object flopy model grid array_dict : dict dictionary of model input arrays @@ -101,7 +107,11 @@ def write_grid_shapefile( w = shapefile.Writer(str(path), shapeType=shapefile.POLYGON) w.autoBalance = 1 - if mg.grid_type == "structured": + if not isinstance(mg, Grid): + raise ValueError( + f"'mg' must be a flopy Grid subclass instance; found '{type(mg)}'" + ) + elif mg.grid_type == "structured": verts = [ mg.get_cell_vertices(i, j) for i in range(mg.nrow) @@ -112,7 +122,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(f"Grid type {mg.grid_type} not supported.") + raise NotImplementedError(f"Grid type {mg.grid_type} not supported.") # set up the attribute fields and arrays of attributes if mg.grid_type == "structured": @@ -293,8 +303,6 @@ def model_attributes_to_shapefile( pak = ml.get_package(pname) attrs = dir(pak) if pak is not None: - if "sr" in attrs: - attrs.remove("sr") if "start_datetime" in attrs: attrs.remove("start_datetime") for attr in attrs: diff --git a/flopy/mbase.py b/flopy/mbase.py index 7e7ca668ae..0b89e96a29 100644 --- a/flopy/mbase.py +++ b/flopy/mbase.py @@ -696,19 +696,29 @@ def __getattr__(self, item): Parameters ---------- item : str - 3 character package name (case insensitive) or "sr" to access - the SpatialReference instance of the ModflowDis object + This can be one of: + + * A 3-character package name (case insensitive) returns package + * "tr" to access the time discretization object + * "modelgrid" to access the spatial discretization object + * "nper" to get the number of stress periods + * "start_datetime" to get str describing model start date/time Returns ------- - sr : SpatialReference instance - pp : Package object - Package object of type :class:`flopy.pakbase.Package` + object, int or None + Package object of type :class:`flopy.pakbase.Package`, + :class:`flopy.utils.reference.TemporalReference`, int or None. + + Raises + ------ + AttributeError + When package or object name cannot be resolved. Note ---- - if self.dis is not None, then the spatial reference instance is updated + if self.dis is not None, then the modelgrid instance is updated using self.dis.delr, self.dis.delc, and self.dis.lenuni before being returned """ @@ -1388,17 +1398,6 @@ def __setattr__(self, key, value): self._set_name(value) elif key == "model_ws": self.change_model_ws(value) - elif key == "sr" and value.__class__.__name__ == "SpatialReference": - warnings.warn( - "SpatialReference has been deprecated.", - category=DeprecationWarning, - ) - if self.dis is not None: - self.dis.sr = value - else: - raise Exception( - "cannot set SpatialReference - ModflowDis not found" - ) elif key == "tr": assert isinstance( value, discretization.reference.TemporalReference diff --git a/flopy/modflow/mfdis.py b/flopy/modflow/mfdis.py index 4797d55cac..a146eeb8d0 100644 --- a/flopy/modflow/mfdis.py +++ b/flopy/modflow/mfdis.py @@ -773,62 +773,11 @@ def load(cls, f, model, ext_unit_dict=None, check=True): f = open(filename, "r") # dataset 0 -- header - header = "" while True: line = f.readline() if line[0] != "#": break - header += line.strip() - - header = header.replace("#", "") - xul, yul = None, None - rotation = None - proj4_str = None - start_datetime = "1/1/1970" - dep = False - for item in header.split(","): - if "xul" in item.lower(): - try: - xul = float(item.split(":")[1]) - except: - if model.verbose: - 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(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(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(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(f" could not parse start in {filename}") - dep = True - if dep: - warnings.warn( - "SpatialReference information found in DIS header," - "this information is being ignored. " - "SpatialReference info is now stored in the namfile" - "header" - ) + # dataset 1 nlay, nrow, ncol, nper, itmuni, lenuni = line.strip().split()[0:6] nlay = int(nlay) @@ -945,11 +894,6 @@ def load(cls, f, model, ext_unit_dict=None, check=True): steady=steady, itmuni=itmuni, lenuni=lenuni, - xul=xul, - yul=yul, - rotation=rotation, - crs=proj4_str, - start_datetime=start_datetime, unitnumber=unitnumber, filenames=filenames, ) diff --git a/flopy/modflow/mfsfr2.py b/flopy/modflow/mfsfr2.py index c2a1f43400..1efe601125 100644 --- a/flopy/modflow/mfsfr2.py +++ b/flopy/modflow/mfsfr2.py @@ -2520,7 +2520,7 @@ def routing(self): ) else: txt += ( - "No DIS package or SpatialReference object; cannot " + "No DIS package or modelgrid object; cannot " "check reach proximities." ) self._txt_footer(headertxt, txt, "") diff --git a/flopy/mt3d/mt.py b/flopy/mt3d/mt.py index c3d82cdda4..7f0443d73b 100644 --- a/flopy/mt3d/mt.py +++ b/flopy/mt3d/mt.py @@ -332,12 +332,6 @@ def solver_tols(self): return self.gcg.cclose, -999 return None - @property - def sr(self): - if self.mf is not None: - return self.mf.sr - return None - @property def nlay(self): if self.btn: diff --git a/flopy/pakbase.py b/flopy/pakbase.py index 432381820c..21a8a8ce16 100644 --- a/flopy/pakbase.py +++ b/flopy/pakbase.py @@ -655,8 +655,6 @@ def data_list(self): # return [data_object, data_object, ...] dl = [] attrs = dir(self) - if "sr" in attrs: - attrs.remove("sr") if "start_datetime" in attrs: attrs.remove("start_datetime") for attr in attrs: diff --git a/flopy/plot/plotutil.py b/flopy/plot/plotutil.py index 4076e6685f..52001cbd87 100644 --- a/flopy/plot/plotutil.py +++ b/flopy/plot/plotutil.py @@ -1060,7 +1060,7 @@ def _plot_array_helper( ---------- plotarray : np.array object model: fp.modflow.Modflow object - optional if spatial reference is provided + optional if modelgrid is provided modelgrid: fp.discretization.Grid object object that defines the spatial orientation of a modflow grid within flopy. Optional if model object is provided diff --git a/flopy/utils/binaryfile.py b/flopy/utils/binaryfile.py index 07445cbcbe..9bd90b90d0 100644 --- a/flopy/utils/binaryfile.py +++ b/flopy/utils/binaryfile.py @@ -1026,26 +1026,6 @@ def __init__( self.modelgrid = self.dis.parent.modelgrid if "tdis" in kwargs.keys(): self.tdis = kwargs.pop("tdis") - if "sr" in kwargs.keys(): - from ..discretization import StructuredGrid, UnstructuredGrid - - sr = kwargs.pop("sr") - if sr.__class__.__name__ == "SpatialReferenceUnstructured": - self.modelgrid = UnstructuredGrid( - vertices=sr.verts, - iverts=sr.iverts, - xcenters=sr.xc, - ycenters=sr.yc, - ncpl=sr.ncpl, - ) - elif sr.__class__.__name__ == "SpatialReference": - self.modelgrid = StructuredGrid( - delc=sr.delc, - delr=sr.delr, - xoff=sr.xll, - yoff=sr.yll, - angrot=sr.rotation, - ) if "modelgrid" in kwargs.keys(): self.modelgrid = kwargs.pop("modelgrid") if len(kwargs.keys()) > 0: diff --git a/flopy/utils/reference.py b/flopy/utils/reference.py index 0fc85c7e95..ea962b5913 100644 --- a/flopy/utils/reference.py +++ b/flopy/utils/reference.py @@ -1,9 +1,6 @@ -""" -Module spatial referencing for flopy model objects +"""Temporal referencing for flopy model objects.""" -""" __all__ = ["TemporalReference"] -# all other classes and methods in this module are deprecated class TemporalReference: From 56a256a1beed026b999e92cf4cd020c67e1ce922 Mon Sep 17 00:00:00 2001 From: Mike Taves Date: Fri, 11 Aug 2023 14:11:59 +1200 Subject: [PATCH 2/2] Add more details from BaseModel.__getattr__ --- flopy/mbase.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/flopy/mbase.py b/flopy/mbase.py index 0b89e96a29..6f1cd660c3 100644 --- a/flopy/mbase.py +++ b/flopy/mbase.py @@ -698,18 +698,18 @@ def __getattr__(self, item): item : str This can be one of: - * A 3-character package name (case insensitive) returns package - * "tr" to access the time discretization object - * "modelgrid" to access the spatial discretization object - * "nper" to get the number of stress periods + * A short package name (case insensitive), e.g., "dis" or "bas6" + returns package object + * "tr" to access the time discretization object, if set * "start_datetime" to get str describing model start date/time + * Some packages use "nper" or "modelgrid" for corner cases Returns ------- - object, int or None + object, str, int or None Package object of type :class:`flopy.pakbase.Package`, - :class:`flopy.utils.reference.TemporalReference`, int or None. + :class:`flopy.utils.reference.TemporalReference`, str, int or None. Raises ------ @@ -732,6 +732,7 @@ def __getattr__(self, item): return None if item == "nper": + # most subclasses have a nper property, but ModflowAg needs this if self.dis is not None: return self.dis.nper else: @@ -755,6 +756,7 @@ def __getattr__(self, item): if pckg is not None or item in self.mfnam_packages: return pckg if item == "modelgrid": + # most subclasses have a modelgrid property, but not MfUsg return raise AttributeError(item)