Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <cstddef> 7 : #include <optional> 8 : #include <string> 9 : #include <type_traits> 10 : 11 : #include "ControlSystem/Protocols/ControlError.hpp" 12 : #include "ControlSystem/Protocols/Measurement.hpp" 13 : #include "Utilities/ProtocolHelpers.hpp" 14 : #include "Utilities/TMPL.hpp" 15 : 16 : namespace control_system::protocols { 17 : /// \brief Definition of a control system 18 : /// 19 : /// Defines a control system for controlling a FunctionOfTime. 20 : /// 21 : /// A conforming class must provide the following functionality: 22 : /// 23 : /// - a static function `name` returning a `std::string`. This 24 : /// corresponds to the name of the FunctionOfTime controlled by this 25 : /// system. 26 : /// 27 : /// - a static function `component_name` returning a 28 : /// `std::optional<std::string>`. This gives a name associated to each 29 : /// component of the FunctionOfTime that is being controlled. E.g. a 30 : /// FunctionOfTime controlling translation will have three components with 31 : /// names "X", "Y", and "Z". This is useful when writing data to disk. The 32 : /// reason this is a `std::optional` rather than just a `std::string` is 33 : /// because of shape control. Since the vector of coefficients of the shape 34 : /// map is stored in ylm::Spherepack order, not all components of this vector 35 : /// correspond to an actual l,m pair (see ylm::Spherepack for why this is). 36 : /// Thus, this is a `std::optional` to signify if a component of the 37 : /// FunctionOfTime isn't actually used and shouldn't be written to disk. 38 : /// 39 : /// - a type alias `measurement` to a struct implementing the 40 : /// Measurement protocol. 41 : /// 42 : /// - a type alias `simple_tags` to a `tmpl::list` of simple tags needed for the 43 : /// control system. These tags will be added to the DataBox of the 44 : /// ControlComponent. The list may be empty. 45 : /// 46 : /// - a type alias `control_error` to a struct that conforms to the ControlError 47 : /// protocol 48 : /// 49 : /// - a static constexpr size_t `deriv_order` which is the order of the highest 50 : /// derivative of a FunctionOfTime that you wish to control. Typically, this 51 : /// is the order of the FunctionOfTime itself. 52 : /// 53 : /// - a member struct (or type alias) `process_measurement`, defining 54 : /// the following: 55 : /// 56 : /// - a templated type alias `argument_tags`, which must produce a 57 : /// `tmpl::list` of tags when instantiated for any submeasurement 58 : /// of the control system's `measurement`. 59 : /// 60 : /// - a static function `apply` that accepts as arguments: 61 : /// 62 : /// - any submeasurement of the control system's `measurement`. 63 : /// For measurements with multiple submeasurements, this can be 64 : /// accomplished either by a template parameter or by 65 : /// overloading the function. 66 : /// 67 : /// - the values corresponding to `argument_tags` instantiated with the 68 : /// type of the first argument. 69 : /// 70 : /// - the global cache `Parallel::GlobalCache<Metavariables>&` 71 : /// 72 : /// - a `const LinkedMessageId<double>&` identifying the 73 : /// measurement, with the `id` field being the measurement time. 74 : /// 75 : /// The `apply` function will be called once for each submeasurement 76 : /// of the control system's `measurement` using data from the 77 : /// `DataBox` passed to `RunCallbacks`. It should communicate any 78 : /// necessary data to the control system singleton. 79 : /// 80 : /// Here's an example for a class conforming to this protocol: 81 : /// 82 : /// \snippet Helpers/ControlSystem/Examples.hpp ControlSystem 83 1 : struct ControlSystem { 84 : template <typename ConformingType> 85 0 : struct test { 86 : static_assert(std::is_same_v<std::decay_t<decltype(ConformingType::name())>, 87 : std::string>); 88 : 89 : static_assert(std::is_same_v<decltype(ConformingType::component_name( 90 : std::declval<const size_t>(), 91 : std::declval<const size_t>())), 92 : std::optional<std::string>>); 93 : 94 0 : using measurement = typename ConformingType::measurement; 95 : static_assert(tt::assert_conforms_to_v<measurement, Measurement>); 96 : 97 : template <typename Submeasurement> 98 0 : struct check_process_measurement_argument_tags { 99 0 : using type = 100 : typename ConformingType::process_measurement::template argument_tags< 101 : Submeasurement>; 102 : }; 103 : 104 0 : using simple_tags = typename ConformingType::simple_tags; 105 : 106 0 : using control_error = typename ConformingType::control_error; 107 : static_assert(tt::assert_conforms_to_v<control_error, ControlError>); 108 : 109 0 : static constexpr size_t deriv_order = ConformingType::deriv_order; 110 : 111 0 : using process_measurement_argument_tags = 112 : tmpl::transform<typename measurement::submeasurements, 113 : check_process_measurement_argument_tags<tmpl::_1>>; 114 : 115 : // We can't check the apply operator, because the tags may be 116 : // incomplete types, so we don't know what the argument types are. 117 : }; 118 : }; 119 : } // namespace control_system::protocols