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 <boost/math/quaternion.hpp> 8 : #include <cstddef> 9 : #include <map> 10 : #include <memory> 11 : #include <ostream> 12 : #include <pup.h> 13 : #include <vector> 14 : 15 : #include "DataStructures/DataVector.hpp" 16 : #include "Domain/FunctionsOfTime/FunctionOfTime.hpp" 17 : #include "Domain/FunctionsOfTime/PiecewisePolynomial.hpp" 18 : #include "Domain/FunctionsOfTime/ThreadsafeList.hpp" 19 : #include "Utilities/Gsl.hpp" 20 : #include "Utilities/Serialization/CharmPupable.hpp" 21 : 22 : namespace domain::FunctionsOfTime { 23 : /*! 24 : * \ingroup ComputationalDomainGroup 25 : * \brief A FunctionOfTime that stores quaternions for the rotation map 26 : * 27 : * \details This FunctionOfTime stores quaternions that will be used in the 28 : * time-dependent rotation map as well as the orbital angular velocity that 29 : * will be controlled by the rotation control sytem. To get the quaternion, an 30 : * ODE is solved of the form \f$ \dot{q} = \frac{1}{2} q \times \omega \f$ 31 : * where \f$ \omega \f$ is the orbital angular velocity which is stored 32 : * internally as the derivative of an angle `PiecewisePolynomial`, and 33 : * \f$ \times \f$ here is quaternion multiplication. 34 : * 35 : * Different from a `PiecewisePolynomial`, only the quaternion 36 : * itself is stored, not any of the derivatives because the derivatives must be 37 : * calculated from the solved ODE at every function call. Because 38 : * derivatives of the quaternion are not stored, the template parameter 39 : * `MaxDeriv` refers to both the max derivative of the stored angle 40 : * PiecewisePolynomial and the max derivative returned by the 41 : * QuaternionFunctionOfTime. The `update` function is then just a wrapper 42 : * around the internal `PiecewisePolynomial::update` function with the addition 43 : * that it then updates the stored quaternions as well. 44 : * 45 : * \note The initial rotation angles passed to the angle PiecewisePolynomial 46 : * don't matter as we never actually use the angles themselves. We only use 47 : * their derivatives (angular velocity) to determine map parameters. In theory 48 : * we could determine each initial angle from the input axis-angle 49 : * representation, but we don't need to. 50 : * 51 : * The angle PiecewisePolynomial is accessible through the `angle_func`, 52 : * `angle_func_and_deriv`, and `angle_func_and_2_derivs` functions which 53 : * correspond to the function calls of a normal PiecewisePolynomial except 54 : * without the `angle_` prefix. 55 : * 56 : * It is encouraged to use `quat_func` and `angle_func` when you want the 57 : * specific values of the functions to avoid ambiguity in what you are 58 : * calling. However, the original three `func` functions inherited from the 59 : * FunctionOfTime base class are necessary because the maps use the generic 60 : * `func` functions, thus they return the quaternion and its derivatives (which 61 : * are needed for the map). This is all to keep the symmetry of naming 62 : * `angle_func` and `quat_func` so that function calls won't be ambiguous. 63 : * 64 : * \note This class conforms to the requirements of the 65 : * `Parallel::GlobalCache` for objects held by mutable global cache tags. 66 : */ 67 : template <size_t MaxDeriv> 68 1 : class QuaternionFunctionOfTime : public FunctionOfTime { 69 : public: 70 0 : QuaternionFunctionOfTime(); 71 0 : QuaternionFunctionOfTime(QuaternionFunctionOfTime&&); 72 0 : QuaternionFunctionOfTime(const QuaternionFunctionOfTime&); 73 0 : QuaternionFunctionOfTime& operator=(QuaternionFunctionOfTime&&); 74 0 : QuaternionFunctionOfTime& operator=(const QuaternionFunctionOfTime&); 75 0 : ~QuaternionFunctionOfTime() override; 76 : 77 0 : QuaternionFunctionOfTime( 78 : double t, const std::array<DataVector, 1>& initial_quat_func, 79 : std::array<DataVector, MaxDeriv + 1> initial_angle_func, 80 : double expiration_time); 81 : 82 : // LCOV_EXCL_START 83 0 : explicit QuaternionFunctionOfTime(CkMigrateMessage* /*unused*/); 84 : // LCOV_EXCL_STOP 85 : 86 0 : auto get_clone() const -> std::unique_ptr<FunctionOfTime> override; 87 : 88 1 : std::unique_ptr<FunctionOfTime> create_at_time( 89 : double t, double expiration_time) const override; 90 : 91 : // clang-tidy: google-runtime-references 92 : // clang-tidy: cppcoreguidelines-owning-memory,-warnings-as-errors 93 0 : WRAPPED_PUPable_decl_template(QuaternionFunctionOfTime<MaxDeriv>); // NOLINT 94 : 95 : /// Returns domain of validity for the function of time 96 1 : std::array<double, 2> time_bounds() const override; 97 : 98 1 : double expiration_after(double time) const override; 99 : 100 : /// Updates the `MaxDeriv`th derivative of the angle piecewisepolynomial at 101 : /// the given time, then updates the stored quaternions. 102 : /// 103 : /// `updated_max_deriv` is a datavector of the `MaxDeriv`s for each component. 104 : /// `next_expiration_time` is the next expiration time. 105 : /// 106 : /// The \p time_of_update must be the same as the old expiration 107 : /// time. It is passed as a check that the calling code is 108 : /// computing the other arguments with the correct value. 109 1 : void update(double time_of_update, DataVector updated_max_deriv, 110 : double next_expiration_time) override; 111 : 112 1 : void truncate_at_time(double time) override; 113 : 114 : // NOLINTNEXTLINE(google-runtime-references) 115 0 : void pup(PUP::er& p) override; 116 : 117 : /// Returns the quaternion at an arbitrary time `t`. 118 1 : std::array<DataVector, 1> func(const double t) const override { 119 : return quat_func(t); 120 : } 121 : 122 : /// Returns the quaternion and its first derivative at an arbitrary time `t`. 123 1 : std::array<DataVector, 2> func_and_deriv(const double t) const override { 124 : return quat_func_and_deriv(t); 125 : } 126 : 127 : /// Returns the quaternion and the first two derivatives at an arbitrary 128 : /// time `t`. 129 1 : std::array<DataVector, 3> func_and_2_derivs(const double t) const override { 130 : return quat_func_and_2_derivs(t); 131 : } 132 : 133 : /// Returns the quaternion at an arbitrary time `t`. 134 1 : std::array<DataVector, 1> quat_func(double t) const; 135 : 136 : /// Returns the quaternion and its first derivative at an arbitrary time `t`. 137 1 : std::array<DataVector, 2> quat_func_and_deriv(double t) const; 138 : 139 : /// Returns the quaternion and the first two derivatives at an arbitrary 140 : /// time `t`. 141 1 : std::array<DataVector, 3> quat_func_and_2_derivs(double t) const; 142 : 143 : /// Returns the quaternion and the first three derivatives at an arbitrary 144 : /// time `t`. 145 1 : std::array<DataVector, 4> quat_func_and_3_derivs(double t) const; 146 : 147 : /// Returns stored angle at an arbitrary time `t`. 148 1 : std::array<DataVector, 1> angle_func(const double t) const { 149 : return angle_f_of_t_.func(t); 150 : } 151 : 152 : /// Returns stored angle and its first derivative (omega) at an arbitrary time 153 : /// `t`. 154 1 : std::array<DataVector, 2> angle_func_and_deriv(const double t) const { 155 : return angle_f_of_t_.func_and_deriv(t); 156 : } 157 : 158 : /// Returns stored angle and the first two derivatives at an arbitrary 159 : /// time `t`. 160 1 : std::array<DataVector, 3> angle_func_and_2_derivs(const double t) const { 161 : return angle_f_of_t_.func_and_2_derivs(t); 162 : } 163 : 164 0 : std::vector<DataVector> angle_func_and_all_derivs(const double t) const { 165 : return angle_f_of_t_.func_and_all_derivs(t); 166 : } 167 : 168 : private: 169 : template <size_t LocalMaxDeriv> 170 0 : friend bool operator==( // NOLINT(readability-redundant-declaration) 171 : const QuaternionFunctionOfTime<LocalMaxDeriv>& lhs, 172 : const QuaternionFunctionOfTime<LocalMaxDeriv>& rhs); 173 : 174 : template <size_t LocalMaxDeriv> 175 0 : friend std::ostream& operator<<( // NOLINT(readability-redundant-declaration) 176 : std::ostream& os, 177 : const QuaternionFunctionOfTime<LocalMaxDeriv>& quaternion_f_of_t); 178 : 179 : FunctionOfTimeHelpers::ThreadsafeList<boost::math::quaternion<double>> 180 0 : stored_quaternions_and_times_{}; 181 0 : domain::FunctionsOfTime::PiecewisePolynomial<MaxDeriv> angle_f_of_t_{}; 182 0 : std::map<double, double> update_backlog_{}; 183 : 184 0 : void unpack_old_version(PUP::er& p, size_t version); 185 : 186 : /// Integrates the ODE \f$ \dot{q} = \frac{1}{2} q \times \omega \f$ from time 187 : /// `t0` to time `t`. On input, `quaternion_to_integrate` is the initial 188 : /// quaternion at time `t0` and on output, it stores the result at time `t` 189 1 : void solve_quaternion_ode( 190 : gsl::not_null<boost::math::quaternion<double>*> quaternion_to_integrate, 191 : double t0, double t) const; 192 : 193 : /// Does common operations to all the `func` functions such as updating stored 194 : /// info, solving the ODE, and returning the normalized quaternion as a boost 195 : /// quaternion for easy calculations 196 1 : boost::math::quaternion<double> setup_func(double t) const; 197 : }; 198 : 199 : template <size_t MaxDeriv> 200 0 : bool operator!=(const QuaternionFunctionOfTime<MaxDeriv>& lhs, 201 : const QuaternionFunctionOfTime<MaxDeriv>& rhs); 202 : 203 : /// \cond 204 : template <size_t MaxDeriv> 205 : PUP::able::PUP_ID QuaternionFunctionOfTime<MaxDeriv>::my_PUP_ID = 0; // NOLINT 206 : /// \endcond 207 : } // namespace domain::FunctionsOfTime