SpECTRE Documentation Coverage Report
Current view: top level - ControlSystem - Trigger.hpp Hit Total Coverage
Commit: f23e75c235cae5144b8ac7ce01280be5b8cd2c8a Lines: 2 12 16.7 %
Date: 2024-09-07 06:21:00
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 <memory>
       7             : #include <optional>
       8             : #include <pup.h>
       9             : #include <string>
      10             : #include <type_traits>
      11             : 
      12             : #include "ControlSystem/CombinedName.hpp"
      13             : #include "ControlSystem/FutureMeasurements.hpp"
      14             : #include "ControlSystem/Metafunctions.hpp"
      15             : #include "IO/Logging/Verbosity.hpp"
      16             : #include "Parallel/ArrayCollection/IsDgElementCollection.hpp"
      17             : #include "Parallel/ArrayCollection/PerformAlgorithmOnElement.hpp"
      18             : #include "Parallel/ArrayCollection/Tags/ElementLocations.hpp"
      19             : #include "Parallel/ArrayComponentId.hpp"
      20             : #include "Parallel/Callback.hpp"
      21             : #include "Parallel/GlobalCache.hpp"
      22             : #include "Parallel/Printf/Printf.hpp"
      23             : #include "ParallelAlgorithms/Actions/GetItemFromDistributedObject.hpp"
      24             : #include "ParallelAlgorithms/EventsAndDenseTriggers/DenseTrigger.hpp"
      25             : #include "Utilities/ErrorHandling/Assert.hpp"
      26             : #include "Utilities/GetOutput.hpp"
      27             : #include "Utilities/Gsl.hpp"
      28             : #include "Utilities/PrettyType.hpp"
      29             : #include "Utilities/Serialization/CharmPupable.hpp"
      30             : #include "Utilities/TMPL.hpp"
      31             : 
      32             : /// \cond
      33             : namespace Tags {
      34             : struct Time;
      35             : }  // namespace Tags
      36             : namespace control_system::Tags {
      37             : template <typename ControlSystems>
      38             : struct FutureMeasurements;
      39             : struct MeasurementTimescales;
      40             : struct Verbosity;
      41             : }  // namespace control_system::Tags
      42             : /// \endcond
      43             : 
      44             : namespace control_system {
      45             : /// \ingroup ControlSystemGroup
      46             : /// \ingroup EventsAndTriggersGroup
      47             : /// Trigger for control system measurements.
      48             : ///
      49             : /// This trigger is only intended to be used with the
      50             : /// `control_system::Event` event.  A specialization of this trigger
      51             : /// will be created during control system initialization for each
      52             : /// unique \ref control_system::protocols::Measurement "measurement".
      53             : ///
      54             : /// These triggers must be added to the \ref
      55             : /// Options::protocols::FactoryCreation "factory_creation" struct in
      56             : /// the metavariables, even though they cannot be created from the
      57             : /// input file.  The `control_system::control_system_triggers`
      58             : /// metafunction provides the list of triggers to include.
      59             : template <typename ControlSystems>
      60           1 : class Trigger : public DenseTrigger {
      61             :   static_assert(tmpl::size<ControlSystems>::value > 0);
      62           0 :   using measurement = typename tmpl::front<ControlSystems>::measurement;
      63             :   static_assert(tmpl::all<ControlSystems,
      64             :                           std::is_same<metafunctions::measurement<tmpl::_1>,
      65             :                                        tmpl::pin<measurement>>>::value);
      66             : 
      67             :  public:
      68             :   /// \cond
      69             :   // LCOV_EXCL_START
      70             :   explicit Trigger(CkMigrateMessage* const msg) : DenseTrigger(msg) {}
      71             :   using PUP::able::register_constructor;
      72             :   WRAPPED_PUPable_decl_template(Trigger);  // NOLINT
      73             :   // LCOV_EXCL_STOP
      74             :   /// \endcond
      75             : 
      76             :   // This trigger is created during control system initialization, not
      77             :   // from the input file.
      78           0 :   static constexpr bool factory_creatable = false;
      79           0 :   Trigger() = default;
      80             : 
      81           0 :   using is_triggered_return_tags = tmpl::list<>;
      82           0 :   using is_triggered_argument_tags =
      83             :       tmpl::list<::Tags::Time,
      84             :                  control_system::Tags::FutureMeasurements<ControlSystems>>;
      85             : 
      86             :   template <typename Metavariables, size_t Dim, typename Component>
      87           0 :   std::optional<bool> is_triggered(
      88             :       Parallel::GlobalCache<Metavariables>& cache,
      89             :       const ElementId<Dim>& array_index, const Component* /*component*/,
      90             :       const double time,
      91             :       const control_system::FutureMeasurements& measurement_times) {
      92             :     const auto next_measurement = measurement_times.next_measurement();
      93             :     ASSERT(next_measurement.has_value(),
      94             :            "Checking trigger without knowing next time.");
      95             :     const bool triggered = time == *next_measurement;
      96             : 
      97             :     if (Parallel::get<Tags::Verbosity>(cache) >= ::Verbosity::Debug) {
      98             :       Parallel::printf(
      99             :           "%s, time = %.16f: Trigger for control systems (%s) is%s "
     100             :           "triggered.\n",
     101             :           get_output(array_index), time,
     102             :           pretty_type::list_of_names<ControlSystems>(),
     103             :           (triggered ? "" : " not"));
     104             :     }
     105             : 
     106             :     return triggered;
     107             :   }
     108             : 
     109           0 :   using next_check_time_return_tags =
     110             :       tmpl::list<control_system::Tags::FutureMeasurements<ControlSystems>>;
     111           0 :   using next_check_time_argument_tags = tmpl::list<::Tags::Time>;
     112             : 
     113             :   template <typename Metavariables, size_t Dim, typename Component>
     114           0 :   std::optional<double> next_check_time(
     115             :       Parallel::GlobalCache<Metavariables>& cache,
     116             :       const ElementId<Dim>& array_index, const Component* /*component*/,
     117             :       const gsl::not_null<control_system::FutureMeasurements*>
     118             :           measurement_times,
     119             :       const double time) {
     120             :     if (measurement_times->next_measurement() == std::optional(time)) {
     121             :       measurement_times->pop_front();
     122             :     }
     123             : 
     124             :     if (not measurement_times->next_measurement().has_value()) {
     125             :       auto& proxy = ::Parallel::get_parallel_component<Component>(cache);
     126             :       const bool is_ready = Parallel::mutable_cache_item_is_ready<
     127             :           control_system::Tags::MeasurementTimescales>(
     128             :           cache, Parallel::make_array_component_id<Component>(array_index),
     129             :           [&](const auto& measurement_timescales) {
     130             :             const std::string& measurement_name =
     131             :                 control_system::combined_name<ControlSystems>();
     132             :             ASSERT(measurement_timescales.count(measurement_name) == 1,
     133             :                    "Control system trigger expects a measurement timescale "
     134             :                    "with the name '"
     135             :                        << measurement_name
     136             :                        << "' but could not find one. Available names are: "
     137             :                        << keys_of(measurement_timescales));
     138             :             measurement_times->update(
     139             :                 *measurement_timescales.at(measurement_name));
     140             :             if (not measurement_times->next_measurement().has_value()) {
     141             :               if constexpr (Parallel::is_dg_element_collection_v<Component>) {
     142             :                 // Note: The ArrayComponentId is still created with the
     143             :                 // array_index (ElementId) because we only support 1 callback
     144             :                 // per ArrayComponentId. This would mean for nodegroups we would
     145             :                 // discard a lot of callbacks that we need. Alternatively, the
     146             :                 // callback could do a broadcast to all elements on the
     147             :                 // nodegroup.
     148             :                 const auto element_location = static_cast<int>(
     149             :                     Parallel::local_synchronous_action<
     150             :                         Parallel::Actions::GetItemFromDistributedOject<
     151             :                             Parallel::Tags::ElementLocations<Dim>>>(
     152             :                         Parallel::get_parallel_component<Component>(cache))
     153             :                         ->at(array_index));
     154             :                 return std::unique_ptr<Parallel::Callback>(
     155             :                     new Parallel::ThreadedActionCallback<
     156             :                         Parallel::Actions::PerformAlgorithmOnElement<false>,
     157             :                         decltype(proxy[element_location]),
     158             :                         std::decay_t<decltype(array_index)>>{
     159             :                         proxy[element_location], array_index});
     160             :               } else {
     161             :                 return std::unique_ptr<Parallel::Callback>(
     162             :                     new Parallel::PerformAlgorithmCallback(proxy[array_index]));
     163             :               }
     164             :             }
     165             :             return std::unique_ptr<Parallel::Callback>{};
     166             :           });
     167             : 
     168             :       if (not is_ready) {
     169             :         if (Parallel::get<Tags::Verbosity>(cache) >= ::Verbosity::Debug) {
     170             :           Parallel::printf(
     171             :               "%s, time = %.16f: Trigger for control systems (%s) - Cannot "
     172             :               "calculate next_check_time\n",
     173             :               get_output(array_index), time,
     174             :               pretty_type::list_of_names<ControlSystems>());
     175             :         }
     176             :         return std::nullopt;
     177             :       }
     178             :     }
     179             : 
     180             :     const double next_trigger = *measurement_times->next_measurement();
     181             :     ASSERT(next_trigger > time,
     182             :            "Next trigger is in the past: " << next_trigger << " > " << time);
     183             : 
     184             :     if (Parallel::get<Tags::Verbosity>(cache) >= ::Verbosity::Debug) {
     185             :       Parallel::printf(
     186             :           "%s, time = %.16f: Trigger for control systems (%s) - next check "
     187             :           "time is %.16f\n",
     188             :           get_output(array_index), time,
     189             :           pretty_type::list_of_names<ControlSystems>(), next_trigger);
     190             :     }
     191             : 
     192             :     return {next_trigger};
     193             :   }
     194             : };
     195             : 
     196             : /// \cond
     197             : template <typename ControlSystems>
     198             : PUP::able::PUP_ID Trigger<ControlSystems>::my_PUP_ID = 0;  // NOLINT
     199             : /// \endcond
     200             : 
     201             : // This metafunction is tested in Test_EventTriggerMetafunctions.cpp
     202             : 
     203             : /// \ingroup ControlSystemGroup
     204             : /// The list of triggers needed for measurements for a list of control
     205             : /// systems.
     206             : template <typename ControlSystems>
     207           1 : using control_system_triggers = tmpl::transform<
     208             :     metafunctions::measurements_t<ControlSystems>,
     209             :     tmpl::bind<Trigger, metafunctions::control_systems_with_measurement<
     210             :                             tmpl::pin<ControlSystems>, tmpl::_1>>>;
     211             : }  // namespace control_system

Generated by: LCOV version 1.14