SpECTRE Documentation Coverage Report
Current view: top level - DataStructures/DataBox - ObservationBox.hpp Hit Total Coverage
Commit: 1f2210958b4f38fdc0400907ee7c6d5af5111418 Lines: 13 26 50.0 %
Date: 2025-12-05 05:03:31
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 "DataStructures/DataBox/DataBox.hpp"
       7             : #include "DataStructures/DataBox/Item.hpp"
       8             : #include "DataStructures/DataBox/TagTraits.hpp"
       9             : #include "Utilities/CleanupRoutine.hpp"
      10             : #include "Utilities/ErrorHandling/StaticAssert.hpp"
      11             : #include "Utilities/Gsl.hpp"
      12             : #include "Utilities/TMPL.hpp"
      13             : 
      14             : /// \cond
      15             : template <typename ComputeTagsList, typename DataBoxType>
      16             : class ObservationBox;
      17             : /// \endcond
      18             : 
      19             : namespace Tags {
      20             : /*!
      21             :  * \brief Tag used to retrieve the ObservationBox from the `get()` function
      22             :  *
      23             :  * The main use of this tag is to allow fetching the ObservationBox from itself.
      24             :  * The intended primary use case is for Events to be able to retrieve the
      25             :  * ObservationBox and then do runtime retrieval of tags to avoid computing
      26             :  * quantities that aren't needed.
      27             :  */
      28           1 : struct ObservationBox {
      29             :   // Trick to get friend function declaration to compile but a const
      30             :   // NoSuchtype****& is rather useless
      31           0 :   using type = NoSuchType****;
      32             : };
      33             : }  // namespace Tags
      34             : 
      35             : /*!
      36             :  * \ingroup DataStructuresGroup
      37             :  * \brief Used for adding compute items to a `DataBox` without copying or moving
      38             :  * any data from the original `DataBox`
      39             :  *
      40             :  * The intended use-case for this class is during IO/observing where additional
      41             :  * compute tags are needed only for observation. The memory used by those
      42             :  * compute tags does not need to be persistent and so we'd like a light-weight
      43             :  * class to handle the on-demand computation.
      44             :  */
      45             : template <typename DataBoxType, typename... ComputeTags>
      46           1 : class ObservationBox<tmpl::list<ComputeTags...>, DataBoxType>
      47             :     : private db::detail::Item<ComputeTags>... {
      48             :  public:
      49             :   /// A list of all the compute item tags
      50           1 :   using compute_item_tags = tmpl::list<ComputeTags...>;
      51             :   /// A list of all tags
      52           1 :   using tags_list =
      53             :       tmpl::push_back<typename DataBoxType::tags_list, ComputeTags...>;
      54             : 
      55           0 :   ObservationBox() = default;
      56           0 :   ObservationBox(const ObservationBox& rhs) = default;
      57           0 :   ObservationBox& operator=(const ObservationBox& rhs) = default;
      58           0 :   ObservationBox(ObservationBox&& rhs) = default;
      59           0 :   ObservationBox& operator=(ObservationBox&& rhs) = default;
      60           0 :   ~ObservationBox() = default;
      61             : 
      62             :   /// Create an `ObservationBox` that can also retrieve things out of the
      63             :   /// `databox` passed in.
      64           1 :   explicit ObservationBox(gsl::not_null<DataBoxType*> databox);
      65             : 
      66             :   /// Retrieve the tag `Tag`, should be called by the free function db::get
      67             :   template <typename Tag>
      68           1 :   const auto& get() const;
      69             : 
      70             :   /// @{
      71             :   /// Retrieve the underlying DataBox.
      72           1 :   DataBoxType& databox() { return *databox_; }
      73           1 :   const DataBoxType& databox() const { return *databox_; }
      74             :   /// @}
      75             : 
      76             :   /// Reset all the compute items, forcing reevaluation.
      77           1 :   void reset();
      78             : 
      79             :  private:
      80             :   template <typename Tag>
      81           0 :   const auto& get_item() const {
      82             :     return static_cast<const db::detail::Item<Tag>&>(*this);
      83             :   }
      84             : 
      85             :   template <typename ComputeTag, typename... ArgumentTags>
      86           0 :   void evaluate_compute_item(tmpl::list<ArgumentTags...> /*meta*/) const;
      87             : 
      88             :   template <typename ReferenceTag, typename... ArgumentTags>
      89           0 :   const auto& get_reference_item(tmpl::list<ArgumentTags...> /*meta*/) const;
      90             : 
      91           0 :   gsl::not_null<DataBoxType*> databox_;
      92             : };
      93             : 
      94             : /*!
      95             :  * \ingroup DataStructuresGroup
      96             :  * \brief Retrieve a `Tag` from the `ObservationBox`.
      97             :  */
      98             : template <typename Tag, typename DataBoxType, typename... ComputeTags>
      99           1 : const auto& get(
     100             :     const ObservationBox<tmpl::list<ComputeTags...>, DataBoxType>& box) {
     101             :   return box.template get<Tag>();
     102             : }
     103             : 
     104             : /// \cond
     105             : template <typename DataBoxType, typename... ComputeTags>
     106             : ObservationBox<tmpl::list<ComputeTags...>, DataBoxType>::ObservationBox(
     107             :     const gsl::not_null<DataBoxType*> databox)
     108             :     : databox_(databox) {
     109             :   DEBUG_STATIC_ASSERT(
     110             :       (db::is_immutable_item_tag_v<ComputeTags> and ...),
     111             :       "All tags passed to ObservationBox must be compute tags.");
     112             : }
     113             : /// \endcond
     114             : 
     115             : template <typename DataBoxType, typename... ComputeTags>
     116             : template <typename Tag>
     117             : const auto& ObservationBox<tmpl::list<ComputeTags...>, DataBoxType>::get()
     118             :     const {
     119             :   if constexpr (std::is_same_v<Tag, ::Tags::DataBox>) {
     120             :     return *databox_;
     121             :   } else if constexpr (std::is_same_v<Tag, ::Tags::ObservationBox>) {
     122             :     return *this;
     123             :   } else {
     124             :     DEBUG_STATIC_ASSERT(
     125             :         not db::detail::has_no_matching_tag_v<tags_list, Tag>,
     126             :         "Found no tags in the ObservationBox that match the tag "
     127             :         "being retrieved.");
     128             :     DEBUG_STATIC_ASSERT(
     129             :         db::detail::has_unique_matching_tag_v<tags_list, Tag>,
     130             :         "Found more than one tag in the ObservationBox that matches the tag "
     131             :         "being retrieved. This happens because more than one tag with the same "
     132             :         "base (class) tag was added to the ObservationBox, or because you add "
     133             :         "a compute tag that is already in the DataBox.");
     134             : 
     135             :     if constexpr (db::tag_is_retrievable_v<Tag, DataBoxType>) {
     136             :       return db::get<Tag>(*databox_);
     137             :     } else {
     138             :       using item_tag = db::detail::first_matching_tag<compute_item_tags, Tag>;
     139             :       if constexpr (db::detail::Item<item_tag>::item_type ==
     140             :                     db::detail::ItemType::Reference) {
     141             :         return get_reference_item<item_tag>(typename item_tag::argument_tags{});
     142             :       } else {
     143             :         if (not get_item<item_tag>().evaluated()) {
     144             :           evaluate_compute_item<item_tag>(typename item_tag::argument_tags{});
     145             :         }
     146             :         if constexpr (tt::is_a_v<std::unique_ptr, typename item_tag::type>) {
     147             :           return *(get_item<item_tag>().get());
     148             :         } else {
     149             :           return get_item<item_tag>().get();
     150             :         }
     151             :       }
     152             :     }
     153             :   }
     154             : }
     155             : 
     156             : template <typename DataBoxType, typename... ComputeTags>
     157             : void ObservationBox<tmpl::list<ComputeTags...>, DataBoxType>::reset() {
     158             :   tmpl::for_each<
     159             :       tmpl::filter<tmpl::list<ComputeTags...>, db::is_compute_tag<tmpl::_1>>>(
     160             :       [this](auto tag) {
     161             :         static_cast<db::detail::Item<tmpl::type_from<decltype(tag)>>&>(*this)
     162             :             .reset();
     163             :       });
     164             : }
     165             : 
     166             : template <typename DataBoxType, typename... ComputeTags>
     167             : template <typename ComputeTag, typename... ArgumentTags>
     168             : void ObservationBox<tmpl::list<ComputeTags...>, DataBoxType>::
     169             :     evaluate_compute_item(tmpl::list<ArgumentTags...> /*meta*/) const {
     170             :   get_item<ComputeTag>().evaluate(get<ArgumentTags>()...);
     171             : }
     172             : 
     173             : template <typename DataBoxType, typename... ComputeTags>
     174             : template <typename ReferenceTag, typename... ArgumentTags>
     175             : const auto&
     176             : ObservationBox<tmpl::list<ComputeTags...>, DataBoxType>::get_reference_item(
     177             :     tmpl::list<ArgumentTags...> /*meta*/) const {
     178             :   return ReferenceTag::get(get<ArgumentTags>()...);
     179             : }
     180             : 
     181             : template <typename ComputeTagsList, typename DataBoxType>
     182           0 : auto make_observation_box(const gsl::not_null<DataBoxType*> databox) {
     183             :   return ObservationBox<db::detail::expand_subitems<ComputeTagsList>,
     184             :                         DataBoxType>{databox};
     185             : }
     186             : 
     187             : namespace observation_box_detail {
     188             : template <typename DataBoxType, typename ComputeTagsList, typename... Args,
     189             :           typename F, typename... ArgumentTags>
     190             : auto apply(F&& f, tmpl::list<ArgumentTags...> /*meta*/,
     191             :            const ObservationBox<ComputeTagsList, DataBoxType>& observation_box,
     192             :            Args&&... args) {
     193             :   if constexpr (db::detail::is_apply_callable_v<
     194             :                     F,
     195             :                     std::decay_t<decltype(
     196             :                         get<ArgumentTags>(observation_box))>...,
     197             :                     Args...>) {
     198             :     return std::decay_t<F>::apply(get<ArgumentTags>(observation_box)...,
     199             :                     std::forward<Args>(args)...);
     200             :   } else if constexpr (::tt::is_callable_v<
     201             :                  F,
     202             :                  std::decay_t<decltype(get<ArgumentTags>(observation_box))>...,
     203             :                  Args...>) {
     204             :     return std::forward<F>(f)(get<ArgumentTags>(observation_box)...,
     205             :                               std::forward<Args>(args)...);
     206             :   } else {
     207             :     db::detail::error_function_not_callable<
     208             :         F, std::decay_t<decltype(get<ArgumentTags>(observation_box))>...,
     209             :         Args...>();
     210             :   }
     211             : }
     212             : 
     213             : template <typename DataBoxType, typename ComputeTagsList, typename... Args,
     214             :           typename F, typename... ReturnTags, typename... ArgumentTags>
     215             : decltype(auto) mutate_apply(
     216             :     F&& f, tmpl::list<ReturnTags...> /*meta*/,
     217             :     tmpl::list<ArgumentTags...> /*meta*/,
     218             :     const gsl::not_null<ObservationBox<ComputeTagsList, DataBoxType>*>
     219             :         observation_box,
     220             :     Args&&... args) {
     221             :   const CleanupRoutine reset_items = [&]() {
     222             :     if constexpr (sizeof...(ReturnTags) != 0) {
     223             :       // Not ideal, but doing a more granular reset is not worth the
     224             :       // trouble.
     225             :       observation_box->reset();
     226             :     }
     227             :   };
     228             :   return db::mutate_apply<tmpl::list<ReturnTags...>, tmpl::list<>>(
     229             :       f, make_not_null(&observation_box->databox()),
     230             :       get<ArgumentTags>(*observation_box)..., std::forward<Args>(args)...);
     231             : }
     232             : }  // namespace observation_box_detail
     233             : 
     234             : /*!
     235             :  * \ingroup DataStructuresGroup
     236             :  * \brief Apply the function object `f` using its nested `argument_tags` list of
     237             :  * tags.
     238             :  */
     239             : template <typename DataBoxType, typename ComputeTagsList, typename... Args,
     240             :           typename F>
     241           1 : auto apply(F&& f,
     242             :            const ObservationBox<ComputeTagsList, DataBoxType>& observation_box,
     243             :            Args&&... args) {
     244             :   return observation_box_detail::apply(
     245             :       std::forward<F>(f), typename std::decay_t<F>::argument_tags{},
     246             :       observation_box, std::forward<Args>(args)...);
     247             : }
     248             : 
     249             : /*!
     250             :  * \ingroup DataStructuresGroup
     251             :  * \brief Apply the function object `f` using its nested `return_tags`
     252             :  * and `argument_tags` list of tags.  Modifications are made to the
     253             :  * underlying DataBox.
     254             :  */
     255             : /// @{
     256             : template <typename DataBoxType, typename ComputeTagsList, typename... Args,
     257             :           typename F>
     258           1 : auto mutate_apply(
     259             :     F&& f,
     260             :     const gsl::not_null<ObservationBox<ComputeTagsList, DataBoxType>*>
     261             :         observation_box,
     262             :     Args&&... args) {
     263             :   return observation_box_detail::mutate_apply(
     264             :       std::forward<F>(f), typename std::decay_t<F>::return_tags{},
     265             :       typename std::decay_t<F>::argument_tags{}, observation_box,
     266             :       std::forward<Args>(args)...);
     267             : }
     268             : 
     269             : template <typename ReturnTags, typename ArgumentTags, typename DataBoxType,
     270             :           typename ComputeTagsList, typename... Args, typename F>
     271           1 : auto mutate_apply(
     272             :     F&& f,
     273             :     const gsl::not_null<ObservationBox<ComputeTagsList, DataBoxType>*>
     274             :         observation_box,
     275             :     Args&&... args) {
     276             :   return observation_box_detail::mutate_apply(std::forward<F>(f), ReturnTags{},
     277             :                                               ArgumentTags{}, observation_box,
     278             :                                               std::forward<Args>(args)...);
     279             : }
     280             : /// @}

Generated by: LCOV version 1.14