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

1 from typing import Optional, Tuple

2

3 import numpy as np

4

5 from imod.logging import init_log_decorator

6 from imod.mf6.boundary_condition import BoundaryCondition

7 from imod.mf6.interfaces.iregridpackage import IRegridPackage

8 from imod.mf6.utilities.regrid import RegridderType

9 from imod.mf6.validation import BOUNDARY_DIMS_SCHEMA, CONC_DIMS_SCHEMA

10 from imod.schemata import (

11 AllInsideNoDataSchema,

12 AllNoDataSchema,

13 AllValueSchema,

14 CoordsSchema,

15 DimsSchema,

16 DTypeSchema,

17 IdentityNoDataSchema,

18 IndexesSchema,

19 OtherCoordsSchema,

20)

21

22

23 class Drainage(BoundaryCondition, IRegridPackage):

24 """

25 The Drain package is used to simulate head-dependent flux boundaries.

26 https://water.usgs.gov/ogw/modflow/mf6io.pdf#page=67

27

28 Parameters

29 ----------

30 elevation: array of floats (xr.DataArray)

31 elevation of the drain. (elev)

32 conductance: array of floats (xr.DataArray)

33 is the conductance of the drain. (cond)

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

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

36 as the concentration for inflow over this boundary.

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

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

39 how outflow over this boundary is computed.

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

41 keyword to indicate that the list of drain information will be written

42 to the listing file immediately after it is read. Default is False.

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

44 Indicates that the list of drain flow rates will be printed to the

45 listing file for every stress period time step in which "BUDGET PRINT"

46 is specified in Output Control. If there is no Output Control option and

47 PRINT FLOWS is specified, then flow rates are printed for the last time

48 step of each stress period.

49 Default is False.

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

51 Indicates that drain flow terms will be written to the file specified

52 with "BUDGET FILEOUT" in Output Control. Default is False.

53 observations: [Not yet supported.]

54 Default is None.

55 validate: {True, False}

56 Flag to indicate whether the package should be validated upon

57 initialization. This raises a ValidationError if package input is

58 provided in the wrong manner. Defaults to True.

59 repeat_stress: Optional[xr.DataArray] of datetimes

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

61 seasonality without duplicating the values. The DataArray should have

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

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

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

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

66 ``set_repeat_stress`` method.

67 """

68

69 _pkg_id = "drn"

70

71 # has to be ordered as in the list

72 _init_schemata = {

73 "elevation": [

74 DTypeSchema(np.floating),

75 IndexesSchema(),

76 CoordsSchema(("layer",)),

77 BOUNDARY_DIMS_SCHEMA,

78 ],

79 "conductance": [

80 DTypeSchema(np.floating),

81 IndexesSchema(),

82 CoordsSchema(("layer",)),

83 BOUNDARY_DIMS_SCHEMA,

84 ],

85 "concentration": [

86 DTypeSchema(np.floating),

87 IndexesSchema(),

88 CoordsSchema(

89 (

90 "species",

91 "layer",

92 )

93 ),

94 CONC_DIMS_SCHEMA,

95 ],

96 "print_flows": [DTypeSchema(np.bool_), DimsSchema()],

97 "save_flows": [DTypeSchema(np.bool_), DimsSchema()],

98 }

99 _write_schemata = {

100 "elevation": [

101 OtherCoordsSchema("idomain"),

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

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

104 ],

105 "conductance": [IdentityNoDataSchema("elevation"), AllValueSchema(">", 0.0)],

106 "concentration": [IdentityNoDataSchema("elevation"), AllValueSchema(">=", 0.0)],

107 }

108

109 _period_data = ("elevation", "conductance")

110 _keyword_map = {}

111 _template = BoundaryCondition._initialize_template(_pkg_id)

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

113

114 _regrid_method = {

115 "elevation": (RegridderType.OVERLAP, "mean"),

116 "conductance": (RegridderType.RELATIVEOVERLAP, "conductance"),

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

118 }

119

120 @init_log_decorator()

121 def __init__(

122 self,

123 elevation,

124 conductance,

125 concentration=None,

126 concentration_boundary_type="aux",

127 print_input=False,

128 print_flows=False,

129 save_flows=False,

130 observations=None,

131 validate: bool = True,

132 repeat_stress=None,

133 ):

134 dict_dataset = {

135 "elevation": elevation,

136 "conductance": conductance,

137 "concentration": concentration,

138 "concentration_boundary_type": concentration_boundary_type,

139 "print_input": print_input,

140 "print_flows": print_flows,

141 "save_flows": save_flows,

142 "observations": observations,

143 "repeat_stress": repeat_stress,

144 }

145 super().__init__(dict_dataset)

146

147 self._validate_init_schemata(validate)

148

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

150 # Insert additional kwargs

151 kwargs["elevation"] = self["elevation"]

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

153

154 return errors

155

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

157 return self._regrid_method