Coverage for C:\src\imod-python\imod\flow\hfb.py: 85%
52 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-08 13:27 +0200
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-08 13:27 +0200
1import jinja2
2import numpy as np
4import imod
5from imod.flow.pkgbase import Package
8class HorizontalFlowBarrier(Package):
9 """
10 Horizontal barriers obstructing flow such as semi- or impermeable fault
11 zone or a sheet pile wall are defined for each model layer by a `*.GEN` line
12 file.
14 Parameters
15 ----------
16 id_name: str or list of str
17 name of the barrier
18 geometry: object array of shapely LineStrings
19 geometry of barriers, should be lines
20 resistance: float or list of floats
21 resistance of the barrier (d).
22 layer: Optional, int
23 layer where barrier is located. Defaults to None.
24 """
26 _template_projectfile = jinja2.Template(
27 "0001, ({{pkg_id}}), 1, {{name}}, {{variable_order}}\n"
28 '{{"{:03d}".format(variable_order|length)}}, {{"{:03d}".format(n_entry)}}\n'
29 "{%- for variable in variable_order%}\n" # Preserve variable order
30 "{%- for layer, value in package_data[variable].items()%}\n"
31 # 1 indicates the layer is activated
32 # 2 indicates the second element of the final two elements should be read
33 # 1.000 is the multiplication factor
34 # 0.000 is the addition factor
35 # -9999 indicates there is no data, following iMOD usual practice
36 '1, 2, {{"{:03d}".format(layer)}}, {{resistance[loop.index]}}, 0.000, -9999., {{value}}\n'
37 "{%- endfor %}\n"
38 "{%- endfor %}\n"
39 )
41 _pkg_id = "hfb"
42 _variable_order = ["resistance"]
44 def __init__(
45 self,
46 id_name,
47 geometry,
48 resistance,
49 layer=None,
50 ):
51 super().__init__()
52 variables = {
53 "id_name": id_name,
54 "geometry": geometry,
55 "layer": layer,
56 "resistance": resistance,
57 }
58 variables = {k: np.atleast_1d(v) for k, v in variables.items() if v is not None}
59 length = max(map(len, variables.values()))
60 index = np.arange(1, length + 1)
61 self.dataset["index"] = index
63 for k, v in variables.items():
64 if v.size == index.size:
65 self.dataset[k] = ("index", v)
66 elif v.size == 1:
67 self.dataset[k] = ("index", np.full(length, v))
68 else:
69 raise ValueError(f"Length of {k} does not match other arguments")
71 def _compose_values_layer(self, varname, directory, nlayer, time=None):
72 values = {}
73 d = {"directory": directory, "name": directory.stem, "extension": ".gen"}
75 if "layer" in self.dataset:
76 for layer in np.unique(self.dataset["layer"]):
77 layer = int(layer)
78 d["layer"] = layer
79 values[layer] = self._compose_path(d)
80 else:
81 for layer in range(1, nlayer + 1): # 1-based indexing
82 values[layer] = self._compose_path(d)
84 return values
86 def _save_layers(self, gdf, directory):
87 d = {"directory": directory, "name": directory.stem, "extension": ".gen"}
88 d["directory"].mkdir(exist_ok=True, parents=True)
90 gdf["id"] = gdf.index
92 if "layer" in gdf:
93 for layer, layerdf in gdf.groupby("layer"):
94 d["layer"] = layer
95 # Ensure right order
96 outdf = layerdf[["id", "geometry"]]
97 path = self._compose_path(d)
98 imod.gen.write(path, outdf)
99 else:
100 outdf = gdf[["id", "geometry"]]
101 path = self._compose_path(d)
102 imod.gen.write(path, outdf)
104 def save(self, directory):
105 import geopandas as gpd
107 gdf = gpd.GeoDataFrame(self.dataset.to_dataframe())
108 # Use _save_layers to keep the code consistent with the Wel implementation.
109 self._save_layers(gdf, directory)
111 def _render_projectfile(self, **kwargs):
112 kwargs["resistance"] = self.dataset["resistance"].values
113 return super()._render_projectfile(**kwargs)