TestMapHelpers.hpp
Go to the documentation of this file.
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 ///\file
5 /// Helper functions for testing coordinate maps
6 
7 #pragma once
8 
10 
11 #include <algorithm>
12 #include <array>
13 #include <functional>
14 #include <numeric>
15 #include <random>
16 
17 #include "DataStructures/DataVector.hpp"
21 #include "Domain/Direction.hpp"
22 #include "Domain/DomainHelpers.hpp"
23 #include "Domain/OrientationMap.hpp"
24 #include "Utilities/TypeTraits.hpp"
25 #include "tests/Unit/Domain/DomainTestHelpers.hpp"
27 
28 /*!
29  * \ingroup TestingFrameworkGroup
30  * \brief Given a Map and a CoordinateMapBase, checks that the maps are equal by
31  * downcasting `map_base` and then comparing to `map`. Returns false if the
32  * downcast fails.
33  */
34 template <typename Map>
35 bool are_maps_equal(const Map& map,
37  Map::dim>& map_base) {
38  const auto* map_derived = dynamic_cast<const Map*>(&map_base);
39  return map_derived == nullptr ? false : (*map_derived == map);
40 }
41 
42 /// \ingroup TestingFrameworkGroup
43 /// \brief Given two coordinate maps (but not their types), check that the maps
44 /// are equal by evaluating them at a random set of points.
45 template <typename SourceFrame, typename TargetFrame, size_t VolumeDim>
49  MAKE_GENERATOR(gen);
50  std::uniform_real_distribution<> real_dis(-1, 1);
51 
52  for (size_t n = 0; n < 10; ++n) {
53  tnsr::I<double, VolumeDim, SourceFrame> source_point{};
54  for (size_t d = 0; d < VolumeDim; ++d) {
55  source_point.get(d) = real_dis(gen);
56  }
57  CAPTURE_PRECISE(source_point);
58  CHECK_ITERABLE_APPROX(map_one(source_point), map_two(source_point));
59  CHECK_ITERABLE_APPROX(map_one.jacobian(source_point),
60  map_two.jacobian(source_point));
61  CHECK_ITERABLE_APPROX(map_one.inv_jacobian(source_point),
62  map_two.inv_jacobian(source_point));
63  }
64 }
65 
66 /// \ingroup TestingFrameworkGroup
67 /// \brief Given a coordinate map, check that this map is equal to the identity
68 /// by evaluating the map at a random set of points.
69 template <typename Map>
70 void check_if_map_is_identity(const Map& map) {
71  using IdentityMap = CoordinateMaps::Identity<Map::dim>;
73  make_coordinate_map<Frame::Inertial, Frame::Grid>(IdentityMap{}),
74  make_coordinate_map<Frame::Inertial, Frame::Grid>(map));
75  CHECK(map.is_identity());
76 }
77 
78 /*!
79  * \ingroup TestingFrameworkGroup
80  * \brief Given a Map `map`, checks that the jacobian gives expected results
81  * when compared to the numerical derivative in each direction.
82  */
83 template <typename Map>
84 void test_jacobian(const Map& map,
85  const std::array<double, Map::dim>& test_point) {
86  // Our default approx value is too stringent for this test
87  Approx local_approx = Approx::custom().epsilon(1e-10).scale(1.0);
88  const double dx = 1e-4;
89  const auto jacobian = map.jacobian(test_point);
90  for (size_t i = 0; i < Map::dim; ++i) {
91  const auto numerical_deriv_i = numerical_derivative(map, test_point, i, dx);
92  for (size_t j = 0; j < Map::dim; ++j) {
93  INFO("i: " << i << " j: " << j);
94  CHECK(jacobian.get(j, i) == local_approx(gsl::at(numerical_deriv_i, j)));
95  }
96  }
97 }
98 
99 /*!
100  * \ingroup TestingFrameworkGroup
101  * \brief Given a Map `map`, checks that the inverse jacobian and jacobian
102  * multiply together to produce the identity matrix
103  */
104 template <typename Map>
105 void test_inv_jacobian(const Map& map,
106  const std::array<double, Map::dim>& test_point) {
107  const auto jacobian = map.jacobian(test_point);
108  const auto inv_jacobian = map.inv_jacobian(test_point);
109 
110  const auto expected_identity = [&jacobian, &inv_jacobian]() {
112  for (size_t i = 0; i < Map::dim; ++i) {
113  for (size_t j = 0; j < Map::dim; ++j) {
114  gsl::at(gsl::at(identity, i), j) = 0.;
115  for (size_t k = 0; k < Map::dim; ++k) {
116  gsl::at(gsl::at(identity, i), j) +=
117  jacobian.get(i, k) * inv_jacobian.get(k, j);
118  }
119  }
120  }
121  return identity;
122  }();
123 
124  for (size_t i = 0; i < Map::dim; ++i) {
125  for (size_t j = 0; j < Map::dim; ++j) {
126  CHECK(gsl::at(gsl::at(expected_identity, i), j) ==
127  approx(i == j ? 1. : 0.));
128  }
129  }
130 }
131 
132 /*!
133  * \ingroup TestingFrameworkGroup
134  * \brief Checks that the CoordinateMap `map` functions as expected when used as
135  * the template parameter to the `CoordinateMap` type.
136  */
137 template <typename Map, typename... Args>
139  const auto coord_map = make_coordinate_map<Frame::Logical, Frame::Grid>(map);
140  MAKE_GENERATOR(gen);
141  std::uniform_real_distribution<> real_dis(-1, 1);
142 
143  const auto test_point = [&gen, &real_dis] {
145  for (size_t i = 0; i < Map::dim; ++i) {
146  gsl::at(p, i) = real_dis(gen);
147  }
148  return p;
149  }();
150 
151  for (size_t i = 0; i < Map::dim; ++i) {
152  CAPTURE_PRECISE(gsl::at(test_point, i));
153  }
154 
155  const auto test_point_tensor = [&test_point]() {
156  tnsr::I<double, Map::dim, Frame::Logical> point_as_tensor{};
157  for (size_t i = 0; i < Map::dim; ++i) {
158  point_as_tensor.get(i) = gsl::at(test_point, i);
159  }
160  return point_as_tensor;
161  }();
162 
163  for (size_t i = 0; i < Map::dim; ++i) {
164  CHECK(coord_map(test_point_tensor).get(i) ==
165  approx(gsl::at(map(test_point), i)));
166  for (size_t j = 0; j < Map::dim; ++j) {
167  CHECK(coord_map.jacobian(test_point_tensor).get(i, j) ==
168  map.jacobian(test_point).get(i, j));
169  CHECK(coord_map.inv_jacobian(test_point_tensor).get(i, j) ==
170  map.inv_jacobian(test_point).get(i, j));
171  }
172  }
173 }
174 
175 /*!
176  * \ingroup TestingFrameworkGroup
177  * \brief Checks that the CoordinateMap `map` functions as expected when used
178  * with different argument types.
179  */
180 template <typename Map, typename... Args>
182  const Map& map, const std::array<double, Map::dim>& test_point,
183  const Args&... args) {
184  const auto make_array_data_vector = [](const auto& double_array) noexcept {
186  std::transform(double_array.begin(), double_array.end(), result.begin(),
187  [](const double x) noexcept {
188  return DataVector{x, x};
189  });
190  return result;
191  };
192  const auto add_reference_wrapper = [](const auto& unwrapped_array) noexcept {
194  return make_array<std::reference_wrapper<const typename Arg::value_type>,
195  Map::dim>(unwrapped_array);
196  };
197 
198  {
199  const auto mapped_point = map(test_point, args...);
200  CHECK_ITERABLE_APPROX(map(add_reference_wrapper(test_point), args...),
201  mapped_point);
202  CHECK_ITERABLE_APPROX(map(make_array_data_vector(test_point), args...),
203  make_array_data_vector(mapped_point));
205  map(add_reference_wrapper(make_array_data_vector(test_point)), args...),
206  make_array_data_vector(mapped_point));
207  }
208 
209  // Here, time_args is a const auto& not const Args& because time_args
210  // is allowed to be different than Args (which was the reason for the
211  // overloader below that calls this function).
212  const auto check_jac =
213  [](const auto& make_arr_data_vec, const auto& add_ref_wrap,
214  const Map& the_map, const std::array<double, Map::dim>& point,
215  const auto&... time_args) noexcept {
216  const auto make_tensor_data_vector = [](const auto& double_tensor) {
218  Tensor<DataVector, typename Arg::symmetry, typename Arg::index_list>
219  result;
220  std::transform(double_tensor.begin(), double_tensor.end(), result.begin(),
221  [](const double x) {
222  return DataVector{x, x};
223  });
224  return result;
225  };
226 
227  {
228  const auto expected = the_map.jacobian(point, time_args...);
229  CHECK_ITERABLE_APPROX(the_map.jacobian(add_ref_wrap(point), time_args...),
230  expected);
232  the_map.jacobian(make_arr_data_vec(point), time_args...),
233  make_tensor_data_vector(expected));
235  the_map.jacobian(add_ref_wrap(make_arr_data_vec(point)),
236  time_args...),
237  make_tensor_data_vector(expected));
238  }
239  {
240  const auto expected = the_map.inv_jacobian(point, time_args...);
242  the_map.inv_jacobian(add_ref_wrap(point), time_args...), expected);
244  the_map.inv_jacobian(make_arr_data_vec(point), time_args...),
245  make_tensor_data_vector(expected));
247  the_map.inv_jacobian(add_ref_wrap(make_arr_data_vec(point)),
248  time_args...),
249  make_tensor_data_vector(expected));
250  }
251 
252  return nullptr;
253  };
254 
255  const auto jac_overloader = make_overloader(
256  // The first two functions are passed through the jacobian
257  // overloader and the check_jac function due to gcc failing to deduce auto
258  [&check_jac](const auto& make_array_data_vec, const auto& add_ref_wrapper,
259  const Map& this_map,
260  const std::array<double, Map::dim>& this_point,
261  const std::false_type /*is_time_independent*/,
262  const Args&... /*the_args*/) noexcept {
263  check_jac(make_array_data_vec, add_ref_wrapper, this_map, this_point);
264  return nullptr;
265  },
266  [&check_jac](const auto& make_array_data_vec, const auto& add_ref_wrapper,
267  const Map& this_map,
268  const std::array<double, Map::dim>& this_point,
269  const std::true_type /*is_time_dependent*/,
270  const Args&... the_args) noexcept {
271  check_jac(make_array_data_vec, add_ref_wrapper, this_map, this_point,
272  the_args...);
273  return nullptr;
274  });
275 
276  jac_overloader(
277  make_array_data_vector, add_reference_wrapper, map, test_point,
278  CoordinateMap_detail::is_jacobian_time_dependent_t<decltype(map),
279  double>{},
280  args...);
281 }
282 
283 /*!
284  * \ingroup TestingFrameworkGroup
285  * \brief Given a Map `map`, checks that the inverse map gives expected results
286  */
287 template <typename Map, typename T>
288 void test_inverse_map(const Map& map,
289  const std::array<T, Map::dim>& test_point) {
290  CHECK_ITERABLE_APPROX(test_point, map.inverse(map(test_point)).get());
291 }
292 
293 /*!
294  * \ingroup TestingFrameworkGroup
295  * \brief Given a Map `map`, tests the map functions, including map inverse,
296  * jacobian, and inverse jacobian, for a series of points.
297  * These points are chosen in a dim-dimensonal cube of side 2 centered at
298  * the origin. The map is expected to be valid on the boundaries of the cube.
299  */
300 template <typename Map>
301 void test_suite_for_map_on_unit_cube(const Map& map) {
302  // Set up random number generator
303  MAKE_GENERATOR(gen);
304  std::uniform_real_distribution<> real_dis(-1.0, 1.0);
305 
307  std::array<double, Map::dim> random_point{};
308  for (size_t i = 0; i < Map::dim; i++) {
309  gsl::at(origin, i) = 0.0;
310  gsl::at(random_point, i) = real_dis(gen);
311  }
312 
313  const auto test_helper =
314  [&origin, &random_point ](const auto& map_to_test) noexcept {
315  test_serialization(map_to_test);
316  CHECK_FALSE(map_to_test != map_to_test);
317  test_coordinate_map_argument_types(map_to_test, origin);
318 
319  test_jacobian(map_to_test, origin);
320  test_inv_jacobian(map_to_test, origin);
321  test_inverse_map(map_to_test, origin);
322 
323  for (VolumeCornerIterator<Map::dim> vci{}; vci; ++vci) {
324  test_jacobian(map_to_test, vci.coords_of_corner());
325  test_inv_jacobian(map_to_test, vci.coords_of_corner());
326  test_inverse_map(map_to_test, vci.coords_of_corner());
327  }
328 
329  test_jacobian(map_to_test, random_point);
330  test_inv_jacobian(map_to_test, random_point);
331  test_inverse_map(map_to_test, random_point);
332  };
333  test_helper(map);
334  const auto map2 = serialize_and_deserialize(map);
336  make_coordinate_map<Frame::Logical, Frame::Grid>(map),
337  make_coordinate_map<Frame::Logical, Frame::Grid>(map2));
338  test_helper(map2);
339 }
340 
341 /*!
342  * \ingroup TestingFrameworkGroup
343  * \brief Given a Map `map`, tests the map functions, including map inverse,
344  * jacobian, and inverse jacobian, for a series of points.
345  * These points are chosen in a sphere of radius `radius_of_sphere`, and the
346  * map is expected to be valid on the boundary of that sphere as well as
347  * in its interior. The flag `include_origin` indicates whether to test the
348  * map at the origin.
349  * This test works only in 3 dimensions.
350  */
351 template <typename Map>
352 void test_suite_for_map_on_sphere(const Map& map,
353  const bool include_origin = true,
354  const double radius_of_sphere = 1.0) {
355  static_assert(Map::dim == 3, "Works only for a 3d map");
356 
357  // Set up random number generator
358  MAKE_GENERATOR(gen);
359 
360  // If we don't include the origin, we want to use some finite inner
361  // boundary so that random points stay away from the origin.
362  // test_jacobian has a dx of 1.e-4 for finite-differencing, so here
363  // we pick a value larger than that.
364  const double inner_bdry = include_origin ? 0.0 : 5.e-3;
365 
366  std::uniform_real_distribution<> radius_dis(inner_bdry, radius_of_sphere);
367  std::uniform_real_distribution<> theta_dis(0, M_PI);
368  std::uniform_real_distribution<> phi_dis(0, 2.0 * M_PI);
369 
370  const double theta = theta_dis(gen);
371  CAPTURE_PRECISE(theta);
372  const double phi = phi_dis(gen);
373  CAPTURE_PRECISE(phi);
374  const double radius = radius_dis(gen);
375  CAPTURE_PRECISE(radius);
376 
377  const std::array<double, 3> random_point{{radius * sin(theta) * cos(phi),
378  radius * sin(theta) * sin(phi),
379  radius * cos(theta)}};
380 
381  const std::array<double, 3> random_bdry_point{
382  {radius_of_sphere * sin(theta) * cos(phi),
383  radius_of_sphere * sin(theta) * sin(phi),
384  radius_of_sphere * cos(theta)}};
385 
386  // This point is either the origin or (if include_origin is false)
387  // it is some random point on the inner boundary.
388  const std::array<double, 3> random_inner_bdry_point_or_origin{
389  {inner_bdry * sin(theta) * cos(phi),
390  inner_bdry * sin(theta) * sin(phi),
391  inner_bdry * cos(theta)}};
392 
393  const auto test_helper =
394  [&random_bdry_point, &random_inner_bdry_point_or_origin,
395  &random_point ](const auto& map_to_test) noexcept {
396  test_serialization(map_to_test);
397  CHECK_FALSE(map_to_test != map_to_test);
398 
400  random_inner_bdry_point_or_origin);
401  test_jacobian(map_to_test, random_inner_bdry_point_or_origin);
402  test_inv_jacobian(map_to_test, random_inner_bdry_point_or_origin);
403  test_inverse_map(map_to_test, random_inner_bdry_point_or_origin);
404 
405  test_coordinate_map_argument_types(map_to_test, random_point);
406  test_jacobian(map_to_test, random_point);
407  test_inv_jacobian(map_to_test, random_point);
408  test_inverse_map(map_to_test, random_point);
409 
410  test_jacobian(map_to_test, random_bdry_point);
411  test_inv_jacobian(map_to_test, random_bdry_point);
412  test_inverse_map(map_to_test, random_bdry_point);
413  };
414  test_helper(map);
415  const auto map2 = serialize_and_deserialize(map);
417  make_coordinate_map<Frame::Logical, Frame::Grid>(map),
418  make_coordinate_map<Frame::Logical, Frame::Grid>(map2));
419  test_helper(map2);
420 }
421 
422 /*!
423  * \ingroup TestingFrameworkGroup
424  * \brief An iterator for looping through all possible orientations
425  * of the n-dim cube.
426  */
427 template <size_t VolumeDim>
429  public:
430  OrientationMapIterator() noexcept {
431  std::iota(dims_.begin(), dims_.end(), 0);
432  set_map();
433  }
434  void operator++() noexcept {
435  ++vci_;
436  if (not vci_) {
437  not_at_end_ = std::next_permutation(dims_.begin(), dims_.end());
439  }
440  set_map();
441  }
442  explicit operator bool() const noexcept { return not_at_end_; }
443  const OrientationMap<VolumeDim>& operator()() const noexcept { return map_; }
444  const OrientationMap<VolumeDim>& operator*() const noexcept { return map_; }
445  void set_map() noexcept {
446  for (size_t i = 0; i < VolumeDim; i++) {
447  gsl::at(directions_, i) =
448  Direction<VolumeDim>{gsl::at(dims_, i), gsl::at(vci_(), i)};
449  }
450  map_ = OrientationMap<VolumeDim>{directions_};
451  }
452 
453  private:
454  bool not_at_end_ = true;
456  std::array<Direction<VolumeDim>, VolumeDim> directions_{};
458  OrientationMap<VolumeDim> map_ = OrientationMap<VolumeDim>{};
459 };
460 
461 /*!
462  * \ingroup TestingFrameworkGroup
463  * \brief Wedge OrientationMap in each of the six directions used in the
464  * Shell and Sphere domain creators.
465  */
467  const OrientationMap<3> upper_zeta_rotation{};
468  const OrientationMap<3> lower_zeta_rotation(std::array<Direction<3>, 3>{
471  const OrientationMap<3> upper_eta_rotation(std::array<Direction<3>, 3>{
474  const OrientationMap<3> lower_eta_rotation(std::array<Direction<3>, 3>{
477  const OrientationMap<3> upper_xi_rotation(std::array<Direction<3>, 3>{
480  const OrientationMap<3> lower_xi_rotation(std::array<Direction<3>, 3>{
483  return {{upper_zeta_rotation, lower_zeta_rotation, upper_eta_rotation,
484  lower_eta_rotation, upper_xi_rotation, lower_xi_rotation}};
485 }
Defines class template Direction.
void test_jacobian(const Map &map, const std::array< double, Map::dim > &test_point)
Given a Map map, checks that the jacobian gives expected results when compared to the numerical deriv...
Definition: TestMapHelpers.hpp:84
void test_inverse_map(const Map &map, const std::array< T, Map::dim > &test_point)
Given a Map map, checks that the inverse map gives expected results.
Definition: TestMapHelpers.hpp:288
constexpr void iota(ForwardIterator first, ForwardIterator last, T value)
Definition: Numeric.hpp:20
Defines DomainHelper functions.
void test_inv_jacobian(const Map &map, const std::array< double, Map::dim > &test_point)
Given a Map map, checks that the inverse jacobian and jacobian multiply together to produce the ident...
Definition: TestMapHelpers.hpp:105
void test_coordinate_map_argument_types(const Map &map, const std::array< double, Map::dim > &test_point, const Args &... args)
Checks that the CoordinateMap map functions as expected when used with different argument types...
Definition: TestMapHelpers.hpp:181
bool are_maps_equal(const Map &map, const CoordinateMapBase< Frame::Logical, Frame::Inertial, Map::dim > &map_base)
Given a Map and a CoordinateMapBase, checks that the maps are equal by downcasting map_base and then ...
Definition: TestMapHelpers.hpp:35
Iterates over the corners of a VolumeDim-dimensional cube.
Definition: DomainHelpers.hpp:240
Overloader< Fs... > make_overloader(Fs... fs)
Create Overloader<Fs...>, see Overloader for details.
Definition: Overloader.hpp:109
void test_coordinate_map_implementation(const Map &map)
Checks that the CoordinateMap map functions as expected when used as the template parameter to the Co...
Definition: TestMapHelpers.hpp:138
Identity map from .
Definition: Identity.hpp:25
Abstract base class for CoordinateMap.
Definition: CoordinateMap.hpp:49
#define CAPTURE_PRECISE(variable)
Alternative to Catch&#39;s CAPTURE that prints more digits.
Definition: TestingFramework.hpp:46
constexpr bool next_permutation(BidirectionalIterator first, BidirectionalIterator last, Compare comp)
Definition: Algorithm.hpp:93
std::array< double, VolumeDim > numerical_derivative(const Invocable &map, const std::array< double, VolumeDim > &x, const size_t direction, const double delta)
Calculates the derivative of an Invocable at a point x - represented by an array of doubles - in the ...
Definition: TestHelpers.hpp:257
std::array< OrientationMap< 3 >, 6 > all_wedge_directions()
Wedge OrientationMap in each of the six directions used in the Shell and Sphere domain creators...
Definition: TestMapHelpers.hpp:466
#define MAKE_GENERATOR(...)
MAKE_GENERATOR(NAME [, SEED]) declares a variable of name NAME containing a generator of type std::mt...
Definition: TestHelpers.hpp:387
virtual InverseJacobian< double, Dim, SourceFrame, TargetFrame > inv_jacobian(tnsr::I< double, Dim, SourceFrame > source_point, double time=std::numeric_limits< double >::signaling_NaN(), const std::unordered_map< std::string, FunctionOfTime &> &f_of_t_list=std::unordered_map< std::string, FunctionOfTime &>{}) const noexcept=0
Compute the inverse Jacobian of the Maps at the point(s) source_point
A particular Side along a particular coordinate Axis.
Definition: Direction.hpp:23
void check_if_maps_are_equal(const CoordinateMapBase< SourceFrame, TargetFrame, VolumeDim > &map_one, const CoordinateMapBase< SourceFrame, TargetFrame, VolumeDim > &map_two)
Given two coordinate maps (but not their types), check that the maps are equal by evaluating them at ...
Definition: TestMapHelpers.hpp:46
tnsr::iaa< DataType, SpatialDim, Frame > phi(const Scalar< DataType > &lapse, const tnsr::i< DataType, SpatialDim, Frame > &deriv_lapse, const tnsr::I< DataType, SpatialDim, Frame > &shift, const tnsr::iJ< DataType, SpatialDim, Frame > &deriv_shift, const tnsr::ii< DataType, SpatialDim, Frame > &spatial_metric, const tnsr::ijj< DataType, SpatialDim, Frame > &deriv_spatial_metric) noexcept
Computes the auxiliary variable used by the generalized harmonic formulation of Einstein&#39;s equations...
Definition: ComputeGhQuantities.cpp:22
void test_serialization(const T &t)
Tests the serialization of comparable types.
Definition: TestHelpers.hpp:55
Definition: IndexType.hpp:42
Defines class CoordinateMap.
Defines classes for Tensor.
An iterator for looping through all possible orientations of the n-dim cube.
Definition: TestMapHelpers.hpp:428
#define CHECK_ITERABLE_APPROX(a, b)
A wrapper around Catch&#39;s CHECK macro that checks approximate equality of entries in iterable containe...
Definition: TestingFramework.hpp:110
void test_suite_for_map_on_unit_cube(const Map &map)
Given a Map map, tests the map functions, including map inverse, jacobian, and inverse jacobian...
Definition: TestMapHelpers.hpp:301
Stores a collection of function values.
Definition: DataVector.hpp:46
Commonly used routines, functions and definitions shared amongst unit tests.
Code to wrap or improve the Catch testing framework used for unit tests.
T serialize_and_deserialize(const T &t)
Serializes and deserializes an object t of type T
Definition: TestHelpers.hpp:42
Definition: IndexType.hpp:44
tnsr::Ij< DataType, Dim, Frame::NoFrame > identity(const DataType &used_for_type) noexcept
returns the Identity matrix
Definition: Identity.hpp:14
virtual Jacobian< double, Dim, SourceFrame, TargetFrame > jacobian(tnsr::I< double, Dim, SourceFrame > source_point, double time=std::numeric_limits< double >::signaling_NaN(), const std::unordered_map< std::string, FunctionOfTime &> &f_of_t_list=std::unordered_map< std::string, FunctionOfTime &>{}) const noexcept=0
Compute the Jacobian of the Maps at the point(s) source_point
Defines type traits, some of which are future STL type_traits header.
void check_if_map_is_identity(const Map &map)
Given a coordinate map, check that this map is equal to the identity by evaluating the map at a rando...
Definition: TestMapHelpers.hpp:70
void test_suite_for_map_on_sphere(const Map &map, const bool include_origin=true, const double radius_of_sphere=1.0)
Given a Map map, tests the map functions, including map inverse, jacobian, and inverse jacobian...
Definition: TestMapHelpers.hpp:352
static Direction< VolumeDim > lower_xi() noexcept
Helper functions for creating specific Directions. These are labeled by the logical-coordinate names ...
Definition: Direction.hpp:108
constexpr T & at(std::array< T, N > &arr, Size index)
Retrieve a entry from a container, with checks in Debug mode that the index being retrieved is valid...
Definition: Gsl.hpp:124
Defines the class Identity.