Coverage for C:\src\imod-python\imod\wq\adv.py: 43%

68 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-08 10:26 +0200

1import textwrap 

2 

3from imod.wq.pkgbase import Package 

4 

5 

6class AdvectionFiniteDifference(Package): 

7 """ 

8 Solve the advection term using the explicit Finite Difference method 

9 (MIXELM = 0) with upstream weighting 

10 

11 Attributes 

12 ---------- 

13 courant: float 

14 Courant number (PERCEL) is the number of cells (or a fraction of a cell) 

15 advection will be allowed in any direction in one transport step. For 

16 implicit finite-difference or particle tracking based schemes, there is 

17 no limit on PERCEL, but for accuracy reasons, it is generally not set 

18 much greater than one. Note, however, that the PERCEL limit is checked 

19 over the entire model grid. Thus, even if PERCEL > 1, advection may not 

20 be more than one cell’s length at most model locations. For the explicit 

21 finite-difference, PERCEL is also a stability constraint, which must not 

22 exceed one and will be automatically reset to one if a value greater 

23 than one is specified. 

24 weighting : string {"upstream", "central"}, optional 

25 Indication of which weighting scheme should be used, set to default 

26 value "upstream" (NADVFD = 0 or 1) 

27 Default value: "upstream" 

28 """ 

29 

30 _pkg_id = "adv" 

31 

32 _keywords = {"weighting": {"upstream": 0, "central": 1}} 

33 

34 _template = ( 

35 "[adv]\n" 

36 " mixelm = 0\n" 

37 " percel = {courant}\n" 

38 " nadvfd = {weighting}\n" 

39 ) 

40 

41 def __init__(self, courant=0.75, weighting="upstream"): 

42 super().__init__() 

43 self["courant"] = courant 

44 self["weighting"] = weighting 

45 

46 def _pkgcheck(self, ibound=None): 

47 self._check_positive(["courant"]) 

48 

49 

50class AdvectionMOC(Package): 

