Coverage for pySDC / projects / Resilience / strategies.py: 60%

1011 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-27 07:06 +0000

1import numpy as np 

2from matplotlib.colors import TABLEAU_COLORS 

3 

4cmap = TABLEAU_COLORS 

5 

6 

7def merge_descriptions(descA, descB): 

8 """ 

9 Merge two dictionaries that may contain dictionaries, which happens when merging descriptions, for instance. 

10 

11 Keys that occur in both dictionaries will be overwritten by the ones from `descB` and `descA` will be modified, not 

12 copied! 

13 

14 Args: 

15 descA (dict): Dictionary that you want to merge into 

16 descB (dict): Dictionary you want to merge from 

17 

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 

27 

28 

29class Strategy: 

30 ''' 

31 Abstract class for resilience strategies 

32 ''' 

33 

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 

40 

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] 

47 

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 ) 

59 

60 self.stop_at_nan = stop_at_nan 

61 

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'] = {} 

69 

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 ] 

85 

86 # stuff for work-precision diagrams 

87 self.precision_parameter = None 

88 self.precision_parameter_loc = [] 

89 

90 def __str__(self): 

91 return self.name 

92 

93 def get_controller_params(self, **kwargs): 

94 return {'all_to_done': False} 

95 

96 def get_description_for_tolerance(self, problem, param, **kwargs): 

97 return {} 

98 

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 

103 

104 Returns: 

105 list: Dictionary of parameters 

106 """ 

107 return self.fixable 

108 

109 def get_fault_args(self, problem, num_procs): 

110 ''' 

111 Routine to get arguments for the faults that are exempt from randomization 

112 

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 

116 

117 Returns: 

118 dict: Arguments for the faults that are exempt from randomization 

119 ''' 

120 args = {} 

121 args['target'] = 0 

122 

123 if problem.__name__ == "run_vdp": 

124 args['time'] = 5.5 # 25 

125 elif problem.__name__ == "run_Schroedinger": 

126 args['time'] = 0.3 

127 elif problem.__name__ == "run_quench": 

128 args['time'] = 41.0 

129 elif problem.__name__ == "run_Lorenz": 

130 args['time'] = 10 

131 elif problem.__name__ == "run_AC": 

132 args['time'] = 1e-2 

133 elif problem.__name__ == "run_RBC": 

134 args['time'] = 20.19 

135 elif problem.__name__ == "run_GS": 

136 args['time'] = 100.0 

137 

138 return args 

139 

140 def get_random_params(self, problem, num_procs): 

141 ''' 

142 Routine to get parameters for the randomization of faults 

143 

144 Args: 

145 problem: A function that runs a pySDC problem, see imports for available problems 

146 num_procs (int): Number of processes you intend to run with 

147 

148 Returns: 

149 dict: Randomization parameters 

150 ''' 

151 base_params = self.get_base_parameters(problem, num_procs) 

152 

153 rnd_params = {} 

154 rnd_params['iteration'] = base_params['step_params']['maxiter'] 

155 rnd_params['rank'] = num_procs 

156 

157 if problem.__name__ in ['run_Schroedinger', 'run_quench', 'run_AC', 'run_RBC', 'run_GS']: 

158 rnd_params['min_node'] = 1 

159 

160 if problem.__name__ == "run_quench": 

161 rnd_params['iteration'] = 5 

162 elif problem.__name__ == 'run_Lorenz': 

163 rnd_params['iteration'] = 5 

164 elif problem.__name__ == 'run_RBC': 

165 rnd_params['problem_pos'] = [3, 16, 16] 

166 elif problem.__name__ == 'run_vdp': 

167 rnd_params['iteration'] = 5 

168 

169 return rnd_params 

170 

171 @property 

172 def style(self): 

173 """ 

174 Get the plotting parameters for the strategy. 

175 Supply them to a plotting function using `**` 

176 

177 Returns: 

178 (dict): The plotting parameters as a dictionary 

179 """ 

180 return { 

181 'marker': self.marker, 

182 'label': self.label, 

183 'color': self.color, 

184 'ls': self.linestyle, 

185 } 

186 

187 @property 

188 def label(self): 

189 """ 

190 Get a label for plotting 

191 """ 

192 return self.name 

193 

194 @classmethod 

195 def get_Tend(cls, problem, num_procs=1, resilience_experiment=False): 

196 ''' 

197 Get the final time of runs for fault stats based on the problem 

198 

199 Args: 

200 problem (function): A problem to run 

201 num_procs (int): Number of processes 

202 

203 Returns: 

204 float: Tend to put into the run 

205 ''' 

206 if problem.__name__ == "run_vdp": 

207 if resilience_experiment: 

208 return 11.5 

209 else: 

210 return 20 

211 elif problem.__name__ == "run_piline": 

212 return 20.0 

213 elif problem.__name__ == "run_Lorenz": 

214 return 20 

215 elif problem.__name__ == "run_Schroedinger": 

216 return 1.0 

217 elif problem.__name__ == "run_quench": 

218 return 500.0 

219 elif problem.__name__ == "run_AC": 

220 return 0.025 

221 elif problem.__name__ == "run_RBC": 

222 return 21 

223 elif problem.__name__ == "run_GS": 

224 return 500 

225 else: 

226 raise NotImplementedError('I don\'t have a final time for your problem!') 

227 

228 def get_base_parameters(self, problem, num_procs=1): 

229 ''' 

230 Get a base parameters for the problems independent of the strategy. 

231 

232 Args: 

233 problem (function): A problem to run 

234 num_procs (int): Number of processes 

235 

236 Returns: 

237 dict: Custom description 

238 ''' 

239 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter 

240 

241 custom_description = {} 

242 custom_description['step_params'] = {} 

243 custom_description['level_params'] = {} 

244 custom_description['problem_params'] = {} 

245 

246 if problem.__name__ == "run_vdp": 

247 custom_description['step_params'] = {'maxiter': 3} 

248 custom_description['problem_params'] = { 

249 'u0': np.array([1.1, 0], dtype=np.float64), 

250 'mu': 1000, 

251 'crash_at_maxiter': False, 

252 'newton_tol': 1e-11, 

253 'stop_at_nan': False, 

254 } 

255 custom_description['level_params'] = {'dt': 1e-4} 

256 

257 elif problem.__name__ == "run_Lorenz": 

258 custom_description['step_params'] = {'maxiter': 5} 

259 custom_description['level_params'] = {'dt': 1e-3} 

260 custom_description['problem_params'] = {'stop_at_nan': False} 

261 elif problem.__name__ == "run_Schroedinger": 

262 custom_description['step_params'] = {'maxiter': 5} 

263 custom_description['level_params'] = {'dt': 1e-2, 'restol': -1} 

264 custom_description['problem_params']['nvars'] = (256, 256) 

265 elif problem.__name__ == "run_quench": 

266 custom_description['level_params'] = {'restol': -1, 'dt': 8.0} 

267 custom_description['step_params'] = {'maxiter': 5} 

268 custom_description['problem_params'] = { 

269 'newton_maxiter': 29, 

270 'newton_tol': 1e-7, 

271 'nvars': 2**6, 

272 'direct_solver': False, 

273 'lintol': 1e-8, 

274 'liniter': 29, 

275 'order': 6, 

276 } 

277 elif problem.__name__ == "run_AC": 

278 eps = 4e-2 

279 custom_description['step_params'] = {'maxiter': 5} 

280 custom_description['problem_params'] = { 

281 'nvars': (128,) * 2, 

282 'init_type': 'circle', 

283 'eps': eps, 

284 'radius': 0.25, 

285 'nu': 2, 

286 } 

287 custom_description['level_params'] = {'restol': -1, 'dt': 0.1 * eps**2} 

288 elif problem.__name__ == 'run_RBC': 

289 custom_description['level_params']['dt'] = 2.5e-2 if num_procs == 4 else 5e-2 

290 custom_description['step_params'] = {'maxiter': 5} 

291 elif problem.__name__ == 'run_GS': 

292 custom_description['level_params']['dt'] = 1.0 

293 custom_description['step_params'] = {'maxiter': 5} 

294 

295 custom_description['convergence_controllers'] = { 

296 # StepSizeLimiter: {'dt_min': self.get_Tend(problem=problem, num_procs=num_procs) / self.max_steps} 

297 } 

298 

299 if self.stop_at_nan: 

300 from pySDC.implementations.convergence_controller_classes.crash import StopAtNan 

301 

302 custom_description['convergence_controllers'][StopAtNan] = {'thresh': 1e20} 

303 

304 from pySDC.implementations.convergence_controller_classes.crash import StopAtMaxRuntime 

305 

306 max_runtime = { 

307 'run_vdp': 1000, 

308 'run_Lorenz': 500, 

309 'run_Schroedinger': 150, 

310 'run_quench': 150, 

311 'run_AC': 150, 

312 'run_RBC': 1000, 

313 'run_GS': 100, 

314 } 

315 

316 custom_description['convergence_controllers'][StopAtMaxRuntime] = { 

317 'max_runtime': max_runtime.get(problem.__name__, 100) 

318 } 

319 return custom_description 

320 

321 def get_custom_description(self, problem, num_procs=1): 

322 ''' 

323 Get a custom description based on the problem 

324 

325 Args: 

326 problem (function): A problem to run 

327 num_procs (int): Number of processes 

328 

329 Returns: 

330 dict: Custom description 

331 ''' 

332 custom_description = self.get_base_parameters(problem, num_procs) 

333 return merge_descriptions(custom_description, self.custom_description) 

334 

335 def get_custom_description_for_faults(self, problem, *args, **kwargs): 

336 ''' 

337 Get a custom description based on the problem to run the fault stuff 

338 

339 Returns: 

340 dict: Custom description 

341 ''' 

342 custom_description = self.get_custom_description(problem, *args, **kwargs) 

343 if problem.__name__ == "run_vdp": 

344 custom_description['step_params'] = {'maxiter': 5} 

345 custom_description['problem_params'] = { 

346 'u0': np.array([2.0, 0], dtype=np.float64), 

347 'mu': 5, 

348 'crash_at_maxiter': False, 

349 'newton_tol': 1e-11, 

350 'stop_at_nan': False, 

351 } 

