EvaluateRank3TestHelpers.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <cstddef>
7 #include <cstdint>
8 #include <iterator>
9 #include <numeric>
10 #include <type_traits>
11 
12 #include "DataStructures/Tags/TempTensor.hpp"
17 #include "Utilities/GenerateInstantiations.hpp"
18 #include "Utilities/Gsl.hpp"
19 #include "Utilities/TMPL.hpp"
20 
21 namespace TestHelpers::TensorExpressions {
22 
23 /// \ingroup TestingFrameworkGroup
24 /// \brief Test that evaluating a right hand side tensor expression containing a
25 /// single rank 3 tensor correctly assigns the data to the evaluated left hand
26 /// side tensor
27 ///
28 /// \details `TensorIndexA`, `TensorIndexB`, and `TensorIndexC` can be any type
29 /// of TensorIndex and are not necessarily `ti_a`, `ti_b`, and `ti_c`. The
30 /// "A", "B", and "C" suffixes just denote the ordering of the generic indices
31 /// of the RHS tensor expression. In the RHS tensor expression, it means
32 /// `TensorIndexA` is the first index used, `TensorIndexB` is the second index
33 /// used, and `TensorIndexC` is the third index used.
34 ///
35 /// If we consider the RHS tensor's generic indices to be (a, b, c), then this
36 /// test checks that the data in the evaluated LHS tensor is correct according
37 /// to the index orders of the LHS and RHS. The possible cases that are checked
38 /// are when the LHS tensor is evaluated with index orders: (a, b, c),
39 /// (a, c, b), (b, a, c), (b, c, a), (c, a, b), and (c, b, a).
40 ///
41 /// \tparam DataType the type of data being stored in the Tensors
42 /// \tparam RhsSymmetry the ::Symmetry of the RHS Tensor
43 /// \tparam RhsTensorIndexTypeList the RHS Tensor's typelist of
44 /// \ref SpacetimeIndex "TensorIndexType"s
45 /// \tparam TensorIndexA the first TensorIndex used on the RHS of the
46 /// TensorExpression, e.g. `ti_a`
47 /// \tparam TensorIndexB the second TensorIndex used on the RHS of the
48 /// TensorExpression, e.g. `ti_B`
49 /// \tparam TensorIndexC the third TensorIndex used on the RHS of the
50 /// TensorExpression, e.g. `ti_c`
51 template <typename DataType, typename RhsSymmetry,
52  typename RhsTensorIndexTypeList, auto& TensorIndexA,
53  auto& TensorIndexB, auto& TensorIndexC>
54 void test_evaluate_rank_3_impl() noexcept {
55  const size_t used_for_size = 5;
56  Tensor<DataType, RhsSymmetry, RhsTensorIndexTypeList> R_abc(used_for_size);
57  std::iota(R_abc.begin(), R_abc.end(), 0.0);
58 
59  // Used for enforcing the ordering of the symmetry and TensorIndexTypes of the
60  // LHS Tensor returned by `evaluate`
61  const std::int32_t rhs_symmetry_element_a = tmpl::at_c<RhsSymmetry, 0>::value;
62  const std::int32_t rhs_symmetry_element_b = tmpl::at_c<RhsSymmetry, 1>::value;
63  const std::int32_t rhs_symmetry_element_c = tmpl::at_c<RhsSymmetry, 2>::value;
64  using rhs_tensorindextype_a = tmpl::at_c<RhsTensorIndexTypeList, 0>;
65  using rhs_tensorindextype_b = tmpl::at_c<RhsTensorIndexTypeList, 1>;
66  using rhs_tensorindextype_c = tmpl::at_c<RhsTensorIndexTypeList, 2>;
67 
68  // L_{abc} = R_{abc}
69  // Use explicit type (vs auto) so the compiler checks the return type of
70  // `evaluate`
71  using L_abc_type = Tensor<DataType, RhsSymmetry, RhsTensorIndexTypeList>;
72  const L_abc_type L_abc_returned =
73  ::TensorExpressions::evaluate<TensorIndexA, TensorIndexB, TensorIndexC>(
74  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
75  L_abc_type L_abc_filled{};
76  ::TensorExpressions::evaluate<TensorIndexA, TensorIndexB, TensorIndexC>(
77  make_not_null(&L_abc_filled),
78  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
79 
80  // L_{acb} = R_{abc}
81  using L_acb_symmetry =
82  Symmetry<rhs_symmetry_element_a, rhs_symmetry_element_c,
83  rhs_symmetry_element_b>;
84  using L_acb_tensorindextype_list =
85  tmpl::list<rhs_tensorindextype_a, rhs_tensorindextype_c,
86  rhs_tensorindextype_b>;
87  using L_acb_type =
88  Tensor<DataType, L_acb_symmetry, L_acb_tensorindextype_list>;
89  const L_acb_type L_acb_returned =
90  ::TensorExpressions::evaluate<TensorIndexA, TensorIndexC, TensorIndexB>(
91  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
92  L_acb_type L_acb_filled{};
93  ::TensorExpressions::evaluate<TensorIndexA, TensorIndexC, TensorIndexB>(
94  make_not_null(&L_acb_filled),
95  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
96 
97  // L_{bac} = R_{abc}
98  using L_bac_symmetry =
99  Symmetry<rhs_symmetry_element_b, rhs_symmetry_element_a,
100  rhs_symmetry_element_c>;
101  using L_bac_tensorindextype_list =
102  tmpl::list<rhs_tensorindextype_b, rhs_tensorindextype_a,
103  rhs_tensorindextype_c>;
104  using L_bac_type =
105  Tensor<DataType, L_bac_symmetry, L_bac_tensorindextype_list>;
106  const L_bac_type L_bac_returned =
107  ::TensorExpressions::evaluate<TensorIndexB, TensorIndexA, TensorIndexC>(
108  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
109  L_bac_type L_bac_filled{};
110  ::TensorExpressions::evaluate<TensorIndexB, TensorIndexA, TensorIndexC>(
111  make_not_null(&L_bac_filled),
112  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
113 
114  // L_{bca} = R_{abc}
115  using L_bca_symmetry =
116  Symmetry<rhs_symmetry_element_b, rhs_symmetry_element_c,
117  rhs_symmetry_element_a>;
118  using L_bca_tensorindextype_list =
119  tmpl::list<rhs_tensorindextype_b, rhs_tensorindextype_c,
120  rhs_tensorindextype_a>;
121  using L_bca_type =
122  Tensor<DataType, L_bca_symmetry, L_bca_tensorindextype_list>;
123  const L_bca_type L_bca_returned =
124  ::TensorExpressions::evaluate<TensorIndexB, TensorIndexC, TensorIndexA>(
125  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
126  L_bca_type L_bca_filled{};
127  ::TensorExpressions::evaluate<TensorIndexB, TensorIndexC, TensorIndexA>(
128  make_not_null(&L_bca_filled),
129  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
130 
131  // L_{cab} = R_{abc}
132  using L_cab_symmetry =
133  Symmetry<rhs_symmetry_element_c, rhs_symmetry_element_a,
134  rhs_symmetry_element_b>;
135  using L_cab_tensorindextype_list =
136  tmpl::list<rhs_tensorindextype_c, rhs_tensorindextype_a,
137  rhs_tensorindextype_b>;
138  using L_cab_type =
139  Tensor<DataType, L_cab_symmetry, L_cab_tensorindextype_list>;
140  const L_cab_type L_cab_returned =
141  ::TensorExpressions::evaluate<TensorIndexC, TensorIndexA, TensorIndexB>(
142  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
143  L_cab_type L_cab_filled{};
144  ::TensorExpressions::evaluate<TensorIndexC, TensorIndexA, TensorIndexB>(
145  make_not_null(&L_cab_filled),
146  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
147 
148  // L_{cba} = R_{abc}
149  using L_cba_symmetry =
150  Symmetry<rhs_symmetry_element_c, rhs_symmetry_element_b,
151  rhs_symmetry_element_a>;
152  using L_cba_tensorindextype_list =
153  tmpl::list<rhs_tensorindextype_c, rhs_tensorindextype_b,
154  rhs_tensorindextype_a>;
155  using L_cba_type =
156  Tensor<DataType, L_cba_symmetry, L_cba_tensorindextype_list>;
157  const L_cba_type L_cba_returned =
158  ::TensorExpressions::evaluate<TensorIndexC, TensorIndexB, TensorIndexA>(
159  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
160  L_cba_type L_cba_filled{};
161  ::TensorExpressions::evaluate<TensorIndexC, TensorIndexB, TensorIndexA>(
162  make_not_null(&L_cba_filled),
163  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
164 
165  const size_t dim_a = tmpl::at_c<RhsTensorIndexTypeList, 0>::dim;
166  const size_t dim_b = tmpl::at_c<RhsTensorIndexTypeList, 1>::dim;
167  const size_t dim_c = tmpl::at_c<RhsTensorIndexTypeList, 2>::dim;
168 
169  for (size_t i = 0; i < dim_a; ++i) {
170  for (size_t j = 0; j < dim_b; ++j) {
171  for (size_t k = 0; k < dim_c; ++k) {
172  // For L_{abc} = R_{abc}, check that L_{ijk} == R_{ijk}
173  CHECK(L_abc_returned.get(i, j, k) == R_abc.get(i, j, k));
174  CHECK(L_abc_filled.get(i, j, k) == R_abc.get(i, j, k));
175  // For L_{acb} = R_{abc}, check that L_{ikj} == R_{ijk}
176  CHECK(L_acb_returned.get(i, k, j) == R_abc.get(i, j, k));
177  CHECK(L_acb_filled.get(i, k, j) == R_abc.get(i, j, k));
178  // For L_{bac} = R_{abc}, check that L_{jik} == R_{ijk}
179  CHECK(L_bac_returned.get(j, i, k) == R_abc.get(i, j, k));
180  CHECK(L_bac_filled.get(j, i, k) == R_abc.get(i, j, k));
181  // For L_{bca} = R_{abc}, check that L_{jki} == R_{ijk}
182  CHECK(L_bca_returned.get(j, k, i) == R_abc.get(i, j, k));
183  CHECK(L_bca_filled.get(j, k, i) == R_abc.get(i, j, k));
184  // For L_{cab} = R_{abc}, check that L_{kij} == R_{ijk}
185  CHECK(L_cab_returned.get(k, i, j) == R_abc.get(i, j, k));
186  CHECK(L_cab_filled.get(k, i, j) == R_abc.get(i, j, k));
187  // For L_{cba} = R_{abc}, check that L_{kji} == R_{ijk}
188  CHECK(L_cba_returned.get(k, j, i) == R_abc.get(i, j, k));
189  CHECK(L_cba_filled.get(k, j, i) == R_abc.get(i, j, k));
190  }
191  }
192  }
193 
194  // Test with TempTensor for LHS tensor
195  if constexpr (not std::is_same_v<DataType, double>) {
196  // L_{abc} = R_{abc}
197  Variables<tmpl::list<::Tags::TempTensor<1, L_abc_type>>> L_abc_var{
198  used_for_size};
199  L_abc_type& L_abc_temp = get<::Tags::TempTensor<1, L_abc_type>>(L_abc_var);
200  ::TensorExpressions::evaluate<TensorIndexA, TensorIndexB, TensorIndexC>(
201  make_not_null(&L_abc_temp),
202  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
203 
204  // L_{acb} = R_{abc}
205  Variables<tmpl::list<::Tags::TempTensor<1, L_acb_type>>> L_acb_var{
206  used_for_size};
207  L_acb_type& L_acb_temp = get<::Tags::TempTensor<1, L_acb_type>>(L_acb_var);
208  ::TensorExpressions::evaluate<TensorIndexA, TensorIndexC, TensorIndexB>(
209  make_not_null(&L_acb_temp),
210  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
211 
212  // L_{bac} = R_{abc}
213  Variables<tmpl::list<::Tags::TempTensor<1, L_bac_type>>> L_bac_var{
214  used_for_size};
215  L_bac_type& L_bac_temp = get<::Tags::TempTensor<1, L_bac_type>>(L_bac_var);
216  ::TensorExpressions::evaluate<TensorIndexB, TensorIndexA, TensorIndexC>(
217  make_not_null(&L_bac_temp),
218  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
219 
220  // L_{bca} = R_{abc}
221  Variables<tmpl::list<::Tags::TempTensor<1, L_bca_type>>> L_bca_var{
222  used_for_size};
223  L_bca_type& L_bca_temp = get<::Tags::TempTensor<1, L_bca_type>>(L_bca_var);
224  ::TensorExpressions::evaluate<TensorIndexB, TensorIndexC, TensorIndexA>(
225  make_not_null(&L_bca_temp),
226  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
227 
228  // L_{cab} = R_{abc}
229  Variables<tmpl::list<::Tags::TempTensor<1, L_cab_type>>> L_cab_var{
230  used_for_size};
231  L_cab_type& L_cab_temp = get<::Tags::TempTensor<1, L_cab_type>>(L_cab_var);
232  ::TensorExpressions::evaluate<TensorIndexC, TensorIndexA, TensorIndexB>(
233  make_not_null(&L_cab_temp),
234  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
235 
236  // L_{cba} = R_{abc}
237  Variables<tmpl::list<::Tags::TempTensor<1, L_cba_type>>> L_cba_var{
238  used_for_size};
239  L_cba_type& L_cba_temp = get<::Tags::TempTensor<1, L_cba_type>>(L_cba_var);
240  ::TensorExpressions::evaluate<TensorIndexC, TensorIndexB, TensorIndexA>(
241  make_not_null(&L_cba_temp),
242  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
243 
244  for (size_t i = 0; i < dim_a; ++i) {
245  for (size_t j = 0; j < dim_b; ++j) {
246  for (size_t k = 0; k < dim_c; ++k) {
247  // For L_{abc} = R_{abc}, check that L_{ijk} == R_{ijk}
248  CHECK(L_abc_temp.get(i, j, k) == R_abc.get(i, j, k));
249  // For L_{acb} = R_{abc}, check that L_{ikj} == R_{ijk}
250  CHECK(L_acb_temp.get(i, k, j) == R_abc.get(i, j, k));
251  // For L_{bac} = R_{abc}, check that L_{jik} == R_{ijk}
252  CHECK(L_bac_temp.get(j, i, k) == R_abc.get(i, j, k));
253  // For L_{bca} = R_{abc}, check that L_{jki} == R_{ijk}
254  CHECK(L_bca_temp.get(j, k, i) == R_abc.get(i, j, k));
255  // For L_{cab} = R_{abc}, check that L_{kij} == R_{ijk}
256  CHECK(L_cab_temp.get(k, i, j) == R_abc.get(i, j, k));
257  // For L_{cba} = R_{abc}, check that L_{kji} == R_{ijk}
258  CHECK(L_cba_temp.get(k, j, i) == R_abc.get(i, j, k));
259  }
260  }
261  }
262  }
263 }
264 
265 /// \ingroup TestingFrameworkGroup
266 /// \brief Iterate testing of evaluating single rank 3 Tensors on multiple Frame
267 /// types and dimension combinations
268 ///
269 /// We test various different symmetries across several functions to ensure that
270 /// the code works correctly with symmetries. This function tests one of the
271 /// following symmetries:
272 /// - <3, 2, 1> (`test_evaluate_rank_3_no_symmetry`)
273 /// - <2, 2, 1> (`test_evaluate_rank_3_ab_symmetry`)
274 /// - <2, 1, 2> (`test_evaluate_rank_3_ac_symmetry`)
275 /// - <2, 1, 1> (`test_evaluate_rank_3_bc_symmetry`)
276 /// - <1, 1, 1> (`test_evaluate_rank_3_abc_symmetry`)
277 ///
278 /// \details `TensorIndexA`, `TensorIndexB`, and `TensorIndexC` can be any type
279 /// of TensorIndex and are not necessarily `ti_a`, `ti_b`, and `ti_c`. The
280 /// "A", "B", and "C" suffixes just denote the ordering of the generic indices
281 /// of the RHS tensor expression. In the RHS tensor expression, it means
282 /// `TensorIndexA` is the first index used, `TensorIndexB` is the second index
283 /// used, and `TensorIndexC` is the third index used.
284 ///
285 /// Note: the functions dealing with symmetric indices have fewer template
286 /// parameters due to the indices having a shared \ref SpacetimeIndex
287 /// "TensorIndexType" and valence
288 ///
289 /// \tparam DataType the type of data being stored in the Tensors
290 /// \tparam TensorIndexTypeA the \ref SpacetimeIndex "TensorIndexType" of the
291 /// first index of the RHS Tensor
292 /// \tparam TensorIndexTypeB the \ref SpacetimeIndex "TensorIndexType" of the
293 /// second index of the RHS Tensor
294 /// \tparam TensorIndexTypeC the \ref SpacetimeIndex "TensorIndexType" of the
295 /// third index of the RHS Tensor
296 /// \tparam ValenceA the valence of the first index used on the RHS of the
297 /// TensorExpression
298 /// \tparam ValenceB the valence of the second index used on the RHS of the
299 /// TensorExpression
300 /// \tparam ValenceC the valence of the third index used on the RHS of the
301 /// TensorExpression
302 /// \tparam TensorIndexA the first TensorIndex used on the RHS of the
303 /// TensorExpression, e.g. `ti_a`
304 /// \tparam TensorIndexB the second TensorIndex used on the RHS of the
305 /// TensorExpression, e.g. `ti_B`
306 /// \tparam TensorIndexC the third TensorIndex used on the RHS of the
307 /// TensorExpression, e.g. `ti_c`
308 template <typename DataType,
309  template <size_t, UpLo, typename> class TensorIndexTypeA,
310  template <size_t, UpLo, typename> class TensorIndexTypeB,
311  template <size_t, UpLo, typename> class TensorIndexTypeC,
312  UpLo ValenceA, UpLo ValenceB, UpLo ValenceC, auto& TensorIndexA,
313  auto& TensorIndexB, auto& TensorIndexC>
315 #define DIM_A(data) BOOST_PP_TUPLE_ELEM(0, data)
316 #define DIM_B(data) BOOST_PP_TUPLE_ELEM(1, data)
317 #define DIM_C(data) BOOST_PP_TUPLE_ELEM(2, data)
318 #define FRAME(data) BOOST_PP_TUPLE_ELEM(3, data)
319 
320 #define CALL_TEST_EVALUATE_RANK_3_IMPL(_, data) \
321  test_evaluate_rank_3_impl< \
322  DataType, Symmetry<3, 2, 1>, \
323  index_list<TensorIndexTypeA<DIM_A(data), ValenceA, FRAME(data)>, \
324  TensorIndexTypeB<DIM_B(data), ValenceB, FRAME(data)>, \
325  TensorIndexTypeC<DIM_C(data), ValenceC, FRAME(data)>>, \
326  TensorIndexA, TensorIndexB, TensorIndexC>();
327 
328  GENERATE_INSTANTIATIONS(CALL_TEST_EVALUATE_RANK_3_IMPL, (1, 2, 3), (1, 2, 3),
329  (1, 2, 3), (Frame::Grid, Frame::Inertial))
330 
331 #undef CALL_TEST_EVALUATE_RANK_3_IMPL
332 #undef FRAME
333 #undef DIM_C
334 #undef DIM_B
335 #undef DIM_A
336 }
337 
338 /// \ingroup TestingFrameworkGroup
339 /// \copydoc test_evaluate_rank_3_no_symmetry()
340 template <typename DataType,
341  template <size_t, UpLo, typename> class TensorIndexTypeAB,
342  template <size_t, UpLo, typename> class TensorIndexTypeC,
343  UpLo ValenceAB, UpLo ValenceC, auto& TensorIndexA, auto& TensorIndexB,
344  auto& TensorIndexC>
346 #define DIM_AB(data) BOOST_PP_TUPLE_ELEM(0, data)
347 #define DIM_C(data) BOOST_PP_TUPLE_ELEM(1, data)
348 #define FRAME(data) BOOST_PP_TUPLE_ELEM(2, data)
349 
350 #define CALL_TEST_EVALUATE_RANK_3_IMPL(_, data) \
351  test_evaluate_rank_3_impl< \
352  DataType, Symmetry<2, 2, 1>, \
353  index_list<TensorIndexTypeAB<DIM_AB(data), ValenceAB, FRAME(data)>, \
354  TensorIndexTypeAB<DIM_AB(data), ValenceAB, FRAME(data)>, \
355  TensorIndexTypeC<DIM_C(data), ValenceC, FRAME(data)>>, \
356  TensorIndexA, TensorIndexB, TensorIndexC>();
357 
358  GENERATE_INSTANTIATIONS(CALL_TEST_EVALUATE_RANK_3_IMPL, (1, 2, 3), (1, 2, 3),
360 
361 #undef CALL_TEST_EVALUATE_RANK_3_IMPL
362 #undef FRAME
363 #undef DIM_C
364 #undef DIM_AB
365 }
366 
367 /// \ingroup TestingFrameworkGroup
368 /// \copydoc test_evaluate_rank_3_no_symmetry()
369 template <typename DataType,
370  template <size_t, UpLo, typename> class TensorIndexTypeAC,
371  template <size_t, UpLo, typename> class TensorIndexTypeB,
372  UpLo ValenceAC, UpLo ValenceB, auto& TensorIndexA, auto& TensorIndexB,
373  auto& TensorIndexC>
375 #define DIM_AC(data) BOOST_PP_TUPLE_ELEM(0, data)
376 #define DIM_B(data) BOOST_PP_TUPLE_ELEM(1, data)
377 #define FRAME(data) BOOST_PP_TUPLE_ELEM(2, data)
378 
379 #define CALL_TEST_EVALUATE_RANK_3_IMPL(_, data) \
380  test_evaluate_rank_3_impl< \
381  DataType, Symmetry<2, 1, 2>, \
382  index_list<TensorIndexTypeAC<DIM_AC(data), ValenceAC, FRAME(data)>, \
383  TensorIndexTypeB<DIM_B(data), ValenceB, FRAME(data)>, \
384  TensorIndexTypeAC<DIM_AC(data), ValenceAC, FRAME(data)>>, \
385  TensorIndexA, TensorIndexB, TensorIndexC>();
386 
387  GENERATE_INSTANTIATIONS(CALL_TEST_EVALUATE_RANK_3_IMPL, (1, 2, 3), (1, 2, 3),
389 
390 #undef CALL_TEST_EVALUATE_RANK_3_IMPL
391 #undef FRAME
392 #undef DIM_B
393 #undef DIM_AC
394 }
395 
396 /// \ingroup TestingFrameworkGroup
397 /// \copydoc test_evaluate_rank_3_no_symmetry()
398 template <
399  typename DataType, template <size_t, UpLo, typename> class TensorIndexTypeA,
400  template <size_t, UpLo, typename> class TensorIndexTypeBC, UpLo ValenceA,
401  UpLo ValenceBC, auto& TensorIndexA, auto& TensorIndexB, auto& TensorIndexC>
403 #define DIM_A(data) BOOST_PP_TUPLE_ELEM(0, data)
404 #define DIM_BC(data) BOOST_PP_TUPLE_ELEM(1, data)
405 #define FRAME(data) BOOST_PP_TUPLE_ELEM(2, data)
406 
407 #define CALL_TEST_EVALUATE_RANK_3_IMPL(_, data) \
408  test_evaluate_rank_3_impl< \
409  DataType, Symmetry<2, 1, 1>, \
410  index_list<TensorIndexTypeA<DIM_A(data), ValenceA, FRAME(data)>, \
411  TensorIndexTypeBC<DIM_BC(data), ValenceBC, FRAME(data)>, \
412  TensorIndexTypeBC<DIM_BC(data), ValenceBC, FRAME(data)>>, \
413  TensorIndexA, TensorIndexB, TensorIndexC>();
414 
415  GENERATE_INSTANTIATIONS(CALL_TEST_EVALUATE_RANK_3_IMPL, (1, 2, 3), (1, 2, 3),
417 
418 #undef CALL_TEST_EVALUATE_RANK_3_IMPL
419 #undef FRAME
420 #undef DIM_BC
421 #undef DIM_A
422 }
423 
424 /// \ingroup TestingFrameworkGroup
425 /// \copydoc test_evaluate_rank_3_no_symmetry()
426 template <typename DataType,
427  template <size_t, UpLo, typename> class TensorIndexType, UpLo Valence,
428  auto& TensorIndexA, auto& TensorIndexB, auto& TensorIndexC>
430 #define DIM(data) BOOST_PP_TUPLE_ELEM(0, data)
431 #define FRAME(data) BOOST_PP_TUPLE_ELEM(1, data)
432 
433 #define CALL_TEST_EVALUATE_RANK_3_IMPL(_, data) \
434  test_evaluate_rank_3_impl< \
435  DataType, Symmetry<1, 1, 1>, \
436  index_list<TensorIndexType<DIM(data), Valence, FRAME(data)>, \
437  TensorIndexType<DIM(data), Valence, FRAME(data)>, \
438  TensorIndexType<DIM(data), Valence, FRAME(data)>>, \
439  TensorIndexA, TensorIndexB, TensorIndexC>();
440 
441  GENERATE_INSTANTIATIONS(CALL_TEST_EVALUATE_RANK_3_IMPL, (1, 2, 3),
443 
444 #undef CALL_TEST_EVALUATE_RANK_3_IMPL
445 #undef FRAME
446 #undef DIM
447 }
448 
449 } // namespace TestHelpers::TensorExpressions
TestHelpers::TensorExpressions::test_evaluate_rank_3_impl
void test_evaluate_rank_3_impl() noexcept
Test that evaluating a right hand side tensor expression containing a single rank 3 tensor correctly ...
Definition: EvaluateRank3TestHelpers.hpp:54
Frame::Inertial
Definition: IndexType.hpp:44
TestHelpers::TensorExpressions::test_evaluate_rank_3_ac_symmetry
void test_evaluate_rank_3_ac_symmetry() noexcept
Iterate testing of evaluating single rank 3 Tensors on multiple Frame types and dimension combination...
Definition: EvaluateRank3TestHelpers.hpp:374
UpLo
UpLo
Definition: IndexType.hpp:20
IndexType.hpp
Frame::Grid
Definition: IndexType.hpp:43
Symmetry.hpp
TestHelpers::TensorExpressions::test_evaluate_rank_3_bc_symmetry
void test_evaluate_rank_3_bc_symmetry() noexcept
Iterate testing of evaluating single rank 3 Tensors on multiple Frame types and dimension combination...
Definition: EvaluateRank3TestHelpers.hpp:402
iterator
TestHelpers::TensorExpressions::test_evaluate_rank_3_ab_symmetry
void test_evaluate_rank_3_ab_symmetry() noexcept
Iterate testing of evaluating single rank 3 Tensors on multiple Frame types and dimension combination...
Definition: EvaluateRank3TestHelpers.hpp:345
cstddef
cstdint
std::int32_t
Symmetry
typename detail::SymmetryImpl< std::make_index_sequence< sizeof...(T)>, tmpl::integral_list< std::int32_t, T... > >::type Symmetry
Computes the canonical symmetry from the integers T
Definition: Symmetry.hpp:80
Variables.hpp
Gsl.hpp
Tensor.hpp
make_not_null
gsl::not_null< T * > make_not_null(T *ptr) noexcept
Construct a not_null from a pointer. Often this will be done as an implicit conversion,...
Definition: Gsl.hpp:880
numeric
TestHelpers::TensorExpressions::test_evaluate_rank_3_no_symmetry
void test_evaluate_rank_3_no_symmetry() noexcept
Iterate testing of evaluating single rank 3 Tensors on multiple Frame types and dimension combination...
Definition: EvaluateRank3TestHelpers.hpp:314
type_traits
TestHelpers::TensorExpressions::test_evaluate_rank_3_abc_symmetry
void test_evaluate_rank_3_abc_symmetry() noexcept
Iterate testing of evaluating single rank 3 Tensors on multiple Frame types and dimension combination...
Definition: EvaluateRank3TestHelpers.hpp:429
GENERATE_INSTANTIATIONS
#define GENERATE_INSTANTIATIONS(INSTANTIATION_MACRO,...)
Macro useful for generating many explicit instantiations of function or class templates.
Definition: GenerateInstantiations.hpp:160
TMPL.hpp
cpp2b::iota
constexpr void iota(ForwardIterator first, ForwardIterator last, T value)
Definition: Numeric.hpp:20