Coverage for pySDC/projects/Resilience/reachTendExactly.py: 100%

19 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-02-20 10:09 +0000

1import numpy as np 

2from pySDC.core.convergence_controller import ConvergenceController 

3from pySDC.implementations.convergence_controller_classes.check_convergence import CheckConvergence 

4 

5 

6class ReachTendExactly(ConvergenceController): 

7 """ 

8 This convergence controller will adapt the step size of (hopefully) the last step such that `Tend` is reached very closely. 

9 Please pass the same `Tend` that you pass to the controller to the params for this to work. 

10 """ 

11 

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

13 defaults = { 

14 "control_order": +94, 

15 "Tend": None, 

16 'min_step_size': 1e-10, 

17 } 

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

19 

20 def get_new_step_size(self, controller, step, **kwargs): 

21 L = step.levels[0] 

22 time_size = step.status.time_size 

23 

24 if not CheckConvergence.check_convergence(step): 

25 return None 

26 

27 dt = L.status.dt_new if L.status.dt_new else L.params.dt 

28 time_left = self.params.Tend - L.time - L.dt 

29 

30 if ( 

31 time_left <= (dt + self.params.min_step_size) * time_size 

32 and not step.status.restart 

33 and time_left > 0 

34 and step.status.last 

35 ): 

36 dt_new = ( 

37 min([(dt + self.params.min_step_size) * time_size, max([time_left, self.params.min_step_size])]) 

38 + time_size * np.finfo('float').eps * 10 

39 ) / time_size 

40 

41 if dt_new != L.status.dt_new: 

42 L.status.dt_new = dt_new 

43 self.log( 

44 f'Changing step size from {dt:12e} to {L.status.dt_new:.12e} because there is only {time_left:.12e} left.', 

45 step, 

46 )