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

1011 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-04 07:15 +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( 

613 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\ 

614 strategy' 

615 ) 

616 

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

618 'e_tol': e_tol, 

619 'dt_slope_max': dt_slope_max, 

620 'dt_rel_min_slope': dt_slope_min, 

621 'beta': beta, 

622 } 

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

624 'dt_max': dt_max, 

625 } 

626 return merge_descriptions(base_params, custom_description) 

627 

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

629 """ 

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

631 

632 Args: 

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

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

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

636 num_procs (int): Number of processes 

637 

638 Returns: 

639 The reference value 

640 """ 

641 if problem.__name__ == 'run_Lorenz': 

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

643 return 2989 

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

645 return 5.636767497207984e-08 

646 

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

648 

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

650 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter 

651 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

652 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeSlopeLimiter 

653 from pySDC.projects.Resilience.RBC import ReachTendExactly 

654 

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

656 if problem.__name__ == "run_quench": 

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

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

659 elif problem.__name__ == "run_AC": 

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

661 elif problem.__name__ == "run_GS": 

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

663 elif problem.__name__ == "run_vdp": 

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

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

666 desc['problem_params'] = { 

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

668 'mu': 5, 

669 'crash_at_maxiter': True, 

670 'newton_tol': 1e-8, 

671 'stop_at_nan': True, 

672 'relative_tolerance': False, 

673 } 

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

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

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

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

678 return desc 

679 

680 

681class AdaptivityRestartFirstStep(AdaptivityStrategy): 

682 def __init__(self, **kwargs): 

683 super().__init__(**kwargs) 

684 self.color = 'teal' 

685 self.name = 'adaptivityRestartFirstStep' 

686 

687 def get_custom_description(self, problem, num_procs): 

688 ''' 

689 Add the other version of basic restarting. 

690 

691 Args: 

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

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

694 

695 Returns: 

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

697 ''' 

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

699 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

700 

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

702 'max_restarts': 15, 

703 'restart_from_first_step': True, 

704 } 

705 return custom_description 

706 

707 @property 

708 def label(self): 

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

710 

711 

712class AdaptiveHotRodStrategy(Strategy): 

713 ''' 

714 Adaptivity + Hot Rod as a resilience strategy 

715 ''' 

716 

717 def __init__(self, **kwargs): 

718 ''' 

719 Initialization routine 

720 ''' 

721 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

722 

723 kwargs['skip_residual_computation'] = 'all' 

724 super().__init__(**kwargs) 

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

726 self.marker = '.' 

727 self.name = 'adaptive Hot Rod' 

728 self.bar_plot_x_label = 'adaptive\nHot Rod' 

729 self.precision_parameter = 'e_tol' 

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

731 

732 def get_custom_description(self, problem, num_procs): 

733 ''' 

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

735 

736 Args: 

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

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

739 

740 Returns: 

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

742 ''' 

743 from pySDC.implementations.convergence_controller_classes.hotrod import HotRod 

744 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

745 

746 if problem.__name__ == "run_vdp": 

747 e_tol = 3e-7 

748 dt_min = 1e-3 

749 maxiter = 4 

750 HotRod_tol = 2e-6 

751 elif problem.__name__ == "run_Lorenz": 

752 e_tol = 3e-7 

753 dt_min = 1e-3 

754 maxiter = 4 

755 HotRod_tol = 2e-6 

756 else: 

757 raise NotImplementedError( 

758 'I don\'t have a tolerance for adaptive Hot Rod for your problem. Please add one \ 

759to the strategy' 

760 ) 

761 

762 no_storage = num_procs > 1 

763 

764 custom_description = { 

765 'convergence_controllers': { 

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

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

768 }, 

769 'step_params': {'maxiter': maxiter}, 

770 } 

771 

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

773 

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

775 """ 

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

777 

778 Args: 

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

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

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

782 num_procs (int): Number of processes 

783 

784 Returns: 

785 The reference value 

786 """ 

787 if problem.__name__ == "run_Lorenz": 

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

789 return 5092 

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

791 return 4.107116318152748e-06 

792 

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

794 

795 

796class IterateStrategy(Strategy): 

797 ''' 

798 Iterate for as much as you want 

799 ''' 

800 

801 def __init__(self, **kwargs): 

802 ''' 

803 Initialization routine 

804 ''' 

805 kwargs['skip_residual_computation'] = 'most' 

806 super().__init__(**kwargs) 

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

808 self.marker = 'v' 

809 self.name = 'iterate' 

810 self.bar_plot_x_label = 'iterate' 

811 self.precision_parameter = 'restol' 

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

813 

814 @property 

815 def label(self): 

816 return r'$k$-adaptivity' 

817 

818 def get_custom_description(self, problem, num_procs): 

819 ''' 

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

821 

822 Args: 

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

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

825 

826 Returns: 

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

828 ''' 

829 restol = -1 

830 e_tol = -1 

831 

832 if problem.__name__ == "run_piline": 

833 restol = 2.3e-8 

