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 : static_assert(
110 : std::is_same_v<decltype(ConformingType::deriv_order), const size_t>);
111 :
112 0 : using process_measurement_argument_tags =
113 : tmpl::transform<typename measurement::submeasurements,
114 : check_process_measurement_argument_tags<tmpl::_1>>;
115 :
116 : // We can't check the apply operator, because the tags may be
117 : // incomplete types, so we don't know what the argument types are.
118 : };
119 : };
120 : } // namespace control_system::protocols
|