51 """ 

52 Solve the advection term using the Method of Characteristics (MIXELM = 1) 

53 

54 Nota bene: number of particles settings have not been tested. The defaults 

55 here are chosen conservatively, with many particles. This increases both 

56 memory usage and computational effort. 

57 

58 Attributes 

59 ----------- 

60 courant: float 

61 Courant number (PERCEL) is the number of cells (or a fraction of a cell) 

62 advection will be allowed in any direction in one transport step. For 

63 implicit finite-difference or particle tracking based schemes, there is 

64 no limit on PERCEL, but for accuracy reasons, it is generally not set 

65 much greater than one. Note, however, that the PERCEL limit is checked 

66 over the entire model grid. Thus, even if PERCEL > 1, advection may not 

67 be more than one cell’s length at most model locations. For the explicit 

68 finite-difference, PERCEL is also a stability constraint, which must not 

69 exceed one and will be automatically reset to one if a value greater 

70 than one is specified. 

71 max_nparticles: int 

72 is the maximum total number of moving particles allowed (MXPART). 

73 tracking: string {"euler", "runge-kutta", "hybrid"}, optional 

74 indicates which particle tracking algorithm is selected for the 

75 Eulerian-Lagrangian methods. ITRACK = 1, the first-order Euler algorithm is 

76 used; ITRACK = 2, the fourth-order Runge-Kutta algorithm is used; this 

77 option is computationally demanding and may be needed only when PERCEL is 

78 set greater than one. ITRACK = 3, the hybrid 1st and 4th order algorithm is 

79 used; the Runge- Kutta algorithm is used in sink/source cells and the cells 

80 next to sinks/sources while the Euler algorithm is used elsewhere. 

81 Default value is "hybrid". 

82 weighting_factor: float, optional 

83 is a concentration weighting factor (WD) between 0.5 and 1. It is used for 

84 operator splitting in the particle tracking based methods. The value of 

85 0.5 is generally adequate. The value may be adjusted to achieve better 

86 mass balance. Generally, it can be increased toward 1.0 as advection 

87 becomes more dominant. 

88 Default value: 0.5. 

89 dconcentration_epsilon: float, optional 

90 is a small Relative Cell Concentration Gradient below which advective 

91 transport is considered negligible. A value around 10-5 is generally 

92 adequate. 

93 Default value: 1.0e-5. 

94 nplane: int, optional 

95 is a flag indicating whether the random or fixed pattern is selected for 

96 initial placement of moving particles. NPLANE = 0, the random pattern is 

97 selected for initial placement. Particles are distributed randomly in 

98 both the horizontal and vertical directions by calling a random number 

99 generator. This option is usually preferred and leads to smaller mass 

100 balance discrepancy in nonuniform or diverging/converging flow fields. 

101 NPLANE > 0, the fixed pattern is selected for initial placement. The 

102 value of NPLANE serves as the number of vertical "planes" on which 

103 initial particles are placed within each cell block. The fixed pattern 

104 may work better than the random pattern only in relatively uniform flow 

105 fields. For two-dimensional simulations in plan view, set NPLANE = 1. 

106 For cross sectional or three-dimensional simulations, NPLANE = 2 is 

107 normally adequate. Increase NPLANE if more resolution in the vertical 

108 direction is desired. 

109 Default value: 2. 

110 nparticles_no_advection: int, optional 

111 is number of initial particles per cell to be placed at cells where the 

112 Relative Cell Concentration Gradient is less than or equal to DCEPS. 

113 Generally, NPL can be set to zero since advection is considered 

114 insignificant when the Relative Cell Concentration Gradient is less than 

115 or equal to DCEPS. Setting NPL equal to NPH causes a uniform number of 

116 particles to be placed in every cell over the entire grid (i.e., the 

117 uniform approach). 

118 Default value: 10. 

119 nparticles_advection: int, optional 

120 is number of initial particles per cell to be placed at cells where the 

121 Relative Cell Concentration Gradient is greater than DCEPS. The 

122 selection of NPH depends on the nature of the flow field and also the 

123 computer memory limitation. Generally, use a smaller number in 

124 relatively uniform flow fields and a larger number in relatively 

125 nonuniform flow fields. However, values exceeding 16 in twodimensional 

126 simulation or 32 in three-dimensional simulation are rarely necessary. 

127 If the random pattern is chosen, NPH particles are randomly distributed 

128 within the cell block. If the fixed pattern is chosen, NPH is divided by 

129 NPLANE to yield the number of particles to be placed per vertical plane. 

130 Default value: 40. 

131 cell_min_nparticles: int, optional 

132 is the minimum number of particles allowed per cell. If the number of 

133 particles in a cell at the end of a transport step is fewer than NPMIN, 

134 new particles are inserted into that cell to maintain a sufficient 

135 number of particles. NPMIN can be set to zero in relatively uniform flow 

136 fields, and a number greater than zero in diverging/converging flow 

137 fields. Generally, a value between zero and four is adequate. 

138 Default value is 5. 

139 cell_max_nparticles: int, optional 

140 is the maximum number of particles allowed per cell. If the number of 

141 particles in a cell exceeds NPMAX, all particles are removed from that 

142 cell and replaced by a new set of particles equal to NPH to maintain 

143 mass balance. Generally, NPMAX can be set to approximately twice of NPH. 

144 Default value: 80. 

145 """ 

146 

147 _pkg_id = "adv" 

148 _keywords = {"tracking": {"euler": 1, "runge-kutta": 2, "hybrid": 3}} 

149 

150 _template = textwrap.dedent( 

151 """ 

152 [adv] 

153 mixelm = 1 

154 percel = {courant} 

155 mxpart = {max_nparticles} 

156 itrack = {tracking} 

157 wd = {weighting_factor} 

158 dceps = {dconcentration_epsilon} 

159 nplane = {nplane} 

160 npl = {nparticles_no_advection} 

161 nph = {nparticles_advection} 

162 npmin = {cell_min_nparticles} 

163 npmax = {cell_max_nparticles} 

164 """ 

165 ) 

166 

167 def __init__( 

168 self, 

169 courant=0.75, 

170 tracking="hybrid", 

171 weighting_factor=0.5, 

172 dconcentration_epsilon=1.0e-5, 

173 nplane=2, 

174 nparticles_no_advection=10, 

175 nparticles_advection=40, 

176 cell_min_nparticles=5, 

177 cell_max_nparticles=80, 

178 ): 

