11import numpy as np
2- from pySDC .core .ConvergenceController import ConvergenceController
2+ from pySDC .core .ConvergenceController import ConvergenceController , Status
33from pySDC .implementations .convergence_controller_classes .step_size_limiter import (
44 StepSizeLimiter ,
55)
@@ -202,7 +202,7 @@ def check_parameters(self, controller, params, description, **kwargs):
202202 bool: Whether the parameters are compatible
203203 str: The error message
204204 """
205- if description ["step_params " ].get ("restol" , - 1.0 ) >= 0 :
205+ if description ["level_params " ].get ("restol" , - 1.0 ) >= 0 :
206206 return (
207207 False ,
208208 "Adaptivity needs constant order in time and hence restol in the step parameters has to be \
@@ -218,8 +218,7 @@ def check_parameters(self, controller, params, description, **kwargs):
218218 if "e_tol" not in params .keys ():
219219 return (
220220 False ,
221- "Adaptivity needs a local tolerance! Please set some up in description['convergence_control\
222- _params']['e_tol']!" ,
221+ "Adaptivity needs a local tolerance! Please pass `e_tol` to the parameters for this convergence controller!" ,
223222 )
224223
225224 return True , ""
@@ -389,7 +388,7 @@ def check_parameters(self, controller, params, description, **kwargs):
389388 bool: Whether the parameters are compatible
390389 str: The error message
391390 """
392- if description ["step_params " ].get ("restol" , - 1.0 ) >= 0 :
391+ if description ["level_params " ].get ("restol" , - 1.0 ) >= 0 :
393392 return (
394393 False ,
395394 "Adaptivity needs constant order in time and hence restol in the step parameters has to be \
@@ -446,3 +445,156 @@ def get_local_error_estimate(self, controller, S, **kwargs):
446445 float: Embedded error estimate
447446 """
448447 return S .levels [0 ].status .residual
448+
449+
450+ class AdaptivityCollocation (AdaptivityBase ):
451+ """
452+ Control the step size via a collocation based estimate of the local error.
453+ The error estimate works by subtracting two solutions to collocation problems with different order. You can
454+ interpolate between collocation methods as much as you want but the adaptive step size selection will always be
455+ based on the last switch of quadrature.
456+ """
457+
458+ def setup (self , controller , params , description , ** kwargs ):
459+ """
460+ Add a default value for control order to the parameters.
461+
462+ Args:
463+ controller (pySDC.Controller): The controller
464+ params (dict): Parameters for the convergence controller
465+ description (dict): The description object used to instantiate the controller
466+
467+ Returns:
468+ dict: Updated parameters
469+ """
470+ defaults = {
471+ "adaptive_coll_params" : {},
472+ "num_colls" : 0 ,
473+ ** super ().setup (controller , params , description , ** kwargs ),
474+ "control_order" : 220 ,
475+ }
476+
477+ for key in defaults ['adaptive_coll_params' ].keys ():
478+ if type (defaults ['adaptive_coll_params' ][key ]) == list :
479+ defaults ['num_colls' ] = max ([defaults ['num_colls' ], len (defaults ['adaptive_coll_params' ][key ])])
480+
481+ return defaults
482+
483+ def setup_status_variables (self , controller , ** kwargs ):
484+ self .status = Status (['error' , 'order' ])
485+ self .status .error = []
486+ self .status .order = []
487+
488+ def reset_status_variables (self , controller , ** kwargs ):
489+ self .setup_status_variables (controller , ** kwargs )
490+
491+ def dependencies (self , controller , description , ** kwargs ):
492+ """
493+ Load the `EstimateEmbeddedErrorCollocation` convergence controller to estimate the local error by switching
494+ between collocation problems between iterations.
495+
496+ Args:
497+ controller (pySDC.Controller): The controller
498+ description (dict): The description object used to instantiate the controller
499+ """
500+ from pySDC .implementations .convergence_controller_classes .estimate_embedded_error import (
501+ EstimateEmbeddedErrorCollocation ,
502+ )
503+
504+ super ().dependencies (controller , description )
505+
506+ params = {'adaptive_coll_params' : self .params .adaptive_coll_params }
507+ controller .add_convergence_controller (
508+ EstimateEmbeddedErrorCollocation ,
509+ params = params ,
510+ description = description ,
511+ )
512+
513+ def get_local_error_estimate (self , controller , S , ** kwargs ):
514+ """
515+ Get the collocation based embedded error estimate.
516+
517+ Args:
518+ controller (pySDC.Controller): The controller
519+ S (pySDC.Step): The current step
520+
521+ Returns:
522+ float: Embedded error estimate
523+ """
524+ if len (self .status .error ) > 1 :
525+ return self .status .error [- 1 ][1 ]
526+ else :
527+ return 0.0
528+
529+ def post_iteration_processing (self , controller , step , ** kwargs ):
530+ """
531+ Get the error estimate and its order if available.
532+
533+ Args:
534+ controller (pySDC.Controller.controller): The controller
535+ step (pySDC.Step.step): The current step
536+ """
537+ if step .status .done :
538+ lvl = step .levels [0 ]
539+ self .status .error += [lvl .status .error_embedded_estimate_collocation ]
540+ self .status .order += [lvl .sweep .coll .order ]
541+
542+ def get_new_step_size (self , controller , S , ** kwargs ):
543+ if len (self .status .order ) == self .params .num_colls :
544+ lvl = S .levels [0 ]
545+
546+ # compute next step size
547+ order = (
548+ min (self .status .order [- 2 ::]) + 1
549+ ) # local order of less accurate of the last two collocation problems
550+ e_est = self .get_local_error_estimate (controller , S )
551+
552+ lvl .status .dt_new = self .compute_optimal_step_size (
553+ self .params .beta , lvl .params .dt , self .params .e_tol , e_est , order
554+ )
555+ self .log (f'Adjusting step size from { lvl .params .dt :.2e} to { lvl .status .dt_new :.2e} ' , S )
556+
557+ def check_parameters (self , controller , params , description , ** kwargs ):
558+ """
559+ Check whether parameters are compatible with whatever assumptions went into the step size functions etc.
560+ For adaptivity, we need to know the order of the scheme.
561+
562+ Args:
563+ controller (pySDC.Controller): The controller
564+ params (dict): The params passed for this specific convergence controller
565+ description (dict): The description object used to instantiate the controller
566+
567+ Returns:
568+ bool: Whether the parameters are compatible
569+ str: The error message
570+ """
571+ if controller .params .mssdc_jac :
572+ return (
573+ False ,
574+ "Adaptivity needs the same order on all steps, please activate Gauss-Seidel multistep mode!" ,
575+ )
576+
577+ if "e_tol" not in params .keys ():
578+ return (
579+ False ,
580+ "Adaptivity needs a local tolerance! Please pass `e_tol` to the parameters for this convergence controller!" ,
581+ )
582+
583+ return True , ""
584+
585+ def determine_restart (self , controller , S , ** kwargs ):
586+ """
587+ Check if the step wants to be restarted by comparing the estimate of the local error to a preset tolerance
588+
589+ Args:
590+ controller (pySDC.Controller): The controller
591+ S (pySDC.Step): The current step
592+
593+ Returns:
594+ None
595+ """
596+ if len (self .status .order ) == self .params .num_colls :
597+ e_est = self .get_local_error_estimate (controller , S )
598+ if e_est >= self .params .e_tol :
599+ S .status .restart = True
600+ self .log (f"Restarting: e={ e_est :.2e} >= e_tol={ self .params .e_tol :.2e} " , S )
0 commit comments