SpECTRE Documentation Coverage Report
Current view: top level - Domain/CoordinateMaps - CoordinateMapHelpers.hpp Hit Total Coverage
Commit: 328f9869698605d8d0d10cb5de37d74567214820 Lines: 0 1 0.0 %
Date: 2026-08-07 19:36:38
Legend: Lines: hit not hit

          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 <memory>
       8             : #include <string>
       9             : #include <type_traits>
      10             : #include <unordered_map>
      11             : 
      12             : #include "DataStructures/DataVector.hpp"
      13             : #include "DataStructures/Tensor/Identity.hpp"
      14             : #include "DataStructures/Tensor/Tensor.hpp"
      15             : #include "Domain/FunctionsOfTime/FunctionOfTime.hpp"
      16             : #include "Utilities/DereferenceWrapper.hpp"
      17             : #include "Utilities/ErrorHandling/FloatingPointExceptions.hpp"
      18             : #include "Utilities/Gsl.hpp"
      19             : #include "Utilities/TypeTraits/RemoveReferenceWrapper.hpp"
      20             : 
      21             : namespace domain {
      22             : namespace CoordinateMap_detail {
      23             : /// Returns a value that aliases `x` where that is cheaper than copying: a
      24             : /// non-owning view for `DataVector` and a copy for arithmetic types such as
      25             : /// `double`. Coordinate maps that pass (a subset of) their source coordinates
      26             : /// on to another map use this function to avoid copying the underlying data.
      27             : /// Coordinate maps take their source coordinates by const reference, so the
      28             : /// data is never modified through the view. The view must not outlive `x`.
      29             : template <typename T>
      30             : T view_or_copy(const T& x) {
      31             :   if constexpr (std::is_same_v<T, DataVector>) {
      32             :     return {const_cast<double*>(x.data()), x.size()};  // NOLINT
      33             :   } else {
      34             :     return x;
      35             :   }
      36             : }
      37             : /// @{
      38             : /// Call the map passing in the time and FunctionsOfTime if the map is
      39             : /// time-dependent
      40             : template <typename T, size_t Dim, typename Map>
      41             : void apply_map(
      42             :     const gsl::not_null<std::array<T, Dim>*> t_map_point, const Map& the_map,
      43             :     const double /*t*/,
      44             :     const std::unordered_map<
      45             :         std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
      46             :     /*functions_of_time*/,
      47             :     const std::false_type /*is_time_independent*/) {
      48             :   if (LIKELY(not the_map.is_identity())) {
      49             :     *t_map_point = the_map(*t_map_point);
      50             :   }
      51             : }
      52             : 
      53             : template <typename T, size_t Dim, typename Map>
      54             : void apply_map(
      55             :     const gsl::not_null<std::array<T, Dim>*> t_map_point, const Map& the_map,
      56             :     const double t,
      57             :     const std::unordered_map<
      58             :         std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
      59             :         functions_of_time,
      60             :     const std::true_type
      61             :     /*is_time_dependent*/) {
      62             :   ASSERT(not functions_of_time.empty(),
      63             :          "A function of time must be present if the maps are time-dependent.");
      64             :   ASSERT(
      65             :       [t]() {
      66             :         const ScopedFpeState disable_fpes(false);
      67             :         return not std::isnan(t);
      68             :       }(),
      69             :       "The time must not be NaN for time-dependent maps.");
      70             :   *t_map_point = the_map(*t_map_point, t, functions_of_time);
      71             : }
      72             : 
      73             : template <typename T, size_t Dim, typename Map>
      74             : auto apply_map(
      75             :     const Map& the_map, const std::array<T, Dim>& source_points,
      76             :     const double /*t*/,
      77             :     const std::unordered_map<
      78             :         std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
      79             :     /*functions_of_time*/,
      80             :     const std::false_type /*is_time_independent*/) {
      81             :   if (LIKELY(not the_map.is_identity())) {
      82             :     return the_map(source_points);
      83             :   }
      84             :   std::decay_t<decltype(the_map(source_points))> result{};
      85             :   for (size_t i = 0; i < result.size(); ++i) {
      86             :     gsl::at(result, i) = gsl::at(source_points, i);
      87             :   }
      88             :   return result;
      89             : }
      90             : 
      91             : template <typename T, size_t Dim, typename Map>
      92             : auto apply_map(
      93             :     const Map& the_map, const std::array<T, Dim>& source_points, const double t,
      94             :     const std::unordered_map<
      95             :         std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
      96             :         functions_of_time,
      97             :     const std::true_type
      98             :     /*is_time_dependent*/) {
      99             :   // Note: We don't forward to the return-by-not-null version to avoid
     100             :   // additional allocations of the target points array. That is, we would
     101             :   // allocate the target points array once here, and then again inside the call
     102             :   // to the coordinate map.
     103             :   ASSERT(not functions_of_time.empty(),
     104             :          "A function of time must be present if the maps are time-dependent.");
     105             :   ASSERT(
     106             :       [t]() {
     107             :         const ScopedFpeState disable_fpes(false);
     108             :         return not std::isnan(t);
     109             :       }(),
     110             :       "The time must not be NaN for time-dependent maps.");
     111             :   return the_map(source_points, t, functions_of_time);
     112             : }
     113             : /// @}
     114             : 
     115             : /// @{
     116             : template <typename T, size_t Dim, typename Map>
     117             : auto apply_inverse_map(
     118             :     const Map& the_map, const std::array<T, Dim>& target_points,
     119             :     const double /*t*/,
     120             :     const std::unordered_map<
     121             :         std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     122             :     /*functions_of_time*/,
     123             :     const std::false_type /*is_time_independent*/) {
     124             :   if (LIKELY(not the_map.is_identity())) {
     125             :     return the_map.inverse(target_points);
     126             :   }
     127             :   using UnwrappedT = tt::remove_cvref_wrap_t<T>;
     128             :   std::decay_t<decltype(the_map.inverse(target_points))> result{
     129             :       std::array<UnwrappedT, Dim>{}};
     130             :   for (size_t i = 0; i < target_points.size(); ++i) {
     131             :     gsl::at(*result, i) = gsl::at(target_points, i);
     132             :   }
     133             :   return result;
     134             : }
     135             : 
     136             : template <typename T, size_t Dim, typename Map>
     137             : auto apply_inverse_map(
     138             :     const Map& the_map, const std::array<T, Dim>& target_points, const double t,
     139             :     const std::unordered_map<
     140             :         std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     141             :         functions_of_time,
     142             :     const std::true_type
     143             :     /*is_time_dependent*/) {
     144             :   ASSERT(not functions_of_time.empty(),
     145             :          "A function of time must be present if the maps are time-dependent.");
     146             :   ASSERT(
     147             :       [t]() {
     148             :         const ScopedFpeState disable_fpes(false);
     149             :         return not std::isnan(t);
     150             :       }(),
     151             :       "The time must not be NaN for time-dependent maps.");
     152             :   return the_map.inverse(target_points, t, functions_of_time);
     153             : }
     154             : /// @}
     155             : 
     156             : /// @{
     157             : /// Compute the frame velocity
     158             : template <typename T, size_t Dim, typename Map>
     159             : auto apply_frame_velocity(
     160             :     const Map& /*the_map*/, const std::array<T, Dim>& source_points,
     161             :     const double /*t*/,
     162             :     const std::unordered_map<
     163             :         std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     164             :     /*functions_of_time*/,
     165             :     const std::false_type /*is_time_independent*/) {
     166             :   return make_array<Map::dim, tt::remove_cvref_wrap_t<T>>(
     167             :       make_with_value<tt::remove_cvref_wrap_t<T>>(
     168             :           dereference_wrapper(source_points[0]), 0.0));
     169             : }
     170             : 
     171             : template <typename T, size_t Dim, typename Map>
     172             : auto apply_frame_velocity(
     173             :     const Map& the_map, const std::array<T, Dim>& source_points, const double t,
     174             :     const std::unordered_map<
     175             :         std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     176             :         functions_of_time,
     177             :     const std::true_type
     178             :     /*is_time_dependent*/) {
     179             :   ASSERT(not functions_of_time.empty(),
     180             :          "A function of time must be present if the maps are time-dependent.");
     181             :   ASSERT(
     182             :       [t]() {
     183             :         const ScopedFpeState disable_fpes(false);
     184             :         return not std::isnan(t);
     185             :       }(),
     186             :       "The time must not be NaN for time-dependent maps.");
     187             :   return the_map.frame_velocity(source_points, t, functions_of_time);
     188             : }
     189             : /// @}
     190             : 
     191             : /// @{
     192             : /// Compute the Jacobian
     193             : template <typename T, size_t Dim, typename Map>
     194             : auto apply_jacobian(
     195             :     const Map& the_map, const std::array<T, Dim>& source_points,
     196             :     const double /*t*/,
     197             :     const std::unordered_map<
     198             :         std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     199             :     /*functions_of_time*/,
     200             :     const std::false_type /*is_time_independent*/) {
     201             :   if (LIKELY(not the_map.is_identity())) {
     202             :     return the_map.jacobian(source_points);
     203             :   }
     204             :   return identity<Dim>(dereference_wrapper(source_points[0]));
     205             : }
     206             : 
     207             : template <typename T, size_t Dim, typename Map>
     208             : auto apply_jacobian(
     209             :     const Map& the_map, const std::array<T, Dim>& source_points, const double t,
     210             :     const std::unordered_map<
     211             :         std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     212             :         functions_of_time,
     213             :     const std::true_type
     214             :     /*is_time_dependent*/) {
     215             :   ASSERT(not functions_of_time.empty(),
     216             :          "A function of time must be present if the maps are time-dependent.");
     217             :   ASSERT(
     218             :       [t]() {
     219             :         const ScopedFpeState disable_fpes(false);
     220             :         return not std::isnan(t);
     221             :       }(),
     222             :       "The time must not be NaN for time-dependent maps.");
     223             :   if (LIKELY(not the_map.is_identity())) {
     224             :     return the_map.jacobian(source_points, t, functions_of_time);
     225             :   }
     226             :   return identity<Dim>(dereference_wrapper(source_points[0]));
     227             : }
     228             : /// @}
     229             : 
     230             : /// @{
     231             : /// Compute the Jacobian
     232             : template <typename T, size_t Dim, typename Map>
     233             : auto apply_inverse_jacobian(
     234             :     const Map& the_map, const std::array<T, Dim>& source_points,
     235             :     const double /*t*/,
     236             :     const std::unordered_map<
     237             :         std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     238             :     /*functions_of_time*/,
     239             :     const std::false_type /*is_time_independent*/) {
     240             :   if (LIKELY(not the_map.is_identity())) {
     241             :     return the_map.inv_jacobian(source_points);
     242             :   }
     243             :   return identity<Dim>(dereference_wrapper(source_points[0]));
     244             : }
     245             : 
     246             : template <typename T, size_t Dim, typename Map>
     247             : auto apply_inverse_jacobian(
     248             :     const Map& the_map, const std::array<T, Dim>& source_points, const double t,
     249             :     const std::unordered_map<
     250             :         std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     251             :         functions_of_time,
     252             :     const std::true_type
     253             :     /*is_time_dependent*/) {
     254             :   ASSERT(not functions_of_time.empty(),
     255             :          "A function of time must be present if the maps are time-dependent.");
     256             :   ASSERT(
     257             :       [t]() {
     258             :         const ScopedFpeState disable_fpes(false);
     259             :         return not std::isnan(t);
     260             :       }(),
     261             :       "The time must not be NaN for time-dependent maps.");
     262             :   if (LIKELY(not the_map.is_identity())) {
     263             :     return the_map.inv_jacobian(source_points, t, functions_of_time);
     264             :   }
     265             :   return identity<Dim>(dereference_wrapper(source_points[0]));
     266             : }
     267             : /// @}
     268             : }  // namespace CoordinateMap_detail
     269             : }  // namespace domain

Generated by: LCOV version 1.14