179 super().__init__() 

180 self["courant"] = courant 

181 self["tracking"] = tracking 

182 self["weighting_factor"] = weighting_factor 

183 self["dconcentration_epsilon"] = dconcentration_epsilon 

184 self["nplane"] = nplane 

185 self["nparticles_no_advection"] = nparticles_no_advection 

186 self["nparticles_advection"] = nparticles_advection 

187 self["cell_min_nparticles"] = cell_min_nparticles 

188 self["cell_max_nparticles"] = cell_max_nparticles 

189 

190 def _pkgcheck(self, ibound=None): 

191 self._check_positive(["courant", "weighting_factor"]) 

192 

193 

194class AdvectionModifiedMOC(Package): 

195 """ 

196 Solve the advention term using the Modified Method of Characteristics (MIXELM = 2) 

197 Courant number (PERCEL) is the number of cells (or a fraction of a 

198 cell) advection will be allowed in any direction in one transport step. 

199 

200 Attributes 

201 ---------- 

202 courant: float 

203 Courant number (PERCEL) is the number of cells (or a fraction of a cell) 

204 advection will be allowed in any direction in one transport step. For 

205 implicit finite-difference or particle tracking based schemes, there is 

206 no limit on PERCEL, but for accuracy reasons, it is generally not set 

207 much greater than one. Note, however, that the PERCEL limit is checked 

208 over the entire model grid. Thus, even if PERCEL > 1, advection may not 

209 be more than one cell’s length at most model locations. For the explicit 

210 finite-difference, PERCEL is also a stability constraint, which must not 

211 exceed one and will be automatically reset to one if a value greater 

212 than one is specified. 

213 tracking: string, {"euler", "runge-kutta", "hybrid"} 

214 indicates which particle tracking algorithm is selected for the 

215 Eulerian-Lagrangian methods. ITRACK = 1, the first-order Euler algorithm is 

216 used; ITRACK = 2, the fourth-order Runge-Kutta algorithm is used; this 

217 option is computationally demanding and may be needed only when PERCEL is 

218 set greater than one. ITRACK = 3, the hybrid 1st and 4th order algorithm is 

219 used; the Runge- Kutta algorithm is used in sink/source cells and the cells 

220 next to sinks/sources while the Euler algorithm is used elsewhere. 

221 weighting_factor: float 

222 is a concentration weighting factor (WD) between 0.5 and 1. It is used for 

223 operator splitting in the particle tracking based methods. The value of 

224 0.5 is generally adequate. The value may be adjusted to achieve better 

225 mass balance. Generally, it can be increased toward 1.0 as advection 

226 becomes more dominant. 

227 dconcentration_epsilon: float, optional 

228 is a small Relative Cell Concentration Gradient (DCEPS) below which advective 

229 transport is considered negligible. A value around 1.0e-5 is generally 

230 adequate. 

231 Default value: 1.0e-5. 

232 sink_particle_placement: int 

233 indicates whether the random or fixed pattern is selected for initial 

234 placement of particles to approximate sink cells in the MMOC scheme. 

235 (NLSINK) 

236 sink_nparticles: int 

237 is the number of particles used to approximate sink cells in the MMOC 

238 scheme. (NPSINK) 

239 """ 

240 

241 _pkg_id = "adv" 

242 

243 _keywords = {"tracking": {"euler": 1, "runge-kutta": 2, "hybrid": 3}} 

244 

245 _template = ( 

246 "[adv]\n" 

247 " mixelm = 2\n" 

248 " percel = {courant}\n" 

249 " itrack = {tracking}\n" 

250 " wd = {weighting_factor}\n" 

251 " interp = 1\n" 

252 " nlsink = {sink_particle_placement}\n" 

253 " npsink = {sink_nparticles}\n" 

254 ) 

255 

256 def __init__( 

257 self, 

258 courant=1.0, 

259 tracking="hybrid", 

260 weighting_factor=0.5, 

261 dconcentration_epsilon=1.0e-5, 

262 sink_particle_placement=2, 

263 sink_nparticles=40, 

264 ): 

