Coverage for C:\src\imod-python\imod\wq\dis.py: 96%
48 statements
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-08 14:15 +0200
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-08 14:15 +0200
1import jinja2
3from imod.wq.pkgbase import Package
6class TimeDiscretization(Package):
7 """
8 Time discretisation package class.
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 """
82 _pkg_id = "dis"
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
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)
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 )
136 return _dis_template.render(d)
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)
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)