SpECTRE Documentation Coverage Report
Current view: top level - Time/StepChoosers - ErrorControl.hpp Hit Total Coverage
Commit: 923cd4a8ea30f5a5589baa60b0a93e358ca9f8e8 Lines: 4 38 10.5 %
Date: 2025-11-07 19:37:56
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <algorithm>
       7             : #include <cmath>
       8             : #include <limits>
       9             : #include <pup.h>
      10             : #include <string>
      11             : #include <type_traits>
      12             : #include <typeindex>
      13             : #include <typeinfo>
      14             : #include <unordered_map>
      15             : 
      16             : #include "Options/String.hpp"
      17             : #include "Time/RequestsStepperErrorTolerances.hpp"
      18             : #include "Time/StepChoosers/StepChooser.hpp"
      19             : #include "Time/StepperErrorTolerances.hpp"
      20             : #include "Time/Tags/StepperErrors.hpp"
      21             : #include "Time/TimeStepRequest.hpp"
      22             : #include "Utilities/Serialization/CharmPupable.hpp"
      23             : #include "Utilities/TMPL.hpp"
      24             : 
      25             : /// \cond
      26             : struct NoSuchType;
      27             : /// \endcond
      28             : 
      29             : namespace StepChoosers {
      30             : /*!
      31             :  * \brief Sets a goal based on time-stepper truncation error.
      32             :  *
      33             :  * \details The suggested step is calculated via a simple specialization of the
      34             :  * scheme suggested in \cite Hairer1993. We first compute the aggregated error
      35             :  * measure from the stepper error:
      36             :  *
      37             :  * \f[
      38             :  * E = \max_i(|E_i| / sc_i),
      39             :  * \f]
      40             :  *
      41             :  * where \f$E_i\f$ is the ODE error reported for each individual grid point,
      42             :  * reported by the time stepper, and \f$sc_i\f$ is the step control measure
      43             :  * determined by the tolerances:
      44             :  *
      45             :  * \f[
      46             :  * sc_i = Atol_i + \max(|y_i|,|y_i + E_i|) Rtol_i,
      47             :  * \f]
      48             :  *
      49             :  * and \f$y_i\f$ is the value of the function at the previous step at
      50             :  * grid point \f$i\f$.  (The estimate is more commonly done comparing
      51             :  * with the current step, but using the previous step avoids a memory
      52             :  * allocation in the TimeStepper and should not have a major effect on
      53             :  * the result.)
      54             :  *
      55             :  * When choosing a step size for LTS or when no record of previous
      56             :  * error is available, the step has size:
      57             :  *
      58             :  * \f[
      59             :  * h_{\text{new}} = h \cdot \min\left(F_{\text{max}},
      60             :  * \max\left(F_{\text{min}},
      61             :  * \frac{F_{\text{safety}}}{E^{1/(q + 1)}}\right)\right),
      62             :  * \f]
      63             :  *
      64             :  * where \f$h_{\text{new}}\f$ is the new suggested step size \f$h\f$ is the
      65             :  * previous step size, \f$F_{\text{max}}\f$ is the maximum factor by which we
      66             :  * allow the step to increase, \f$F_{\text{min}}\f$ is the minimum factor by
      67             :  * which we allow the step to decrease. \f$F_{\text{safety}}\f$ is the safety
      68             :  * factor on the computed error -- this forces the step size slightly lower
      69             :  * than we would naively compute so that the result of the step will likely be
      70             :  * within the target error. \f$q\f$ is the order of the stepper error
      71             :  * calculation. Intuitively, we should change the step less drastically for a
      72             :  * higher order stepper.
      73             :  *
      74             :  * When controlling slab size, after the first error calculation, the
      75             :  * error \f$E\f$ is recorded in the \ref DataBoxGroup "DataBox", and
      76             :  * subsequent error calculations use a simple PI scheme suggested in
      77             :  * \cite NumericalRecipes section 17.2.1:
      78             :  *
      79             :  * \f[
      80             :  * h_{\text{new}} = h \cdot \min\left(F_{\text{max}},
      81             :  * \max\left(F_{\text{min}},
      82             :  * F_{\text{safety}} E^{-0.7 / (q + 1)}
      83             :  * E_{\text{prev}}^{0.4 / (q + 1)}\right)\right),
      84             :  * \f]
      85             :  *
      86             :  * where \f$E_{\text{prev}}\f$ is the error computed in the previous
      87             :  * step.  This method is never used for choosing an LTS step because
      88             :  * the restriction of step size changes to factors of two was found to
      89             :  * interfere with the more gradual increase chosen by the PI
      90             :  * controller.
      91             :  *
      92             :  * \note The template parameter `ErrorControlSelector` is used to disambiguate
      93             :  * in the input-file options between `ErrorControl` step choosers that are
      94             :  * based on different variables. This is needed if multiple systems are evolved
      95             :  * in the same executable. The name used for the input file includes
      96             :  * `ErrorControlSelector::name()` if it is provided.
      97             :  */
      98             : template <typename StepChooserUse, typename EvolvedVariableTag,
      99             :           typename ErrorControlSelector = NoSuchType>
     100           1 : class ErrorControl : public StepChooser<StepChooserUse>,
     101             :                      public RequestsStepperErrorTolerances {
     102             :  public:
     103             :   /// \cond
     104             :   ErrorControl() = default;
     105             :   explicit ErrorControl(CkMigrateMessage* /*unused*/) {}
     106             :   using PUP::able::register_constructor;
     107             :   WRAPPED_PUPable_decl_template(ErrorControl);  // NOLINT
     108             :   /// \endcond
     109             : 
     110           0 :   static std::string name() {
     111             :     if constexpr (std::is_same_v<ErrorControlSelector, NoSuchType>) {
     112             :       return "ErrorControl";
     113             :     } else {
     114             :       return "ErrorControl(" + ErrorControlSelector::name() + ")";
     115             :     }
     116             :   }
     117             : 
     118           0 :   struct AbsoluteTolerance {
     119           0 :     using type = double;
     120           0 :     static constexpr Options::String help{"Target absolute tolerance"};
     121           0 :     static type lower_bound() { return 0.0; }
     122             :   };
     123             : 
     124           0 :   struct RelativeTolerance {
     125           0 :     using type = double;
     126           0 :     static constexpr Options::String help{"Target relative tolerance"};
     127           0 :     static type lower_bound() { return 0.0; }
     128             :   };
     129             : 
     130           0 :   struct MaxFactor {
     131           0 :     using type = double;
     132           0 :     static constexpr Options::String help{
     133             :         "Maximum factor to increase the step by"};
     134           0 :     static type lower_bound() { return 1.0; }
     135             :   };
     136             : 
     137           0 :   struct MinFactor {
     138           0 :     using type = double;
     139           0 :     static constexpr Options::String help{
     140             :         "Minimum factor to increase the step by"};
     141           0 :     static type lower_bound() { return 0.0; }
     142           0 :     static type upper_bound() { return 1.0; }
     143             :   };
     144             : 
     145           0 :   struct SafetyFactor {
     146           0 :     using type = double;
     147           0 :     static constexpr Options::String help{
     148             :         "Extra factor to apply to step estimate; can be used to decrease step "
     149             :         "size to improve step acceptance rate."};
     150           0 :     static type lower_bound() { return 0.0; }
     151             :   };
     152             : 
     153           0 :   static constexpr Options::String help{
     154             :       "Sets a goal based on time-stepper truncation error."};
     155           0 :   using options = tmpl::list<AbsoluteTolerance, RelativeTolerance, MaxFactor,
     156             :                              MinFactor, SafetyFactor>;
     157             : 
     158           0 :   ErrorControl(const double absolute_tolerance, const double relative_tolerance,
     159             :                const double max_factor, const double min_factor,
     160             :                const double safety_factor)
     161             :       : absolute_tolerance_{absolute_tolerance},
     162             :         relative_tolerance_{relative_tolerance},
     163             :         max_factor_{max_factor},
     164             :         min_factor_{min_factor},
     165             :         safety_factor_{safety_factor} {}
     166             : 
     167           0 :   using argument_tags = tmpl::list<::Tags::StepperErrors<EvolvedVariableTag>>;
     168             : 
     169           0 :   TimeStepRequest operator()(
     170             :       const typename ::Tags::StepperErrors<EvolvedVariableTag>::type& errors,
     171             :       const double /*previous_step*/) const {
     172             :     // Do not request that the step size be changed if there isn't a new error
     173             :     // estimate
     174             :     if (not errors[1].has_value()) {
     175             :       return {};
     176             :     }
     177             :     double new_step;
     178             :     if (std::is_same_v<StepChooserUse, ::StepChooserUse::LtsStep> or
     179             :         not errors[0].has_value() or errors[0]->order != errors[1]->order) {
     180             :       new_step =
     181             :           errors[1]->step_size.value() *
     182             :           std::clamp(safety_factor_ *
     183             :                          pow(1.0 / std::max(errors[1]->step_error(), 1e-14),
     184             :                              1.0 / (errors[1]->order + 1)),
     185             :                      min_factor_, max_factor_);
     186             :     } else {
     187             :       // From simple advice from Numerical Recipes 17.2.1 regarding a heuristic
     188             :       // for PI step control.
     189             :       const double alpha_factor = 0.7 / (errors[1]->order + 1);
     190             :       const double beta_factor = 0.4 / (errors[0]->order + 1);
     191             :       new_step =
     192             :           errors[1]->step_size.value() *
     193             :           std::clamp(
     194             :               safety_factor_ *
     195             :                   pow(1.0 / std::max(errors[1]->step_error(), 1e-14),
     196             :                       alpha_factor) *
     197             :                   pow(std::max(errors[0]->step_error(), 1e-14), beta_factor),
     198             :               min_factor_, max_factor_);
     199             :     }
     200             :     return ::TimeStepRequest{.size_goal = new_step};
     201             :   }
     202             : 
     203           1 :   bool uses_local_data() const override { return true; }
     204           1 :   bool can_be_delayed() const override { return true; }
     205             : 
     206           1 :   std::unordered_map<std::type_index, StepperErrorTolerances> tolerances()
     207             :       const override {
     208             :     return {{typeid(EvolvedVariableTag),
     209             :              {.estimates = StepperErrorTolerances::Estimates::StepperOrder,
     210             :               .absolute = absolute_tolerance_,
     211             :               .relative = relative_tolerance_}}};
     212             :   }
     213             : 
     214           0 :   void pup(PUP::er& p) override {  // NOLINT
     215             :     StepChooser<StepChooserUse>::pup(p);
     216             :     p | absolute_tolerance_;
     217             :     p | relative_tolerance_;
     218             :     p | min_factor_;
     219             :     p | max_factor_;
     220             :     p | safety_factor_;
     221             :   }
     222             : 
     223             :  private:
     224           0 :   double absolute_tolerance_ = std::numeric_limits<double>::signaling_NaN();
     225           0 :   double relative_tolerance_ = std::numeric_limits<double>::signaling_NaN();
     226           0 :   double max_factor_ = std::numeric_limits<double>::signaling_NaN();
     227           0 :   double min_factor_ = std::numeric_limits<double>::signaling_NaN();
     228           0 :   double safety_factor_ = std::numeric_limits<double>::signaling_NaN();
     229             : };
     230             : /// \cond
     231             : template <typename StepChooserUse, typename EvolvedVariableTag,
     232             :           typename ErrorControlSelector>
     233             : PUP::able::PUP_ID ErrorControl<StepChooserUse, EvolvedVariableTag,
     234             :                                ErrorControlSelector>::my_PUP_ID = 0;  // NOLINT
     235             : /// \endcond
     236             : }  // namespace StepChoosers

Generated by: LCOV version 1.14