|
1 | | -from typing import Union |
| 1 | +from typing import Union, cast |
2 | 2 |
|
3 | 3 | import numpy as np |
| 4 | +import pandas as pd |
4 | 5 | import xarray as xr |
5 | 6 |
|
| 7 | +from imod.typing import GridDataDict, Imod5DataDict, SelSettingsType |
6 | 8 | from imod.typing.grid import full_like |
7 | 9 |
|
8 | 10 |
|
@@ -48,3 +50,71 @@ def fill_missing_layers( |
48 | 50 | """ |
49 | 51 | layer = full.coords["layer"] |
50 | 52 | return source.reindex(layer=layer, fill_value=fillvalue) |
| 53 | + |
| 54 | + |
| 55 | +def _well_from_imod5_cap_point_data(cap_data: GridDataDict) -> dict[str, np.ndarray]: |
| 56 | + raise NotImplementedError( |
| 57 | + "Assigning sprinkling wells with an IPF file is not supported, please specify them as IDF." |
| 58 | + ) |
| 59 | + |
| 60 | + |
| 61 | +def _well_from_imod5_cap_grid_data(cap_data: GridDataDict) -> dict[str, np.ndarray]: |
| 62 | + drop_layer_kwargs: SelSettingsType = { |
| 63 | + "layer": 0, |
| 64 | + "drop": True, |
| 65 | + "missing_dims": "ignore", |
| 66 | + } |
| 67 | + type = cap_data["artificial_recharge"].isel(**drop_layer_kwargs).compute() |
| 68 | + layer = ( |
| 69 | + cap_data["artificial_recharge_layer"] |
| 70 | + .isel(**drop_layer_kwargs) |
| 71 | + .astype(int) |
| 72 | + .compute() |
| 73 | + ) |
| 74 | + |
| 75 | + from_groundwater = (type != 0).to_numpy() |
| 76 | + coords = type.coords |
| 77 | + x_grid, y_grid = np.meshgrid(coords["x"].to_numpy(), coords["y"].to_numpy()) |
| 78 | + |
| 79 | + data = {} |
| 80 | + data["layer"] = layer.data[from_groundwater] |
| 81 | + data["y"] = y_grid[from_groundwater] |
| 82 | + data["x"] = x_grid[from_groundwater] |
| 83 | + data["rate"] = np.zeros_like(data["x"]) |
| 84 | + |
| 85 | + return data |
| 86 | + |
| 87 | + |
| 88 | +def well_from_imod5_cap_data(imod5_data: Imod5DataDict) -> dict[str, np.ndarray]: |
| 89 | + """ |
| 90 | + Abstraction data for sprinkling is defined in iMOD5 either with grids (IDF) |
| 91 | + or points (IPF) combined with a grid. Depending on the type, the function does |
| 92 | + different conversions |
| 93 | +
|
| 94 | + - grids (IDF) |
| 95 | + The ``"artifical_recharge_layer"`` variable was defined as grid |
| 96 | + (IDF), this grid defines in which layer a groundwater abstraction |
| 97 | + well should be placed. The ``"artificial_recharge"`` grid contains |
| 98 | + types which point to the type of abstraction: |
| 99 | + * 0: no abstraction |
| 100 | + * 1: groundwater abstraction |
| 101 | + * 2: surfacewater abstraction |
| 102 | + The ``"artificial_recharge_capacity"`` grid/constant defines the |
| 103 | + capacity of each groundwater or surfacewater abstraction. This is an |
| 104 | + ``1:1`` mapping: Each grid cell maps to a separate well. |
| 105 | +
|
| 106 | + - points with grid (IPF & IDF) |
| 107 | + The ``"artifical_recharge_layer"`` variable was defined as point |
| 108 | + data (IPF), this table contains wellids with an abstraction capacity |
| 109 | + and layer. The ``"artificial_recharge"`` grid contains a mapping of |
| 110 | + grid cells to wellids in the point data. The |
| 111 | + ``"artificial_recharge_capacity"`` is ignored as the abstraction |
| 112 | + capacity is already defined in the point data. This is an ``n:1`` |
| 113 | + mapping: multiple grid cells can map to one well. |
| 114 | + """ |
| 115 | + cap_data = cast(GridDataDict, imod5_data["cap"]) |
| 116 | + |
| 117 | + if isinstance(cap_data["artificial_recharge_layer"], pd.DataFrame): |
| 118 | + return _well_from_imod5_cap_point_data(cap_data) |
| 119 | + else: |
| 120 | + return _well_from_imod5_cap_grid_data(cap_data) |
0 commit comments