834 elif problem.__name__ == "run_vdp": 

835 restol = 9e-7 

836 elif problem.__name__ == "run_Lorenz": 

837 restol = 16e-7 

838 elif problem.__name__ == "run_Schroedinger": 

839 restol = 6.5e-7 

840 elif problem.__name__ == "run_quench": 

841 restol = 1e-7 

842 elif problem.__name__ == "run_AC": 

843 restol = 1e-11 

844 elif problem.__name__ == "run_RBC": 

845 restol = 1e-4 

846 elif problem.__name__ == "run_GS": 

847 restol = 1e-4 

848 else: 

849 raise NotImplementedError( 

850 'I don\'t have a residual tolerance for your problem. Please add one to the \ 

851strategy' 

852 ) 

853 

854 custom_description = { 

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

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

857 } 

858 

859 if problem.__name__ == "run_quench": 

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

861 

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

863 

864 def get_random_params(self, problem, num_procs): 

865 ''' 

866 Routine to get parameters for the randomization of faults 

867 

868 Args: 

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

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

871 

872 Returns: 

873 dict: Randomization parameters 

874 ''' 

875 

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

877 if problem.__name__ == "run_quench": 

878 rnd_params['iteration'] = 1 

879 return rnd_params 

880 

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

882 """ 

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

884 

885 Args: 

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

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

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

889 num_procs (int): Number of processes 

890 

891 Returns: 

892 The reference value 

893 """ 

894 if problem.__name__ == "run_Lorenz": 

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

896 return 9200 

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

898 return 2.139863344829962e-05 

899 

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

901 

902 

903class kAdaptivityStrategy(IterateStrategy): 

904 def __init__(self, **kwargs): 

905 super().__init__(**kwargs) 

906 self.precision_parameter = 'dt' 

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

908 

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

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

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

912 if problem.__name__ == "run_quench": 

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

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

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

916 elif problem.__name__ == "run_AC": 

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

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

919 elif problem.__name__ == "run_RBC": 

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

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

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

923 elif problem.__name__ == "run_GS": 

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

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

926 return desc 

927 

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

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

930 if problem.__name__ == 'run_quench': 

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

932 elif problem.__name__ == 'run_AC': 

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

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

935 elif problem.__name__ == 'run_RBC': 

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

937 elif problem.__name__ == 'run_Lorenz': 

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

939 elif problem.__name__ == "run_vdp": 

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

941 desc['problem_params'] = { 

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

943 'mu': 5, 

944 'crash_at_maxiter': False, 

945 'newton_tol': 1e-11, 

946 'stop_at_nan': False, 

947 } 

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

949 return desc 

950 

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

952 """ 

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

954 

955 Args: 

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

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

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

959 num_procs (int): Number of processes 

960 

961 Returns: 

962 The reference value 

963 """ 

964 if problem.__name__ == "run_Lorenz": 

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

966 return 12350 

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

968 return 1.3527453646133836e-07 

969 

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

971 

972 

973class HotRodStrategy(Strategy): 

974 ''' 

975 Hot Rod as a resilience strategy 

976 ''' 

977 

978 def __init__(self, **kwargs): 

979 ''' 

980 Initialization routine 

981 ''' 

982 kwargs['skip_residual_computation'] = 'all' 

983 super().__init__(**kwargs) 

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

985 self.marker = '^' 

986 self.name = 'Hot Rod' 

987 self.bar_plot_x_label = 'Hot Rod' 

988 self.precision_parameter = 'dt' 

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

990 

991 def get_custom_description(self, problem, num_procs): 

992 ''' 

993 Routine to get a custom description that adds Hot Rod 

994 

995 Args: 

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

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

998 

999 Returns: 

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

1001 ''' 

1002 from pySDC.implementations.convergence_controller_classes.hotrod import HotRod 

1003 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestartingNonMPI 

1004 

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

1006 if problem.__name__ == "run_vdp": 

1007 # if num_procs == 4: 

1008 # HotRod_tol = 1.800804e-04 

1009 # elif num_procs == 5: 

1010 # HotRod_tol = 9.329361e-05 

1011 # else: # 1 process 

1012 # HotRod_tol = 1.347949e-06 

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

1014 HotRod_tol = 7.2e-05 

1015 maxiter = 6 

1016 elif problem.__name__ == "run_Lorenz": 

1017 if num_procs == 5: 

1018 HotRod_tol = 9.539348e-06 

1019 elif num_procs == 4: 

1020 HotRod_tol = 3.201e-6 

1021 else: 

1022 HotRod_tol = 7.720589e-07 

1023 maxiter = 6 

1024 elif problem.__name__ == "run_Schroedinger": 

1025 if num_procs == 5: 

1026 HotRod_tol = 2.497697e-06 

1027 elif num_procs == 4: 

1028 HotRod_tol = 1.910405e-06 

1029 else: 

1030 HotRod_tol = 4.476790e-07 

1031 maxiter = 6 

1032 elif problem.__name__ == "run_quench": 

