Skip to content

Commit

Permalink
Remove delr and delc from ds (#346)
Browse files Browse the repository at this point in the history
* Remove delr and delc from ds, first commit

* import grid again in gwf

* Some more removal of delr and delc and simplify _get_delr_from_x

* Handle comments by @OnnoEbbens
  • Loading branch information
rubencalje authored Jun 17, 2024
1 parent c78976e commit 6ff7172
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 79 deletions.
12 changes: 4 additions & 8 deletions nlmod/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -703,12 +703,6 @@ def ds_contains(
datavars.append("yv")
datavars.append("icvert")

# TODO: temporary fix until delr/delc are completely removed
if "delr" in datavars:
datavars.remove("delr")
if "delc" in datavars:
datavars.remove("delc")

if "angrot" in ds.attrs:
# set by `nlmod.base.to_model_ds()` and `nlmod.dims.resample._set_angrot_attributes()`
attrs_angrot_required = ["angrot", "xorigin", "yorigin"]
Expand Down Expand Up @@ -745,8 +739,10 @@ def ds_contains(

for t_attr in time_attrs_required:
if t_attr not in ds["time"].attrs:
msg = f"{t_attr} not in dataset['time'].attrs. " +\
"Run nlmod.time.set_ds_time() to set time."
msg = (
f"{t_attr} not in dataset['time'].attrs. "
+ "Run nlmod.time.set_ds_time() to set time."
)
raise ValueError(msg)

if attrs_ds:
Expand Down
7 changes: 0 additions & 7 deletions nlmod/dims/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,6 @@ def to_model_ds(
)
elif isinstance(delr, np.ndarray) and isinstance(delc, np.ndarray):
ds["area"] = ("y", "x"), np.outer(delc, delr)
ds["delr"] = ("x"), delr
ds["delc"] = ("y"), delc
else:
raise TypeError("unexpected type for delr and/or delc")

Expand Down Expand Up @@ -383,11 +381,6 @@ def _get_structured_grid_ds(
coords=coords,
attrs=attrs,
)
# set delr and delc
delr = np.diff(xedges)
ds["delr"] = ("x"), delr
delc = -np.diff(yedges)
ds["delc"] = ("y"), delc

if crs is not None:
ds.rio.set_crs(crs)
Expand Down
42 changes: 8 additions & 34 deletions nlmod/dims/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
get_affine_mod_to_world,
get_affine_world_to_mod,
structured_da_to_ds,
get_delr,
get_delc,
)

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -211,17 +213,9 @@ def modelgrid_from_ds(ds, rotated=True, nlay=None, top=None, botm=None, **kwargs
raise TypeError(
f"extent should be a list, tuple or numpy array, not {type(ds.extent)}"
)
if "delc" in ds:
delc = ds["delc"].values
else:
raise KeyError("delc not in dataset")
if "delr" in ds:
delr = ds["delr"].values
else:
raise KeyError("delr not in dataset")
modelgrid = StructuredGrid(
delc=delc,
delr=delr,
delc=get_delc(ds),
delr=get_delr(ds),
**kwargs,
)
elif ds.gridtype == "vertex":
Expand Down Expand Up @@ -463,8 +457,8 @@ def refine(
gwf,
nrow=len(ds.y),
ncol=len(ds.x),
delr=ds.delr,
delc=ds.delc,
delr=get_delr(ds),
delc=get_delc(ds),
xorigin=ds.extent[0],
yorigin=ds.extent[2],
)
Expand Down Expand Up @@ -1948,28 +1942,8 @@ def polygons_from_model_ds(model_ds):
"""

if model_ds.gridtype == "structured":
# TODO: update with new delr/delc calculation
# check if coordinates are consistent with delr/delc values
delr_x = np.unique(model_ds.x.values[1:] - model_ds.x.values[:-1])
delc_y = np.unique(model_ds.y.values[:-1] - model_ds.y.values[1:])

delr = np.unique(model_ds.delr)
if len(delr) > 1:
raise ValueError("delr is variable")
else:
delr = delr.item()

delc = np.unique(model_ds.delc)
if len(delc) > 1:
raise ValueError("delc is variable")
else:
delc = delc.item()

if not ((delr_x == delr) and (delc_y == delc)):
raise ValueError(
"delr and delc attributes of model_ds inconsistent "
"with x and y coordinates"
)
delr = get_delr(model_ds)
delc = get_delc(model_ds)

xmins = model_ds.x - (delr * 0.5)
xmaxs = model_ds.x + (delr * 0.5)
Expand Down
66 changes: 58 additions & 8 deletions nlmod/dims/resample.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,58 @@ def get_xy_mid_structured(extent, delr, delc, descending_y=True):
raise TypeError("unexpected type for delr and/or delc")


def get_delr(ds):
"""
Get the distance along rows (delr) from the x-coordinate of a structured model
dataset.
Parameters
----------
ds : xarray.Dataset
A model dataset containing an x-coordinate and an attribute 'extent'.
Returns
-------
delr : np.ndarray
The cell-size along rows (of length ncol).
"""
assert ds.gridtype == "structured"
x = (ds.x - ds.extent[0]).values
delr = _get_delta_along_axis(x)
return delr


def get_delc(ds):
"""
Get the distance along columns (delc) from the y-coordinate of a structured model
dataset.
Parameters
----------
ds : xarray.Dataset
A model dataset containing an y-coordinate and an attribute 'extent'.
Returns
-------
delc : np.ndarray
The cell-size along columns (of length nrow).
"""
assert ds.gridtype == "structured"
y = (ds.extent[3] - ds.y).values
delc = _get_delta_along_axis(y)
return delc


def _get_delta_along_axis(x):
"""Internal method to determine delr or delc from x or y relative to xmin or ymax"""
delr = [x[0] * 2]
for xi in x[1:]:
delr.append((xi - np.sum(delr)) * 2)
return np.array(delr)


def ds_to_structured_grid(
ds_in,
extent,
Expand Down Expand Up @@ -163,17 +215,11 @@ def ds_to_structured_grid(
x=x, y=y, method=method, kwargs={"fill_value": "extrapolate"}
)
ds_out.attrs = attrs
# ds_out = ds_out.expand_dims({"ncol": len(x), "nrow": len(y)})
ds_out["delr"] = ("ncol",), delr
ds_out["delc"] = ("nrow",), delc
return ds_out

ds_out = xr.Dataset(coords={"y": y, "x": x, "layer": ds_in.layer.data}, attrs=attrs)
for var in ds_in.data_vars:
ds_out[var] = structured_da_to_ds(ds_in[var], ds_out, method=method)
# ds_out = ds_out.expand_dims({"ncol": len(x), "nrow": len(y)})
ds_out["delr"] = ("x",), delr
ds_out["delc"] = ("y",), delc
return ds_out


Expand Down Expand Up @@ -658,9 +704,13 @@ def get_affine(ds, sx=None, sy=None):
"""Get the affine-transformation, from pixel to real-world coordinates."""
attrs = _get_attrs(ds)
if sx is None:
sx = attrs["delr"]
sx = get_delr(ds)
assert len(np.unique(sx)) == 1, "Affine-transformation needs a constant delr"
sx = sx[0]
if sy is None:
sy = -attrs["delc"]
sy = get_delc(ds)
assert len(np.unique(sy)) == 1, "Affine-transformation needs a constant delc"
sy = sy[0]

if "angrot" in attrs:
xorigin = attrs["xorigin"]
Expand Down
7 changes: 1 addition & 6 deletions nlmod/gis.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,6 @@ def struc_da_to_gdf(model_ds, data_variables, polygons=None, dealing_with_time="
raise ValueError(
f"expected dimensions ('layer', 'y', 'x'), got {da.dims}"
)
# TODO: remove when delr/delc are removed as data vars
elif da_name in ["delr", "delc"]:
continue
else:
raise NotImplementedError(
f"expected two or three dimensions got {no_dims} for data variable {da_name}"
Expand Down Expand Up @@ -289,9 +286,7 @@ def ds_to_vector_file(
if model_ds.gridtype == "structured":
gdf = struc_da_to_gdf(model_ds, (da_name,), polygons=polygons)
elif model_ds.gridtype == "vertex":
# TODO: remove when delr/dec are removed
if da_name not in ["delr", "delc"]:
gdf = vertex_da_to_gdf(model_ds, (da_name,), polygons=polygons)
gdf = vertex_da_to_gdf(model_ds, (da_name,), polygons=polygons)
if driver == "GPKG":
gdf.to_file(fname_gpkg, layer=da_name, driver=driver)
else:
Expand Down
15 changes: 5 additions & 10 deletions nlmod/gwf/gwf.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
import warnings

import flopy
import numpy as np
import xarray as xr

from ..dims import grid
from ..dims.resample import get_delr, get_delc
from ..dims.layers import get_idomain
from ..sim import ims, sim, tdis
from ..util import _get_value_from_ds_attr, _get_value_from_ds_datavar
Expand Down Expand Up @@ -109,11 +109,6 @@ def _dis(ds, model, length_units="METERS", pname="dis", **kwargs):
return disv(ds, model, length_units=length_units)

# check attributes
for att in ["delr", "delc"]:
if att in ds.attrs:
if isinstance(ds.attrs[att], np.float32):
ds.attrs[att] = float(ds.attrs[att])

if "angrot" in ds.attrs and ds.attrs["angrot"] != 0.0:
xorigin = ds.attrs["xorigin"]
yorigin = ds.attrs["yorigin"]
Expand All @@ -135,8 +130,8 @@ def _dis(ds, model, length_units="METERS", pname="dis", **kwargs):
nlay=ds.sizes["layer"],
nrow=ds.sizes["y"],
ncol=ds.sizes["x"],
delr=ds["delr"].values if "delr" in ds else ds.delr,
delc=ds["delc"].values if "delc" in ds else ds.delc,
delr=get_delr(ds),
delc=get_delc(ds),
top=ds["top"].data,
botm=ds["botm"].data,
idomain=idomain,
Expand All @@ -154,8 +149,8 @@ def _dis(ds, model, length_units="METERS", pname="dis", **kwargs):
nlay=ds.sizes["layer"],
nrow=ds.sizes["y"],
ncol=ds.sizes["x"],
delr=ds["delr"].values if "delr" in ds else ds.delr,
delc=ds["delc"].values if "delc" in ds else ds.delc,
delr=get_delr(ds),
delc=get_delc(ds),
top=ds["top"].data,
botm=ds["botm"].data,
idomain=idomain,
Expand Down
8 changes: 6 additions & 2 deletions nlmod/gwf/surface_water.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from ..dims.grid import gdf_to_grid
from ..dims.layers import get_idomain
from ..dims.resample import get_extent_polygon, extent_to_polygon
from ..dims.resample import get_extent_polygon, extent_to_polygon, get_delr, get_delc
from ..read import bgt, waterboard
from ..cache import cache_pickle

Expand Down Expand Up @@ -147,7 +147,11 @@ def agg_de_lange(group, cid, ds, c1=0.0, c0=1.0, N=1e-3, crad_positive=True):
# correction if group contains multiple shapes
# but covers whole cell
if group.area.sum() == A:
li = A / np.max([ds.delr, ds.delc])
delr = get_delr(ds)
assert len(np.unique(delr)) == 1, "Variable grid size is not yet supported"
delc = get_delc(ds)
assert len(np.unique(delc)) == 1, "Variable grid size is not yet supported"
li = A / np.max([delr[0], delc[0]])

# width
B = group.area.sum(skipna=True) / li
Expand Down
6 changes: 2 additions & 4 deletions nlmod/read/rws.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ def get_gdf_surface_water(ds):
return gdf_swater


# TODO: temporary fix until delr/delc are removed completely
@cache.cache_netcdf(coords_3d=True, datavars=["delr", "delc"])
@cache.cache_netcdf(coords_3d=True)
def get_surface_water(ds, da_basename):
"""create 3 data-arrays from the shapefile with surface water:
Expand Down Expand Up @@ -92,8 +91,7 @@ def get_surface_water(ds, da_basename):
return ds_out


# TODO: temporary fix until delr/delc are removed completely
@cache.cache_netcdf(coords_2d=True, datavars=["delc", "delr"])
@cache.cache_netcdf(coords_2d=True)
def get_northsea(ds, da_name="northsea"):
"""Get Dataset which is 1 at the northsea and 0 everywhere else. Sea is
defined by rws surface water shapefile.
Expand Down

0 comments on commit 6ff7172

Please sign in to comment.