SpECTRE Documentation Coverage Report
Current view: top level - ControlSystem - Trigger.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 16.7 % 12 2
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 <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 2.0-1