• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sxs-collaboration / spectre / 4245608534

pending completion
4245608534

push

github

GitHub
Merge pull request #4745 from knelli2/time_dep_dep

13 of 13 new or added lines in 4 files covered. (100.0%)

63923 of 66629 relevant lines covered (95.94%)

427287.21 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.43
/src/DataStructures/Variables.hpp
1
// Distributed under the MIT License.
2
// See LICENSE.txt for details.
3

4
/// \file
5
/// Defines class Variables
6

7
#pragma once
8

9
#include <algorithm>
10
#include <array>
11
#include <blaze/math/AlignmentFlag.h>
12
#include <blaze/math/CustomVector.h>
13
#include <blaze/math/DenseVector.h>
14
#include <blaze/math/GroupTag.h>
15
#include <blaze/math/PaddingFlag.h>
16
#include <blaze/math/TransposeFlag.h>
17
#include <blaze/math/Vector.h>
18
#include <limits>
19
#include <memory>
20
#include <ostream>
21
#include <pup.h>
22
#include <string>
23
#include <tuple>
24

25
#include "DataStructures/DataBox/PrefixHelpers.hpp"
26
#include "DataStructures/DataBox/Subitems.hpp"
27
#include "DataStructures/DataBox/Tag.hpp"
28
#include "DataStructures/DataBox/TagName.hpp"
29
#include "DataStructures/DataBox/TagTraits.hpp"
30
#include "DataStructures/DataVector.hpp"
31
#include "DataStructures/MathWrapper.hpp"
32
#include "DataStructures/Tensor/IndexType.hpp"
33
#include "DataStructures/Tensor/Tensor.hpp"
34
#include "Utilities/EqualWithinRoundoff.hpp"
35
#include "Utilities/ErrorHandling/Assert.hpp"
36
#include "Utilities/ForceInline.hpp"
37
#include "Utilities/Gsl.hpp"
38
#include "Utilities/Literals.hpp"
39
#include "Utilities/MakeSignalingNan.hpp"
40
#include "Utilities/MemoryHelpers.hpp"
41
#include "Utilities/PrettyType.hpp"
42
#include "Utilities/Requires.hpp"
43
#include "Utilities/TMPL.hpp"
44
#include "Utilities/TaggedTuple.hpp"
45
#include "Utilities/TypeTraits.hpp"
46
#include "Utilities/TypeTraits/IsA.hpp"
47

48
// IWYU pragma: no_forward_declare MakeWithValueImpl
49
// IWYU pragma: no_forward_declare Variables
50

51
/// \cond
52
template <typename X, typename Symm, typename IndexList>
53
class Tensor;
54
template <typename TagsList>
55
class Variables;
56
template <typename T, typename VectorType, size_t StaticSize>
57
class VectorImpl;
58
namespace Tags {
59
template <typename TagsList>
60
class Variables;
61
}  // namespace Tags
62
/// \endcond
63

64
/*!
65
 * \ingroup DataStructuresGroup
66
 * \brief A Variables holds a contiguous memory block with Tensors pointing
67
 * into it.
68
 *
69
 * The `Tags` are `struct`s that must have a public type alias `type` whose
70
 * value must be a `Tensor<DataVector, ...>`, a `static' method `name()` that
71
 * returns a `std::string` of the tag name, and must derive off of
72
 * `db::SimpleTag`. In general, they should be DataBoxTags that are not compute
73
 * items. For example,
74
 *
75
 * \snippet Helpers/DataStructures/TestTags.hpp simple_variables_tag
76
 *
77
 * Prefix tags can also be stored and their format is:
78
 *
79
 * \snippet Helpers/DataStructures/TestTags.hpp prefix_variables_tag
80
 *
81
 * #### Design Decisions
82
 *
83
 * The `Variables` class is designed to hold several different `Tensor`s
84
 * performing one memory allocation for all the `Tensor`s. The advantage is that
85
 * memory allocations are quite expensive, especially in a parallel environment.
86
 *
87
 * In Debug mode, or if the macro `SPECTRE_NAN_INIT` is defined, the contents
88
 * are initialized with `NaN`s.
89
 *
90
 * `Variables` stores the data it owns in a `std::unique_ptr<double[]>`
91
 * instead of a `std::vector` because `std::vector` value-initializes its
92
 * contents, which is very slow.
93
 */
