SpECTRE Documentation Coverage Report
Current view: top level - DataStructures/Tensor - Tensor.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 46.0 % 87 40
Test Date: 2026-10-22 17:29:42
Legend: Lines:     hit not hit

            Line data    Source code
       1            1 : // Distributed under the MIT License.
       2              : // See LICENSE.txt for details.
       3              : 
       4              : /// \file
       5              : /// Defines classes for Tensor
       6              : 
       7              : #pragma once
       8              : 
       9              : #include <concepts>
      10              : #include <cstddef>
      11              : #include <pup.h>
      12              : #include <pup_stl.h>
      13              : 
      14              : #include "DataStructures/Tensor/Expressions/AddSubtract.hpp"
      15              : #include "DataStructures/Tensor/Expressions/Contract.hpp"
      16              : #include "DataStructures/Tensor/Expressions/DataTypeSupport.hpp"
      17              : #include "DataStructures/Tensor/Expressions/Divide.hpp"
      18              : #include "DataStructures/Tensor/Expressions/Evaluate.hpp"
      19              : #include "DataStructures/Tensor/Expressions/IndexPropertyCheck.hpp"
      20              : #include "DataStructures/Tensor/Expressions/LhsTensorSymmAndIndices.hpp"
      21              : #include "DataStructures/Tensor/Expressions/Negate.hpp"
      22              : #include "DataStructures/Tensor/Expressions/NumberAsExpression.hpp"
      23              : #include "DataStructures/Tensor/Expressions/Product.hpp"
      24              : #include "DataStructures/Tensor/Expressions/SpatialSpacetimeIndex.hpp"
      25              : #include "DataStructures/Tensor/Expressions/SquareRoot.hpp"
      26              : #include "DataStructures/Tensor/Expressions/TensorAsExpression.hpp"
      27              : #include "DataStructures/Tensor/Expressions/TensorExpression.hpp"
      28              : #include "DataStructures/Tensor/Expressions/TensorIndex.hpp"
      29              : #include "DataStructures/Tensor/Expressions/TensorIndexTransformation.hpp"
      30              : #include "DataStructures/Tensor/Expressions/TimeIndex.hpp"
      31              : #include "DataStructures/Tensor/IndexType.hpp"
      32              : #include "DataStructures/Tensor/Structure.hpp"
      33              : #include "DataStructures/Tensor/TypeAliases.hpp"
      34              : #include "Utilities/Autodiff/Autodiff.hpp"
      35              : #include "Utilities/ErrorHandling/Error.hpp"
      36              : #include "Utilities/ForceInline.hpp"
      37              : #include "Utilities/Gsl.hpp"
      38              : #include "Utilities/MakeArray.hpp"
      39              : #include "Utilities/MakeWithValue.hpp"
      40              : #include "Utilities/PrettyType.hpp"
      41              : #include "Utilities/SetNumberOfGridPoints.hpp"
      42              : #include "Utilities/Simd/Simd.hpp"
      43              : #include "Utilities/StdHelpers.hpp"
      44              : #include "Utilities/TMPL.hpp"
      45              : #include "Utilities/TypeTraits.hpp"
      46              : #include "Utilities/TypeTraits/IsStreamable.hpp"
      47              : // Not all the TensorExpression includes are necessary, but we include them so
      48              : // that Tensor.hpp provides a uniform interface to Tensors and TensorExpressions
      49              : 
      50              : /// \cond
      51              : template <typename X, typename Symm = Symmetry<>,
      52              :           typename IndexList = index_list<>>
      53              : class Tensor;
      54              : /// \endcond
      55              : 
      56              : namespace Tensor_detail {
      57              : template <typename T, typename = void>
      58              : struct is_tensor : std::false_type {};
      59              : template <typename X, typename Symm, typename IndexList>
      60              : struct is_tensor<Tensor<X, Symm, IndexList>> : std::true_type {};
      61              : }  // namespace Tensor_detail
      62              : 
      63              : /*!
      64              :  * \ingroup TensorGroup
      65              :  * \brief Represents an object with multiple components
      66              :  *
      67              :  * \details
      68              :  * Tensor is a container that represents indexable geometric objects. Each index
      69              :  * has its own dimension, valence, and frame and must be either spatial or
      70              :  * spacetime. Note that the dimension passed to `SpatialIndex` and
      71              :  * `SpacetimeIndex` is always the spatial dimension of the index. Tensors with
      72              :  * symmetric indices are stored only once and must be of the same
      73              :  * type. A list of available type aliases can be found in the ::tnsr namespace
      74              :  * where the adopted conventions are:
      75              :  *
      76              :  * 1. Upper case for contravariant or upper indices, lower case for covariant or
      77              :  * lower indices.
      78              :  *
      79              :  * 2. `a, b, c, d` are used for spacetime indices while `i, j, k, l` are used
      80              :  * for spatial indices.
      81              :  *
      82              :  * 3. `::Scalar` is not inside the `::tnsr` namespace but is used to represent
      83              :  * a scalar with no indices.
      84              :  *
      85              :  * \example
      86              :  * \snippet Test_Tensor.cpp scalar
      87              :  * \snippet Test_Tensor.cpp spatial_vector
      88              :  * \snippet Test_Tensor.cpp spacetime_vector
      89              :  * \snippet Test_Tensor.cpp rank_3_122
      90              :  *
      91              :  * \tparam X the type held
      92              :  * \tparam Symm the ::Symmetry of the indices
      93              :  * \tparam IndexList a typelist of \ref SpacetimeIndex "TensorIndexType"'s
      94              :  */
      95              : template <typename X, typename Symm, template <typename...> class IndexList,
      96              :           typename... Indices>
      97            1 : class Tensor<X, Symm, IndexList<Indices...>> {
      98              :   static_assert(sizeof...(Indices) < 5,
      99              :                 "If you are sure you need rank 5 or higher Tensor's please "
     100              :                 "file an issue on GitHub or discuss with a core developer of "
     101              :                 "SpECTRE.");
     102              :  public:
     103              :   /// The type of the sequence that holds the data
     104            1 :   using storage_type =
     105              :       std::array<X, Tensor_detail::Structure<Symm, Indices...>::size()>;
     106              :   /// The type that is stored by the Tensor
     107            1 :   using type = X;
     108              :   /// Typelist of the symmetry of the Tensor
     109              :   ///
     110              :   /// \details
     111              :   /// For a rank-3 tensor symmetric in the last two indices,
     112              :   /// \f$T_{a(bc)}\f$, the ::Symmetry is `<2, 1, 1>`. For a non-symmetric rank-2
     113              :   /// tensor the ::Symmetry is `<2, 1>`.
     114            1 :   using symmetry = Symm;
     115              :   /// Typelist of the \ref SpacetimeIndex "TensorIndexType"'s that the
     116              :   /// Tensor has
     117            1 :   using index_list = tmpl::list<Indices...>;
     118              :   /// The number of indices that the Tensor has
     119            1 :   static constexpr size_t num_tensor_indices = sizeof...(Indices);
     120              :   /// The Tensor_detail::Structure for the particular tensor index structure
     121              :   ///
     122              :   /// Each tensor index structure, e.g. \f$T_{ab}\f$, \f$T_a{}^b\f$ or
     123              :   /// \f$T^{ab}\f$ has its own Tensor_detail::TensorStructure that holds
     124              :   /// information about how the data is stored, what the multiplicity of the
     125              :   /// stored indices are, the number of (independent) components, etc.
     126            1 :   using structure = Tensor_detail::Structure<Symm, Indices...>;
     127              :   /// The type of the TensorExpression that would represent this Tensor in a
     128              :   /// tensor expression.
     129              :   template <typename ArgsList>
     130            1 :   using TE = tenex::TensorAsExpression<Tensor<X, Symm, IndexList<Indices...>>,
     131              :                                        ArgsList>;
     132              : 
     133            0 :   Tensor() = default;
     134            0 :   ~Tensor() = default;
     135            0 :   Tensor(const Tensor&) = default;
     136            0 :   Tensor(Tensor&&) = default;
     137            0 :   Tensor& operator=(const Tensor&) = default;
     138            0 :   Tensor& operator=(Tensor&&) = default;
     139              : 
     140              :   /// Initialize a vector or scalar from an array
     141              :   ///
     142              :   /// \example
     143              :   /// \snippet Test_Tensor.cpp init_vector
     144              :   /// \param data the values of the individual components of the Vector
     145            1 :   explicit constexpr Tensor(storage_type data)
     146              :     requires(sizeof...(Indices) <= 1);
     147              : 
     148              :   /// Constructor that passes "args" to constructor of X and initializes each
     149              :   /// component to be the same
     150              :   template <typename Arg0, typename... Args>
     151            1 :   explicit constexpr Tensor(Arg0&& arg0, Args&&... args)
     152              :       // NOLINTNEXTLINE(readability-simplify-boolean-expr)
     153              :     requires(not(sizeof...(Args) == 0 and
     154              :                  std::same_as<std::decay_t<Arg0>, Tensor>) and
     155              :              std::constructible_from<X, Arg0, Args...>);
     156              : 
     157            0 :   using value_type = typename storage_type::value_type;
     158            0 :   using reference = typename storage_type::reference;
     159            0 :   using const_reference = typename storage_type::const_reference;
     160            0 :   using iterator = typename storage_type::iterator;
     161            0 :   using const_iterator = typename storage_type::const_iterator;
     162            0 :   using pointer = typename storage_type::pointer;
     163            0 :   using const_pointer = typename storage_type::const_pointer;
     164            0 :   using reverse_iterator = typename storage_type::reverse_iterator;
     165            0 :   using const_reverse_iterator = typename storage_type::const_reverse_iterator;
     166              : 
     167            0 :   constexpr iterator begin() { return data_.begin(); }
     168            0 :   constexpr const_iterator begin() const { return data_.begin(); }
     169            0 :   constexpr const_iterator cbegin() const { return data_.begin(); }
     170              : 
     171            0 :   constexpr iterator end() { return data_.end(); }
     172            0 :   constexpr const_iterator end() const { return data_.end(); }
     173            0 :   constexpr const_iterator cend() const { return data_.end(); }
     174              : 
     175            0 :   constexpr reverse_iterator rbegin() { return data_.rbegin(); }
     176            0 :   constexpr const_reverse_iterator rbegin() const { return data_.rbegin(); }
     177            0 :   constexpr const_reverse_iterator crbegin() const { return data_.rbegin(); }
     178              : 
     179            0 :   constexpr reverse_iterator rend() { return data_.rend(); }
     180            0 :   constexpr const_reverse_iterator rend() const { return data_.rend(); }
     181            0 :   constexpr const_reverse_iterator crend() const { return data_.rend(); }
     182              : 
     183              :   /// @{
     184              :   /// Get data entry using an array representing a tensor index
     185              :   ///
     186              :   /// \details
     187              :   /// Let \f$T_{abc}\f$ be a Tensor.
     188              :   /// Then `get({{0, 2, 1}})` returns the \f$T_{0 2 1}\f$ component.
     189              :   /// \param tensor_index the index at which to get the data
     190              :   template <typename T>
     191            1 :   SPECTRE_ALWAYS_INLINE constexpr reference get(
     192              :       const std::array<T, sizeof...(Indices)>& tensor_index) {
     193              :     return gsl::at(data_, structure::get_storage_index(tensor_index));
     194              :   }
     195              :   template <typename T>
     196            1 :   SPECTRE_ALWAYS_INLINE constexpr const_reference get(
     197              :       const std::array<T, sizeof...(Indices)>& tensor_index) const {
     198              :     return gsl::at(data_, structure::get_storage_index(tensor_index));
     199              :   }
     200              :   /// @}
     201              :   /// @{
     202              :   /// Get data entry using a list of integers representing a tensor index
     203              :   ///
     204              :   /// \details
     205              :   /// Let \f$T_{abc}\f$ be a Tensor.
     206              :   /// Then `get(0, 2, 1)` returns the \f$T_{0 2 1}\f$ component.
     207              :   /// \param n the index at which to get the data
     208              :   template <typename... N>
     209            1 :   constexpr reference get(N... n) {
     210              :     static_assert(
     211              :         sizeof...(Indices) == sizeof...(N),
     212              :         "the number of tensor indices specified must match the rank of "
     213              :         "the tensor");
     214              :     return gsl::at(data_, structure::get_storage_index(n...));
     215              :   }
     216              :   template <typename... N>
     217            1 :   constexpr const_reference get(N... n) const {
     218              :     static_assert(
     219              :         sizeof...(Indices) == sizeof...(N),
     220              :         "the number of tensor indices specified must match the rank of "
     221              :         "the tensor");
     222              :     return gsl::at(data_, structure::get_storage_index(n...));
     223              :   }
     224              :   /// @}
     225              : 
     226              :   /// @{
     227              :   /// Retrieve the index `N...` by computing the storage index at compile time
     228              :   // clang-tidy: redundant declaration (bug in clang-tidy)
     229              :   template <int... N, typename... Args>
     230              :   friend SPECTRE_ALWAYS_INLINE constexpr typename Tensor<Args...>::reference
     231            1 :   get(Tensor<Args...>& t);  // NOLINT
     232              :   // clang-tidy: redundant declaration (bug in clang-tidy)
     233              :   template <int... N, typename... Args>
     234              :   friend SPECTRE_ALWAYS_INLINE constexpr
     235              :       typename Tensor<Args...>::const_reference
     236            1 :       get(const Tensor<Args...>& t);  // NOLINT
     237              :                                       /// @}
     238              : 
     239              :   /// @{
     240              :   /// Retrieve a TensorExpression object with the index structure passed in
     241              :   template <typename... TensorIndices>
     242            1 :   SPECTRE_ALWAYS_INLINE constexpr auto operator()(
     243              :       TensorIndices... /*meta*/) const {
     244              :     static_assert((... and tt::is_tensor_index<TensorIndices>::value),
     245              :                   "The tensor expression must be created using TensorIndex "
     246              :                   "objects to represent generic indices, e.g. ti::a, ti::b, "
     247              :                   "etc.");
     248              :     static_assert(
     249              :         tenex::tensorindex_list_is_valid<tmpl::list<TensorIndices...>>::value,
     250              :         "Cannot create a tensor expression with a repeated generic index. "
     251              :         "(Note that the concrete time indices, ti::T and ti::t, can be "
     252              :         "repeated.) If you intend to contract, ensure that the indices to "
     253              :         "contract have opposite valences.");
     254              :     static_assert(
     255              :         std::is_same_v<tmpl::integral_list<UpLo, TensorIndices::valence...>,
     256              :                        tmpl::integral_list<UpLo, Indices::ul...>>,
     257              :         "The valences of the generic indices in the expression do "
     258              :         "not match the valences of the indices in the Tensor.");
     259              :     static_assert((... and (not(TensorIndices::is_spacetime and
     260              :                                 (Indices::index_type == IndexType::Spatial)))),
     261              :                   "Cannot use a spacetime index for a spatial index. e.g. "
     262              :                   "Cannot do R(ti::a), where R's index is spatial, because "
     263              :                   "ti::a denotes a generic spacetime index.");
     264              :     return tenex::contract(TE<tmpl::list<TensorIndices...>>{*this});
     265              :   }
     266              :   /// @}
     267              : 
     268              :   /// @{
     269              :   /// Return i'th component of storage vector
     270            1 :   constexpr reference operator[](const size_t storage_index) {
     271              :     return gsl::at(data_, storage_index);
     272              :   }
     273            1 :   constexpr const_reference operator[](const size_t storage_index) const {
     274              :     return gsl::at(data_, storage_index);
     275              :   }
     276              :   /// @}
     277              : 
     278              :   /// Return the number of independent components of the Tensor
     279              :   ///
     280              :   /// \details
     281              :   /// Returns the number of independent components of the Tensor taking into
     282              :   /// account symmetries. For example, let \f$T_{ab}\f$ be a n-dimensional
     283              :   /// rank-2 symmetric tensor, then the number of independent components is
     284              :   /// \f$n(n+1)/2\f$.
     285            1 :   SPECTRE_ALWAYS_INLINE static constexpr size_t size() {
     286              :     return structure::size();
     287              :   }
     288              : 
     289              :   /// Returns the rank of the Tensor
     290              :   ///
     291              :   /// \details
     292              :   /// The rank of a tensor is the number of indices it has. For example, the
     293              :   /// tensor \f$v^a\f$ is rank-1, the tensor \f$\phi\f$ is rank-0, and the
     294              :   /// tensor \f$T_{abc}\f$ is rank-3.
     295            1 :   SPECTRE_ALWAYS_INLINE static constexpr size_t rank() {
     296              :     return sizeof...(Indices);
     297              :   }
     298              : 
     299              :   /// @{
     300              :   /// Given an iterator or storage index, get the canonical tensor index.
     301              :   /// For scalars this is defined to be std::array<int, 1>{{0}}
     302              :   SPECTRE_ALWAYS_INLINE constexpr std::array<size_t, sizeof...(Indices)>
     303            1 :   get_tensor_index(const const_iterator& iter) const {
     304              :     return structure::get_canonical_tensor_index(
     305              :         static_cast<size_t>(iter - begin()));
     306              :   }
     307              :   SPECTRE_ALWAYS_INLINE static constexpr std::array<size_t, sizeof...(Indices)>
     308            1 :   get_tensor_index(const size_t storage_index) {
     309              :     return structure::get_canonical_tensor_index(storage_index);
     310              :   }
     311              :   /// @}
     312              : 
     313              :   /// @{
     314              :   /// Get the storage index of the tensor index. Should only be used when
     315              :   /// optimizing code in which computing the storage index is a bottleneck.
     316              :   template <typename... N>
     317            1 :   SPECTRE_ALWAYS_INLINE static constexpr size_t get_storage_index(
     318              :       const N... args) {
     319              :     return structure::get_storage_index(args...);
     320              :   }
     321              :   template <typename I>
     322            1 :   SPECTRE_ALWAYS_INLINE static constexpr size_t get_storage_index(
     323              :       const std::array<I, sizeof...(Indices)>& tensor_index) {
     324              :     return structure::get_storage_index(tensor_index);
     325              :   }
     326              :   /// @}
     327              : 
     328              :   /// @{
     329              :   /// Given an iterator or storage index, get the multiplicity of an index
     330              :   ///
     331              :   /// \see TensorMetafunctions::compute_multiplicity
     332            1 :   SPECTRE_ALWAYS_INLINE constexpr size_t multiplicity(
     333              :       const const_iterator& iter) const {
     334              :     return structure::multiplicity(static_cast<size_t>(iter - begin()));
     335              :   }
     336            1 :   SPECTRE_ALWAYS_INLINE static constexpr size_t multiplicity(
     337              :       const size_t storage_index) {
     338              :     return structure::multiplicity(storage_index);
     339              :   }
     340              :   /// @}
     341              : 
     342              :   /// @{
     343              :   /// Get dimensionality of i'th tensor index
     344              :   ///
     345              :   /// \snippet Test_Tensor.cpp index_dim
     346              :   /// \see ::index_dim
     347            1 :   SPECTRE_ALWAYS_INLINE static constexpr size_t index_dim(const size_t i) {
     348              :     static_assert(sizeof...(Indices),
     349              :                   "A scalar does not have any indices from which you can "
     350              :                   "retrieve the dimensionality.");
     351              :     return gsl::at(structure::dims(), i);
     352              :   }
     353              :   /// @}
     354              : 
     355              :   /// @{
     356              :   /// Return an array corresponding to the ::Symmetry of the Tensor
     357              :   SPECTRE_ALWAYS_INLINE static constexpr std::array<int, sizeof...(Indices)>
     358            1 :   symmetries() {
     359              :     return structure::symmetries();
     360              :   }
     361              :   /// @}
     362              : 
     363              :   /// @{
     364              :   /// Return array of the ::IndexType's (spatial or spacetime)
     365              :   SPECTRE_ALWAYS_INLINE static constexpr std::array<IndexType,
     366              :                                                     sizeof...(Indices)>
     367            1 :   index_types() {
     368              :     return structure::index_types();
     369              :   }
     370              :   /// @}
     371              : 
     372              :   /// @{
     373              :   /// Return array of dimensionality of each index
     374              :   ///
     375              :   /// \snippet Test_Tensor.cpp index_dim
     376              :   /// \see index_dim ::index_dim
     377              :   SPECTRE_ALWAYS_INLINE static constexpr std::array<size_t, sizeof...(Indices)>
     378            1 :   index_dims() {
     379              :     return structure::dims();
     380              :   }
     381              :   /// @}
     382              : 
     383              :   /// @{
     384              :   /// Return array of the valence of each index (::UpLo)
     385              :   SPECTRE_ALWAYS_INLINE static constexpr std::array<UpLo, sizeof...(Indices)>
     386            1 :   index_valences() {
     387              :     return structure::index_valences();
     388              :   }
     389              :   /// @}
     390              : 
     391              :   /// @{
     392              :   /// Returns std::tuple of the ::Frame of each index
     393            1 :   SPECTRE_ALWAYS_INLINE static constexpr auto index_frames() {
     394              :     return Tensor_detail::Structure<Symm, Indices...>::index_frames();
     395              :   }
     396              :   /// @}
     397              : 
     398              :   /// @{
     399              :   /// \brief Given a tensor index, get the canonical label associated with the
     400              :   /// canonical \ref SpacetimeIndex "TensorIndexType"
     401              :   ///
     402              :   /// \param tensor_index The index of the tensor component to label
     403              :   /// \param axis_labels The labels for the indices. Defaults to "t", "x", "y"
     404              :   /// and "z" for spacetime indices and "x", "y" and "z" for spatial indices.
     405              :   /// Note that a tensor can have indices of different types, so we specify
     406              :   /// labels for each index individually.
     407              :   template <typename T = int>
     408            1 :   static std::string component_name(
     409              :       const std::array<T, rank()>& tensor_index = std::array<T, rank()>{},
     410              :       const std::array<std::string, rank()>& axis_labels =
     411              :           make_array<rank()>(std::string(""))) {
     412              :     return structure::component_name(tensor_index, axis_labels);
     413              :   }
     414              :   /// @}
     415              : 
     416              :   /// @{
     417              :   /// \brief Suffix to append to the tensor name that indicates the component
     418              :   ///
     419              :   /// The suffix is empty for scalars, otherwise it is an underscore followed by
     420              :   /// the `Tensor::component_name` of either the `tensor_index` or the canonical
     421              :   /// tensor index obtained from the `storage_index`. Use `axis_labels` to
     422              :   /// overwrite the default labels for each component (see
     423              :   /// `Tensor::component_name`).
     424              :   ///
     425              :   /// An example use case for the suffix is to label tensor components in
     426              :   /// data files.
     427              :   ///
     428              :   /// \see Tensor::component_name
     429              :   template <typename IndexType = int>
     430            1 :   static std::string component_suffix(
     431              :       const std::array<IndexType, rank()>& tensor_index =
     432              :           std::array<IndexType, rank()>{},
     433              :       const std::array<std::string, rank()>& axis_labels =
     434              :           make_array<rank()>(std::string(""))) {
     435              :     return rank() == 0 ? "" : "_" + component_name(tensor_index, axis_labels);
     436              :   }
     437              : 
     438            1 :   static std::string component_suffix(
     439              :       const size_t storage_index,
     440              :       const std::array<std::string, rank()>& axis_labels) {
     441              :     return component_suffix(get_tensor_index(storage_index), axis_labels);
     442              :   }
     443              : 
     444            1 :   static std::string component_suffix(size_t storage_index);
     445              :   /// @}
     446              : 
     447              :   /// Copy tensor data into an `std::vector<X>` along with the
     448              :   /// component names into a `std::vector<std::string>`
     449              :   /// \requires `std::is_same<X, DataVector>::%value` is true
     450            1 :   std::pair<std::vector<std::string>, std::vector<X>> get_vector_of_data()
     451              :       const;
     452              : 
     453              :   /// \cond HIDDEN_SYMBOLS
     454              :   /// Serialization function used by Charm++
     455              :   // NOLINTNEXTLINE(google-runtime-references)
     456              :   void pup(PUP::er& p) { p | data_; }
     457              :   /// \endcond
     458              : 
     459              :  private:
     460              :   // clang-tidy: redundant declaration
     461              :   /// \cond
     462              :   template <int I, class... Ts>
     463              :   friend SPECTRE_ALWAYS_INLINE constexpr size_t index_dim(  // NOLINT
     464              :       const Tensor<Ts...>& /*t*/);
     465              :   /// \endcond
     466              : 
     467            0 :   storage_type data_;
     468              : };
     469              : 
     470              : // ================================================================
     471              : // Template Definitions - Variadic templates must be in header
     472              : // ================================================================
     473              : 
     474              : template <typename X, typename Symm, template <typename...> class IndexList,
     475              :           typename... Indices>
     476              : // Implementation note: we explicitly prevent inlining and mark the function
     477              : // as used so that GDB's pretty printing facilities have access to this
     478              : // function.
     479            0 : __attribute__((noinline)) __attribute__((used)) std::string
     480              : Tensor<X, Symm, IndexList<Indices...>>::component_suffix(
     481              :     const size_t storage_index) {
     482              :   return component_suffix(get_tensor_index(storage_index),
     483              :                           make_array<rank()>(std::string("")));
     484              : }
     485              : 
     486              : template <typename X, typename Symm, template <typename...> class IndexList,
     487              :           typename... Indices>
     488              : constexpr Tensor<X, Symm, IndexList<Indices...>>::Tensor(storage_type data)
     489              :   requires(sizeof...(Indices) <= 1)
     490              :     : data_(std::move(data)) {}
     491              : 
     492              : template <typename X, typename Symm, template <typename...> class IndexList,
     493              :           typename... Indices>
     494              : template <typename Arg0, typename... Args>
     495              : constexpr Tensor<X, Symm, IndexList<Indices...>>::Tensor(Arg0&& arg0,
     496              :                                                          Args&&... args)
     497              :     // NOLINTNEXTLINE(readability-simplify-boolean-expr)
     498              :   requires(not(sizeof...(Args) == 0 and
     499              :                std::same_as<std::decay_t<Arg0>, Tensor>) and
     500              :            std::constructible_from<X, Arg0, Args...>)
     501              :     : data_(make_array<size(), X>(std::forward<Arg0>(arg0),
     502              :                                   std::forward<Args>(args)...)) {}
     503              : 
     504              : template <typename X, typename Symm, template <typename...> class IndexList,
     505              :           typename... Indices>
     506              : std::pair<std::vector<std::string>, std::vector<X>>
     507              : Tensor<X, Symm, IndexList<Indices...>>::get_vector_of_data() const {
     508              :   std::vector<value_type> serialized_tensor(size());
     509              :   std::vector<std::string> component_names(size());
     510              :   for (size_t i = 0; i < data_.size(); ++i) {
     511              :     component_names[i] = component_name(get_tensor_index(i));
     512              :     serialized_tensor[i] = gsl::at(data_, i);
     513              :   }
     514              :   return std::make_pair(component_names, serialized_tensor);
     515              : }
     516              : 
     517              : template <int... N, typename... Args>
     518            0 : SPECTRE_ALWAYS_INLINE constexpr typename Tensor<Args...>::reference get(
     519              :     Tensor<Args...>& t) {
     520              :   static_assert(Tensor<Args...>::rank() == sizeof...(N),
     521              :                 "the number of tensor indices specified must match the rank "
     522              :                 "of the tensor");
     523              :   return gsl::at(
     524              :       t.data_, Tensor<Args...>::structure::template get_storage_index<N...>());
     525              : }
     526              : 
     527              : template <int... N, typename... Args>
     528            0 : SPECTRE_ALWAYS_INLINE constexpr typename Tensor<Args...>::const_reference get(
     529              :     const Tensor<Args...>& t) {
     530              :   static_assert(Tensor<Args...>::rank() == sizeof...(N),
     531              :                 "the number of tensor indices specified must match the rank "
     532              :                 "of the tensor");
     533              :   return gsl::at(
     534              :       t.data_, Tensor<Args...>::structure::template get_storage_index<N...>());
     535              : }
     536              : 
     537              : template <typename X, typename Symm, template <typename...> class IndexList,
     538              :           typename... Indices>
     539            0 : bool operator==(const Tensor<X, Symm, IndexList<Indices...>>& lhs,
     540              :                 const Tensor<X, Symm, IndexList<Indices...>>& rhs) {
     541              :   return std::equal(lhs.begin(), lhs.end(), rhs.begin());
     542              : }
     543              : template <typename X, typename Symm, template <typename...> class IndexList,
     544              :           typename... Indices>
     545            0 : bool operator!=(const Tensor<X, Symm, IndexList<Indices...>>& lhs,
     546              :                 const Tensor<X, Symm, IndexList<Indices...>>& rhs) {
     547              :   return not(lhs == rhs);
     548              : }
     549              : 
     550              : /// \ingroup TensorGroup
     551              : /// Get dimensionality of i'th tensor index
     552              : ///
     553              : /// \snippet Test_Tensor.cpp index_dim
     554              : template <int I, class... Ts>
     555            1 : SPECTRE_ALWAYS_INLINE constexpr size_t index_dim(const Tensor<Ts...>& /*t*/) {
     556              :   return Tensor<Ts...>::structure::template dim<I>();
     557              : }
     558              : 
     559              : // We place the stream operators in the header file so they do not need to be
     560              : // explicitly instantiated.
     561              : template <typename X, typename Symm, template <typename...> class IndexList,
     562              :           typename... Indices>
     563            0 : std::ostream& operator<<(std::ostream& os,
     564              :                          const Tensor<X, Symm, IndexList<Indices...>>& x) {
     565              :   static_assert(tt::is_streamable_v<decltype(os), X>,
     566              :                 "operator<< is not defined for the type you are trying to "
     567              :                 "stream in Tensor");
     568              :   for (size_t i = 0; i < x.size() - 1; ++i) {
     569              :     os << "T" << x.get_tensor_index(i) << "=" << x[i] << "\n";
     570              :   }
     571              :   size_t i = x.size() - 1;
     572              :   os << "T" << x.get_tensor_index(i) << "=" << x[i];
     573              :   return os;
     574              : }
     575              : 
     576              : namespace MakeWithValueImpls {
     577              : template <typename T, typename... Structure>
     578            0 : struct NumberOfPoints<Tensor<T, Structure...>> {
     579              :   static SPECTRE_ALWAYS_INLINE size_t
     580            0 :   apply(const Tensor<T, Structure...>& input) {
     581              :     return number_of_points(*input.begin());
     582              :   }
     583              : };
     584              : 
     585              : template <typename T, typename... Structure>
     586            0 : struct MakeWithSize<Tensor<T, Structure...>> {
     587              :   template <typename U>
     588            0 :   static SPECTRE_ALWAYS_INLINE Tensor<T, Structure...> apply(const size_t size,
     589              :                                                              const U value) {
     590              :     return Tensor<T, Structure...>(make_with_value<T>(size, value));
     591              :   }
     592              : };
     593              : 
     594              : template <typename... Structure, typename T>
     595            0 : struct MakeWithValueImpl<Tensor<double, Structure...>, T> {
     596            0 :   static SPECTRE_ALWAYS_INLINE Tensor<double, Structure...> apply(
     597              :       const T& /*input*/, const double value) {
     598              :     return Tensor<double, Structure...>(value);
     599              :   }
     600              : };
     601              : 
     602              : template <typename... Structure, typename T>
     603              : struct MakeWithValueImpl<Tensor<std::complex<double>, Structure...>, T> {
     604              :   static SPECTRE_ALWAYS_INLINE Tensor<std::complex<double>, Structure...> apply(
     605              :       const T& /*input*/, const std::complex<double> value) {
     606              :     return Tensor<std::complex<double>, Structure...>(value);
     607              :   }
     608              : };
     609              : 
     610              : #ifdef SPECTRE_AUTODIFF
     611              : template <typename... Structure, typename T>
     612            0 : struct MakeWithValueImpl<
     613              :     Tensor<autodiff::HigherOrderDual<2, double>, Structure...>, T> {
     614              :   static SPECTRE_ALWAYS_INLINE
     615              :       Tensor<autodiff::HigherOrderDual<2, double>, Structure...>
     616            0 :       apply(const T& /*input*/, const double value) {
     617              :     return Tensor<autodiff::HigherOrderDual<2, double>, Structure...>(value);
     618              :   }
     619              : };
     620              : 
     621              : template <typename... Structure, typename T>
     622            0 : struct MakeWithValueImpl<
     623              :     Tensor<autodiff::HigherOrderDual<2, simd::batch<double>>, Structure...>,
     624              :     T> {
     625              :   static SPECTRE_ALWAYS_INLINE
     626              :       Tensor<autodiff::HigherOrderDual<2, simd::batch<double>>, Structure...>
     627            0 :       apply(const T& /*input*/, const double value) {
     628              :     return Tensor<autodiff::HigherOrderDual<2, simd::batch<double>>,
     629              :                   Structure...>(simd::batch<double>::broadcast(value));
     630              :   }
     631              : };
     632              : #endif  // SPECTRE_AUTODIFF
     633              : }  // namespace MakeWithValueImpls
     634              : 
     635              : template <typename T, typename... Structure>
     636            0 : struct SetNumberOfGridPointsImpls::SetNumberOfGridPointsImpl<
     637              :     Tensor<T, Structure...>> {
     638            0 :   static constexpr bool is_trivial = SetNumberOfGridPointsImpl<T>::is_trivial;
     639            0 :   static SPECTRE_ALWAYS_INLINE void apply(
     640              :       const gsl::not_null<Tensor<T, Structure...>*> result, const size_t size) {
     641              :     for (auto& component : *result) {
     642              :       set_number_of_grid_points(make_not_null(&component), size);
     643              :     }
     644              :   }
     645              : };
        

Generated by: LCOV version 2.0-1