352 custom_description['level_params'] = {'dt': 1e-2} 

353 return custom_description 

354 

355 def get_reference_value(self, problem, key, op, num_procs=1): 

356 """ 

357 Get a reference value for a given problem for testing in CI. 

358 

359 Args: 

360 problem: A function that runs a pySDC problem, see imports for available problems 

361 key (str): The name of the variable you want to compare 

362 op (function): The operation you want to apply to the data 

363 num_procs (int): Number of processes 

364 

365 Returns: 

366 The reference value 

367 """ 

368 raise NotImplementedError( 

369 f'The reference value you are looking for is not implemented for {type(self).__name__} strategy!' 

370 ) 

371 

372 

373class InexactBaseStrategy(Strategy): 

374 """ 

375 Base class for inexact strategies. 

376 """ 

377 

378 def __init__( 

379 self, double_adaptivity=False, newton_inexactness=True, linear_inexactness=True, SDC_maxiter=16, **kwargs 

380 ): 

381 kwargs = {**kwargs, 'skip_residual_computation': 'most'} 

382 super().__init__(**kwargs) 

383 self.double_adaptivity = double_adaptivity 

384 self.newton_inexactness = newton_inexactness 

385 self.linear_inexactness = linear_inexactness 

386 self.SDC_maxiter = SDC_maxiter 

387 

388 def get_controller_params(self, **kwargs): 

389 return {'all_to_done': True} 

390 

391 def get_custom_description(self, problem, num_procs=1): 

392 from pySDC.implementations.convergence_controller_classes.inexactness import NewtonInexactness 

393 

394 preconditioner = { 

395 'run_Lorenz': 'MIN-SR-NS', 

396 }.get(problem.__name__, 'MIN-SR-S') 

397 

398 desc = {} 

399 desc['sweeper_params'] = {'QI': preconditioner} 

400 desc['step_params'] = {'maxiter': self.SDC_maxiter} 

401 desc['problem_params'] = {} 

402 desc['level_params'] = {'restol': 1e-8, 'residual_type': 'last_abs'} 

403 desc['convergence_controllers'] = {} 

404 

405 inexactness_params = { 

406 'min_tol': 1e-12, 

407 'ratio': 1e-2, 

408 'max_tol': 1e-4, 

409 'use_e_tol': False, 

410 'maxiter': 15, 

411 } 

412 

413 if self.newton_inexactness and problem.__name__ not in ['run_Schroedinger', 'run_AC', 'run_RBC', 'run_GS']: 

414 if problem.__name__ == 'run_quench': 

415 inexactness_params['ratio'] = 1e-1 

416 inexactness_params['min_tol'] = 1e-11 

417 inexactness_params['maxiter'] = 5 

418 elif problem.__name__ == "run_vdp": 

419 inexactness_params['ratio'] = 1e-5 

420 inexactness_params['min_tol'] = 1e-15 

421 inexactness_params['maxiter'] = 9 

422 desc['convergence_controllers'][NewtonInexactness] = inexactness_params 

423 

424 if problem.__name__ in ['run_vdp']: 

425 desc['problem_params']['stop_at_nan'] = False 

426 

427 if self.linear_inexactness and problem.__name__ in ['run_quench']: 

428 desc['problem_params']['inexact_linear_ratio'] = 1e-1 

429 if problem.__name__ in ['run_quench']: 

430 desc['problem_params']['direct_solver'] = False 

431 desc['problem_params']['liniter'] = 9 

432 desc['problem_params']['min_lintol'] = 1e-11 

433 

434 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

435 

436 desc['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = { 

437 'max_restarts': 29, 

438 'crash_after_max_restarts': True, 

439 } 

440 return merge_descriptions(super().get_custom_description(problem, num_procs), desc) 

441 

442 

443class BaseStrategy(Strategy): 

444 ''' 

445 Do a fixed iteration count 

446 ''' 

447 

448 def __init__(self, skip_residual_computation='all', **kwargs): 

449 ''' 

450 Initialization routine 

451 ''' 

452 super().__init__(skip_residual_computation=skip_residual_computation, **kwargs) 

453 self.color = list(cmap.values())[0] 

454 self.marker = 'o' 

455 self.name = 'base' 

456 self.bar_plot_x_label = 'base' 

457 self.precision_parameter = 'dt' 

458 self.precision_parameter_loc = ['level_params', 'dt'] 

459 

460 @property 

461 def label(self): 

462 return r'fixed' 

463 

464 def get_custom_description(self, problem, num_procs): 

465 desc = super().get_custom_description(problem, num_procs) 

466 if problem.__name__ == "run_AC": 

467 desc['level_params']['dt'] = 1e-2 * desc['problem_params']['eps'] ** 2 

468 return desc 

469 

470 def get_custom_description_for_faults(self, problem, num_procs, *args, **kwargs): 

471 desc = self.get_custom_description(problem, num_procs, *args, **kwargs) 

472 if problem.__name__ == "run_quench": 

473 desc['level_params']['dt'] = 5.0 

474 elif problem.__name__ == "run_AC": 

475 desc['level_params']['dt'] = 4e-5 if num_procs == 4 else 8e-5 

476 elif problem.__name__ == "run_GS": 

477 desc['level_params']['dt'] = 4e-1 

478 elif problem.__name__ == "run_vdp": 

479 desc['step_params'] = {'maxiter': 5} 

480 desc['problem_params'] = { 

481 'u0': np.array([2.0, 0], dtype=np.float64), 

482 'mu': 5, 

483 'crash_at_maxiter': False, 

484 'newton_tol': 1e-11, 

485 'stop_at_nan': False, 

486 } 

487 desc['level_params'] = {'dt': 4.5e-2} 

488 return desc 

489 

490 def get_reference_value(self, problem, key, op, num_procs=1): 

491 """ 

492 Get a reference value for a given problem for testing in CI. 

493 

494 Args: 

495 problem: A function that runs a pySDC problem, see imports for available problems 

496 key (str): The name of the variable you want to compare 

497 op (function): The operation you want to apply to the data 

498 num_procs (int): Number of processes 

499 

500 Returns: 

501 The reference value 

502 """ 

503 if problem.__name__ == "run_Lorenz": 

504 if key == 'work_newton' and op == sum: 

505 return 12350 

506 elif key == 'e_global_post_run' and op == max: 

507 return 1.3527453646133836e-07 

508 

509 super().get_reference_value(problem, key, op, num_procs) 

510 

511 

512class AdaptivityStrategy(Strategy): 

513 ''' 

514 Adaptivity as a resilience strategy 

515 ''' 

516 

517 def __init__(self, **kwargs): 

518 ''' 

519 Initialization routine 

520 ''' 

521 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

522 

523 kwargs['skip_residual_computation'] = 'all' 

524 super().__init__(**kwargs) 

525 self.color = list(cmap.values())[1] 

526 self.marker = '*' 

527 self.name = 'adaptivity' 

528 self.bar_plot_x_label = 'adaptivity' 

529 self.precision_parameter = 'e_tol' 

530 self.precision_parameter_loc = ['convergence_controllers', Adaptivity, 'e_tol'] 

531 

532 @property 

533 def label(self): 

534 return r'$\Delta t$-adaptivity' 

535 

536 # def get_fixable_params(self, maxiter, **kwargs): 

537 # """ 

538 # Here faults occurring in the last iteration cannot be fixed. 

539 

540 # Args: 

541 # maxiter (int): Max. iterations until convergence is declared 

542 

543 # Returns: 

544 # (list): Contains dictionaries of keyword arguments for `FaultStats.get_mask` 

545 # """ 

546 # self.fixable += [ 

547 # { 

548 # 'key': 'iteration', 

549 # 'op': 'lt', 

550 # 'val': maxiter, 

551 # } 

552 # ] 

553 # return self.fixable 

554 

555 def get_custom_description(self, problem, num_procs): 

556 ''' 

557 Routine to get a custom description that adds adaptivity 

558 

559 Args: 

560 problem: A function that runs a pySDC problem, see imports for available problems 

561 num_procs (int): Number of processes you intend to run with 

562 

563 Returns: 

564 The custom descriptions you can supply to the problem when running it 

565 ''' 

566 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

567 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter 

568 

569 base_params = super().get_custom_description(problem, num_procs) 

570 custom_description = {} 

571 custom_description['convergence_controllers'] = {} 

572 

573 dt_max = np.inf 

574 dt_slope_max = np.inf 

575 dt_slope_min = 0 

576 beta = 0.9 

577 

578 if problem.__name__ == "run_piline": 

579 e_tol = 1e-7 

580 elif problem.__name__ == "run_vdp": 

581 e_tol = 2e-5 

582 elif problem.__name__ == "run_Lorenz": 

583 e_tol = 1e-6 if num_procs == 4 else 1e-7 

584 elif problem.__name__ == "run_Schroedinger": 

585 e_tol = 4e-7 

586 elif problem.__name__ == "run_quench": 

587 e_tol = 1e-8 

588 custom_description['problem_params'] = { 

589 'newton_tol': 1e-10, 

590 'lintol': 1e-11, 

591 } 

592 

593 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

594 

595 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = { 

596 'max_restarts': 99, 

597 } 

598 elif problem.__name__ == "run_AC": 

599 e_tol = 1e-7 

600 # dt_max = 0.1 * base_params['problem_params']['eps'] ** 2 

601 elif problem.__name__ == 'run_RBC': 

602 if num_procs == 4: 

603 e_tol = 2e-2 

604 else: 

605 e_tol = 1e-4 

606 dt_slope_min = 1 

607 beta = 0.5 

608 elif problem.__name__ == 'run_GS': 

609 e_tol = 1e-5 

610 

611 else: 

