SpECTRE Documentation Coverage Report
Current view: top level - DataStructures/Tensor - Tensor.hpp Hit Total Coverage
Commit: 3ffcbc8ecf43797401b60bcca17d6040ee06f013 Lines: 40 87 46.0 %
Date: 2026-03-03 02:01:44
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 1.14