1033 if num_procs == 5: 

1034 HotRod_tol = 1.017534e-03 

1035 elif num_procs == 4: 

1036 HotRod_tol = 1.017534e-03 

1037 else: 

1038 HotRod_tol = 5.198620e-04 

1039 maxiter = 6 

1040 elif problem.__name__ == 'run_AC': 

1041 HotRod_tol = 9.564437e-06 

1042 maxiter = 6 

1043 elif problem.__name__ == 'run_RBC': 

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

1045 maxiter = 6 

1046 elif problem.__name__ == 'run_GS': 

1047 HotRod_tol = 3.22e-5 

1048 maxiter = 6 

1049 else: 

1050 raise NotImplementedError( 

1051 'I don\'t have a tolerance for Hot Rod for your problem. Please add one to the\ 

1052 strategy' 

1053 ) 

1054 

1055 no_storage = False # num_procs > 1 

1056 

1057 custom_description = { 

1058 'convergence_controllers': { 

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

1060 BasicRestartingNonMPI: { 

1061 'max_restarts': 2, 

1062 'crash_after_max_restarts': False, 

1063 'restart_from_first_step': True, 

1064 }, 

1065 }, 

1066 'step_params': {'maxiter': maxiter}, 

1067 'level_params': {}, 

1068 } 

1069 if problem.__name__ == "run_AC": 

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

1071 return merge_descriptions(base_params, custom_description) 

1072 

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

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

1075 if problem.__name__ == "run_quench": 

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

1077 elif problem.__name__ == "run_AC": 

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

1079 elif problem.__name__ == "run_GS": 

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

1081 elif problem.__name__ == "run_vdp": 

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

1083 desc['problem_params'] = { 

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

1085 'mu': 5, 

1086 'crash_at_maxiter': False, 

1087 'newton_tol': 1e-11, 

1088 'stop_at_nan': False, 

1089 } 

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

1091 return desc 

1092 

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

1094 """ 

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

1096 

1097 Args: 

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

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

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

1101 num_procs (int): Number of processes 

1102 

1103 Returns: 

1104 The reference value 

1105 """ 

1106 if problem.__name__ == "run_Lorenz": 

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

1108 return 12350 

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

1110 return 1.3527453646133836e-07 

1111 

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

1113 

1114 

1115class AdaptivityCollocationStrategy(InexactBaseStrategy): 

1116 ''' 

1117 Adaptivity based on collocation as a resilience strategy 

1118 ''' 

1119 

1120 def __init__(self, **kwargs): 

1121 ''' 

1122 Initialization routine 

1123 ''' 

1124 kwargs = { 

1125 'skip_residual_computation': 'most', 

1126 **kwargs, 

1127 } 

1128 

1129 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityCollocation 

1130 

1131 self.restol = None 

1132 super().__init__(**kwargs) 

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

1134 self.marker = '*' 

1135 self.name = 'adaptivity_coll' 

1136 self.bar_plot_x_label = 'adaptivity collocation' 

1137 self.precision_parameter = 'e_tol' 

1138 self.adaptive_coll_params = {} 

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

1140 

1141 def get_custom_description(self, problem, num_procs): 

1142 ''' 

1143 Routine to get a custom description that adds adaptivity 

1144 

1145 Args: 

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

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

1148 

1149 Returns: 

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

1151 ''' 

1152 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityCollocation 

1153 

1154 custom_description = {} 

1155 

1156 dt_max = np.inf 

1157 dt_min = 1e-5 

1158 

1159 if problem.__name__ == "run_piline": 

1160 e_tol = 1e-7 

1161 dt_min = 1e-2 

1162 elif problem.__name__ == "run_vdp": 

1163 e_tol = 2e-5 

1164 dt_min = 1e-3 

1165 elif problem.__name__ == "run_Lorenz": 

1166 e_tol = 2e-5 

1167 dt_min = 1e-3 

1168 elif problem.__name__ == "run_Schroedinger": 

1169 e_tol = 4e-6 

1170 dt_min = 1e-3 

1171 elif problem.__name__ == "run_quench": 

1172 e_tol = 1e-5 

1173 dt_min = 1e-3 

1174 dt_max = 1e2 

1175 elif problem.__name__ == "run_AC": 

1176 e_tol = 1e-4 

1177 else: 

1178 raise NotImplementedError( 

1179 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\ 

1180 strategy' 

1181 ) 

1182 

1183 custom_description['convergence_controllers'] = { 

1184 AdaptivityCollocation: { 

1185 'e_tol': e_tol, 

1186 'dt_min': dt_min, 

1187 'dt_max': dt_max, 

1188 'adaptive_coll_params': self.adaptive_coll_params, 

1189 'restol_rel': 1e-2, 

1190 } 

1191 } 

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

1193 

1194 

1195class AdaptivityCollocationTypeStrategy(AdaptivityCollocationStrategy): 

1196 def __init__(self, **kwargs): 

1197 super().__init__(**kwargs) 

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