265 super().__init__() 

266 self["courant"] = courant 

267 self["tracking"] = tracking 

268 self["weighting_factor"] = weighting_factor 

269 self["sink_particle_placement"] = sink_particle_placement 

270 self["sink_nparticles"] = sink_nparticles 

271 

272 def _pkgcheck(self, ibound=None): 

273 self._check_positive(["courant", "weighting_factor"]) 

274 

275 

276class AdvectionHybridMOC(Package): 

277 """ 

278 Hybrid Method of Characteristics and Modified Method of Characteristics with 

279 MOC or MMOC automatically and dynamically selected (MIXELM = 3) 

280 

281 Attributes 

282 ---------- 

283 courant: float 

284 Courant number (PERCEL) is the number of cells (or a fraction of a cell) 

285 advection will be allowed in any direction in one transport step. For 

286 implicit finite-difference or particle tracking based schemes, there is 

287 no limit on PERCEL, but for accuracy reasons, it is generally not set 

288 much greater than one. Note, however, that the PERCEL limit is checked 

289 over the entire model grid. Thus, even if PERCEL > 1, advection may not 

290 be more than one cell’s length at most model locations. For the explicit 

291 finite-difference, PERCEL is also a stability constraint, which must not 

292 exceed one and will be automatically reset to one if a value greater 

293 than one is specified. 

294 max_particles: int 

295 is the maximum total number of moving particles allowed (MXPART). 

296 tracking: int 

297 indicates which particle tracking algorithm is selected for the 

298 Eulerian-Lagrangian methods. ITRACK = 1, the first-order Euler algorithm is 

299 used; ITRACK = 2, the fourth-order Runge-Kutta algorithm is used; this 

300 option is computationally demanding and may be needed only when PERCEL is 

301 set greater than one. ITRACK = 3, the hybrid 1st and 4th order algorithm is 

302 used; the Runge- Kutta algorithm is used in sink/source cells and the cells 

303 next to sinks/sources while the Euler algorithm is used elsewhere. 

304 weighting_factor: float 

305 is a concentration weighting factor (WD) between 0.5 and 1. It is used for 

306 operator splitting in the particle tracking based methods. The value of 

307 0.5 is generally adequate. The value may be adjusted to achieve better 

308 mass balance. Generally, it can be increased toward 1.0 as advection 

309 becomes more dominant. 

310 dceps: float 

311 is a small Relative Cell Concentration Gradient below which advective 

312 transport is considered negligible. A value around 10-5 is generally 

313 adequate. 

314 nplane: int 

315 is a flag indicating whether the random or fixed pattern is selected for 

316 initial placement of moving particles. NPLANE = 0, the random pattern is 

317 selected for initial placement. Particles are distributed randomly in 

318 both the horizontal and vertical directions by calling a random number 

319 generator. This option is usually preferred and leads to smaller mass 

320 balance discrepancy in nonuniform or diverging/converging flow fields. 

321 NPLANE > 0, the fixed pattern is selected for initial placement. The 

322 value of NPLANE serves as the number of vertical "planes" on which 

323 initial particles are placed within each cell block. The fixed pattern 

324 may work better than the random pattern only in relatively uniform flow 

325 fields. For two-dimensional simulations in plan view, set NPLANE = 1. 

326 For cross sectional or three-dimensional simulations, NPLANE = 2 is 

327 normally adequate. Increase NPLANE if more resolution in the vertical 

328 direction is desired. 

329 npl: int 

330 is number of initial particles per cell to be placed at cells where the 

331 Relative Cell Concentration Gradient is less than or equal to DCEPS. 

332 Generally, NPL can be set to zero since advection is considered 

333 insignificant when the Relative Cell Concentration Gradient is less than 

334 or equal to DCEPS. Setting NPL equal to NPH causes a uniform number of 

335 particles to be placed in every cell over the entire grid (i.e., the 

336 uniform approach). 

337 nph: int 

338 is number of initial particles per cell to be placed at cells where the 

339 Relative Cell Concentration Gradient is greater than DCEPS. The 

340 selection of NPH depends on the nature of the flow field and also the 

341 computer memory limitation. Generally, use a smaller number in 

342 relatively uniform flow fields and a larger number in relatively 

343 nonuniform flow fields. However, values exceeding 16 in twodimensional 

344 simulation or 32 in three-dimensional simulation are rarely necessary. 

345 If the random pattern is chosen, NPH particles are randomly distributed 

346 within the cell block. If the fixed pattern is chosen, NPH is divided by 

347 NPLANE to yield the number of particles to be placed per vertical plane. 

348 npmin: int 

349 is the minimum number of particles allowed per cell. If the number of 

350 particles in a cell at the end of a transport step is fewer than NPMIN, 

351 new particles are inserted into that cell to maintain a sufficient 

352 number of particles. NPMIN can be set to zero in relatively uniform flow 

353 fields, and a number greater than zero in diverging/converging flow 

354 fields. Generally, a value between zero and four is adequate. 

355 npmax: int 

356 is the maximum number of particles allowed per cell. If the number of 

357 particles in a cell exceeds NPMAX, all particles are removed from that 

358 cell and replaced by a new set of particles equal to NPH to maintain 

359 mass balance. Generally, NPMAX can be set to approximately twice of NPH. 

360 dchmoc: real 

361 is the critical Relative Concentration Gradient for controlling the 

362 selective use of either MOC or MMOC in the HMOC solution scheme. The MOC 

363 solution is selected at cells where the Relative Concentration Gradient 

364 is greater than DCHMOC; The MMOC solution is selected at cells where the 

365 Relative Concentration Gradient is less than or equal to DCHMOC 

366 """ 