94
template <typename... Tags>
95
class Variables<tmpl::list<Tags...>> {
96
 public:
97
  using size_type = size_t;
98
  using difference_type = std::ptrdiff_t;
99
  static constexpr auto transpose_flag = blaze::defaultTransposeFlag;
100

101
  /// A typelist of the Tags whose variables are held
102
  using tags_list = tmpl::list<Tags...>;
103
  static_assert(sizeof...(Tags) > 0,
104
                "You must provide at least one tag to the Variables "
105
                "for type inference");
106
  static_assert((db::is_simple_tag_v<Tags> and ...));
107
  static_assert(tmpl2::flat_all_v<tt::is_a_v<Tensor, typename Tags::type>...>);
108

109
 private:
110
  using first_tensors_type = typename tmpl::front<tags_list>::type::type;
111

112
 public:
113
  static_assert(tmpl2::flat_all_v<std::is_same_v<typename Tags::type::type,
114
                                                 first_tensors_type>...> or
115
                    tmpl2::flat_all_v<is_spin_weighted_of_same_type_v<
116
                        typename Tags::type::type, first_tensors_type>...>,
117
                "All tensors stored in a single Variables must "
118
                "have the same internal storage type.");
119

120
  using vector_type =
121
      tmpl::conditional_t<is_any_spin_weighted_v<first_tensors_type>,
122
                          typename first_tensors_type::value_type,
123
                          first_tensors_type>;
124
  using value_type = typename vector_type::value_type;
125
  using pointer = value_type*;
126
  using const_pointer = const value_type*;
127
  using allocator_type = std::allocator<value_type>;
128
  using pointer_type =
129
      blaze::CustomVector<value_type, blaze::AlignmentFlag::unaligned,
130
                          blaze::PaddingFlag::unpadded, transpose_flag,
131
                          blaze::GroupTag<0>, vector_type>;
132

133
  static_assert(
134
      std::is_fundamental_v<value_type> or tt::is_a_v<std::complex, value_type>,
135
      "`value_type` of the Variables (so the storage type of the vector type "
136
      "within the tensors in the Variables) must be either a fundamental type "
137
      "or a std::complex. If this constraint is relaxed, the value_type "
138
      "should be handled differently in the Variables, including pass by "
139
      "reference.");
140

141
  /// The number of variables of the Variables object is holding. E.g.
142
  /// \f$\psi_{ab}\f$ would be counted as one variable.
143
  static constexpr auto number_of_variables = sizeof...(Tags);
144

145
  /// The total number of independent components of all the variables. E.g.
146
  /// a rank-2 symmetric spacetime Tensor \f$\psi_{ab}\f$ in 3 spatial
147
  /// dimensions would have 10 independent components.
148
  static constexpr size_t number_of_independent_components =
149
      (... + Tags::type::size());
150

151
  /// Default construct an empty Variables class, Charm++ needs this
152
  Variables();
153

154
  explicit Variables(size_t number_of_grid_points);
155

156
  Variables(size_t number_of_grid_points, value_type value);
157

158
  /// Construct a non-owning Variables that points to `start`. `size` is the
159
  /// size of the allocation, which must be
160
  /// `number_of_grid_points * Variables::number_of_independent_components`
161
  Variables(pointer start, size_t size);
162

163
  Variables(Variables&& rhs);
164
  Variables& operator=(Variables&& rhs);
165

166
  Variables(const Variables& rhs);
167
  Variables& operator=(const Variables& rhs);
168

169
  /// @{
170
  /// Copy and move semantics for wrapped variables
171
  template <typename... WrappedTags,
172
            Requires<tmpl2::flat_all<std::is_same<
173
                db::remove_all_prefixes<WrappedTags>,
174
                db::remove_all_prefixes<Tags>>::value...>::value> = nullptr>
175
  explicit Variables(Variables<tmpl::list<WrappedTags...>>&& rhs);
176
  template <typename... WrappedTags,
177
            Requires<tmpl2::flat_all<std::is_same<
178
                db::remove_all_prefixes<WrappedTags>,
179
                db::remove_all_prefixes<Tags>>::value...>::value> = nullptr>
180
  Variables& operator=(Variables<tmpl::list<WrappedTags...>>&& rhs);
181

182
  template <typename... WrappedTags,
183
            Requires<tmpl2::flat_all<std::is_same<
184
                db::remove_all_prefixes<WrappedTags>,
185
                db::remove_all_prefixes<Tags>>::value...>::value> = nullptr>
186
  explicit Variables(const Variables<tmpl::list<WrappedTags...>>& rhs);
187
  template <typename... WrappedTags,
188
            Requires<tmpl2::flat_all<std::is_same<
189
                db::remove_all_prefixes<WrappedTags>,
190
                db::remove_all_prefixes<Tags>>::value...>::value> = nullptr>
191
  Variables& operator=(const Variables<tmpl::list<WrappedTags...>>& rhs);
192
  /// @}
193

194
  /// \cond HIDDEN_SYMBOLS
195
  ~Variables() = default;
1,866,084✔
196
  /// \endcond
197

198
  /// @{
199
  /// Initialize a Variables to the state it would have after calling
200
  /// the constructor with the same arguments.
201
  // this should be updated if we ever use a variables which has a `value_type`
202
  // larger than ~2 doubles in size.
203
  void initialize(size_t number_of_grid_points);
204
  void initialize(size_t number_of_grid_points, value_type value);
205
  /// @}
206

207
  /// @{
208
  /// Set the VectorImpl to be a reference to another VectorImpl object
209
  void set_data_ref(const gsl::not_null<Variables*> rhs) {
4✔
210
    set_data_ref(rhs->data(), rhs->size());
8✔
211
  }
4✔
212

213
  void set_data_ref(pointer const start, const size_t size) {
91,786✔
214
    variable_data_impl_dynamic_.reset();
91,786✔
215
    if (start == nullptr) {
91,786✔
216
      variable_data_ = pointer_type{};
×
217
      size_ = 0;
×
218
      number_of_grid_points_ = 0;
×
219
    } else {
220
      size_ = size;
91,786✔
221
      variable_data_.reset(start, size_);
91,786✔
222
      ASSERT(
90,150✔
223
          size_ % number_of_independent_components == 0,
224
          "The size (" << size_
225
                       << ") must be a multiple of the number of independent "
226
                          "components ("
227
                       << number_of_independent_components
228
                       << ") since we calculate the number of grid points from "
229
                          "the size and number of independent components.");
230
      number_of_grid_points_ = size_ / number_of_independent_components;
91,786✔
231
    }
232
    owning_ = false;
91,786✔
233
    add_reference_variable_data();
91,786✔
234
  }
91,786✔
235
  /// @}
236

237
  constexpr SPECTRE_ALWAYS_INLINE size_t number_of_grid_points() const {
238
    return number_of_grid_points_;
5,534,999✔
239
  }
240

241
  /// Number of grid points * number of independent components
242
  constexpr SPECTRE_ALWAYS_INLINE size_type size() const { return size_; }
714,972✔
243

244
  /// @{
245
  /// Access pointer to underlying data
246
  pointer data() { return variable_data_.data(); }
1,262,975✔
247
  const_pointer data() const { return variable_data_.data(); }
1,378,001✔
248
  /// @}
249

250
  /// \cond HIDDEN_SYMBOLS
251
  /// Needed because of limitations and inconsistency between compiler
252
  /// implementations of friend function templates with auto return type of
253
  /// class templates
254
  const auto& get_variable_data() const { return variable_data_; }
12,240✔
255
  /// \endcond
256

257
  /// Returns true if the class owns the data
258
  bool is_owning() const { return owning_; }
2,545,307✔
259

260
  // clang-tidy: redundant-declaration
261
  template <typename Tag, typename TagList>
262
  friend constexpr typename Tag::type& get(  // NOLINT
263
      Variables<TagList>& v);
264
  template <typename Tag, typename TagList>
265
  friend constexpr const typename Tag::type& get(  // NOLINT
266
      const Variables<TagList>& v);
267

268
  /// Serialization for Charm++.
269
  // NOLINTNEXTLINE(google-runtime-references)
270
  void pup(PUP::er& p);
271

272
  /// @{
273
  /// \brief Assign a subset of the `Tensor`s from another Variables or a
274
  /// tuples::TaggedTuple. Any tags that aren't in both containers are
275
  /// ignored.
276
  ///
277
  /// \note There is no need for an rvalue overload because we need to copy into
278
  /// the contiguous array anyway
279
  template <typename... SubsetOfTags>
280
  void assign_subset(const Variables<tmpl::list<SubsetOfTags...>>& vars) {
79,008✔
281
    EXPAND_PACK_LEFT_TO_RIGHT([this, &vars]() {
158,366✔
282
      if constexpr (tmpl::list_contains_v<tmpl::list<Tags...>, SubsetOfTags>) {
283
        get<SubsetOfTags>(*this) = get<SubsetOfTags>(vars);
284
      } else {
285
        (void)this;
286
        (void)vars;
287
      }
288
    }());
289
  }
79,008✔
290

291
  template <typename... SubsetOfTags>
292
  void assign_subset(const tuples::TaggedTuple<SubsetOfTags...>& vars) {
6,594✔
293
    EXPAND_PACK_LEFT_TO_RIGHT([this, &vars]() {
16,381✔
294
      if constexpr (tmpl::list_contains_v<tmpl::list<Tags...>, SubsetOfTags>) {
295
        get<SubsetOfTags>(*this) = get<SubsetOfTags>(vars);
296
      } else {
297
        (void)this;
298
        (void)vars;
299
      }
300
    }());
301
  }
6,594✔
302
  /// @}
303

304
  /// Create a Variables from a subset of the `Tensor`s in this
305
  /// Variables
306
  template <typename SubsetOfTags>
307
  Variables<SubsetOfTags> extract_subset() const {
81,978✔
308
    Variables<SubsetOfTags> sub_vars(number_of_grid_points());
81,978✔
309
    tmpl::for_each<SubsetOfTags>([&](const auto tag_v) {
328,086✔
310
      using tag = tmpl::type_from<decltype(tag_v)>;
311
      get<tag>(sub_vars) = get<tag>(*this);
82,036✔
312
    });
313
    return sub_vars;
81,978✔
314
  }
315

316
  /// Create a non-owning Variables referencing a subset of the
317
  /// `Tensor`s in this Variables.  The referenced tensors must be
318
  /// consecutive in this Variables's tags list.
319
  ///
320
  /// \warning As with other appearances of non-owning variables, this
321
  /// method can cast away constness.
322
  template <typename SubsetOfTags>
323
  Variables<SubsetOfTags> reference_subset() const {
16✔
324
    if constexpr (std::is_same_v<SubsetOfTags, tmpl::list<>>) {
325
      return {};
4✔
326
    } else {
327
      using subset_from_tags_list = tmpl::reverse_find<
328
          tmpl::find<
329
              tags_list,
330
              std::is_same<tmpl::_1, tmpl::pin<tmpl::front<SubsetOfTags>>>>,
331
          std::is_same<tmpl::_1, tmpl::pin<tmpl::back<SubsetOfTags>>>>;
332
      static_assert(std::is_same_v<subset_from_tags_list, SubsetOfTags>,
333
                    "Tags passed to reference_subset must be consecutive tags "
334
                    "in the original tags_list.");
335

336
      using preceeding_tags = tmpl::pop_back<tmpl::reverse_find<
337
          tags_list,
338
          std::is_same<tmpl::_1, tmpl::pin<tmpl::front<SubsetOfTags>>>>>;
339

340
      static constexpr auto count_components = [](auto... tags) {
341
        return (0_st + ... + tmpl::type_from<decltype(tags)>::type::size());
342
      };
343
      static constexpr size_t number_of_preceeding_components =
344
          tmpl::as_pack<preceeding_tags>(count_components);
345
      static constexpr size_t number_of_components_in_subset =
346
          tmpl::as_pack<SubsetOfTags>(count_components);
347

348
      return {const_cast<value_type*>(data()) +
12✔
349
                  number_of_grid_points() * number_of_preceeding_components,
4✔
350
              number_of_grid_points() * number_of_components_in_subset};
16✔
351
    }
352
  }
353

354
  /// Create a non-owning version of this Variables with different
355
  /// prefixes on the tensors.  Both sets of prefixes must have the
356
  /// same tensor types.
357
  ///
358
  /// \warning As with other appearances of non-owning variables, this
359
  /// method can cast away constness.
360
  template <typename WrappedVariables>
361
  WrappedVariables reference_with_different_prefixes() const {
4✔
362
    static_assert(
363
        tmpl::all<tmpl::transform<
364
            typename WrappedVariables::tags_list, tmpl::list<Tags...>,
365
            std::is_same<tmpl::bind<db::remove_all_prefixes, tmpl::_1>,
366
                         tmpl::bind<db::remove_all_prefixes, tmpl::_2>>>>::
367
            value,
368
        "Unprefixed tags do not match!");
369
    static_assert(
370
        tmpl::all<tmpl::transform<
371
            typename WrappedVariables::tags_list, tmpl::list<Tags...>,
372
            std::is_same<tmpl::bind<tmpl::type_from, tmpl::_1>,
373
                         tmpl::bind<tmpl::type_from, tmpl::_2>>>>::value,
374
        "Tensor types do not match!");
375
    return {const_cast<value_type*>(data()), size()};
8✔
376
  }
377

378
  /// Converting constructor for an expression to a Variables class
379
  // clang-tidy: mark as explicit (we want conversion to Variables)
380
  template <typename VT, bool VF>
381
  Variables(const blaze::DenseVector<VT, VF>& expression);  // NOLINT
382

383
  template <typename VT, bool VF>
384
  Variables& operator=(const blaze::DenseVector<VT, VF>& expression);
385

386
  // Prevent the previous two declarations from implicitly converting
387
  // DataVectors and similar to Variables.
388
  template <typename T, typename VectorType, size_t StaticSize>
389
  Variables(const VectorImpl<T, VectorType, StaticSize>&) = delete;
390
  template <typename T, typename VectorType, size_t StaticSize>
391
  Variables& operator=(const VectorImpl<T, VectorType, StaticSize>&) = delete;
392

393
  template <typename... WrappedTags,
394
            Requires<tmpl2::flat_all<std::is_same_v<
395
                db::remove_all_prefixes<WrappedTags>,
396
                db::remove_all_prefixes<Tags>>...>::value> = nullptr>
397
  SPECTRE_ALWAYS_INLINE Variables& operator+=(
398
      const Variables<tmpl::list<WrappedTags...>>& rhs) {
399
    static_assert(
400
        (std::is_same_v<typename Tags::type, typename WrappedTags::type> and
401
         ...),
402
        "Tensor types do not match!");
403
    variable_data_ += rhs.variable_data_;
1,685✔
404
    return *this;
1,685✔
405
  }
406
  template <typename VT, bool VF>
407
  SPECTRE_ALWAYS_INLINE Variables& operator+=(
408
      const blaze::Vector<VT, VF>& rhs) {
409
    variable_data_ += rhs;
10✔
410
    return *this;
10✔
411
  }
412

413
  template <typename... WrappedTags,
414
            Requires<tmpl2::flat_all<std::is_same_v<
415
                db::remove_all_prefixes<WrappedTags>,
416
                db::remove_all_prefixes<Tags>>...>::value> = nullptr>
417
  SPECTRE_ALWAYS_INLINE Variables& operator-=(
418
      const Variables<tmpl::list<WrappedTags...>>& rhs) {
419
    static_assert(
420
        (std::is_same_v<typename Tags::type, typename WrappedTags::type> and
421
         ...),
422
        "Tensor types do not match!");
423
    variable_data_ -= rhs.variable_data_;
85✔
424
    return *this;
85✔
425
  }
426
  template <typename VT, bool VF>
427
  SPECTRE_ALWAYS_INLINE Variables& operator-=(
428
      const blaze::Vector<VT, VF>& rhs) {
429
    variable_data_ -= rhs;
11✔
430
    return *this;
11✔
431
  }
432

433
  SPECTRE_ALWAYS_INLINE Variables& operator*=(const value_type& rhs) {
434
    variable_data_ *= rhs;
150,709✔
435
    return *this;
150,709✔
436
  }
437

438
  SPECTRE_ALWAYS_INLINE Variables& operator/=(const value_type& rhs) {
439
    variable_data_ /= rhs;
17✔
440
    return *this;
17✔
441
  }
442

443
  template <typename... WrappedTags,
444
            Requires<tmpl2::flat_all<std::is_same_v<
445
                db::remove_all_prefixes<WrappedTags>,
446
                db::remove_all_prefixes<Tags>>...>::value> = nullptr>
447
  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator+(
448
      const Variables<tmpl::list<WrappedTags...>>& lhs, const Variables& rhs) {
449
    static_assert(
450
        (std::is_same_v<typename Tags::type, typename WrappedTags::type> and
451
         ...),
452
        "Tensor types do not match!");
453
    return lhs.get_variable_data() + rhs.variable_data_;
44✔
454
  }
455
  template <typename VT, bool VF>
456
  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator+(
457
      const blaze::DenseVector<VT, VF>& lhs, const Variables& rhs) {
458
    return *lhs + rhs.variable_data_;
40✔
459
  }
460
  template <typename VT, bool VF>
461
  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator+(
462
      const Variables& lhs, const blaze::DenseVector<VT, VF>& rhs) {
463
    return lhs.variable_data_ + *rhs;
28✔
464
  }
465

466
  template <typename... WrappedTags,
467
            Requires<tmpl2::flat_all<std::is_same_v<
468
                db::remove_all_prefixes<WrappedTags>,
469
                db::remove_all_prefixes<Tags>>...>::value> = nullptr>
470
  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator-(
471
      const Variables<tmpl::list<WrappedTags...>>& lhs, const Variables& rhs) {
472
    static_assert(
473
        (std::is_same_v<typename Tags::type, typename WrappedTags::type> and
474
         ...),
475
        "Tensor types do not match!");
476
    return lhs.get_variable_data() - rhs.variable_data_;
12,188✔
477
  }
478
  template <typename VT, bool VF>
479
  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator-(
480
      const blaze::DenseVector<VT, VF>& lhs, const Variables& rhs) {
481
    return *lhs - rhs.variable_data_;
48✔
482
  }
483
  template <typename VT, bool VF>
484
  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator-(
485
      const Variables& lhs, const blaze::DenseVector<VT, VF>& rhs) {
486
    return lhs.variable_data_ - *rhs;
16✔
487
  }
488

489
  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator*(const Variables& lhs,
490
                                                        const value_type& rhs) {
491
    return lhs.variable_data_ * rhs;
44✔
492
  }
493
  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator*(const value_type& lhs,
494
                                                        const Variables& rhs) {
495
    return lhs * rhs.variable_data_;
31,060✔
496
  }
497

498
  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator/(const Variables& lhs,
499
                                                        const value_type& rhs) {
500
    return lhs.variable_data_ / rhs;
8✔
501
  }
502

503
  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator-(const Variables& lhs) {
504
    return -lhs.variable_data_;
14✔
505
  }
506
  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator+(const Variables& lhs) {
507
    return lhs.variable_data_;
8✔
508
  }
509

510
 private:
511
  /// @{
512
  /*!
513
   * \brief Subscript operator
514
   *
515
   * The subscript operator is private since it should not be used directly.
516
   * Mathematical operations should be done using the math operators provided.
517
   * Since the internal ordering of variables is implementation defined there
518
   * is no safe way to perform any operation that is not a linear combination of
519
   * Variables. Retrieving a Tensor must be done via the `get()` function.
520
   *
521
   *  \requires `i >= 0 and i < size()`
522
   */
523
  SPECTRE_ALWAYS_INLINE value_type& operator[](const size_type i) {
524
    return variable_data_[i];
525
  }
526
  SPECTRE_ALWAYS_INLINE const value_type& operator[](const size_type i) const {
527
    return variable_data_[i];
528
  }
529
  /// @}
530

531
  void add_reference_variable_data();
532

533
  friend bool operator==(const Variables& lhs, const Variables& rhs) {
68,620✔
534
    return blaze::equal<blaze::strict>(lhs.variable_data_, rhs.variable_data_);
68,620✔
535
  }
536

537
  template <typename VT, bool TF>
538
  friend bool operator==(const Variables& lhs,
539
                         const blaze::DenseVector<VT, TF>& rhs) {
540
    return blaze::equal<blaze::strict>(lhs.variable_data_, *rhs);
541
  }
542

543
  template <typename VT, bool TF>
544
  friend bool operator==(const blaze::DenseVector<VT, TF>& lhs,
13✔
545
                         const Variables& rhs) {
546
    return blaze::equal<blaze::strict>(*lhs, rhs.variable_data_);
26✔
547
  }
548

549
  template <class FriendTags>
550
  friend class Variables;
551

552
  std::array<value_type, number_of_independent_components>
553
      variable_data_impl_static_;
554
  std::unique_ptr<value_type[]> variable_data_impl_dynamic_{};
555
  bool owning_{true};
556
  size_t size_ = 0;
557
  size_t number_of_grid_points_ = 0;
558

559
  pointer_type variable_data_;
560
  tuples::TaggedTuple<Tags...> reference_variable_data_;
561
};
562

