SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/SpinWeightedSphericalHarmonics - ComplexDataView.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 33.3 % 3 1
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 <complex>
       7              : #include <cstddef>
       8              : 
       9              : #include "DataStructures/ComplexDataVector.hpp"
      10              : #include "DataStructures/DataVector.hpp"
      11              : #include "Utilities/Gsl.hpp"
      12              : 
      13              : namespace Spectral {
      14              : /// \ingroup SpectralGroup
      15              : /// Namespace for spin-weighted spherical harmonic utilities.
      16            1 : namespace Swsh {
      17              : 
      18              : /// \brief A set of labels for the possible representations of complex numbers
      19              : /// for the `ComplexDataView` and the computations performed in the
      20              : /// spin-weighted spherical harmonic transform library.
      21              : ///
      22              : /// \details The representation describes one of two behaviors:
      23              : ///  - `Interleaved`: The vectors of complex numbers will be represented by
      24              : ///  alternating doubles in memory. This causes both the real and imaginary part
      25              : ///  at a given gridpoint to be near one another, but successive real values
      26              : ///  farther. This is the native representation of complex data in the C++
      27              : ///  standard, and is the representation needed for Blaze math
      28              : ///  operations. Therefore, using this representation type in libsharp
      29              : ///  computations will cause operations which access only the real or imaginary
      30              : ///  parts individually to trace over larger memory regions. However, this
      31              : ///  representation will give rise to fewer copying operations to perform the
      32              : ///  libsharp operations.
      33              : ///
      34              : ///  - `RealsThenImags`: The vectors of complex numbers will primarily be
      35              : ///  represented by a pair of vectors of doubles, one for the real values and
      36              : ///  one for the imaginary values (the full computation cannot be performed
      37              : ///  exclusively in this representation, as it must return to a vector of
      38              : ///  `std::complex<double>` for Blaze math operations). This causes the
      39              : ///  successive real values for different gridpoints to be closer in memory, but
      40              : ///  the real and imaginary parts for a given gridpoint to be farther in
      41              : ///  memory. This is not the native representation for complex data in C++, so
      42              : ///  the data must be transformed between operations which use Blaze and the
      43              : ///  transform operations which use `RealsThenImags`. Therefore, using this
      44              : ///  representation in libsharp computations will cause operations which act on
      45              : ///  real or imaginary parts individually to have better memory locality (so
      46              : ///  likely improved cache performance, but such statements are highly
      47              : ///  hardware-dependent). However, this representation will give rise to more
      48              : ///  copying operations to perform the libsharp operations.
      49              : ///
      50              : /// \note The pair of representations is provided as a means to 'turn a dial' in
      51              : /// optimizations. It is unclear which of these representations will be
      52              : /// preferable, and it may well be the case that different representations are
      53              : /// better for different calculation types or different hardware. Therefore,
      54              : /// when optimizing code which uses libsharp, it is encouraged to profile the
      55              : /// cost of each representation for a computation and choose the one which
      56              : /// performs best.
      57            0 : enum class ComplexRepresentation { Interleaved, RealsThenImags };
      58              : 
      59              : namespace detail {
      60              : // A storage container for storing sub-vector references ("views") of a
      61              : // ComplexDataVector.
      62              : //
      63              : // This class takes as a template argument a ComplexRepresentation to use when
      64              : // returning pointers to the components of the complex data. The representation
      65              : // is either:
      66              : // - `ComplexRepresentation::Interleaved`, which indicates that the complex data
      67              : // is represented as a vector of `std::complex<double>`, and then
      68              : // ComplexDataView acts as a view (a pure reference to a subvector).
      69              : // - `ComplexRepresentation::RealsThenImags`, which indicates that the complex
      70              : // data is represented as a pair of vectors of `double`. This is no longer a
      71              : // strict view in the typical sense, as the memory layout is different from
      72              : // the data which it references. In order to minimize copies, the user must
      73              : // specify when edits to the ComplexDataView are complete by calling the
      74              : // `copy_back_to_source()` member function.
      75              : //
      76              : // Warning: For optimization reasons, mutations applied via member functions or
      77              : // manipulations of data pointed to by pointers returned by member functions
      78              : // *may or may not* be immediately applied to the source vector used to
      79              : // construct the ComplexDataView. Correct use of this class will first perform
      80              : // (potentially several) manipulations of the data via the ComplexDataView, then
      81              : // as a final step flush the data to the source vector via the member function
      82              : // `copy_back_to_source()`. At that point, the vector is guaranteed to be
      83              : // placed in the same state as the ComplexDataView. **The process of
      84              : // constructing a ComplexDataView, then mutating data in both the
      85              : // ComplexDataView and the source vector, then calling `copy_back_to_source()`
      86              : // is considered undefined behavior, and depends on the details of the memory
      87              : // layout chosen.**
      88              : template <ComplexRepresentation Representation>
      89              : class ComplexDataView {
      90              :  public:
      91              :   // The Representation determines the internal data representation
      92              :   static const ComplexRepresentation complex_representation = Representation;
      93              : 
      94              :   // The internal storage type
      95              :   using value_type = std::complex<double>;
      96              : 
      97              :   // Construct a view which starts at index `offset` of the supplied
      98              :   // vector, and extends for `size` elements
      99              :   ComplexDataView(gsl::not_null<ComplexDataVector*> vector, size_t size,
     100              :                   size_t offset = 0);
     101              : 
     102              :   // Construct a view which starts at pointer `start` and extends for
     103              :   // `size` elements. Need not be a part of a ComplexDataVector.
     104              :   ComplexDataView(std::complex<double>* start, size_t size);
     105              : 
     106              :   // For the lifetime of the data view, it points to the same portion of a
     107              :   // single vector. We disallow default move assignment, as it would exhibit
     108              :   // behavior that would contradict that. All assignment operations permitted by
     109              :   // the ComplexDataView are copying operations which act only on the data, not
     110              :   // the reference.
     111              :   ComplexDataView() = delete;
     112              :   ComplexDataView(const ComplexDataView&) = default;
     113              :   ComplexDataView(ComplexDataView&&) = default;
     114              :   ComplexDataView operator=(ComplexDataView&&) = delete;
     115              :   ~ComplexDataView() = default;
     116              : 
     117              :   // assign into the view the values of a same-sized ComplexDataVector
     118              :   ComplexDataView<Representation>& operator=(const ComplexDataVector& vector);
     119              : 
     120              :   // Assign into the view the values from a same-sized view
     121              :   ComplexDataView<Representation>& operator=(
     122              :       const ComplexDataView<Representation>& view);
     123              : 
     124              :   // Conjugate the data.
     125              :   void conjugate();
     126              : 
     127              :   // Assign into the real components of a view the values from a
     128              :   // provided `DataVector`
     129              :   ComplexDataView<Representation>& assign_real(const DataVector& vector);
     130              : 
     131              :   // Assign into the imaginary components of a view the values from a
     132              :   // provided `DataVector`
     133              :   ComplexDataView<Representation>& assign_imag(const DataVector& vector);
     134              : 
     135              :   // Gets the size of the view (the number of complex entries).
     136              :   size_t size() const { return size_; }
     137              : 
     138              :   // Gets the stride between successive real or successive imaginary components
     139              :   // in memory.
     140              :   static constexpr size_t stride() { return stride_; }
     141              : 
     142              :   // Gets the raw pointer to the start of the real data, which are separated
     143              :   // from one another by `stride()`.
     144              :   double* real_data();
     145              :   const double* real_data() const;
     146              : 
     147              :   // Gets the raw pointer to the start of the imaginary data, which are
     148              :   // separated from one another by `stride()`.
     149              :   double* imag_data();
     150              :   const double* imag_data() const;
     151              : 
     152              :   // A function for manually flushing the data back to the source. This class
     153              :   // minimizes copies wherever possible, so the manual control of bringing the
     154              :   // data back to the source vector only when necessary is important for
     155              :   // optimization.
     156              :   // Warning: Until this function is called, mutations applied via other member
     157              :   // functions or mutations applied via the pointers obtained from other member
     158              :   // functions are not guaranteed to be applied to the source vector.
     159              :   void copy_back_to_source();
     160              : 
     161              :  private:
     162              :   size_t size_;
     163              : 
     164              :   static const size_t stride_ =
     165              :       Representation == ComplexRepresentation::RealsThenImags ? 1 : 2;
     166              : 
     167              :   // In either case, we want to avoid unnecessary copies, so we track whether
     168              :   // the data has been copied from one representation to the other.
     169              :   bool real_slices_up_to_date_;
     170              :   // These two DataVectors are unused in the case of `Interleaved`
     171              :   // representation
     172              :   DataVector real_slice_;
     173              :   DataVector imag_slice_;
     174              : 
     175              :   double* data_real_;
     176              :   double* data_imag_;
     177              : 
     178              :   ComplexDataVector complex_view_;
     179              : };
     180              : 
     181              : }  // namespace detail
     182              : }  // namespace Swsh
     183              : }  // namespace Spectral
        

Generated by: LCOV version 2.0-1