612 raise NotImplementedError('I don\'t have a tolerance for adaptivity for your problem. Please add one to the\ 

613 strategy') 

614 

615 custom_description['convergence_controllers'][Adaptivity] = { 

616 'e_tol': e_tol, 

617 'dt_slope_max': dt_slope_max, 

618 'dt_rel_min_slope': dt_slope_min, 

619 'beta': beta, 

620 } 

621 custom_description['convergence_controllers'][StepSizeLimiter] = { 

622 'dt_max': dt_max, 

623 } 

624 return merge_descriptions(base_params, custom_description) 

625 

626 def get_reference_value(self, problem, key, op, num_procs=1): 

627 """ 

628 Get a reference value for a given problem for testing in CI. 

629 

630 Args: 

631 problem: A function that runs a pySDC problem, see imports for available problems 

632 key (str): The name of the variable you want to compare 

633 op (function): The operation you want to apply to the data 

634 num_procs (int): Number of processes 

635 

636 Returns: 

637 The reference value 

638 """ 

639 if problem.__name__ == 'run_Lorenz': 

640 if key == 'work_newton' and op == sum: 

641 return 2989 

642 elif key == 'e_global_post_run' and op == max: 

643 return 5.636767497207984e-08 

644 

645 super().get_reference_value(problem, key, op, num_procs) 

646 

647 def get_custom_description_for_faults(self, problem, num_procs, *args, **kwargs): 

648 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter 

649 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

650 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeSlopeLimiter 

651 from pySDC.projects.Resilience.RBC import ReachTendExactly 

652 

653 desc = self.get_custom_description(problem, num_procs, *args, **kwargs) 

654 if problem.__name__ == "run_quench": 

655 desc['level_params']['dt'] = 1.1e1 

656 desc['convergence_controllers'][Adaptivity]['e_tol'] = 1e-6 

657 elif problem.__name__ == "run_AC": 

658 desc['convergence_controllers'][Adaptivity]['e_tol'] = 1e-5 

659 elif problem.__name__ == "run_GS": 

660 desc['convergence_controllers'][Adaptivity]['e_tol'] = 2e-6 

661 elif problem.__name__ == "run_vdp": 

662 desc['step_params'] = {'maxiter': 5} 

663 desc['sweeper_params'] = {'num_nodes': 3, 'QI': 'LU'} 

664 desc['problem_params'] = { 

665 'u0': np.array([2.0, 0], dtype=np.float64), 

666 'mu': 5, 

667 'crash_at_maxiter': True, 

668 'newton_tol': 1e-8, 

669 'stop_at_nan': True, 

670 'relative_tolerance': False, 

671 } 

672 desc['level_params'] = {'dt': 8e-3} 

673 desc['convergence_controllers'][Adaptivity]['e_tol'] = 2e-7 

674 desc['convergence_controllers'][ReachTendExactly] = {'Tend': 11.5} 

675 # desc['convergence_controllers'][StepSizeSlopeLimiter] = {'dt_slope_min': 1/4, 'dt_slope_max': 4} 

676 return desc 

677 

678 

679class AdaptivityRestartFirstStep(AdaptivityStrategy): 

680 def __init__(self, **kwargs): 

681 super().__init__(**kwargs) 

682 self.color = 'teal' 

683 self.name = 'adaptivityRestartFirstStep' 

684 

685 def get_custom_description(self, problem, num_procs): 

686 ''' 

687 Add the other version of basic restarting. 

688 

689 Args: 

690 problem: A function that runs a pySDC problem, see imports for available problems 

691 num_procs (int): Number of processes you intend to run with 

692 

693 Returns: 

694 The custom descriptions you can supply to the problem when running it 

695 ''' 

696 custom_description = super().get_custom_description(problem, num_procs) 

697 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

698 

699 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = { 

700 'max_restarts': 15, 

701 'restart_from_first_step': True, 

702 } 

703 return custom_description 

704 

705 @property 

706 def label(self): 

707 return f'{super().label} restart from first step' 

708 

709 

710class AdaptiveHotRodStrategy(Strategy): 

711 ''' 

712 Adaptivity + Hot Rod as a resilience strategy 

713 ''' 

714 

715 def __init__(self, **kwargs): 

716 ''' 

717 Initialization routine 

718 ''' 

719 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

720 

721 kwargs['skip_residual_computation'] = 'all' 

722 super().__init__(**kwargs) 

723 self.color = list(cmap.values())[4] 

724 self.marker = '.' 

725 self.name = 'adaptive Hot Rod' 

726 self.bar_plot_x_label = 'adaptive\nHot Rod' 

727 self.precision_parameter = 'e_tol' 

728 self.precision_parameter_loc = ['convergence_controllers', Adaptivity, 'e_tol'] 

729 

730 def get_custom_description(self, problem, num_procs): 

731 ''' 

732 Routine to get a custom description that adds adaptivity and Hot Rod 

733 

734 Args: 

735 problem: A function that runs a pySDC problem, see imports for available problems 

736 num_procs (int): Number of processes you intend to run with 

737 

738 Returns: 

739 The custom description you can supply to the problem when running it 

740 ''' 

741 from pySDC.implementations.convergence_controller_classes.hotrod import HotRod 

742 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

743 

744 if problem.__name__ == "run_vdp": 

745 e_tol = 3e-7 

746 dt_min = 1e-3 

747 maxiter = 4 

748 HotRod_tol = 2e-6 

749 elif problem.__name__ == "run_Lorenz": 

750 e_tol = 3e-7 

751 dt_min = 1e-3 

752 maxiter = 4 

753 HotRod_tol = 2e-6 

754 else: 

755 raise NotImplementedError('I don\'t have a tolerance for adaptive Hot Rod for your problem. Please add one \ 

756to the strategy') 

757 

758 no_storage = num_procs > 1 

759 

760 custom_description = { 

761 'convergence_controllers': { 

762 HotRod: {'HotRod_tol': HotRod_tol, 'no_storage': no_storage}, 

763 Adaptivity: {'e_tol': e_tol, 'dt_min': dt_min, 'embedded_error_flavor': 'linearized'}, 

764 }, 

765 'step_params': {'maxiter': maxiter}, 

766 } 

767 

768 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description) 

769 

770 def get_reference_value(self, problem, key, op, num_procs=1): 

771 """ 

772 Get a reference value for a given problem for testing in CI. 

773 

774 Args: 

775 problem: A function that runs a pySDC problem, see imports for available problems 

776 key (str): The name of the variable you want to compare 

777 op (function): The operation you want to apply to the data 

778 num_procs (int): Number of processes 

779 

780 Returns: 

781 The reference value 

782 """ 

783 if problem.__name__ == "run_Lorenz": 

784 if key == 'work_newton' and op == sum: 

785 return 5092 

786 elif key == 'e_global_post_run' and op == max: 

787 return 4.107116318152748e-06 

788 

789 super().get_reference_value(problem, key, op, num_procs) 

790 

791 

792class IterateStrategy(Strategy): 

793 ''' 

794 Iterate for as much as you want 

795 ''' 

796 

797 def __init__(self, **kwargs): 

798 ''' 

799 Initialization routine 

800 ''' 

801 kwargs['skip_residual_computation'] = 'most' 

802 super().__init__(**kwargs) 

803 self.color = list(cmap.values())[2] 

804 self.marker = 'v' 

805 self.name = 'iterate' 

806 self.bar_plot_x_label = 'iterate' 

807 self.precision_parameter = 'restol' 

808 self.precision_parameter_loc = ['level_params', 'restol'] 

809 

810 @property 

811 def label(self): 

812 return r'$k$-adaptivity' 

813 

814 def get_custom_description(self, problem, num_procs): 

815 ''' 

816 Routine to get a custom description that allows for adaptive iteration counts 

817 

818 Args: 

819 problem: A function that runs a pySDC problem, see imports for available problems 

820 num_procs (int): Number of processes you intend to run with 

821 

822 Returns: 

823 The custom description you can supply to the problem when running it 

824 ''' 

825 restol = -1 

826 e_tol = -1 

827 

828 if problem.__name__ == "run_piline": 

829 restol = 2.3e-8 

830 elif problem.__name__ == "run_vdp": 

831 restol = 9e-7 

832 elif problem.__name__ == "run_Lorenz": 

833 restol = 16e-7 

834 elif problem.__name__ == "run_Schroedinger": 

835 restol = 6.5e-7 

836 elif problem.__name__ == "run_quench": 

837 restol = 1e-7 

838 elif problem.__name__ == "run_AC": 

839 restol = 1e-11 

840 elif problem.__name__ == "run_RBC": 

841 restol = 1e-4 

842 elif problem.__name__ == "run_GS": 

843 restol = 1e-4 

844 else: 

845 raise NotImplementedError('I don\'t have a residual tolerance for your problem. Please add one to the \ 

846strategy') 

847 

848 custom_description = { 

849 'step_params': {'maxiter': 99}, 

850 'level_params': {'restol': restol, 'e_tol': e_tol}, 

851 } 

852 

853 if problem.__name__ == "run_quench": 

854 custom_description['level_params']['dt'] = 1.0 

855 

856 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description) 

857 

858 def get_random_params(self, problem, num_procs): 

859 ''' 

860 Routine to get parameters for the randomization of faults 

861 

862 Args: 

863 problem: A function that runs a pySDC problem, see imports for available problems 

864 num_procs (int): Number of processes you intend to run with 

865 

866 Returns: 

867 dict: Randomization parameters 

868 ''' 

869 

870 rnd_params = super().get_random_params(problem, num_procs) 

871 if problem.__name__ == "run_quench": 

872 rnd_params['iteration'] = 1 

873 return rnd_params 

874 

875 def get_reference_value(self, problem, key, op, num_procs=1): 

876 """ 

877 Get a reference value for a given problem for testing in CI. 

878 

879 Args: 

880 problem: A function that runs a pySDC problem, see imports for available problems 

881 key (str): The name of the variable you want to compare 

882 op (function): The operation you want to apply to the data 

883 num_procs (int): Number of processes 

884 

885 Returns: 

886 The reference value 

887 """ 

888 if problem.__name__ == "run_Lorenz": 

889 if key == 'work_newton' and op == sum: 

890 return 9200 

891 elif key == 'e_global_post_run' and op == max: 

892 return 2.139863344829962e-05 

893 

894 super().get_reference_value(problem, key, op, num_procs) 

895 

896 

897class kAdaptivityStrategy(IterateStrategy): 

898 def __init__(self, **kwargs): 

899 super().__init__(**kwargs) 

900 self.precision_parameter = 'dt' 

901 self.precision_parameter_loc = ['level_params', 'dt'] 

902 

903 def get_custom_description(self, problem, num_procs, *args, **kwargs): 

904 desc = super().get_custom_description(problem, num_procs, *args, **kwargs) 

905 desc['level_params']['restol'] = 1e-9 

906 if problem.__name__ == "run_quench": 

907 desc['problem_params']['newton_tol'] = 1e-9 

908 desc['problem_params']['lintol'] = 1e-9 

909 desc['level_params']['dt'] = 2.5 

910 elif problem.__name__ == "run_AC": 

911 desc['level_params']['restol'] = 1e-11 

912 desc['level_params']['dt'] = 0.4 * desc['problem_params']['eps'] ** 2 / 8.0 

913 elif problem.__name__ == "run_RBC": 

914 desc['level_params']['dt'] = 7e-2 

915 desc['level_params']['restol'] = 1e-6 

916 desc['level_params']['e_tol'] = 1e-7 

917 elif problem.__name__ == "run_GS": 

918 desc['level_params']['dt'] = 1.0 

919 desc['level_params']['restol'] = 1e-9 

920 return desc 

921 

922 def get_custom_description_for_faults(self, problem, num_procs, *args, **kwargs): 

923 desc = self.get_custom_description(problem, num_procs, *args, **kwargs) 

924 if problem.__name__ == 'run_quench': 

925 desc['level_params']['dt'] = 5.0 

926 elif problem.__name__ == 'run_AC': 

927 desc['level_params']['dt'] = 4e-4 if num_procs == 4 else 5e-4 

928 desc['level_params']['restol'] = 1e-5 if num_procs == 4 else 1e-11 

929 elif problem.__name__ == 'run_RBC': 

930 desc['level_params']['restol'] = 1e-3 if num_procs == 4 else 1e-6 

931 elif problem.__name__ == 'run_Lorenz': 

932 desc['level_params']['dt'] = 8e-3 

933 elif problem.__name__ == "run_vdp": 

934 desc['sweeper_params'] = {'num_nodes': 3} 

935 desc['problem_params'] = { 

936 'u0': np.array([2.0, 0], dtype=np.float64), 

937 'mu': 5, 

938 'crash_at_maxiter': False, 

939 'newton_tol': 1e-11, 

940 'stop_at_nan': False, 

941 } 

942 desc['level_params'] = {'dt': 4.0e-2, 'restol': 1e-7} 

943 return desc 

944 

945 def get_reference_value(self, problem, key, op, num_procs=1): 

946 """ 

947 Get a reference value for a given problem for testing in CI. 

948 

949 Args: 

950 problem: A function that runs a pySDC problem, see imports for available problems 

951 key (str): The name of the variable you want to compare 

952 op (function): The operation you want to apply to the data 

953 num_procs (int): Number of processes 

954 

955 Returns: 

956 The reference value 

957 """ 

958 if problem.__name__ == "run_Lorenz": 

959 if key == 'work_newton' and op == sum: 

960 return 12350 

961 elif key == 'e_global_post_run' and op == max: 

962 return 1.3527453646133836e-07 

963 

964 super().get_reference_value(problem, key, op, num_procs) 

965 

966 

967class HotRodStrategy(Strategy): 

968 ''' 

969 Hot Rod as a resilience strategy 

970 ''' 

971 

972 def __init__(self, **kwargs): 

973 ''' 

974 Initialization routine 

975 ''' 

976 kwargs['skip_residual_computation'] = 'all' 

977 super().__init__(**kwargs) 

978 self.color = list(cmap.values())[3] 

979 self.marker = '^' 

980 self.name = 'Hot Rod' 

981 self.bar_plot_x_label = 'Hot Rod' 

982 self.precision_parameter = 'dt' 

983 self.precision_parameter_loc = ['level_params', 'dt'] 

984 

985 def get_custom_description(self, problem, num_procs): 

986 ''' 

987 Routine to get a custom description that adds Hot Rod 

988 

989 Args: 

990 problem: A function that runs a pySDC problem, see imports for available problems 

991 num_procs (int): Number of processes you intend to run with 

992 

993 Returns: 

994 The custom description you can supply to the problem when running it 

995 ''' 

996 from pySDC.implementations.convergence_controller_classes.hotrod import HotRod 

997 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestartingNonMPI 

998 

999 base_params = super().get_custom_description(problem, num_procs) 

1000 if problem.__name__ == "run_vdp": 

1001 # if num_procs == 4: 

1002 # HotRod_tol = 1.800804e-04 

1003 # elif num_procs == 5: 

1004 # HotRod_tol = 9.329361e-05 

1005 # else: # 1 process 

1006 # HotRod_tol = 1.347949e-06 

1007 # HotRod_tol = 7e-6 if num_procs > 1 else 5e-7 

1008 HotRod_tol = 7.2e-05 

1009 maxiter = 6 

1010 elif problem.__name__ == "run_Lorenz": 

1011 if num_procs == 5: 

1012 HotRod_tol = 9.539348e-06 

1013 elif num_procs == 4: 

1014 HotRod_tol = 3.201e-6 

1015 else: 

1016 HotRod_tol = 7.720589e-07 

1017 maxiter = 6 

1018 elif problem.__name__ == "run_Schroedinger": 

1019 if num_procs == 5: 

1020 HotRod_tol = 2.497697e-06 

1021 elif num_procs == 4: 

1022 HotRod_tol = 1.910405e-06 

1023 else: 

1024 HotRod_tol = 4.476790e-07 

1025 maxiter = 6 

1026 elif problem.__name__ == "run_quench": 

1027 if num_procs == 5: 

1028 HotRod_tol = 1.017534e-03 

1029 elif num_procs == 4: 

1030 HotRod_tol = 1.017534e-03 

1031 else: 

1032 HotRod_tol = 5.198620e-04 

1033 maxiter = 6 

1034 elif problem.__name__ == 'run_AC': 

1035 HotRod_tol = 9.564437e-06 

1036 maxiter = 6 

1037 elif problem.__name__ == 'run_RBC': 

1038 HotRod_tol = 3e-4 if num_procs == 4 else 6.34e-6 

1039 maxiter = 6 

1040 elif problem.__name__ == 'run_GS': 

1041 HotRod_tol = 3.22e-5 

1042 maxiter = 6 

1043 else: 

1044 raise NotImplementedError('I don\'t have a tolerance for Hot Rod for your problem. Please add one to the\ 

1045 strategy') 

1046 

1047 no_storage = False # num_procs > 1 

1048 

1049 custom_description = { 

1050 'convergence_controllers': { 

1051 HotRod: {'HotRod_tol': HotRod_tol, 'no_storage': no_storage}, 

1052 BasicRestartingNonMPI: { 

1053 'max_restarts': 2, 

1054 'crash_after_max_restarts': False, 

1055 'restart_from_first_step': True, 

1056 }, 

1057 }, 

1058 'step_params': {'maxiter': maxiter}, 

1059 'level_params': {}, 

1060 } 

1061 if problem.__name__ == "run_AC": 

1062 custom_description['level_params']['dt'] = 8e-5 

1063 return merge_descriptions(base_params, custom_description) 

1064 

1065 def get_custom_description_for_faults(self, problem, *args, **kwargs): 

1066 desc = self.get_custom_description(problem, *args, **kwargs) 

1067 if problem.__name__ == "run_quench": 

1068 desc['level_params']['dt'] = 5.0 

1069 elif problem.__name__ == "run_AC": 

1070 desc['level_params']['dt'] = 8e-5 

1071 elif problem.__name__ == "run_GS": 

1072 desc['level_params']['dt'] = 4e-1 

1073 elif problem.__name__ == "run_vdp": 

1074 desc['step_params'] = {'maxiter': 6} 

1075 desc['problem_params'] = { 

1076 'u0': np.array([2.0, 0], dtype=np.float64), 

1077 'mu': 5, 

1078 'crash_at_maxiter': False, 

1079 'newton_tol': 1e-11, 

1080 'stop_at_nan': False, 

1081 } 

1082 desc['level_params'] = {'dt': 4.5e-2} 

1083 return desc 

1084 

1085 def get_reference_value(self, problem, key, op, num_procs=1): 

1086 """ 

1087 Get a reference value for a given problem for testing in CI. 

1088 

1089 Args: 

1090 problem: A function that runs a pySDC problem, see imports for available problems 

1091 key (str): The name of the variable you want to compare 

1092 op (function): The operation you want to apply to the data 

1093 num_procs (int): Number of processes 

1094 

1095 Returns: 

1096 The reference value 

1097 """ 

1098 if problem.__name__ == "run_Lorenz": 

1099 if key == 'work_newton' and op == sum: 

1100 return 12350 

1101 elif key == 'e_global_post_run' and op == max: 

1102 return 1.3527453646133836e-07 

1103 

1104 super().get_reference_value(problem, key, op, num_procs) 

1105 

1106 

1107class AdaptivityCollocationStrategy(InexactBaseStrategy): 

1108 ''' 

1109 Adaptivity based on collocation as a resilience strategy 

1110 ''' 

1111 

1112 def __init__(self, **kwargs): 

1113 ''' 

1114 Initialization routine 

1115 ''' 

1116 kwargs = { 

1117 'skip_residual_computation': 'most', 

1118 **kwargs, 

1119 } 

1120 

1121 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityCollocation 

1122 

1123 self.restol = None 

1124 super().__init__(**kwargs) 

1125 self.color = list(cmap.values())[1] 

1126 self.marker = '*' 

1127 self.name = 'adaptivity_coll' 

1128 self.bar_plot_x_label = 'adaptivity collocation' 

1129 self.precision_parameter = 'e_tol' 

1130 self.adaptive_coll_params = {} 

1131 self.precision_parameter_loc = ['convergence_controllers', AdaptivityCollocation, 'e_tol'] 

1132 

1133 def get_custom_description(self, problem, num_procs): 

1134 ''' 

1135 Routine to get a custom description that adds adaptivity 

1136 

1137 Args: 

1138 problem: A function that runs a pySDC problem, see imports for available problems 

1139 num_procs (int): Number of processes you intend to run with 

1140 

1141 Returns: 

1142 The custom descriptions you can supply to the problem when running it 

1143 ''' 

1144 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityCollocation 

1145 

1146 custom_description = {} 

1147 

1148 dt_max = np.inf 

1149 dt_min = 1e-5 

1150 

1151 if problem.__name__ == "run_piline": 

1152 e_tol = 1e-7 

1153 dt_min = 1e-2 

1154 elif problem.__name__ == "run_vdp": 

1155 e_tol = 2e-5 

1156 dt_min = 1e-3 

1157 elif problem.__name__ == "run_Lorenz": 

1158 e_tol = 2e-5 

1159 dt_min = 1e-3 

1160 elif problem.__name__ == "run_Schroedinger": 

1161 e_tol = 4e-6 

1162 dt_min = 1e-3 

1163 elif problem.__name__ == "run_quench": 

1164 e_tol = 1e-5 

1165 dt_min = 1e-3 

1166 dt_max = 1e2 

1167 elif problem.__name__ == "run_AC": 

1168 e_tol = 1e-4 

1169 else: 

1170 raise NotImplementedError('I don\'t have a tolerance for adaptivity for your problem. Please add one to the\ 

1171 strategy') 

1172 

1173 custom_description['convergence_controllers'] = { 

1174 AdaptivityCollocation: { 

1175 'e_tol': e_tol, 

1176 'dt_min': dt_min, 

1177 'dt_max': dt_max, 

1178 'adaptive_coll_params': self.adaptive_coll_params, 

1179 'restol_rel': 1e-2, 

1180 } 

1181 } 

1182 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description) 

1183 

1184 

1185class AdaptivityCollocationTypeStrategy(AdaptivityCollocationStrategy): 

1186 def __init__(self, **kwargs): 

1187 super().__init__(**kwargs) 

1188 self.color = list(cmap.values())[4] 

1189 self.marker = '.' 

1190 self.adaptive_coll_params = { 

1191 'quad_type': ['RADAU-RIGHT', 'GAUSS'], 

1192 'do_coll_update': [False, True], 

1193 } 

1194 

1195 @property 

1196 def label(self): 

1197 return 'adaptivity type' 

1198 

1199 def get_reference_value(self, problem, key, op, num_procs=1): 

1200 """ 

1201 Get a reference value for a given problem for testing in CI. 

1202 

1203 Args: 

1204 problem: A function that runs a pySDC problem, see imports for available problems 

1205 key (str): The name of the variable you want to compare 

1206 op (function): The operation you want to apply to the data 

1207 num_procs (int): Number of processes 

1208 

1209 Returns: 

1210 The reference value 

1211 """ 

1212 if problem.__name__ == "run_Lorenz": 

1213 if key == 'work_newton' and op == sum: 

1214 return 1025 

1215 elif key == 'e_global_post_run' and op == max: 

1216 return 4.266975256683736e-06 

1217 

1218 super().get_reference_value(problem, key, op, num_procs) 

1219 

1220 

1221class AdaptivityCollocationRefinementStrategy(AdaptivityCollocationStrategy): 

1222 def __init__(self, **kwargs): 

1223 super().__init__(**kwargs) 

1224 self.color = list(cmap.values())[5] 

1225 self.marker = '^' 

1226 self.adaptive_coll_params = { 

1227 'num_nodes': [2, 3], 

1228 'quad_type': ['GAUSS', 'RADAU-RIGHT'], 

1229 'do_coll_update': [True, False], 

1230 } 

1231 

1232 @property 

1233 def label(self): 

1234 return 'adaptivity refinement' 

1235 

1236 def get_reference_value(self, problem, key, op, num_procs=1): 

1237 """ 

1238 Get a reference value for a given problem for testing in CI. 

1239 

1240 Args: 

1241 problem: A function that runs a pySDC problem, see imports for available problems 

1242 key (str): The name of the variable you want to compare 

1243 op (function): The operation you want to apply to the data 

1244 num_procs (int): Number of processes 

1245 

1246 Returns: 

1247 The reference value 

1248 """ 

1249 if problem.__name__ == "run_Lorenz": 

1250 if key == 'work_newton' and op == sum: 

1251 return 917 

1252 elif key == 'e_global_post_run' and op == max: 

1253 return 1.0874929465387595e-05 

1254 

1255 super().get_reference_value(problem, key, op, num_procs) 

1256 

1257 

1258class AdaptivityCollocationDerefinementStrategy(AdaptivityCollocationStrategy): 

1259 def __init__(self, **kwargs): 

1260 super().__init__(**kwargs) 

1261 self.color = list(cmap.values())[6] 

1262 self.marker = '^' 

1263 self.adaptive_coll_params = {'num_nodes': [4, 3]} 

1264 

1265 @property 

1266 def label(self): 

1267 return 'adaptivity de-refinement' 

1268 

1269 def get_reference_value(self, problem, key, op, num_procs=1): 

1270 """ 

1271 Get a reference value for a given problem for testing in CI. 

1272 

1273 Args: 

1274 problem: A function that runs a pySDC problem, see imports for available problems 

1275 key (str): The name of the variable you want to compare 

1276 op (function): The operation you want to apply to the data 

1277 num_procs (int): Number of processes 

1278 

1279 Returns: 

1280 The reference value 

1281 """ 

1282 if problem.__name__ == 'run_Lorenz': 

1283 if key == 'work_newton' and op == sum: 

1284 return 1338 

1285 elif key == 'e_global_post_run' and op == max: 

1286 return 0.0001013999955041811 

1287 

1288 super().get_reference_value(problem, key, op, num_procs) 

1289 

1290 

1291class DIRKStrategy(AdaptivityStrategy): 

1292 ''' 

1293 DIRK4(3) 

1294 ''' 

1295 

1296 def __init__(self, **kwargs): 

1297 ''' 

1298 Initialization routine 

1299 ''' 

1300 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK 

1301 

1302 super().__init__(**kwargs) 

1303 self.color = list(cmap.values())[7] 

1304 self.marker = '^' 

1305 self.name = 'DIRK' 

1306 self.bar_plot_x_label = 'DIRK4(3)' 

1307 self.precision_parameter = 'e_tol' 

1308 self.precision_parameter_loc = ['convergence_controllers', AdaptivityRK, 'e_tol'] 

1309 self.max_steps = 1e5 

1310 

1311 @property 

1312 def label(self): 

1313 return 'DIRK4(3)' 

1314 

1315 def get_custom_description(self, problem, num_procs): 

1316 ''' 

1317 Routine to get a custom description that adds adaptivity 

1318 

1319 Args: 

1320 problem: A function that runs a pySDC problem, see imports for available problems 

1321 num_procs (int): Number of processes you intend to run with 

1322 

1323 Returns: 

1324 The custom descriptions you can supply to the problem when running it 

1325 ''' 

1326 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK, Adaptivity 

1327 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1328 from pySDC.implementations.sweeper_classes.Runge_Kutta import DIRK43 

1329 

1330 adaptivity_description = super().get_custom_description(problem, num_procs) 

1331 

1332 e_tol = adaptivity_description['convergence_controllers'][Adaptivity]['e_tol'] 

1333 adaptivity_description['convergence_controllers'].pop(Adaptivity, None) 

1334 adaptivity_description.pop('sweeper_params', None) 

1335 

1336 rk_params = { 

1337 'step_params': {'maxiter': 1}, 

1338 'sweeper_class': DIRK43, 

1339 'convergence_controllers': { 

1340 AdaptivityRK: {'e_tol': e_tol}, 

1341 BasicRestarting.get_implementation(useMPI=self.useMPI): { 

1342 'max_restarts': 49, 

1343 'crash_after_max_restarts': False, 

1344 }, 

1345 }, 

1346 } 

1347 

1348 custom_description = merge_descriptions(adaptivity_description, rk_params) 

1349 

1350 return custom_description 

1351 

1352 def get_reference_value(self, problem, key, op, num_procs=1): 

1353 """ 

1354 Get a reference value for a given problem for testing in CI. 

1355 

1356 Args: 

1357 problem: A function that runs a pySDC problem, see imports for available problems 

1358 key (str): The name of the variable you want to compare 

1359 op (function): The operation you want to apply to the data 

1360 num_procs (int): Number of processes 

1361 

1362 Returns: 

1363 The reference value 

1364 """ 

1365 if problem.__name__ == "run_Lorenz": 

1366 if key == 'work_newton' and op == sum: 

1367 return 5467 

1368 elif key == 'e_global_post_run' and op == max: 

1369 return 7.049480537091313e-07 

1370 

1371 super().get_reference_value(problem, key, op, num_procs) 

1372 

1373 def get_random_params(self, problem, num_procs): 

1374 ''' 

1375 Routine to get parameters for the randomization of faults 

1376 

1377 Args: 

1378 problem: A function that runs a pySDC problem, see imports for available problems 

1379 num_procs (int): Number of processes you intend to run with 

1380 

1381 Returns: 

1382 dict: Randomization parameters 

1383 ''' 

1384 rnd_params = super().get_random_params(problem, num_procs) 

1385 rnd_params['iteration'] = 1 

1386 rnd_params['min_node'] = 5 

1387 

1388 return rnd_params 

1389 

1390 

1391class ARKStrategy(AdaptivityStrategy): 

1392 ''' 

1393 ARK5(4) 

1394 ''' 

1395 

1396 def __init__(self, **kwargs): 

1397 ''' 

1398 Initialization routine 

1399 ''' 

1400 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK 

1401 

1402 super().__init__(**kwargs) 

1403 self.color = list(cmap.values())[7] 

1404 self.marker = 'P' 

1405 self.name = 'ARK' 

1406 self.bar_plot_x_label = 'ARK5(4)' 

1407 self.precision_parameter = 'e_tol' 

1408 self.precision_parameter_loc = ['convergence_controllers', AdaptivityRK, 'e_tol'] 

1409 self.max_steps = 1e5 

1410 

1411 @property 

1412 def label(self): 

1413 return 'ARK5(4)' 

1414 

1415 def get_custom_description(self, problem, num_procs): 

1416 ''' 

1417 Routine to get a custom description that adds adaptivity 

1418 

1419 Args: 

1420 problem: A function that runs a pySDC problem, see imports for available problems 

1421 num_procs (int): Number of processes you intend to run with 

1422 

1423 Returns: 

1424 The custom descriptions you can supply to the problem when running it 

1425 ''' 

1426 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK, Adaptivity 

1427 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeSlopeLimiter 

1428 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1429 from pySDC.implementations.sweeper_classes.Runge_Kutta import ARK548L2SA 

1430 

1431 adaptivity_description = super().get_custom_description(problem, num_procs) 

1432 

1433 e_tol = adaptivity_description['convergence_controllers'][Adaptivity]['e_tol'] / 20.0 

1434 adaptivity_description['convergence_controllers'].pop(Adaptivity, None) 

1435 adaptivity_description.pop('sweeper_params', None) 

1436 

1437 rk_params = { 

1438 'step_params': {'maxiter': 1}, 

1439 'sweeper_class': ARK548L2SA, 

1440 'convergence_controllers': { 

1441 AdaptivityRK: {'e_tol': e_tol}, 

1442 BasicRestarting.get_implementation(useMPI=self.useMPI): { 

1443 'max_restarts': 49, 

1444 'crash_after_max_restarts': False, 

1445 }, 

1446 }, 

1447 } 

1448 

1449 if problem.__name__ == "run_RBC": 

1450 rk_params['convergence_controllers'][StepSizeSlopeLimiter] = {'dt_rel_min_slope': 0.25} 

1451 

1452 custom_description = merge_descriptions(adaptivity_description, rk_params) 

1453 

1454 return custom_description 

1455 

1456 def get_reference_value(self, problem, key, op, num_procs=1): 

1457 """ 

1458 Get a reference value for a given problem for testing in CI. 

1459 

1460 Args: 

1461 problem: A function that runs a pySDC problem, see imports for available problems 

1462 key (str): The name of the variable you want to compare 

1463 op (function): The operation you want to apply to the data 

1464 num_procs (int): Number of processes 

1465 

1466 Returns: 

1467 The reference value 

1468 """ 

1469 if problem.__name__ == "run_Schroedinger": 

1470 if key == 'work_newton' and op == sum: 

1471 return 0 

1472 elif key == 'e_global_post_run' and op == max: 

1473 return 3.1786601531890356e-08 

1474 

1475 super().get_reference_value(problem, key, op, num_procs) 

1476 

1477 

1478class ARK3_CFL_Strategy(BaseStrategy): 

1479 """ 

1480 This is special for RBC with CFL number for accuracy 

1481 """ 

1482 

1483 def __init__(self, **kwargs): 

1484 ''' 

1485 Initialization routine 

1486 ''' 

1487 from pySDC.implementations.problem_classes.RayleighBenard import CFLLimit 

1488 

1489 super().__init__(**kwargs) 

1490 self.color = 'maroon' 

1491 self.marker = '<' 

1492 self.name = 'ARK3' 

1493 self.bar_plot_x_label = 'ARK3' 

1494 self.precision_parameter = 'cfl' 

1495 self.precision_parameter_loc = ['convergence_controllers', CFLLimit, 'cfl'] 

1496 self.max_steps = 1e5 

1497 

1498 @property 

1499 def label(self): 

1500 return 'ARK3' 

1501 

1502 def get_custom_description(self, problem, num_procs): 

1503 ''' 

1504 Args: 

1505 problem: A function that runs a pySDC problem, see imports for available problems 

1506 num_procs (int): Number of processes you intend to run with 

1507 

1508 Returns: 

1509 The custom descriptions you can supply to the problem when running it 

1510 ''' 

1511 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1512 from pySDC.implementations.sweeper_classes.Runge_Kutta import ARK3 

1513 from pySDC.implementations.problem_classes.RayleighBenard import CFLLimit 

1514 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeSlopeLimiter 

1515 

1516 desc = super().get_custom_description(problem, num_procs) 

1517 

1518 rk_params = { 

1519 'step_params': {'maxiter': 1}, 

1520 'sweeper_class': ARK3, 

1521 'convergence_controllers': { 

1522 CFLLimit: { 

1523 'cfl': 0.5, 

1524 'dt_max': 1.0, 

1525 }, 

1526 StepSizeSlopeLimiter: {'dt_rel_min_slope': 0.2}, 

1527 }, 

1528 } 

1529 

1530 custom_description = merge_descriptions(desc, rk_params) 

1531 

1532 return custom_description 

1533 

1534 

1535class ESDIRKStrategy(AdaptivityStrategy): 

1536 ''' 

1537 ESDIRK5(3) 

1538 ''' 

1539 

1540 def __init__(self, **kwargs): 

1541 ''' 

1542 Initialization routine 

1543 ''' 

1544 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK 

1545 

1546 super().__init__(**kwargs) 

1547 self.color = 'violet' 

1548 self.marker = '^' 

1549 self.name = 'ESDIRK' 

1550 self.bar_plot_x_label = 'ESDIRK5(3)' 

1551 self.precision_parameter = 'e_tol' 

1552 self.precision_parameter_loc = ['convergence_controllers', AdaptivityRK, 'e_tol'] 

1553 self.max_steps = 1e5 

1554 

1555 @property 

1556 def label(self): 

1557 return 'ESDIRK5(3)' 

1558 

1559 def get_description_for_tolerance(self, problem, param, **kwargs): 

1560 desc = {} 

1561 if problem.__name__ == 'run_Schroedinger': 

1562 desc['problem_params'] = {'lintol': param} 

1563 return desc 

1564 

1565 def get_custom_description(self, problem, num_procs): 

1566 ''' 

1567 Routine to get a custom description that adds adaptivity 

1568 

1569 Args: 

1570 problem: A function that runs a pySDC problem, see imports for available problems 

1571 num_procs (int): Number of processes you intend to run with 

1572 

1573 Returns: 

1574 The custom descriptions you can supply to the problem when running it 

1575 ''' 

1576 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK, Adaptivity 

1577 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1578 from pySDC.implementations.sweeper_classes.Runge_Kutta import ESDIRK53 

1579 

1580 adaptivity_description = super().get_custom_description(problem, num_procs) 

1581 

1582 e_tol = adaptivity_description['convergence_controllers'][Adaptivity]['e_tol'] 

1583 adaptivity_description['convergence_controllers'].pop(Adaptivity, None) 

1584 adaptivity_description.pop('sweeper_params', None) 

1585 

1586 mod = 1e1 if problem.__name__ == 'run_quench' else 1.0 

1587 

1588 rk_params = { 

1589 'step_params': {'maxiter': 1}, 

1590 'sweeper_class': ESDIRK53, 

1591 'convergence_controllers': { 

1592 AdaptivityRK: {'e_tol': e_tol * mod}, 

1593 BasicRestarting.get_implementation(useMPI=self.useMPI): { 

1594 'max_restarts': 49, 

1595 'crash_after_max_restarts': False, 

1596 }, 

1597 }, 

1598 } 

1599 

1600 custom_description = merge_descriptions(adaptivity_description, rk_params) 

1601 

1602 return custom_description 

1603 

1604 def get_reference_value(self, problem, key, op, num_procs=1): 

1605 """ 

1606 Get a reference value for a given problem for testing in CI. 

1607 

1608 Args: 

1609 problem: A function that runs a pySDC problem, see imports for available problems 

1610 key (str): The name of the variable you want to compare 

1611 op (function): The operation you want to apply to the data 

1612 num_procs (int): Number of processes 

1613 

1614 Returns: 

1615 The reference value 

1616 """ 

1617 if problem.__name__ == "run_Lorenz": 

1618 if key == 'work_newton' and op == sum: 

1619 return 2963 

1620 elif key == 'e_global_post_run' and op == max: 

1621 return 4.126039954144289e-09 

1622 

1623 super().get_reference_value(problem, key, op, num_procs) 

1624 

1625 def get_random_params(self, problem, num_procs): 

1626 ''' 

1627 Routine to get parameters for the randomization of faults 

1628 

1629 Args: 

1630 problem: A function that runs a pySDC problem, see imports for available problems 

1631 num_procs (int): Number of processes you intend to run with 

1632 

1633 Returns: 

1634 dict: Randomization parameters 

1635 ''' 

1636 rnd_params = super().get_random_params(problem, num_procs) 

1637 rnd_params['iteration'] = 1 

1638 rnd_params['min_node'] = 6 

1639 

1640 return rnd_params 

1641 

1642 

1643class ERKStrategy(DIRKStrategy): 

1644 """ 

1645 Explicit embedded RK using Cash-Karp's method 

1646 """ 

1647 

1648 def __init__(self, **kwargs): 

1649 ''' 

1650 Initialization routine 

1651 ''' 

1652 super().__init__(**kwargs) 

1653 self.color = list(cmap.values())[8] 

1654 self.marker = 'x' 

1655 self.name = 'ERK' 

1656 self.bar_plot_x_label = 'ERK5(4)' 

1657 

1658 def get_description_for_tolerance(self, problem, param, **kwargs): 

1659 desc = {} 

1660 if problem.__name__ == 'run_Schroedinger': 

1661 desc['problem_params'] = {'lintol': param} 

1662 

1663 return desc 

1664 

1665 @property 

1666 def label(self): 

1667 return 'CK5(4)' 

1668 

1669 def get_random_params(self, problem, num_procs): 

1670 ''' 

1671 Routine to get parameters for the randomization of faults 

1672 

1673 Args: 

1674 problem: A function that runs a pySDC problem, see imports for available problems 

1675 num_procs (int): Number of processes you intend to run with 

1676 

1677 Returns: 

1678 dict: Randomization parameters 

1679 ''' 

1680 rnd_params = super().get_random_params(problem, num_procs) 

1681 rnd_params['min_node'] = 7 

1682 

1683 return rnd_params 

1684 

1685 def get_custom_description(self, problem, num_procs=1): 

1686 from pySDC.implementations.sweeper_classes.Runge_Kutta import Cash_Karp 

1687 

1688 desc = super().get_custom_description(problem, num_procs) 

1689 desc['sweeper_class'] = Cash_Karp 

1690 

1691 if problem.__name__ == "run_AC": 

1692 desc['level_params']['dt'] = 2e-5 

1693 return desc 

1694 

1695 def get_reference_value(self, problem, key, op, num_procs=1): 

1696 """ 

1697 Get a reference value for a given problem for testing in CI. 

1698 

1699 Args: 

1700 problem: A function that runs a pySDC problem, see imports for available problems 

1701 key (str): The name of the variable you want to compare 

1702 op (function): The operation you want to apply to the data 

1703 num_procs (int): Number of processes 

1704 

1705 Returns: 

1706 The reference value 

1707 """ 

1708 if problem.__name__ == "run_Lorenz": 

1709 if key == 'work_newton' and op == sum: 

1710 return 0 

1711 elif key == 'e_global_post_run' and op == max: 

1712 return 1.509206128957885e-07 

1713 

1714 super().get_reference_value(problem, key, op, num_procs) 

1715 

1716 

1717class DoubleAdaptivityStrategy(AdaptivityStrategy): 

1718 ''' 

1719 Adaptivity based both on embedded estimate and on residual 

1720 ''' 

1721 

1722 def __init__(self, **kwargs): 

1723 ''' 

1724 Initialization routine 

1725 ''' 

1726 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

1727 

1728 kwargs['skip_residual_computation'] = 'all' 

1729 super().__init__(**kwargs) 

1730 self.color = list(cmap.values())[7] 

1731 self.marker = '^' 

1732 self.name = 'double_adaptivity' 

1733 self.bar_plot_x_label = 'double adaptivity' 

1734 self.precision_parameter = 'e_tol' 

1735 self.precision_parameter_loc = ['convergence_controllers', Adaptivity, 'e_tol'] 

1736 self.residual_e_tol_ratio = 1.0 

1737 self.residual_e_tol_abs = None 

1738 

1739 @property 

1740 def label(self): 

1741 return 'double adaptivity' 

1742 

1743 def get_custom_description(self, problem, num_procs): 

1744 ''' 

1745 Routine to get a custom description that adds adaptivity 

1746 

1747 Args: 

1748 problem: A function that runs a pySDC problem, see imports for available problems 

1749 num_procs (int): Number of processes you intend to run with 

1750 

1751 Returns: 

1752 The custom descriptions you can supply to the problem when running it 

1753 ''' 

1754 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityResidual, Adaptivity 

1755 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1756 

1757 custom_description = super().get_custom_description(problem, num_procs) 

1758 

1759 if self.residual_e_tol_abs: 

1760 e_tol = self.residual_e_tol_abs 

1761 else: 

1762 e_tol = custom_description['convergence_controllers'][Adaptivity]['e_tol'] * self.residual_e_tol_ratio 

1763 custom_description['convergence_controllers'][AdaptivityResidual] = { 

1764 'e_tol': e_tol, 

1765 'allowed_modifications': ['decrease'], 

1766 } 

1767 

1768 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = { 

1769 'max_restarts': 15 

1770 } 

1771 

1772 return custom_description 

1773 

1774 def get_reference_value(self, problem, key, op, num_procs=1): 

1775 """ 

1776 Get a reference value for a given problem for testing in CI. 

1777 

1778 Args: 

1779 problem: A function that runs a pySDC problem, see imports for available problems 

1780 key (str): The name of the variable you want to compare 

1781 op (function): The operation you want to apply to the data 

1782 num_procs (int): Number of processes 

1783 

1784 Returns: 

1785 The reference value 

1786 """ 

1787 if problem.__name__ == 'run_Lorenz': 

1788 if key == 'work_newton' and op == sum: 

1789 return 2989 

1790 elif key == 'e_global_post_run' and op == max: 

1791 return 5.636763944494305e-08 

1792 

1793 super().get_reference_value(problem, key, op, num_procs) 

1794 

1795 

1796class AdaptivityAvoidRestartsStrategy(AdaptivityStrategy): 

1797 """ 

1798 Adaptivity with the avoid restarts option 

1799 """ 

1800 

1801 @property 

1802 def label(self): 

1803 return 'adaptivity (avoid restarts)' 

1804 

1805 def get_custom_description(self, problem, num_procs): 

1806 ''' 

1807 Routine to get a custom description that adds adaptivity 

1808 

1809 Args: 

1810 problem: A function that runs a pySDC problem, see imports for available problems 

1811 num_procs (int): Number of processes you intend to run with 

1812 

1813 Returns: 

1814 The custom descriptions you can supply to the problem when running it 

1815 ''' 

1816 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

1817 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1818 

1819 custom_description = super().get_custom_description(problem, num_procs) 

1820 

1821 custom_description['convergence_controllers'][Adaptivity]['avoid_restarts'] = True 

1822 

1823 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = { 

1824 'max_restarts': 15 

1825 } 

1826 

1827 return custom_description 

1828 

1829 def get_reference_value(self, problem, key, op, num_procs=1): 

1830 """ 

1831 Get a reference value for a given problem for testing in CI. 

1832 

1833 Args: 

1834 problem: A function that runs a pySDC problem, see imports for available problems 

1835 key (str): The name of the variable you want to compare 

1836 op (function): The operation you want to apply to the data 

1837 num_procs (int): Number of processes 

1838 

1839 Returns: 

1840 The reference value 

1841 """ 

1842 if problem.__name__ == "run_Lorenz": 

1843 if key == 'work_newton' and op == sum: 

1844 return 2989 

1845 elif key == 'e_global_post_run' and op == max: 

1846 return 5.636763944494305e-08 

1847 

1848 super().get_reference_value(problem, key, op, num_procs) 

1849 

1850 

1851class AdaptivityInterpolationStrategy(AdaptivityStrategy): 

1852 """ 

1853 Adaptivity with interpolation between restarts 

1854 """ 

1855 

1856 @property 

1857 def label(self): 

1858 return 'adaptivity+interpolation' 

1859 

1860 def get_custom_description(self, problem, num_procs): 

1861 ''' 

1862 Routine to get a custom description that adds adaptivity 

1863 

1864 Args: 

1865 problem: A function that runs a pySDC problem, see imports for available problems 

1866 num_procs (int): Number of processes you intend to run with 

1867 

1868 Returns: 

1869 The custom descriptions you can supply to the problem when running it 

1870 ''' 

1871 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

1872 from pySDC.implementations.convergence_controller_classes.interpolate_between_restarts import ( 

1873 InterpolateBetweenRestarts, 

1874 ) 

1875 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1876 

1877 custom_description = super().get_custom_description(problem, num_procs) 

1878 

1879 custom_description['convergence_controllers'][Adaptivity]['avoid_restarts'] = False 

1880 custom_description['convergence_controllers'][InterpolateBetweenRestarts] = {} 

1881 

1882 custom_description['convergence_controllers'][BasicRestarting.get_implementation(useMPI=self.useMPI)] = { 

1883 'max_restarts': 15 

1884 } 

1885 

1886 return custom_description 

1887 

1888 def get_reference_value(self, problem, key, op, num_procs=1): 

1889 """ 

1890 Get a reference value for a given problem for testing in CI. 

1891 

1892 Args: 

1893 problem: A function that runs a pySDC problem, see imports for available problems 

1894 key (str): The name of the variable you want to compare 

1895 op (function): The operation you want to apply to the data 

1896 num_procs (int): Number of processes 

1897 

1898 Returns: 

1899 The reference value 

1900 """ 

1901 if problem.__name__ == "run_Lorenz": 

1902 if key == 'work_newton' and op == sum: 

1903 return 6659 

1904 elif key == 'e_global_post_run' and op == max: 

1905 return 2.9780002756552015e-06 

1906 

1907 super().get_reference_value(problem, key, op, num_procs) 

1908 

1909 

1910class AdaptivityExtrapolationWithinQStrategy(InexactBaseStrategy): 

1911 ''' 

1912 Adaptivity based on extrapolation between collocation nodes as a resilience strategy 

1913 ''' 

1914 

1915 def __init__(self, **kwargs): 

1916 ''' 

1917 Initialization routine 

1918 ''' 

1919 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityExtrapolationWithinQ 

1920 

1921 self.restol = None 

1922 super().__init__(**kwargs) 

1923 self.color = list(cmap.values())[8] 

1924 self.marker = '*' 

1925 self.name = 'adaptivity_extraQ' 

1926 self.bar_plot_x_label = 'adaptivity Q' 

1927 self.precision_parameter = 'e_tol' 

1928 self.adaptive_coll_params = {} 

1929 self.precision_parameter_loc = ['convergence_controllers', AdaptivityExtrapolationWithinQ, 'e_tol'] 

1930 

1931 def get_custom_description(self, problem, num_procs): 

1932 ''' 

1933 Routine to get a custom description that adds adaptivity 

1934 

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 

1938 

1939 Returns: 

1940 The custom descriptions you can supply to the problem when running it 

1941 ''' 

1942 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityExtrapolationWithinQ 

1943 

1944 custom_description = {} 

1945 

1946 dt_max = np.inf 

1947 dt_min = 1e-5 

1948 

1949 if problem.__name__ == "run_vdp": 

1950 e_tol = 2e-5 

1951 dt_min = 1e-3 

1952 elif problem.__name__ == "run_piline": 

1953 e_tol = 1e-7 

1954 dt_min = 1e-2 

1955 elif problem.__name__ == "run_Lorenz": 

1956 e_tol = 2e-5 

1957 dt_min = 1e-3 

1958 elif problem.__name__ == "run_Schroedinger": 

1959 e_tol = 4e-6 

1960 dt_min = 1e-3 

1961 elif problem.__name__ == "run_quench": 

1962 e_tol = 1e-5 

1963 dt_min = 1e-3 

1964 dt_max = 1e2 

1965 elif problem.__name__ == "run_AC": 

1966 e_tol = 1e-4 

1967 else: 

1968 raise NotImplementedError('I don\'t have a tolerance for adaptivity for your problem. Please add one to the\ 

1969 strategy') 

1970 

1971 custom_description['convergence_controllers'] = { 

1972 AdaptivityExtrapolationWithinQ: { 

1973 'e_tol': e_tol, 

1974 'dt_min': dt_min, 

1975 'dt_max': dt_max, 

1976 'restol_rel': 1e-2, 

1977 'restart_at_maxiter': True, 

1978 } 

1979 } 

1980 return merge_descriptions(super().get_custom_description(problem, num_procs), custom_description) 

1981 

1982 def get_reference_value(self, problem, key, op, num_procs=1): 

1983 """ 

1984 Get a reference value for a given problem for testing in CI. 

1985 

1986 Args: 

1987 problem: A function that runs a pySDC problem, see imports for available problems 

1988 key (str): The name of the variable you want to compare 

1989 op (function): The operation you want to apply to the data 

1990 num_procs (int): Number of processes 

1991 

1992 Returns: 

1993 The reference value 

1994 """ 

1995 if problem.__name__ == "run_Lorenz": 

1996 if key == 'work_newton' and op == sum: 

1997 return 2198 

1998 elif key == 'e_global_post_run' and op == max: 

1999 return 5.412657451131508e-07 

2000 

2001 super().get_reference_value(problem, key, op, num_procs) 

2002 

2003 

2004class AdaptivityPolynomialError(InexactBaseStrategy): 

2005 ''' 

2006 Adaptivity based on extrapolation between collocation nodes as a resilience strategy 

2007 ''' 

2008 

2009 def __init__(self, interpolate_between_restarts=False, use_restol_rel=True, max_slope=4, **kwargs): 

2010 ''' 

2011 Initialization routine 

2012 ''' 

2013 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError 

2014 

2015 self.restol = None 

2016 super().__init__(**kwargs) 

2017 self.color = list(cmap.values())[9] 

2018 self.marker = '+' 

2019 self.name = 'adaptivity-inter' 

2020 self.bar_plot_x_label = 'adaptivity Q' 

2021 self.precision_parameter = 'e_tol' 

2022 self.adaptive_coll_params = {} 

2023 self.precision_parameter_loc = ['convergence_controllers', AdaptivityPolynomialError, 'e_tol'] 

2024 self.interpolate_between_restarts = interpolate_between_restarts 

2025 self.use_restol_rel = use_restol_rel 

2026 self.max_slope = max_slope 

2027 

2028 def get_custom_description(self, problem, num_procs): 

2029 ''' 

2030 Routine to get a custom description that adds adaptivity 

2031 

2032 Args: 

2033 problem: A function that runs a pySDC problem, see imports for available problems 

2034 num_procs (int): Number of processes you intend to run with 

2035 

2036 Returns: 

2037 The custom descriptions you can supply to the problem when running it 

2038 ''' 

2039 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError 

2040 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter 

2041 from pySDC.implementations.convergence_controller_classes.check_convergence import CheckConvergence 

2042 

2043 base_params = super().get_custom_description(problem, num_procs) 

2044 custom_description = {} 

2045 

2046 dt_max = np.inf 

2047 restol_rel = 1e-4 

2048 restol_min = 1e-12 

2049 restol_max = 1e-5 

2050 dt_slope_min = 0 

2051 dt_min = 0 

2052 abort_at_growing_residual = True 

2053 level_params = {} 

2054 problem_params = {} 

2055 beta = 0.9 

2056 

2057 if problem.__name__ == "run_vdp": 

2058 e_tol = 6e-4 

2059 level_params['dt'] = 0.1 

2060 restol_rel = 1e-5 

2061 restol_min = 1e-12 

2062 dt_min = 1e-7 

2063 problem_params['newton_tol'] = 1e-14 

2064 elif problem.__name__ == "run_piline": 

2065 e_tol = 1e-7 

2066 elif problem.__name__ == "run_Lorenz": 

2067 e_tol = 2e-4 

2068 elif problem.__name__ == "run_Schroedinger": 

2069 e_tol = 3e-5 

2070 elif problem.__name__ == "run_quench": 

2071 e_tol = 1e-7 

2072 level_params['dt'] = 50.0 

2073 restol_min = 1e-11 

2074 restol_rel = 1e-1 

2075 elif problem.__name__ == "run_AC": 

2076 e_tol = 1.0e-4 

2077 restol_rel = 1e-3 if num_procs == 4 else 1e-3 

2078 # dt_max = 0.1 * base_params['problem_params']['eps'] ** 2 

2079 elif problem.__name__ == "run_RBC": 

2080 e_tol = 5e-2 if num_procs == 4 else 5e-3 

2081 dt_slope_min = 1.0 

2082 abort_at_growing_residual = False 

2083 restol_rel = 1e-2 if num_procs == 4 else 1e-4 

2084 restol_max = 1e-1 

2085 restol_min = 5e-8 

2086 self.max_slope = 4 

2087 beta = 0.5 

2088 level_params['e_tol'] = 1e-5 

2089 elif problem.__name__ == 'run_GS': 

2090 e_tol = 1e-4 

2091 restol_rel = 4e-3 

2092 restol_max = 1e-4 

2093 restol_min = 1e-9 

2094 else: 

2095 raise NotImplementedError('I don\'t have a tolerance for adaptivity for your problem. Please add one to the\ 

2096 strategy') 

2097 

2098 custom_description['convergence_controllers'] = { 

2099 AdaptivityPolynomialError: { 

2100 'e_tol': e_tol, 

2101 'restol_rel': restol_rel if self.use_restol_rel else 1e-11, 

2102 'restol_min': restol_min if self.use_restol_rel else 1e-12, 

2103 'restol_max': restol_max if self.use_restol_rel else 1e-5, 

2104 'restart_at_maxiter': True, 

2105 'factor_if_not_converged': self.max_slope, 

2106 'interpolate_between_restarts': self.interpolate_between_restarts, 

2107 'abort_at_growing_residual': abort_at_growing_residual, 

2108 'beta': beta, 

2109 }, 

2110 StepSizeLimiter: { 

2111 'dt_max': dt_max, 

2112 'dt_slope_max': self.max_slope, 

2113 'dt_min': dt_min, 

2114 'dt_rel_min_slope': dt_slope_min, 

2115 }, 

2116 } 

2117 custom_description['level_params'] = level_params 

2118 custom_description['problem_params'] = problem_params 

2119 

2120 return merge_descriptions(base_params, custom_description) 

2121 

2122 def get_custom_description_for_faults(self, problem, num_procs, *args, **kwargs): 

2123 desc = self.get_custom_description(problem, num_procs, *args, **kwargs) 

2124 if problem.__name__ == "run_quench": 

2125 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError 

2126 

2127 desc['convergence_controllers'][AdaptivityPolynomialError]['e_tol'] = 1e-7 * 11 

2128 desc['level_params']['dt'] = 4.0 

2129 elif problem.__name__ == "run_AC": 

2130 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError 

2131 

2132 desc['convergence_controllers'][AdaptivityPolynomialError]['e_tol'] = 6e-3 if num_procs == 4 else 1e-3 

2133 if num_procs == 4: 

2134 desc['step_params'] = {'maxiter': 50} 

2135 elif problem.__name__ == "run_Lorenz": 

2136 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError 

2137 

2138 desc['convergence_controllers'][AdaptivityPolynomialError]['e_tol'] = 2e-4 

2139 desc['convergence_controllers'][AdaptivityPolynomialError]['restol_min'] = 1e-11 

2140 desc['convergence_controllers'][AdaptivityPolynomialError]['restol_rel'] = 1e-11 

2141 elif problem.__name__ == "run_vdp": 

2142 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError 

2143 from pySDC.implementations.convergence_controller_classes.inexactness import NewtonInexactness 

2144 

2145 desc['step_params'] = {'maxiter': 16} 

2146 desc['problem_params'] = { 

2147 'u0': np.array([2.0, 0], dtype=np.float64), 

2148 'mu': 5, 

2149 'crash_at_maxiter': False, 

2150 'newton_tol': 1e-11, 

2151 'stop_at_nan': False, 

2152 } 

2153 desc['convergence_controllers'][AdaptivityPolynomialError]['e_tol'] = 5e-4 

2154 desc['convergence_controllers'][AdaptivityPolynomialError]['restol_rel'] = 8e-5 

2155 desc['convergence_controllers'].pop(NewtonInexactness) 

2156 desc['level_params'] = {'dt': 4.5e-2} 

2157 return desc 

2158 

2159 def get_random_params(self, problem, num_procs): 

2160 ''' 

2161 Routine to get parameters for the randomization of faults 

2162 

2163 Args: 

2164 problem: A function that runs a pySDC problem, see imports for available problems 

2165 num_procs (int): Number of processes you intend to run with 

2166 

2167 Returns: 

2168 dict: Randomization parameters 

2169 ''' 

2170 

2171 rnd_params = super().get_random_params(problem, num_procs) 

2172 if problem.__name__ == "run_quench": 

2173 rnd_params['iteration'] = 1 

2174 elif problem.__name__ == 'run_Lorenz': 

2175 rnd_params['iteration'] = 5 

2176 return rnd_params 

2177 

2178 def get_reference_value(self, problem, key, op, num_procs=1): 

2179 """ 

2180 Get a reference value for a given problem for testing in CI. 

2181 

2182 Args: 

2183 problem: A function that runs a pySDC problem, see imports for available problems 

2184 key (str): The name of the variable you want to compare 

2185 op (function): The operation you want to apply to the data 

2186 num_procs (int): Number of processes 

2187 

2188 Returns: 

2189 The reference value 

2190 """ 

2191 if problem.__name__ == "run_Lorenz": 

2192 if key == 'work_newton' and op == sum: 

2193 return 2123 

2194 elif key == 'e_global_post_run' and op == max: 

2195 return 7.931560830343187e-08 

2196 

2197 super().get_reference_value(problem, key, op, num_procs) 

2198 

2199 @property 

2200 def label(self): 

2201 return r'$\Delta t$-$k$-adaptivity'