563
// The above Variables implementation doesn't work for an empty parameter pack,
564
// so specialize here.
565
template <>
566
class Variables<tmpl::list<>> {
567
 public:
568
  using tags_list = tmpl::list<>;
569
  static constexpr size_t number_of_independent_components = 0;
570
  Variables() = default;
571
  explicit Variables(const size_t /*number_of_grid_points*/) {}
237✔
572
  template <typename T>
573
  Variables(const T* /*pointer*/, const size_t /*size*/) {}
384✔
574
  static constexpr size_t size() { return 0; }
575
};
576

577
// gcc8 screams when the empty Variables has pup as a member function, so we
578
// declare pup as a free function here.
579
// clang-tidy: runtime-references
580
SPECTRE_ALWAYS_INLINE void pup(
581
    PUP::er& /*p*/,                           // NOLINT
582
    Variables<tmpl::list<>>& /* unused */) {  // NOLINT
583
}
584
SPECTRE_ALWAYS_INLINE void operator|(
585
    PUP::er& /*p*/, Variables<tmpl::list<>>& /* unused */) {  // NOLINT
586
}
6✔
587

588
SPECTRE_ALWAYS_INLINE bool operator==(const Variables<tmpl::list<>>& /*lhs*/,
589
                                      const Variables<tmpl::list<>>& /*rhs*/) {
590
  return true;
2✔
591
}
592
SPECTRE_ALWAYS_INLINE bool operator!=(const Variables<tmpl::list<>>& /*lhs*/,
593
                                      const Variables<tmpl::list<>>& /*rhs*/) {
594
  return false;
595
}
596