1199 self.marker = '.' 

1200 self.adaptive_coll_params = { 

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

1202 'do_coll_update': [False, True], 

1203 } 

1204 

1205 @property 

1206 def label(self): 

1207 return 'adaptivity type' 

1208 

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

1210 """ 

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

1212 

1213 Args: 

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

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

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

1217 num_procs (int): Number of processes 

1218 

1219 Returns: 

1220 The reference value 

1221 """ 

1222 if problem.__name__ == "run_Lorenz": 

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

1224 return 1025 

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

1226 return 4.266975256683736e-06 

1227 

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

1229 

1230 

1231class AdaptivityCollocationRefinementStrategy(AdaptivityCollocationStrategy): 

1232 def __init__(self, **kwargs): 

1233 super().__init__(**kwargs) 

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

1235 self.marker = '^' 

1236 self.adaptive_coll_params = { 

1237 'num_nodes': [2, 3], 

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

1239 'do_coll_update': [True, False], 

1240 } 

1241 

1242 @property 

1243 def label(self): 

1244 return 'adaptivity refinement' 

1245 

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

1247 """ 

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

1249 

1250 Args: 

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

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

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

1254 num_procs (int): Number of processes 

1255 

1256 Returns: 

1257 The reference value 

1258 """ 

1259 if problem.__name__ == "run_Lorenz": 

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

1261 return 917 

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

1263 return 1.0874929465387595e-05 

1264 

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

1266 

1267 

1268class AdaptivityCollocationDerefinementStrategy(AdaptivityCollocationStrategy): 

1269 def __init__(self, **kwargs): 

1270 super().__init__(**kwargs) 

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

1272 self.marker = '^' 

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

1274 

1275 @property 

1276 def label(self): 

1277 return 'adaptivity de-refinement' 

1278 

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

1280 """ 

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

1282 

1283 Args: 

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

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

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

1287 num_procs (int): Number of processes 

1288 

1289 Returns: 

1290 The reference value 

1291 """ 

1292 if problem.__name__ == 'run_Lorenz': 

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

1294 return 1338 

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

1296 return 0.0001013999955041811 

1297 

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

1299 

1300 

1301class DIRKStrategy(AdaptivityStrategy): 

1302 ''' 

1303 DIRK4(3) 

1304 ''' 

1305 

1306 def __init__(self, **kwargs): 

1307 ''' 

1308 Initialization routine 

1309 ''' 

1310 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK 

1311 

1312 super().__init__(**kwargs) 

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

1314 self.marker = '^' 

1315 self.name = 'DIRK' 

1316 self.bar_plot_x_label = 'DIRK4(3)' 

1317 self.precision_parameter = 'e_tol' 

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

1319 self.max_steps = 1e5 

1320 

1321 @property 

1322 def label(self): 

1323 return 'DIRK4(3)' 

1324 

1325 def get_custom_description(self, problem, num_procs): 

1326 ''' 

1327 Routine to get a custom description that adds adaptivity 

1328 

1329 Args: 

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

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

1332 

1333 Returns: 

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

1335 ''' 

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

1337 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1338 from pySDC.implementations.sweeper_classes.Runge_Kutta import DIRK43 

1339 

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

1341 

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

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

1344 adaptivity_description.pop('sweeper_params', None) 

1345 

1346 rk_params = { 

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

1348 'sweeper_class': DIRK43, 

1349 'convergence_controllers': { 

1350 AdaptivityRK: {'e_tol': e_tol}, 

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

1352 'max_restarts': 49, 

1353 'crash_after_max_restarts': False, 

1354 }, 

1355 }, 

1356 } 

1357 

1358 custom_description = merge_descriptions(adaptivity_description, rk_params) 

1359 

1360 return custom_description 

1361 

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

1363 """ 

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

1365 

1366 Args: 

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

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

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

1370 num_procs (int): Number of processes 

1371 

1372 Returns: 

1373 The reference value 

1374 """ 

1375 if problem.__name__ == "run_Lorenz": 

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

1377 return 5467 

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

1379 return 7.049480537091313e-07 

1380 

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

1382 

1383 def get_random_params(self, problem, num_procs): 

1384 ''' 

1385 Routine to get parameters for the randomization of faults 

1386 

1387 Args: 

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

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

1390 

1391 Returns: 

1392 dict: Randomization parameters 

1393 ''' 

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

1395 rnd_params['iteration'] = 1 

1396 rnd_params['min_node'] = 5 

1397 

1398 return rnd_params 

1399 

1400 

1401class ARKStrategy(AdaptivityStrategy): 

1402 ''' 

1403 ARK5(4) 

1404 ''' 

1405 

1406 def __init__(self, **kwargs): 

1407 ''' 

1408 Initialization routine 

1409 ''' 

1410 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK 

1411 

1412 super().__init__(**kwargs) 

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

1414 self.marker = 'P' 

1415 self.name = 'ARK' 

1416 self.bar_plot_x_label = 'ARK5(4)' 

