SpECTRE Documentation Coverage Report
Current view: top level - ControlSystem/Tags - MeasurementTimescales.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 12.5 % 8 1
Test Date: 2026-10-22 17:29:42
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 <array>
       7              : #include <limits>
       8              : #include <memory>
       9              : #include <optional>
      10              : #include <string>
      11              : #include <unordered_map>
      12              : 
      13              : #include "ControlSystem/CalculateMeasurementTimescales.hpp"
      14              : #include "ControlSystem/CombinedName.hpp"
      15              : #include "ControlSystem/Controller.hpp"
      16              : #include "ControlSystem/ExpirationTimes.hpp"
      17              : #include "ControlSystem/Metafunctions.hpp"
      18              : #include "ControlSystem/Tags/OptionTags.hpp"
      19              : #include "ControlSystem/Tags/SystemTags.hpp"
      20              : #include "ControlSystem/TimescaleTuner.hpp"
      21              : #include "DataStructures/DataBox/Tag.hpp"
      22              : #include "DataStructures/DataVector.hpp"
      23              : #include "Domain/Creators/OptionTags.hpp"
      24              : #include "Domain/FunctionsOfTime/FunctionOfTime.hpp"
      25              : #include "Domain/FunctionsOfTime/PiecewisePolynomial.hpp"
      26              : #include "Options/Auto.hpp"
      27              : #include "Time/OptionTags/InitialTime.hpp"
      28              : #include "Time/OptionTags/InitialTimeStep.hpp"
      29              : #include "Utilities/ErrorHandling/Error.hpp"
      30              : #include "Utilities/TMPL.hpp"
      31              : #include "Utilities/TypeTraits/IsA.hpp"
      32              : 
      33              : /// \cond
      34              : template <class Metavariables, typename ControlSystem>
      35              : struct ControlComponent;
      36              : /// \endcond
      37              : 
      38              : namespace control_system::Tags {
      39              : /*!
      40              :  * \ingroup DataBoxTagsGroup
      41              :  * \ingroup ControlSystemGroup
      42              :  * \brief The measurement timescales associated with
      43              :  * domain::Tags::FunctionsOfTime.
      44              :  *
      45              :  * We group measurement timescales by
      46              :  * the `control_system::protocols::Measurement` that their corresponding control
      47              :  * systems use. This is because one measurement may be used to update many
      48              :  * functions of time. Each group of functions of time associated with a
      49              :  * particular measurement has a corresponding timescale here, represented as
      50              :  * `PiecewisePolynomial<0>` with a single entry. That single entry is the
      51              :  * minimum of all `control_system::calculate_measurement_timescales` for every
      52              :  * control system in that group.
      53              :  *
      54              :  * The name of a measurement timescale is calculated using
      55              :  * `control_system::system_to_combined_names` for every group of control systems
      56              :  * with the same measurement.
      57              :  *
      58              :  * If all control systems that use the same measurement aren't active, then the
      59              :  * measurement timescale and expiration time are
      60              :  * `std::numeric_limits<double>::infinity()`.
      61              :  */
      62            1 : struct MeasurementTimescales : db::SimpleTag {
      63            0 :   using type = std::unordered_map<
      64              :       std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>;
      65              : 
      66              :   template <typename Metavariables>
      67            0 :   using option_holders = control_system::inputs<
      68              :       tmpl::transform<tmpl::filter<typename Metavariables::component_list,
      69              :                                    tt::is_a<ControlComponent, tmpl::_1>>,
      70              :                       tmpl::bind<tmpl::back, tmpl::_1>>>;
      71              : 
      72            0 :   static constexpr bool pass_metavariables = true;
      73              : 
      74              :   template <typename Metavariables>
      75            0 :   using option_tags = tmpl::push_front<
      76              :       option_holders<Metavariables>,
      77              :       control_system::OptionTags::MeasurementsPerUpdate,
      78              :       control_system::OptionTags::DelayUpdate,
      79              :       domain::OptionTags::DomainCreator<Metavariables::volume_dim>,
      80              :       ::OptionTags::InitialTime, ::OptionTags::InitialTimeStep>;
      81              : 
      82              :   template <typename Metavariables, typename... OptionHolders>
      83            0 :   static type create_from_options(
      84              :       const int measurements_per_update, const bool delay_update,
      85              :       const std::unique_ptr<::DomainCreator<Metavariables::volume_dim>>&
      86              :           domain_creator,
      87              :       const double initial_time, const double initial_time_step,
      88              :       const Options::Auto<OptionHolders,
      89              :                           Options::AutoLabel::None>&... option_holders) {
      90              :     return create_from_options<Metavariables>(
      91              :         measurements_per_update, delay_update, domain_creator, initial_time,
      92              :         initial_time_step,
      93              :         static_cast<std::optional<OptionHolders>>(option_holders)...);
      94              :   }
      95              : 
      96              :   template <typename Metavariables, typename... OptionHolders>
      97            0 :   static type create_from_options(
      98              :       const int measurements_per_update, const bool delay_update,
      99              :       const std::unique_ptr<::DomainCreator<Metavariables::volume_dim>>&
     100              :           domain_creator,
     101              :       const double initial_time, const double initial_time_step,
     102              :       const std::optional<OptionHolders>&... option_holders) {
     103              :     std::unordered_map<std::string,
     104              :                        std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>
     105              :         timescales{};
     106              : 
     107              :     using control_systems =
     108              :         tmpl::list<typename OptionHolders::control_system...>;
     109              : 
     110              :     // First string is name of each control system. Second string is combination
     111              :     // of control systems with same measurement
     112              :     std::unordered_map<std::string, std::string> map_of_names =
     113              :         system_to_combined_names<control_systems>();
     114              : 
     115              :     // Initialize all measurements to infinity so we can take the min later
     116              :     std::unordered_map<std::string, double> min_measurement_timescales{};
     117              :     std::unordered_map<std::string, double> expiration_times{};
     118              :     for (const auto& [control_system_name, combined_name] : map_of_names) {
     119              :       (void)control_system_name;
     120              :       if (min_measurement_timescales.count(combined_name) != 1) {
     121              :         min_measurement_timescales[combined_name] =
     122              :             std::numeric_limits<double>::infinity();
     123              :         expiration_times[combined_name] =
     124              :             std::numeric_limits<double>::infinity();
     125              :       }
     126              :     }
     127              : 
     128              :     [[maybe_unused]] const auto combine_measurement_timescales =
     129              :         [&initial_time, &initial_time_step, &domain_creator,
     130              :          &measurements_per_update, &delay_update, &map_of_names,
     131              :          &min_measurement_timescales,
     132              :          &expiration_times](const auto& option_holder) {
     133              :           // This check is intentionally inside the lambda so that it will not
     134              :           // trigger for domains without control systems.
     135              :           if (initial_time_step <= 0.0) {
     136              :             ERROR(
     137              :                 "Control systems can only be used in forward-in-time "
     138              :                 "evolutions.");
     139              :           }
     140              : 
     141              :           const std::string& control_system_name = std::decay_t<
     142              :               decltype(option_holder)>::value_type::control_system::name();
     143              :           const std::string& combined_name = map_of_names[control_system_name];
     144              : 
     145              :           // If the control system isn't active, set measurement timescale and
     146              :           // expiration time to be infinity.
     147              :           double min_measurement_timescale =
     148              :               std::numeric_limits<double>::infinity();
     149              : 
     150              :           if (option_holder.has_value()) {
     151              :             auto tuner = option_holder->tuner;
     152              :             ::control_system::Tags::detail::initialize_tuner(
     153              :                 make_not_null(&tuner), domain_creator, initial_time,
     154              :                 control_system_name);
     155              : 
     156              :             const auto& controller = option_holder->controller;
     157              :             DataVector measurement_timescales =
     158              :                 calculate_measurement_timescales(controller, tuner,
     159              :                                                  measurements_per_update);
     160              : 
     161              :             min_measurement_timescale = min(measurement_timescales);
     162              :           }
     163              : 
     164              :           min_measurement_timescales[combined_name] =
     165              :               std::min(min_measurement_timescales[combined_name],
     166              :                        min_measurement_timescale);
     167              : 
     168              :           if (min_measurement_timescales[combined_name] !=
     169              :               std::numeric_limits<double>::infinity()) {
     170              :             const double expiration_time = measurement_initial_expiration_time(
     171              :                 initial_time,
     172              :                 DataVector{1_st, min_measurement_timescales[combined_name]},
     173              :                 measurements_per_update, delay_update);
     174              :             expiration_times[combined_name] =
     175              :                 std::min(expiration_times[combined_name], expiration_time);
     176              :           }
     177              :         };
     178              : 
     179              :     EXPAND_PACK_LEFT_TO_RIGHT(combine_measurement_timescales(option_holders));
     180              : 
     181              :     for (const auto& [combined_name, min_measurement_timescale] :
     182              :          min_measurement_timescales) {
     183              :       double expiration_time = expiration_times[combined_name];
     184              :       timescales.emplace(
     185              :           combined_name,
     186              :           std::make_unique<domain::FunctionsOfTime::PiecewisePolynomial<0>>(
     187              :               initial_time,
     188              :               std::array{DataVector{1, min_measurement_timescale}},
     189              :               expiration_time));
     190              :     }
     191              : 
     192              :     return timescales;
     193              :   }
     194              : };
     195              : }  // namespace control_system::Tags
        

Generated by: LCOV version 2.0-1