SpECTRE Documentation Coverage Report
Current view: top level - ControlSystem/Tags - MeasurementTimescales.hpp Hit Total Coverage
Commit: fbcce2ed065a8e48da2f38009a84bbfbc0c260ee Lines: 1 8 12.5 %
Date: 2025-11-14 20:55:50
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 1.14