1417 self.precision_parameter = 'e_tol' 

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

1419 self.max_steps = 1e5 

1420 

1421 @property 

1422 def label(self): 

1423 return 'ARK5(4)' 

1424 

1425 def get_custom_description(self, problem, num_procs): 

1426 ''' 

1427 Routine to get a custom description that adds adaptivity 

1428 

1429 Args: 

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

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

1432 

1433 Returns: 

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

1435 ''' 

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

1437 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeSlopeLimiter 

1438 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1439 from pySDC.implementations.sweeper_classes.Runge_Kutta import ARK548L2SA 

1440 

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

1442 

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

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

1445 adaptivity_description.pop('sweeper_params', None) 

1446 

1447 rk_params = { 

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

1449 'sweeper_class': ARK548L2SA, 

1450 'convergence_controllers': { 

1451 AdaptivityRK: {'e_tol': e_tol}, 

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

1453 'max_restarts': 49, 

1454 'crash_after_max_restarts': False, 

1455 }, 

1456 }, 

1457 } 

1458 

1459 if problem.__name__ == "run_RBC": 

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

1461 

1462 custom_description = merge_descriptions(adaptivity_description, rk_params) 

1463 

1464 return custom_description 

1465 

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

1467 """ 

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

1469 

1470 Args: 

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

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

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

1474 num_procs (int): Number of processes 

1475 

1476 Returns: 

1477 The reference value 

1478 """ 

1479 if problem.__name__ == "run_Schroedinger": 

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

1481 return 0 

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

1483 return 3.1786601531890356e-08 

1484 

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

1486 

1487 

1488class ARK3_CFL_Strategy(BaseStrategy): 

1489 """ 

1490 This is special for RBC with CFL number for accuracy 

1491 """ 

1492 

1493 def __init__(self, **kwargs): 

1494 ''' 

1495 Initialization routine 

1496 ''' 

1497 from pySDC.implementations.problem_classes.RayleighBenard import CFLLimit 

1498 

1499 super().__init__(**kwargs) 

1500 self.color = 'maroon' 

1501 self.marker = '<' 

1502 self.name = 'ARK3' 

1503 self.bar_plot_x_label = 'ARK3' 

1504 self.precision_parameter = 'cfl' 

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

1506 self.max_steps = 1e5 

1507 

1508 @property 

1509 def label(self): 

1510 return 'ARK3' 

1511 

1512 def get_custom_description(self, problem, num_procs): 

1513 ''' 

1514 Args: 

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

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

1517 

1518 Returns: 

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

1520 ''' 

1521 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1522 from pySDC.implementations.sweeper_classes.Runge_Kutta import ARK3 

1523 from pySDC.implementations.problem_classes.RayleighBenard import CFLLimit 

1524 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeSlopeLimiter 

1525 

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

1527 

1528 rk_params = { 

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

1530 'sweeper_class': ARK3, 

1531 'convergence_controllers': { 

1532 CFLLimit: { 

1533 'cfl': 0.5, 

1534 'dt_max': 1.0, 

1535 }, 

1536 StepSizeSlopeLimiter: {'dt_rel_min_slope': 0.2}, 

1537 }, 

1538 } 

1539 

1540 custom_description = merge_descriptions(desc, rk_params) 

1541 

1542 return custom_description 

1543 

1544 

1545class ESDIRKStrategy(AdaptivityStrategy): 

1546 ''' 

1547 ESDIRK5(3) 

1548 ''' 

1549 

1550 def __init__(self, **kwargs): 

1551 ''' 

1552 Initialization routine 

1553 ''' 

1554 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK 

1555 

1556 super().__init__(**kwargs) 

1557 self.color = 'violet' 

1558 self.marker = '^' 

1559 self.name = 'ESDIRK' 

1560 self.bar_plot_x_label = 'ESDIRK5(3)' 

1561 self.precision_parameter = 'e_tol' 

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

1563 self.max_steps = 1e5 

1564 

1565 @property 

1566 def label(self): 

1567 return 'ESDIRK5(3)' 

1568 

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

1570 desc = {} 

1571 if problem.__name__ == 'run_Schroedinger': 

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

1573 return desc 

1574 

1575 def get_custom_description(self, problem, num_procs): 

1576 ''' 

1577 Routine to get a custom description that adds adaptivity 

1578 

1579 Args: 

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

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

1582 

1583 Returns: 

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

1585 ''' 

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

1587 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1588 from pySDC.implementations.sweeper_classes.Runge_Kutta import ESDIRK53 

1589 

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

1591 

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

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

1594 adaptivity_description.pop('sweeper_params', None) 

1595 

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

1597 

1598 rk_params = { 

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

1600 'sweeper_class': ESDIRK53, 

1601 'convergence_controllers': { 

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

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

1604 'max_restarts': 49, 

1605 'crash_after_max_restarts': False, 

1606 }, 

1607 }, 

1608 } 

1609 

1610 custom_description = merge_descriptions(adaptivity_description, rk_params) 