597
inline std::ostream& operator<<(std::ostream& os,
1✔
598
                                const Variables<tmpl::list<>>& /*d*/) {
599
  return os << "{}";
1✔
600
}
601

602
template <typename... Tags>
603
Variables<tmpl::list<Tags...>>::Variables() {
489,794✔
604
  // This makes an assertion trigger if one tries to assign to
605
  // components of a default-constructed Variables.
606
  const auto set_refs = [](auto& var) {
764,451✔
607
    for (auto& dv : var) {
2,584,463✔
608
      dv.set_data_ref(nullptr, 0);
1,820,012✔
609
    }
610
    return 0;
764,451✔
611
  };
612
  (void)set_refs;
613
  expand_pack(set_refs(tuples::get<Tags>(reference_variable_data_))...);
489,794✔
614
}
489,794✔
615

616
template <typename... Tags>
617
Variables<tmpl::list<Tags...>>::Variables(const size_t number_of_grid_points) {
375,043✔
618
  initialize(number_of_grid_points);
375,043✔
619
}
375,043✔
620

621
template <typename... Tags>
622
Variables<tmpl::list<Tags...>>::Variables(const size_t number_of_grid_points,
56,282✔
623
                                          const value_type value) {
56,282✔
624
  initialize(number_of_grid_points, value);
56,282✔
625
}
56,282✔
626

627
template <typename... Tags>
628
void Variables<tmpl::list<Tags...>>::initialize(
868,558✔
629
    const size_t number_of_grid_points) {
630
  if (number_of_grid_points_ == 0) {
868,558✔
631
    variable_data_impl_dynamic_.reset();
820,848✔
632
    size_ = 0;
820,848✔
633
    number_of_grid_points_ = 0;
820,848✔
634
  }
635
  if (number_of_grid_points_ == number_of_grid_points) {
868,558✔
636
    return;
48,611✔
637
  }
638
  if (UNLIKELY(not is_owning())) {
819,947✔
639
    ERROR("Variables::initialize cannot be called on a non-owning Variables.  "
×
640
          "This likely happened because of an attempted resize.  The current "
641
          "number of grid points is " << number_of_grid_points_ << " and the "
642
          "requested number is " << number_of_grid_points << ".");
643
  }
644
  number_of_grid_points_ = number_of_grid_points;
819,947✔
645
  size_ = number_of_grid_points * number_of_independent_components;
819,947✔
646
  if (size_ > 0) {
819,947✔
647
    if (number_of_grid_points_ == 1) {
819,693✔
648
      variable_data_impl_dynamic_.reset();
17,189✔
649
    } else {
650
      variable_data_impl_dynamic_ =
802,504✔
651
          cpp20::make_unique_for_overwrite<value_type[]>(size_);
652
    }
653
    add_reference_variable_data();
819,693✔
654
#if defined(SPECTRE_DEBUG) || defined(SPECTRE_NAN_INIT)
655
    std::fill(variable_data_.data(), variable_data_.data() + size_,
819,693✔
656
              make_signaling_NaN<value_type>());
1,639,386✔
657
#endif  // SPECTRE_DEBUG
658
  }
659
}
660

