Source code for imod.msw.idf_mapping

from dataclasses import asdict
from typing import Optional

import numpy as np
import xarray as xr

from imod.common.interfaces.iregridpackage import IRegridPackage
from imod.common.utilities.dataclass_type import DataclassType
from imod.common.utilities.regrid import _regrid_array
from imod.msw.fixed_format import VariableMetaData
from imod.msw.pkgbase import MetaSwapPackage
from imod.msw.regrid.regrid_schemes import IdfMappingRegridMethod
from imod.typing import GridDataArray
from imod.util.regrid import RegridderWeightsCache
from imod.util.spatial import spatial_reference


[docs] class IdfMapping(MetaSwapPackage, IRegridPackage): """ Describes svat location in the IDF grid. Note that MetaSWAP can only write equidistant grids. """ _file_name = "idf_svat.inp" _metadata_dict = { "svat": VariableMetaData(10, 1, 9999999, int), "rows": VariableMetaData(10, 1, 9999999, int), "columns": VariableMetaData(10, 1, 9999999, int), "x_grid": VariableMetaData(15, -9999999.0, 9999999.0, float), "y_grid": VariableMetaData(15, -9999999.0, 9999999.0, float), } _with_subunit = () _without_subunit = ("rows", "columns", "x_grid", "y_grid") _to_fill = () _regrid_method = IdfMappingRegridMethod() # NOTE that it is stated in the IO manual: "The x- and y-coordinates should # increase with increasing col, row." But the example works with decreasing # y-coordinates.
[docs] def __init__(self, area, nodata): super().__init__() self.dataset["area"] = area self.dataset["nodata"] = nodata nrow = self.dataset.coords["y"].size ncol = self.dataset.coords["x"].size y_index = xr.DataArray( np.arange(1, nrow + 1), coords={"y": self.dataset.coords["y"]}, dims=("y",) ) x_index = xr.DataArray( np.arange(1, ncol + 1), coords={"x": self.dataset.coords["x"]}, dims=("x",) ) rows, columns = xr.broadcast(y_index, x_index) self.dataset["rows"] = rows self.dataset["columns"] = columns y_grid, x_grid = xr.broadcast(self.dataset["y"], self.dataset["x"]) self.dataset["x_grid"] = x_grid self.dataset["y_grid"] = y_grid
def _get_output_settings(self): grid = self.dataset["area"] dx, xmin, _, dy, ymin, _ = spatial_reference(grid) ncol = grid["x"].size nrow = grid["y"].size # If non-equidistant, spatial_reference returned a 1d array instead of # float if (not np.isscalar(dx)) or (not np.isscalar(dy)): raise ValueError("MetaSWAP only supports equidistant grids") nodata = self.dataset["nodata"].values return { "simgro_opt": -1, "idf_per": 1, "idf_dx": dx, "idf_dy": np.abs(dy), "idf_ncol": ncol, "idf_nrow": nrow, "idf_xmin": xmin, "idf_ymin": ymin, "idf_nodata": nodata, }
[docs] def regrid_like( self, target_grid: GridDataArray, regrid_cache: RegridderWeightsCache, regridder_types: Optional[DataclassType] = None, ) -> "MetaSwapPackage": """ Creates a package of the same type as this package, based on another discretization. It regrids all the arrays in this package to the desired discretization, and leaves the options unmodified. At the moment only regridding to a different planar grid is supported, meaning ``target_grid`` has different ``"x"`` and ``"y"``. The default regridding methods are obtained by calling ``.get_regrid_methods()`` on the package, which returns a dataclass with the default regridding methods for each variable in the package. Parameters ---------- target_grid: xr.DataArray or xu.UgridDataArray a grid defined using the same discretization as the one we want to regrid the package to. regrid_cache: RegridderWeightsCache stores regridder weights for different regridders. Can be used to speed up regridding, if the same regridders are used several times for regridding different arrays. regridder_types: RegridMethodType, optional dictionary mapping arraynames (str) to a tuple of regrid type (a specialization class of BaseRegridder) and function name (str) this dictionary can be used to override the default mapping method. Examples -------- To regrid the infiltration package with a non-default method for the infiltration capacity, call ``regrid_like`` with these arguments: >>> regridder_types = imod.msw.regrid.InfiltrationRegridMethod(infiltration_capacity=(imod.RegridderType.OVERLAP, "max")) >>> regrid_cache = imod.util.regrid.RegridderWeightsCache() >>> new_infiltration = infiltration.regrid_like(like, regrid_cache, regridder_types) Returns ------- A package with the same options as this package, and with all the data-arrays regridded to another discretization, similar to the one used in input argument "target_grid" """ if regridder_types is None: regridder_settings = asdict(self.get_regrid_methods(), dict_factory=dict) else: regridder_settings = asdict(regridder_types, dict_factory=dict) nodata = self.dataset["nodata"].values[()] regridded_area = _regrid_array( self.dataset["area"], regrid_cache, regridder_settings["area"][0], regridder_settings["area"][1], target_grid, ) return type(self)(regridded_area, nodata)