Line data Source code
1 1 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : /// \file
5 : /// Defines classes representing tensor indices
6 :
7 : #pragma once
8 :
9 : #include <cstddef>
10 : #include <ostream>
11 : #include <string>
12 : #include <type_traits>
13 :
14 : #include "Utilities/Literals.hpp" // IWYU pragma: keep
15 : #include "Utilities/TMPL.hpp"
16 :
17 : /// \ingroup TensorGroup
18 : /// Whether a \ref SpacetimeIndex "TensorIndexType" is covariant or
19 : /// contravariant
20 1 : enum class UpLo {
21 : /// Contravariant, or Upper index
22 : Up,
23 : /// Covariant, or Lower index
24 : Lo
25 : };
26 :
27 : /// \cond HIDDEN_SYMBOLS
28 : inline std::ostream& operator<<(std::ostream& os, const UpLo& ul) {
29 : return os << (ul == UpLo::Up ? "Up"s : "Lo"s);
30 : }
31 : /// \endcond
32 :
33 : /// \ingroup TensorGroup
34 : /// Indicates the ::Frame that a \ref SpacetimeIndex "TensorIndexType"
35 : /// is in.
36 1 : namespace Frame {
37 : /// \ingroup TensorGroup
38 : /// Marks a Frame as being "physical" in the sense that it is meaningful to
39 : /// evaluate an analytic solution in that frame.
40 1 : struct FrameIsPhysical {};
41 :
42 0 : struct BlockLogical {};
43 0 : struct ElementLogical {};
44 0 : struct Fluid {};
45 0 : struct Grid {};
46 0 : struct Inertial : FrameIsPhysical {};
47 0 : struct Distorted {};
48 : /// Represents an index that is not in a known frame, e.g. some internal
49 : /// intermediate frame that is irrelevant to the interface.
50 1 : struct NoFrame {};
51 :
52 : /// Represents a spherical-coordinate frame that is associated with a
53 : /// Cartesian frame, e.g. \f$(r,\theta,\phi)\f$ associated with the Inertial
54 : /// frame, as used on an apparent horizon or a wave-extraction surface.
55 : template <typename CartesianFrame>
56 1 : struct Spherical {};
57 :
58 : /// \ingroup TensorGroup
59 : /// Returns std::true_type if the frame is "physical" in the sense that it is
60 : /// meaningful to evaluate an analytic solution in that frame.
61 : /// \example
62 : /// \snippet Test_Tensor.cpp is_frame_physical
63 : template <typename CheckFrame>
64 1 : using is_frame_physical =
65 : std::integral_constant<bool,
66 : std::is_base_of<FrameIsPhysical, CheckFrame>::value>;
67 :
68 : /// \ingroup TensorGroup
69 : /// Returns true if the frame is "physical" in the sense that it is
70 : /// meaningful to evaluate an analytic solution in that frame.
71 : /// \example
72 : /// \snippet Test_Tensor.cpp is_frame_physical
73 : template <typename CheckFrame>
74 1 : constexpr bool is_frame_physical_v = is_frame_physical<CheckFrame>::value;
75 :
76 : /// \cond HIDDEN_SYMBOLS
77 : inline std::ostream& operator<<(std::ostream& os,
78 : const Frame::BlockLogical& /*meta*/) {
79 : return os << "BlockLogical";
80 : }
81 : inline std::ostream& operator<<(std::ostream& os,
82 : const Frame::ElementLogical& /*meta*/) {
83 : return os << "ElementLogical";
84 : }
85 : inline std::ostream& operator<<(std::ostream& os,
86 : const Frame::Fluid& /*meta*/) {
87 : return os << "Fluid";
88 : }
89 : inline std::ostream& operator<<(std::ostream& os,
90 : const Frame::Grid& /*meta*/) {
91 : return os << "Grid";
92 : }
93 : inline std::ostream& operator<<(std::ostream& os,
94 : const Frame::Inertial& /*meta*/) {
95 : return os << "Inertial";
96 : }
97 : inline std::ostream& operator<<(std::ostream& os,
98 : const Frame::Distorted& /*meta*/) {
99 : return os << "Distorted";
100 : }
101 : inline std::ostream& operator<<(std::ostream& os,
102 : const Frame::NoFrame& /*meta*/) {
103 : return os << "NoFrame";
104 : }
105 : /// \endcond
106 :
107 : /// \ingroup TensorGroup
108 : /// The frame-dependent prefix used when constructing the string returned by the
109 : /// name function of a tag.
110 : ///
111 : /// For Frame::Inertial it is the empty string, otherwise, it is the name of
112 : /// the Frame followed by an underscore (as the name will be used in I/O).
113 : /// \example
114 : /// \snippet Hydro/Test_Tags.cpp prefix_example
115 : template <typename Fr>
116 1 : inline std::string prefix();
117 :
118 : /// \cond HIDDEN_SYMBOLS
119 : template <>
120 : inline std::string prefix<Frame::BlockLogical>() {
121 : return "BlockLogical_";
122 : }
123 :
124 : template <>
125 : inline std::string prefix<Frame::ElementLogical>() {
126 : return "ElementLogical_";
127 : }
128 :
129 : template <>
130 : inline std::string prefix<Frame::Fluid>() {
131 : return "Fluid_";
132 : }
133 :
134 : template <>
135 : inline std::string prefix<Frame::Grid>() {
136 : return "Grid_";
137 : }
138 :
139 : template <>
140 : inline std::string prefix<Frame::Inertial>() {
141 : return "";
142 : }
143 :
144 : template <>
145 : inline std::string prefix<Frame::Distorted>() {
146 : return "Distorted_";
147 : }
148 : /// \endcond
149 : } // namespace Frame
150 :
151 : /// \ingroup TensorGroup
152 : /// Indicates whether the \ref SpacetimeIndex "TensorIndexType" is
153 : /// Spatial or Spacetime
154 1 : enum class IndexType : char {
155 : /// The \ref SpatialIndex "TensorIndexType" is purely spatial
156 : Spatial,
157 : /// The \ref SpacetimeIndex "TensorIndexType" is a spacetime index
158 : Spacetime
159 : };
160 :
161 : /// \cond HIDDEN_SYMBOLS
162 : inline std::ostream& operator<<(std::ostream& os, const IndexType& index_type) {
163 : return os << (index_type == IndexType::Spatial ? "Spatial" : "Spacetime");
164 : }
165 : /// \endcond
166 :
167 : namespace Tensor_detail {
168 : /// \ingroup TensorGroup
169 : /// A ::TensorIndexType holds information about what type of index an index of a
170 : /// Tensor is. It holds the information about the number of spatial dimensions,
171 : /// whether the index is covariant or contravariant (::UpLo), the ::Frame the
172 : /// index is in, and whether the Index is Spatial or Spacetime.
173 : /// \tparam SpatialDim the spatial dimensionality of the TensorIndex
174 : /// \tparam Ul either UpLo::Up or UpLo::Lo for contra or covariant
175 : /// \tparam Fr the Frame the TensorIndex is in
176 : /// \tparam Index either IndexType::Spatial or IndexType::Spacetime
177 : template <size_t SpatialDim, UpLo Ul, typename Fr, IndexType Index>
178 : struct TensorIndexType {
179 : static_assert(SpatialDim > 0,
180 : "Cannot have a spatial dimensionality less than 1 (one) in a "
181 : "TensorIndexType");
182 : using value_type = decltype(SpatialDim);
183 : static constexpr value_type dim =
184 : Index == IndexType::Spatial ? SpatialDim
185 : : SpatialDim + static_cast<value_type>(1);
186 : // value is here just so that some generic metafunctions can retrieve the dim
187 : // easily
188 : static constexpr value_type value = dim;
189 : static constexpr UpLo ul = Ul;
190 : using Frame = Fr;
191 : static constexpr IndexType index_type = Index;
192 : };
193 : } // namespace Tensor_detail
194 :
195 : /// \ingroup TensorGroup
196 : /// A SpatialIndex holds information about the number of spatial
197 : /// dimensions, whether the index is covariant or contravariant (::UpLo), and
198 : /// the ::Frame the index is in.
199 : /// \tparam SpatialDim the spatial dimensionality of the \ref
200 : /// SpatialIndex "TensorIndexType"
201 : /// \tparam Ul either UpLo::Up or UpLo::Lo for contra or covariant
202 : /// \tparam Fr the ::Frame the \ref SpatialIndex "TensorIndexType"
203 : /// is in
204 : template <size_t SpatialDim, UpLo Ul, typename Fr>
205 1 : using SpatialIndex =
206 : Tensor_detail::TensorIndexType<SpatialDim, Ul, Fr, IndexType::Spatial>;
207 :
208 : /// \ingroup TensorGroup
209 : /// A SpacetimeIndex holds information about the number of spatial
210 : /// dimensions, whether the index is covariant or contravariant (::UpLo), and
211 : /// the ::Frame the index is in.
212 : ///
213 : /// \tparam SpatialDim the spatial dimensionality of the \ref
214 : /// SpacetimeIndex "TensorIndexType"
215 : /// \tparam Ul either UpLo::Up or UpLo::Lo for contra or covariant
216 : /// \tparam Fr the ::Frame the \ref SpacetimeIndex "TensorIndexType"
217 : /// is in
218 : template <size_t SpatialDim, UpLo Ul, typename Fr>
219 1 : using SpacetimeIndex =
220 : Tensor_detail::TensorIndexType<SpatialDim, Ul, Fr, IndexType::Spacetime>;
221 :
222 : namespace tt {
223 : /// @{
224 : /// \ingroup TensorGroup TypeTraitsGroup
225 : /// Inherits from std::true_type if T is a \ref SpacetimeIndex
226 : /// "TensorIndexType"
227 : /// \tparam T the type to check
228 : template <typename T>
229 1 : struct is_tensor_index_type : std::false_type {};
230 : /// \cond HIDDEN_SYMBOLS
231 : template <size_t SpatialDim, UpLo Ul, typename Fr, IndexType Index>
232 : struct is_tensor_index_type<
233 : Tensor_detail::TensorIndexType<SpatialDim, Ul, Fr, Index>>
234 : : std::true_type {};
235 : /// \endcond
236 : /// \see is_tensor_index_type
237 : template <typename T>
238 1 : using is_tensor_index_type_t = typename is_tensor_index_type<T>::type;
239 : /// @}
240 : } // namespace tt
241 :
242 : /// \ingroup TensorGroup
243 : /// Change the \ref SpacetimeIndex "TensorIndexType" to be covariant
244 : /// if it's contravariant and vice-versa
245 : ///
246 : /// Here is an example of how to use ::change_index_up_lo
247 : /// \snippet Test_Tensor.cpp change_up_lo
248 : ///
249 : /// \tparam Index the \ref SpacetimeIndex "TensorIndexType" to change
250 : template <typename Index>
251 1 : using change_index_up_lo = Tensor_detail::TensorIndexType<
252 : Index::index_type == IndexType::Spatial ? Index::value : Index::value - 1,
253 : Index::ul == UpLo::Up ? UpLo::Lo : UpLo::Up, typename Index::Frame,
254 : Index::index_type>;
255 :
256 : template <typename... Ts>
257 0 : using index_list = tmpl::list<Ts...>;
258 :
259 : /// \ingroup TensorGroup
260 : /// Change the \ref SpacetimeIndex "TensorIndexType" to be spacetime
261 : /// if it's spatial and vice versa
262 : ///
263 : /// \tparam Index the \ref SpacetimeIndex "TensorIndexType" to change
264 : template <typename Index>
265 1 : using change_index_type = Tensor_detail::TensorIndexType<
266 : Index::index_type == IndexType::Spatial ? Index::dim : Index::dim - 1,
267 : Index::ul, typename Index::Frame,
268 : Index::index_type == IndexType::Spatial ? IndexType::Spacetime
269 : : IndexType::Spatial>;
|