661
template <typename... Tags>
662
void Variables<tmpl::list<Tags...>>::initialize(
63,592✔
663
    const size_t number_of_grid_points, const value_type value) {
664
  initialize(number_of_grid_points);
63,592✔
665
  std::fill(variable_data_.data(), variable_data_.data() + size_, value);
63,592✔
666
}
63,592✔
667

668
/// \cond HIDDEN_SYMBOLS
669
template <typename... Tags>
670
Variables<tmpl::list<Tags...>>::Variables(
168,545✔
671
    const Variables<tmpl::list<Tags...>>& rhs) {
168,545✔
672
  initialize(rhs.number_of_grid_points());
168,545✔
673
  variable_data_ =
168,545✔
674
      static_cast<const blaze::Vector<pointer_type, transpose_flag>&>(
675
          rhs.variable_data_);
168,545✔
676
}
168,545✔
677

678
template <typename... Tags>
679
Variables<tmpl::list<Tags...>>& Variables<tmpl::list<Tags...>>::operator=(
32,521✔
680
    const Variables<tmpl::list<Tags...>>& rhs) {
681
  if (&rhs == this) {
32,521✔
682
    return *this;
5✔
683
  }
684
  initialize(rhs.number_of_grid_points());
32,516✔
685
  variable_data_ =
32,516✔
686
      static_cast<const blaze::Vector<pointer_type, transpose_flag>&>(
687
          rhs.variable_data_);
32,516✔
688
  return *this;
32,516✔
689
}
690

691
template <typename... Tags>
692
Variables<tmpl::list<Tags...>>::Variables(Variables<tmpl::list<Tags...>>&& rhs)
636,219✔
693
    : variable_data_impl_dynamic_(std::move(rhs.variable_data_impl_dynamic_)),
636,219✔
694
      owning_(rhs.owning_),
636,219✔
695
      size_(rhs.size()),
696
      number_of_grid_points_(rhs.number_of_grid_points()),
697
      variable_data_(std::move(rhs.variable_data_)) {
1,908,657✔
698
  if (number_of_grid_points_ == 1) {
636,219✔
699
#if defined(__GNUC__) and not defined(__clang__)
700
#pragma GCC diagnostic push
701
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
702
#endif  // defined(__GNUC__) and not defined(__clang__)
703
    variable_data_impl_static_ = std::move(rhs.variable_data_impl_static_);
7,693✔
704
#if defined(__GNUC__) and not defined(__clang__)
705
#pragma GCC diagnostic pop
706
#endif  // defined(__GNUC__) and not defined(__clang__)
707
  }
708
  rhs.variable_data_impl_dynamic_.reset();
636,219✔
709
  rhs.owning_ = true;
636,219✔
710
  rhs.size_ = 0;
636,219✔
711
  rhs.number_of_grid_points_ = 0;
636,219✔
712
  add_reference_variable_data();
636,219✔
713
}
636,219✔
714

715
template <typename... Tags>
716
Variables<tmpl::list<Tags...>>& Variables<tmpl::list<Tags...>>::operator=(
140,481✔
717
    Variables<tmpl::list<Tags...>>&& rhs) {
718
  if (this == &rhs) {
140,481✔
719
    return *this;
8✔
720
  }
721
  owning_ = rhs.owning_;
140,473✔
722
  size_ = rhs.size_;
140,473✔
723
  number_of_grid_points_ = std::move(rhs.number_of_grid_points_);
140,473✔
724
  variable_data_ = std::move(rhs.variable_data_);
140,473✔
725
  variable_data_impl_dynamic_ = std::move(rhs.variable_data_impl_dynamic_);
140,473✔
726
  if (number_of_grid_points_ == 1) {
140,473✔
727
#if defined(__GNUC__) and not defined(__clang__)
728
#pragma GCC diagnostic push
729
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
730
#endif  // defined(__GNUC__) and not defined(__clang__)
731
    variable_data_impl_static_ = std::move(rhs.variable_data_impl_static_);
1,265✔
732
#if defined(__GNUC__) and not defined(__clang__)
733
#pragma GCC diagnostic pop
734
#endif  // defined(__GNUC__) and not defined(__clang__)
735
  }
736

737
  rhs.variable_data_impl_dynamic_.reset();
140,473✔
738
  rhs.owning_ = true;
140,473✔
739
  rhs.size_ = 0;
140,473✔
740
  rhs.number_of_grid_points_ = 0;
140,473✔
741
  add_reference_variable_data();
140,473✔
742
  return *this;
140,473✔
743
}
744

745
template <typename... Tags>
746
template <typename... WrappedTags,
747
          Requires<tmpl2::flat_all<
748
              std::is_same<db::remove_all_prefixes<WrappedTags>,
749
                           db::remove_all_prefixes<Tags>>::value...>::value>>
750
Variables<tmpl::list<Tags...>>::Variables(
166✔
751
    const Variables<tmpl::list<WrappedTags...>>& rhs) {
166✔
752
  static_assert(
753
      (std::is_same_v<typename Tags::type, typename WrappedTags::type> and ...),
754
      "Tensor types do not match!");
755
  initialize(rhs.number_of_grid_points());
166✔
756
  variable_data_ =
166✔
757
      static_cast<const blaze::Vector<pointer_type, transpose_flag>&>(
758
          rhs.variable_data_);
166✔
759
}
166✔
760

761
template <typename... Tags>
762
template <typename... WrappedTags,
763
          Requires<tmpl2::flat_all<
764
              std::is_same<db::remove_all_prefixes<WrappedTags>,
765
                           db::remove_all_prefixes<Tags>>::value...>::value>>
766
Variables<tmpl::list<Tags...>>& Variables<tmpl::list<Tags...>>::operator=(
206✔
767
    const Variables<tmpl::list<WrappedTags...>>& rhs) {
768
  static_assert(
769
      (std::is_same_v<typename Tags::type, typename WrappedTags::type> and ...),
770
      "Tensor types do not match!");
771
  initialize(rhs.number_of_grid_points());
206✔
772
  variable_data_ =
206✔
773
      static_cast<const blaze::Vector<pointer_type, transpose_flag>&>(
774
          rhs.variable_data_);
206✔
775
  return *this;
206✔
776
}
777

778
template <typename... Tags>
779
template <typename... WrappedTags,
780
          Requires<tmpl2::flat_all<
781
              std::is_same<db::remove_all_prefixes<WrappedTags>,
782
                           db::remove_all_prefixes<Tags>>::value...>::value>>
783
Variables<tmpl::list<Tags...>>::Variables(
82,755✔
784
    Variables<tmpl::list<WrappedTags...>>&& rhs)
785
    : variable_data_impl_dynamic_(std::move(rhs.variable_data_impl_dynamic_)),
82,755✔
786
      owning_(rhs.owning_),
82,755✔
787
      size_(rhs.size()),
788
      number_of_grid_points_(rhs.number_of_grid_points()),
