SpECTRE Documentation Coverage Report
Current view: top level - Domain - Tags.hpp Hit Total Coverage
Commit: ecb8a275e1aebab77dcce48a5e098ed4e486ab4b Lines: 19 83 22.9 %
Date: 2026-08-22 01:05:40
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             :     if (source_coords.get(0).size() == 0) {
     108             :       // When subcell is not supported on an element due to topology, the
     109             :       // subcell mesh is
     110             :       // {0, Basis::Uninitialized, Quadrature::Uninitialized}. It is never
     111             :       // used, but the compute items still need to run
     112             :       return;
     113             :     }
     114             :     *target_coords = element_map(source_coords);
     115             :   }
     116             : };
     117             : 
     118             : /// \ingroup DataBoxTagsGroup
     119             : /// \ingroup ComputationalDomainGroup
     120             : /// \brief The inverse Jacobian from the source frame to the target frame.
     121             : ///
     122             : /// Specifically, \f$\partial x^{\bar{i}} / \partial x^i\f$, where \f$\bar{i}\f$
     123             : /// denotes the source frame and \f$i\f$ denotes the target frame.
     124             : template <size_t Dim, typename SourceFrame, typename TargetFrame>
     125           1 : struct InverseJacobian : db::SimpleTag {
     126           0 :   static std::string name() {
     127             :     return "InverseJacobian(" + get_output(SourceFrame{}) + "," +
     128             :            get_output(TargetFrame{}) + ")";
     129             :   }
     130           0 :   using type = ::InverseJacobian<DataVector, Dim, SourceFrame, TargetFrame>;
     131             : };
     132             : 
     133             : /// \ingroup DataBoxTagsGroup
     134             : /// \ingroup ComputationalDomainGroup
     135             : /// Computes the inverse Jacobian of the map held by `MapTag` at the coordinates
     136             : /// held by `SourceCoordsTag`. The coordinates must be in the source frame of
     137             : /// the map.
     138             : template <typename MapTag, typename SourceCoordsTag>
     139           1 : struct InverseJacobianCompute
     140             :     : InverseJacobian<MapTag::dim, typename MapTag::source_frame,
     141             :                       typename MapTag::target_frame>,
     142             :       db::ComputeTag {
     143           0 :   using base = InverseJacobian<MapTag::dim, typename MapTag::source_frame,
     144             :                                typename MapTag::target_frame>;
     145           0 :   using return_type = typename base::type;
     146           0 :   using argument_tags = tmpl::list<MapTag, SourceCoordsTag>;
     147           0 :   static constexpr auto function(
     148             :       const gsl::not_null<return_type*> inv_jacobian,
     149             :       const typename MapTag::type& element_map,
     150             :       const tnsr::I<DataVector, MapTag::dim, typename MapTag::source_frame>&
     151             :           source_coords) {
     152             :     *inv_jacobian = element_map.inv_jacobian(source_coords);
     153             :   }
     154             : };
     155             : 
     156             : /// \ingroup DataBoxTagsGroup
     157             : /// \ingroup ComputationalDomainGroup
     158             : /// \brief The Jacobian from the source frame to the target frame.
     159             : ///
     160             : /// Specifically, \f$\partial x^{i} / \partial \xi^{\bar{i}}\f$, where
     161             : /// \f$\xi^\bar{i}\f$ denotes the source frame and \f$x^i\f$ denotes the target
     162             : /// frame.
     163             : template <size_t Dim, typename SourceFrame, typename TargetFrame>
     164           1 : struct Jacobian : db::SimpleTag {
     165           0 :   static std::string name() {
     166             :     return "Jacobian(" + get_output(SourceFrame{}) + "," +
     167             :            get_output(TargetFrame{}) + ")";
     168             :   }
     169           0 :   using type = ::Jacobian<DataVector, Dim, SourceFrame, TargetFrame>;
     170             : };
     171             : 
     172             : /// \ingroup DataBoxTagsGroup
     173             : /// \ingroup ComputationalDomainGroup
     174             : /// Computes the Jacobian of the map from the `InverseJacobian<Dim, SourceFrame,
     175             : /// TargetFrame>` tag.
     176             : template <size_t Dim, typename SourceFrame, typename TargetFrame>
     177           1 : struct JacobianCompute : Jacobian<Dim, SourceFrame, TargetFrame>,
     178             :                          db::ComputeTag {
     179           0 :   using base = Jacobian<Dim, SourceFrame, TargetFrame>;
     180           0 :   using return_type = typename base::type;
     181           0 :   using argument_tags =
     182             :       tmpl::list<InverseJacobian<Dim, SourceFrame, TargetFrame>>;
     183           0 :   static constexpr auto function(
     184             :       const gsl::not_null<return_type*> jacobian,
     185             :       const ::InverseJacobian<DataVector, Dim, SourceFrame, TargetFrame>&
     186             :           inv_jac) {
     187             :     *jacobian = determinant_and_inverse(inv_jac).second;
     188             :   }
     189             : };
     190             : 
     191             : /// \ingroup DataBoxTagsGroup
     192             : /// \ingroup ComputationalDomainGroup
     193             : /// \brief The determinant of the inverse Jacobian from the source frame to the
     194             : /// target frame.
     195             : template <typename SourceFrame, typename TargetFrame>
     196           1 : struct DetInvJacobian : db::SimpleTag {
     197           0 :   using type = Scalar<DataVector>;
     198           0 :   static std::string name() {
     199             :     return "DetInvJacobian(" + get_output(SourceFrame{}) + "," +
     200             :            get_output(TargetFrame{}) + ")";
     201             :   }
     202             : };
     203             : 
     204             : /// \ingroup DataBoxTagsGroup
     205             : /// \ingroup ComputationalDomainGroup
     206             : /// Computes the determinant of the inverse Jacobian.
     207             : template <size_t Dim, typename SourceFrame, typename TargetFrame>
     208           1 : struct DetInvJacobianCompute : db::ComputeTag,
     209             :                                DetInvJacobian<SourceFrame, TargetFrame> {
     210           0 :   using base = DetInvJacobian<SourceFrame, TargetFrame>;
     211           0 :   using return_type = typename base::type;
     212           0 :   using argument_tags =
     213             :       tmpl::list<InverseJacobian<Dim, SourceFrame, TargetFrame>>;
     214           0 :   static void function(const gsl::not_null<return_type*> det_inv_jac,
     215             :                        const ::InverseJacobian<DataVector, Dim, SourceFrame,
     216             :                                                TargetFrame>& inv_jac) {
     217             :     determinant(det_inv_jac, inv_jac);
     218             :   }
     219             : };
     220             : 
     221             : /// \ingroup DataBoxTagsGroup
     222             : /// \ingroup ComputationalDomainGroup
     223             : /// \brief The determinant of the Jacobian from the source frame to the target
     224             : /// frame.
     225             : template <typename SourceFrame, typename TargetFrame>
     226           1 : struct DetJacobian : db::SimpleTag {
     227           0 :   using type = Scalar<DataVector>;
     228           0 :   static std::string name() {
     229             :     return "DetJacobian(" + get_output(SourceFrame{}) + "," +
     230             :            get_output(TargetFrame{}) + ")";
     231             :   }
     232             : };
     233             : 
     234             : /// \ingroup DataBoxTagsGroup
     235             : /// \ingroup ComputationalDomainGroup
     236             : /// \brief The inverse Jacobian times the determinant of the Jacobian.
     237             : ///
     238             : /// This quantity is divergence-free analytically. See
     239             : /// `::dg::metric_identity_det_jac_times_inv_jac` for more information.
     240             : template <size_t Dim, typename SourceFrame, typename TargetFrame>
     241           1 : struct DetTimesInvJacobian : db::SimpleTag {
     242           0 :   using type = ::InverseJacobian<DataVector, Dim, SourceFrame, TargetFrame>;
     243           0 :   static std::string name() {
     244             :     return "DetTimesInvJacobian(" + get_output(SourceFrame{}) + "," +
     245             :            get_output(TargetFrame{}) + ")";
     246             :   }
     247             : };
     248             : 
     249             : /// @{
     250             : /// \ingroup DataBoxTagsGroup
     251             : /// \ingroup ComputationalDomainGroup
     252             : /// The set of directions to neighboring Elements
     253             : template <size_t VolumeDim>
     254           1 : struct InternalDirections : db::SimpleTag {
     255           0 :   static constexpr size_t volume_dim = VolumeDim;
     256           0 :   using type = std::unordered_set<::Direction<VolumeDim>>;
     257             : };
     258             : 
     259             : template <size_t VolumeDim>
     260           0 : struct InternalDirectionsCompute : InternalDirections<VolumeDim>,
     261             :                                    db::ComputeTag {
     262           0 :   static constexpr size_t volume_dim = VolumeDim;
     263           0 :   using base = InternalDirections<VolumeDim>;
     264           0 :   using return_type = std::unordered_set<::Direction<VolumeDim>>;
     265           0 :   using argument_tags = tmpl::list<Element<VolumeDim>>;
     266           0 :   static void function(const gsl::not_null<return_type*> directions,
     267             :                        const ::Element<VolumeDim>& element) {
     268             :     for (const auto& direction_neighbors : element.neighbors()) {
     269             :       directions->insert(direction_neighbors.first);
     270             :     }
     271             :   }
     272             : };
     273             : /// @}
     274             : 
     275             : /// @{
     276             : /// \ingroup DataBoxTagsGroup
     277             : /// \ingroup ComputationalDomainGroup
     278             : /// The set of directions which correspond to external boundaries.
     279             : /// Used for representing data on the interior side of the external boundary
     280             : /// faces.
     281             : template <size_t VolumeDim>
     282           1 : struct BoundaryDirectionsInterior : db::SimpleTag {
     283           0 :   static constexpr size_t volume_dim = VolumeDim;
     284           0 :   using type = std::unordered_set<::Direction<VolumeDim>>;
     285             : };
     286             : 
     287             : template <size_t VolumeDim>
     288           0 : struct BoundaryDirectionsInteriorCompute
     289             :     : BoundaryDirectionsInterior<VolumeDim>,
     290             :       db::ComputeTag {
     291           0 :   static constexpr size_t volume_dim = VolumeDim;
     292           0 :   using base = BoundaryDirectionsInterior<VolumeDim>;
     293           0 :   using return_type = std::unordered_set<::Direction<VolumeDim>>;
     294           0 :   using argument_tags = tmpl::list<Element<VolumeDim>>;
     295           0 :   static void function(const gsl::not_null<return_type*> directions,
     296             :                        const ::Element<VolumeDim>& element) {
     297             :     *directions = element.external_boundaries();
     298             :   }
     299             : };
     300             : /// @}
     301             : 
     302             : /// @{
     303             : /// \ingroup DataBoxTagsGroup
     304             : /// \ingroup ComputationalDomainGroup
     305             : /// The set of directions which correspond to external boundaries. To be used
     306             : /// to represent data which exists on the exterior side of the external boundary
     307             : /// faces.
     308             : template <size_t VolumeDim>
     309           1 : struct BoundaryDirectionsExterior : db::SimpleTag {
     310           0 :   static constexpr size_t volume_dim = VolumeDim;
     311           0 :   using type = std::unordered_set<::Direction<VolumeDim>>;
     312             : };
     313             : 
     314             : template <size_t VolumeDim>
     315           0 : struct BoundaryDirectionsExteriorCompute
     316             :     : BoundaryDirectionsExterior<VolumeDim>,
     317             :       db::ComputeTag {
     318           0 :   static constexpr size_t volume_dim = VolumeDim;
     319           0 :   using base = BoundaryDirectionsExterior<VolumeDim>;
     320           0 :   using return_type = std::unordered_set<::Direction<VolumeDim>>;
     321           0 :   using argument_tags = tmpl::list<Element<VolumeDim>>;
     322           0 :   static constexpr auto function(const gsl::not_null<return_type*> directions,
     323             :                                  const ::Element<VolumeDim>& element) {
     324             :     *directions = element.external_boundaries();
     325             :   }
     326             : };
     327             : /// @}
     328             : 
     329             : /// \ingroup DataBoxTagsGroup
     330             : /// \ingroup ComputationalDomainGroup
     331             : /// \brief Tag which is either a SimpleTag for quantities on an
     332             : /// interface, base tag to a compute item which acts on tags on an interface, or
     333             : /// base tag to a compute item which slices a tag from the volume to an
     334             : /// interface.
     335             : ///
     336             : /// The contained object will be a map from ::Direction to the item type of
     337             : /// `Tag`, with the set of directions being those produced by `DirectionsTag`.
     338             : ///
     339             : /// If a SimpleTag is desired on the interface, then this tag can be added to
     340             : /// the DataBox directly. If a ComputeTag which acts on Tags on the interface is
     341             : /// desired, then the tag should be added using `InterfaceCompute`. If a
     342             : /// ComputeTag which slices a TensorTag or a VariablesTag in the volume to an
     343             : /// Interface is desired, then it should be added using `Slice`. In all cases,
     344             : /// the tag can then be retrieved using `Tags::Interface<DirectionsTag, Tag>`.
     345             : ///
     346             : /// \tparam DirectionsTag the item of directions
     347             : /// \tparam Tag the tag labeling the item
     348             : ///
     349             : /// \see InterfaceCompute, Slice
     350             : template <typename DirectionsTag, typename Tag>
     351           1 : struct Interface : db::SimpleTag {
     352             :   static_assert(db::is_simple_tag_v<DirectionsTag>);
     353             :   static_assert(db::is_simple_tag_v<Tag>);
     354           0 :   static std::string name() {
     355             :     return "Interface<" + db::tag_name<DirectionsTag>() + ", " +
     356             :            db::tag_name<Tag>() + ">";
     357             :   };
     358           0 :   using tag = Tag;
     359           0 :   using type = std::unordered_map<::Direction<DirectionsTag::volume_dim>,
     360             :                                   typename Tag::type>;
     361             : };
     362             : 
     363             : /// \ingroup DataBoxTagsGroup
     364             : /// \ingroup ComputationalDomainGroup
     365             : /// ::Direction to an interface
     366             : template <size_t VolumeDim>
     367           1 : struct Direction : db::SimpleTag {
     368           0 :   using type = ::Direction<VolumeDim>;
     369             : };
     370             : 
     371             : }  // namespace Tags
     372             : }  // namespace domain
     373             : 
     374             : namespace db {
     375             : namespace detail {
     376             : template <typename DirectionsTag, typename VariablesTag>
     377             : struct InterfaceSubitemsImpl {
     378             :   using type = tmpl::transform<
     379             :       typename VariablesTag::type::tags_list,
     380             :       tmpl::bind<domain::Tags::Interface, tmpl::pin<DirectionsTag>, tmpl::_1>>;
     381             : 
     382             :   using tag = domain::Tags::Interface<DirectionsTag, VariablesTag>;
     383             : 
     384             :   template <typename Subtag>
     385             :   static void create_item(
     386             :       const gsl::not_null<typename tag::type*> parent_value,
     387             :       const gsl::not_null<typename Subtag::type*> sub_value) {
     388             :     sub_value->clear();
     389             :     for (auto& direction_vars : *parent_value) {
     390             :       const auto& direction = direction_vars.first;
     391             :       auto& parent_vars = get<typename Subtag::tag>(direction_vars.second);
     392             :       auto& sub_var = (*sub_value)[direction];
     393             :       for (auto vars_it = parent_vars.begin(), sub_var_it = sub_var.begin();
     394             :            vars_it != parent_vars.end(); ++vars_it, ++sub_var_it) {
     395             :         sub_var_it->set_data_ref(&*vars_it);
     396             :       }
     397             :     }
     398             :   }
     399             : 
     400             :   // The `return_type` can be anything for Subitems because the DataBox figures
     401             :   // out the correct return type, we just use the `return_type` type alias to
     402             :   // signal to the DataBox we want mutating behavior.
     403             :   using return_type = NoSuchType;
     404             : 
     405             :   template <typename Subtag>
     406             :   static void create_compute_item(
     407             :       const gsl::not_null<typename Subtag::type*> sub_value,
     408             :       const typename tag::type& parent_value) {
     409             :     for (const auto& direction_vars : parent_value) {
     410             :       const auto& direction = direction_vars.first;
     411             :       const auto& parent_vars =
     412             :           get<typename Subtag::tag>(direction_vars.second);
     413             :       auto& sub_var = (*sub_value)[direction];
     414             :       auto sub_var_it = sub_var.begin();
     415             :       for (auto vars_it = parent_vars.begin();
     416             :            vars_it != parent_vars.end(); ++vars_it, ++sub_var_it) {
     417             :         // clang-tidy: do not use const_cast
     418             :         // The DataBox will only give out a const reference to the
     419             :         // result of a compute item.  Here, that is a reference to a
     420             :         // const map to Tensors of DataVectors.  There is no (publicly
     421             :         // visible) indirection there, so having the map const will
     422             :         // allow only allow const access to the contained DataVectors,
     423             :         // so no modification through the pointer cast here is
     424             :         // possible.
     425             :         sub_var_it->set_data_ref(const_cast<DataVector*>(&*vars_it));  // NOLINT
     426             :       }
     427             :     }
     428             :   }
     429             : };
     430             : }  // namespace detail
     431             : 
     432             : template <typename DirectionsTag, typename VariablesTag>
     433           0 : struct Subitems<domain::Tags::Interface<DirectionsTag, VariablesTag>,
     434             :                 Requires<tt::is_a_v<Variables, typename VariablesTag::type>>>
     435             :     : detail::InterfaceSubitemsImpl<DirectionsTag, VariablesTag> {};
     436             : 
     437             : }  // namespace db

Generated by: LCOV version 1.14