SpECTRE Documentation Coverage Report
Current view: top level - DataStructures/DataBox - ObservationBox.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 50.0 % 26 13
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 "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 2.0-1