789
      variable_data_(std::move(rhs.variable_data_)) {
248,265✔
790
  static_assert(
791
      (std::is_same_v<typename Tags::type, typename WrappedTags::type> and ...),
792
      "Tensor types do not match!");
793
  if (number_of_grid_points_ == 1) {
82,755✔
794
#if defined(__GNUC__) and not defined(__clang__)
795
#pragma GCC diagnostic push
796
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
797
#endif  // defined(__GNUC__) and not defined(__clang__)
798
    variable_data_impl_static_ = std::move(rhs.variable_data_impl_static_);
1,060✔
799
#if defined(__GNUC__) and not defined(__clang__)
800
#pragma GCC diagnostic pop
801
#endif  // defined(__GNUC__) and not defined(__clang__)
802
  }
803
  rhs.variable_data_impl_dynamic_.reset();
82,755✔
804
  rhs.size_ = 0;
82,755✔
805
  rhs.owning_ = true;
82,755✔
806
  rhs.number_of_grid_points_ = 0;
82,755✔
807
  add_reference_variable_data();
82,755✔
808
}
82,755✔
809

810
template <typename... Tags>
811
template <typename... WrappedTags,
812
          Requires<tmpl2::flat_all<
813
              std::is_same<db::remove_all_prefixes<WrappedTags>,
814
                           db::remove_all_prefixes<Tags>>::value...>::value>>
815
Variables<tmpl::list<Tags...>>& Variables<tmpl::list<Tags...>>::operator=(
1,343✔
816
    Variables<tmpl::list<WrappedTags...>>&& rhs) {
817
  static_assert(
818
      (std::is_same_v<typename Tags::type, typename WrappedTags::type> and ...),
819
      "Tensor types do not match!");
820
  variable_data_ = std::move(rhs.variable_data_);
1,343✔
821
  owning_ = rhs.owning_;
1,343✔
822
  size_ = rhs.size_;
1,343✔
823
  number_of_grid_points_ = std::move(rhs.number_of_grid_points_);
1,343✔
824
  variable_data_impl_dynamic_ = std::move(rhs.variable_data_impl_dynamic_);
1,343✔
825
  if (number_of_grid_points_ == 1) {
1,343✔
826
#if defined(__GNUC__) and not defined(__clang__)
827
#pragma GCC diagnostic push
828
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
829
#endif  // defined(__GNUC__) and not defined(__clang__)
830
    variable_data_impl_static_ = std::move(rhs.variable_data_impl_static_);
×
831
#if defined(__GNUC__) and not defined(__clang__)
832
#pragma GCC diagnostic pop
833
#endif  // defined(__GNUC__) and not defined(__clang__)
834
  }
835

836
  rhs.variable_data_impl_dynamic_.reset();
1,343✔
837
  rhs.size_ = 0;
1,343✔
838
  rhs.owning_ = true;
1,343✔
839
  rhs.number_of_grid_points_ = 0;
1,343✔
840
  add_reference_variable_data();
1,343✔
841
  return *this;
1,343✔
842
}
843

844
template <typename... Tags>
845
Variables<tmpl::list<Tags...>>::Variables(const pointer start,
42,035✔
846
                                          const size_t size) {
42,035✔
847
  set_data_ref(start, size);
42,035✔
848
}
42,035✔
849

850
template <typename... Tags>
851
void Variables<tmpl::list<Tags...>>::pup(PUP::er& p) {
200,811✔
852
  ASSERT(
200,811✔
853
      owning_,
854
      "Cannot pup a non-owning Variables! It may be reasonable to pack a "
855
      "non-owning Variables, but not to unpack one. This should be discussed "
856
      "in an issue with the core devs if the feature seems necessary.");
857
  size_t number_of_grid_points = number_of_grid_points_;
200,811✔
858
  p | number_of_grid_points;
200,811✔
859
  if (p.isUnpacking()) {
200,811✔
860
    initialize(number_of_grid_points);
66,937✔
861
  }
862
  PUParray(p, variable_data_.data(), size_);
200,811✔
863
}
200,811✔
864
/// \endcond
865

866
/// @{
867
/*!
868
 * \ingroup DataStructuresGroup
869
 * \brief Return Tag::type pointing into the contiguous array
870
 *
871
 * \tparam Tag the variable to return
872
 */
873
template <typename Tag, typename TagList>
874
constexpr typename Tag::type& get(Variables<TagList>& v) {
2,246,262✔
875
  static_assert(tmpl::list_contains_v<TagList, Tag>,
876
                "Could not retrieve Tag from Variables. See the first "
877
                "template parameter of the instantiation for what Tag is "
878
                "being retrieved and the second template parameter for "
879
                "what Tags are available.");
880
  return tuples::get<Tag>(v.reference_variable_data_);
2,246,262✔
881
}
882
template <typename Tag, typename TagList>
883
constexpr const typename Tag::type& get(const Variables<TagList>& v) {
1,471,943✔
884
  static_assert(tmpl::list_contains_v<TagList, Tag>,
885
                "Could not retrieve Tag from Variables. See the first "
886
                "template parameter of the instantiation for what Tag is "
887
                "being retrieved and the second template parameter for "
888
                "what Tags are available.");
889
  return tuples::get<Tag>(v.reference_variable_data_);
1,471,943✔
890
}
891
/// @}
892

893
template <typename... Tags>
894
template <typename VT, bool VF>
895
Variables<tmpl::list<Tags...>>::Variables(
31,038✔
896
    const blaze::DenseVector<VT, VF>& expression) {
31,041✔
897
  ASSERT((*expression).size() % number_of_independent_components == 0,
31,040✔
898
         "Invalid size " << (*expression).size() << " for a Variables with "
899
         << number_of_independent_components << " components.");
900
  initialize((*expression).size() / number_of_independent_components);
31,037✔
901
  variable_data_ = expression;
31,037✔
902
}
31,037✔
903

904
/// \cond
905
template <typename... Tags>
906
template <typename VT, bool VF>
907
Variables<tmpl::list<Tags...>>& Variables<tmpl::list<Tags...>>::operator=(
9✔
908
    const blaze::DenseVector<VT, VF>& expression) {
909
  ASSERT((*expression).size() % number_of_independent_components == 0,
11✔
910
         "Invalid size " << (*expression).size() << " for a Variables with "
911
         << number_of_independent_components << " components.");
912
  initialize((*expression).size() / number_of_independent_components);
8✔
913
  variable_data_ = expression;
8✔
914
  return *this;
8✔
915
}
916
/// \endcond
917

918
/// \cond HIDDEN_SYMBOLS
919
template <typename... Tags>
920
void Variables<tmpl::list<Tags...>>::add_reference_variable_data() {
1,772,269✔
921
  if (size_ == 0) {
1,772,269✔
922
    return;
46,993✔
923
  }
924
  if (is_owning()) {
1,725,276✔
925
    if (number_of_grid_points_ == 1) {
1,633,474✔
926
      variable_data_.reset(variable_data_impl_static_.data(), size_);
27,205✔
927
    } else {
928
      variable_data_.reset(variable_data_impl_dynamic_.get(), size_);
1,606,269✔
929
    }
930
  }
931
  ASSERT(variable_data_.size() == size_ and
1,725,276✔
932
             size_ == number_of_grid_points_ * number_of_independent_components,
933
         "Size mismatch: variable_data_.size() = "
934
             << variable_data_.size() << " size_ = " << size_ << " should be: "
935
             << number_of_grid_points_ * number_of_independent_components
936
             << "\nThis is an internal inconsistency bug in Variables. Please "
937
                "file an issue.");
938
  size_t variable_offset = 0;
1,725,276✔
939
  tmpl::for_each<tags_list>([this, &variable_offset](auto tag_v) {
16,191,712✔
940
    using Tag = tmpl::type_from<decltype(tag_v)>;
941
    auto& var = tuples::get<Tag>(reference_variable_data_);
3,548,514✔
942
    for (size_t i = 0; i < Tag::type::size(); ++i) {
21,911,306✔
943
      var[i].set_data_ref(
7,407,145✔
944
          &variable_data_[variable_offset++ * number_of_grid_points_],
945
          number_of_grid_points_);
946
    }
947
  });
948
}
949
/// \endcond
950

