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 <cmath> 8 : #include <cstddef> 9 : #include <optional> 10 : #include <string> 11 : 12 : #include "ControlSystem/Component.hpp" 13 : #include "ControlSystem/ControlErrors/Shape.hpp" 14 : #include "ControlSystem/Measurements/BothHorizons.hpp" 15 : #include "ControlSystem/Measurements/SingleHorizon.hpp" 16 : #include "ControlSystem/Protocols/ControlError.hpp" 17 : #include "ControlSystem/Protocols/ControlSystem.hpp" 18 : #include "ControlSystem/Protocols/Measurement.hpp" 19 : #include "ControlSystem/Tags/QueueTags.hpp" 20 : #include "ControlSystem/Tags/SystemTags.hpp" 21 : #include "ControlSystem/UpdateControlSystem.hpp" 22 : #include "DataStructures/DataBox/DataBox.hpp" 23 : #include "DataStructures/DataBox/Tag.hpp" 24 : #include "DataStructures/LinkedMessageQueue.hpp" 25 : #include "Domain/Structure/ObjectLabel.hpp" 26 : #include "NumericalAlgorithms/SphericalHarmonics/SpherepackIterator.hpp" 27 : #include "NumericalAlgorithms/SphericalHarmonics/Strahlkorper.hpp" 28 : #include "NumericalAlgorithms/SphericalHarmonics/Tags.hpp" 29 : #include "Parallel/GlobalCache.hpp" 30 : #include "Parallel/Printf/Printf.hpp" 31 : #include "ParallelAlgorithms/Actions/UpdateMessageQueue.hpp" 32 : #include "Utilities/GetOutput.hpp" 33 : #include "Utilities/ProtocolHelpers.hpp" 34 : #include "Utilities/TMPL.hpp" 35 : 36 : /// \cond 37 : namespace Frame { 38 : struct Distorted; 39 : } // namespace Frame 40 : /// \endcond 41 : 42 : namespace control_system::Systems { 43 : /*! 44 : * \brief Controls the \link domain::CoordinateMaps::TimeDependent::Shape Shape 45 : * \endlink map 46 : * 47 : * \details Controls the functions \f$ \lambda_{lm}(t) \f$ in the \link 48 : * domain::CoordinateMaps::TimeDependent::Shape Shape \endlink map to match the 49 : * shape of the excision sphere to the shape of the horizon. 50 : * 51 : * Requirements: 52 : * - This control system requires that there be at least one excision surface in 53 : * the simulation 54 : * - Currently this control system can only be used with the \link 55 : * control_system::measurements::BothHorizons BothHorizons \endlink 56 : * measurement 57 : * - Currently this control system can only be used with the \link 58 : * control_system::ControlErrors::Shape Shape \endlink control error 59 : */ 60 : template <::domain::ObjectLabel Object, size_t DerivOrder, typename Measurement> 61 1 : struct Shape : tt::ConformsTo<protocols::ControlSystem> { 62 0 : static constexpr size_t deriv_order = DerivOrder; 63 : 64 0 : static std::string name() { return "Shape"s + ::domain::name(Object); } 65 : 66 0 : static std::optional<std::string> component_name( 67 : const size_t i, const size_t num_components) { 68 : // num_components = 2 * (l_max + 1)**2 if l_max == m_max which it is for the 69 : // shape map. This is why we can divide by 2 and take the sqrt without 70 : // worrying about odd numbers or non-perfect squares 71 : const size_t l_max = -1 + sqrt(num_components / 2); 72 : ylm::SpherepackIterator iter(l_max, l_max); 73 : const auto compact_index = iter.compact_index(i); 74 : if (compact_index.has_value()) { 75 : iter.set(compact_index.value()); 76 : const int m = iter.coefficient_array() == 77 : ylm::SpherepackIterator::CoefficientArray::a 78 : ? static_cast<int>(iter.m()) 79 : : -static_cast<int>(iter.m()); 80 : return {"l"s + get_output(iter.l()) + "m"s + get_output(m)}; 81 : } else { 82 : return std::nullopt; 83 : } 84 : } 85 : 86 0 : using measurement = Measurement; 87 : static_assert( 88 : std::is_same_v<measurement, measurements::SingleHorizon<Object>> or 89 : std::is_same_v<measurement, measurements::BothHorizons>, 90 : "Must use either SingleHorizon or BothHorizon measurement for Shape " 91 : "control system."); 92 : static_assert( 93 : tt::conforms_to_v<measurement, control_system::protocols::Measurement>); 94 : 95 0 : using control_error = ControlErrors::Shape<Object>; 96 : static_assert(tt::conforms_to_v<control_error, 97 : control_system::protocols::ControlError>); 98 : 99 : // tag goes in control component 100 0 : struct MeasurementQueue : db::SimpleTag { 101 0 : using type = LinkedMessageQueue< 102 : double, tmpl::list<QueueTags::Horizon<Frame::Distorted, Object>>>; 103 : }; 104 : 105 0 : using simple_tags = tmpl::list<MeasurementQueue>; 106 : 107 0 : struct process_measurement { 108 : template <typename Submeasurement> 109 0 : using argument_tags = tmpl::list<ylm::Tags::Strahlkorper<Frame::Distorted>>; 110 : 111 : template <typename Metavariables> 112 0 : static void apply(typename measurements::SingleHorizon< 113 : Object>::Submeasurement submeasurement, 114 : const ylm::Strahlkorper<Frame::Distorted>& strahlkorper, 115 : Parallel::GlobalCache<Metavariables>& cache, 116 : const LinkedMessageId<double>& measurement_id) { 117 : auto& control_sys_proxy = Parallel::get_parallel_component< 118 : ControlComponent<Metavariables, Shape>>(cache); 119 : 120 : Parallel::simple_action<::Actions::UpdateMessageQueue< 121 : MeasurementQueue, UpdateControlSystem<Shape>, 122 : QueueTags::Horizon<Frame::Distorted, Object>>>( 123 : control_sys_proxy, measurement_id, strahlkorper); 124 : 125 : if (Parallel::get<Tags::Verbosity>(cache) >= ::Verbosity::Verbose) { 126 : Parallel::printf("%s, time = %.16f: Received measurement '%s'.\n", 127 : name(), measurement_id.id, 128 : pretty_type::name(submeasurement)); 129 : } 130 : } 131 : 132 : template <::domain::ObjectLabel MeasureHorizon, typename Metavariables> 133 0 : static void apply( 134 : measurements::BothHorizons::FindHorizon<MeasureHorizon> submeasurement, 135 : const ylm::Strahlkorper<Frame::Distorted>& strahlkorper, 136 : Parallel::GlobalCache<Metavariables>& cache, 137 : const LinkedMessageId<double>& measurement_id) { 138 : // The measurement event will call this for both horizons, but we only 139 : // need one of the horizons. So if it is called for the wrong horizon, 140 : // just do nothing. 141 : if constexpr (MeasureHorizon == Object) { 142 : auto& control_sys_proxy = Parallel::get_parallel_component< 143 : ControlComponent<Metavariables, Shape>>(cache); 144 : 145 : Parallel::simple_action<::Actions::UpdateMessageQueue< 146 : MeasurementQueue, UpdateControlSystem<Shape>, 147 : QueueTags::Horizon<Frame::Distorted, Object>>>( 148 : control_sys_proxy, measurement_id, strahlkorper); 149 : 150 : if (Parallel::get<Tags::Verbosity>(cache) >= ::Verbosity::Verbose) { 151 : Parallel::printf("%s, time = %.16f: Received measurement '%s'.\n", 152 : name(), measurement_id.id, 153 : pretty_type::name(submeasurement)); 154 : } 155 : } else { 156 : (void)submeasurement; 157 : (void)strahlkorper; 158 : (void)cache; 159 : (void)measurement_id; 160 : } 161 : } 162 : }; 163 : }; 164 : } // namespace control_system::Systems