1611 

1612 return custom_description 

1613 

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

1615 """ 

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

1617 

1618 Args: 

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

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

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

1622 num_procs (int): Number of processes 

1623 

1624 Returns: 

1625 The reference value 

1626 """ 

1627 if problem.__name__ == "run_Lorenz": 

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

1629 return 2963 

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

1631 return 4.126039954144289e-09 

1632 

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

1634 

1635 def get_random_params(self, problem, num_procs): 

1636 ''' 

1637 Routine to get parameters for the randomization of faults 

1638 

1639 Args: 

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

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

1642 

1643 Returns: 

1644 dict: Randomization parameters 

1645 ''' 

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

1647 rnd_params['iteration'] = 1 

1648 rnd_params['min_node'] = 6 

1649 

1650 return rnd_params 

1651 

1652 

1653class ERKStrategy(DIRKStrategy): 

1654 """ 

1655 Explicit embedded RK using Cash-Karp's method 

1656 """ 

1657 

1658 def __init__(self, **kwargs): 

1659 ''' 

1660 Initialization routine 

1661 ''' 

1662 super().__init__(**kwargs) 

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

1664 self.marker = 'x' 

1665 self.name = 'ERK' 

1666 self.bar_plot_x_label = 'ERK5(4)' 

1667 

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

1669 desc = {} 

1670 if problem.__name__ == 'run_Schroedinger': 

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

1672 

1673 return desc 

1674 

1675 @property 

1676 def label(self): 

1677 return 'CK5(4)' 

1678 

1679 def get_random_params(self, problem, num_procs): 

1680 ''' 

1681 Routine to get parameters for the randomization of faults 

1682 

1683 Args: 

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

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

1686 

1687 Returns: 

1688 dict: Randomization parameters 

1689 ''' 

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

1691 rnd_params['min_node'] = 7 

1692 

1693 return rnd_params 

1694 

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

1696 from pySDC.implementations.sweeper_classes.Runge_Kutta import Cash_Karp 

1697 

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

1699 desc['sweeper_class'] = Cash_Karp 

1700 

1701 if problem.__name__ == "run_AC": 

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

1703 return desc 

1704 

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. 

1708 

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 

1714 

1715 Returns: 

1716 The reference value 

1717 """ 

1718 if problem.__name__ == "run_Lorenz": 

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

1720 return 0 

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

1722 return 1.509206128957885e-07 

1723 

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

1725 

1726 

1727class DoubleAdaptivityStrategy(AdaptivityStrategy): 

1728 ''' 

1729 Adaptivity based both on embedded estimate and on residual 

1730 ''' 

1731 

1732 def __init__(self, **kwargs): 

1733 ''' 

1734 Initialization routine 

1735 ''' 

1736 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

1737 

1738 kwargs['skip_residual_computation'] = 'all' 

1739 super().__init__(**kwargs) 

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

1741 self.marker = '^' 

1742 self.name = 'double_adaptivity' 

1743 self.bar_plot_x_label = 'double adaptivity' 

1744 self.precision_parameter = 'e_tol' 

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

1746 self.residual_e_tol_ratio = 1.0 

1747 self.residual_e_tol_abs = None 

1748 

1749 @property 

1750 def label(self): 

1751 return 'double adaptivity' 

1752 

1753 def get_custom_description(self, problem, num_procs): 

1754 ''' 

1755 Routine to get a custom description that adds adaptivity 

1756 

1757 Args: 

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

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

1760 

1761 Returns: 

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

1763 ''' 

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

1765 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1766 

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

1768 

1769 if self.residual_e_tol_abs: 

1770 e_tol = self.residual_e_tol_abs 

1771 else: 

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

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

1774 'e_tol': e_tol, 

1775 'allowed_modifications': ['decrease'], 

1776 } 

1777 

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

1779 'max_restarts': 15 

1780 } 

1781 

1782 return custom_description 

1783 

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

1785 """ 

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

1787 

1788 Args: 

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

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

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

1792 num_procs (int): Number of processes 

1793 

1794 Returns: 

1795 The reference value 

1796 """ 

1797 if problem.__name__ == 'run_Lorenz': 

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

1799 return 2989 

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

1801 return 5.636763944494305e-08 

1802 

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

1804 

1805 

1806class AdaptivityAvoidRestartsStrategy(AdaptivityStrategy): 

1807 """ 

1808 Adaptivity with the avoid restarts option 

1809 """ 

1810 

1811 @property 

1812 def label(self): 

1813 return 'adaptivity (avoid restarts)' 

1814 

1815 def get_custom_description(self, problem, num_procs): 

1816 ''' 

1817 Routine to get a custom description that adds adaptivity 

1818 

1819 Args: 

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

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

1822 

1823 Returns: 

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

1825 ''' 

1826 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

1827 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1828 

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

1830 

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

1832 

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

1834 'max_restarts': 15 

1835 } 

1836 

1837 return custom_description 

1838 

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

1840 """ 

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

1842 