951
template <typename... Tags>
952
Variables<tmpl::list<Tags...>>& operator*=(
125,917✔
953
    Variables<tmpl::list<Tags...>>& lhs,
954
    const typename Variables<tmpl::list<Tags...>>::vector_type& rhs) {
955
  using value_type = typename Variables<tmpl::list<Tags...>>::value_type;
956
  ASSERT(lhs.number_of_grid_points() == rhs.size(),
125,917✔
957
         "Size mismatch in multiplication: " << lhs.number_of_grid_points()
958
                                             << " and " << rhs.size());
959
  value_type* const lhs_data = lhs.data();
125,917✔
960
  const value_type* const rhs_data = rhs.data();
125,917✔
961
  for (size_t c = 0; c < lhs.number_of_independent_components; ++c) {
340,629✔
962
    for (size_t s = 0; s < lhs.number_of_grid_points(); ++s) {
2,401,500✔
963
      // clang-tidy: do not use pointer arithmetic
964
      lhs_data[c * lhs.number_of_grid_points() + s] *= rhs_data[s];  // NOLINT
1,972,076✔
965
    }
966
  }
967
  return lhs;
125,917✔
968
}
969

970
template <typename... Tags>
971
Variables<tmpl::list<Tags...>> operator*(
4✔
972
    const Variables<tmpl::list<Tags...>>& lhs,
973
    const typename Variables<tmpl::list<Tags...>>::vector_type& rhs) {
974
  auto result = lhs;
4✔
975
  result *= rhs;
4✔
976
  return result;
4✔
977
}
978

979
template <typename... Tags>
980
Variables<tmpl::list<Tags...>> operator*(
4✔
981
    const typename Variables<tmpl::list<Tags...>>::vector_type& lhs,
982
    const Variables<tmpl::list<Tags...>>& rhs) {
983
  auto result = rhs;
4✔
984
  result *= lhs;
4✔
985
  return result;
4✔
986
}
987

988
template <typename... Tags>
989
Variables<tmpl::list<Tags...>>& operator/=(
10,631✔
990
    Variables<tmpl::list<Tags...>>& lhs,
991
    const typename Variables<tmpl::list<Tags...>>::vector_type& rhs) {
992
  ASSERT(lhs.number_of_grid_points() == rhs.size(),
10,631✔
993
         "Size mismatch in multiplication: " << lhs.number_of_grid_points()
994
                                             << " and " << rhs.size());
995
  using value_type = typename Variables<tmpl::list<Tags...>>::value_type;
996
  value_type* const lhs_data = lhs.data();
10,631✔
997
  const value_type* const rhs_data = rhs.data();
10,631✔
998
  for (size_t c = 0; c < lhs.number_of_independent_components; ++c) {
24,598✔
999
    for (size_t s = 0; s < lhs.number_of_grid_points(); ++s) {
310,682✔
1000
      // clang-tidy: do not use pointer arithmetic
1001
      lhs_data[c * lhs.number_of_grid_points() + s] /= rhs_data[s];  // NOLINT
282,748✔
1002
    }
1003
  }
1004
  return lhs;
10,631✔
1005
}
1006

1007
template <typename... Tags>
1008
Variables<tmpl::list<Tags...>> operator/(
4✔
1009
    const Variables<tmpl::list<Tags...>>& lhs,
1010
    const typename Variables<tmpl::list<Tags...>>::vector_type& rhs) {
1011
  auto result = lhs;
4✔
1012
  result /= rhs;
4✔
1013
  return result;
4✔
1014
}
1015

1016
template <typename... Tags, Requires<sizeof...(Tags) != 0> = nullptr>
1017
std::ostream& operator<<(std::ostream& os,
4,471✔
1018
                         const Variables<tmpl::list<Tags...>>& d) {
1019
  size_t count = 0;
4,471✔
1020
  const auto helper = [&os, &d, &count](auto tag_v) {
12,635✔
1021
    count++;
8,527✔
1022
    using Tag = typename decltype(tag_v)::type;
1023
    os << db::tag_name<Tag>() << ":\n";
8,527✔
1024
    os << get<Tag>(d);
8,527✔
1025
    if (count < sizeof...(Tags)) {
8,527✔
1026
      os << "\n\n";
4,056✔
1027
    }
1028
  };
1029
  EXPAND_PACK_LEFT_TO_RIGHT(helper(tmpl::type_<Tags>{}));
4,471✔
1030
  return os;
4,471✔
1031
}
1032

1033
template <typename TagsList>
1034
bool operator!=(const Variables<TagsList>& lhs,
52✔
1035
                const Variables<TagsList>& rhs) {
1036
  return not(lhs == rhs);
52✔
1037
}
1038

1039
template <typename... TagsLhs, typename... TagsRhs,
1040
          Requires<not std::is_same<tmpl::list<TagsLhs...>,
1041
                                    tmpl::list<TagsRhs...>>::value> = nullptr>
1042
void swap(Variables<tmpl::list<TagsLhs...>>& lhs,
591✔
1043
          Variables<tmpl::list<TagsRhs...>>& rhs) {
1044
  Variables<tmpl::list<TagsLhs...>> temp{std::move(lhs)};
1,182✔
1045
  lhs = std::move(rhs);
591✔
1046
  rhs = std::move(temp);
591✔
1047
}
591✔
1048

1049
/// \ingroup DataStructuresGroup
1050
/// Construct a variables from the `Tensor`s in a `TaggedTuple`.
1051
template <typename... Tags>
1052
Variables<tmpl::list<Tags...>> variables_from_tagged_tuple(
6,100✔
1053
    const tuples::TaggedTuple<Tags...>& tuple) {
1054
  auto result = make_with_value<Variables<tmpl::list<Tags...>>>(
1055
      get<tmpl::front<tmpl::list<Tags...>>>(tuple), 0.0);
6,100✔
1056
  result.assign_subset(tuple);
6,100✔
1057
  return result;
6,100✔
1058
}
1059

1060
namespace MakeWithValueImpls {
1061
template <typename TagList>
1062
struct MakeWithSize<Variables<TagList>> {
1063
  static SPECTRE_ALWAYS_INLINE Variables<TagList> apply(
1064
      const size_t size, const typename Variables<TagList>::value_type value) {
1065
    return Variables<TagList>(size, value);
11,168✔
1066
  }
1067
};
1068

1069
template <typename TagList>
1070
struct NumberOfPoints<Variables<TagList>> {
1071
  static SPECTRE_ALWAYS_INLINE size_t apply(const Variables<TagList>& input) {
1072
    return input.number_of_grid_points();
1,745✔
1073
  }
1074
};
1075
}  // namespace MakeWithValueImpls
1076

