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> // IWYU pragma: keep 9 : #include <vector> 10 : 11 : #include "DataStructures/DataBox/DataBox.hpp" 12 : #include "DataStructures/DataBox/ObservationBox.hpp" 13 : #include "Options/String.hpp" 14 : #include "ParallelAlgorithms/EventsAndTriggers/Event.hpp" 15 : #include "ParallelAlgorithms/EventsAndTriggers/Trigger.hpp" 16 : #include "Utilities/Gsl.hpp" 17 : #include "Utilities/TMPL.hpp" 18 : 19 : /// \cond 20 : namespace Parallel { 21 : template <typename Metavariables> 22 : class GlobalCache; 23 : } // namespace Parallel 24 : namespace db { 25 : template <typename TagsList> 26 : class DataBox; 27 : } // namespace db 28 : /// \endcond 29 : 30 : /// \ingroup EventsAndTriggersGroup 31 : /// Class that checks triggers and runs events 32 1 : class EventsAndTriggers { 33 : private: 34 : template <typename Event> 35 0 : struct get_tags { 36 0 : using type = typename Event::compute_tags_for_observation_box; 37 : }; 38 : 39 : public: 40 0 : struct TriggerAndEvents { 41 0 : struct Trigger { 42 0 : using type = std::unique_ptr<::Trigger>; 43 0 : static constexpr Options::String help = "Determines when the Events run."; 44 : }; 45 0 : struct Events { 46 0 : using type = std::vector<std::unique_ptr<::Event>>; 47 0 : static constexpr Options::String help = 48 : "These events run when the Trigger fires."; 49 : }; 50 0 : static constexpr Options::String help = 51 : "Events that run when the Trigger fires."; 52 0 : using options = tmpl::list<Trigger, Events>; 53 0 : void pup(PUP::er& p) { 54 : p | trigger; 55 : p | events; 56 : } 57 0 : std::unique_ptr<::Trigger> trigger; 58 0 : std::vector<std::unique_ptr<::Event>> events; 59 : }; 60 : 61 0 : using Storage = std::vector<TriggerAndEvents>; 62 : 63 0 : EventsAndTriggers() = default; 64 0 : explicit EventsAndTriggers(Storage events_and_triggers) 65 : : events_and_triggers_(std::move(events_and_triggers)) {} 66 : 67 : /// Check the triggers and run the associated events. 68 : /// 69 : /// By default the trigger check just calls the `is_triggered` 70 : /// method, but the last argument can be passed to override this. 71 : /// It must be a functor taking a `const Trigger&` and returning 72 : /// `bool`. 73 : template <typename DbTags, typename Metavariables, typename ArrayIndex, 74 : typename Component, typename CheckTrigger = std::nullptr_t> 75 1 : void run_events(const gsl::not_null<db::DataBox<DbTags>*> box, 76 : Parallel::GlobalCache<Metavariables>& cache, 77 : const ArrayIndex& array_index, const Component* component, 78 : const Event::ObservationValue& observation_value, 79 : const CheckTrigger& check_trigger = nullptr) const { 80 : using compute_tags = tmpl::remove_duplicates<tmpl::filter< 81 : tmpl::flatten<tmpl::transform< 82 : tmpl::at<typename Metavariables::factory_creation::factory_classes, 83 : Event>, 84 : get_tags<tmpl::_1>>>, 85 : db::is_compute_tag<tmpl::_1>>>; 86 : std::optional<decltype(make_observation_box<compute_tags>(box))> 87 : observation_box{}; 88 : for (const auto& trigger_and_events : events_and_triggers_) { 89 : const auto& trigger = trigger_and_events.trigger; 90 : const auto& events = trigger_and_events.events; 91 : const bool is_triggered = [&]() { 92 : if constexpr (std::is_same_v<std::decay_t<CheckTrigger>, 93 : std::nullptr_t>) { 94 : return trigger->is_triggered(*box); 95 : } else { 96 : return check_trigger(std::as_const(*trigger)); 97 : } 98 : }(); 99 : if (is_triggered) { 100 : if (not observation_box.has_value()) { 101 : observation_box = make_observation_box<compute_tags>(box); 102 : } 103 : for (const auto& event : events) { 104 : event->run(make_not_null(&observation_box.value()), cache, 105 : array_index, component, observation_value); 106 : } 107 : } 108 : } 109 : } 110 : 111 : // NOLINTNEXTLINE(google-runtime-references) 112 0 : void pup(PUP::er& p) { p | events_and_triggers_; } 113 : 114 : template <typename F> 115 0 : void for_each_event(F&& f) const { 116 : for (const auto& trigger_and_events : events_and_triggers_) { 117 : for (const auto& event : trigger_and_events.events) { 118 : f(*event); 119 : } 120 : } 121 : } 122 : 123 : private: 124 : // The unique pointer contents *must* be treated as const everywhere 125 : // in order to make the const global cache behave sanely. They are 126 : // only non-const to make pup work. 127 0 : Storage events_and_triggers_; 128 : }; 129 : 130 : template <> 131 0 : struct Options::create_from_yaml<EventsAndTriggers> { 132 0 : using type = EventsAndTriggers; 133 : template <typename Metavariables> 134 0 : static type create(const Options::Option& options) { 135 : return type(options.parse_as<typename type::Storage, Metavariables>()); 136 : } 137 : };