Coverage for pySDC/implementations/convergence_controller_classes/check_iteration_estimator.py: 98%

43 statements  

« prev     ^ index     » next       coverage.py v7.6.7, created at 2024-11-16 14:51 +0000

1import numpy as np 

2from pySDC.core.convergence_controller import ConvergenceController, Status 

3from pySDC.implementations.convergence_controller_classes.store_uold import StoreUOld 

4 

5 

6class CheckIterationEstimatorNonMPI(ConvergenceController): 

7 def __init__(self, controller, params, description, **kwargs): 

8 """ 

9 Initialization routine 

10 

11 Args: 

12 controller (pySDC.Controller): The controller 

13 params (dict): Parameters for the convergence controller 

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

15 """ 

16 super(CheckIterationEstimatorNonMPI, self).__init__(controller, params, description) 

17 self.buffers = Status(["Kest_loc", "diff_new", "Ltilde_loc"]) 

18 self.status = Status(["diff_old_loc", "diff_first_loc"]) 

19 

20 def check_parameters(self, controller, params, description, **kwargs): 

21 """ 

22 Check whether parameters are compatible with whatever assumptions went into the step size functions etc. 

23 In this case, we need the user to supply a tolerance. 

24 

25 Args: 

26 controller (pySDC.Controller): The controller 

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

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

29 

30 Returns: 

31 bool: Whether the parameters are compatible 

32 str: The error message 

33 """ 

34 if "errtol" not in params.keys(): 

35 return ( 

36 False, 

37 "Please give the iteration estimator a tolerance in the form of `errtol`. Thanks!", 

38 ) 

39 

40 return True, "" 

41 

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

43 """ 

44 Setup parameters. Here we only give a default value for the control order. 

45 

46 Args: 

47 controller (pySDC.Controller): The controller 

48 params (dict): Parameters for the convergence controller 

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

50 

51 Returns: 

52 dict: The updated parameters 

53 """ 

54 return {"control_order": -50, **super().setup(controller, params, description, **kwargs)} 

55 

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

57 """ 

58 Need to store the solution of previous iterations. 

59 

60 Args: 

61 controller (pySDC.Controller): The controller 

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

63 

64 Returns: 

65 None 

66 """ 

67 controller.add_convergence_controller(StoreUOld, description=description) 

68 return None 

69 

70 def reset_buffers_nonMPI(self, controller, **kwargs): 

71 """ 

72 Reset buffers used to immitate communication in non MPI version. 

73 

74 Args: 

75 controller (pySDC.controller): The controller 

76 

77 Returns: 

78 None 

79 """ 

80 self.buffers.Kest_loc = [99] * len(controller.MS) 

81 self.buffers.diff_new = 0.0 

82 self.buffers.Ltilde_loc = 0.0 

83 

84 def setup_status_variables(self, controller, **kwargs): 

85 """ 

86 Setup storage variables for the differences between sweeps for all steps. 

87 

88 Args: 

89 controller (pySDC.Controller): The controller 

90 

91 Returns: 

92 None 

93 """ 

94 self.status.diff_old_loc = [0.0] * len(controller.MS) 

95 self.status.diff_first_loc = [0.0] * len(controller.MS) 

96 return None 

97 

98 def check_iteration_status(self, controller, S, **kwargs): 

99 """ 

100 Args: 

101 controller (pySDC.Controller): The controller 

102 S (pySDC.step): The current step 

103 

104 Returns: 

105 None 

106 """ 

107 L = S.levels[0] 

108 slot = S.status.slot 

109 

110 # find the global maximum difference between iterations 

111 for m in range(1, L.sweep.coll.num_nodes + 1): 

112 self.buffers.diff_new = max(self.buffers.diff_new, abs(L.uold[m] - L.u[m])) 

113 

114 if S.status.iter == 1: 

115 self.status.diff_old_loc[slot] = self.buffers.diff_new 

116 self.status.diff_first_loc[slot] = self.buffers.diff_new 

117 elif S.status.iter > 1: 

118 # approximate contraction factor 

119 self.buffers.Ltilde_loc = min(self.buffers.diff_new / self.status.diff_old_loc[slot], 0.9) 

120 

121 self.status.diff_old_loc[slot] = self.buffers.diff_new 

122 

123 # estimate how many more iterations we need for this step to converge to the desired tolerance 

124 alpha = 1 / (1 - self.buffers.Ltilde_loc) * self.status.diff_first_loc[slot] 

125 self.buffers.Kest_loc = np.log(self.params.errtol / alpha) / np.log(self.buffers.Ltilde_loc) * 1.05 

126 self.logger.debug( 

127 f'LOCAL: {L.time:8.4f}, {S.status.iter}: {int(np.ceil(self.buffers.Kest_loc))}, ' 

128 f'{self.buffers.Ltilde_loc:8.6e}, {self.buffers.Kest_loc:8.6e}, \ 

129{self.buffers.Ltilde_loc ** S.status.iter * alpha:8.6e}' 

130 ) 

131 

132 # set global Kest as last local one, force stop if done 

133 if S.status.last: 

134 Kest_glob = self.buffers.Kest_loc 

135 if np.ceil(Kest_glob) <= S.status.iter: 

136 S.status.force_done = True