1077
namespace EqualWithinRoundoffImpls {
1078
// It would be nice to use `blaze::equal` in these implementations, but it
1079
// doesn't currently allow to specify a tolerance. See upstream issue:
1080
// https://bitbucket.org/blaze-lib/blaze/issues/417/adjust-relaxed-equal-accuracy
1081
template <typename TagList, typename Floating>
1082
struct EqualWithinRoundoffImpl<Variables<TagList>, Floating,
1083
                               Requires<std::is_floating_point_v<Floating>>> {
1084
  static bool apply(const Variables<TagList>& lhs, const Floating& rhs,
3,612✔
1085
                    const double eps, const double scale) {
1086
    for (size_t i = 0; i < lhs.size(); ++i) {
86,612✔
1087
      if (not equal_within_roundoff(lhs.data()[i], rhs, eps, scale)) {
83,790✔
1088
        return false;
2,201✔
1089
      }
1090
    }
1091
    return true;
1,411✔
1092
  }
1093
};
1094
template <typename TagList, typename Floating>
1095
struct EqualWithinRoundoffImpl<Floating, Variables<TagList>,
1096
                               Requires<std::is_floating_point_v<Floating>>> {
1097
  static SPECTRE_ALWAYS_INLINE bool apply(const Floating& lhs,
1098
                                          const Variables<TagList>& rhs,
1099
                                          const double eps,
1100
                                          const double scale) {
1101
    return equal_within_roundoff(rhs, lhs, eps, scale);
8✔
1102
  }
1103
};
1104
template <typename LhsTagList, typename RhsTagList>
1105
struct EqualWithinRoundoffImpl<Variables<LhsTagList>, Variables<RhsTagList>> {
1106
  static bool apply(const Variables<LhsTagList>& lhs,
16✔
1107
                    const Variables<RhsTagList>& rhs, const double eps,
1108
                    const double scale) {
1109
    ASSERT(lhs.size() == rhs.size(),
32✔
1110
           "Can only compare two Variables of the same size, but lhs has size "
1111
               << lhs.size() << " and rhs has size " << rhs.size() << ".");
1112
    for (size_t i = 0; i < lhs.size(); ++i) {
228✔
1113
      if (not equal_within_roundoff(lhs.data()[i], rhs.data()[i], eps, scale)) {
212✔
1114
        return false;
8✔
1115
      }
1116
    }
1117
    return true;
8✔
1118
  }
1119
};
1120
}  // namespace EqualWithinRoundoffImpls
1121

1122
namespace db {
1123
// Enable subitems for ::Tags::Variables and derived tags (e.g. compute tags).
1124
// Other tags that hold a `Variables` don't expose the constituent tensors as
1125
// subitems by default.
1126
namespace Variables_detail {
1127
// Check if the argument is a `::Tags::Variables`, or derived from it. Can't use
1128
// `tt:is_a_v` because we also want to match derived classes. Can't use
1129
// `std::is_base_of` because `::Tags::Variables` is a template.
1130
template <typename TagsList>
1131
constexpr std::true_type is_a_variables_tag(::Tags::Variables<TagsList>&&) {
1132
  return {};
1133
}
1134
constexpr std::false_type is_a_variables_tag(...) { return {}; }
1135
template <typename Tag>
1136
static constexpr bool is_a_variables_tag_v =
1137
    decltype(is_a_variables_tag(std::declval<Tag>()))::value;
1138
}  // namespace Variables_detail
1139
template <typename Tag>
1140
struct Subitems<Tag, Requires<Variables_detail::is_a_variables_tag_v<Tag>>> {
1141
  using type = typename Tag::type::tags_list;
1142

1143
  template <typename Subtag, typename LocalTag = Tag>
1144
  static void create_item(
69,476✔
1145
      const gsl::not_null<typename LocalTag::type*> parent_value,
1146
      const gsl::not_null<typename Subtag::type*> sub_value) {
1147
    auto& vars = get<Subtag>(*parent_value);
69,476✔
1148
    // Only update the Tensor if the Variables has changed its allocation
1149
    if constexpr (not is_any_spin_weighted_v<typename Subtag::type::type>) {
1150
      if (vars.begin()->data() != sub_value->begin()->data()) {
64,506✔
1151
        for (auto vars_it = vars.begin(), sub_var_it = sub_value->begin();
66,246✔
1152
             vars_it != vars.end(); ++vars_it, ++sub_var_it) {
66,246✔
1153
          sub_var_it->set_data_ref(make_not_null(&*vars_it));
39,241✔
1154
        }
1155
      }
1156
    } else {
1157
      if (vars.begin()->data().data() != sub_value->begin()->data().data()) {
4,970✔
1158
        for (auto vars_it = vars.begin(), sub_var_it = sub_value->begin();
6,582✔
1159
             vars_it != vars.end(); ++vars_it, ++sub_var_it) {
6,582✔
1160
          sub_var_it->set_data_ref(make_not_null(&*vars_it));
3,291✔
1161
        }
1162
      }
1163
    }
1164
  }
69,476✔
1165

1166
  template <typename Subtag>
1167
  static const typename Subtag::type& create_compute_item(
443✔
1168
      const typename Tag::type& parent_value) {
1169
    return get<Subtag>(parent_value);
443✔
1170
  }
1171
};
1172
}  // namespace db
1173

1174
namespace Variables_detail {
1175
template <typename Tags>
1176
using MathWrapperVectorType = tmpl::conditional_t<
1177
    std::is_same_v<typename Variables<Tags>::value_type, double>, DataVector,
1178
    ComplexDataVector>;
1179
}  // namespace Variables_detail
1180

1181
template <typename Tags>
1182
auto make_math_wrapper(const gsl::not_null<Variables<Tags>*> data) {
408✔
1183
  using Vector = Variables_detail::MathWrapperVectorType<Tags>;
1184
  Vector referencing(data->data(), data->size());
816✔
1185
  return make_math_wrapper(&referencing);
816✔
1186
}
1187

1188
template <typename Tags>
1189
auto make_math_wrapper(const Variables<Tags>& data) {
1,630✔
1190
  using Vector = Variables_detail::MathWrapperVectorType<Tags>;
1191
  const Vector referencing(
3,260✔
1192
      const_cast<typename Vector::value_type*>(data.data()), data.size());
1,630✔
1193
  return make_math_wrapper(referencing);
3,260✔
1194
}
1195

1196
/// \cond
1197
template <size_t I, class... Tags>
1198
inline constexpr typename tmpl::at_c<tmpl::list<Tags...>, I>::type&& get(
1199
    Variables<tmpl::list<Tags...>>&& t) {
1200
  return get<tmpl::at_c<tmpl::list<Tags...>, I>>(t);
1201
}
1202

1203
template <size_t I, class... Tags>
1204
inline constexpr const typename tmpl::at_c<tmpl::list<Tags...>, I>::type& get(
36✔
1205
    const Variables<tmpl::list<Tags...>>& t) {
1206
  return get<tmpl::at_c<tmpl::list<Tags...>, I>>(t);
36✔
1207
}
1208

1209
template <size_t I, class... Tags>
1210
inline constexpr typename tmpl::at_c<tmpl::list<Tags...>, I>::type& get(
503✔
1211
    Variables<tmpl::list<Tags...>>& t) {
1212
  return get<tmpl::at_c<tmpl::list<Tags...>, I>>(t);
503✔
1213
}
1214
/// \endcond
1215

1216
namespace std {
1217
template <typename... Tags>
1218
struct tuple_size<Variables<tmpl::list<Tags...>>>
1219
    : std::integral_constant<int, sizeof...(Tags)> {};
1220
template <size_t I, typename... Tags>
1221
struct tuple_element<I, Variables<tmpl::list<Tags...>>> {
1222
  using type = typename tmpl::at_c<tmpl::list<Tags...>, I>::type;
1223
};
1224
}  // namespace std
1225

1226
template <typename TagsList>
1227
bool contains_allocations(const Variables<TagsList>& value) {
8,438✔
1228
  return value.number_of_grid_points() > 1;
8,438✔
1229
}
1230

1231
inline bool contains_allocations(const Variables<tmpl::list<>>& /*value*/) {
1✔
1232
  return false;
1✔
1233
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc