Coverage for pySDC/projects/Resilience/strategies.py: 66%
909 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-20 14:51 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-20 14:51 +0000
1import numpy as np
2from matplotlib.colors import TABLEAU_COLORS
4cmap = TABLEAU_COLORS
7def merge_descriptions(descA, descB):
8 """
9 Merge two dictionaries that may contain dictionaries, which happens when merging descriptions, for instance.
11 Keys that occur in both dictionaries will be overwritten by the ones from `descB` and `descA` will be modified, not
12 copied!
14 Args:
15 descA (dict): Dictionary that you want to merge into
16 descB (dict): Dictionary you want to merge from
18 Returns:
19 dict: decsA with updated parameters
20 """
21 for key in descB.keys():
22 if type(descB[key]) == dict:
23 descA[key] = merge_descriptions(descA.get(key, {}), descB[key])
24 else:
25 descA[key] = descB[key]
26 return descA
29class Strategy:
30 '''
31 Abstract class for resilience strategies
32 '''
34 def __init__(self, useMPI=False, skip_residual_computation='none', stop_at_nan=True, **kwargs):
35 '''
36 Initialization routine
37 '''
38 self.useMPI = useMPI
39 self.max_steps = 1e5
41 # set default values for plotting
42 self.linestyle = '-'
43 self.marker = '.'
44 self.name = ''
45 self.bar_plot_x_label = ''
46 self.color = list(cmap.values())[0]
48 # parameters for computational efficiency
49 if skip_residual_computation == 'all':
50 self.skip_residual_computation = ('IT_CHECK', 'IT_DOWN', 'IT_UP', 'IT_FINE', 'IT_COARSE')
51 elif skip_residual_computation == 'most':
52 self.skip_residual_computation = ('IT_DOWN', 'IT_UP', 'IT_FINE', 'IT_COARSE')
53 elif skip_residual_computation == 'none':
54 self.skip_residual_computation = ()
55 else:
56 raise NotImplementedError(
57 f'Don\'t know when to skip residual computation with rule \"{skip_residual_computation}\"'
58 )
60 self.stop_at_nan = stop_at_nan
62 # setup custom descriptions
63 self.custom_description = {}
64 self.custom_description['sweeper_params'] = {'skip_residual_computation': self.skip_residual_computation}
65 self.custom_description['level_params'] = {}
66 self.custom_description['problem_params'] = {}
67 self.custom_description['step_params'] = {}
68 self.custom_description['convergence_controllers'] = {}
70 # prepare parameters for masks to identify faults that cannot be fixed by this strategy
71 self.fixable = []
72 self.fixable += [
73 {
74 'key': 'node',
75 'op': 'gt',
76 'val': 0,
77 }
78 ]
79 self.fixable += [
80 {
81 'key': 'error',
82 'op': 'isfinite',
83 }
84 ]
86 # stuff for work-precision diagrams
87 self.precision_parameter = None
88 self.precision_parameter_loc = []
90 def __str__(self):
91 return self.name
93 def get_controller_params(self, **kwargs):
94 return {'all_to_done': False}
96 def get_description_for_tolerance(self, problem, param, **kwargs):
97 return {}
99 def get_fixable_params(self, **kwargs):
100 """
101 Return a list containing dictionaries which can be passed to `FaultStats.get_mask` as keyword arguments to
102 obtain a mask of faults that can be fixed
104 Returns:
105 list: Dictionary of parameters
106 """
107 return self.fixable
109 def get_fault_args(self, problem, num_procs):
110 '''
111 Routine to get arguments for the faults that are exempt from randomization
113 Args:
114 problem: A function that runs a pySDC problem, see imports for available problems
115 num_procs (int): Number of processes you intend to run with
117 Returns:
118 dict: Arguments for the faults that are exempt from randomization
119 '''
120 args = {}
121 args['target'] = 0
123 if problem.__name__ == "run_vdp":
124 args['time'] = 5.25
125 elif problem.__name__ == "run_Schroedinger":
126 args['time'] = 0.3
127 elif problem.__name__ == "run_quench":
128 args['time'] = 41.0
129 elif problem.__name__ == "run_Lorenz":
130 args['time'] = 10
131 elif problem.__name__ == "run_AC":
132 args['time'] = 1e-2
133 elif problem.__name__ == "run_RBC":
134 args['time'] = 20.19
136 return args
138 def get_random_params(self, problem, num_procs):
139 '''
140 Routine to get parameters for the randomization of faults
142 Args:
143 problem: A function that runs a pySDC problem, see imports for available problems
144 num_procs (int): Number of processes you intend to run with
146 Returns:
147 dict: Randomization parameters
148 '''
149 base_params = self.get_base_parameters(problem, num_procs)
151 rnd_params = {}
152 rnd_params['iteration'] = base_params['step_params']['maxiter']
153 rnd_params['rank'] = num_procs
155 if problem.__name__ in ['run_Schroedinger', 'run_quench', 'run_AC', 'run_RBC']:
156 rnd_params['min_node'] = 1
158 if problem.__name__ == "run_quench":
159 rnd_params['iteration'] = 5
160 elif problem.__name__ == 'run_Lorenz':
161 rnd_params['iteration'] = 5
162 elif problem.__name__ == 'run_RBC':
163 rnd_params['problem_pos'] = [3, 16, 16]
165 return rnd_params
167 @property
168 def style(self):
169 """
170 Get the plotting parameters for the strategy.
171 Supply them to a plotting function using `**`
173 Returns:
174 (dict): The plotting parameters as a dictionary
175 """
176 return {
177 'marker': self.marker,
178 'label': self.label,
179 'color': self.color,
180 'ls': self.linestyle,
181 }
183 @property
184 def label(self):
185 """
186 Get a label for plotting
187 """
188 return self.name
190 @classmethod
191 def get_Tend(cls, problem, num_procs=1):
192 '''
193 Get the final time of runs for fault stats based on the problem
195 Args:
196 problem (function): A problem to run
197 num_procs (int): Number of processes
199 Returns:
200 float: Tend to put into the run
201 '''
202 if problem.__name__ == "run_vdp":
203 return 20 # 11.5
204 elif problem.__name__ == "run_piline":
205 return 20.0
206 elif problem.__name__ == "run_Lorenz":
207 return 20
208 elif problem.__name__ == "run_Schroedinger":
209 return 1.0
210 elif problem.__name__ == "run_quench":
211 return 500.0
212 elif problem.__name__ == "run_AC":
213 return 0.025
214 elif problem.__name__ == "run_RBC":
215 return 21
216 else:
217 raise NotImplementedError('I don\'t have a final time for your problem!')
219 def get_base_parameters(self, problem, num_procs=1):
220 '''
221 Get a base parameters for the problems independent of the strategy.
223 Args:
224 problem (function): A problem to run
225 num_procs (int): Number of processes
227 Returns:
228 dict: Custom description
229 '''
230 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter
232 custom_description = {}
233 custom_description['step_params'] = {}
234 custom_description['level_params'] = {}
235 custom_description['problem_params'] = {}
237 if problem.__name__ == "run_vdp":
238 custom_description['step_params'] = {'maxiter': 3}
239 custom_description['problem_params'] = {
240 'u0': np.array([1.1, 0], dtype=np.float64),
241 'mu': 1000,
242 'crash_at_maxiter': False,
243 'newton_tol': 1e-11,
244 'stop_at_nan': False,
245 }
246 custom_description['level_params'] = {'dt': 1e-4}
248 elif problem.__name__ == "run_Lorenz":
249 custom_description['step_params'] = {'maxiter': 5}
250 custom_description['level_params'] = {'dt': 1e-3}
251 custom_description['problem_params'] = {'stop_at_nan': False}
252 elif problem.__name__ == "run_Schroedinger":
253 custom_description['step_params'] = {'maxiter': 5}
254 custom_description['level_params'] = {'dt': 1e-2, 'restol': -1}
255 custom_description['problem_params']['nvars'] = (256, 256)
256 elif problem.__name__ == "run_quench":
257 custom_description['level_params'] = {'restol': -1, 'dt': 8.0}
258 custom_description['step_params'] = {'maxiter': 5}
259 custom_description['problem_params'] = {
260 'newton_maxiter': 29,
261 'newton_tol': 1e-7,
262 'nvars': 2**6,
263 'direct_solver': False,
264 'lintol': 1e-8,
265 'liniter': 29,
266 'order': 6,
267 }
268 elif problem.__name__ == "run_AC":
269 eps = 4e-2
270 custom_description['step_params'] = {'maxiter': 5}
271 custom_description['problem_params'] = {
272 'nvars': (128,) * 2,
273 'init_type': 'circle',
274 'eps': eps,
275 'radius': 0.25,
276 'nu': 2,
277 }
278 custom_description['level_params'] = {'restol': -1, 'dt': 0.1 * eps**2}
279 elif problem.__name__ == 'run_RBC':
280 custom_description['level_params']['dt'] = 5e-2
281 custom_description['step_params'] = {'maxiter': 5}
283 custom_description['convergence_controllers'] = {
284 # StepSizeLimiter: {'dt_min': self.get_Tend(problem=problem, num_procs=num_procs) / self.max_steps}
285 }
287 if self.stop_at_nan:
288 from pySDC.implementations.convergence_controller_classes.crash import StopAtNan
290 custom_description['convergence_controllers'][StopAtNan] = {'thresh': 1e20}
292 from pySDC.implementations.convergence_controller_classes.crash import StopAtMaxRuntime
294 max_runtime = {
295 'run_vdp': 1000,
296 'run_Lorenz': 500,
297 'run_Schroedinger': 150,
298 'run_quench': 150,
299 'run_AC': 150,
300 'run_RBC': 1000,
301 }
303 custom_description['convergence_controllers'][StopAtMaxRuntime] = {
304 'max_runtime': max_runtime.get(problem.__name__, 100)
305 }
306 return custom_description
308 def get_custom_description(self, problem, num_procs=1):
309 '''
310 Get a custom description based on the problem
312 Args:
313 problem (function): A problem to run
314 num_procs (int): Number of processes
316 Returns:
317 dict: Custom description
318 '''
319 custom_description = self.get_base_parameters(problem, num_procs)
320 return merge_descriptions(custom_description, self.custom_description)
322 def get_custom_description_for_faults(self, *args, **kwargs):
323 '''
324 Get a custom description based on the problem to run the fault stuff
326 Returns:
327 dict: Custom description
328 '''
329 return self.get_custom_description(*args, **kwargs)
331 def get_reference_value(self, problem, key, op, num_procs=1):
332 """
333 Get a reference value for a given problem for testing in CI.
335 Args:
336 problem: A function that runs a pySDC problem, see imports for available problems
337 key (str): The name of the variable you want to compare
338 op (function): The operation you want to apply to the data
339 num_procs (int): Number of processes
341 Returns:
342 The reference value
343 """
344 raise NotImplementedError(
345 f'The reference value you are looking for is not implemented for {type(self).__name__} strategy!'
346 )
349class InexactBaseStrategy(Strategy):
350 """
351 Base class for inexact strategies.
352 """
354 def __init__(
355 self, double_adaptivity=False, newton_inexactness=True, linear_inexactness=True, SDC_maxiter=16, **kwargs
356 ):
357 kwargs = {**kwargs, 'skip_residual_computation': 'most'}
358 super().__init__(**kwargs)
359 self.double_adaptivity = double_adaptivity
360 self.newton_inexactness = newton_inexactness
361 self.linear_inexactness = linear_inexactness
362 self.SDC_maxiter = SDC_maxiter
364 def get_controller_params(self, **kwargs):
365 return {'all_to_done': True}
367 def get_custom_description(self, problem, num_procs=1):
368 from pySDC.implementations.convergence_controller_classes.inexactness import NewtonInexactness
370 preconditioner = 'MIN-SR-NS' if problem.__name__ in ['run_Lorenz'] else 'MIN-SR-S'
372 desc = {}
373 desc['sweeper_params'] = {'QI': preconditioner}
374 desc['step_params'] = {'maxiter': self.SDC_maxiter}
375 desc['problem_params'] = {}
376 desc['level_params'] = {'restol': 1e-8, 'residual_type': 'last_abs'}
377 desc['convergence_controllers'] = {}
379 inexactness_params = {
380 'min_tol': 1e-12,
381 'ratio': 1e-2,
382 'max_tol': 1e-4,
383 'use_e_tol': False,
384 'maxiter': 15,
385 }
387 if self.newton_inexactness and problem.__name__ not in ['run_Schroedinger', 'run_AC', 'run_RBC']:
388 if problem.__name__ == 'run_quench':
389 inexactness_params['ratio'] = 1e-1
390 inexactness_params['min_tol'] = 1e-11
391 inexactness_params['maxiter'] = 5
392 elif problem.__name__ == "run_vdp":
393 inexactness_params['ratio'] = 1e-5
394 inexactness_params['min_tol'] = 1e-15
395 inexactness_params['maxiter'] = 9
396 desc['convergence_controllers'][NewtonInexactness] = inexactness_params
398 if problem.__name__ in ['run_vdp']:
399 desc['problem_params']['stop_at_nan'] = False
401 if self.linear_inexactness and problem.__name__ in ['run_quench']:
402 desc['problem_params']['inexact_linear_ratio'] = 1e-1
403 if problem.__name__ in ['run_quench']:
404 desc['problem_params']['direct_solver'] = False
405 desc['problem_params']['liniter'] = 9
406 desc['problem_params']['min_lintol'] = 1e-11
408 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
410 desc['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
411 'max_restarts': 29,
412 'crash_after_max_restarts': True,
413 }
414 return merge_descriptions(super().get_custom_description(problem, num_procs), desc)
417class BaseStrategy(Strategy):
418 '''
419 Do a fixed iteration count
420 '''
422 def __init__(self, skip_residual_computation='all', **kwargs):
423 '''
424 Initialization routine
425 '''
426 super().__init__(skip_residual_computation=skip_residual_computation, **kwargs)
427 self.color = list(cmap.values())[0]
428 self.marker = 'o'
429 self.name = 'base'
430 self.bar_plot_x_label = 'base'
431 self.precision_parameter = 'dt'
432 self.precision_parameter_loc = ['level_params', 'dt']
434 @property
435 def label(self):
436 return r'fixed'
438 def get_custom_description(self, problem, num_procs):
439 desc = super().get_custom_description(problem, num_procs)
440 if problem.__name__ == "run_AC":
441 desc['level_params']['dt'] = 1e-2 * desc['problem_params']['eps'] ** 2
442 return desc
444 def get_custom_description_for_faults(self, problem, *args, **kwargs):
445 desc = self.get_custom_description(problem, *args, **kwargs)
446 if problem.__name__ == "run_quench":
447 desc['level_params']['dt'] = 5.0
448 elif problem.__name__ == "run_AC":
449 desc['level_params']['dt'] = 8e-5
450 return desc
452 def get_reference_value(self, problem, key, op, num_procs=1):
453 """
454 Get a reference value for a given problem for testing in CI.
456 Args:
457 problem: A function that runs a pySDC problem, see imports for available problems
458 key (str): The name of the variable you want to compare
459 op (function): The operation you want to apply to the data
460 num_procs (int): Number of processes
462 Returns:
463 The reference value
464 """
465 if problem.__name__ == "run_Lorenz":
466 if key == 'work_newton' and op == sum:
467 return 12350
468 elif key == 'e_global_post_run' and op == max:
469 return 1.3527453646133836e-07
471 super().get_reference_value(problem, key, op, num_procs)
474class AdaptivityStrategy(Strategy):
475 '''
476 Adaptivity as a resilience strategy
477 '''
479 def __init__(self, **kwargs):
480 '''
481 Initialization routine
482 '''
483 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
485 kwargs['skip_residual_computation'] = 'all'
486 super().__init__(**kwargs)
487 self.color = list(cmap.values())[1]
488 self.marker = '*'
489 self.name = 'adaptivity'
490 self.bar_plot_x_label = 'adaptivity'
491 self.precision_parameter = 'e_tol'
492 self.precision_parameter_loc = ['convergence_controllers', Adaptivity, 'e_tol']
494 @property
495 def label(self):
496 return r'$\Delta t$-adaptivity'
498 def get_fixable_params(self, maxiter, **kwargs):
499 """
500 Here faults occurring in the last iteration cannot be fixed.
502 Args:
503 maxiter (int): Max. iterations until convergence is declared
505 Returns:
506 (list): Contains dictionaries of keyword arguments for `FaultStats.get_mask`
507 """
508 self.fixable += [
509 {
510 'key': 'iteration',
511 'op': 'lt',
512 'val': maxiter,
513 }
514 ]
515 return self.fixable
517 def get_custom_description(self, problem, num_procs):
518 '''
519 Routine to get a custom description that adds adaptivity
521 Args:
522 problem: A function that runs a pySDC problem, see imports for available problems
523 num_procs (int): Number of processes you intend to run with
525 Returns:
526 The custom descriptions you can supply to the problem when running it
527 '''
528 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
529 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter
531 base_params = super().get_custom_description(problem, num_procs)
532 custom_description = {}
533 custom_description['convergence_controllers'] = {}
535 dt_max = np.inf
536 dt_slope_max = np.inf
537 dt_slope_min = 0
539 if problem.__name__ == "run_piline":
540 e_tol = 1e-7
541 elif problem.__name__ == "run_vdp":
542 e_tol = 2e-5
543 elif problem.__name__ == "run_Lorenz":
544 e_tol = 1e-7
545 elif problem.__name__ == "run_Schroedinger":
546 e_tol = 4e-7
547 elif problem.__name__ == "run_quench":
548 e_tol = 1e-8
549 custom_description['problem_params'] = {
550 'newton_tol': 1e-10,
551 'lintol': 1e-11,
552 }
554 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
556 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
557 'max_restarts': 99,
558 }
559 elif problem.__name__ == "run_AC":
560 e_tol = 1e-7
561 # dt_max = 0.1 * base_params['problem_params']['eps'] ** 2
562 elif problem.__name__ == 'run_RBC':
563 e_tol = 1e-4
564 dt_slope_min = 1
566 else:
567 raise NotImplementedError(
568 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\
569 strategy'
570 )
572 custom_description['convergence_controllers'][Adaptivity] = {
573 'e_tol': e_tol,
574 'dt_slope_max': dt_slope_max,
575 'dt_rel_min_slope': dt_slope_min,
576 }
577 custom_description['convergence_controllers'][StepSizeLimiter] = {
578 'dt_max': dt_max,
579 }
580 return merge_descriptions(base_params, custom_description)
582 def get_reference_value(self, problem, key, op, num_procs=1):
583 """
584 Get a reference value for a given problem for testing in CI.
586 Args:
587 problem: A function that runs a pySDC problem, see imports for available problems
588 key (str): The name of the variable you want to compare
589 op (function): The operation you want to apply to the data
590 num_procs (int): Number of processes
592 Returns:
593 The reference value
594 """
595 if problem.__name__ == 'run_Lorenz':
596 if key == 'work_newton' and op == sum:
597 return 2989
598 elif key == 'e_global_post_run' and op == max:
599 return 5.636767497207984e-08
601 super().get_reference_value(problem, key, op, num_procs)
603 def get_custom_description_for_faults(self, problem, num_procs, *args, **kwargs):
604 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter
605 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
607 desc = self.get_custom_description(problem, num_procs, *args, **kwargs)
608 if problem.__name__ == "run_quench":
609 desc['level_params']['dt'] = 1.1e1
610 desc['convergence_controllers'][Adaptivity]['e_tol'] = 1e-6
611 elif problem.__name__ == "run_AC":
612 desc['convergence_controllers'][Adaptivity]['e_tol'] = 1e-5
613 return desc
616class AdaptivityRestartFirstStep(AdaptivityStrategy):
617 def __init__(self, **kwargs):
618 super().__init__(**kwargs)
619 self.color = 'teal'
620 self.name = 'adaptivityRestartFirstStep'
622 def get_custom_description(self, problem, num_procs):
623 '''
624 Add the other version of basic restarting.
626 Args:
627 problem: A function that runs a pySDC problem, see imports for available problems
628 num_procs (int): Number of processes you intend to run with
630 Returns:
631 The custom descriptions you can supply to the problem when running it
632 '''
633 custom_description = super().get_custom_description(problem, num_procs)
634 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
636 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
637 'max_restarts': 15,
638 'restart_from_first_step': True,
639 }
640 return custom_description
642 @property
643 def label(self):
644 return f'{super().label} restart from first step'
647class AdaptiveHotRodStrategy(Strategy):
648 '''
649 Adaptivity + Hot Rod as a resilience strategy
650 '''
652 def __init__(self, **kwargs):
653 '''
654 Initialization routine
655 '''
656 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
658 kwargs['skip_residual_computation'] = 'all'
659 super().__init__(**kwargs)
660 self.color = list(cmap.values())[4]
661 self.marker = '.'
662 self.name = 'adaptive Hot Rod'
663 self.bar_plot_x_label = 'adaptive\nHot Rod'
664 self.precision_parameter = 'e_tol'
665 self.precision_parameter_loc = ['convergence_controllers', Adaptivity, 'e_tol']
667 def get_custom_description(self, problem, num_procs):
668 '''
669 Routine to get a custom description that adds adaptivity and Hot Rod
671 Args:
672 problem: A function that runs a pySDC problem, see imports for available problems
673 num_procs (int): Number of processes you intend to run with
675 Returns:
676 The custom description you can supply to the problem when running it
677 '''
678 from pySDC.implementations.convergence_controller_classes.hotrod import HotRod
679 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
681 if problem.__name__ == "run_vdp":
682 e_tol = 3e-7
683 dt_min = 1e-3
684 maxiter = 4
685 HotRod_tol = 2e-6
686 elif problem.__name__ == "run_Lorenz":
687 e_tol = 3e-7
688 dt_min = 1e-3
689 maxiter = 4
690 HotRod_tol = 2e-6
691 else:
692 raise NotImplementedError(
693 'I don\'t have a tolerance for adaptive Hot Rod for your problem. Please add one \
694to the strategy'
695 )
697 no_storage = num_procs > 1
699 custom_description = {
700 'convergence_controllers': {
701 HotRod: {'HotRod_tol': HotRod_tol, 'no_storage': no_storage},
702 Adaptivity: {'e_tol': e_tol, 'dt_min': dt_min, 'embedded_error_flavor': 'linearized'},
703 },
704 'step_params': {'maxiter': maxiter},
705 }
707 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description)
709 def get_reference_value(self, problem, key, op, num_procs=1):
710 """
711 Get a reference value for a given problem for testing in CI.
713 Args:
714 problem: A function that runs a pySDC problem, see imports for available problems
715 key (str): The name of the variable you want to compare
716 op (function): The operation you want to apply to the data
717 num_procs (int): Number of processes
719 Returns:
720 The reference value
721 """
722 if problem.__name__ == "run_Lorenz":
723 if key == 'work_newton' and op == sum:
724 return 5092
725 elif key == 'e_global_post_run' and op == max:
726 return 4.107116318152748e-06
728 super().get_reference_value(problem, key, op, num_procs)
731class IterateStrategy(Strategy):
732 '''
733 Iterate for as much as you want
734 '''
736 def __init__(self, **kwargs):
737 '''
738 Initialization routine
739 '''
740 kwargs['skip_residual_computation'] = 'most'
741 super().__init__(**kwargs)
742 self.color = list(cmap.values())[2]
743 self.marker = 'v'
744 self.name = 'iterate'
745 self.bar_plot_x_label = 'iterate'
746 self.precision_parameter = 'restol'
747 self.precision_parameter_loc = ['level_params', 'restol']
749 @property
750 def label(self):
751 return r'$k$-adaptivity'
753 def get_custom_description(self, problem, num_procs):
754 '''
755 Routine to get a custom description that allows for adaptive iteration counts
757 Args:
758 problem: A function that runs a pySDC problem, see imports for available problems
759 num_procs (int): Number of processes you intend to run with
761 Returns:
762 The custom description you can supply to the problem when running it
763 '''
764 restol = -1
765 e_tol = -1
767 if problem.__name__ == "run_piline":
768 restol = 2.3e-8
769 elif problem.__name__ == "run_vdp":
770 restol = 9e-7
771 elif problem.__name__ == "run_Lorenz":
772 restol = 16e-7
773 elif problem.__name__ == "run_Schroedinger":
774 restol = 6.5e-7
775 elif problem.__name__ == "run_quench":
776 restol = 1e-7
777 elif problem.__name__ == "run_AC":
778 restol = 1e-11
779 elif problem.__name__ == "run_RBC":
780 restol = 1e-4
781 else:
782 raise NotImplementedError(
783 'I don\'t have a residual tolerance for your problem. Please add one to the \
784strategy'
785 )
787 custom_description = {
788 'step_params': {'maxiter': 99},
789 'level_params': {'restol': restol, 'e_tol': e_tol},
790 }
792 if problem.__name__ == "run_quench":
793 custom_description['level_params']['dt'] = 1.0
795 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description)
797 def get_random_params(self, problem, num_procs):
798 '''
799 Routine to get parameters for the randomization of faults
801 Args:
802 problem: A function that runs a pySDC problem, see imports for available problems
803 num_procs (int): Number of processes you intend to run with
805 Returns:
806 dict: Randomization parameters
807 '''
809 rnd_params = super().get_random_params(problem, num_procs)
810 if problem.__name__ == "run_quench":
811 rnd_params['iteration'] = 1
812 return rnd_params
814 def get_reference_value(self, problem, key, op, num_procs=1):
815 """
816 Get a reference value for a given problem for testing in CI.
818 Args:
819 problem: A function that runs a pySDC problem, see imports for available problems
820 key (str): The name of the variable you want to compare
821 op (function): The operation you want to apply to the data
822 num_procs (int): Number of processes
824 Returns:
825 The reference value
826 """
827 if problem.__name__ == "run_Lorenz":
828 if key == 'work_newton' and op == sum:
829 return 9200
830 elif key == 'e_global_post_run' and op == max:
831 return 2.139863344829962e-05
833 super().get_reference_value(problem, key, op, num_procs)
836class kAdaptivityStrategy(IterateStrategy):
837 def __init__(self, **kwargs):
838 super().__init__(**kwargs)
839 self.precision_parameter = 'dt'
840 self.precision_parameter_loc = ['level_params', 'dt']
842 def get_custom_description(self, problem, num_procs, *args, **kwargs):
843 desc = super().get_custom_description(problem, num_procs, *args, **kwargs)
844 desc['level_params']['restol'] = 1e-9
845 if problem.__name__ == "run_quench":
846 desc['problem_params']['newton_tol'] = 1e-9
847 desc['problem_params']['lintol'] = 1e-9
848 desc['level_params']['dt'] = 2.5
849 elif problem.__name__ == "run_AC":
850 desc['level_params']['restol'] = 1e-11
851 desc['level_params']['dt'] = 0.4 * desc['problem_params']['eps'] ** 2 / 8.0
852 elif problem.__name__ == "run_RBC":
853 desc['level_params']['dt'] = 7e-2
854 desc['level_params']['restol'] = 1e-9
855 return desc
857 def get_custom_description_for_faults(self, problem, *args, **kwargs):
858 desc = self.get_custom_description(problem, *args, **kwargs)
859 if problem.__name__ == 'run_quench':
860 desc['level_params']['dt'] = 5.0
861 elif problem.__name__ == 'run_AC':
862 desc['level_params']['dt'] = 5e-4
863 elif problem.__name__ == 'run_RBC':
864 desc['level_params']['restol'] = 1e-6
865 return desc
867 def get_reference_value(self, problem, key, op, num_procs=1):
868 """
869 Get a reference value for a given problem for testing in CI.
871 Args:
872 problem: A function that runs a pySDC problem, see imports for available problems
873 key (str): The name of the variable you want to compare
874 op (function): The operation you want to apply to the data
875 num_procs (int): Number of processes
877 Returns:
878 The reference value
879 """
880 if problem.__name__ == "run_Lorenz":
881 if key == 'work_newton' and op == sum:
882 return 12350
883 elif key == 'e_global_post_run' and op == max:
884 return 1.3527453646133836e-07
886 super().get_reference_value(problem, key, op, num_procs)
889class HotRodStrategy(Strategy):
890 '''
891 Hot Rod as a resilience strategy
892 '''
894 def __init__(self, **kwargs):
895 '''
896 Initialization routine
897 '''
898 kwargs['skip_residual_computation'] = 'all'
899 super().__init__(**kwargs)
900 self.color = list(cmap.values())[3]
901 self.marker = '^'
902 self.name = 'Hot Rod'
903 self.bar_plot_x_label = 'Hot Rod'
904 self.precision_parameter = 'dt'
905 self.precision_parameter_loc = ['level_params', 'dt']
907 def get_custom_description(self, problem, num_procs):
908 '''
909 Routine to get a custom description that adds Hot Rod
911 Args:
912 problem: A function that runs a pySDC problem, see imports for available problems
913 num_procs (int): Number of processes you intend to run with
915 Returns:
916 The custom description you can supply to the problem when running it
917 '''
918 from pySDC.implementations.convergence_controller_classes.hotrod import HotRod
919 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestartingNonMPI
921 base_params = super().get_custom_description(problem, num_procs)
922 if problem.__name__ == "run_vdp":
923 if num_procs == 4:
924 HotRod_tol = 1.800804e-04
925 elif num_procs == 5:
926 HotRod_tol = 9.329361e-05
927 else: # 1 process
928 HotRod_tol = 1.347949e-06
929 HotRod_tol = 7e-6 if num_procs > 1 else 5e-7
930 maxiter = 4
931 elif problem.__name__ == "run_Lorenz":
932 if num_procs == 5:
933 HotRod_tol = 9.539348e-06
934 elif num_procs == 4:
935 HotRod_tol = 3.201e-6
936 else:
937 HotRod_tol = 7.720589e-07
938 maxiter = 6
939 elif problem.__name__ == "run_Schroedinger":
940 if num_procs == 5:
941 HotRod_tol = 2.497697e-06
942 elif num_procs == 4:
943 HotRod_tol = 1.910405e-06
944 else:
945 HotRod_tol = 4.476790e-07
946 maxiter = 6
947 elif problem.__name__ == "run_quench":
948 if num_procs == 5:
949 HotRod_tol = 1.017534e-03
950 elif num_procs == 4:
951 HotRod_tol = 1.017534e-03
952 else:
953 HotRod_tol = 5.198620e-04
954 maxiter = 6
955 elif problem.__name__ == 'run_AC':
956 HotRod_tol = 9.564437e-06
957 maxiter = 6
958 elif problem.__name__ == 'run_RBC':
959 HotRod_tol = 6.34e-6
960 maxiter = 6
961 else:
962 raise NotImplementedError(
963 'I don\'t have a tolerance for Hot Rod for your problem. Please add one to the\
964 strategy'
965 )
967 no_storage = False # num_procs > 1
969 custom_description = {
970 'convergence_controllers': {
971 HotRod: {'HotRod_tol': HotRod_tol, 'no_storage': no_storage},
972 BasicRestartingNonMPI: {
973 'max_restarts': 2,
974 'crash_after_max_restarts': False,
975 'restart_from_first_step': True,
976 },
977 },
978 'step_params': {'maxiter': maxiter},
979 'level_params': {},
980 }
981 if problem.__name__ == "run_AC":
982 custom_description['level_params']['dt'] = 8e-5
983 return merge_descriptions(base_params, custom_description)
985 def get_custom_description_for_faults(self, problem, *args, **kwargs):
986 desc = self.get_custom_description(problem, *args, **kwargs)
987 if problem.__name__ == "run_quench":
988 desc['level_params']['dt'] = 5.0
989 return desc
991 def get_reference_value(self, problem, key, op, num_procs=1):
992 """
993 Get a reference value for a given problem for testing in CI.
995 Args:
996 problem: A function that runs a pySDC problem, see imports for available problems
997 key (str): The name of the variable you want to compare
998 op (function): The operation you want to apply to the data
999 num_procs (int): Number of processes
1001 Returns:
1002 The reference value
1003 """
1004 if problem.__name__ == "run_Lorenz":
1005 if key == 'work_newton' and op == sum:
1006 return 12350
1007 elif key == 'e_global_post_run' and op == max:
1008 return 1.3527453646133836e-07
1010 super().get_reference_value(problem, key, op, num_procs)
1013class AdaptivityCollocationStrategy(InexactBaseStrategy):
1014 '''
1015 Adaptivity based on collocation as a resilience strategy
1016 '''
1018 def __init__(self, **kwargs):
1019 '''
1020 Initialization routine
1021 '''
1022 kwargs = {
1023 'skip_residual_computation': 'most',
1024 **kwargs,
1025 }
1027 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityCollocation
1029 self.restol = None
1030 super().__init__(**kwargs)
1031 self.color = list(cmap.values())[1]
1032 self.marker = '*'
1033 self.name = 'adaptivity_coll'
1034 self.bar_plot_x_label = 'adaptivity collocation'
1035 self.precision_parameter = 'e_tol'
1036 self.adaptive_coll_params = {}
1037 self.precision_parameter_loc = ['convergence_controllers', AdaptivityCollocation, 'e_tol']
1039 def get_custom_description(self, problem, num_procs):
1040 '''
1041 Routine to get a custom description that adds adaptivity
1043 Args:
1044 problem: A function that runs a pySDC problem, see imports for available problems
1045 num_procs (int): Number of processes you intend to run with
1047 Returns:
1048 The custom descriptions you can supply to the problem when running it
1049 '''
1050 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityCollocation
1052 custom_description = {}
1054 dt_max = np.inf
1055 dt_min = 1e-5
1057 if problem.__name__ == "run_piline":
1058 e_tol = 1e-7
1059 dt_min = 1e-2
1060 elif problem.__name__ == "run_vdp":
1061 e_tol = 2e-5
1062 dt_min = 1e-3
1063 elif problem.__name__ == "run_Lorenz":
1064 e_tol = 2e-5
1065 dt_min = 1e-3
1066 elif problem.__name__ == "run_Schroedinger":
1067 e_tol = 4e-6
1068 dt_min = 1e-3
1069 elif problem.__name__ == "run_quench":
1070 e_tol = 1e-5
1071 dt_min = 1e-3
1072 dt_max = 1e2
1073 elif problem.__name__ == "run_AC":
1074 e_tol = 1e-4
1075 else:
1076 raise NotImplementedError(
1077 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\
1078 strategy'
1079 )
1081 custom_description['convergence_controllers'] = {
1082 AdaptivityCollocation: {
1083 'e_tol': e_tol,
1084 'dt_min': dt_min,
1085 'dt_max': dt_max,
1086 'adaptive_coll_params': self.adaptive_coll_params,
1087 'restol_rel': 1e-2,
1088 }
1089 }
1090 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description)
1093class AdaptivityCollocationTypeStrategy(AdaptivityCollocationStrategy):
1094 def __init__(self, **kwargs):
1095 super().__init__(**kwargs)
1096 self.color = list(cmap.values())[4]
1097 self.marker = '.'
1098 self.adaptive_coll_params = {
1099 'quad_type': ['RADAU-RIGHT', 'GAUSS'],
1100 'do_coll_update': [False, True],
1101 }
1103 @property
1104 def label(self):
1105 return 'adaptivity type'
1107 def get_reference_value(self, problem, key, op, num_procs=1):
1108 """
1109 Get a reference value for a given problem for testing in CI.
1111 Args:
1112 problem: A function that runs a pySDC problem, see imports for available problems
1113 key (str): The name of the variable you want to compare
1114 op (function): The operation you want to apply to the data
1115 num_procs (int): Number of processes
1117 Returns:
1118 The reference value
1119 """
1120 if problem.__name__ == "run_Lorenz":
1121 if key == 'work_newton' and op == sum:
1122 return 1025
1123 elif key == 'e_global_post_run' and op == max:
1124 return 4.266975256683736e-06
1126 super().get_reference_value(problem, key, op, num_procs)
1129class AdaptivityCollocationRefinementStrategy(AdaptivityCollocationStrategy):
1130 def __init__(self, **kwargs):
1131 super().__init__(**kwargs)
1132 self.color = list(cmap.values())[5]
1133 self.marker = '^'
1134 self.adaptive_coll_params = {
1135 'num_nodes': [2, 3],
1136 'quad_type': ['GAUSS', 'RADAU-RIGHT'],
1137 'do_coll_update': [True, False],
1138 }
1140 @property
1141 def label(self):
1142 return 'adaptivity refinement'
1144 def get_reference_value(self, problem, key, op, num_procs=1):
1145 """
1146 Get a reference value for a given problem for testing in CI.
1148 Args:
1149 problem: A function that runs a pySDC problem, see imports for available problems
1150 key (str): The name of the variable you want to compare
1151 op (function): The operation you want to apply to the data
1152 num_procs (int): Number of processes
1154 Returns:
1155 The reference value
1156 """
1157 if problem.__name__ == "run_Lorenz":
1158 if key == 'work_newton' and op == sum:
1159 return 917
1160 elif key == 'e_global_post_run' and op == max:
1161 return 1.0874929465387595e-05
1163 super().get_reference_value(problem, key, op, num_procs)
1166class AdaptivityCollocationDerefinementStrategy(AdaptivityCollocationStrategy):
1167 def __init__(self, **kwargs):
1168 super().__init__(**kwargs)
1169 self.color = list(cmap.values())[6]
1170 self.marker = '^'
1171 self.adaptive_coll_params = {'num_nodes': [4, 3]}
1173 @property
1174 def label(self):
1175 return 'adaptivity de-refinement'
1177 def get_reference_value(self, problem, key, op, num_procs=1):
1178 """
1179 Get a reference value for a given problem for testing in CI.
1181 Args:
1182 problem: A function that runs a pySDC problem, see imports for available problems
1183 key (str): The name of the variable you want to compare
1184 op (function): The operation you want to apply to the data
1185 num_procs (int): Number of processes
1187 Returns:
1188 The reference value
1189 """
1190 if problem.__name__ == 'run_Lorenz':
1191 if key == 'work_newton' and op == sum:
1192 return 1338
1193 elif key == 'e_global_post_run' and op == max:
1194 return 0.0001013999955041811
1196 super().get_reference_value(problem, key, op, num_procs)
1199class DIRKStrategy(AdaptivityStrategy):
1200 '''
1201 DIRK4(3)
1202 '''
1204 def __init__(self, **kwargs):
1205 '''
1206 Initialization routine
1207 '''
1208 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK
1210 super().__init__(**kwargs)
1211 self.color = list(cmap.values())[7]
1212 self.marker = '^'
1213 self.name = 'DIRK'
1214 self.bar_plot_x_label = 'DIRK4(3)'
1215 self.precision_parameter = 'e_tol'
1216 self.precision_parameter_loc = ['convergence_controllers', AdaptivityRK, 'e_tol']
1217 self.max_steps = 1e5
1219 @property
1220 def label(self):
1221 return 'DIRK4(3)'
1223 def get_custom_description(self, problem, num_procs):
1224 '''
1225 Routine to get a custom description that adds adaptivity
1227 Args:
1228 problem: A function that runs a pySDC problem, see imports for available problems
1229 num_procs (int): Number of processes you intend to run with
1231 Returns:
1232 The custom descriptions you can supply to the problem when running it
1233 '''
1234 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK, Adaptivity
1235 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1236 from pySDC.implementations.sweeper_classes.Runge_Kutta import DIRK43
1238 adaptivity_description = super().get_custom_description(problem, num_procs)
1240 e_tol = adaptivity_description['convergence_controllers'][Adaptivity]['e_tol']
1241 adaptivity_description['convergence_controllers'].pop(Adaptivity, None)
1242 adaptivity_description.pop('sweeper_params', None)
1244 rk_params = {
1245 'step_params': {'maxiter': 1},
1246 'sweeper_class': DIRK43,
1247 'convergence_controllers': {
1248 AdaptivityRK: {'e_tol': e_tol},
1249 BasicRestarting.get_implementation(useMPI=self.useMPI): {
1250 'max_restarts': 49,
1251 'crash_after_max_restarts': False,
1252 },
1253 },
1254 }
1256 custom_description = merge_descriptions(adaptivity_description, rk_params)
1258 return custom_description
1260 def get_reference_value(self, problem, key, op, num_procs=1):
1261 """
1262 Get a reference value for a given problem for testing in CI.
1264 Args:
1265 problem: A function that runs a pySDC problem, see imports for available problems
1266 key (str): The name of the variable you want to compare
1267 op (function): The operation you want to apply to the data
1268 num_procs (int): Number of processes
1270 Returns:
1271 The reference value
1272 """
1273 if problem.__name__ == "run_Lorenz":
1274 if key == 'work_newton' and op == sum:
1275 return 5467
1276 elif key == 'e_global_post_run' and op == max:
1277 return 7.049480537091313e-07
1279 super().get_reference_value(problem, key, op, num_procs)
1281 def get_random_params(self, problem, num_procs):
1282 '''
1283 Routine to get parameters for the randomization of faults
1285 Args:
1286 problem: A function that runs a pySDC problem, see imports for available problems
1287 num_procs (int): Number of processes you intend to run with
1289 Returns:
1290 dict: Randomization parameters
1291 '''
1292 rnd_params = super().get_random_params(problem, num_procs)
1293 rnd_params['iteration'] = 1
1294 rnd_params['min_node'] = 5
1296 return rnd_params
1299class ARKStrategy(AdaptivityStrategy):
1300 '''
1301 ARK5(4)
1302 '''
1304 def __init__(self, **kwargs):
1305 '''
1306 Initialization routine
1307 '''
1308 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK
1310 super().__init__(**kwargs)
1311 self.color = list(cmap.values())[7]
1312 self.marker = 'P'
1313 self.name = 'ARK'
1314 self.bar_plot_x_label = 'ARK5(4)'
1315 self.precision_parameter = 'e_tol'
1316 self.precision_parameter_loc = ['convergence_controllers', AdaptivityRK, 'e_tol']
1317 self.max_steps = 1e5
1319 @property
1320 def label(self):
1321 return 'ARK5(4)'
1323 def get_custom_description(self, problem, num_procs):
1324 '''
1325 Routine to get a custom description that adds adaptivity
1327 Args:
1328 problem: A function that runs a pySDC problem, see imports for available problems
1329 num_procs (int): Number of processes you intend to run with
1331 Returns:
1332 The custom descriptions you can supply to the problem when running it
1333 '''
1334 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK, Adaptivity
1335 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeSlopeLimiter
1336 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1337 from pySDC.implementations.sweeper_classes.Runge_Kutta import ARK548L2SA
1339 adaptivity_description = super().get_custom_description(problem, num_procs)
1341 e_tol = adaptivity_description['convergence_controllers'][Adaptivity]['e_tol'] / 20.0
1342 adaptivity_description['convergence_controllers'].pop(Adaptivity, None)
1343 adaptivity_description.pop('sweeper_params', None)
1345 rk_params = {
1346 'step_params': {'maxiter': 1},
1347 'sweeper_class': ARK548L2SA,
1348 'convergence_controllers': {
1349 AdaptivityRK: {'e_tol': e_tol},
1350 BasicRestarting.get_implementation(useMPI=self.useMPI): {
1351 'max_restarts': 49,
1352 'crash_after_max_restarts': False,
1353 },
1354 },
1355 }
1357 if problem.__name__ == "run_RBC":
1358 rk_params['convergence_controllers'][StepSizeSlopeLimiter] = {'dt_rel_min_slope': 0.25}
1360 custom_description = merge_descriptions(adaptivity_description, rk_params)
1362 return custom_description
1364 def get_reference_value(self, problem, key, op, num_procs=1):
1365 """
1366 Get a reference value for a given problem for testing in CI.
1368 Args:
1369 problem: A function that runs a pySDC problem, see imports for available problems
1370 key (str): The name of the variable you want to compare
1371 op (function): The operation you want to apply to the data
1372 num_procs (int): Number of processes
1374 Returns:
1375 The reference value
1376 """
1377 if problem.__name__ == "run_Schroedinger":
1378 if key == 'work_newton' and op == sum:
1379 return 0
1380 elif key == 'e_global_post_run' and op == max:
1381 return 3.1786601531890356e-08
1383 super().get_reference_value(problem, key, op, num_procs)
1386class ESDIRKStrategy(AdaptivityStrategy):
1387 '''
1388 ESDIRK5(3)
1389 '''
1391 def __init__(self, **kwargs):
1392 '''
1393 Initialization routine
1394 '''
1395 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK
1397 super().__init__(**kwargs)
1398 self.color = 'violet'
1399 self.marker = '^'
1400 self.name = 'ESDIRK'
1401 self.bar_plot_x_label = 'ESDIRK5(3)'
1402 self.precision_parameter = 'e_tol'
1403 self.precision_parameter_loc = ['convergence_controllers', AdaptivityRK, 'e_tol']
1404 self.max_steps = 1e5
1406 @property
1407 def label(self):
1408 return 'ESDIRK5(3)'
1410 def get_description_for_tolerance(self, problem, param, **kwargs):
1411 desc = {}
1412 if problem.__name__ == 'run_Schroedinger':
1413 desc['problem_params'] = {'lintol': param}
1414 return desc
1416 def get_custom_description(self, problem, num_procs):
1417 '''
1418 Routine to get a custom description that adds adaptivity
1420 Args:
1421 problem: A function that runs a pySDC problem, see imports for available problems
1422 num_procs (int): Number of processes you intend to run with
1424 Returns:
1425 The custom descriptions you can supply to the problem when running it
1426 '''
1427 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK, Adaptivity
1428 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1429 from pySDC.implementations.sweeper_classes.Runge_Kutta import ESDIRK53
1431 adaptivity_description = super().get_custom_description(problem, num_procs)
1433 e_tol = adaptivity_description['convergence_controllers'][Adaptivity]['e_tol']
1434 adaptivity_description['convergence_controllers'].pop(Adaptivity, None)
1435 adaptivity_description.pop('sweeper_params', None)
1437 mod = 1e1 if problem.__name__ == 'run_quench' else 1.0
1439 rk_params = {
1440 'step_params': {'maxiter': 1},
1441 'sweeper_class': ESDIRK53,
1442 'convergence_controllers': {
1443 AdaptivityRK: {'e_tol': e_tol * mod},
1444 BasicRestarting.get_implementation(useMPI=self.useMPI): {
1445 'max_restarts': 49,
1446 'crash_after_max_restarts': False,
1447 },
1448 },
1449 }
1451 custom_description = merge_descriptions(adaptivity_description, rk_params)
1453 return custom_description
1455 def get_reference_value(self, problem, key, op, num_procs=1):
1456 """
1457 Get a reference value for a given problem for testing in CI.
1459 Args:
1460 problem: A function that runs a pySDC problem, see imports for available problems
1461 key (str): The name of the variable you want to compare
1462 op (function): The operation you want to apply to the data
1463 num_procs (int): Number of processes
1465 Returns:
1466 The reference value
1467 """
1468 if problem.__name__ == "run_Lorenz":
1469 if key == 'work_newton' and op == sum:
1470 return 2963
1471 elif key == 'e_global_post_run' and op == max:
1472 return 4.126039954144289e-09
1474 super().get_reference_value(problem, key, op, num_procs)
1476 def get_random_params(self, problem, num_procs):
1477 '''
1478 Routine to get parameters for the randomization of faults
1480 Args:
1481 problem: A function that runs a pySDC problem, see imports for available problems
1482 num_procs (int): Number of processes you intend to run with
1484 Returns:
1485 dict: Randomization parameters
1486 '''
1487 rnd_params = super().get_random_params(problem, num_procs)
1488 rnd_params['iteration'] = 1
1489 rnd_params['min_node'] = 6
1491 return rnd_params
1494class ERKStrategy(DIRKStrategy):
1495 """
1496 Explicit embedded RK using Cash-Karp's method
1497 """
1499 def __init__(self, **kwargs):
1500 '''
1501 Initialization routine
1502 '''
1503 super().__init__(**kwargs)
1504 self.color = list(cmap.values())[8]
1505 self.marker = 'x'
1506 self.name = 'ERK'
1507 self.bar_plot_x_label = 'ERK5(4)'
1509 def get_description_for_tolerance(self, problem, param, **kwargs):
1510 desc = {}
1511 if problem.__name__ == 'run_Schroedinger':
1512 desc['problem_params'] = {'lintol': param}
1514 return desc
1516 @property
1517 def label(self):
1518 return 'CP5(4)'
1520 def get_random_params(self, problem, num_procs):
1521 '''
1522 Routine to get parameters for the randomization of faults
1524 Args:
1525 problem: A function that runs a pySDC problem, see imports for available problems
1526 num_procs (int): Number of processes you intend to run with
1528 Returns:
1529 dict: Randomization parameters
1530 '''
1531 rnd_params = super().get_random_params(problem, num_procs)
1532 rnd_params['min_node'] = 7
1534 return rnd_params
1536 def get_custom_description(self, problem, num_procs=1):
1537 from pySDC.implementations.sweeper_classes.Runge_Kutta import Cash_Karp
1539 desc = super().get_custom_description(problem, num_procs)
1540 desc['sweeper_class'] = Cash_Karp
1542 if problem.__name__ == "run_AC":
1543 desc['level_params']['dt'] = 2e-5
1544 return desc
1546 def get_reference_value(self, problem, key, op, num_procs=1):
1547 """
1548 Get a reference value for a given problem for testing in CI.
1550 Args:
1551 problem: A function that runs a pySDC problem, see imports for available problems
1552 key (str): The name of the variable you want to compare
1553 op (function): The operation you want to apply to the data
1554 num_procs (int): Number of processes
1556 Returns:
1557 The reference value
1558 """
1559 if problem.__name__ == "run_Lorenz":
1560 if key == 'work_newton' and op == sum:
1561 return 0
1562 elif key == 'e_global_post_run' and op == max:
1563 return 1.509206128957885e-07
1565 super().get_reference_value(problem, key, op, num_procs)
1568class DoubleAdaptivityStrategy(AdaptivityStrategy):
1569 '''
1570 Adaptivity based both on embedded estimate and on residual
1571 '''
1573 def __init__(self, **kwargs):
1574 '''
1575 Initialization routine
1576 '''
1577 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
1579 kwargs['skip_residual_computation'] = 'all'
1580 super().__init__(**kwargs)
1581 self.color = list(cmap.values())[7]
1582 self.marker = '^'
1583 self.name = 'double_adaptivity'
1584 self.bar_plot_x_label = 'double adaptivity'
1585 self.precision_parameter = 'e_tol'
1586 self.precision_parameter_loc = ['convergence_controllers', Adaptivity, 'e_tol']
1587 self.residual_e_tol_ratio = 1.0
1588 self.residual_e_tol_abs = None
1590 @property
1591 def label(self):
1592 return 'double adaptivity'
1594 def get_custom_description(self, problem, num_procs):
1595 '''
1596 Routine to get a custom description that adds adaptivity
1598 Args:
1599 problem: A function that runs a pySDC problem, see imports for available problems
1600 num_procs (int): Number of processes you intend to run with
1602 Returns:
1603 The custom descriptions you can supply to the problem when running it
1604 '''
1605 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityResidual, Adaptivity
1606 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1608 custom_description = super().get_custom_description(problem, num_procs)
1610 if self.residual_e_tol_abs:
1611 e_tol = self.residual_e_tol_abs
1612 else:
1613 e_tol = custom_description['convergence_controllers'][Adaptivity]['e_tol'] * self.residual_e_tol_ratio
1614 custom_description['convergence_controllers'][AdaptivityResidual] = {
1615 'e_tol': e_tol,
1616 'allowed_modifications': ['decrease'],
1617 }
1619 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
1620 'max_restarts': 15
1621 }
1623 return custom_description
1625 def get_reference_value(self, problem, key, op, num_procs=1):
1626 """
1627 Get a reference value for a given problem for testing in CI.
1629 Args:
1630 problem: A function that runs a pySDC problem, see imports for available problems
1631 key (str): The name of the variable you want to compare
1632 op (function): The operation you want to apply to the data
1633 num_procs (int): Number of processes
1635 Returns:
1636 The reference value
1637 """
1638 if problem.__name__ == 'run_Lorenz':
1639 if key == 'work_newton' and op == sum:
1640 return 2989
1641 elif key == 'e_global_post_run' and op == max:
1642 return 5.636763944494305e-08
1644 super().get_reference_value(problem, key, op, num_procs)
1647class AdaptivityAvoidRestartsStrategy(AdaptivityStrategy):
1648 """
1649 Adaptivity with the avoid restarts option
1650 """
1652 @property
1653 def label(self):
1654 return 'adaptivity (avoid restarts)'
1656 def get_custom_description(self, problem, num_procs):
1657 '''
1658 Routine to get a custom description that adds adaptivity
1660 Args:
1661 problem: A function that runs a pySDC problem, see imports for available problems
1662 num_procs (int): Number of processes you intend to run with
1664 Returns:
1665 The custom descriptions you can supply to the problem when running it
1666 '''
1667 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
1668 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1670 custom_description = super().get_custom_description(problem, num_procs)
1672 custom_description['convergence_controllers'][Adaptivity]['avoid_restarts'] = True
1674 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
1675 'max_restarts': 15
1676 }
1678 return custom_description
1680 def get_reference_value(self, problem, key, op, num_procs=1):
1681 """
1682 Get a reference value for a given problem for testing in CI.
1684 Args:
1685 problem: A function that runs a pySDC problem, see imports for available problems
1686 key (str): The name of the variable you want to compare
1687 op (function): The operation you want to apply to the data
1688 num_procs (int): Number of processes
1690 Returns:
1691 The reference value
1692 """
1693 if problem.__name__ == "run_Lorenz":
1694 if key == 'work_newton' and op == sum:
1695 return 2989
1696 elif key == 'e_global_post_run' and op == max:
1697 return 5.636763944494305e-08
1699 super().get_reference_value(problem, key, op, num_procs)
1702class AdaptivityInterpolationStrategy(AdaptivityStrategy):
1703 """
1704 Adaptivity with interpolation between restarts
1705 """
1707 @property
1708 def label(self):
1709 return 'adaptivity+interpolation'
1711 def get_custom_description(self, problem, num_procs):
1712 '''
1713 Routine to get a custom description that adds adaptivity
1715 Args:
1716 problem: A function that runs a pySDC problem, see imports for available problems
1717 num_procs (int): Number of processes you intend to run with
1719 Returns:
1720 The custom descriptions you can supply to the problem when running it
1721 '''
1722 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
1723 from pySDC.implementations.convergence_controller_classes.interpolate_between_restarts import (
1724 InterpolateBetweenRestarts,
1725 )
1726 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1728 custom_description = super().get_custom_description(problem, num_procs)
1730 custom_description['convergence_controllers'][Adaptivity]['avoid_restarts'] = False
1731 custom_description['convergence_controllers'][InterpolateBetweenRestarts] = {}
1733 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
1734 'max_restarts': 15
1735 }
1737 return custom_description
1739 def get_reference_value(self, problem, key, op, num_procs=1):
1740 """
1741 Get a reference value for a given problem for testing in CI.
1743 Args:
1744 problem: A function that runs a pySDC problem, see imports for available problems
1745 key (str): The name of the variable you want to compare
1746 op (function): The operation you want to apply to the data
1747 num_procs (int): Number of processes
1749 Returns:
1750 The reference value
1751 """
1752 if problem.__name__ == "run_Lorenz":
1753 if key == 'work_newton' and op == sum:
1754 return 6659
1755 elif key == 'e_global_post_run' and op == max:
1756 return 2.9780002756552015e-06
1758 super().get_reference_value(problem, key, op, num_procs)
1761class AdaptivityExtrapolationWithinQStrategy(InexactBaseStrategy):
1762 '''
1763 Adaptivity based on extrapolation between collocation nodes as a resilience strategy
1764 '''
1766 def __init__(self, **kwargs):
1767 '''
1768 Initialization routine
1769 '''
1770 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityExtrapolationWithinQ
1772 self.restol = None
1773 super().__init__(**kwargs)
1774 self.color = list(cmap.values())[8]
1775 self.marker = '*'
1776 self.name = 'adaptivity_extraQ'
1777 self.bar_plot_x_label = 'adaptivity Q'
1778 self.precision_parameter = 'e_tol'
1779 self.adaptive_coll_params = {}
1780 self.precision_parameter_loc = ['convergence_controllers', AdaptivityExtrapolationWithinQ, 'e_tol']
1782 def get_custom_description(self, problem, num_procs):
1783 '''
1784 Routine to get a custom description that adds adaptivity
1786 Args:
1787 problem: A function that runs a pySDC problem, see imports for available problems
1788 num_procs (int): Number of processes you intend to run with
1790 Returns:
1791 The custom descriptions you can supply to the problem when running it
1792 '''
1793 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityExtrapolationWithinQ
1795 custom_description = {}
1797 dt_max = np.inf
1798 dt_min = 1e-5
1800 if problem.__name__ == "run_vdp":
1801 e_tol = 2e-5
1802 dt_min = 1e-3
1803 elif problem.__name__ == "run_piline":
1804 e_tol = 1e-7
1805 dt_min = 1e-2
1806 elif problem.__name__ == "run_Lorenz":
1807 e_tol = 2e-5
1808 dt_min = 1e-3
1809 elif problem.__name__ == "run_Schroedinger":
1810 e_tol = 4e-6
1811 dt_min = 1e-3
1812 elif problem.__name__ == "run_quench":
1813 e_tol = 1e-5
1814 dt_min = 1e-3
1815 dt_max = 1e2
1816 elif problem.__name__ == "run_AC":
1817 e_tol = 1e-4
1818 else:
1819 raise NotImplementedError(
1820 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\
1821 strategy'
1822 )
1824 custom_description['convergence_controllers'] = {
1825 AdaptivityExtrapolationWithinQ: {
1826 'e_tol': e_tol,
1827 'dt_min': dt_min,
1828 'dt_max': dt_max,
1829 'restol_rel': 1e-2,
1830 'restart_at_maxiter': True,
1831 }
1832 }
1833 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description)
1835 def get_reference_value(self, problem, key, op, num_procs=1):
1836 """
1837 Get a reference value for a given problem for testing in CI.
1839 Args:
1840 problem: A function that runs a pySDC problem, see imports for available problems
1841 key (str): The name of the variable you want to compare
1842 op (function): The operation you want to apply to the data
1843 num_procs (int): Number of processes
1845 Returns:
1846 The reference value
1847 """
1848 if problem.__name__ == "run_Lorenz":
1849 if key == 'work_newton' and op == sum:
1850 return 2198
1851 elif key == 'e_global_post_run' and op == max:
1852 return 5.412657451131508e-07
1854 super().get_reference_value(problem, key, op, num_procs)
1857class AdaptivityPolynomialError(InexactBaseStrategy):
1858 '''
1859 Adaptivity based on extrapolation between collocation nodes as a resilience strategy
1860 '''
1862 def __init__(self, interpolate_between_restarts=False, use_restol_rel=True, max_slope=4, **kwargs):
1863 '''
1864 Initialization routine
1865 '''
1866 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError
1868 self.restol = None
1869 super().__init__(**kwargs)
1870 self.color = list(cmap.values())[9]
1871 self.marker = '+'
1872 self.name = 'adaptivity-inter'
1873 self.bar_plot_x_label = 'adaptivity Q'
1874 self.precision_parameter = 'e_tol'
1875 self.adaptive_coll_params = {}
1876 self.precision_parameter_loc = ['convergence_controllers', AdaptivityPolynomialError, 'e_tol']
1877 self.interpolate_between_restarts = interpolate_between_restarts
1878 self.use_restol_rel = use_restol_rel
1879 self.max_slope = max_slope
1881 def get_custom_description(self, problem, num_procs):
1882 '''
1883 Routine to get a custom description that adds adaptivity
1885 Args:
1886 problem: A function that runs a pySDC problem, see imports for available problems
1887 num_procs (int): Number of processes you intend to run with
1889 Returns:
1890 The custom descriptions you can supply to the problem when running it
1891 '''
1892 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError
1893 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter
1894 from pySDC.implementations.convergence_controller_classes.check_convergence import CheckConvergence
1896 base_params = super().get_custom_description(problem, num_procs)
1897 custom_description = {}
1899 dt_max = np.inf
1900 restol_rel = 1e-4
1901 restol_min = 1e-12
1902 restol_max = 1e-5
1903 dt_slope_min = 0
1904 dt_min = 0
1905 abort_at_growing_residual = True
1906 level_params = {}
1907 problem_params = {}
1909 if problem.__name__ == "run_vdp":
1910 e_tol = 6e-4
1911 level_params['dt'] = 0.1
1912 restol_rel = 1e-5
1913 restol_min = 1e-12
1914 dt_min = 1e-7
1915 problem_params['newton_tol'] = 1e-14
1916 elif problem.__name__ == "run_piline":
1917 e_tol = 1e-7
1918 elif problem.__name__ == "run_Lorenz":
1919 e_tol = 2e-4
1920 elif problem.__name__ == "run_Schroedinger":
1921 e_tol = 3e-5
1922 elif problem.__name__ == "run_quench":
1923 e_tol = 1e-7
1924 level_params['dt'] = 50.0
1925 restol_min = 1e-11
1926 restol_rel = 1e-1
1927 elif problem.__name__ == "run_AC":
1928 e_tol = 1.0e-4
1929 restol_rel = 1e-3
1930 # dt_max = 0.1 * base_params['problem_params']['eps'] ** 2
1931 elif problem.__name__ == "run_RBC":
1932 e_tol = 5e-3
1933 dt_slope_min = 1.0
1934 abort_at_growing_residual = False
1935 restol_rel = 1e-3
1936 restol_max = 1e-1
1937 restol_min = 5e-7
1938 self.max_slope = 4
1939 else:
1940 raise NotImplementedError(
1941 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\
1942 strategy'
1943 )
1945 custom_description['convergence_controllers'] = {
1946 AdaptivityPolynomialError: {
1947 'e_tol': e_tol,
1948 'restol_rel': restol_rel if self.use_restol_rel else 1e-11,
1949 'restol_min': restol_min if self.use_restol_rel else 1e-12,
1950 'restol_max': restol_max if self.use_restol_rel else 1e-5,
1951 'restart_at_maxiter': True,
1952 'factor_if_not_converged': self.max_slope,
1953 'interpolate_between_restarts': self.interpolate_between_restarts,
1954 'abort_at_growing_residual': abort_at_growing_residual,
1955 },
1956 StepSizeLimiter: {
1957 'dt_max': dt_max,
1958 'dt_slope_max': self.max_slope,
1959 'dt_min': dt_min,
1960 'dt_rel_min_slope': dt_slope_min,
1961 },
1962 }
1963 custom_description['level_params'] = level_params
1964 custom_description['problem_params'] = problem_params
1965 return merge_descriptions(base_params, custom_description)
1967 def get_custom_description_for_faults(self, problem, *args, **kwargs):
1968 desc = self.get_custom_description(problem, *args, **kwargs)
1969 if problem.__name__ == "run_quench":
1970 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError
1972 desc['convergence_controllers'][AdaptivityPolynomialError]['e_tol'] = 1e-7 * 11
1973 desc['level_params']['dt'] = 4.0
1974 elif problem.__name__ == "run_AC":
1975 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError
1977 desc['convergence_controllers'][AdaptivityPolynomialError]['e_tol'] = 1e-3
1978 return desc
1980 def get_random_params(self, problem, num_procs):
1981 '''
1982 Routine to get parameters for the randomization of faults
1984 Args:
1985 problem: A function that runs a pySDC problem, see imports for available problems
1986 num_procs (int): Number of processes you intend to run with
1988 Returns:
1989 dict: Randomization parameters
1990 '''
1992 rnd_params = super().get_random_params(problem, num_procs)
1993 if problem.__name__ == "run_quench":
1994 rnd_params['iteration'] = 1
1995 elif problem.__name__ == 'run_Lorenz':
1996 rnd_params['iteration'] = 4
1997 return rnd_params
1999 def get_reference_value(self, problem, key, op, num_procs=1):
2000 """
2001 Get a reference value for a given problem for testing in CI.
2003 Args:
2004 problem: A function that runs a pySDC problem, see imports for available problems
2005 key (str): The name of the variable you want to compare
2006 op (function): The operation you want to apply to the data
2007 num_procs (int): Number of processes
2009 Returns:
2010 The reference value
2011 """
2012 if problem.__name__ == "run_Lorenz":
2013 if key == 'work_newton' and op == sum:
2014 return 2123
2015 elif key == 'e_global_post_run' and op == max:
2016 return 7.931560830343187e-08
2018 super().get_reference_value(problem, key, op, num_procs)
2020 @property
2021 def label(self):
2022 return r'$\Delta t$-$k$-adaptivity'