1843 Args: 

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

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

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

1847 num_procs (int): Number of processes 

1848 

1849 Returns: 

1850 The reference value 

1851 """ 

1852 if problem.__name__ == "run_Lorenz": 

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

1854 return 2989 

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

1856 return 5.636763944494305e-08 

1857 

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

1859 

1860 

1861class AdaptivityInterpolationStrategy(AdaptivityStrategy): 

1862 """ 

1863 Adaptivity with interpolation between restarts 

1864 """ 

1865 

1866 @property 

1867 def label(self): 

1868 return 'adaptivity+interpolation' 

1869 

1870 def get_custom_description(self, problem, num_procs): 

1871 ''' 

1872 Routine to get a custom description that adds adaptivity 

1873 

1874 Args: 

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

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

1877 

1878 Returns: 

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

1880 ''' 

1881 from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity 

1882 from pySDC.implementations.convergence_controller_classes.interpolate_between_restarts import ( 

1883 InterpolateBetweenRestarts, 

1884 ) 

1885 from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestarting 

1886 

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

1888 

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

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

1891 

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

1893 'max_restarts': 15 

1894 } 

1895 

1896 return custom_description 

1897 

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

1899 """ 

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

1901 

1902 Args: 

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

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

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

1906 num_procs (int): Number of processes 

1907 

1908 Returns: 

1909 The reference value 

1910 """ 

1911 if problem.__name__ == "run_Lorenz": 

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

1913 return 6659 

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

1915 return 2.9780002756552015e-06 

1916 

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

1918 

1919 

1920class AdaptivityExtrapolationWithinQStrategy(InexactBaseStrategy): 

1921 ''' 

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

1923 ''' 

1924 

1925 def __init__(self, **kwargs): 

1926 ''' 

1927 Initialization routine 

1928 ''' 

1929 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityExtrapolationWithinQ 

1930 

1931 self.restol = None 

1932 super().__init__(**kwargs) 

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

1934 self.marker = '*' 

1935 self.name = 'adaptivity_extraQ' 

1936 self.bar_plot_x_label = 'adaptivity Q' 

1937 self.precision_parameter = 'e_tol' 

1938 self.adaptive_coll_params = {} 

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

1940 

1941 def get_custom_description(self, problem, num_procs): 

1942 ''' 

1943 Routine to get a custom description that adds adaptivity 

1944 

1945 Args: 

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

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

1948 

1949 Returns: 

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

1951 ''' 

1952 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityExtrapolationWithinQ 

1953 

1954 custom_description = {} 

1955 

1956 dt_max = np.inf 

1957 dt_min = 1e-5 

1958 

1959 if problem.__name__ == "run_vdp": 

1960 e_tol = 2e-5 

1961 dt_min = 1e-3 

1962 elif problem.__name__ == "run_piline": 

1963 e_tol = 1e-7 

1964 dt_min = 1e-2 

1965 elif problem.__name__ == "run_Lorenz": 

1966 e_tol = 2e-5 

1967 dt_min = 1e-3 

1968 elif problem.__name__ == "run_Schroedinger": 

1969 e_tol = 4e-6 

1970 dt_min = 1e-3 

1971 elif problem.__name__ == "run_quench": 

1972 e_tol = 1e-5 

1973 dt_min = 1e-3 

1974 dt_max = 1e2 

1975 elif problem.__name__ == "run_AC": 

1976 e_tol = 1e-4 

1977 else: 

1978 raise NotImplementedError( 

1979 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\ 

1980 strategy' 

1981 ) 

1982 

1983 custom_description['convergence_controllers'] = { 

1984 AdaptivityExtrapolationWithinQ: { 

1985 'e_tol': e_tol, 

1986 'dt_min': dt_min, 

1987 'dt_max': dt_max, 

1988 'restol_rel': 1e-2, 

1989 'restart_at_maxiter': True, 

1990 } 

1991 } 

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

1993 

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

1995 """ 

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

1997 

1998 Args: 

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

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

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

2002 num_procs (int): Number of processes 

2003 

2004 Returns: 

2005 The reference value 