367 

368 _pkg_id = "adv" 

369 

370 def __init__( 

371 self, 

372 courant=0.75, 

373 tracking="hybrid", 

374 weighting_factor=0.5, 

375 dconcentration_epsilon=1.0e-5, 

376 nplane=2, 

377 nparticles_no_advection=10, 

378 nparticles_advection=40, 

379 cell_min_nparticles=5, 

380 cell_max_nparticles=80, 

381 sink_particle_placement=2, 

382 sink_nparticles=40, 

383 dconcentration_hybrid=1.0e-4, 

384 ): 

385 super().__init__() 

386 self["courant"] = courant 

387 self["tracking"] = tracking 

388 self["weighting_factor"] = weighting_factor 

389 self["dconcentration_epsilon"] = dconcentration_epsilon 

390 self["nplane"] = nplane 

391 self["nparticles_no_advection"] = nparticles_no_advection 

392 self["nparticles_advection"] = nparticles_advection 

393 self["cell_min_nparticles"] = cell_min_nparticles 

394 self["cell_max_nparticles"] = cell_max_nparticles 

395 self["sink_particle_placement"] = sink_particle_placement 

396 self["sink_nparticles"] = sink_nparticles 

397 self["dconcentration_hybrid"] = dconcentration_hybrid 

398 

399 def _pkgcheck(self, ibound=None): 

400 self._check_positive(["courant", "weighting_factor"]) 

401 

402 

403class AdvectionTVD(Package): 

404 """ 

405 Total Variation Diminishing (TVD) formulation (ULTIMATE, MIXELM = -1). 

406 

407 Attributes 

408 ---------- 

409 courant : float 

410 Courant number (PERCEL) is the number of cells (or a fraction of a cell) 

411 advection will be allowed in any direction in one transport step. For 

412 implicit finite-difference or particle tracking based schemes, there is 

413 no limit on PERCEL, but for accuracy reasons, it is generally not set 

414 much greater than one. Note, however, that the PERCEL limit is checked 

415 over the entire model grid. Thus, even if PERCEL > 1, advection may not 

416 be more than one cell’s length at most model locations. For the explicit 

417 finite-difference, PERCEL is also a stability constraint, which must not 

418 exceed one and will be automatically reset to one if a value greater 

419 than one is specified. 

420 """ 

421 

422 _pkg_id = "adv" 

423 

424 _template = "[adv]\n" " mixelm = -1\n" " percel = {courant}\n" 

425 

426 def __init__(self, courant=0.75): 

427 super().__init__() 

428 self["courant"] = courant 

429 

430 def _pkgcheck(self, ibound=None): 

431 self._check_positive(["courant"])