Coverage for C:\src\imod-python\imod\wq\dis.py: 17%

1 import jinja2

2

3 from imod.wq.pkgbase import Package

4

5

6 class TimeDiscretization(Package):

7 """

8 Time discretisation package class.

9

10 Parameters

11 ----------

12 timestep_duration: float

13 is the length of the current stress period (PERLEN). If the flow

14 solution is transient, timestep_duration specified here must be equal to

15 that specified for the flow model. If the flow solution is steady-state,

16 timestep_duration can be set to any desired length.

17 n_timesteps: int, optional

18 is the number of time steps for the transient flow solution in the

19 current stress period (NSTP). If the flow solution is steady-state,

20 n_timestep=1. Default value is 1.

21 transient: bool, optional

22 Flag indicating wether the flow simulation is transient (True) or False

23 (Steady State).

24 Default is True.

25 timestep_multiplier: float, optional

26 is the multiplier for the length of successive time steps used in the

27 transient flow solution (TSMULT); it is used only if n_timesteps>1.

28 timestep_multiplier>0, the length of each flow time step within the

29 current stress period is calculated using the geometric progression as

30 in MODFLOW. Note that both n_timesteps and timestep_multiplier specified

31 here must be identical to those specified in the flow model if the flow

32 model is transient.

33 timestep_multiplier ≤ 0, the length of each flow time step within the

34 current stress period is read from the record TSLNGH. This option is

35 needed in case the length of time steps for the flow solution is not

36 based on a geometric progression in a flow model, unlike MODFLOW.

37 Default is 1.0.

38 max_n_transport_timestep: int, optional

39 is the maximum number of transport steps allowed within one time step of

40 the flow solution (mxstrn). If the number of transport steps within a

41 flow time step exceeds max_n_transport_timestep, the simulation is

42 terminated.

43 Default is 50_000.

44 transport_timestep_multiplier: float or {"None"}, optional

45 is the multiplier for successive transport steps within a flow time step

46 (TTSMULT).

47 If the Generalized Conjugate Gradient (GCG) solver is used and the

48 solution option for the advection term is the standard finite difference

49 method. A value between 1.0 and 2.0 is generally adequate. If the GCG

50 package is not used, the transport solution is solved explicitly as in

51 the original MT3D code, and transport_timestep_multiplier is always set

52 to 1.0 regardless of the user-specified input. Note that for the

53 particle tracking based solution options and the 3rd-order TVD scheme,

54 transport_timestep_multiplier does not apply.

55 Default is {"None"}.

56 transport_initial_timestep: int, optional

57 is the user-specified transport stepsize within each time step of the

58 flow solution (DT0).

59 transport_initial_timestep is interpreted differently depending on

60 whether the solution option chosen is explicit or implicit: For explicit

61 solutions (i.e., the GCG solver is not used), the program will always

62 calculate a maximum transport stepsize which meets the various stability

63 criteria. Setting transport_initial_timestep to zero causes the model

64 calculated transport stepsize to be used in the simulation. However, the

65 model-calculated transport_initial_timestep may not always be optimal.

66 In this situation, transport_initial_timestep should be adjusted to find

67 a value that leads to the best results. If transport_initial_timestep is

68 given a value greater than the model-calculated stepsize, the

69 model-calculated stepsize, instead of the user-specified value, will be

70 used in the simulation.

71 For implicit solutions (i.e., the GCG solver is used),

72 transport_initial_timestep is the initial transport stepsize. If it is

73 specified as zero, the model-calculated value of

74 transport_initial_timestep, based on the user-specified Courant number

75 in the Advection Package, will be used. The subsequent transport

76 stepsize may increase or remain constant depending on the userspecified

77 transport stepsize multiplier transport_timestep_multiplier and the

78 solution scheme for the advection term.

79 Default is 0.

80 """

81

82 _pkg_id = "dis"

83

84 def __init__(

85 self,

86 timestep_duration,

87 n_timesteps=1,

88 transient=True,

89 timestep_multiplier=1.0,

90 max_n_transport_timestep=50_000,

91 transport_timestep_multiplier=None,

92 transport_initial_timestep=0.0,

93 ):

94 super().__init__()

95 self["timestep_duration"] = timestep_duration

96 self["n_timesteps"] = n_timesteps

97 self["transient"] = transient

98 self["timestep_multiplier"] = timestep_multiplier

99 self["max_n_transport_timestep"] = max_n_transport_timestep

100 if transport_timestep_multiplier is not None:

101 self["transport_timestep_multiplier"] = transport_timestep_multiplier

102 self["transport_initial_timestep"] = transport_initial_timestep

103

104 def _render(self, globaltimes):

105 d = {}

106 dicts = {}

107 _dis_mapping = (

108 ("perlen", "timestep_duration"),

109 ("nstp", "n_timesteps"),

110 ("sstr", "transient"),

111 ("tsmult", "timestep_multiplier"),

112 )

113 d["mapping"] = _dis_mapping

114 datavars = [t[1] for t in _dis_mapping]

115 for varname in datavars:

116 dicts[varname] = self._compose_values_time(varname, globaltimes)

117 if varname == "transient":

118 for k, v in dicts[varname].items():

119 if v == 1:

120 dicts[varname][k] = "tr"

121 else:

122 dicts[varname][k] = "ss"

123 d["dicts"] = dicts

124 d["n_periods"] = len(globaltimes)

125

126 _dis_template = jinja2.Template(

127 "\n"

128 " nper = {{n_periods}}\n"

129 " {%- for name, dictname in mapping -%}"

130 " {%- for time, value in dicts[dictname].items() %}\n"

131 " {{name}}_p{{time}} = {{value}}"

132 " {%- endfor -%}"

133 " {%- endfor -%}"

134 )

135

136 return _dis_template.render(d)

137

138 def _render_btn(self, globaltimes):

139 d = {}

140 dicts = {}

141 # TODO: check what's necessary

142 _btn_mapping = (

143 # ("perlen", "duration"), # should not be necessary

144 # ("nstp", "n_timesteps"), # should not be necessary

145 ("tsmult", "timestep_multiplier"),

146 # ("tslngh", "timestep_length"),

147 ("dt0", "transport_initial_timestep"),

148 ("ttsmult", "transport_timestep_multiplier"),

149 ("mxstrn", "max_n_transport_timestep"),

150 )

151 _btn_template = jinja2.Template(

152 " {%- for name, dictname in mapping -%}"

153 " {%- for time, value in dicts[dictname].items() %}\n"

154 " {{name}}_p{{time}} = {{value}}"

155 " {%- endfor -%}"

156 " {%- endfor -%}"

157 )

158 mapping = tuple(

159 [(k, v) for k, v in _btn_mapping if v in self.dataset.data_vars]

160 )

161 d["mapping"] = mapping

162 datavars = [t[1] for t in mapping]

163 for varname in datavars:

164 dicts[varname] = self._compose_values_time(varname, globaltimes)

165 d["dicts"] = dicts

166 return _btn_template.render(d)

167

168 def _pkgcheck(self, ibound=None):

169 to_check = [

170 "timestep_duration",

171 "n_timesteps",

172 "transient",

173 "timestep_multiplier",

174 "max_n_transport_timestep",

175 "transport_initial_timestep",

176 ]

177 if "transport_timestep_multiplier" in self.dataset.data_vars:

178 to_check.append("transport_timestep_multiplier")

179 self._check_positive(to_check)