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
« 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
6class CheckIterationEstimatorNonMPI(ConvergenceController):
7 def __init__(self, controller, params, description, **kwargs):
8 """
9 Initialization routine
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"])
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.
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
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 )
40 return True, ""
42 def setup(self, controller, params, description, **kwargs):
43 """
44 Setup parameters. Here we only give a default value for the control order.
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
51 Returns:
52 dict: The updated parameters
53 """
54 return {"control_order": -50, **super().setup(controller, params, description, **kwargs)}
56 def dependencies(self, controller, description, **kwargs):
57 """
58 Need to store the solution of previous iterations.
60 Args:
61 controller (pySDC.Controller): The controller
62 description (dict): The description object used to instantiate the controller
64 Returns:
65 None
66 """
67 controller.add_convergence_controller(StoreUOld, description=description)
68 return None
70 def reset_buffers_nonMPI(self, controller, **kwargs):
71 """
72 Reset buffers used to immitate communication in non MPI version.
74 Args:
75 controller (pySDC.controller): The controller
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
84 def setup_status_variables(self, controller, **kwargs):
85 """
86 Setup storage variables for the differences between sweeps for all steps.
88 Args:
89 controller (pySDC.Controller): The controller
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
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
104 Returns:
105 None
106 """
107 L = S.levels[0]
108 slot = S.status.slot
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]))
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)
121 self.status.diff_old_loc[slot] = self.buffers.diff_new
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 )
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