Coverage for pySDC/projects/Resilience/strategies.py: 75%
834 statements
« prev ^ index » next coverage.py v7.5.0, created at 2024-04-29 09:02 +0000
« prev ^ index » next coverage.py v7.5.0, created at 2024-04-29 09:02 +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'] = 0.3
131 elif problem.__name__ == "run_AC":
132 args['time'] = 1e-2
134 return args
136 def get_random_params(self, problem, num_procs):
137 '''
138 Routine to get parameters for the randomization of faults
140 Args:
141 problem: A function that runs a pySDC problem, see imports for available problems
142 num_procs (int): Number of processes you intend to run with
144 Returns:
145 dict: Randomization parameters
146 '''
147 base_params = self.get_base_parameters(problem, num_procs)
149 rnd_params = {}
150 rnd_params['iteration'] = base_params['step_params']['maxiter']
151 rnd_params['rank'] = num_procs
153 if problem.__name__ in ['run_Schroedinger', 'run_quench', 'run_AC']:
154 rnd_params['min_node'] = 1
156 if problem.__name__ == "run_quench":
157 rnd_params['iteration'] = 5
158 elif problem.__name__ == 'run_Lorenz':
159 rnd_params['iteration'] = 5
160 return rnd_params
162 @property
163 def style(self):
164 """
165 Get the plotting parameters for the strategy.
166 Supply them to a plotting function using `**`
168 Returns:
169 (dict): The plotting parameters as a dictionary
170 """
171 return {
172 'marker': self.marker,
173 'label': self.label,
174 'color': self.color,
175 'ls': self.linestyle,
176 }
178 @property
179 def label(self):
180 """
181 Get a label for plotting
182 """
183 return self.name
185 @classmethod
186 def get_Tend(cls, problem, num_procs=1):
187 '''
188 Get the final time of runs for fault stats based on the problem
190 Args:
191 problem (function): A problem to run
192 num_procs (int): Number of processes
194 Returns:
195 float: Tend to put into the run
196 '''
197 if problem.__name__ == "run_vdp":
198 return 11.5
199 elif problem.__name__ == "run_piline":
200 return 20.0
201 elif problem.__name__ == "run_Lorenz":
202 return 1.5
203 elif problem.__name__ == "run_Schroedinger":
204 return 1.0
205 elif problem.__name__ == "run_quench":
206 return 500.0
207 elif problem.__name__ == "run_AC":
208 return 0.025
209 else:
210 raise NotImplementedError('I don\'t have a final time for your problem!')
212 def get_base_parameters(self, problem, num_procs=1):
213 '''
214 Get a base parameters for the problems independent of the strategy.
216 Args:
217 problem (function): A problem to run
218 num_procs (int): Number of processes
220 Returns:
221 dict: Custom description
222 '''
223 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter
225 custom_description = {}
226 custom_description['step_params'] = {}
227 custom_description['level_params'] = {}
228 custom_description['problem_params'] = {}
230 if problem.__name__ == "run_vdp":
231 custom_description['step_params'] = {'maxiter': 3}
232 custom_description['problem_params'] = {
233 'u0': np.array([2, 0], dtype=np.float64),
234 'crash_at_maxiter': False,
235 'newton_tol': 1e-11,
236 'stop_at_nan': False,
237 }
238 custom_description['level_params'] = {'dt': 1e-2}
240 elif problem.__name__ == "run_Lorenz":
241 custom_description['step_params'] = {'maxiter': 5}
242 custom_description['level_params'] = {'dt': 1e-2}
243 custom_description['problem_params'] = {'stop_at_nan': False}
244 elif problem.__name__ == "run_Schroedinger":
245 custom_description['step_params'] = {'maxiter': 5}
246 custom_description['level_params'] = {'dt': 1e-2, 'restol': -1}
247 custom_description['problem_params']['nvars'] = (256, 256)
248 elif problem.__name__ == "run_quench":
249 custom_description['level_params'] = {'restol': -1, 'dt': 8.0}
250 custom_description['step_params'] = {'maxiter': 5}
251 custom_description['problem_params'] = {
252 'newton_maxiter': 29,
253 'newton_tol': 1e-7,
254 'nvars': 2**6,
255 'direct_solver': False,
256 'lintol': 1e-8,
257 'liniter': 29,
258 'order': 6,
259 }
260 elif problem.__name__ == "run_AC":
261 eps = 4e-2
262 custom_description['step_params'] = {'maxiter': 5}
263 custom_description['problem_params'] = {
264 'nvars': (128,) * 2,
265 'init_type': 'circle',
266 'eps': eps,
267 'radius': 0.25,
268 'nu': 2,
269 }
270 custom_description['level_params'] = {'restol': -1, 'dt': 0.5 * eps**2}
272 custom_description['convergence_controllers'] = {
273 # StepSizeLimiter: {'dt_min': self.get_Tend(problem=problem, num_procs=num_procs) / self.max_steps}
274 }
276 if self.stop_at_nan:
277 from pySDC.implementations.convergence_controller_classes.crash import StopAtNan
279 custom_description['convergence_controllers'][StopAtNan] = {'thresh': 1e20}
281 from pySDC.implementations.convergence_controller_classes.crash import StopAtMaxRuntime
283 max_runtime = {
284 'run_vdp': 60,
285 'run_Lorenz': 60,
286 'run_Schroedinger': 150,
287 'run_quench': 150,
288 'run_AC': 150,
289 }
291 custom_description['convergence_controllers'][StopAtMaxRuntime] = {
292 'max_runtime': max_runtime.get(problem.__name__, 100)
293 }
294 return custom_description
296 def get_custom_description(self, problem, num_procs=1):
297 '''
298 Get a custom description based on the problem
300 Args:
301 problem (function): A problem to run
302 num_procs (int): Number of processes
304 Returns:
305 dict: Custom description
306 '''
307 custom_description = self.get_base_parameters(problem, num_procs)
308 return merge_descriptions(custom_description, self.custom_description)
310 def get_custom_description_for_faults(self, *args, **kwargs):
311 '''
312 Get a custom description based on the problem to run the fault stuff
314 Returns:
315 dict: Custom description
316 '''
317 return self.get_custom_description(*args, **kwargs)
319 def get_reference_value(self, problem, key, op, num_procs=1):
320 """
321 Get a reference value for a given problem for testing in CI.
323 Args:
324 problem: A function that runs a pySDC problem, see imports for available problems
325 key (str): The name of the variable you want to compare
326 op (function): The operation you want to apply to the data
327 num_procs (int): Number of processes
329 Returns:
330 The reference value
331 """
332 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
335class InexactBaseStrategy(Strategy):
336 """
337 Base class for inexact strategies.
338 """
340 def __init__(
341 self, double_adaptivity=False, newton_inexactness=True, linear_inexactness=True, SDC_maxiter=16, **kwargs
342 ):
343 kwargs = {**kwargs, 'skip_residual_computation': 'most'}
344 super().__init__(**kwargs)
345 self.double_adaptivity = double_adaptivity
346 self.newton_inexactness = newton_inexactness
347 self.linear_inexactness = linear_inexactness
348 self.SDC_maxiter = SDC_maxiter
350 def get_controller_params(self, **kwargs):
351 return {'all_to_done': True}
353 def get_custom_description(self, problem, num_procs=1):
354 from pySDC.implementations.convergence_controller_classes.inexactness import NewtonInexactness
356 preconditioner = 'MIN-SR-NS' if problem.__name__ in ['run_vdp', 'run_Lorenz'] else 'MIN-SR-S'
358 desc = {}
359 desc['sweeper_params'] = {'QI': preconditioner}
360 desc['step_params'] = {'maxiter': self.SDC_maxiter}
361 desc['problem_params'] = {}
362 desc['level_params'] = {'restol': 1e-8, 'residual_type': 'last_abs'}
363 desc['convergence_controllers'] = {}
365 inexactness_params = {
366 'min_tol': 1e-12,
367 'ratio': 1e-2,
368 'max_tol': 1e-4,
369 'use_e_tol': False,
370 'maxiter': 15,
371 }
373 if self.newton_inexactness and problem.__name__ not in ['run_Schroedinger', 'run_AC']:
374 if problem.__name__ == 'run_quench':
375 inexactness_params['ratio'] = 1e-1
376 inexactness_params['min_tol'] = 1e-11
377 inexactness_params['maxiter'] = 5
378 desc['convergence_controllers'][NewtonInexactness] = inexactness_params
380 if problem.__name__ in ['run_vdp']:
381 desc['problem_params']['stop_at_nan'] = False
383 if self.linear_inexactness and problem.__name__ in ['run_quench']:
384 desc['problem_params']['inexact_linear_ratio'] = 1e-1
385 if problem.__name__ in ['run_quench']:
386 desc['problem_params']['direct_solver'] = False
387 desc['problem_params']['liniter'] = 9
388 desc['problem_params']['min_lintol'] = 1e-11
390 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
392 desc['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
393 'max_restarts': 29,
394 'crash_after_max_restarts': True,
395 }
396 return merge_descriptions(super().get_custom_description(problem, num_procs), desc)
399class BaseStrategy(Strategy):
400 '''
401 Do a fixed iteration count
402 '''
404 def __init__(self, skip_residual_computation='all', **kwargs):
405 '''
406 Initialization routine
407 '''
408 super().__init__(skip_residual_computation=skip_residual_computation, **kwargs)
409 self.color = list(cmap.values())[0]
410 self.marker = 'o'
411 self.name = 'base'
412 self.bar_plot_x_label = 'base'
413 self.precision_parameter = 'dt'
414 self.precision_parameter_loc = ['level_params', 'dt']
416 @property
417 def label(self):
418 return r'fixed'
420 def get_custom_description(self, problem, num_procs):
421 desc = super().get_custom_description(problem, num_procs)
422 if problem.__name__ == "run_AC":
423 desc['level_params']['dt'] = 0.8 * desc['problem_params']['eps'] ** 2 / 8.0
424 return desc
426 def get_custom_description_for_faults(self, problem, *args, **kwargs):
427 desc = self.get_custom_description(problem, *args, **kwargs)
428 if problem.__name__ == "run_quench":
429 desc['level_params']['dt'] = 5.0
430 return desc
432 def get_reference_value(self, problem, key, op, num_procs=1):
433 """
434 Get a reference value for a given problem for testing in CI.
436 Args:
437 problem: A function that runs a pySDC problem, see imports for available problems
438 key (str): The name of the variable you want to compare
439 op (function): The operation you want to apply to the data
440 num_procs (int): Number of processes
442 Returns:
443 The reference value
444 """
445 if problem.__name__ == "run_vdp":
446 if key == 'work_newton' and op == sum:
447 return 12453
448 elif key == 'e_global_post_run' and op == max:
449 return 4.3956128381594795e-06
451 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
454class AdaptivityStrategy(Strategy):
455 '''
456 Adaptivity as a resilience strategy
457 '''
459 def __init__(self, **kwargs):
460 '''
461 Initialization routine
462 '''
463 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
465 kwargs['skip_residual_computation'] = 'all'
466 super().__init__(**kwargs)
467 self.color = list(cmap.values())[1]
468 self.marker = '*'
469 self.name = 'adaptivity'
470 self.bar_plot_x_label = 'adaptivity'
471 self.precision_parameter = 'e_tol'
472 self.precision_parameter_loc = ['convergence_controllers', Adaptivity, 'e_tol']
474 @property
475 def label(self):
476 return r'$\Delta t$-adaptivity'
478 def get_fixable_params(self, maxiter, **kwargs):
479 """
480 Here faults occurring in the last iteration cannot be fixed.
482 Args:
483 maxiter (int): Max. iterations until convergence is declared
485 Returns:
486 (list): Contains dictionaries of keyword arguments for `FaultStats.get_mask`
487 """
488 self.fixable += [
489 {
490 'key': 'iteration',
491 'op': 'lt',
492 'val': maxiter,
493 }
494 ]
495 return self.fixable
497 def get_custom_description(self, problem, num_procs):
498 '''
499 Routine to get a custom description that adds adaptivity
501 Args:
502 problem: A function that runs a pySDC problem, see imports for available problems
503 num_procs (int): Number of processes you intend to run with
505 Returns:
506 The custom descriptions you can supply to the problem when running it
507 '''
508 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
509 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter
511 base_params = super().get_custom_description(problem, num_procs)
512 custom_description = {}
513 custom_description['convergence_controllers'] = {}
515 dt_max = np.inf
516 dt_slope_max = np.inf
518 if problem.__name__ == "run_piline":
519 e_tol = 1e-7
520 elif problem.__name__ == "run_vdp":
521 e_tol = 2e-5
522 elif problem.__name__ == "run_Lorenz":
523 e_tol = 2e-5
524 elif problem.__name__ == "run_Schroedinger":
525 e_tol = 4e-7
526 elif problem.__name__ == "run_quench":
527 e_tol = 1e-8
528 custom_description['problem_params'] = {
529 'newton_tol': 1e-10,
530 'lintol': 1e-11,
531 }
533 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
535 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
536 'max_restarts': 99,
537 }
538 elif problem.__name__ == "run_AC":
539 e_tol = 1e-6
540 dt_max = 0.8 * base_params['problem_params']['eps'] ** 2
542 else:
543 raise NotImplementedError(
544 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\
545 strategy'
546 )
548 custom_description['convergence_controllers'][Adaptivity] = {
549 'e_tol': e_tol,
550 'dt_slope_max': dt_slope_max,
551 }
552 custom_description['convergence_controllers'][StepSizeLimiter] = {
553 'dt_max': dt_max,
554 }
555 return merge_descriptions(base_params, custom_description)
557 def get_reference_value(self, problem, key, op, num_procs=1):
558 """
559 Get a reference value for a given problem for testing in CI.
561 Args:
562 problem: A function that runs a pySDC problem, see imports for available problems
563 key (str): The name of the variable you want to compare
564 op (function): The operation you want to apply to the data
565 num_procs (int): Number of processes
567 Returns:
568 The reference value
569 """
570 if problem.__name__ == "run_vdp":
571 if key == 'work_newton' and op == sum:
572 return 3825
573 elif key == 'e_global_post_run' and op == max:
574 return 1.3370376368393444e-05
576 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
578 def get_custom_description_for_faults(self, problem, num_procs, *args, **kwargs):
579 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter
580 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
582 desc = self.get_custom_description(problem, num_procs, *args, **kwargs)
583 if problem.__name__ == "run_quench":
584 desc['level_params']['dt'] = 1.1e1
585 desc['convergence_controllers'][Adaptivity]['e_tol'] = 1e-6
586 return desc
589class AdaptivityRestartFirstStep(AdaptivityStrategy):
590 def __init__(self, **kwargs):
591 super().__init__(**kwargs)
592 self.color = 'teal'
593 self.name = 'adaptivityRestartFirstStep'
595 def get_custom_description(self, problem, num_procs):
596 '''
597 Add the other version of basic restarting.
599 Args:
600 problem: A function that runs a pySDC problem, see imports for available problems
601 num_procs (int): Number of processes you intend to run with
603 Returns:
604 The custom descriptions you can supply to the problem when running it
605 '''
606 custom_description = super().get_custom_description(problem, num_procs)
607 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
609 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
610 'max_restarts': 15,
611 'restart_from_first_step': True,
612 }
613 return custom_description
615 @property
616 def label(self):
617 return f'{super().label} restart from first step'
620class AdaptiveHotRodStrategy(Strategy):
621 '''
622 Adaptivity + Hot Rod as a resilience strategy
623 '''
625 def __init__(self, **kwargs):
626 '''
627 Initialization routine
628 '''
629 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
631 kwargs['skip_residual_computation'] = 'all'
632 super().__init__(**kwargs)
633 self.color = list(cmap.values())[4]
634 self.marker = '.'
635 self.name = 'adaptive Hot Rod'
636 self.bar_plot_x_label = 'adaptive\nHot Rod'
637 self.precision_parameter = 'e_tol'
638 self.precision_parameter_loc = ['convergence_controllers', Adaptivity, 'e_tol']
640 def get_custom_description(self, problem, num_procs):
641 '''
642 Routine to get a custom description that adds adaptivity and Hot Rod
644 Args:
645 problem: A function that runs a pySDC problem, see imports for available problems
646 num_procs (int): Number of processes you intend to run with
648 Returns:
649 The custom description you can supply to the problem when running it
650 '''
651 from pySDC.implementations.convergence_controller_classes.hotrod import HotRod
652 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
654 if problem.__name__ == "run_vdp":
655 e_tol = 3e-7
656 dt_min = 1e-3
657 maxiter = 4
658 HotRod_tol = 2e-6
659 else:
660 raise NotImplementedError(
661 'I don\'t have a tolerance for adaptive Hot Rod for your problem. Please add one \
662to the strategy'
663 )
665 no_storage = num_procs > 1
667 custom_description = {
668 'convergence_controllers': {
669 HotRod: {'HotRod_tol': HotRod_tol, 'no_storage': no_storage},
670 Adaptivity: {'e_tol': e_tol, 'dt_min': dt_min, 'embedded_error_flavor': 'linearized'},
671 },
672 'step_params': {'maxiter': maxiter},
673 }
675 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description)
677 def get_reference_value(self, problem, key, op, num_procs=1):
678 """
679 Get a reference value for a given problem for testing in CI.
681 Args:
682 problem: A function that runs a pySDC problem, see imports for available problems
683 key (str): The name of the variable you want to compare
684 op (function): The operation you want to apply to the data
685 num_procs (int): Number of processes
687 Returns:
688 The reference value
689 """
690 if problem.__name__ == "run_vdp":
691 if key == 'work_newton' and op == sum:
692 return 4466
693 elif key == 'e_global_post_run' and op == max:
694 return 2.1455229857747504e-06
696 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
699class IterateStrategy(Strategy):
700 '''
701 Iterate for as much as you want
702 '''
704 def __init__(self, **kwargs):
705 '''
706 Initialization routine
707 '''
708 kwargs['skip_residual_computation'] = 'most'
709 super().__init__(**kwargs)
710 self.color = list(cmap.values())[2]
711 self.marker = 'v'
712 self.name = 'iterate'
713 self.bar_plot_x_label = 'iterate'
714 self.precision_parameter = 'restol'
715 self.precision_parameter_loc = ['level_params', 'restol']
717 @property
718 def label(self):
719 return r'$k$-adaptivity'
721 def get_custom_description(self, problem, num_procs):
722 '''
723 Routine to get a custom description that allows for adaptive iteration counts
725 Args:
726 problem: A function that runs a pySDC problem, see imports for available problems
727 num_procs (int): Number of processes you intend to run with
729 Returns:
730 The custom description you can supply to the problem when running it
731 '''
732 restol = -1
733 e_tol = -1
735 if problem.__name__ == "run_piline":
736 restol = 2.3e-8
737 elif problem.__name__ == "run_vdp":
738 restol = 9e-7
739 elif problem.__name__ == "run_Lorenz":
740 restol = 16e-7
741 elif problem.__name__ == "run_Schroedinger":
742 restol = 6.5e-7
743 elif problem.__name__ == "run_quench":
744 restol = 1e-7
745 elif problem.__name__ == "run_AC":
746 restol = 1e-11
747 else:
748 raise NotImplementedError(
749 'I don\'t have a residual tolerance for your problem. Please add one to the \
750strategy'
751 )
753 custom_description = {
754 'step_params': {'maxiter': 99},
755 'level_params': {'restol': restol, 'e_tol': e_tol},
756 }
758 if problem.__name__ == "run_quench":
759 custom_description['level_params']['dt'] = 1.0
761 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description)
763 def get_random_params(self, problem, num_procs):
764 '''
765 Routine to get parameters for the randomization of faults
767 Args:
768 problem: A function that runs a pySDC problem, see imports for available problems
769 num_procs (int): Number of processes you intend to run with
771 Returns:
772 dict: Randomization parameters
773 '''
775 rnd_params = super().get_random_params(problem, num_procs)
776 if problem.__name__ == "run_quench":
777 rnd_params['iteration'] = 1
778 return rnd_params
780 def get_reference_value(self, problem, key, op, num_procs=1):
781 """
782 Get a reference value for a given problem for testing in CI.
784 Args:
785 problem: A function that runs a pySDC problem, see imports for available problems
786 key (str): The name of the variable you want to compare
787 op (function): The operation you want to apply to the data
788 num_procs (int): Number of processes
790 Returns:
791 The reference value
792 """
793 if problem.__name__ == "run_vdp":
794 if key == 'work_newton' and op == sum:
795 return 8534
796 elif key == 'e_global_post_run' and op == max:
797 return 0.0005961192269257065
799 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
802class kAdaptivityStrategy(IterateStrategy):
803 def __init__(self, **kwargs):
804 super().__init__(**kwargs)
805 self.precision_parameter = 'dt'
806 self.precision_parameter_loc = ['level_params', 'dt']
808 def get_custom_description(self, problem, num_procs, *args, **kwargs):
809 desc = super().get_custom_description(problem, num_procs, *args, **kwargs)
810 desc['level_params']['restol'] = 1e-9
811 if problem.__name__ == "run_quench":
812 desc['problem_params']['newton_tol'] = 1e-9
813 desc['problem_params']['lintol'] = 1e-9
814 desc['level_params']['dt'] = 2.5
815 elif problem.__name__ == "run_AC":
816 desc['level_params']['restol'] = 1e-11
817 desc['level_params']['dt'] = 0.8 * desc['problem_params']['eps'] ** 2 / 8.0
818 return desc
820 def get_custom_description_for_faults(self, problem, *args, **kwargs):
821 desc = self.get_custom_description(problem, *args, **kwargs)
822 if problem.__name__ == 'run_quench':
823 desc['level_params']['dt'] = 5.0
824 elif problem.__name__ == 'run_AC':
825 desc['level_params']['dt'] = 0.6 * desc['problem_params']['eps'] ** 2
826 return desc
828 def get_reference_value(self, problem, key, op, num_procs=1):
829 """
830 Get a reference value for a given problem for testing in CI.
832 Args:
833 problem: A function that runs a pySDC problem, see imports for available problems
834 key (str): The name of the variable you want to compare
835 op (function): The operation you want to apply to the data
836 num_procs (int): Number of processes
838 Returns:
839 The reference value
840 """
841 if problem.__name__ == "run_vdp":
842 if key == 'work_newton' and op == sum:
843 return 13241
844 elif key == 'e_global_post_run' and op == max:
845 return 1.0505165626284452e-08
847 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
850class HotRodStrategy(Strategy):
851 '''
852 Hot Rod as a resilience strategy
853 '''
855 def __init__(self, **kwargs):
856 '''
857 Initialization routine
858 '''
859 kwargs['skip_residual_computation'] = 'all'
860 super().__init__(**kwargs)
861 self.color = list(cmap.values())[3]
862 self.marker = '^'
863 self.name = 'Hot Rod'
864 self.bar_plot_x_label = 'Hot Rod'
865 self.precision_parameter = 'dt'
866 self.precision_parameter_loc = ['level_params', 'dt']
868 def get_custom_description(self, problem, num_procs):
869 '''
870 Routine to get a custom description that adds Hot Rod
872 Args:
873 problem: A function that runs a pySDC problem, see imports for available problems
874 num_procs (int): Number of processes you intend to run with
876 Returns:
877 The custom description you can supply to the problem when running it
878 '''
879 from pySDC.implementations.convergence_controller_classes.hotrod import HotRod
880 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestartingNonMPI
882 base_params = super().get_custom_description(problem, num_procs)
883 if problem.__name__ == "run_vdp":
884 if num_procs == 4:
885 HotRod_tol = 1.800804e-04
886 elif num_procs == 5:
887 HotRod_tol = 9.329361e-05
888 else: # 1 process
889 HotRod_tol = 1.347949e-06
890 HotRod_tol = 7e-6 if num_procs > 1 else 5e-7
891 maxiter = 4
892 elif problem.__name__ == "run_Lorenz":
893 if num_procs == 5:
894 HotRod_tol = 9.539348e-06
895 elif num_procs == 4:
896 HotRod_tol = 3.201e-6
897 else:
898 HotRod_tol = 7.720589e-07
899 maxiter = 6
900 elif problem.__name__ == "run_Schroedinger":
901 if num_procs == 5:
902 HotRod_tol = 2.497697e-06
903 elif num_procs == 4:
904 HotRod_tol = 1.910405e-06
905 else:
906 HotRod_tol = 4.476790e-07
907 maxiter = 6
908 elif problem.__name__ == "run_quench":
909 if num_procs == 5:
910 HotRod_tol = 1.017534e-03
911 elif num_procs == 4:
912 HotRod_tol = 1.017534e-03
913 else:
914 HotRod_tol = 5.198620e-04
915 maxiter = 6
916 elif problem.__name__ == 'run_AC':
917 HotRod_tol = 9.564437e-06
918 maxiter = 6
919 else:
920 raise NotImplementedError(
921 'I don\'t have a tolerance for Hot Rod for your problem. Please add one to the\
922 strategy'
923 )
925 no_storage = False # num_procs > 1
927 custom_description = {
928 'convergence_controllers': {
929 HotRod: {'HotRod_tol': HotRod_tol, 'no_storage': no_storage},
930 BasicRestartingNonMPI: {
931 'max_restarts': 2,
932 'crash_after_max_restarts': False,
933 'restart_from_first_step': True,
934 },
935 },
936 'step_params': {'maxiter': maxiter},
937 'level_params': {},
938 }
939 if problem.__name__ == "run_AC":
940 custom_description['level_params']['dt'] = 0.8 * base_params['problem_params']['eps'] ** 2 / 8.0
941 return merge_descriptions(base_params, custom_description)
943 def get_custom_description_for_faults(self, problem, *args, **kwargs):
944 desc = self.get_custom_description(problem, *args, **kwargs)
945 if problem.__name__ == "run_quench":
946 desc['level_params']['dt'] = 5.0
947 return desc
949 def get_reference_value(self, problem, key, op, num_procs=1):
950 """
951 Get a reference value for a given problem for testing in CI.
953 Args:
954 problem: A function that runs a pySDC problem, see imports for available problems
955 key (str): The name of the variable you want to compare
956 op (function): The operation you want to apply to the data
957 num_procs (int): Number of processes
959 Returns:
960 The reference value
961 """
962 if problem.__name__ == "run_vdp":
963 if key == 'work_newton' and op == sum:
964 return 15230
965 elif key == 'e_global_post_run' and op == max:
966 return 4.3956128381594795e-06
968 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
971class AdaptivityCollocationStrategy(InexactBaseStrategy):
972 '''
973 Adaptivity based on collocation as a resilience strategy
974 '''
976 def __init__(self, **kwargs):
977 '''
978 Initialization routine
979 '''
980 kwargs = {
981 'skip_residual_computation': 'most',
982 **kwargs,
983 }
985 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityCollocation
987 self.restol = None
988 super().__init__(**kwargs)
989 self.color = list(cmap.values())[1]
990 self.marker = '*'
991 self.name = 'adaptivity_coll'
992 self.bar_plot_x_label = 'adaptivity collocation'
993 self.precision_parameter = 'e_tol'
994 self.adaptive_coll_params = {}
995 self.precision_parameter_loc = ['convergence_controllers', AdaptivityCollocation, 'e_tol']
997 def get_custom_description(self, problem, num_procs):
998 '''
999 Routine to get a custom description that adds adaptivity
1001 Args:
1002 problem: A function that runs a pySDC problem, see imports for available problems
1003 num_procs (int): Number of processes you intend to run with
1005 Returns:
1006 The custom descriptions you can supply to the problem when running it
1007 '''
1008 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityCollocation
1010 custom_description = {}
1012 dt_max = np.inf
1013 dt_min = 1e-5
1015 if problem.__name__ == "run_piline":
1016 e_tol = 1e-7
1017 dt_min = 1e-2
1018 elif problem.__name__ == "run_vdp":
1019 e_tol = 2e-5
1020 dt_min = 1e-3
1021 elif problem.__name__ == "run_Lorenz":
1022 e_tol = 2e-5
1023 dt_min = 1e-3
1024 elif problem.__name__ == "run_Schroedinger":
1025 e_tol = 4e-6
1026 dt_min = 1e-3
1027 elif problem.__name__ == "run_quench":
1028 e_tol = 1e-5
1029 dt_min = 1e-3
1030 dt_max = 1e2
1031 elif problem.__name__ == "run_AC":
1032 e_tol = 1e-4
1033 else:
1034 raise NotImplementedError(
1035 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\
1036 strategy'
1037 )
1039 custom_description['convergence_controllers'] = {
1040 AdaptivityCollocation: {
1041 'e_tol': e_tol,
1042 'dt_min': dt_min,
1043 'dt_max': dt_max,
1044 'adaptive_coll_params': self.adaptive_coll_params,
1045 'restol_rel': 1e-2,
1046 }
1047 }
1048 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description)
1051class AdaptivityCollocationTypeStrategy(AdaptivityCollocationStrategy):
1052 def __init__(self, **kwargs):
1053 super().__init__(**kwargs)
1054 self.color = list(cmap.values())[4]
1055 self.marker = '.'
1056 self.adaptive_coll_params = {
1057 'quad_type': ['RADAU-RIGHT', 'GAUSS'],
1058 'do_coll_update': [False, True],
1059 }
1061 @property
1062 def label(self):
1063 return 'adaptivity type'
1065 def get_reference_value(self, problem, key, op, num_procs=1):
1066 """
1067 Get a reference value for a given problem for testing in CI.
1069 Args:
1070 problem: A function that runs a pySDC problem, see imports for available problems
1071 key (str): The name of the variable you want to compare
1072 op (function): The operation you want to apply to the data
1073 num_procs (int): Number of processes
1075 Returns:
1076 The reference value
1077 """
1078 if problem.__name__ == "run_vdp":
1079 if key == 'work_newton' and op == sum:
1080 return 1954
1081 elif key == 'e_global_post_run' and op == max:
1082 return 1.1341277847964903e-06
1084 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
1087class AdaptivityCollocationRefinementStrategy(AdaptivityCollocationStrategy):
1088 def __init__(self, **kwargs):
1089 super().__init__(**kwargs)
1090 self.color = list(cmap.values())[5]
1091 self.marker = '^'
1092 self.adaptive_coll_params = {
1093 'num_nodes': [2, 3],
1094 'quad_type': ['GAUSS', 'RADAU-RIGHT'],
1095 'do_coll_update': [True, False],
1096 }
1098 @property
1099 def label(self):
1100 return 'adaptivity refinement'
1102 def get_reference_value(self, problem, key, op, num_procs=1):
1103 """
1104 Get a reference value for a given problem for testing in CI.
1106 Args:
1107 problem: A function that runs a pySDC problem, see imports for available problems
1108 key (str): The name of the variable you want to compare
1109 op (function): The operation you want to apply to the data
1110 num_procs (int): Number of processes
1112 Returns:
1113 The reference value
1114 """
1115 if problem.__name__ == "run_vdp":
1116 if key == 'work_newton' and op == sum:
1117 return 1785
1118 elif key == 'e_global_post_run' and op == max:
1119 return 1.2448609458259874e-06
1121 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
1124class AdaptivityCollocationDerefinementStrategy(AdaptivityCollocationStrategy):
1125 def __init__(self, **kwargs):
1126 super().__init__(**kwargs)
1127 self.color = list(cmap.values())[6]
1128 self.marker = '^'
1129 self.adaptive_coll_params = {'num_nodes': [4, 3]}
1131 @property
1132 def label(self):
1133 return 'adaptivity de-refinement'
1135 def get_reference_value(self, problem, key, op, num_procs=1):
1136 """
1137 Get a reference value for a given problem for testing in CI.
1139 Args:
1140 problem: A function that runs a pySDC problem, see imports for available problems
1141 key (str): The name of the variable you want to compare
1142 op (function): The operation you want to apply to the data
1143 num_procs (int): Number of processes
1145 Returns:
1146 The reference value
1147 """
1148 if problem.__name__ == "run_vdp":
1149 if key == 'work_newton' and op == sum:
1150 return 2508
1151 elif key == 'e_global_post_run' and op == max:
1152 return 3.452255036812124e-05
1154 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
1157class DIRKStrategy(AdaptivityStrategy):
1158 '''
1159 DIRK4(3)
1160 '''
1162 def __init__(self, **kwargs):
1163 '''
1164 Initialization routine
1165 '''
1166 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK
1168 super().__init__(**kwargs)
1169 self.color = list(cmap.values())[7]
1170 self.marker = '^'
1171 self.name = 'DIRK'
1172 self.bar_plot_x_label = 'DIRK4(3)'
1173 self.precision_parameter = 'e_tol'
1174 self.precision_parameter_loc = ['convergence_controllers', AdaptivityRK, 'e_tol']
1175 self.max_steps = 1e5
1177 @property
1178 def label(self):
1179 return 'DIRK4(3)'
1181 def get_custom_description(self, problem, num_procs):
1182 '''
1183 Routine to get a custom description that adds adaptivity
1185 Args:
1186 problem: A function that runs a pySDC problem, see imports for available problems
1187 num_procs (int): Number of processes you intend to run with
1189 Returns:
1190 The custom descriptions you can supply to the problem when running it
1191 '''
1192 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK, Adaptivity
1193 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1194 from pySDC.implementations.sweeper_classes.Runge_Kutta import DIRK43
1196 adaptivity_description = super().get_custom_description(problem, num_procs)
1198 e_tol = adaptivity_description['convergence_controllers'][Adaptivity]['e_tol']
1199 adaptivity_description['convergence_controllers'].pop(Adaptivity, None)
1200 adaptivity_description.pop('sweeper_params', None)
1202 rk_params = {
1203 'step_params': {'maxiter': 1},
1204 'sweeper_class': DIRK43,
1205 'convergence_controllers': {
1206 AdaptivityRK: {'e_tol': e_tol},
1207 BasicRestarting.get_implementation(useMPI=self.useMPI): {
1208 'max_restarts': 49,
1209 'crash_after_max_restarts': False,
1210 },
1211 },
1212 }
1214 custom_description = merge_descriptions(adaptivity_description, rk_params)
1216 return custom_description
1218 def get_reference_value(self, problem, key, op, num_procs=1):
1219 """
1220 Get a reference value for a given problem for testing in CI.
1222 Args:
1223 problem: A function that runs a pySDC problem, see imports for available problems
1224 key (str): The name of the variable you want to compare
1225 op (function): The operation you want to apply to the data
1226 num_procs (int): Number of processes
1228 Returns:
1229 The reference value
1230 """
1231 if problem.__name__ == "run_vdp":
1232 if key == 'work_newton' and op == sum:
1233 return 2168
1234 elif key == 'e_global_post_run' and op == max:
1235 return 0.00024166437265116247
1237 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
1239 def get_random_params(self, problem, num_procs):
1240 '''
1241 Routine to get parameters for the randomization of faults
1243 Args:
1244 problem: A function that runs a pySDC problem, see imports for available problems
1245 num_procs (int): Number of processes you intend to run with
1247 Returns:
1248 dict: Randomization parameters
1249 '''
1250 rnd_params = super().get_random_params(problem, num_procs)
1251 rnd_params['iteration'] = 1
1252 rnd_params['min_node'] = 5
1254 return rnd_params
1257class ARKStrategy(AdaptivityStrategy):
1258 '''
1259 ARK5(4)
1260 '''
1262 def __init__(self, **kwargs):
1263 '''
1264 Initialization routine
1265 '''
1266 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK
1268 super().__init__(**kwargs)
1269 self.color = list(cmap.values())[7]
1270 self.marker = 'P'
1271 self.name = 'ARK'
1272 self.bar_plot_x_label = 'ARK5(4)'
1273 self.precision_parameter = 'e_tol'
1274 self.precision_parameter_loc = ['convergence_controllers', AdaptivityRK, 'e_tol']
1275 self.max_steps = 1e5
1277 @property
1278 def label(self):
1279 return 'ARK5(4)'
1281 def get_custom_description(self, problem, num_procs):
1282 '''
1283 Routine to get a custom description that adds adaptivity
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 The custom descriptions you can supply to the problem when running it
1291 '''
1292 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK, Adaptivity
1293 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1294 from pySDC.implementations.sweeper_classes.Runge_Kutta import ARK548L2SA
1296 adaptivity_description = super().get_custom_description(problem, num_procs)
1298 e_tol = adaptivity_description['convergence_controllers'][Adaptivity]['e_tol'] / 20.0
1299 adaptivity_description['convergence_controllers'].pop(Adaptivity, None)
1300 adaptivity_description.pop('sweeper_params', None)
1302 rk_params = {
1303 'step_params': {'maxiter': 1},
1304 'sweeper_class': ARK548L2SA,
1305 'convergence_controllers': {
1306 AdaptivityRK: {'e_tol': e_tol},
1307 BasicRestarting.get_implementation(useMPI=self.useMPI): {
1308 'max_restarts': 49,
1309 'crash_after_max_restarts': False,
1310 },
1311 },
1312 }
1314 custom_description = merge_descriptions(adaptivity_description, rk_params)
1316 return custom_description
1318 def get_reference_value(self, problem, key, op, num_procs=1):
1319 """
1320 Get a reference value for a given problem for testing in CI.
1322 Args:
1323 problem: A function that runs a pySDC problem, see imports for available problems
1324 key (str): The name of the variable you want to compare
1325 op (function): The operation you want to apply to the data
1326 num_procs (int): Number of processes
1328 Returns:
1329 The reference value
1330 """
1331 if problem.__name__ == "run_Schroedinger":
1332 if key == 'work_newton' and op == sum:
1333 return 0
1334 elif key == 'e_global_post_run' and op == max:
1335 return 3.1786601531890356e-08
1337 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
1340class ESDIRKStrategy(AdaptivityStrategy):
1341 '''
1342 ESDIRK5(3)
1343 '''
1345 def __init__(self, **kwargs):
1346 '''
1347 Initialization routine
1348 '''
1349 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK
1351 super().__init__(**kwargs)
1352 self.color = 'violet'
1353 self.marker = '^'
1354 self.name = 'ESDIRK'
1355 self.bar_plot_x_label = 'ESDIRK5(3)'
1356 self.precision_parameter = 'e_tol'
1357 self.precision_parameter_loc = ['convergence_controllers', AdaptivityRK, 'e_tol']
1358 self.max_steps = 1e5
1360 @property
1361 def label(self):
1362 return 'ESDIRK5(3)'
1364 def get_description_for_tolerance(self, problem, param, **kwargs):
1365 desc = {}
1366 if problem.__name__ == 'run_Schroedinger':
1367 desc['problem_params'] = {'lintol': param}
1368 return desc
1370 def get_custom_description(self, problem, num_procs):
1371 '''
1372 Routine to get a custom description that adds adaptivity
1374 Args:
1375 problem: A function that runs a pySDC problem, see imports for available problems
1376 num_procs (int): Number of processes you intend to run with
1378 Returns:
1379 The custom descriptions you can supply to the problem when running it
1380 '''
1381 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK, Adaptivity
1382 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1383 from pySDC.implementations.sweeper_classes.Runge_Kutta import ESDIRK53
1385 adaptivity_description = super().get_custom_description(problem, num_procs)
1387 e_tol = adaptivity_description['convergence_controllers'][Adaptivity]['e_tol']
1388 adaptivity_description['convergence_controllers'].pop(Adaptivity, None)
1389 adaptivity_description.pop('sweeper_params', None)
1391 mod = 1e1 if problem.__name__ == 'run_quench' else 1.0
1393 rk_params = {
1394 'step_params': {'maxiter': 1},
1395 'sweeper_class': ESDIRK53,
1396 'convergence_controllers': {
1397 AdaptivityRK: {'e_tol': e_tol * mod},
1398 BasicRestarting.get_implementation(useMPI=self.useMPI): {
1399 'max_restarts': 49,
1400 'crash_after_max_restarts': False,
1401 },
1402 },
1403 }
1405 custom_description = merge_descriptions(adaptivity_description, rk_params)
1407 return custom_description
1409 def get_reference_value(self, problem, key, op, num_procs=1):
1410 """
1411 Get a reference value for a given problem for testing in CI.
1413 Args:
1414 problem: A function that runs a pySDC problem, see imports for available problems
1415 key (str): The name of the variable you want to compare
1416 op (function): The operation you want to apply to the data
1417 num_procs (int): Number of processes
1419 Returns:
1420 The reference value
1421 """
1422 if problem.__name__ == "run_vdp":
1423 if key == 'work_newton' and op == sum:
1424 return 1562
1425 elif key == 'e_global_post_run' and op == max:
1426 return 3.6982949243591356e-06
1428 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
1430 def get_random_params(self, problem, num_procs):
1431 '''
1432 Routine to get parameters for the randomization of faults
1434 Args:
1435 problem: A function that runs a pySDC problem, see imports for available problems
1436 num_procs (int): Number of processes you intend to run with
1438 Returns:
1439 dict: Randomization parameters
1440 '''
1441 rnd_params = super().get_random_params(problem, num_procs)
1442 rnd_params['iteration'] = 1
1443 rnd_params['min_node'] = 6
1445 return rnd_params
1448class ERKStrategy(DIRKStrategy):
1449 """
1450 Explicit embedded RK using Cash-Karp's method
1451 """
1453 def __init__(self, **kwargs):
1454 '''
1455 Initialization routine
1456 '''
1457 super().__init__(**kwargs)
1458 self.color = list(cmap.values())[8]
1459 self.marker = 'x'
1460 self.name = 'ERK'
1461 self.bar_plot_x_label = 'ERK5(4)'
1463 def get_description_for_tolerance(self, problem, param, **kwargs):
1464 desc = {}
1465 if problem.__name__ == 'run_Schroedinger':
1466 desc['problem_params'] = {'lintol': param}
1468 return desc
1470 @property
1471 def label(self):
1472 return 'CP5(4)'
1474 def get_random_params(self, problem, num_procs):
1475 '''
1476 Routine to get parameters for the randomization of faults
1478 Args:
1479 problem: A function that runs a pySDC problem, see imports for available problems
1480 num_procs (int): Number of processes you intend to run with
1482 Returns:
1483 dict: Randomization parameters
1484 '''
1485 rnd_params = super().get_random_params(problem, num_procs)
1486 rnd_params['min_node'] = 7
1488 return rnd_params
1490 def get_custom_description(self, problem, num_procs=1):
1491 from pySDC.implementations.sweeper_classes.Runge_Kutta import Cash_Karp
1493 desc = super().get_custom_description(problem, num_procs)
1494 desc['sweeper_class'] = Cash_Karp
1496 if problem.__name__ == "run_AC":
1497 desc['level_params']['dt'] = 2e-5
1498 return desc
1500 def get_reference_value(self, problem, key, op, num_procs=1):
1501 """
1502 Get a reference value for a given problem for testing in CI.
1504 Args:
1505 problem: A function that runs a pySDC problem, see imports for available problems
1506 key (str): The name of the variable you want to compare
1507 op (function): The operation you want to apply to the data
1508 num_procs (int): Number of processes
1510 Returns:
1511 The reference value
1512 """
1513 if problem.__name__ == "run_vdp":
1514 if key == 'work_newton' and op == sum:
1515 return 0
1516 elif key == 'e_global_post_run' and op == max:
1517 return 2.0606132165701396e-05
1519 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
1522class DoubleAdaptivityStrategy(AdaptivityStrategy):
1523 '''
1524 Adaptivity based both on embedded estimate and on residual
1525 '''
1527 def __init__(self, **kwargs):
1528 '''
1529 Initialization routine
1530 '''
1531 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
1533 kwargs['skip_residual_computation'] = 'all'
1534 super().__init__(**kwargs)
1535 self.color = list(cmap.values())[7]
1536 self.marker = '^'
1537 self.name = 'double_adaptivity'
1538 self.bar_plot_x_label = 'double adaptivity'
1539 self.precision_parameter = 'e_tol'
1540 self.precision_parameter_loc = ['convergence_controllers', Adaptivity, 'e_tol']
1541 self.residual_e_tol_ratio = 1.0
1542 self.residual_e_tol_abs = None
1544 @property
1545 def label(self):
1546 return 'double adaptivity'
1548 def get_custom_description(self, problem, num_procs):
1549 '''
1550 Routine to get a custom description that adds adaptivity
1552 Args:
1553 problem: A function that runs a pySDC problem, see imports for available problems
1554 num_procs (int): Number of processes you intend to run with
1556 Returns:
1557 The custom descriptions you can supply to the problem when running it
1558 '''
1559 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityResidual, Adaptivity
1560 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1562 custom_description = super().get_custom_description(problem, num_procs)
1564 if self.residual_e_tol_abs:
1565 e_tol = self.residual_e_tol_abs
1566 else:
1567 e_tol = custom_description['convergence_controllers'][Adaptivity]['e_tol'] * self.residual_e_tol_ratio
1568 custom_description['convergence_controllers'][AdaptivityResidual] = {
1569 'e_tol': e_tol,
1570 'allowed_modifications': ['decrease'],
1571 }
1573 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
1574 'max_restarts': 15
1575 }
1577 return custom_description
1579 def get_reference_value(self, problem, key, op, num_procs=1):
1580 """
1581 Get a reference value for a given problem for testing in CI.
1583 Args:
1584 problem: A function that runs a pySDC problem, see imports for available problems
1585 key (str): The name of the variable you want to compare
1586 op (function): The operation you want to apply to the data
1587 num_procs (int): Number of processes
1589 Returns:
1590 The reference value
1591 """
1592 if problem.__name__ == "run_vdp":
1593 if key == 'work_newton' and op == sum:
1594 return 3825
1595 elif key == 'e_global_post_run' and op == max:
1596 return 1.3370376368393444e-05
1598 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
1601class AdaptivityAvoidRestartsStrategy(AdaptivityStrategy):
1602 """
1603 Adaptivity with the avoid restarts option
1604 """
1606 @property
1607 def label(self):
1608 return 'adaptivity (avoid restarts)'
1610 def get_custom_description(self, problem, num_procs):
1611 '''
1612 Routine to get a custom description that adds adaptivity
1614 Args:
1615 problem: A function that runs a pySDC problem, see imports for available problems
1616 num_procs (int): Number of processes you intend to run with
1618 Returns:
1619 The custom descriptions you can supply to the problem when running it
1620 '''
1621 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
1622 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1624 custom_description = super().get_custom_description(problem, num_procs)
1626 custom_description['convergence_controllers'][Adaptivity]['avoid_restarts'] = True
1628 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
1629 'max_restarts': 15
1630 }
1632 return custom_description
1634 def get_reference_value(self, problem, key, op, num_procs=1):
1635 """
1636 Get a reference value for a given problem for testing in CI.
1638 Args:
1639 problem: A function that runs a pySDC problem, see imports for available problems
1640 key (str): The name of the variable you want to compare
1641 op (function): The operation you want to apply to the data
1642 num_procs (int): Number of processes
1644 Returns:
1645 The reference value
1646 """
1647 if problem.__name__ == "run_vdp":
1648 if key == 'work_newton' and op == sum:
1649 return 2955
1650 elif key == 'e_global_post_run' and op == max:
1651 return 5.274015506540053e-07
1653 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
1656class AdaptivityInterpolationStrategy(AdaptivityStrategy):
1657 """
1658 Adaptivity with interpolation between restarts
1659 """
1661 @property
1662 def label(self):
1663 return 'adaptivity+interpolation'
1665 def get_custom_description(self, problem, num_procs):
1666 '''
1667 Routine to get a custom description that adds adaptivity
1669 Args:
1670 problem: A function that runs a pySDC problem, see imports for available problems
1671 num_procs (int): Number of processes you intend to run with
1673 Returns:
1674 The custom descriptions you can supply to the problem when running it
1675 '''
1676 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
1677 from pySDC.implementations.convergence_controller_classes.interpolate_between_restarts import (
1678 InterpolateBetweenRestarts,
1679 )
1680 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1682 custom_description = super().get_custom_description(problem, num_procs)
1684 custom_description['convergence_controllers'][Adaptivity]['avoid_restarts'] = False
1685 custom_description['convergence_controllers'][InterpolateBetweenRestarts] = {}
1687 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
1688 'max_restarts': 15
1689 }
1691 return custom_description
1693 def get_reference_value(self, problem, key, op, num_procs=1):
1694 """
1695 Get a reference value for a given problem for testing in CI.
1697 Args:
1698 problem: A function that runs a pySDC problem, see imports for available problems
1699 key (str): The name of the variable you want to compare
1700 op (function): The operation you want to apply to the data
1701 num_procs (int): Number of processes
1703 Returns:
1704 The reference value
1705 """
1706 if problem.__name__ == "run_vdp":
1707 if key == 'work_newton' and op == sum:
1708 return 6659
1709 elif key == 'e_global_post_run' and op == max:
1710 return 2.9780002756552015e-06
1712 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
1715class AdaptivityExtrapolationWithinQStrategy(InexactBaseStrategy):
1716 '''
1717 Adaptivity based on extrapolation between collocation nodes as a resilience strategy
1718 '''
1720 def __init__(self, **kwargs):
1721 '''
1722 Initialization routine
1723 '''
1724 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityExtrapolationWithinQ
1726 self.restol = None
1727 super().__init__(**kwargs)
1728 self.color = list(cmap.values())[8]
1729 self.marker = '*'
1730 self.name = 'adaptivity_extraQ'
1731 self.bar_plot_x_label = 'adaptivity Q'
1732 self.precision_parameter = 'e_tol'
1733 self.adaptive_coll_params = {}
1734 self.precision_parameter_loc = ['convergence_controllers', AdaptivityExtrapolationWithinQ, 'e_tol']
1736 def get_custom_description(self, problem, num_procs):
1737 '''
1738 Routine to get a custom description that adds adaptivity
1740 Args:
1741 problem: A function that runs a pySDC problem, see imports for available problems
1742 num_procs (int): Number of processes you intend to run with
1744 Returns:
1745 The custom descriptions you can supply to the problem when running it
1746 '''
1747 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityExtrapolationWithinQ
1749 custom_description = {}
1751 dt_max = np.inf
1752 dt_min = 1e-5
1754 if problem.__name__ == "run_vdp":
1755 e_tol = 2e-5
1756 dt_min = 1e-3
1757 elif problem.__name__ == "run_piline":
1758 e_tol = 1e-7
1759 dt_min = 1e-2
1760 elif problem.__name__ == "run_Lorenz":
1761 e_tol = 2e-5
1762 dt_min = 1e-3
1763 elif problem.__name__ == "run_Schroedinger":
1764 e_tol = 4e-6
1765 dt_min = 1e-3
1766 elif problem.__name__ == "run_quench":
1767 e_tol = 1e-5
1768 dt_min = 1e-3
1769 dt_max = 1e2
1770 elif problem.__name__ == "run_AC":
1771 e_tol = 1e-4
1772 else:
1773 raise NotImplementedError(
1774 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\
1775 strategy'
1776 )
1778 custom_description['convergence_controllers'] = {
1779 AdaptivityExtrapolationWithinQ: {
1780 'e_tol': e_tol,
1781 'dt_min': dt_min,
1782 'dt_max': dt_max,
1783 'restol_rel': 1e-2,
1784 'restart_at_maxiter': True,
1785 }
1786 }
1787 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description)
1789 def get_reference_value(self, problem, key, op, num_procs=1):
1790 """
1791 Get a reference value for a given problem for testing in CI.
1793 Args:
1794 problem: A function that runs a pySDC problem, see imports for available problems
1795 key (str): The name of the variable you want to compare
1796 op (function): The operation you want to apply to the data
1797 num_procs (int): Number of processes
1799 Returns:
1800 The reference value
1801 """
1802 if problem.__name__ == "run_vdp":
1803 if key == 'work_newton' and op == sum:
1804 return 2426
1805 elif key == 'e_global_post_run' and op == max:
1806 return 1.7293825160247245e-06
1808 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
1811class AdaptivityPolynomialError(InexactBaseStrategy):
1812 '''
1813 Adaptivity based on extrapolation between collocation nodes as a resilience strategy
1814 '''
1816 def __init__(self, interpolate_between_restarts=False, use_restol_rel=True, **kwargs):
1817 '''
1818 Initialization routine
1819 '''
1820 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError
1822 self.restol = None
1823 super().__init__(**kwargs)
1824 self.color = list(cmap.values())[9]
1825 self.marker = '+'
1826 self.name = 'adaptivity-inter'
1827 self.bar_plot_x_label = 'adaptivity Q'
1828 self.precision_parameter = 'e_tol'
1829 self.adaptive_coll_params = {}
1830 self.precision_parameter_loc = ['convergence_controllers', AdaptivityPolynomialError, 'e_tol']
1831 self.interpolate_between_restarts = interpolate_between_restarts
1832 self.use_restol_rel = use_restol_rel
1834 def get_custom_description(self, problem, num_procs):
1835 '''
1836 Routine to get a custom description that adds adaptivity
1838 Args:
1839 problem: A function that runs a pySDC problem, see imports for available problems
1840 num_procs (int): Number of processes you intend to run with
1842 Returns:
1843 The custom descriptions you can supply to the problem when running it
1844 '''
1845 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError
1846 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter
1848 base_params = super().get_custom_description(problem, num_procs)
1849 custom_description = {}
1851 dt_max = np.inf
1852 max_slope = 4.0
1853 restol_rel = 1e-4
1854 restol_min = 1e-12
1855 level_params = {}
1857 if problem.__name__ == "run_vdp":
1858 e_tol = 6e-4
1859 level_params['dt'] = 0.1
1860 elif problem.__name__ == "run_piline":
1861 e_tol = 1e-7
1862 elif problem.__name__ == "run_Lorenz":
1863 e_tol = 7e-4
1864 elif problem.__name__ == "run_Schroedinger":
1865 e_tol = 3e-5
1866 elif problem.__name__ == "run_quench":
1867 e_tol = 1e-7
1868 level_params['dt'] = 50.0
1869 restol_min = 1e-11
1870 restol_rel = 1e-1
1871 elif problem.__name__ == "run_AC":
1872 e_tol = 1e-4
1873 dt_max = 0.8 * base_params['problem_params']['eps'] ** 2
1874 else:
1875 raise NotImplementedError(
1876 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\
1877 strategy'
1878 )
1880 custom_description['convergence_controllers'] = {
1881 AdaptivityPolynomialError: {
1882 'e_tol': e_tol,
1883 'restol_rel': restol_rel if self.use_restol_rel else 1e-11,
1884 'restol_min': restol_min if self.use_restol_rel else 1e-12,
1885 'restart_at_maxiter': True,
1886 'factor_if_not_converged': max_slope,
1887 'interpolate_between_restarts': self.interpolate_between_restarts,
1888 },
1889 StepSizeLimiter: {
1890 'dt_max': dt_max,
1891 'dt_slope_max': max_slope,
1892 },
1893 }
1894 custom_description['level_params'] = level_params
1895 return merge_descriptions(base_params, custom_description)
1897 def get_custom_description_for_faults(self, problem, *args, **kwargs):
1898 desc = self.get_custom_description(problem, *args, **kwargs)
1899 if problem.__name__ == "run_quench":
1900 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError
1902 desc['convergence_controllers'][AdaptivityPolynomialError]['e_tol'] = 1e-7 * 11
1903 desc['level_params']['dt'] = 4.0
1904 elif problem.__name__ == "run_AC":
1905 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError
1907 desc['convergence_controllers'][AdaptivityPolynomialError]['e_tol'] = 1e-3
1908 return desc
1910 def get_random_params(self, problem, num_procs):
1911 '''
1912 Routine to get parameters for the randomization of faults
1914 Args:
1915 problem: A function that runs a pySDC problem, see imports for available problems
1916 num_procs (int): Number of processes you intend to run with
1918 Returns:
1919 dict: Randomization parameters
1920 '''
1922 rnd_params = super().get_random_params(problem, num_procs)
1923 if problem.__name__ == "run_quench":
1924 rnd_params['iteration'] = 1
1925 elif problem.__name__ == 'run_Lorenz':
1926 rnd_params['iteration'] = 4
1927 return rnd_params
1929 def get_reference_value(self, problem, key, op, num_procs=1):
1930 """
1931 Get a reference value for a given problem for testing in CI.
1933 Args:
1934 problem: A function that runs a pySDC problem, see imports for available problems
1935 key (str): The name of the variable you want to compare
1936 op (function): The operation you want to apply to the data
1937 num_procs (int): Number of processes
1939 Returns:
1940 The reference value
1941 """
1942 if problem.__name__ == "run_vdp":
1943 if key == 'work_newton' and op == sum:
1944 return 2819
1945 elif key == 'e_global_post_run' and op == max:
1946 return 1.8147451097405565e-07
1948 raise NotImplementedError('The reference value you are looking for is not implemented for this strategy!')
1950 @property
1951 def label(self):
1952 return r'$\Delta t$-$k$-adaptivity'