Coverage for pySDC/implementations/convergence_controller_classes/step_size_limiter.py: 100%

43 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-09-19 09:13 +0000

1import numpy as np 

2from pySDC.core.convergence_controller import ConvergenceController 

3 

4 

5class StepSizeLimiter(ConvergenceController): 

6 """ 

7 Class to set limits to adaptive step size computation during run time 

8 

9 Please supply dt_min or dt_max in the params to limit in either direction 

10 """ 

11 

12 def setup(self, controller, params, description, **kwargs): 

13 """ 

14 Define parameters here 

15 

16 Args: 

17 controller (pySDC.Controller): The controller 

18 params (dict): The params passed for this specific convergence controller 

19 description (dict): The description object used to instantiate the controller 

20 

21 Returns: 

22 (dict): The updated params dictionary 

23 """ 

24 defaults = { 

25 "control_order": +92, 

26 "dt_min": 0, 

27 "dt_max": np.inf, 

28 } 

29 return {**defaults, **super().setup(controller, params, description, **kwargs)} 

30 

31 def dependencies(self, controller, description, **kwargs): 

32 """ 

33 Load the slope limiter if needed. 

34 

35 Args: 

36 controller (pySDC.Controller): The controller 

37 description (dict): The description object used to instantiate the controller 

38 

39 Returns: 

40 None 

41 """ 

42 slope_limiter_keys = ['dt_slope_min', 'dt_slope_max', 'dt_rel_min_slope'] 

43 available_keys = [me for me in slope_limiter_keys if me in self.params.__dict__.keys()] 

44 

45 if len(available_keys) > 0: 

46 slope_limiter_params = {key: self.params.__dict__[key] for key in available_keys} 

47 slope_limiter_params['control_order'] = self.params.control_order - 1 

48 controller.add_convergence_controller( 

49 StepSizeSlopeLimiter, params=slope_limiter_params, description=description 

50 ) 

51 

52 return None 

53 

54 def get_new_step_size(self, controller, S, **kwargs): 

55 """ 

56 Enforce an upper and lower limit to the step size here. 

57 Be aware that this is only tested when a new step size has been determined. That means if you set an initial 

58 value for the step size outside of the limits, and you don't do any further step size control, that value will 

59 go through. 

60 Also, the final step is adjusted such that we reach Tend as best as possible, which might give step sizes below 

61 the lower limit set here. 

62 

63 Args: 

64 controller (pySDC.Controller): The controller 

65 S (pySDC.Step): The current step 

66 

67 Returns: 

68 None 

69 """ 

70 for L in S.levels: 

71 if L.status.dt_new is not None: 

72 if L.status.dt_new < self.params.dt_min: 

73 self.log( 

74 f"Step size is below minimum, increasing from {L.status.dt_new:.2e} \ 

75 to \ 

76{self.params.dt_min:.2e}", 

77 S, 

78 ) 

79 L.status.dt_new = self.params.dt_min 

80 elif L.status.dt_new > self.params.dt_max: 

81 self.log( 

82 f"Step size exceeds maximum, decreasing from {L.status.dt_new:.2e} to {self.params.dt_max:.2e}", 

83 S, 

84 ) 

85 L.status.dt_new = self.params.dt_max 

86 

87 return None 

88 

89 

90class StepSizeSlopeLimiter(ConvergenceController): 

91 """ 

92 Class to set limits to adaptive step size computation during run time 

93 

94 Please supply `dt_slope_min` or `dt_slope_max` in the params to limit in either direction. 

95 You can also supply `dt_rel_min_slope` in order to keep the old step size in case the relative change is smaller 

96 than this minimum. 

97 """ 

98 

99 def setup(self, controller, params, description, **kwargs): 

100 """ 

101 Define parameters here 

102 

103 Args: 

104 controller (pySDC.Controller): The controller 

105 params (dict): The params passed for this specific convergence controller 

106 description (dict): The description object used to instantiate the controller 

107 

108 Returns: 

109 (dict): The updated params dictionary 

110 """ 

111 defaults = { 

112 "control_order": 91, 

113 "dt_slope_min": 0, 

114 "dt_slope_max": np.inf, 

115 "dt_rel_min_slope": 0, 

116 } 

117 return {**defaults, **super().setup(controller, params, description, **kwargs)} 

118 

119 def get_new_step_size(self, controller, S, **kwargs): 

120 """ 

121 Enforce an upper and lower limit to the slope of the step size here. 

122 The final step is adjusted such that we reach Tend as best as possible, which might give step sizes below 

123 the lower limit set here. 

124 

125 Args: 

126 controller (pySDC.Controller): The controller 

127 S (pySDC.Step): The current step 

128 

129 Returns: 

130 None 

131 """ 

132 for L in S.levels: 

133 if L.status.dt_new is not None: 

134 if L.status.dt_new / L.params.dt < self.params.dt_slope_min: 

135 dt_new = L.params.dt * self.params.dt_slope_min 

136 self.log( 

137 f"Step size slope is below minimum, increasing from {L.status.dt_new:.2e} \ 

138 to \ 

139{dt_new:.2e}", 

140 S, 

141 ) 

142 L.status.dt_new = dt_new 

143 elif L.status.dt_new / L.params.dt > self.params.dt_slope_max: 

144 dt_new = L.params.dt * self.params.dt_slope_max 

145 self.log( 

146 f"Step size slope exceeds maximum, decreasing from {L.status.dt_new:.2e} \ 

147 to \ 

148{dt_new:.2e}", 

149 S, 

150 ) 

151 L.status.dt_new = dt_new 

152 elif abs(L.status.dt_new / L.params.dt - 1) < self.params.dt_rel_min_slope: 

153 L.status.dt_new = L.params.dt 

154 self.log( 

155 f"Step size did not change sufficiently to warrant step size change, keeping {L.status.dt_new:.2e}", 

156 S, 

157 ) 

158 

159 return None