SpECTRE Documentation Coverage Report
Current view: top level - DataStructures/DataBox - ObservationBox.hpp Hit Total Coverage
Commit: 664546099c4dbf27a1b708fac45e39c82dd743d2 Lines: 12 25 48.0 %
Date: 2024-04-19 16:28:01
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             :   /// Retrieve the underlying DataBox.
      71           1 :   DataBoxType& databox() { return *databox_; }
      72             : 
      73             :   /// Reset all the compute items, forcing reevaluation.
      74           1 :   void reset();
      75             : 
      76             :  private:
      77             :   template <typename Tag>
      78           0 :   const auto& get_item() const {
      79             :     return static_cast<const db::detail::Item<Tag>&>(*this);
      80             :   }
      81             : 
      82             :   template <typename ComputeTag, typename... ArgumentTags>
      83           0 :   void evaluate_compute_item(tmpl::list<ArgumentTags...> /*meta*/) const;
      84             : 
      85             :   template <typename ReferenceTag, typename... ArgumentTags>
      86           0 :   const auto& get_reference_item(tmpl::list<ArgumentTags...> /*meta*/) const;
      87             : 
      88           0 :   gsl::not_null<DataBoxType*> databox_;
      89             : };
      90             : 
      91             : /*!
      92             :  * \ingroup DataStructuresGroup
      93             :  * \brief Retrieve a `Tag` from the `ObservationBox`.
      94             :  */
      95             : template <typename Tag, typename DataBoxType, typename... ComputeTags>
      96           1 : const auto& get(
      97             :     const ObservationBox<tmpl::list<ComputeTags...>, DataBoxType>& box) {
      98             :   return box.template get<Tag>();
      99             : }
     100             : 
     101             : /// \cond
     102             : template <typename DataBoxType, typename... ComputeTags>
     103             : ObservationBox<tmpl::list<ComputeTags...>, DataBoxType>::ObservationBox(
     104             :     const gsl::not_null<DataBoxType*> databox)
     105             :     : databox_(databox) {
     106             :   DEBUG_STATIC_ASSERT(
     107             :       (db::is_immutable_item_tag_v<ComputeTags> and ...),
     108             :       "All tags passed to ObservationBox must be compute tags.");
     109             : }
     110             : /// \endcond
     111             : 
     112             : template <typename DataBoxType, typename... ComputeTags>
     113             : template <typename Tag>
     114             : const auto& ObservationBox<tmpl::list<ComputeTags...>, DataBoxType>::get()
     115             :     const {
     116             :   if constexpr (std::is_same_v<Tag, ::Tags::DataBox>) {
     117             :     return *databox_;
     118             :   } else if constexpr (std::is_same_v<Tag, ::Tags::ObservationBox>) {
     119             :     return *this;
     120             :   } else {
     121             :     DEBUG_STATIC_ASSERT(
     122             :         not db::detail::has_no_matching_tag_v<tags_list, Tag>,
     123             :         "Found no tags in the ObservationBox that match the tag "
     124             :         "being retrieved.");
     125             :     DEBUG_STATIC_ASSERT(
     126             :         db::detail::has_unique_matching_tag_v<tags_list, Tag>,
     127             :         "Found more than one tag in the ObservationBox that matches the tag "
     128             :         "being retrieved. This happens because more than one tag with the same "
     129             :         "base (class) tag was added to the ObservationBox, or because you add "
     130             :         "a compute tag that is already in the DataBox.");
     131             : 
     132             :     if constexpr (db::tag_is_retrievable_v<Tag, DataBoxType>) {
     133             :       return db::get<Tag>(*databox_);
     134             :     } else {
     135             :       using item_tag = db::detail::first_matching_tag<compute_item_tags, Tag>;
     136             :       if constexpr (db::detail::Item<item_tag>::item_type ==
     137             :                     db::detail::ItemType::Reference) {
     138             :         return get_reference_item<item_tag>(typename item_tag::argument_tags{});
     139             :       } else {
     140             :         if (not get_item<item_tag>().evaluated()) {
     141             :           evaluate_compute_item<item_tag>(typename item_tag::argument_tags{});
     142             :         }
     143             :         if constexpr (tt::is_a_v<std::unique_ptr, typename item_tag::type>) {
     144             :           return *(get_item<item_tag>().get());
     145             :         } else {
     146             :           return get_item<item_tag>().get();
     147             :         }
     148             :       }
     149             :     }
     150             :   }
     151             : }
     152             : 
     153             : template <typename DataBoxType, typename... ComputeTags>
     154             : void ObservationBox<tmpl::list<ComputeTags...>, DataBoxType>::reset() {
     155             :   tmpl::for_each<
     156             :       tmpl::filter<tmpl::list<ComputeTags...>, db::is_compute_tag<tmpl::_1>>>(
     157             :       [this](auto tag) {
     158             :         static_cast<db::detail::Item<tmpl::type_from<decltype(tag)>>&>(*this)
     159             :             .reset();
     160             :       });
     161             : }
     162             : 
     163             : template <typename DataBoxType, typename... ComputeTags>
     164             : template <typename ComputeTag, typename... ArgumentTags>
     165             : void ObservationBox<tmpl::list<ComputeTags...>, DataBoxType>::
     166             :     evaluate_compute_item(tmpl::list<ArgumentTags...> /*meta*/) const {
     167             :   get_item<ComputeTag>().evaluate(get<ArgumentTags>()...);
     168             : }
     169             : 
     170             : template <typename DataBoxType, typename... ComputeTags>
     171             : template <typename ReferenceTag, typename... ArgumentTags>
     172             : const auto&
     173             : ObservationBox<tmpl::list<ComputeTags...>, DataBoxType>::get_reference_item(
     174             :     tmpl::list<ArgumentTags...> /*meta*/) const {
     175             :   return ReferenceTag::get(get<ArgumentTags>()...);
     176             : }
     177             : 
     178             : template <typename ComputeTagsList, typename DataBoxType>
     179           0 : auto make_observation_box(const gsl::not_null<DataBoxType*> databox) {
     180             :   return ObservationBox<db::detail::expand_subitems<ComputeTagsList>,
     181             :                         DataBoxType>{databox};
     182             : }
     183             : 
     184             : namespace observation_box_detail {
     185             : template <typename DataBoxType, typename ComputeTagsList, typename... Args,
     186             :           typename F, typename... ArgumentTags>
     187             : auto apply(F&& f, tmpl::list<ArgumentTags...> /*meta*/,
     188             :            const ObservationBox<ComputeTagsList, DataBoxType>& observation_box,
     189             :            Args&&... args) {
     190             :   if constexpr (db::detail::is_apply_callable_v<
     191             :                     F,
     192             :                     std::decay_t<decltype(
     193             :                         get<ArgumentTags>(observation_box))>...,
     194             :                     Args...>) {
     195             :     return std::decay_t<F>::apply(get<ArgumentTags>(observation_box)...,
     196             :                     std::forward<Args>(args)...);
     197             :   } else if constexpr (::tt::is_callable_v<
     198             :                  F,
     199             :                  std::decay_t<decltype(get<ArgumentTags>(observation_box))>...,
     200             :                  Args...>) {
     201             :     return std::forward<F>(f)(get<ArgumentTags>(observation_box)...,
     202             :                               std::forward<Args>(args)...);
     203             :   } else {
     204             :     db::detail::error_function_not_callable<
     205             :         F, std::decay_t<decltype(get<ArgumentTags>(observation_box))>...,
     206             :         Args...>();
     207             :   }
     208             : }
     209             : 
     210             : template <typename DataBoxType, typename ComputeTagsList, typename... Args,
     211             :           typename F, typename... ReturnTags, typename... ArgumentTags>
     212             : decltype(auto) mutate_apply(
     213             :     F&& f, tmpl::list<ReturnTags...> /*meta*/,
     214             :     tmpl::list<ArgumentTags...> /*meta*/,
     215             :     const gsl::not_null<ObservationBox<ComputeTagsList, DataBoxType>*>
     216             :         observation_box,
     217             :     Args&&... args) {
     218             :   const CleanupRoutine reset_items = [&]() {
     219             :     if constexpr (sizeof...(ReturnTags) != 0) {
     220             :       // Not ideal, but doing a more granular reset is not worth the
     221             :       // trouble.
     222             :       observation_box->reset();
     223             :     }
     224             :   };
     225             :   return db::mutate_apply<tmpl::list<ReturnTags...>, tmpl::list<>>(
     226             :       f, make_not_null(&observation_box->databox()),
     227             :       get<ArgumentTags>(*observation_box)..., std::forward<Args>(args)...);
     228             : }
     229             : }  // namespace observation_box_detail
     230             : 
     231             : /*!
     232             :  * \ingroup DataStructuresGroup
     233             :  * \brief Apply the function object `f` using its nested `argument_tags` list of
     234             :  * tags.
     235             :  */
     236             : template <typename DataBoxType, typename ComputeTagsList, typename... Args,
     237             :           typename F>
     238           1 : auto apply(F&& f,
     239             :            const ObservationBox<ComputeTagsList, DataBoxType>& observation_box,
     240             :            Args&&... args) {
     241             :   return observation_box_detail::apply(
     242             :       std::forward<F>(f), typename std::decay_t<F>::argument_tags{},
     243             :       observation_box, std::forward<Args>(args)...);
     244             : }
     245             : 
     246             : /*!
     247             :  * \ingroup DataStructuresGroup
     248             :  * \brief Apply the function object `f` using its nested `return_tags`
     249             :  * and `argument_tags` list of tags.  Modifications are made to the
     250             :  * underlying DataBox.
     251             :  */
     252             : /// @{
     253             : template <typename DataBoxType, typename ComputeTagsList, typename... Args,
     254             :           typename F>
     255           1 : auto mutate_apply(
     256             :     F&& f,
     257             :     const gsl::not_null<ObservationBox<ComputeTagsList, DataBoxType>*>
     258             :         observation_box,
     259             :     Args&&... args) {
     260             :   return observation_box_detail::mutate_apply(
     261             :       std::forward<F>(f), typename std::decay_t<F>::return_tags{},
     262             :       typename std::decay_t<F>::argument_tags{}, observation_box,
     263             :       std::forward<Args>(args)...);
     264             : }
     265             : 
     266             : template <typename ReturnTags, typename ArgumentTags, typename DataBoxType,
     267             :           typename ComputeTagsList, typename... Args, typename F>
     268           1 : auto mutate_apply(
     269             :     F&& f,
     270             :     const gsl::not_null<ObservationBox<ComputeTagsList, DataBoxType>*>
     271             :         observation_box,
     272             :     Args&&... args) {
     273             :   return observation_box_detail::mutate_apply(std::forward<F>(f), ReturnTags{},
     274             :                                               ArgumentTags{}, observation_box,
     275             :                                               std::forward<Args>(args)...);
     276             : }
     277             : /// @}

Generated by: LCOV version 1.14