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

1import jinja2 

2import numpy as np 

3 

4import imod 

5from imod.flow.pkgbase import Package 

6 

7 

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. 

13 

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 """ 

25 

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 ) 

40 

41 _pkg_id = "hfb" 

42 _variable_order = ["resistance"] 

43 

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 

62 

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") 

70 

71 def _compose_values_layer(self, varname, directory, nlayer, time=None): 

72 values = {} 

73 d = {"directory": directory, "name": directory.stem, "extension": ".gen"} 

74 

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) 

83 

84 return values 

85 

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) 

89 

90 gdf["id"] = gdf.index 

91 

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) 

103 

104 def save(self, directory): 

105 import geopandas as gpd 

106 

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) 

110 

111 def _render_projectfile(self, **kwargs): 

112 kwargs["resistance"] = self.dataset["resistance"].values 

113 return super()._render_projectfile(**kwargs)