SpECTRE Documentation Coverage Report
Current view: top level - Evolution/DiscontinuousGalerkin - AtomicInboxBoundaryData.hpp Hit Total Coverage
Commit: f23e75c235cae5144b8ac7ce01280be5b8cd2c8a Lines: 4 16 25.0 %
Date: 2024-09-07 06:21:00
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 <atomic>
       7             : #include <cstddef>
       8             : 
       9             : #include "Domain/Structure/MaxNumberOfNeighbors.hpp"
      10             : #include "Evolution/DiscontinuousGalerkin/BoundaryData.hpp"
      11             : #include "Parallel/StaticSpscQueue.hpp"
      12             : #include "Time/TimeStepId.hpp"
      13             : 
      14             : /// \cond
      15             : template <size_t Dim>
      16             : struct DirectionalId;
      17             : /// \endcond
      18             : 
      19             : namespace evolution::dg {
      20             : /*!
      21             :  * \brief Holds the data in the different directions for the nodegroup
      22             :  * `DgElementArray` implementation.
      23             :  *
      24             :  * The reason for this class is to reduce contention between cores and to
      25             :  * allow the use of a Single-Producer-Single-Consumer (SPSC) queue instead of
      26             :  * an MPMC queue. This has significant performance improvements since it
      27             :  * drastically reduces contention.
      28             :  *
      29             :  * The uint message counter is used to count how many neighbors have contributed
      30             :  * for the next time. This is used to delay calling `perform_algorithm()` in
      31             :  * order to reduce the number of messages we send through the runtime
      32             :  * system. The `number_of_neighbors` is used to track the number of expected
      33             :  * messages. Note that some additional logic is needed also for supporting
      34             :  * local time stepping, since not every message entry "counts" since it
      35             :  * depends on the time level of neighboring elements.
      36             :  *
      37             :  * \warning Only `AtomicInboxBoundaryData` with zero messages can be move
      38             :  * constructed. A non-zero number of neighbors is allowed. This is necessary
      39             :  * in order to be able to serialize a
      40             :  * `std::unordered_map<Key,AtomicInboxBoundaryData>`.
      41             :  */
      42             : template <size_t Dim>
      43           1 : struct AtomicInboxBoundaryData {
      44           0 :   using stored_type = evolution::dg::BoundaryData<Dim>;
      45           0 :   AtomicInboxBoundaryData() = default;
      46           0 :   AtomicInboxBoundaryData(const AtomicInboxBoundaryData&) = delete;
      47           0 :   AtomicInboxBoundaryData& operator=(const AtomicInboxBoundaryData&) = delete;
      48           0 :   AtomicInboxBoundaryData(AtomicInboxBoundaryData&& rhs) noexcept;
      49           0 :   AtomicInboxBoundaryData& operator=(AtomicInboxBoundaryData&&) noexcept =
      50             :       delete;
      51           0 :   ~AtomicInboxBoundaryData() = default;
      52             : 
      53             :   /*!
      54             :    * Computes the 1d index into the `boundary_data_in_directions` array
      55             :    * for a specific `directional_id` that has been re-oriented using the
      56             :    * `OrientationMap` to be put in the same block frame as the element that is
      57             :    * receiving the data (i.e. that whose inbox this is being inserted into).
      58             :    *
      59             :    * The hash is computed as
      60             :    * \f{align}{
      61             :    * 2^D d + 2^{D-1} s + e
      62             :    * \f}
      63             :    * where \f$D\f$ is the number of spatial dimensions, \f$d\f$ is the logical
      64             :    * dimension of the direction to the neighbor from the element whose inbox
      65             :    * this is, \f$s\f$ is the side in the logical dimension \f$d\f$ with a value
      66             :    * of 1 for upper and 0 for lower, and \f$e\f$ is a hash of the index of the
      67             :    * `SegmentId`'s of the neighbor's `ElementId` for the dimensions other than
      68             :    * \f$d\f$. In particular: for \f$d=1\f$, \f$e\f$ is 0 (1) if
      69             :    * the `SegmentId` index along the face is even (odd); and for \f$d = 3\f$
      70             :    * \f$e\f$ is 0 (1, 2, 3) if the `SegmentId` indices along the face are both
      71             :    * even (lower dim odd, higher dim odd, both dims odd). The element segment
      72             :    * hash is computed as the logical `and` of the `SegmentID`'s index in that
      73             :    * direction, left shifted by which direction on the face it is.
      74             :    */
      75           1 :   static size_t index(const DirectionalId<Dim>& directional_id);
      76             : 
      77           0 :   void pup(PUP::er& p);
      78             : 
      79             :   // We use 20 entries in the SPSC under the assumption that each neighbor
      80             :   // will never insert more than 20 entries before the element uses
      81             :   // them. While in practice a smaller buffer could be used, this is to
      82             :   // safeguard against future features.
      83             :   std::array<Parallel::StaticSpscQueue<
      84             :                  std::tuple<::TimeStepId, stored_type, DirectionalId<Dim>>, 20>,
      85             :              maximum_number_of_neighbors(Dim)>
      86           0 :       boundary_data_in_directions{};
      87           0 :   std::atomic_uint message_count{};
      88           0 :   std::atomic_uint number_of_neighbors{};
      89             : };
      90             : 
      91             : /// \brief `std::true` if `T` is a `AtomicInboxBoundaryData`
      92             : template <typename T>
      93           1 : struct is_atomic_inbox_boundary_data : std::false_type {};
      94             : 
      95             : /// \cond
      96             : template <size_t Dim>
      97             : struct is_atomic_inbox_boundary_data<AtomicInboxBoundaryData<Dim>>
      98             :     : std::true_type {};
      99             : /// \endcond
     100             : 
     101             : /// \brief `true` if `T` is a `AtomicInboxBoundaryData`
     102             : template <typename T>
     103           1 : constexpr size_t is_atomic_inbox_boundary_data_v =
     104             :     is_atomic_inbox_boundary_data<T>::value;
     105             : }  // namespace evolution::dg

Generated by: LCOV version 1.14