Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <string> 7 : 8 : #include "DataStructures/ComplexDataVector.hpp" 9 : #include "DataStructures/ComplexModalVector.hpp" 10 : #include "DataStructures/DataBox/Tag.hpp" 11 : #include "DataStructures/DataBox/TagName.hpp" 12 : #include "DataStructures/SpinWeighted.hpp" 13 : #include "DataStructures/Tensor/Tensor.hpp" 14 : #include "DataStructures/Tensor/TypeAliases.hpp" 15 : #include "Utilities/TMPL.hpp" 16 : #include "Utilities/TypeTraits.hpp" 17 : 18 : namespace Spectral { 19 : namespace Swsh { 20 : /// \cond 21 : class SwshInterpolator; 22 : /// \endcond 23 : 24 0 : namespace Tags { 25 : 26 : /// \ingroup SwshGroup 27 : /// \brief Struct for labeling the \f$\eth\f$ spin-weighted derivative in tags 28 1 : struct Eth {}; 29 : /// \ingroup SwshGroup 30 : /// \brief Struct for labeling the \f$\bar{\eth}\f$ spin-weighted derivative in 31 : /// tags 32 1 : struct Ethbar {}; 33 : /// \ingroup SwshGroup 34 : /// \brief Struct for labeling the \f$\eth^2\f$ spin-weighted derivative in tags 35 1 : struct EthEth {}; 36 : /// \ingroup SwshGroup 37 : /// \brief Struct for labeling the \f$\bar{\eth} \eth\f$ spin-weighted 38 : /// derivative in tags 39 1 : struct EthbarEth {}; 40 : /// \ingroup SwshGroup 41 : /// \brief Struct for labeling the \f$\eth \bar{\eth}\f$ spin-weighted 42 : /// derivative in tags 43 1 : struct EthEthbar {}; 44 : /// \ingroup SwshGroup 45 : /// \brief Struct for labeling the \f$\bar{\eth}^2\f$ spin-weighted derivative 46 : /// in tags 47 1 : struct EthbarEthbar {}; 48 : 49 : /// \ingroup SwshGroup 50 : /// \brief Struct for labeling the inverse \f$\eth^{-1}\f$ spin-weighted 51 : /// derivative in tags 52 1 : struct InverseEth {}; 53 : /// \ingroup SwshGroup 54 : /// \brief Struct for labeling the inverse\f$\bar{\eth}^{-1}\f$ spin-weighted 55 : /// derivative in tags 56 1 : struct InverseEthbar {}; 57 : 58 : /// \brief Struct which acts as a placeholder for a spin-weighted derivative 59 : /// label in the spin-weighted derivative utilities, but represents a 'no-op': 60 : /// no derivative is taken. 61 1 : struct NoDerivative {}; 62 : 63 : namespace detail { 64 : template <typename DerivativeKind> 65 : inline constexpr int derivative_spin_weight_impl() { 66 : if (std::is_same_v<DerivativeKind, Eth> or 67 : std::is_same_v<DerivativeKind, InverseEthbar>) { 68 : return 1; 69 : } else if (std::is_same_v<DerivativeKind, Ethbar> or 70 : std::is_same_v<DerivativeKind, InverseEth>) { 71 : return -1; 72 : } else if (std::is_same_v<DerivativeKind, EthEth>) { 73 : return 2; 74 : } else if (std::is_same_v<DerivativeKind, EthbarEthbar>) { 75 : return -2; 76 : } 77 : return 0; 78 : } 79 : } // namespace detail 80 : 81 : // utility function for determining the change of spin after a spin-weighted 82 : // derivative has been applied. 83 : template <typename DerivativeKind> 84 0 : constexpr int derivative_spin_weight = 85 : detail::derivative_spin_weight_impl<DerivativeKind>(); 86 : 87 : namespace detail { 88 : // The below tags are used to find the new type represented by the spin-weighted 89 : // derivative of a spin-weighted quantity. The derivatives alter the spin 90 : // weights, and so the utility `adjust_spin_weight_t<Tag, DerivativeKind>` is a 91 : // metafunction that determines the correct spin-weighted type for the 92 : // spin-weighted derivative `DerivativeKind` of `Tag`. 93 : // 94 : // if there is no `Tag::type::spin`, but the internal type is a compatible 95 : // complex vector type, the spin associated with `Tag` is assumed to be 0. 96 : template <typename DataType, typename DerivativeKind> 97 : struct adjust_spin_weight { 98 : using type = 99 : Scalar<SpinWeighted<DataType, derivative_spin_weight<DerivativeKind>>>; 100 : }; 101 : 102 : // case for if there is a `Tag::type::spin` 103 : template <typename DataType, int Spin, typename DerivativeKind> 104 : struct adjust_spin_weight<SpinWeighted<DataType, Spin>, DerivativeKind> { 105 : using type = Scalar< 106 : SpinWeighted<DataType, Spin + derivative_spin_weight<DerivativeKind>>>; 107 : }; 108 : 109 : template <typename Tag, typename DerivativeKind> 110 : using adjust_spin_weight_t = 111 : typename adjust_spin_weight<typename Tag::type::type, DerivativeKind>::type; 112 : 113 : // Helper function for creating an appropriate prefix tag name from one of the 114 : // spin-weighted derivative types and an existing tag name 115 : template <typename DerivativeKind> 116 : std::string compose_spin_weighted_derivative_name(const std::string& suffix); 117 : 118 : } // namespace detail 119 : 120 : /// Convenience metafunction for accessing the tag from which a `Derivative` was 121 : /// derived. 122 : template <typename Tag> 123 1 : using derived_from = typename Tag::derived_from; 124 : 125 : /// \ingroup SwshGroup 126 : /// \brief Prefix tag representing the spin-weighted derivative of a 127 : /// spin-weighted scalar. 128 : /// 129 : /// Template Parameters: 130 : /// - `Tag`: The tag to prefix 131 : /// - `DerivativeKind`: The type of spin-weighted derivative. This may be any of 132 : /// the labeling structs: `Eth`, `Ethbar`, `EthEth`, `EthbarEth`, `EthEthbar`, 133 : /// `EthbarEthbar`, or `NoDerivative`. 134 : /// 135 : /// Type Aliases and static values: 136 : /// - `type`: Always a `SpinWeighted<Scalar<ComplexDataVector>, Spin>`, where 137 : /// `Spin` is the spin weight after the derivative `DerivativeKind` has been 138 : /// applied. 139 : /// - `tag`: An alias to the wrapped tag `Tag`. Provided for applicability to 140 : /// general `db::PrefixTag` functionality. 141 : /// - `derivative_of`: Another alias to the wrapped tag `Tag`. Provided so that 142 : /// utilities that use this prefix for taking derivatives can have a more 143 : /// expressive code style. 144 : /// - `derivative_kind`: Type alias to `DerivativeKind`, represents the kind of 145 : /// spin-weighted derivative applied to `Tag` 146 : /// - `spin`: The spin weight of the scalar after the derivative has been 147 : /// applied. 148 : template <typename Tag, typename DerivativeKind> 149 1 : struct Derivative : db::PrefixTag, db::SimpleTag { 150 0 : using type = detail::adjust_spin_weight_t<Tag, DerivativeKind>; 151 0 : using tag = Tag; 152 : // derivative_of is provided as a second alias so that utilities that assume a 153 : // derivative prefix tag fail earlier during compilation 154 0 : using derivative_of = Tag; 155 0 : using derivative_kind = DerivativeKind; 156 0 : const static int spin = type::type::spin; 157 0 : static std::string name() { 158 : return detail::compose_spin_weighted_derivative_name<DerivativeKind>( 159 : db::tag_name<Tag>()); 160 : } 161 : }; 162 : 163 : /// \ingroup SwshGroup 164 : /// \brief Prefix tag representing the spin-weighted spherical harmonic 165 : /// transform of a spin-weighted scalar. 166 : /// 167 : /// Template Parameters: 168 : /// - `Tag`: The tag to prefix. 169 : /// 170 : /// Type aliases and static values: 171 : /// - `type`: Always a `SpinWeighted<Scalar<ComplexModalVector>, Spin>`, where 172 : /// `Spin` is the same spin weight of the pre-transformed `Tag`, and 0 if 173 : /// provided a `Tag` with a `Type` that is not `SpinWeighted` 174 : /// - `tag`: An alias to the wrapped tag `Tag`. Provided for applicability to 175 : /// general `db::PrefixTag` functionality 176 : /// - `transform_of`: Another alias to the wrapped tag `Tag`. Provided so that 177 : /// utilities that use this prefix for taking transforms can have a more 178 : /// expressive code style. 179 : template <typename Tag> 180 1 : struct SwshTransform : db::PrefixTag, db::SimpleTag { 181 0 : using type = Scalar<SpinWeighted< 182 : ComplexModalVector, 183 : detail::adjust_spin_weight_t<Tag, NoDerivative>::type::spin>>; 184 0 : using tag = Tag; 185 : // transform_of is provided as a second alias so that utilities that assume a 186 : // derivative prefix tag fail earlier during compilation 187 0 : using transform_of = Tag; 188 0 : const static int spin = type::type::spin; 189 : }; 190 : 191 : /// \ingroup SwshGroup 192 : /// \brief Base Tag for the maximum spin-weighted spherical harmonic l; sets 193 : /// angular resolution. 194 1 : struct LMaxBase : db::BaseTag {}; 195 : 196 : /// \ingroup SwshGroup 197 : /// \brief Tag for the maximum spin-weighted spherical harmonic l; sets angular 198 : /// resolution. 199 1 : struct LMax : db::SimpleTag, LMaxBase { 200 0 : using type = size_t; 201 : }; 202 : 203 : /// \ingroup SwshGroup 204 : /// \brief Base Tag for the number of radial grid points in the 205 : /// three-dimensional representation of radially concentric spherical shells. 206 1 : struct NumberOfRadialPointsBase : db::BaseTag {}; 207 : 208 : /// \ingroup SwshGroup 209 : /// \brief Tag for the number of radial grid points in the three-dimensional 210 : /// representation of radially concentric spherical shells 211 1 : struct NumberOfRadialPoints : db::SimpleTag, NumberOfRadialPointsBase { 212 0 : using type = size_t; 213 : }; 214 : 215 : /// \ingroup SwshGroup 216 : /// \brief Tag for a SwshInterpolator associated with a particular set 217 : /// of angular coordinates. 218 : /// 219 : /// \details It is recommended to use this to store a `SwshInterpolator` in the 220 : /// \ref DataBoxGroup of a parallel component, as interpolations can be 221 : /// significantly faster if they don't have to re-construct the 222 : /// `SwhsInterpolator` as frequently. 223 : template <typename Tag> 224 1 : struct SwshInterpolator : db::SimpleTag, db::PrefixTag { 225 0 : using tag = Tag; 226 0 : using type = ::Spectral::Swsh::SwshInterpolator; 227 : }; 228 : 229 : } // namespace Tags 230 : 231 : namespace detail { 232 : // implementation for get_tags_with_spin 233 : template <typename Tag, typename S> 234 : struct has_spin : std::bool_constant<Tag::type::type::spin == S::value> {}; 235 : 236 : template <typename PrefixTag, typename S> 237 : struct wrapped_has_spin : has_spin<typename PrefixTag::tag, S> {}; 238 : 239 : } // namespace detail 240 : 241 : /// \ingroup SwshGroup 242 : /// \brief A metafunction for determining the coefficient buffers needed by 243 : /// `angular_derivatives()` to avoid repeatedly allocating space for modal 244 : /// data each time a derivative is taken. 245 : /// \note Using these buffers is required to use the batch 246 : /// `angular_derivatives()` rather than the individual `angular_derivative()`. 247 : template <typename DerivativeTag> 248 1 : using coefficient_buffer_tags_for_derivative_tag = tmpl::list< 249 : Spectral::Swsh::Tags::SwshTransform<typename DerivativeTag::derivative_of>, 250 : Spectral::Swsh::Tags::SwshTransform<DerivativeTag>>; 251 : 252 : /// \ingroup SwshGroup 253 : /// \brief Extract from `TagList` the subset of those tags that have a static 254 : /// int member `spin` equal to the template parameter `Spin`. 255 : /// 256 : /// \snippet Test_SwshTags.cpp get_tags_with_spin 257 : template <int Spin, typename TagList> 258 1 : using get_tags_with_spin = tmpl::remove_duplicates<tmpl::filter< 259 : TagList, detail::has_spin<tmpl::_1, std::integral_constant<int, Spin>>>>; 260 : 261 : /// \ingroup SwshGroup 262 : /// \brief Extract from `TagList` the subset of those tags that wrap a tag 263 : /// that has a static int member `spin` equal to the template parameter `Spin`. 264 : /// 265 : /// \snippet Test_SwshTags.cpp get_prefix_tags_that_wrap_tags_with_spin 266 : template <int Spin, typename TagList> 267 1 : using get_prefix_tags_that_wrap_tags_with_spin = 268 : tmpl::filter<TagList, tmpl::bind<detail::wrapped_has_spin, tmpl::_1, 269 : std::integral_constant<int, Spin>>>; 270 : 271 : } // namespace Swsh 272 : } // namespace Spectral