SpECTRE Documentation Coverage Report
Current view: top level - Domain - Tags.hpp Hit Total Coverage
Commit: 1f2210958b4f38fdc0400907ee7c6d5af5111418 Lines: 19 83 22.9 %
Date: 2025-12-05 05:03:31
Legend: Lines: hit not hit

          Line data    Source code
       1           1 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : /// \file
       5             : /// Defines tags related to domain quantities
       6             : 
       7             : #pragma once
       8             : 
       9             : #include <array>
      10             : #include <cstddef>
      11             : #include <memory>
      12             : #include <string>
      13             : #include <unordered_map>
      14             : #include <unordered_set>
      15             : #include <vector>
      16             : 
      17             : #include "DataStructures/DataBox/Subitems.hpp"
      18             : #include "DataStructures/DataBox/Tag.hpp"
      19             : #include "DataStructures/DataBox/TagName.hpp"
      20             : #include "DataStructures/Tensor/EagerMath/Determinant.hpp"
      21             : #include "DataStructures/Tensor/EagerMath/DeterminantAndInverse.hpp"
      22             : #include "DataStructures/Tensor/TypeAliases.hpp"
      23             : #include "DataStructures/Variables.hpp"
      24             : #include "Domain/Structure/Direction.hpp"
      25             : #include "Domain/Structure/Element.hpp"
      26             : #include "Utilities/GetOutput.hpp"
      27             : #include "Utilities/Gsl.hpp"
      28             : #include "Utilities/NoSuchType.hpp"
      29             : #include "Utilities/Requires.hpp"
      30             : #include "Utilities/TMPL.hpp"
      31             : #include "Utilities/TypeTraits.hpp"
      32             : #include "Utilities/TypeTraits/IsA.hpp"
      33             : 
      34             : /// \cond
      35             : class DataVector;
      36             : template <size_t VolumeDim>
      37             : class Domain;
      38             : template <size_t VolumeDim, typename Frame>
      39             : class ElementMap;
      40             : template <size_t VolumeDim>
      41             : class Mesh;
      42             : /// \endcond
      43             : 
      44             : namespace domain {
      45             : /// \ingroup ComputationalDomainGroup
      46             : /// \brief %Tags for the domain.
      47             : namespace Tags {
      48             : /// \ingroup DataBoxTagsGroup
      49             : /// \ingroup ComputationalDomainGroup
      50             : /// The ::Element associated with the DataBox
      51             : template <size_t VolumeDim>
      52           1 : struct Element : db::SimpleTag {
      53           0 :   using type = ::Element<VolumeDim>;
      54             : };
      55             : 
      56             : /// \ingroup DataBoxTagsGroup
      57             : /// \ingroup ComputationalDomainGroup
      58             : /// \brief The computational grid of the Element in the DataBox
      59             : /// \details The corresponding interface tag uses Mesh::slice_through to compute
      60             : /// the mesh on the face of the element.
      61             : template <size_t VolumeDim>
      62           1 : struct Mesh : db::SimpleTag {
      63           0 :   using type = ::Mesh<VolumeDim>;
      64             : };
      65             : 
      66             : /// \ingroup DataBoxTagsGroup
      67             : /// \ingroup ComputationalDomainGroup
      68             : /// The coordinate map from the ElementLogical frame to the TargetFrame
      69             : template <size_t VolumeDim, typename TargetFrame = Frame::Inertial>
      70           1 : struct ElementMap : db::SimpleTag {
      71           0 :   static constexpr size_t dim = VolumeDim;
      72           0 :   using target_frame = TargetFrame;
      73           0 :   using source_frame = Frame::ElementLogical;
      74             : 
      75           0 :   static std::string name() {
      76             :     return "ElementMap(" + get_output(TargetFrame{}) + ")";
      77             :   }
      78           0 :   using type = ::ElementMap<VolumeDim, TargetFrame>;
      79             : };
      80             : 
      81             : /// \ingroup DataBoxTagsGroup
      82             : /// \ingroup ComputationalDomainGroup
      83             : /// The coordinates in a given frame.
      84             : template <size_t Dim, typename Frame>
      85           1 : struct Coordinates : db::SimpleTag {
      86           0 :   static std::string name() { return get_output(Frame{}) + "Coordinates"; }
      87           0 :   using type = tnsr::I<DataVector, Dim, Frame>;
      88             : };
      89             : 
      90             : /// \ingroup DataBoxTagsGroup
      91             : /// \ingroup ComputationalDomainGroup
      92             : /// The coordinates in the target frame of `MapTag`. The `SourceCoordsTag`'s
      93             : /// frame must be the source frame of `MapTag`
      94             : template <class MapTag, class SourceCoordsTag,
      95             :           template <size_t, class> class CoordinatesTag = Coordinates>
      96           1 : struct MappedCoordinates
      97             :     : CoordinatesTag<MapTag::dim, typename MapTag::target_frame>,
      98             :       db::ComputeTag {
      99           0 :   using base = CoordinatesTag<MapTag::dim, typename MapTag::target_frame>;
     100           0 :   using return_type = typename base::type;
     101           0 :   using argument_tags = tmpl::list<MapTag, SourceCoordsTag>;
     102           0 :   static constexpr auto function(
     103             :       const gsl::not_null<return_type*> target_coords,
     104             :       const typename MapTag::type& element_map,
     105             :       const tnsr::I<DataVector, MapTag::dim, typename MapTag::source_frame>&
     106             :           source_coords) {
     107             :     *target_coords = element_map(source_coords);
     108             :   }
     109             : };
     110             : 
     111             : /// \ingroup DataBoxTagsGroup
     112             : /// \ingroup ComputationalDomainGroup
     113             : /// \brief The inverse Jacobian from the source frame to the target frame.
     114             : ///
     115             : /// Specifically, \f$\partial x^{\bar{i}} / \partial x^i\f$, where \f$\bar{i}\f$
     116             : /// denotes the source frame and \f$i\f$ denotes the target frame.
     117             : template <size_t Dim, typename SourceFrame, typename TargetFrame>
     118           1 : struct InverseJacobian : db::SimpleTag {
     119           0 :   static std::string name() {
     120             :     return "InverseJacobian(" + get_output(SourceFrame{}) + "," +
     121             :            get_output(TargetFrame{}) + ")";
     122             :   }
     123           0 :   using type = ::InverseJacobian<DataVector, Dim, SourceFrame, TargetFrame>;
     124             : };
     125             : 
     126             : /// \ingroup DataBoxTagsGroup
     127             : /// \ingroup ComputationalDomainGroup
     128             : /// Computes the inverse Jacobian of the map held by `MapTag` at the coordinates
     129             : /// held by `SourceCoordsTag`. The coordinates must be in the source frame of
     130             : /// the map.
     131             : template <typename MapTag, typename SourceCoordsTag>
     132           1 : struct InverseJacobianCompute
     133             :     : InverseJacobian<MapTag::dim, typename MapTag::source_frame,
     134             :                       typename MapTag::target_frame>,
     135             :       db::ComputeTag {
     136           0 :   using base = InverseJacobian<MapTag::dim, typename MapTag::source_frame,
     137             :                                typename MapTag::target_frame>;
     138           0 :   using return_type = typename base::type;
     139           0 :   using argument_tags = tmpl::list<MapTag, SourceCoordsTag>;
     140           0 :   static constexpr auto function(
     141             :       const gsl::not_null<return_type*> inv_jacobian,
     142             :       const typename MapTag::type& element_map,
     143             :       const tnsr::I<DataVector, MapTag::dim, typename MapTag::source_frame>&
     144             :           source_coords) {
     145             :     *inv_jacobian = element_map.inv_jacobian(source_coords);
     146             :   }
     147             : };
     148             : 
     149             : /// \ingroup DataBoxTagsGroup
     150             : /// \ingroup ComputationalDomainGroup
     151             : /// \brief The Jacobian from the source frame to the target frame.
     152             : ///
     153             : /// Specifically, \f$\partial x^{i} / \partial \xi^{\bar{i}}\f$, where
     154             : /// \f$\xi^\bar{i}\f$ denotes the source frame and \f$x^i\f$ denotes the target
     155             : /// frame.
     156             : template <size_t Dim, typename SourceFrame, typename TargetFrame>
     157           1 : struct Jacobian : db::SimpleTag {
     158           0 :   static std::string name() {
     159             :     return "Jacobian(" + get_output(SourceFrame{}) + "," +
     160             :            get_output(TargetFrame{}) + ")";
     161             :   }
     162           0 :   using type = ::Jacobian<DataVector, Dim, SourceFrame, TargetFrame>;
     163             : };
     164             : 
     165             : /// \ingroup DataBoxTagsGroup
     166             : /// \ingroup ComputationalDomainGroup
     167             : /// Computes the Jacobian of the map from the `InverseJacobian<Dim, SourceFrame,
     168             : /// TargetFrame>` tag.
     169             : template <size_t Dim, typename SourceFrame, typename TargetFrame>
     170           1 : struct JacobianCompute : Jacobian<Dim, SourceFrame, TargetFrame>,
     171             :                          db::ComputeTag {
     172           0 :   using base = Jacobian<Dim, SourceFrame, TargetFrame>;
     173           0 :   using return_type = typename base::type;
     174           0 :   using argument_tags =
     175             :       tmpl::list<InverseJacobian<Dim, SourceFrame, TargetFrame>>;
     176           0 :   static constexpr auto function(
     177             :       const gsl::not_null<return_type*> jacobian,
     178             :       const ::InverseJacobian<DataVector, Dim, SourceFrame, TargetFrame>&
     179             :           inv_jac) {
     180             :     *jacobian = determinant_and_inverse(inv_jac).second;
     181             :   }
     182             : };
     183             : 
     184             : /// \ingroup DataBoxTagsGroup
     185             : /// \ingroup ComputationalDomainGroup
     186             : /// \brief The determinant of the inverse Jacobian from the source frame to the
     187             : /// target frame.
     188             : template <typename SourceFrame, typename TargetFrame>
     189           1 : struct DetInvJacobian : db::SimpleTag {
     190           0 :   using type = Scalar<DataVector>;
     191           0 :   static std::string name() {
     192             :     return "DetInvJacobian(" + get_output(SourceFrame{}) + "," +
     193             :            get_output(TargetFrame{}) + ")";
     194             :   }
     195             : };
     196             : 
     197             : /// \ingroup DataBoxTagsGroup
     198             : /// \ingroup ComputationalDomainGroup
     199             : /// Computes the determinant of the inverse Jacobian.
     200             : template <size_t Dim, typename SourceFrame, typename TargetFrame>
     201           1 : struct DetInvJacobianCompute : db::ComputeTag,
     202             :                                DetInvJacobian<SourceFrame, TargetFrame> {
     203           0 :   using base = DetInvJacobian<SourceFrame, TargetFrame>;
     204           0 :   using return_type = typename base::type;
     205           0 :   using argument_tags =
     206             :       tmpl::list<InverseJacobian<Dim, SourceFrame, TargetFrame>>;
     207           0 :   static void function(const gsl::not_null<return_type*> det_inv_jac,
     208             :                        const ::InverseJacobian<DataVector, Dim, SourceFrame,
     209             :                                                TargetFrame>& inv_jac) {
     210             :     determinant(det_inv_jac, inv_jac);
     211             :   }
     212             : };
     213             : 
     214             : /// \ingroup DataBoxTagsGroup
     215             : /// \ingroup ComputationalDomainGroup
     216             : /// \brief The determinant of the Jacobian from the source frame to the target
     217             : /// frame.
     218             : template <typename SourceFrame, typename TargetFrame>
     219           1 : struct DetJacobian : db::SimpleTag {
     220           0 :   using type = Scalar<DataVector>;
     221           0 :   static std::string name() {
     222             :     return "DetJacobian(" + get_output(SourceFrame{}) + "," +
     223             :            get_output(TargetFrame{}) + ")";
     224             :   }
     225             : };
     226             : 
     227             : /// \ingroup DataBoxTagsGroup
     228             : /// \ingroup ComputationalDomainGroup
     229             : /// \brief The inverse Jacobian times the determinant of the Jacobian.
     230             : ///
     231             : /// This quantity is divergence-free analytically. See
     232             : /// `::dg::metric_identity_det_jac_times_inv_jac` for more information.
     233             : template <size_t Dim, typename SourceFrame, typename TargetFrame>
     234           1 : struct DetTimesInvJacobian : db::SimpleTag {
     235           0 :   using type = ::InverseJacobian<DataVector, Dim, SourceFrame, TargetFrame>;
     236           0 :   static std::string name() {
     237             :     return "DetTimesInvJacobian(" + get_output(SourceFrame{}) + "," +
     238             :            get_output(TargetFrame{}) + ")";
     239             :   }
     240             : };
     241             : 
     242             : /// @{
     243             : /// \ingroup DataBoxTagsGroup
     244             : /// \ingroup ComputationalDomainGroup
     245             : /// The set of directions to neighboring Elements
     246             : template <size_t VolumeDim>
     247           1 : struct InternalDirections : db::SimpleTag {
     248           0 :   static constexpr size_t volume_dim = VolumeDim;
     249           0 :   using type = std::unordered_set<::Direction<VolumeDim>>;
     250             : };
     251             : 
     252             : template <size_t VolumeDim>
     253           0 : struct InternalDirectionsCompute : InternalDirections<VolumeDim>,
     254             :                                    db::ComputeTag {
     255           0 :   static constexpr size_t volume_dim = VolumeDim;
     256           0 :   using base = InternalDirections<VolumeDim>;
     257           0 :   using return_type = std::unordered_set<::Direction<VolumeDim>>;
     258           0 :   using argument_tags = tmpl::list<Element<VolumeDim>>;
     259           0 :   static void function(const gsl::not_null<return_type*> directions,
     260             :                        const ::Element<VolumeDim>& element) {
     261             :     for (const auto& direction_neighbors : element.neighbors()) {
     262             :       directions->insert(direction_neighbors.first);
     263             :     }
     264             :   }
     265             : };
     266             : /// @}
     267             : 
     268             : /// @{
     269             : /// \ingroup DataBoxTagsGroup
     270             : /// \ingroup ComputationalDomainGroup
     271             : /// The set of directions which correspond to external boundaries.
     272             : /// Used for representing data on the interior side of the external boundary
     273             : /// faces.
     274             : template <size_t VolumeDim>
     275           1 : struct BoundaryDirectionsInterior : db::SimpleTag {
     276           0 :   static constexpr size_t volume_dim = VolumeDim;
     277           0 :   using type = std::unordered_set<::Direction<VolumeDim>>;
     278             : };
     279             : 
     280             : template <size_t VolumeDim>
     281           0 : struct BoundaryDirectionsInteriorCompute
     282             :     : BoundaryDirectionsInterior<VolumeDim>,
     283             :       db::ComputeTag {
     284           0 :   static constexpr size_t volume_dim = VolumeDim;
     285           0 :   using base = BoundaryDirectionsInterior<VolumeDim>;
     286           0 :   using return_type = std::unordered_set<::Direction<VolumeDim>>;
     287           0 :   using argument_tags = tmpl::list<Element<VolumeDim>>;
     288           0 :   static void function(const gsl::not_null<return_type*> directions,
     289             :                        const ::Element<VolumeDim>& element) {
     290             :     *directions = element.external_boundaries();
     291             :   }
     292             : };
     293             : /// @}
     294             : 
     295             : /// @{
     296             : /// \ingroup DataBoxTagsGroup
     297             : /// \ingroup ComputationalDomainGroup
     298             : /// The set of directions which correspond to external boundaries. To be used
     299             : /// to represent data which exists on the exterior side of the external boundary
     300             : /// faces.
     301             : template <size_t VolumeDim>
     302           1 : struct BoundaryDirectionsExterior : db::SimpleTag {
     303           0 :   static constexpr size_t volume_dim = VolumeDim;
     304           0 :   using type = std::unordered_set<::Direction<VolumeDim>>;
     305             : };
     306             : 
     307             : template <size_t VolumeDim>
     308           0 : struct BoundaryDirectionsExteriorCompute
     309             :     : BoundaryDirectionsExterior<VolumeDim>,
     310             :       db::ComputeTag {
     311           0 :   static constexpr size_t volume_dim = VolumeDim;
     312           0 :   using base = BoundaryDirectionsExterior<VolumeDim>;
     313           0 :   using return_type = std::unordered_set<::Direction<VolumeDim>>;
     314           0 :   using argument_tags = tmpl::list<Element<VolumeDim>>;
     315           0 :   static constexpr auto function(const gsl::not_null<return_type*> directions,
     316             :                                  const ::Element<VolumeDim>& element) {
     317             :     *directions = element.external_boundaries();
     318             :   }
     319             : };
     320             : /// @}
     321             : 
     322             : /// \ingroup DataBoxTagsGroup
     323             : /// \ingroup ComputationalDomainGroup
     324             : /// \brief Tag which is either a SimpleTag for quantities on an
     325             : /// interface, base tag to a compute item which acts on tags on an interface, or
     326             : /// base tag to a compute item which slices a tag from the volume to an
     327             : /// interface.
     328             : ///
     329             : /// The contained object will be a map from ::Direction to the item type of
     330             : /// `Tag`, with the set of directions being those produced by `DirectionsTag`.
     331             : ///
     332             : /// If a SimpleTag is desired on the interface, then this tag can be added to
     333             : /// the DataBox directly. If a ComputeTag which acts on Tags on the interface is
     334             : /// desired, then the tag should be added using `InterfaceCompute`. If a
     335             : /// ComputeTag which slices a TensorTag or a VariablesTag in the volume to an
     336             : /// Interface is desired, then it should be added using `Slice`. In all cases,
     337             : /// the tag can then be retrieved using `Tags::Interface<DirectionsTag, Tag>`.
     338             : ///
     339             : /// \tparam DirectionsTag the item of directions
     340             : /// \tparam Tag the tag labeling the item
     341             : ///
     342             : /// \see InterfaceCompute, Slice
     343             : template <typename DirectionsTag, typename Tag>
     344           1 : struct Interface : db::SimpleTag {
     345             :   static_assert(db::is_simple_tag_v<DirectionsTag>);
     346             :   static_assert(db::is_simple_tag_v<Tag>);
     347           0 :   static std::string name() {
     348             :     return "Interface<" + db::tag_name<DirectionsTag>() + ", " +
     349             :            db::tag_name<Tag>() + ">";
     350             :   };
     351           0 :   using tag = Tag;
     352           0 :   using type = std::unordered_map<::Direction<DirectionsTag::volume_dim>,
     353             :                                   typename Tag::type>;
     354             : };
     355             : 
     356             : /// \ingroup DataBoxTagsGroup
     357             : /// \ingroup ComputationalDomainGroup
     358             : /// ::Direction to an interface
     359             : template <size_t VolumeDim>
     360           1 : struct Direction : db::SimpleTag {
     361           0 :   using type = ::Direction<VolumeDim>;
     362             : };
     363             : 
     364             : }  // namespace Tags
     365             : }  // namespace domain
     366             : 
     367             : namespace db {
     368             : namespace detail {
     369             : template <typename DirectionsTag, typename VariablesTag>
     370             : struct InterfaceSubitemsImpl {
     371             :   using type = tmpl::transform<
     372             :       typename VariablesTag::type::tags_list,
     373             :       tmpl::bind<domain::Tags::Interface, tmpl::pin<DirectionsTag>, tmpl::_1>>;
     374             : 
     375             :   using tag = domain::Tags::Interface<DirectionsTag, VariablesTag>;
     376             : 
     377             :   template <typename Subtag>
     378             :   static void create_item(
     379             :       const gsl::not_null<typename tag::type*> parent_value,
     380             :       const gsl::not_null<typename Subtag::type*> sub_value) {
     381             :     sub_value->clear();
     382             :     for (auto& direction_vars : *parent_value) {
     383             :       const auto& direction = direction_vars.first;
     384             :       auto& parent_vars = get<typename Subtag::tag>(direction_vars.second);
     385             :       auto& sub_var = (*sub_value)[direction];
     386             :       for (auto vars_it = parent_vars.begin(), sub_var_it = sub_var.begin();
     387             :            vars_it != parent_vars.end(); ++vars_it, ++sub_var_it) {
     388             :         sub_var_it->set_data_ref(&*vars_it);
     389             :       }
     390             :     }
     391             :   }
     392             : 
     393             :   // The `return_type` can be anything for Subitems because the DataBox figures
     394             :   // out the correct return type, we just use the `return_type` type alias to
     395             :   // signal to the DataBox we want mutating behavior.
     396             :   using return_type = NoSuchType;
     397             : 
     398             :   template <typename Subtag>
     399             :   static void create_compute_item(
     400             :       const gsl::not_null<typename Subtag::type*> sub_value,
     401             :       const typename tag::type& parent_value) {
     402             :     for (const auto& direction_vars : parent_value) {
     403             :       const auto& direction = direction_vars.first;
     404             :       const auto& parent_vars =
     405             :           get<typename Subtag::tag>(direction_vars.second);
     406             :       auto& sub_var = (*sub_value)[direction];
     407             :       auto sub_var_it = sub_var.begin();
     408             :       for (auto vars_it = parent_vars.begin();
     409             :            vars_it != parent_vars.end(); ++vars_it, ++sub_var_it) {
     410             :         // clang-tidy: do not use const_cast
     411             :         // The DataBox will only give out a const reference to the
     412             :         // result of a compute item.  Here, that is a reference to a
     413             :         // const map to Tensors of DataVectors.  There is no (publicly
     414             :         // visible) indirection there, so having the map const will
     415             :         // allow only allow const access to the contained DataVectors,
     416             :         // so no modification through the pointer cast here is
     417             :         // possible.
     418             :         sub_var_it->set_data_ref(const_cast<DataVector*>(&*vars_it));  // NOLINT
     419             :       }
     420             :     }
     421             :   }
     422             : };
     423             : }  // namespace detail
     424             : 
     425             : template <typename DirectionsTag, typename VariablesTag>
     426           0 : struct Subitems<domain::Tags::Interface<DirectionsTag, VariablesTag>,
     427             :                 Requires<tt::is_a_v<Variables, typename VariablesTag::type>>>
     428             :     : detail::InterfaceSubitemsImpl<DirectionsTag, VariablesTag> {};
     429             : 
     430             : }  // namespace db

Generated by: LCOV version 1.14