SpECTRE Documentation Coverage Report
Current view: top level - Domain - ElementMap.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 15.8 % 19 3
Test Date: 2026-10-22 17:29:42
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 <cstddef>
       8              : #include <limits>
       9              : #include <memory>
      10              : 
      11              : #include "DataStructures/Tensor/Tensor.hpp"
      12              : #include "Domain/Block.hpp"
      13              : #include "Domain/CoordinateMaps/CoordinateMap.hpp"
      14              : #include "Domain/FunctionsOfTime/FunctionOfTime.hpp"
      15              : #include "Domain/Structure/ElementId.hpp"
      16              : #include "Utilities/Gsl.hpp"
      17              : #include "Utilities/MakeArray.hpp"
      18              : 
      19              : namespace PUP {
      20              : class er;
      21              : }  // namespace PUP
      22              : 
      23              : /*!
      24              :  * \ingroup ComputationalDomainGroup
      25              :  * \brief The CoordinateMap for the Element from the Logical frame to the
      26              :  * `TargetFrame`
      27              :  *
      28              :  * An ElementMap takes a CoordinateMap for a Block and an ElementId as input,
      29              :  * and then "prepends" the correct affine map to the CoordinateMap so that the
      30              :  * map corresponds to the coordinate map for the Element rather than the Block.
      31              :  * This allows DomainCreators to only specify the maps for the Blocks without
      32              :  * worrying about how the domain may be decomposed beyond that.
      33              :  */
      34              : template <size_t Dim, typename TargetFrame>
      35            1 : class ElementMap {
      36              :  public:
      37            0 :   static constexpr size_t dim = Dim;
      38            0 :   using source_frame = Frame::ElementLogical;
      39            0 :   using target_frame = TargetFrame;
      40              : 
      41              :   /// \cond HIDDEN_SYMBOLS
      42              :   ElementMap() = default;
      43              :   /// \endcond
      44              : 
      45            0 :   ElementMap(const ElementId<Dim>& element_id,
      46              :              std::unique_ptr<domain::CoordinateMapBase<Frame::BlockLogical,
      47              :                                                        TargetFrame, Dim>>
      48              :                  block_map);
      49              : 
      50              :   /// Construct from an `element_id` within the `block`. The (affine)
      51              :   /// ElementLogical to BlockLogical map is determined by the `element_id`. The
      52              :   /// BlockLogical to TargetFrame map is determined by the `block`:
      53              :   /// - If the block is time-independent: the `block.stationary_map()` is used.
      54              :   /// - If the block is time-dependent: The `block.moving_mesh_*_map()` maps
      55              :   ///   are used. Which maps are used depends on the TargetFrame.
      56            1 :   ElementMap(const ElementId<Dim>& element_id, const Block<Dim>& block);
      57              : 
      58              :   const domain::CoordinateMapBase<Frame::BlockLogical, TargetFrame, Dim>&
      59            0 :   block_map() const {
      60              :     return *block_map_;
      61              :   }
      62              : 
      63              :   template <typename T>
      64            0 :   tnsr::I<T, Dim, TargetFrame> operator()(
      65              :       const tnsr::I<T, Dim, Frame::ElementLogical>& source_point,
      66              :       const double time = std::numeric_limits<double>::signaling_NaN(),
      67              :       const domain::FunctionsOfTimeMap& functions_of_time = {}) const {
      68              :     auto block_source_point =
      69              :         apply_affine_transformation_to_point(source_point);
      70              :     return block_map_->operator()(std::move(block_source_point), time,
      71              :                                   functions_of_time);
      72              :   }
      73              : 
      74              :   template <typename T>
      75            0 :   tnsr::I<T, Dim, Frame::ElementLogical> inverse(
      76              :       tnsr::I<T, Dim, TargetFrame> target_point,
      77              :       const double time = std::numeric_limits<double>::signaling_NaN(),
      78              :       const domain::FunctionsOfTimeMap& functions_of_time = {}) const {
      79              :     auto block_source_point{
      80              :         block_map_->inverse(std::move(target_point), time, functions_of_time)
      81              :             .value()};
      82              :     // Apply the affine map to the points
      83              :     tnsr::I<T, Dim, Frame::ElementLogical> source_point;
      84              :     for (size_t d = 0; d < Dim; ++d) {
      85              :       const double inv_jac = 1.0 / gsl::at(map_slope_, d);
      86              :       const double temp = gsl::at(map_offset_, d) * inv_jac;
      87              :       source_point.get(d) = inv_jac * block_source_point.get(d) - temp;
      88              :     }
      89              :     return source_point;
      90              :   }
      91              : 
      92              :   template <typename T>
      93            0 :   InverseJacobian<T, Dim, Frame::ElementLogical, TargetFrame> inv_jacobian(
      94              :       const tnsr::I<T, Dim, Frame::ElementLogical>& source_point,
      95              :       const double time = std::numeric_limits<double>::signaling_NaN(),
      96              :       const domain::FunctionsOfTimeMap& functions_of_time = {}) const {
      97              :     auto block_source_point =
      98              :         apply_affine_transformation_to_point(source_point);
      99              :     auto block_inv_jac = block_map_->inv_jacobian(std::move(block_source_point),
     100              :                                                   time, functions_of_time);
     101              :     InverseJacobian<T, Dim, Frame::ElementLogical, TargetFrame> inv_jac;
     102              :     for (size_t d = 0; d < Dim; ++d) {
     103              :       const double inv_jac_in_dir = 1.0 / gsl::at(map_slope_, d);
     104              :       for (size_t i = 0; i < Dim; ++i) {
     105              :         inv_jac.get(d, i) = inv_jac_in_dir * block_inv_jac.get(d, i);
     106              :       }
     107              :     }
     108              :     return inv_jac;
     109              :   }
     110              : 
     111              :   template <typename T>
     112            0 :   Jacobian<T, Dim, Frame::ElementLogical, TargetFrame> jacobian(
     113              :       const tnsr::I<T, Dim, Frame::ElementLogical>& source_point,
     114              :       const double time = std::numeric_limits<double>::signaling_NaN(),
     115              :       const domain::FunctionsOfTimeMap& functions_of_time = {}) const {
     116              :     auto block_source_point =
     117              :         apply_affine_transformation_to_point(source_point);
     118              :     auto block_jac = block_map_->jacobian(std::move(block_source_point), time,
     119              :                                           functions_of_time);
     120              :     Jacobian<T, Dim, Frame::ElementLogical, TargetFrame> jac;
     121              :     for (size_t d = 0; d < Dim; ++d) {
     122              :       for (size_t i = 0; i < Dim; ++i) {
     123              :         jac.get(i, d) = block_jac.get(i, d) * gsl::at(map_slope_, d);
     124              :       }
     125              :     }
     126              :     return jac;
     127              :   }
     128              : 
     129              : #ifdef SPECTRE_AUTODIFF
     130              :   /*!
     131              :    * \brief The inverse Hessian of the element map.
     132              :    *
     133              :    * Let \f$ \xi^i \f$ be the element logical coordinates, \f$ x^i \f$ be the
     134              :    * block logical coordinates, and \f$ y^i \f$ be the inertial coordinates.
     135              :    * The element map maps \f$ \xi^i \rightarrow x^i \rightarrow y^i \f$. Thus,
     136              :    * the inverse Hessian is
     137              :    * \f[
     138              :    * \frac{\partial^2\xi^i}{\partial y^j \partial y^k} =
     139              :    * \frac{\partial}{\partial y^j}\frac{\partial x^l}{\partial y^k}
     140              :    * \frac{\partial \xi^i}{\partial x^l}} =
     141              :    * \frac{\partial^2 x^l}{\partial y^j \partial y^k}
     142              :    * \frac{\partial \xi^i}{\partial x^l}
     143              :    * \f]
     144              :    * where we have used the fact
     145              :    * \f[
     146              :    * \frac{\partial^2 \xi^i}{\partial x^l \partial x^n} = 0.
     147              :    * \f]
     148              :    */
     149              :   template <typename T>
     150            1 :   InverseHessian<T, Dim, Frame::ElementLogical, TargetFrame> inv_hessian(
     151              :       const tnsr::I<T, Dim, Frame::ElementLogical>& source_point,
     152              :       const double time = std::numeric_limits<double>::signaling_NaN(),
     153              :       const domain::FunctionsOfTimeMap& functions_of_time = {}) const {
     154              :     auto block_source_point =
     155              :         apply_affine_transformation_to_point(source_point);
     156              :     auto block_inv_jac =
     157              :         block_map_->inv_jacobian(block_source_point, time, functions_of_time);
     158              :     auto block_inv_hes = block_map_->inv_hessian(
     159              :         std::move(block_source_point), block_inv_jac, time, functions_of_time);
     160              :     InverseHessian<T, Dim, Frame::ElementLogical, TargetFrame> inv_hes;
     161              :     for (size_t i = 0; i < Dim; ++i) {
     162              :       for (size_t j = 0; j < Dim; ++j) {
     163              :         for (size_t k = j; k < Dim; ++k) {
     164              :           inv_hes.get(i, j, k) =
     165              :               block_inv_hes.get(i, j, k) / gsl::at(map_slope_, i);
     166              :         }
     167              :       }
     168              :     }
     169              :     return inv_hes;
     170              :   }
     171              : #endif  // SPECTRE_AUTODIFF
     172              : 
     173              :   // NOLINTNEXTLINE(google-runtime-references)
     174            0 :   void pup(PUP::er& p);
     175              : 
     176              :  private:
     177              :   template <typename T>
     178            0 :   tnsr::I<T, Dim, Frame::BlockLogical> apply_affine_transformation_to_point(
     179              :       const tnsr::I<T, Dim, Frame::ElementLogical>& source_point) const {
     180              :     tnsr::I<T, Dim, Frame::BlockLogical> block_source_point;
     181              :     for (size_t d = 0; d < Dim; ++d) {
     182              :       block_source_point.get(d) = source_point.get(d) * gsl::at(map_slope_, d) +
     183              :                                   gsl::at(map_offset_, d);
     184              :     }
     185              :     return block_source_point;
     186              :   }
     187              : 
     188              :   std::unique_ptr<
     189              :       domain::CoordinateMapBase<Frame::BlockLogical, TargetFrame, Dim>>
     190            0 :       block_map_{nullptr};
     191              :   // map_slope_[i] = 0.5 * (segment_ids[i].endpoint(Side::Upper) -
     192              :   //                        segment_ids[i].endpoint(Side::Lower))
     193              :   // Note: the map_slope_ is the jacobian_
     194            0 :   std::array<double, Dim> map_slope_{
     195              :       make_array<Dim>(std::numeric_limits<double>::signaling_NaN())};
     196              :   // map_offset_[i] = 0.5 * (segment_ids[i].endpoint(Side::Upper) +
     197              :   //                         segment_ids[i].endpoint(Side::Lower))
     198            0 :   std::array<double, Dim> map_offset_{
     199              :       make_array<Dim>(std::numeric_limits<double>::signaling_NaN())};
     200              : };
     201              : 
     202              : template <size_t Dim, typename TargetFrame>
     203            0 : ElementMap(ElementId<Dim> element_id,
     204              :            std::unique_ptr<
     205              :                domain::CoordinateMapBase<Frame::BlockLogical, TargetFrame, Dim>>
     206              :                block_map) -> ElementMap<Dim, TargetFrame>;
        

Generated by: LCOV version 2.0-1