Coverage for pySDC/projects/Resilience/strategies.py: 72%
867 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-09 14:59 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-09 14:59 +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 20 # 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([1.1, 0], dtype=np.float64),
234 'mu': 1000,
235 'crash_at_maxiter': False,
236 'newton_tol': 1e-11,
237 'stop_at_nan': False,
238 }
239 custom_description['level_params'] = {'dt': 1e-4}
241 elif problem.__name__ == "run_Lorenz":
242 custom_description['step_params'] = {'maxiter': 5}
243 custom_description['level_params'] = {'dt': 1e-2}
244 custom_description['problem_params'] = {'stop_at_nan': False}
245 elif problem.__name__ == "run_Schroedinger":
246 custom_description['step_params'] = {'maxiter': 5}
247 custom_description['level_params'] = {'dt': 1e-2, 'restol': -1}
248 custom_description['problem_params']['nvars'] = (256, 256)
249 elif problem.__name__ == "run_quench":
250 custom_description['level_params'] = {'restol': -1, 'dt': 8.0}
251 custom_description['step_params'] = {'maxiter': 5}
252 custom_description['problem_params'] = {
253 'newton_maxiter': 29,
254 'newton_tol': 1e-7,
255 'nvars': 2**6,
256 'direct_solver': False,
257 'lintol': 1e-8,
258 'liniter': 29,
259 'order': 6,
260 }
261 elif problem.__name__ == "run_AC":
262 eps = 4e-2
263 custom_description['step_params'] = {'maxiter': 5}
264 custom_description['problem_params'] = {
265 'nvars': (128,) * 2,
266 'init_type': 'circle',
267 'eps': eps,
268 'radius': 0.25,
269 'nu': 2,
270 }
271 custom_description['level_params'] = {'restol': -1, 'dt': 0.1 * eps**2}
273 custom_description['convergence_controllers'] = {
274 # StepSizeLimiter: {'dt_min': self.get_Tend(problem=problem, num_procs=num_procs) / self.max_steps}
275 }
277 if self.stop_at_nan:
278 from pySDC.implementations.convergence_controller_classes.crash import StopAtNan
280 custom_description['convergence_controllers'][StopAtNan] = {'thresh': 1e20}
282 from pySDC.implementations.convergence_controller_classes.crash import StopAtMaxRuntime
284 max_runtime = {
285 'run_vdp': 1000,
286 'run_Lorenz': 60,
287 'run_Schroedinger': 150,
288 'run_quench': 150,
289 'run_AC': 150,
290 }
292 custom_description['convergence_controllers'][StopAtMaxRuntime] = {
293 'max_runtime': max_runtime.get(problem.__name__, 100)
294 }
295 return custom_description
297 def get_custom_description(self, problem, num_procs=1):
298 '''
299 Get a custom description based on the problem
301 Args:
302 problem (function): A problem to run
303 num_procs (int): Number of processes
305 Returns:
306 dict: Custom description
307 '''
308 custom_description = self.get_base_parameters(problem, num_procs)
309 return merge_descriptions(custom_description, self.custom_description)
311 def get_custom_description_for_faults(self, *args, **kwargs):
312 '''
313 Get a custom description based on the problem to run the fault stuff
315 Returns:
316 dict: Custom description
317 '''
318 return self.get_custom_description(*args, **kwargs)
320 def get_reference_value(self, problem, key, op, num_procs=1):
321 """
322 Get a reference value for a given problem for testing in CI.
324 Args:
325 problem: A function that runs a pySDC problem, see imports for available problems
326 key (str): The name of the variable you want to compare
327 op (function): The operation you want to apply to the data
328 num_procs (int): Number of processes
330 Returns:
331 The reference value
332 """
333 raise NotImplementedError(
334 f'The reference value you are looking for is not implemented for {type(self).__name__} strategy!'
335 )
338class InexactBaseStrategy(Strategy):
339 """
340 Base class for inexact strategies.
341 """
343 def __init__(
344 self, double_adaptivity=False, newton_inexactness=True, linear_inexactness=True, SDC_maxiter=16, **kwargs
345 ):
346 kwargs = {**kwargs, 'skip_residual_computation': 'most'}
347 super().__init__(**kwargs)
348 self.double_adaptivity = double_adaptivity
349 self.newton_inexactness = newton_inexactness
350 self.linear_inexactness = linear_inexactness
351 self.SDC_maxiter = SDC_maxiter
353 def get_controller_params(self, **kwargs):
354 return {'all_to_done': True}
356 def get_custom_description(self, problem, num_procs=1):
357 from pySDC.implementations.convergence_controller_classes.inexactness import NewtonInexactness
359 preconditioner = 'MIN-SR-NS' if problem.__name__ in ['run_Lorenz'] else 'MIN-SR-S'
361 desc = {}
362 desc['sweeper_params'] = {'QI': preconditioner}
363 desc['step_params'] = {'maxiter': self.SDC_maxiter}
364 desc['problem_params'] = {}
365 desc['level_params'] = {'restol': 1e-8, 'residual_type': 'last_abs'}
366 desc['convergence_controllers'] = {}
368 inexactness_params = {
369 'min_tol': 1e-12,
370 'ratio': 1e-2,
371 'max_tol': 1e-4,
372 'use_e_tol': False,
373 'maxiter': 15,
374 }
376 if self.newton_inexactness and problem.__name__ not in ['run_Schroedinger', 'run_AC']:
377 if problem.__name__ == 'run_quench':
378 inexactness_params['ratio'] = 1e-1
379 inexactness_params['min_tol'] = 1e-11
380 inexactness_params['maxiter'] = 5
381 elif problem.__name__ == "run_vdp":
382 inexactness_params['ratio'] = 1e-5
383 inexactness_params['min_tol'] = 1e-15
384 inexactness_params['maxiter'] = 9
385 desc['convergence_controllers'][NewtonInexactness] = inexactness_params
387 if problem.__name__ in ['run_vdp']:
388 desc['problem_params']['stop_at_nan'] = False
390 if self.linear_inexactness and problem.__name__ in ['run_quench']:
391 desc['problem_params']['inexact_linear_ratio'] = 1e-1
392 if problem.__name__ in ['run_quench']:
393 desc['problem_params']['direct_solver'] = False
394 desc['problem_params']['liniter'] = 9
395 desc['problem_params']['min_lintol'] = 1e-11
397 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
399 desc['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
400 'max_restarts': 29,
401 'crash_after_max_restarts': True,
402 }
403 return merge_descriptions(super().get_custom_description(problem, num_procs), desc)
406class BaseStrategy(Strategy):
407 '''
408 Do a fixed iteration count
409 '''
411 def __init__(self, skip_residual_computation='all', **kwargs):
412 '''
413 Initialization routine
414 '''
415 super().__init__(skip_residual_computation=skip_residual_computation, **kwargs)
416 self.color = list(cmap.values())[0]
417 self.marker = 'o'
418 self.name = 'base'
419 self.bar_plot_x_label = 'base'
420 self.precision_parameter = 'dt'
421 self.precision_parameter_loc = ['level_params', 'dt']
423 @property
424 def label(self):
425 return r'fixed'
427 def get_custom_description(self, problem, num_procs):
428 desc = super().get_custom_description(problem, num_procs)
429 if problem.__name__ == "run_AC":
430 desc['level_params']['dt'] = 1e-2 * desc['problem_params']['eps'] ** 2
431 return desc
433 def get_custom_description_for_faults(self, problem, *args, **kwargs):
434 desc = self.get_custom_description(problem, *args, **kwargs)
435 if problem.__name__ == "run_quench":
436 desc['level_params']['dt'] = 5.0
437 return desc
439 def get_reference_value(self, problem, key, op, num_procs=1):
440 """
441 Get a reference value for a given problem for testing in CI.
443 Args:
444 problem: A function that runs a pySDC problem, see imports for available problems
445 key (str): The name of the variable you want to compare
446 op (function): The operation you want to apply to the data
447 num_procs (int): Number of processes
449 Returns:
450 The reference value
451 """
452 if problem.__name__ == "run_Lorenz":
453 if key == 'work_newton' and op == sum:
454 return 2136
455 elif key == 'e_global_post_run' and op == max:
456 return 9.256926357892326e-06
458 super().get_reference_value(problem, key, op, num_procs)
461class AdaptivityStrategy(Strategy):
462 '''
463 Adaptivity as a resilience strategy
464 '''
466 def __init__(self, **kwargs):
467 '''
468 Initialization routine
469 '''
470 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
472 kwargs['skip_residual_computation'] = 'all'
473 super().__init__(**kwargs)
474 self.color = list(cmap.values())[1]
475 self.marker = '*'
476 self.name = 'adaptivity'
477 self.bar_plot_x_label = 'adaptivity'
478 self.precision_parameter = 'e_tol'
479 self.precision_parameter_loc = ['convergence_controllers', Adaptivity, 'e_tol']
481 @property
482 def label(self):
483 return r'$\Delta t$-adaptivity'
485 def get_fixable_params(self, maxiter, **kwargs):
486 """
487 Here faults occurring in the last iteration cannot be fixed.
489 Args:
490 maxiter (int): Max. iterations until convergence is declared
492 Returns:
493 (list): Contains dictionaries of keyword arguments for `FaultStats.get_mask`
494 """
495 self.fixable += [
496 {
497 'key': 'iteration',
498 'op': 'lt',
499 'val': maxiter,
500 }
501 ]
502 return self.fixable
504 def get_custom_description(self, problem, num_procs):
505 '''
506 Routine to get a custom description that adds adaptivity
508 Args:
509 problem: A function that runs a pySDC problem, see imports for available problems
510 num_procs (int): Number of processes you intend to run with
512 Returns:
513 The custom descriptions you can supply to the problem when running it
514 '''
515 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
516 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter
518 base_params = super().get_custom_description(problem, num_procs)
519 custom_description = {}
520 custom_description['convergence_controllers'] = {}
522 dt_max = np.inf
523 dt_slope_max = np.inf
525 if problem.__name__ == "run_piline":
526 e_tol = 1e-7
527 elif problem.__name__ == "run_vdp":
528 e_tol = 2e-5
529 elif problem.__name__ == "run_Lorenz":
530 e_tol = 2e-5
531 elif problem.__name__ == "run_Schroedinger":
532 e_tol = 4e-7
533 elif problem.__name__ == "run_quench":
534 e_tol = 1e-8
535 custom_description['problem_params'] = {
536 'newton_tol': 1e-10,
537 'lintol': 1e-11,
538 }
540 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
542 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
543 'max_restarts': 99,
544 }
545 elif problem.__name__ == "run_AC":
546 e_tol = 1e-7
547 # dt_max = 0.1 * base_params['problem_params']['eps'] ** 2
549 else:
550 raise NotImplementedError(
551 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\
552 strategy'
553 )
555 custom_description['convergence_controllers'][Adaptivity] = {
556 'e_tol': e_tol,
557 'dt_slope_max': dt_slope_max,
558 }
559 custom_description['convergence_controllers'][StepSizeLimiter] = {
560 'dt_max': dt_max,
561 }
562 return merge_descriptions(base_params, custom_description)
564 def get_reference_value(self, problem, key, op, num_procs=1):
565 """
566 Get a reference value for a given problem for testing in CI.
568 Args:
569 problem: A function that runs a pySDC problem, see imports for available problems
570 key (str): The name of the variable you want to compare
571 op (function): The operation you want to apply to the data
572 num_procs (int): Number of processes
574 Returns:
575 The reference value
576 """
577 if problem.__name__ == 'run_Lorenz':
578 if key == 'work_newton' and op == sum:
579 return 1369
580 elif key == 'e_global_post_run' and op == max:
581 return 9.364841517367495e-06
583 super().get_reference_value(problem, key, op, num_procs)
585 def get_custom_description_for_faults(self, problem, num_procs, *args, **kwargs):
586 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter
587 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
589 desc = self.get_custom_description(problem, num_procs, *args, **kwargs)
590 if problem.__name__ == "run_quench":
591 desc['level_params']['dt'] = 1.1e1
592 desc['convergence_controllers'][Adaptivity]['e_tol'] = 1e-6
593 return desc
596class AdaptivityRestartFirstStep(AdaptivityStrategy):
597 def __init__(self, **kwargs):
598 super().__init__(**kwargs)
599 self.color = 'teal'
600 self.name = 'adaptivityRestartFirstStep'
602 def get_custom_description(self, problem, num_procs):
603 '''
604 Add the other version of basic restarting.
606 Args:
607 problem: A function that runs a pySDC problem, see imports for available problems
608 num_procs (int): Number of processes you intend to run with
610 Returns:
611 The custom descriptions you can supply to the problem when running it
612 '''
613 custom_description = super().get_custom_description(problem, num_procs)
614 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
616 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
617 'max_restarts': 15,
618 'restart_from_first_step': True,
619 }
620 return custom_description
622 @property
623 def label(self):
624 return f'{super().label} restart from first step'
627class AdaptiveHotRodStrategy(Strategy):
628 '''
629 Adaptivity + Hot Rod as a resilience strategy
630 '''
632 def __init__(self, **kwargs):
633 '''
634 Initialization routine
635 '''
636 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
638 kwargs['skip_residual_computation'] = 'all'
639 super().__init__(**kwargs)
640 self.color = list(cmap.values())[4]
641 self.marker = '.'
642 self.name = 'adaptive Hot Rod'
643 self.bar_plot_x_label = 'adaptive\nHot Rod'
644 self.precision_parameter = 'e_tol'
645 self.precision_parameter_loc = ['convergence_controllers', Adaptivity, 'e_tol']
647 def get_custom_description(self, problem, num_procs):
648 '''
649 Routine to get a custom description that adds adaptivity and Hot Rod
651 Args:
652 problem: A function that runs a pySDC problem, see imports for available problems
653 num_procs (int): Number of processes you intend to run with
655 Returns:
656 The custom description you can supply to the problem when running it
657 '''
658 from pySDC.implementations.convergence_controller_classes.hotrod import HotRod
659 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
661 if problem.__name__ == "run_vdp":
662 e_tol = 3e-7
663 dt_min = 1e-3
664 maxiter = 4
665 HotRod_tol = 2e-6
666 elif problem.__name__ == "run_Lorenz":
667 e_tol = 3e-7
668 dt_min = 1e-3
669 maxiter = 4
670 HotRod_tol = 2e-6
671 else:
672 raise NotImplementedError(
673 'I don\'t have a tolerance for adaptive Hot Rod for your problem. Please add one \
674to the strategy'
675 )
677 no_storage = num_procs > 1
679 custom_description = {
680 'convergence_controllers': {
681 HotRod: {'HotRod_tol': HotRod_tol, 'no_storage': no_storage},
682 Adaptivity: {'e_tol': e_tol, 'dt_min': dt_min, 'embedded_error_flavor': 'linearized'},
683 },
684 'step_params': {'maxiter': maxiter},
685 }
687 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description)
689 def get_reference_value(self, problem, key, op, num_procs=1):
690 """
691 Get a reference value for a given problem for testing in CI.
693 Args:
694 problem: A function that runs a pySDC problem, see imports for available problems
695 key (str): The name of the variable you want to compare
696 op (function): The operation you want to apply to the data
697 num_procs (int): Number of processes
699 Returns:
700 The reference value
701 """
702 if problem.__name__ == "run_Lorenz":
703 if key == 'work_newton' and op == sum:
704 return 4758
705 elif key == 'e_global_post_run' and op == max:
706 return 4.107116318152748e-06
708 super().get_reference_value(problem, key, op, num_procs)
711class IterateStrategy(Strategy):
712 '''
713 Iterate for as much as you want
714 '''
716 def __init__(self, **kwargs):
717 '''
718 Initialization routine
719 '''
720 kwargs['skip_residual_computation'] = 'most'
721 super().__init__(**kwargs)
722 self.color = list(cmap.values())[2]
723 self.marker = 'v'
724 self.name = 'iterate'
725 self.bar_plot_x_label = 'iterate'
726 self.precision_parameter = 'restol'
727 self.precision_parameter_loc = ['level_params', 'restol']
729 @property
730 def label(self):
731 return r'$k$-adaptivity'
733 def get_custom_description(self, problem, num_procs):
734 '''
735 Routine to get a custom description that allows for adaptive iteration counts
737 Args:
738 problem: A function that runs a pySDC problem, see imports for available problems
739 num_procs (int): Number of processes you intend to run with
741 Returns:
742 The custom description you can supply to the problem when running it
743 '''
744 restol = -1
745 e_tol = -1
747 if problem.__name__ == "run_piline":
748 restol = 2.3e-8
749 elif problem.__name__ == "run_vdp":
750 restol = 9e-7
751 elif problem.__name__ == "run_Lorenz":
752 restol = 16e-7
753 elif problem.__name__ == "run_Schroedinger":
754 restol = 6.5e-7
755 elif problem.__name__ == "run_quench":
756 restol = 1e-7
757 elif problem.__name__ == "run_AC":
758 restol = 1e-11
759 else:
760 raise NotImplementedError(
761 'I don\'t have a residual tolerance for your problem. Please add one to the \
762strategy'
763 )
765 custom_description = {
766 'step_params': {'maxiter': 99},
767 'level_params': {'restol': restol, 'e_tol': e_tol},
768 }
770 if problem.__name__ == "run_quench":
771 custom_description['level_params']['dt'] = 1.0
773 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description)
775 def get_random_params(self, problem, num_procs):
776 '''
777 Routine to get parameters for the randomization of faults
779 Args:
780 problem: A function that runs a pySDC problem, see imports for available problems
781 num_procs (int): Number of processes you intend to run with
783 Returns:
784 dict: Randomization parameters
785 '''
787 rnd_params = super().get_random_params(problem, num_procs)
788 if problem.__name__ == "run_quench":
789 rnd_params['iteration'] = 1
790 return rnd_params
792 def get_reference_value(self, problem, key, op, num_procs=1):
793 """
794 Get a reference value for a given problem for testing in CI.
796 Args:
797 problem: A function that runs a pySDC problem, see imports for available problems
798 key (str): The name of the variable you want to compare
799 op (function): The operation you want to apply to the data
800 num_procs (int): Number of processes
802 Returns:
803 The reference value
804 """
805 if problem.__name__ == "run_Lorenz":
806 if key == 'work_newton' and op == sum:
807 return 1872
808 elif key == 'e_global_post_run' and op == max:
809 return 2.2362043480939064e-05
811 super().get_reference_value(problem, key, op, num_procs)
814class kAdaptivityStrategy(IterateStrategy):
815 def __init__(self, **kwargs):
816 super().__init__(**kwargs)
817 self.precision_parameter = 'dt'
818 self.precision_parameter_loc = ['level_params', 'dt']
820 def get_custom_description(self, problem, num_procs, *args, **kwargs):
821 desc = super().get_custom_description(problem, num_procs, *args, **kwargs)
822 desc['level_params']['restol'] = 1e-9
823 if problem.__name__ == "run_quench":
824 desc['problem_params']['newton_tol'] = 1e-9
825 desc['problem_params']['lintol'] = 1e-9
826 desc['level_params']['dt'] = 2.5
827 elif problem.__name__ == "run_AC":
828 desc['level_params']['restol'] = 1e-11
829 desc['level_params']['dt'] = 0.4 * desc['problem_params']['eps'] ** 2 / 8.0
830 return desc
832 def get_custom_description_for_faults(self, problem, *args, **kwargs):
833 desc = self.get_custom_description(problem, *args, **kwargs)
834 if problem.__name__ == 'run_quench':
835 desc['level_params']['dt'] = 5.0
836 elif problem.__name__ == 'run_AC':
837 desc['level_params']['dt'] = 0.6 * desc['problem_params']['eps'] ** 2
838 return desc
840 def get_reference_value(self, problem, key, op, num_procs=1):
841 """
842 Get a reference value for a given problem for testing in CI.
844 Args:
845 problem: A function that runs a pySDC problem, see imports for available problems
846 key (str): The name of the variable you want to compare
847 op (function): The operation you want to apply to the data
848 num_procs (int): Number of processes
850 Returns:
851 The reference value
852 """
853 if problem.__name__ == "run_Lorenz":
854 if key == 'work_newton' and op == sum:
855 return 2392
856 elif key == 'e_global_post_run' and op == max:
857 return 4.808610118089973e-06
859 super().get_reference_value(problem, key, op, num_procs)
862class HotRodStrategy(Strategy):
863 '''
864 Hot Rod as a resilience strategy
865 '''
867 def __init__(self, **kwargs):
868 '''
869 Initialization routine
870 '''
871 kwargs['skip_residual_computation'] = 'all'
872 super().__init__(**kwargs)
873 self.color = list(cmap.values())[3]
874 self.marker = '^'
875 self.name = 'Hot Rod'
876 self.bar_plot_x_label = 'Hot Rod'
877 self.precision_parameter = 'dt'
878 self.precision_parameter_loc = ['level_params', 'dt']
880 def get_custom_description(self, problem, num_procs):
881 '''
882 Routine to get a custom description that adds Hot Rod
884 Args:
885 problem: A function that runs a pySDC problem, see imports for available problems
886 num_procs (int): Number of processes you intend to run with
888 Returns:
889 The custom description you can supply to the problem when running it
890 '''
891 from pySDC.implementations.convergence_controller_classes.hotrod import HotRod
892 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestartingNonMPI
894 base_params = super().get_custom_description(problem, num_procs)
895 if problem.__name__ == "run_vdp":
896 if num_procs == 4:
897 HotRod_tol = 1.800804e-04
898 elif num_procs == 5:
899 HotRod_tol = 9.329361e-05
900 else: # 1 process
901 HotRod_tol = 1.347949e-06
902 HotRod_tol = 7e-6 if num_procs > 1 else 5e-7
903 maxiter = 4
904 elif problem.__name__ == "run_Lorenz":
905 if num_procs == 5:
906 HotRod_tol = 9.539348e-06
907 elif num_procs == 4:
908 HotRod_tol = 3.201e-6
909 else:
910 HotRod_tol = 7.720589e-07
911 maxiter = 6
912 elif problem.__name__ == "run_Schroedinger":
913 if num_procs == 5:
914 HotRod_tol = 2.497697e-06
915 elif num_procs == 4:
916 HotRod_tol = 1.910405e-06
917 else:
918 HotRod_tol = 4.476790e-07
919 maxiter = 6
920 elif problem.__name__ == "run_quench":
921 if num_procs == 5:
922 HotRod_tol = 1.017534e-03
923 elif num_procs == 4:
924 HotRod_tol = 1.017534e-03
925 else:
926 HotRod_tol = 5.198620e-04
927 maxiter = 6
928 elif problem.__name__ == 'run_AC':
929 HotRod_tol = 9.564437e-06
930 maxiter = 6
931 else:
932 raise NotImplementedError(
933 'I don\'t have a tolerance for Hot Rod for your problem. Please add one to the\
934 strategy'
935 )
937 no_storage = False # num_procs > 1
939 custom_description = {
940 'convergence_controllers': {
941 HotRod: {'HotRod_tol': HotRod_tol, 'no_storage': no_storage},
942 BasicRestartingNonMPI: {
943 'max_restarts': 2,
944 'crash_after_max_restarts': False,
945 'restart_from_first_step': True,
946 },
947 },
948 'step_params': {'maxiter': maxiter},
949 'level_params': {},
950 }
951 if problem.__name__ == "run_AC":
952 custom_description['level_params']['dt'] = 0.8 * base_params['problem_params']['eps'] ** 2 / 8.0
953 return merge_descriptions(base_params, custom_description)
955 def get_custom_description_for_faults(self, problem, *args, **kwargs):
956 desc = self.get_custom_description(problem, *args, **kwargs)
957 if problem.__name__ == "run_quench":
958 desc['level_params']['dt'] = 5.0
959 return desc
961 def get_reference_value(self, problem, key, op, num_procs=1):
962 """
963 Get a reference value for a given problem for testing in CI.
965 Args:
966 problem: A function that runs a pySDC problem, see imports for available problems
967 key (str): The name of the variable you want to compare
968 op (function): The operation you want to apply to the data
969 num_procs (int): Number of processes
971 Returns:
972 The reference value
973 """
974 if problem.__name__ == "run_Lorenz":
975 if key == 'work_newton' and op == sum:
976 return 2329
977 elif key == 'e_global_post_run' and op == max:
978 return 9.256926357892326e-06
980 super().get_reference_value(problem, key, op, num_procs)
983class AdaptivityCollocationStrategy(InexactBaseStrategy):
984 '''
985 Adaptivity based on collocation as a resilience strategy
986 '''
988 def __init__(self, **kwargs):
989 '''
990 Initialization routine
991 '''
992 kwargs = {
993 'skip_residual_computation': 'most',
994 **kwargs,
995 }
997 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityCollocation
999 self.restol = None
1000 super().__init__(**kwargs)
1001 self.color = list(cmap.values())[1]
1002 self.marker = '*'
1003 self.name = 'adaptivity_coll'
1004 self.bar_plot_x_label = 'adaptivity collocation'
1005 self.precision_parameter = 'e_tol'
1006 self.adaptive_coll_params = {}
1007 self.precision_parameter_loc = ['convergence_controllers', AdaptivityCollocation, 'e_tol']
1009 def get_custom_description(self, problem, num_procs):
1010 '''
1011 Routine to get a custom description that adds adaptivity
1013 Args:
1014 problem: A function that runs a pySDC problem, see imports for available problems
1015 num_procs (int): Number of processes you intend to run with
1017 Returns:
1018 The custom descriptions you can supply to the problem when running it
1019 '''
1020 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityCollocation
1022 custom_description = {}
1024 dt_max = np.inf
1025 dt_min = 1e-5
1027 if problem.__name__ == "run_piline":
1028 e_tol = 1e-7
1029 dt_min = 1e-2
1030 elif problem.__name__ == "run_vdp":
1031 e_tol = 2e-5
1032 dt_min = 1e-3
1033 elif problem.__name__ == "run_Lorenz":
1034 e_tol = 2e-5
1035 dt_min = 1e-3
1036 elif problem.__name__ == "run_Schroedinger":
1037 e_tol = 4e-6
1038 dt_min = 1e-3
1039 elif problem.__name__ == "run_quench":
1040 e_tol = 1e-5
1041 dt_min = 1e-3
1042 dt_max = 1e2
1043 elif problem.__name__ == "run_AC":
1044 e_tol = 1e-4
1045 else:
1046 raise NotImplementedError(
1047 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\
1048 strategy'
1049 )
1051 custom_description['convergence_controllers'] = {
1052 AdaptivityCollocation: {
1053 'e_tol': e_tol,
1054 'dt_min': dt_min,
1055 'dt_max': dt_max,
1056 'adaptive_coll_params': self.adaptive_coll_params,
1057 'restol_rel': 1e-2,
1058 }
1059 }
1060 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description)
1063class AdaptivityCollocationTypeStrategy(AdaptivityCollocationStrategy):
1064 def __init__(self, **kwargs):
1065 super().__init__(**kwargs)
1066 self.color = list(cmap.values())[4]
1067 self.marker = '.'
1068 self.adaptive_coll_params = {
1069 'quad_type': ['RADAU-RIGHT', 'GAUSS'],
1070 'do_coll_update': [False, True],
1071 }
1073 @property
1074 def label(self):
1075 return 'adaptivity type'
1077 def get_reference_value(self, problem, key, op, num_procs=1):
1078 """
1079 Get a reference value for a given problem for testing in CI.
1081 Args:
1082 problem: A function that runs a pySDC problem, see imports for available problems
1083 key (str): The name of the variable you want to compare
1084 op (function): The operation you want to apply to the data
1085 num_procs (int): Number of processes
1087 Returns:
1088 The reference value
1089 """
1090 if problem.__name__ == "run_Lorenz":
1091 if key == 'work_newton' and op == sum:
1092 return 983
1093 elif key == 'e_global_post_run' and op == max:
1094 return 3.944880392126038e-06
1096 super().get_reference_value(problem, key, op, num_procs)
1099class AdaptivityCollocationRefinementStrategy(AdaptivityCollocationStrategy):
1100 def __init__(self, **kwargs):
1101 super().__init__(**kwargs)
1102 self.color = list(cmap.values())[5]
1103 self.marker = '^'
1104 self.adaptive_coll_params = {
1105 'num_nodes': [2, 3],
1106 'quad_type': ['GAUSS', 'RADAU-RIGHT'],
1107 'do_coll_update': [True, False],
1108 }
1110 @property
1111 def label(self):
1112 return 'adaptivity refinement'
1114 def get_reference_value(self, problem, key, op, num_procs=1):
1115 """
1116 Get a reference value for a given problem for testing in CI.
1118 Args:
1119 problem: A function that runs a pySDC problem, see imports for available problems
1120 key (str): The name of the variable you want to compare
1121 op (function): The operation you want to apply to the data
1122 num_procs (int): Number of processes
1124 Returns:
1125 The reference value
1126 """
1127 if problem.__name__ == "run_Lorenz":
1128 if key == 'work_newton' and op == sum:
1129 return 917
1130 elif key == 'e_global_post_run' and op == max:
1131 return 1.0587702028885815e-05
1133 super().get_reference_value(problem, key, op, num_procs)
1136class AdaptivityCollocationDerefinementStrategy(AdaptivityCollocationStrategy):
1137 def __init__(self, **kwargs):
1138 super().__init__(**kwargs)
1139 self.color = list(cmap.values())[6]
1140 self.marker = '^'
1141 self.adaptive_coll_params = {'num_nodes': [4, 3]}
1143 @property
1144 def label(self):
1145 return 'adaptivity de-refinement'
1147 def get_reference_value(self, problem, key, op, num_procs=1):
1148 """
1149 Get a reference value for a given problem for testing in CI.
1151 Args:
1152 problem: A function that runs a pySDC problem, see imports for available problems
1153 key (str): The name of the variable you want to compare
1154 op (function): The operation you want to apply to the data
1155 num_procs (int): Number of processes
1157 Returns:
1158 The reference value
1159 """
1160 if problem.__name__ == 'run_Lorenz':
1161 if key == 'work_newton' and op == sum:
1162 return 1358
1163 elif key == 'e_global_post_run' and op == max:
1164 return 0.00010316526647002888
1166 super().get_reference_value(problem, key, op, num_procs)
1169class DIRKStrategy(AdaptivityStrategy):
1170 '''
1171 DIRK4(3)
1172 '''
1174 def __init__(self, **kwargs):
1175 '''
1176 Initialization routine
1177 '''
1178 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK
1180 super().__init__(**kwargs)
1181 self.color = list(cmap.values())[7]
1182 self.marker = '^'
1183 self.name = 'DIRK'
1184 self.bar_plot_x_label = 'DIRK4(3)'
1185 self.precision_parameter = 'e_tol'
1186 self.precision_parameter_loc = ['convergence_controllers', AdaptivityRK, 'e_tol']
1187 self.max_steps = 1e5
1189 @property
1190 def label(self):
1191 return 'DIRK4(3)'
1193 def get_custom_description(self, problem, num_procs):
1194 '''
1195 Routine to get a custom description that adds adaptivity
1197 Args:
1198 problem: A function that runs a pySDC problem, see imports for available problems
1199 num_procs (int): Number of processes you intend to run with
1201 Returns:
1202 The custom descriptions you can supply to the problem when running it
1203 '''
1204 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK, Adaptivity
1205 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1206 from pySDC.implementations.sweeper_classes.Runge_Kutta import DIRK43
1208 adaptivity_description = super().get_custom_description(problem, num_procs)
1210 e_tol = adaptivity_description['convergence_controllers'][Adaptivity]['e_tol']
1211 adaptivity_description['convergence_controllers'].pop(Adaptivity, None)
1212 adaptivity_description.pop('sweeper_params', None)
1214 rk_params = {
1215 'step_params': {'maxiter': 1},
1216 'sweeper_class': DIRK43,
1217 'convergence_controllers': {
1218 AdaptivityRK: {'e_tol': e_tol},
1219 BasicRestarting.get_implementation(useMPI=self.useMPI): {
1220 'max_restarts': 49,
1221 'crash_after_max_restarts': False,
1222 },
1223 },
1224 }
1226 custom_description = merge_descriptions(adaptivity_description, rk_params)
1228 return custom_description
1230 def get_reference_value(self, problem, key, op, num_procs=1):
1231 """
1232 Get a reference value for a given problem for testing in CI.
1234 Args:
1235 problem: A function that runs a pySDC problem, see imports for available problems
1236 key (str): The name of the variable you want to compare
1237 op (function): The operation you want to apply to the data
1238 num_procs (int): Number of processes
1240 Returns:
1241 The reference value
1242 """
1243 if problem.__name__ == "run_Lorenz":
1244 if key == 'work_newton' and op == sum:
1245 return 1820
1246 elif key == 'e_global_post_run' and op == max:
1247 return 0.00013730538358736055
1249 super().get_reference_value(problem, key, op, num_procs)
1251 def get_random_params(self, problem, num_procs):
1252 '''
1253 Routine to get parameters for the randomization of faults
1255 Args:
1256 problem: A function that runs a pySDC problem, see imports for available problems
1257 num_procs (int): Number of processes you intend to run with
1259 Returns:
1260 dict: Randomization parameters
1261 '''
1262 rnd_params = super().get_random_params(problem, num_procs)
1263 rnd_params['iteration'] = 1
1264 rnd_params['min_node'] = 5
1266 return rnd_params
1269class ARKStrategy(AdaptivityStrategy):
1270 '''
1271 ARK5(4)
1272 '''
1274 def __init__(self, **kwargs):
1275 '''
1276 Initialization routine
1277 '''
1278 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK
1280 super().__init__(**kwargs)
1281 self.color = list(cmap.values())[7]
1282 self.marker = 'P'
1283 self.name = 'ARK'
1284 self.bar_plot_x_label = 'ARK5(4)'
1285 self.precision_parameter = 'e_tol'
1286 self.precision_parameter_loc = ['convergence_controllers', AdaptivityRK, 'e_tol']
1287 self.max_steps = 1e5
1289 @property
1290 def label(self):
1291 return 'ARK5(4)'
1293 def get_custom_description(self, problem, num_procs):
1294 '''
1295 Routine to get a custom description that adds adaptivity
1297 Args:
1298 problem: A function that runs a pySDC problem, see imports for available problems
1299 num_procs (int): Number of processes you intend to run with
1301 Returns:
1302 The custom descriptions you can supply to the problem when running it
1303 '''
1304 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK, Adaptivity
1305 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1306 from pySDC.implementations.sweeper_classes.Runge_Kutta import ARK548L2SA
1308 adaptivity_description = super().get_custom_description(problem, num_procs)
1310 e_tol = adaptivity_description['convergence_controllers'][Adaptivity]['e_tol'] / 20.0
1311 adaptivity_description['convergence_controllers'].pop(Adaptivity, None)
1312 adaptivity_description.pop('sweeper_params', None)
1314 rk_params = {
1315 'step_params': {'maxiter': 1},
1316 'sweeper_class': ARK548L2SA,
1317 'convergence_controllers': {
1318 AdaptivityRK: {'e_tol': e_tol},
1319 BasicRestarting.get_implementation(useMPI=self.useMPI): {
1320 'max_restarts': 49,
1321 'crash_after_max_restarts': False,
1322 },
1323 },
1324 }
1326 custom_description = merge_descriptions(adaptivity_description, rk_params)
1328 return custom_description
1330 def get_reference_value(self, problem, key, op, num_procs=1):
1331 """
1332 Get a reference value for a given problem for testing in CI.
1334 Args:
1335 problem: A function that runs a pySDC problem, see imports for available problems
1336 key (str): The name of the variable you want to compare
1337 op (function): The operation you want to apply to the data
1338 num_procs (int): Number of processes
1340 Returns:
1341 The reference value
1342 """
1343 if problem.__name__ == "run_Schroedinger":
1344 if key == 'work_newton' and op == sum:
1345 return 0
1346 elif key == 'e_global_post_run' and op == max:
1347 return 3.1786601531890356e-08
1349 super().get_reference_value(problem, key, op, num_procs)
1352class ESDIRKStrategy(AdaptivityStrategy):
1353 '''
1354 ESDIRK5(3)
1355 '''
1357 def __init__(self, **kwargs):
1358 '''
1359 Initialization routine
1360 '''
1361 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK
1363 super().__init__(**kwargs)
1364 self.color = 'violet'
1365 self.marker = '^'
1366 self.name = 'ESDIRK'
1367 self.bar_plot_x_label = 'ESDIRK5(3)'
1368 self.precision_parameter = 'e_tol'
1369 self.precision_parameter_loc = ['convergence_controllers', AdaptivityRK, 'e_tol']
1370 self.max_steps = 1e5
1372 @property
1373 def label(self):
1374 return 'ESDIRK5(3)'
1376 def get_description_for_tolerance(self, problem, param, **kwargs):
1377 desc = {}
1378 if problem.__name__ == 'run_Schroedinger':
1379 desc['problem_params'] = {'lintol': param}
1380 return desc
1382 def get_custom_description(self, problem, num_procs):
1383 '''
1384 Routine to get a custom description that adds adaptivity
1386 Args:
1387 problem: A function that runs a pySDC problem, see imports for available problems
1388 num_procs (int): Number of processes you intend to run with
1390 Returns:
1391 The custom descriptions you can supply to the problem when running it
1392 '''
1393 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK, Adaptivity
1394 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1395 from pySDC.implementations.sweeper_classes.Runge_Kutta import ESDIRK53
1397 adaptivity_description = super().get_custom_description(problem, num_procs)
1399 e_tol = adaptivity_description['convergence_controllers'][Adaptivity]['e_tol']
1400 adaptivity_description['convergence_controllers'].pop(Adaptivity, None)
1401 adaptivity_description.pop('sweeper_params', None)
1403 mod = 1e1 if problem.__name__ == 'run_quench' else 1.0
1405 rk_params = {
1406 'step_params': {'maxiter': 1},
1407 'sweeper_class': ESDIRK53,
1408 'convergence_controllers': {
1409 AdaptivityRK: {'e_tol': e_tol * mod},
1410 BasicRestarting.get_implementation(useMPI=self.useMPI): {
1411 'max_restarts': 49,
1412 'crash_after_max_restarts': False,
1413 },
1414 },
1415 }
1417 custom_description = merge_descriptions(adaptivity_description, rk_params)
1419 return custom_description
1421 def get_reference_value(self, problem, key, op, num_procs=1):
1422 """
1423 Get a reference value for a given problem for testing in CI.
1425 Args:
1426 problem: A function that runs a pySDC problem, see imports for available problems
1427 key (str): The name of the variable you want to compare
1428 op (function): The operation you want to apply to the data
1429 num_procs (int): Number of processes
1431 Returns:
1432 The reference value
1433 """
1434 if problem.__name__ == "run_Lorenz":
1435 if key == 'work_newton' and op == sum:
1436 return 984
1437 elif key == 'e_global_post_run' and op == max:
1438 return 3.148061889390874e-06
1440 super().get_reference_value(problem, key, op, num_procs)
1442 def get_random_params(self, problem, num_procs):
1443 '''
1444 Routine to get parameters for the randomization of faults
1446 Args:
1447 problem: A function that runs a pySDC problem, see imports for available problems
1448 num_procs (int): Number of processes you intend to run with
1450 Returns:
1451 dict: Randomization parameters
1452 '''
1453 rnd_params = super().get_random_params(problem, num_procs)
1454 rnd_params['iteration'] = 1
1455 rnd_params['min_node'] = 6
1457 return rnd_params
1460class ERKStrategy(DIRKStrategy):
1461 """
1462 Explicit embedded RK using Cash-Karp's method
1463 """
1465 def __init__(self, **kwargs):
1466 '''
1467 Initialization routine
1468 '''
1469 super().__init__(**kwargs)
1470 self.color = list(cmap.values())[8]
1471 self.marker = 'x'
1472 self.name = 'ERK'
1473 self.bar_plot_x_label = 'ERK5(4)'
1475 def get_description_for_tolerance(self, problem, param, **kwargs):
1476 desc = {}
1477 if problem.__name__ == 'run_Schroedinger':
1478 desc['problem_params'] = {'lintol': param}
1480 return desc
1482 @property
1483 def label(self):
1484 return 'CP5(4)'
1486 def get_random_params(self, problem, num_procs):
1487 '''
1488 Routine to get parameters for the randomization of faults
1490 Args:
1491 problem: A function that runs a pySDC problem, see imports for available problems
1492 num_procs (int): Number of processes you intend to run with
1494 Returns:
1495 dict: Randomization parameters
1496 '''
1497 rnd_params = super().get_random_params(problem, num_procs)
1498 rnd_params['min_node'] = 7
1500 return rnd_params
1502 def get_custom_description(self, problem, num_procs=1):
1503 from pySDC.implementations.sweeper_classes.Runge_Kutta import Cash_Karp
1505 desc = super().get_custom_description(problem, num_procs)
1506 desc['sweeper_class'] = Cash_Karp
1508 if problem.__name__ == "run_AC":
1509 desc['level_params']['dt'] = 2e-5
1510 return desc
1512 def get_reference_value(self, problem, key, op, num_procs=1):
1513 """
1514 Get a reference value for a given problem for testing in CI.
1516 Args:
1517 problem: A function that runs a pySDC problem, see imports for available problems
1518 key (str): The name of the variable you want to compare
1519 op (function): The operation you want to apply to the data
1520 num_procs (int): Number of processes
1522 Returns:
1523 The reference value
1524 """
1525 if problem.__name__ == "run_Lorenz":
1526 if key == 'work_newton' and op == sum:
1527 return 0
1528 elif key == 'e_global_post_run' and op == max:
1529 return 3.5085474063834e-05
1531 super().get_reference_value(problem, key, op, num_procs)
1534class DoubleAdaptivityStrategy(AdaptivityStrategy):
1535 '''
1536 Adaptivity based both on embedded estimate and on residual
1537 '''
1539 def __init__(self, **kwargs):
1540 '''
1541 Initialization routine
1542 '''
1543 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
1545 kwargs['skip_residual_computation'] = 'all'
1546 super().__init__(**kwargs)
1547 self.color = list(cmap.values())[7]
1548 self.marker = '^'
1549 self.name = 'double_adaptivity'
1550 self.bar_plot_x_label = 'double adaptivity'
1551 self.precision_parameter = 'e_tol'
1552 self.precision_parameter_loc = ['convergence_controllers', Adaptivity, 'e_tol']
1553 self.residual_e_tol_ratio = 1.0
1554 self.residual_e_tol_abs = None
1556 @property
1557 def label(self):
1558 return 'double adaptivity'
1560 def get_custom_description(self, problem, num_procs):
1561 '''
1562 Routine to get a custom description that adds adaptivity
1564 Args:
1565 problem: A function that runs a pySDC problem, see imports for available problems
1566 num_procs (int): Number of processes you intend to run with
1568 Returns:
1569 The custom descriptions you can supply to the problem when running it
1570 '''
1571 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityResidual, Adaptivity
1572 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1574 custom_description = super().get_custom_description(problem, num_procs)
1576 if self.residual_e_tol_abs:
1577 e_tol = self.residual_e_tol_abs
1578 else:
1579 e_tol = custom_description['convergence_controllers'][Adaptivity]['e_tol'] * self.residual_e_tol_ratio
1580 custom_description['convergence_controllers'][AdaptivityResidual] = {
1581 'e_tol': e_tol,
1582 'allowed_modifications': ['decrease'],
1583 }
1585 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
1586 'max_restarts': 15
1587 }
1589 return custom_description
1591 def get_reference_value(self, problem, key, op, num_procs=1):
1592 """
1593 Get a reference value for a given problem for testing in CI.
1595 Args:
1596 problem: A function that runs a pySDC problem, see imports for available problems
1597 key (str): The name of the variable you want to compare
1598 op (function): The operation you want to apply to the data
1599 num_procs (int): Number of processes
1601 Returns:
1602 The reference value
1603 """
1604 if problem.__name__ == 'run_Lorenz':
1605 if key == 'work_newton' and op == sum:
1606 return 1369
1607 elif key == 'e_global_post_run' and op == max:
1608 return 9.364841517367495e-06
1610 super().get_reference_value(problem, key, op, num_procs)
1613class AdaptivityAvoidRestartsStrategy(AdaptivityStrategy):
1614 """
1615 Adaptivity with the avoid restarts option
1616 """
1618 @property
1619 def label(self):
1620 return 'adaptivity (avoid restarts)'
1622 def get_custom_description(self, problem, num_procs):
1623 '''
1624 Routine to get a custom description that adds adaptivity
1626 Args:
1627 problem: A function that runs a pySDC problem, see imports for available problems
1628 num_procs (int): Number of processes you intend to run with
1630 Returns:
1631 The custom descriptions you can supply to the problem when running it
1632 '''
1633 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
1634 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1636 custom_description = super().get_custom_description(problem, num_procs)
1638 custom_description['convergence_controllers'][Adaptivity]['avoid_restarts'] = True
1640 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
1641 'max_restarts': 15
1642 }
1644 return custom_description
1646 def get_reference_value(self, problem, key, op, num_procs=1):
1647 """
1648 Get a reference value for a given problem for testing in CI.
1650 Args:
1651 problem: A function that runs a pySDC problem, see imports for available problems
1652 key (str): The name of the variable you want to compare
1653 op (function): The operation you want to apply to the data
1654 num_procs (int): Number of processes
1656 Returns:
1657 The reference value
1658 """
1659 if problem.__name__ == "run_Lorenz":
1660 if key == 'work_newton' and op == sum:
1661 return 1369
1662 elif key == 'e_global_post_run' and op == max:
1663 return 9.364841517367495e-06
1665 super().get_reference_value(problem, key, op, num_procs)
1668class AdaptivityInterpolationStrategy(AdaptivityStrategy):
1669 """
1670 Adaptivity with interpolation between restarts
1671 """
1673 @property
1674 def label(self):
1675 return 'adaptivity+interpolation'
1677 def get_custom_description(self, problem, num_procs):
1678 '''
1679 Routine to get a custom description that adds adaptivity
1681 Args:
1682 problem: A function that runs a pySDC problem, see imports for available problems
1683 num_procs (int): Number of processes you intend to run with
1685 Returns:
1686 The custom descriptions you can supply to the problem when running it
1687 '''
1688 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
1689 from pySDC.implementations.convergence_controller_classes.interpolate_between_restarts import (
1690 InterpolateBetweenRestarts,
1691 )
1692 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting
1694 custom_description = super().get_custom_description(problem, num_procs)
1696 custom_description['convergence_controllers'][Adaptivity]['avoid_restarts'] = False
1697 custom_description['convergence_controllers'][InterpolateBetweenRestarts] = {}
1699 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = {
1700 'max_restarts': 15
1701 }
1703 return custom_description
1705 def get_reference_value(self, problem, key, op, num_procs=1):
1706 """
1707 Get a reference value for a given problem for testing in CI.
1709 Args:
1710 problem: A function that runs a pySDC problem, see imports for available problems
1711 key (str): The name of the variable you want to compare
1712 op (function): The operation you want to apply to the data
1713 num_procs (int): Number of processes
1715 Returns:
1716 The reference value
1717 """
1718 if problem.__name__ == "run_Lorenz":
1719 if key == 'work_newton' and op == sum:
1720 return 6659
1721 elif key == 'e_global_post_run' and op == max:
1722 return 2.9780002756552015e-06
1724 super().get_reference_value(problem, key, op, num_procs)
1727class AdaptivityExtrapolationWithinQStrategy(InexactBaseStrategy):
1728 '''
1729 Adaptivity based on extrapolation between collocation nodes as a resilience strategy
1730 '''
1732 def __init__(self, **kwargs):
1733 '''
1734 Initialization routine
1735 '''
1736 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityExtrapolationWithinQ
1738 self.restol = None
1739 super().__init__(**kwargs)
1740 self.color = list(cmap.values())[8]
1741 self.marker = '*'
1742 self.name = 'adaptivity_extraQ'
1743 self.bar_plot_x_label = 'adaptivity Q'
1744 self.precision_parameter = 'e_tol'
1745 self.adaptive_coll_params = {}
1746 self.precision_parameter_loc = ['convergence_controllers', AdaptivityExtrapolationWithinQ, 'e_tol']
1748 def get_custom_description(self, problem, num_procs):
1749 '''
1750 Routine to get a custom description that adds adaptivity
1752 Args:
1753 problem: A function that runs a pySDC problem, see imports for available problems
1754 num_procs (int): Number of processes you intend to run with
1756 Returns:
1757 The custom descriptions you can supply to the problem when running it
1758 '''
1759 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityExtrapolationWithinQ
1761 custom_description = {}
1763 dt_max = np.inf
1764 dt_min = 1e-5
1766 if problem.__name__ == "run_vdp":
1767 e_tol = 2e-5
1768 dt_min = 1e-3
1769 elif problem.__name__ == "run_piline":
1770 e_tol = 1e-7
1771 dt_min = 1e-2
1772 elif problem.__name__ == "run_Lorenz":
1773 e_tol = 2e-5
1774 dt_min = 1e-3
1775 elif problem.__name__ == "run_Schroedinger":
1776 e_tol = 4e-6
1777 dt_min = 1e-3
1778 elif problem.__name__ == "run_quench":
1779 e_tol = 1e-5
1780 dt_min = 1e-3
1781 dt_max = 1e2
1782 elif problem.__name__ == "run_AC":
1783 e_tol = 1e-4
1784 else:
1785 raise NotImplementedError(
1786 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\
1787 strategy'
1788 )
1790 custom_description['convergence_controllers'] = {
1791 AdaptivityExtrapolationWithinQ: {
1792 'e_tol': e_tol,
1793 'dt_min': dt_min,
1794 'dt_max': dt_max,
1795 'restol_rel': 1e-2,
1796 'restart_at_maxiter': True,
1797 }
1798 }
1799 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description)
1801 def get_reference_value(self, problem, key, op, num_procs=1):
1802 """
1803 Get a reference value for a given problem for testing in CI.
1805 Args:
1806 problem: A function that runs a pySDC problem, see imports for available problems
1807 key (str): The name of the variable you want to compare
1808 op (function): The operation you want to apply to the data
1809 num_procs (int): Number of processes
1811 Returns:
1812 The reference value
1813 """
1814 if problem.__name__ == "run_Lorenz":
1815 if key == 'work_newton' and op == sum:
1816 return 2198
1817 elif key == 'e_global_post_run' and op == max:
1818 return 5.412657451131508e-07
1820 super().get_reference_value(problem, key, op, num_procs)
1823class AdaptivityPolynomialError(InexactBaseStrategy):
1824 '''
1825 Adaptivity based on extrapolation between collocation nodes as a resilience strategy
1826 '''
1828 def __init__(self, interpolate_between_restarts=False, use_restol_rel=True, max_slope=4, **kwargs):
1829 '''
1830 Initialization routine
1831 '''
1832 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError
1834 self.restol = None
1835 super().__init__(**kwargs)
1836 self.color = list(cmap.values())[9]
1837 self.marker = '+'
1838 self.name = 'adaptivity-inter'
1839 self.bar_plot_x_label = 'adaptivity Q'
1840 self.precision_parameter = 'e_tol'
1841 self.adaptive_coll_params = {}
1842 self.precision_parameter_loc = ['convergence_controllers', AdaptivityPolynomialError, 'e_tol']
1843 self.interpolate_between_restarts = interpolate_between_restarts
1844 self.use_restol_rel = use_restol_rel
1845 self.max_slope = max_slope
1847 def get_custom_description(self, problem, num_procs):
1848 '''
1849 Routine to get a custom description that adds adaptivity
1851 Args:
1852 problem: A function that runs a pySDC problem, see imports for available problems
1853 num_procs (int): Number of processes you intend to run with
1855 Returns:
1856 The custom descriptions you can supply to the problem when running it
1857 '''
1858 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError
1859 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter
1861 base_params = super().get_custom_description(problem, num_procs)
1862 custom_description = {}
1864 dt_max = np.inf
1865 restol_rel = 1e-4
1866 restol_min = 1e-12
1867 dt_min = 0
1868 level_params = {}
1869 problem_params = {}
1871 if problem.__name__ == "run_vdp":
1872 e_tol = 6e-4
1873 level_params['dt'] = 0.1
1874 restol_rel = 1e-5
1875 restol_min = 1e-12
1876 dt_min = 1e-7
1877 problem_params['newton_tol'] = 1e-14
1878 elif problem.__name__ == "run_piline":
1879 e_tol = 1e-7
1880 elif problem.__name__ == "run_Lorenz":
1881 e_tol = 7e-4
1882 elif problem.__name__ == "run_Schroedinger":
1883 e_tol = 3e-5
1884 elif problem.__name__ == "run_quench":
1885 e_tol = 1e-7
1886 level_params['dt'] = 50.0
1887 restol_min = 1e-11
1888 restol_rel = 1e-1
1889 elif problem.__name__ == "run_AC":
1890 e_tol = 1.0e-4
1891 restol_rel = 1e-3
1892 # dt_max = 0.1 * base_params['problem_params']['eps'] ** 2
1893 else:
1894 raise NotImplementedError(
1895 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\
1896 strategy'
1897 )
1899 custom_description['convergence_controllers'] = {
1900 AdaptivityPolynomialError: {
1901 'e_tol': e_tol,
1902 'restol_rel': restol_rel if self.use_restol_rel else 1e-11,
1903 'restol_min': restol_min if self.use_restol_rel else 1e-12,
1904 'restart_at_maxiter': True,
1905 'factor_if_not_converged': self.max_slope,
1906 'interpolate_between_restarts': self.interpolate_between_restarts,
1907 },
1908 StepSizeLimiter: {
1909 'dt_max': dt_max,
1910 'dt_slope_max': self.max_slope,
1911 'dt_min': dt_min,
1912 },
1913 }
1914 custom_description['level_params'] = level_params
1915 custom_description['problem_params'] = problem_params
1916 return merge_descriptions(base_params, custom_description)
1918 def get_custom_description_for_faults(self, problem, *args, **kwargs):
1919 desc = self.get_custom_description(problem, *args, **kwargs)
1920 if problem.__name__ == "run_quench":
1921 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError
1923 desc['convergence_controllers'][AdaptivityPolynomialError]['e_tol'] = 1e-7 * 11
1924 desc['level_params']['dt'] = 4.0
1925 elif problem.__name__ == "run_AC":
1926 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError
1928 desc['convergence_controllers'][AdaptivityPolynomialError]['e_tol'] = 1e-3
1929 return desc
1931 def get_random_params(self, problem, num_procs):
1932 '''
1933 Routine to get parameters for the randomization of faults
1935 Args:
1936 problem: A function that runs a pySDC problem, see imports for available problems
1937 num_procs (int): Number of processes you intend to run with
1939 Returns:
1940 dict: Randomization parameters
1941 '''
1943 rnd_params = super().get_random_params(problem, num_procs)
1944 if problem.__name__ == "run_quench":
1945 rnd_params['iteration'] = 1
1946 elif problem.__name__ == 'run_Lorenz':
1947 rnd_params['iteration'] = 4
1948 return rnd_params
1950 def get_reference_value(self, problem, key, op, num_procs=1):
1951 """
1952 Get a reference value for a given problem for testing in CI.
1954 Args:
1955 problem: A function that runs a pySDC problem, see imports for available problems
1956 key (str): The name of the variable you want to compare
1957 op (function): The operation you want to apply to the data
1958 num_procs (int): Number of processes
1960 Returns:
1961 The reference value
1962 """
1963 if problem.__name__ == "run_Lorenz":
1964 if key == 'work_newton' and op == sum:
1965 return 2124
1966 elif key == 'e_global_post_run' and op == max:
1967 return 8.484321512014503e-08
1969 super().get_reference_value(problem, key, op, num_procs)
1971 @property
1972 def label(self):
1973 return r'$\Delta t$-$k$-adaptivity'