Coverage for C:\src\imod-python\imod\mf6\chd.py: 100%

29 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-08 14:15 +0200

1from typing import Optional, Tuple 

2 

3import numpy as np 

4 

5from imod.logging import init_log_decorator 

6from imod.mf6.boundary_condition import BoundaryCondition 

7from imod.mf6.interfaces.iregridpackage import IRegridPackage 

8from imod.mf6.utilities.regrid import RegridderType 

9from imod.mf6.validation import BOUNDARY_DIMS_SCHEMA, CONC_DIMS_SCHEMA 

10from imod.schemata import ( 

11 AllInsideNoDataSchema, 

12 AllNoDataSchema, 

13 AllValueSchema, 

14 CoordsSchema, 

15 DTypeSchema, 

16 IdentityNoDataSchema, 

17 IndexesSchema, 

18 OtherCoordsSchema, 

19) 

20 

21 

22class ConstantHead(BoundaryCondition, IRegridPackage): 

23 """ 

24 Constant-Head package. Any number of CHD Packages can be specified for a 

25 single groundwater flow model; however, an error will occur if a CHD Package 

26 attempts to make a GWF cell a constant-head cell when that cell has already 

27 been designated as a constant-head cell either within the present CHD 

28 Package or within another CHD Package. In previous MODFLOW versions, it was 

29 not possible to convert a constant-head cell to an active cell. Once a cell 

30 was designated as a constant-head cell, it remained a constant-head cell 

31 until the end of the end of the simulation. In MODFLOW 6 a constant-head 

32 cell will become active again if it is not included as a constant-head cell 

33 in subsequent stress periods. Previous MODFLOW versions allowed 

34 specification of SHEAD and EHEAD, which were the starting and ending 

35 prescribed heads for a stress period. Linear interpolation was used to 

36 calculate a value for each time step. In MODFLOW 6 only a single head value 

37 can be specified for any constant-head cell in any stress period. The 

38 time-series functionality must be used in order to interpolate values to 

39 individual time steps. 

40 

41 Parameters 

42 ---------- 

43 head: array of floats (xr.DataArray) 

44 Is the head at the boundary. 

45 print_input: ({True, False}, optional) 

46 keyword to indicate that the list of constant head information will 

47 be written to the listing file immediately after it is read. Default is 

48 False. 

49 concentration: array of floats (xr.DataArray, optional) 

50 if this flow package is used in simulations also involving transport, then this array is used 

51 as the concentration for inflow over this boundary. 

52 concentration_boundary_type: ({"AUX", "AUXMIXED"}, optional) 

53 if this flow package is used in simulations also involving transport, then this keyword specifies 

54 how outflow over this boundary is computed. 

55 print_flows: ({True, False}, optional) 

56 Indicates that the list of constant head flow rates will be printed to 

57 the listing file for every stress period time step in which "BUDGET 

58 PRINT" is specified in Output Control. If there is no Output Control 

59 option and PRINT FLOWS is specified, then flow rates are printed for the 

60 last time step of each stress period. 

61 Default is False. 

62 save_flows: ({True, False}, optional) 

63 Indicates that constant head flow terms will be written to the file 

64 specified with "BUDGET FILEOUT" in Output Control. Default is False. 

65 observations: [Not yet supported.] 

66 Default is None. 

67 validate: {True, False} 

68 Flag to indicate whether the package should be validated upon 

69 initialization. This raises a ValidationError if package input is 

70 provided in the wrong manner. Defaults to True. 

71 repeat_stress: Optional[xr.DataArray] of datetimes 

72 Used to repeat data for e.g. repeating stress periods such as 

73 seasonality without duplicating the values. The DataArray should have 

74 dimensions ``("repeat", "repeat_items")``. The ``repeat_items`` 

75 dimension should have size 2: the first value is the "key", the second 

76 value is the "value". For the "key" datetime, the data of the "value" 

77 datetime will be used. Can also be set with a dictionary using the 

78 ``set_repeat_stress`` method. 

79 """ 

80 

81 _pkg_id = "chd" 

82 _keyword_map = {} 

83 _period_data = ("head",) 

84 

85 _init_schemata = { 

86 "head": [ 

87 DTypeSchema(np.floating), 

88 IndexesSchema(), 

89 CoordsSchema(("layer",)), 

90 BOUNDARY_DIMS_SCHEMA, 

91 ], 

92 "concentration": [ 

93 DTypeSchema(np.floating), 

94 IndexesSchema(), 

95 CoordsSchema(("layer",)), 

96 CONC_DIMS_SCHEMA, 

97 ], 

98 } 

99 _write_schemata = { 

100 "head": [ 

101 OtherCoordsSchema("idomain"), 

102 AllNoDataSchema(), # Check for all nan, can occur while clipping 

103 AllInsideNoDataSchema(other="idomain", is_other_notnull=(">", 0)), 

104 ], 

105 "concentration": [IdentityNoDataSchema("head"), AllValueSchema(">=", 0.0)], 

106 } 

107 

108 _keyword_map = {} 

109 _auxiliary_data = {"concentration": "species"} 

110 _template = BoundaryCondition._initialize_template(_pkg_id) 

111 

112 _regrid_method = { 

113 "head": ( 

114 RegridderType.OVERLAP, 

115 "mean", 

116 ), # TODO: should be set to barycentric once supported 

117 "concentration": (RegridderType.OVERLAP, "mean"), 

118 } 

119 

120 @init_log_decorator() 

121 def __init__( 

122 self, 

123 head, 

124 concentration=None, 

125 concentration_boundary_type="aux", 

126 print_input=False, 

127 print_flows=False, 

128 save_flows=False, 

129 observations=None, 

130 validate: bool = True, 

131 repeat_stress=None, 

132 ): 

133 dict_dataset = { 

134 "head": head, 

135 "concentration": concentration, 

136 "concentration_boundary_type": concentration_boundary_type, 

137 "print_input": print_input, 

138 "print_flows": print_flows, 

139 "save_flows": save_flows, 

140 "observations": observations, 

141 "repeat_stress": repeat_stress, 

142 } 

143 super().__init__(dict_dataset) 

144 self._validate_init_schemata(validate) 

145 

146 def _validate(self, schemata, **kwargs): 

147 # Insert additional kwargs 

148 kwargs["head"] = self["head"] 

149 errors = super()._validate(schemata, **kwargs) 

150 

151 return errors 

152 

153 def get_regrid_methods(self) -> Optional[dict[str, Tuple[RegridderType, str]]]: 

154 return self._regrid_method