Coverage for C:\src\imod-python\imod\mf6\adv.py: 91%

34 statements  

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

1""" 

2When simulating transport, MODFLOW6 needs to compute the concentration at a 

3cellface between 2 adjacent cells. It supports 3 ways of doing this. Each of 

4those has its own wrapper class. These numerical schemes differ in how much 

5numerical dispersion they cause, how much oscillations, and how timestep and 

6grid size affect stability. Central-in-space weighting is not often used 

7because it can result in spurious oscillations in the simulated concentrations. 

8Upstream weighting is a fast alternative, and TVD is a more expensive and more 

9robust alternative. 

10""" 

11 

12from copy import deepcopy 

13from typing import Optional, Tuple 

14 

15from imod.mf6.interfaces.iregridpackage import IRegridPackage 

16from imod.mf6.package import Package 

17from imod.mf6.utilities.regrid import RegridderType 

18 

19 

20class Advection(Package, IRegridPackage): 

21 _pkg_id = "adv" 

22 _template = Package._initialize_template(_pkg_id) 

23 _regrid_method: dict[str, tuple[RegridderType, str]] = {} 

24 

25 def __init__(self, scheme: str): 

26 dict_dataset = {"scheme": scheme} 

27 super().__init__(dict_dataset) 

28 

29 def render(self, directory, pkgname, globaltimes, binary): 

30 scheme = self.dataset["scheme"].item() 

31 return self._template.render({"scheme": scheme}) 

32 

33 def mask(self, _) -> Package: 

34 """ 

35 The mask method is irrelevant for this package , instead this method 

36 retuns a copy of itself. 

37 """ 

38 return deepcopy(self) 

39 

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

41 return self._regrid_method 

42 

43 

44class AdvectionUpstream(Advection): 

45 """ 

46 The upstream weighting (first order upwind) scheme sets the concentration 

47 at the cellface between two adjacent cells equal to the concentration in 

48 the cell where the flow comes from. It surpresses oscillations. 

49 Note: all constructor arguments will be ignored 

50 """ 

51 

52 def __init__(self, scheme: str = "upstream"): 

53 if not scheme == "upstream": 

54 raise ValueError( 

55 "error in scheme parameter. Should be 'upstream' if present." 

56 ) 

57 super().__init__(scheme="upstream") 

58 

59 

60class AdvectionCentral(Advection): 

61 """ 

62 The central-in-space weighting scheme is based on a simple 

63 distance-weighted linear interpolation between the center of cell n and the 

64 center of cell m to calculate solute concentration at the shared face 

65 between cell n and cell m. Although central-in-space is a misnomer for 

66 grids without equal spacing between connected cells, it is retained here 

67 for consistency with nomenclature used by other MODFLOW-based transport 

68 programs, such as MT3D. 

69 Note: all constructor arguments will be ignored 

70 """ 

71 

72 def __init__(self, scheme: str = "central"): 

73 if not scheme == "central": 

74 raise ValueError( 

75 "error in scheme parameter. Should be 'central' if present." 

76 ) 

77 super().__init__(scheme="central") 

78 

79 

80class AdvectionTVD(Advection): 

81 """ 

82 An implicit second order TVD scheme. More expensive than upstream 

83 weighting but more robust. 

84 Note: all constructor arguments will be ignored 

85 """ 

86 

87 def __init__(self, scheme: str = "TVD"): 

88 if not scheme == "TVD": 

89 raise ValueError("error in scheme parameter. Should be 'TVD' if present.") 

90 super().__init__(scheme="TVD")