2006 """ 

2007 if problem.__name__ == "run_Lorenz": 

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

2009 return 2198 

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

2011 return 5.412657451131508e-07 

2012 

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

2014 

2015 

2016class AdaptivityPolynomialError(InexactBaseStrategy): 

2017 ''' 

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

2019 ''' 

2020 

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

2022 ''' 

2023 Initialization routine 

2024 ''' 

2025 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError 

2026 

2027 self.restol = None 

2028 super().__init__(**kwargs) 

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

2030 self.marker = '+' 

2031 self.name = 'adaptivity-inter' 

2032 self.bar_plot_x_label = 'adaptivity Q' 

2033 self.precision_parameter = 'e_tol' 

2034 self.adaptive_coll_params = {} 

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

2036 self.interpolate_between_restarts = interpolate_between_restarts 

2037 self.use_restol_rel = use_restol_rel 

2038 self.max_slope = max_slope 

2039 

2040 def get_custom_description(self, problem, num_procs): 

2041 ''' 

2042 Routine to get a custom description that adds adaptivity 

2043 

2044 Args: 

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

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

2047 

2048 Returns: 

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

2050 ''' 

2051 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError 

2052 from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter 

2053 from pySDC.implementations.convergence_controller_classes.check_convergence import CheckConvergence 

2054 

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

2056 custom_description = {} 

2057 

2058 dt_max = np.inf 

2059 restol_rel = 1e-4 

2060 restol_min = 1e-12 

2061 restol_max = 1e-5 

2062 dt_slope_min = 0 

2063 dt_min = 0 

2064 abort_at_growing_residual = True 

2065 level_params = {} 

2066 problem_params = {} 

2067 beta = 0.9 

2068 

2069 if problem.__name__ == "run_vdp": 

2070 e_tol = 6e-4 

2071 level_params['dt'] = 0.1 

2072 restol_rel = 1e-5 

2073 restol_min = 1e-12 

2074 dt_min = 1e-7 

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

2076 elif problem.__name__ == "run_piline": 

2077 e_tol = 1e-7 

2078 elif problem.__name__ == "run_Lorenz": 

2079 e_tol = 2e-4 

2080 elif problem.__name__ == "run_Schroedinger": 

2081 e_tol = 3e-5 

2082 elif problem.__name__ == "run_quench": 

2083 e_tol = 1e-7 

2084 level_params['dt'] = 50.0 

2085 restol_min = 1e-11 

2086 restol_rel = 1e-1 

2087 elif problem.__name__ == "run_AC": 

2088 e_tol = 1.0e-4 

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

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

2091 elif problem.__name__ == "run_RBC": 

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

2093 dt_slope_min = 1.0 

2094 abort_at_growing_residual = False 

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

2096 restol_max = 1e-1 

2097 restol_min = 5e-8 

2098 self.max_slope = 4 

2099 beta = 0.5 

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

2101 elif problem.__name__ == 'run_GS': 

2102 e_tol = 1e-4 

2103 restol_rel = 4e-3 

2104 restol_max = 1e-4 

2105 restol_min = 1e-9 

2106 else: 

2107 raise NotImplementedError( 

2108 'I don\'t have a tolerance for adaptivity for your problem. Please add one to the\ 

2109 strategy' 

2110 ) 

2111 

2112 custom_description['convergence_controllers'] = { 

2113 AdaptivityPolynomialError: { 

2114 'e_tol': e_tol, 

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

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

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

2118 'restart_at_maxiter': True, 

2119 'factor_if_not_converged': self.max_slope, 

2120 'interpolate_between_restarts': self.interpolate_between_restarts, 

2121 'abort_at_growing_residual': abort_at_growing_residual, 

2122 'beta': beta, 

2123 }, 

2124 StepSizeLimiter: { 

2125 'dt_max': dt_max, 

2126 'dt_slope_max': self.max_slope, 

2127 'dt_min': dt_min, 

2128 'dt_rel_min_slope': dt_slope_min, 

2129 }, 

2130 } 

2131 custom_description['level_params'] = level_params 

2132 custom_description['problem_params'] = problem_params 

2133 

2134 return merge_descriptions(base_params, custom_description) 

2135 

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

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

2138 if problem.__name__ == "run_quench": 

2139 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError 

2140 

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

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

2143 elif problem.__name__ == "run_AC": 

2144 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError 

2145 

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

2147 if num_procs == 4: 

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

2149 elif problem.__name__ == "run_Lorenz": 

2150 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError 

2151 

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

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

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

2155 elif problem.__name__ == "run_vdp": 

2156 from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityPolynomialError 

2157 from pySDC.implementations.convergence_controller_classes.inexactness import NewtonInexactness 

2158 

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

2160 desc['problem_params'] = { 

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

2162 'mu': 5, 

2163 'crash_at_maxiter': False, 

2164 'newton_tol': 1e-11, 

2165 'stop_at_nan': False, 

2166 } 

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

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

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

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

2171 return desc 

2172 

2173 def get_random_params(self, problem, num_procs): 

2174 ''' 

2175 Routine to get parameters for the randomization of faults 

2176 

2177 Args: 

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

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

2180 

2181 Returns: 

2182 dict: Randomization parameters 

2183 ''' 

2184 

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

2186 if problem.__name__ == "run_quench": 

2187 rnd_params['iteration'] = 1 

2188 elif problem.__name__ == 'run_Lorenz': 

2189 rnd_params['iteration'] = 5 

2190 return rnd_params 

2191 

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

2193 """ 

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

2195 

2196 Args: 

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

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

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

2200 num_procs (int): Number of processes 

2201 

2202 Returns: 

2203 The reference value 

2204 """ 

2205 if problem.__name__ == "run_Lorenz": 

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

2207 return 2123 

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

2209 return 7.931560830343187e-08 

2210 

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

2212 

2213 @property 

2214 def label(self): 

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