Variables.hpp
Go to the documentation of this file.
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 <cstdlib>
11 #include <limits>
12 #include <memory>
13 #include <ostream>
14 #include <pup.h>
15 #include <string>
16 
19 #include "DataStructures/DataVector.hpp"
23 #include "ErrorHandling/Assert.hpp"
25 #include "Utilities/Gsl.hpp"
26 #include "Utilities/MakeSignalingNan.hpp"
27 #include "Utilities/PrettyType.hpp"
28 #include "Utilities/Requires.hpp"
29 #include "Utilities/TMPL.hpp"
31 #include "Utilities/TypeTraits.hpp"
32 
33 // IWYU pragma: no_forward_declare MakeWithValueImpl
34 // IWYU pragma: no_forward_declare Variables
35 
36 /// \cond
37 template <typename X, typename Symm, typename IndexList>
38 class Tensor;
39 
40 template <typename TagsList>
41 class Variables;
42 /// \endcond
43 
44 namespace Tags {
45 template <typename TagsList>
48  "The TagsList passed to Tags::Variables is not a typelist");
49  using tags_list = TagsList;
51  static std::string name() noexcept {
52  std::string tag_name{"Variables("};
53  size_t iter = 0;
54  tmpl::for_each<TagsList>([&tag_name, &iter ](auto tag) noexcept {
55  tag_name += tmpl::type_from<decltype(tag)>::name();
56  if (iter + 1 != tmpl::size<TagsList>::value) {
57  tag_name += ",";
58  }
59  iter++;
60  });
61  return tag_name + ")";
62  }
63 };
64 } // namespace Tags
65 
66 /*!
67  * \ingroup DataStructuresGroup
68  * \brief A Variables holds a contiguous memory block with Tensors pointing
69  * into it.
70  *
71  * The `Tags` are `struct`s that must have a public type alias `type` whose
72  * value must be a `Tensor<DataVector, ...>`, a `static' method `name()` that
73  * returns a `std::string` of the tag name, and must derive off of
74  * `db::SimpleTag`. In general, they should be DataBoxTags that are not compute
75  * items. For example,
76  *
77  * \snippet Test_Variables.cpp simple_variables_tag
78  *
79  * Prefix tags can also be stored and their format is:
80  *
81  * \snippet Test_Variables.cpp prefix_variables_tag
82  *
83  * #### Design Decisions
84  *
85  * The `Variables` class is designed to hold several different `Tensor`s
86  * performing one memory allocation for all the `Tensor`s. The advantage is that
87  * memory allocations are quite expensive, especially in a parallel environment.
88  *
89  * `Variables` stores the data it owns in a `std::unique_ptr<double[],
90  * decltype(&free)>` instead of a `std::vector` because allocating the
91  * `unique_ptr` with `malloc` allows us to avoid initializing the memory
92  * completely in release mode when no value is passed to the constructor.
93  * Additionally, if the macro `SPECTRE_NAN_INIT` is defined, initialization with
94  * `NaN`s is done even in release mode.
95  */
96 template <typename... Tags>
97 class Variables<tmpl::list<Tags...>> {
98  public:
99  using size_type = size_t;
101  static constexpr auto transpose_flag = blaze::defaultTransposeFlag;
102 
103  /// A typelist of the Tags whose variables are held
104  using tags_list = tmpl::list<Tags...>;
105  static_assert(sizeof...(Tags) > 0,
106  "You must provide at least one tag to the Variables "
107  "for type inference");
108 
109  static_assert(
111  cpp17::is_same_v<typename Tags::type::type,
112  typename tmpl::front<tags_list>::type::type>...> or
113  tmpl2::flat_all_v<is_spin_weighted_of_same_type_v<
114  typename tmpl::front<tags_list>::type::type,
115  typename Tags::type::type>...>),
116  "All tensors stored in a single Variables must "
117  "have the same internal storage type.");
118 
119  static_assert(
122  "The tensor stored in a Variables must have as member `type` "
123  "a vector with a member `value_type` (e.g. Tensors of doubles are "
124  "disallowed, use instead a Tensor of DataVectors).");
125 
126  using vector_type = tmpl::conditional_t<
127  is_any_spin_weighted_v<typename tmpl::front<tags_list>::type::value_type>,
128  typename tmpl::front<tags_list>::type::type::value_type,
129  typename tmpl::front<tags_list>::type::type>;
130  using value_type = typename vector_type::value_type;
132  using pointer_type =
133  PointerVector<value_type, blaze::unaligned, blaze::unpadded,
134  transpose_flag,
135  blaze::DynamicVector<value_type, transpose_flag>>;
136 
137  static_assert(
138  cpp17::is_fundamental_v<value_type> or
139  tt::is_a_v<std::complex, value_type>,
140  "`value_type` of the Variables (so the storage type of the vector type "
141  "within the tensors in the Variables) must be either a fundamental type "
142  "or a std::complex. If this constraint is relaxed, the value_type "
143  "should be handled differently in the Variables, including pass by "
144  "reference.");
145 
146  /// The number of variables of the Variables object is holding. E.g.
147  /// \f$\psi_{ab}\f$ would be counted as one variable.
148  static constexpr auto number_of_variables = sizeof...(Tags);
149 
150  /// \cond
151  // If you encounter an error of the `size()` function not existing you are
152  // not filling the Variables with Tensors. Variables can be generalized to
153  // holding containers other than Tensor by having the containers have a
154  // `size()` function that in most cases should return 1. For Tensors the
155  // `size()` function returns the number of independent components.
156  template <typename State, typename Element>
157  struct number_of_independent_components_helper {
158  using type =
159  typename tmpl::plus<State, tmpl::int32_t<Element::type::size()>>::type;
160  };
161  /// \endcond
162 
163  /// The total number of independent components of all the variables. E.g.
164  /// a rank-2 symmetric spacetime Tensor \f$\psi_{ab}\f$ in 3 spatial
165  /// dimensions would have 10 independent components.
166  static constexpr size_t number_of_independent_components =
167  tmpl::fold<tmpl::list<Tags...>, tmpl::int32_t<0>,
168  number_of_independent_components_helper<
169  tmpl::_state, tmpl::_element>>::value;
170 
171  /// Default construct an empty Variables class, Charm++ needs this
172  Variables() noexcept;
173 
174  explicit Variables(size_t number_of_grid_points) noexcept;
175 
176  Variables(size_t number_of_grid_points, value_type value) noexcept;
177 
178  Variables(Variables&& rhs) noexcept = default;
179  Variables& operator=(Variables&& rhs) noexcept;
180 
181  Variables(const Variables& rhs) noexcept;
182  Variables& operator=(const Variables& rhs) noexcept;
183 
184  // @{
185  /// Copy and move semantics for wrapped variables
186  template <typename... WrappedTags,
187  Requires<tmpl2::flat_all_v<std::is_same<
188  db::remove_all_prefixes<WrappedTags>,
189  db::remove_all_prefixes<Tags>>::value...>> = nullptr>
190  explicit Variables(Variables<tmpl::list<WrappedTags...>>&& rhs) noexcept;
191  template <typename... WrappedTags,
192  Requires<tmpl2::flat_all_v<std::is_same<
193  db::remove_all_prefixes<WrappedTags>,
194  db::remove_all_prefixes<Tags>>::value...>> = nullptr>
195  Variables& operator=(Variables<tmpl::list<WrappedTags...>>&& rhs) noexcept;
196 
197  template <typename... WrappedTags,
198  Requires<tmpl2::flat_all_v<std::is_same<
199  db::remove_all_prefixes<WrappedTags>,
200  db::remove_all_prefixes<Tags>>::value...>> = nullptr>
201  explicit Variables(const Variables<tmpl::list<WrappedTags...>>& rhs) noexcept;
202  template <typename... WrappedTags,
203  Requires<tmpl2::flat_all_v<std::is_same<
204  db::remove_all_prefixes<WrappedTags>,
205  db::remove_all_prefixes<Tags>>::value...>> = nullptr>
206  Variables& operator=(
207  const Variables<tmpl::list<WrappedTags...>>& rhs) noexcept;
208  // @}
209 
210  /// \cond HIDDEN_SYMBOLS
211  ~Variables() noexcept = default;
212  /// \endcond
213 
214  // @{
215  /// Initialize a Variables to the state it would have after calling
216  /// the constructor with the same arguments.
217  // this should be updated if we ever use a variables which has a `value_type`
218  // larger than ~2 doubles in size.
219  void initialize(size_t number_of_grid_points) noexcept;
220  void initialize(size_t number_of_grid_points, value_type value) noexcept;
221  // @}
222 
223  constexpr SPECTRE_ALWAYS_INLINE size_t number_of_grid_points() const
224  noexcept {
225  return number_of_grid_points_;
226  }
227 
228  /// Number of grid points * number of independent components
229  constexpr SPECTRE_ALWAYS_INLINE size_type size() const noexcept {
230  return size_;
231  }
232 
233  //{@
234  /// Access pointer to underlying data
235  value_type* data() noexcept { return variable_data_.data(); }
236  const value_type* data() const noexcept { return variable_data_.data(); }
237  //@}
238 
239  /// \cond HIDDEN_SYMBOLS
240  /// Needed because of limitations and inconsistency between compiler
241  /// implementations of friend function templates with auto return type of
242  /// class templates
243  const auto& get_variable_data() const noexcept { return variable_data_; }
244  /// \endcond
245 
246  // clang-tidy: redundant-declaration
247  template <typename Tag, typename TagList>
248  friend constexpr typename Tag::type& get( // NOLINT
249  Variables<TagList>& v) noexcept;
250  template <typename Tag, typename TagList>
251  friend constexpr const typename Tag::type& get( // NOLINT
252  const Variables<TagList>& v) noexcept;
253 
254  /// Serialization for Charm++.
255  // clang-tidy: google-runtime-references
256  void pup(PUP::er& p) noexcept; // NOLINT
257 
258  // @{
259  /// \brief Assign a subset of the `Tensor`s from another Variables or a
260  /// tuples::TaggedTuple
261  ///
262  /// \note There is no need for an rvalue overload because we need to copy into
263  /// the contiguous array anyway
264  template <typename... SubsetOfTags,
265  Requires<tmpl2::flat_all_v<tmpl::list_contains_v<
266  tmpl::list<Tags...>, SubsetOfTags>...>> = nullptr>
268  const Variables<tmpl::list<SubsetOfTags...>>& vars) noexcept {
270  (get<SubsetOfTags>(*this) = get<SubsetOfTags>(vars)));
271  }
272 
273  template <typename... SubsetOfTags,
274  Requires<tmpl2::flat_all_v<tmpl::list_contains_v<
275  tmpl::list<Tags...>, SubsetOfTags>...>> = nullptr>
277  const tuples::TaggedTuple<SubsetOfTags...>& vars) noexcept {
279  (get<SubsetOfTags>(*this) = get<SubsetOfTags>(vars)));
280  }
281  // @}
282 
283  /// Converting constructor for an expression to a Variables class
284  // clang-tidy: mark as explicit (we want conversion to Variables)
285  template <typename VT, bool VF>
286  Variables(const blaze::Vector<VT, VF>& expression) noexcept; // NOLINT
287 
288  template <typename VT, bool VF>
289  Variables& operator=(const blaze::Vector<VT, VF>& expression) noexcept;
290 
291  template <typename... WrappedTags,
293  cpp17::is_same_v<db::remove_all_prefixes<WrappedTags>,
294  db::remove_all_prefixes<Tags>>...>> = nullptr>
295  SPECTRE_ALWAYS_INLINE Variables& operator+=(
296  const Variables<tmpl::list<WrappedTags...>>& rhs) noexcept {
297  variable_data_ += rhs.variable_data_;
298  return *this;
299  }
300  template <typename VT, bool VF>
301  SPECTRE_ALWAYS_INLINE Variables& operator+=(
302  const blaze::Vector<VT, VF>& rhs) noexcept {
303  variable_data_ += rhs;
304  return *this;
305  }
306 
307  template <typename... WrappedTags,
309  cpp17::is_same_v<db::remove_all_prefixes<WrappedTags>,
310  db::remove_all_prefixes<Tags>>...>> = nullptr>
311  SPECTRE_ALWAYS_INLINE Variables& operator-=(
312  const Variables<tmpl::list<WrappedTags...>>& rhs) noexcept {
313  variable_data_ -= rhs.variable_data_;
314  return *this;
315  }
316  template <typename VT, bool VF>
317  SPECTRE_ALWAYS_INLINE Variables& operator-=(
318  const blaze::Vector<VT, VF>& rhs) noexcept {
319  variable_data_ -= rhs;
320  return *this;
321  }
322 
323  SPECTRE_ALWAYS_INLINE Variables& operator*=(const value_type& rhs) noexcept {
324  variable_data_ *= rhs;
325  return *this;
326  }
327 
328  SPECTRE_ALWAYS_INLINE Variables& operator/=(const value_type& rhs) noexcept {
329  variable_data_ /= rhs;
330  return *this;
331  }
332 
333  template <typename... WrappedTags,
335  cpp17::is_same_v<db::remove_all_prefixes<WrappedTags>,
336  db::remove_all_prefixes<Tags>>...>> = nullptr>
337  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator+(
338  const Variables<tmpl::list<WrappedTags...>>& lhs,
339  const Variables& rhs) noexcept {
340  return lhs.get_variable_data() + rhs.variable_data_;
341  }
342  template <typename VT, bool VF>
343  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator+(
344  const blaze::Vector<VT, VF>& lhs, const Variables& rhs) noexcept {
345  return ~lhs + rhs.variable_data_;
346  }
347  template <typename VT, bool VF>
348  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator+(
349  const Variables& lhs, const blaze::Vector<VT, VF>& rhs) noexcept {
350  return lhs.variable_data_ + ~rhs;
351  }
352 
353  template <typename... WrappedTags,
355  cpp17::is_same_v<db::remove_all_prefixes<WrappedTags>,
356  db::remove_all_prefixes<Tags>>...>> = nullptr>
357  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator-(
358  const Variables<tmpl::list<WrappedTags...>>& lhs,
359  const Variables& rhs) noexcept {
360  return lhs.get_variable_data() - rhs.variable_data_;
361  }
362  template <typename VT, bool VF>
363  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator-(
364  const blaze::Vector<VT, VF>& lhs, const Variables& rhs) noexcept {
365  return ~lhs - rhs.variable_data_;
366  }
367  template <typename VT, bool VF>
368  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator-(
369  const Variables& lhs, const blaze::Vector<VT, VF>& rhs) noexcept {
370  return lhs.variable_data_ - ~rhs;
371  }
372 
373  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator*(
374  const Variables& lhs, const value_type& rhs) noexcept {
375  return lhs.variable_data_ * rhs;
376  }
377  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator*(
378  const value_type& lhs, const Variables& rhs) noexcept {
379  return lhs * rhs.variable_data_;
380  }
381 
382  friend SPECTRE_ALWAYS_INLINE decltype(auto) operator/(
383  const Variables& lhs, const value_type& rhs) noexcept {
384  return lhs.variable_data_ / rhs;
385  }
386 
387  private:
388  //{@
389  /*!
390  * \brief Subscript operator
391  *
392  * The subscript operator is private since it should not be used directly.
393  * Mathematical operations should be done using the math operators provided.
394  * Since the internal ordering of variables is implementation defined there
395  * is no safe way to perform any operation that is not a linear combination of
396  * Variables. Retrieving a Tensor must be done via the `get()` function.
397  *
398  * \requires `i >= 0 and i < size()`
399  */
400  SPECTRE_ALWAYS_INLINE value_type& operator[](const size_type i) noexcept {
401  return variable_data_[i];
402  }
403  SPECTRE_ALWAYS_INLINE const value_type& operator[](const size_type i) const
404  noexcept {
405  return variable_data_[i];
406  }
407  //@}
408 
409  static SPECTRE_ALWAYS_INLINE void add_reference_variable_data(
410  tmpl::list<> /*unused*/, const size_t /*variable_offset*/ = 0) noexcept {}
411 
412  template <
413  typename TagToAdd, typename... Rest,
415  void add_reference_variable_data(tmpl::list<TagToAdd, Rest...> /*unused*/,
416  size_t variable_offset = 0) noexcept;
417 
418  friend bool operator==(const Variables& lhs, const Variables& rhs) noexcept {
419  return lhs.variable_data_ == rhs.variable_data_;
420  }
421 
422  template <class FriendTags>
423  friend class Variables;
424 
425  std::unique_ptr<value_type[], decltype(&free)> variable_data_impl_{nullptr,
426  &free};
427  size_t size_ = 0;
428  size_t number_of_grid_points_ = 0;
429 
430  // variable_data_ is only used to plug into the Blaze expression templates
431  pointer_type variable_data_;
432  tuples::TaggedTuple<Tags...> reference_variable_data_;
433 };
434 
435 template <typename... Tags>
436 Variables<tmpl::list<Tags...>>::Variables() noexcept {
437  // This makes an assertion trigger if one tries to assign to
438  // components of a default-constructed Variables.
439  const auto set_refs = [](auto& var) noexcept {
440  for (auto& dv : var) {
441  dv.set_data_ref(nullptr, 0);
442  }
443  return 0;
444  };
445  (void)set_refs;
446  expand_pack(set_refs(tuples::get<Tags>(reference_variable_data_))...);
447 }
448 
449 template <typename... Tags>
450 Variables<tmpl::list<Tags...>>::Variables(
451  const size_t number_of_grid_points) noexcept {
452  initialize(number_of_grid_points);
453 }
454 
455 template <typename... Tags>
456 Variables<tmpl::list<Tags...>>::Variables(const size_t number_of_grid_points,
457  const value_type value) noexcept {
458  initialize(number_of_grid_points, value);
459 }
460 
461 template <typename... Tags>
462 void Variables<tmpl::list<Tags...>>::initialize(
463  const size_t number_of_grid_points) noexcept {
464  size_ = number_of_grid_points * number_of_independent_components;
465  if (size_ > 0) {
466  // clang-tidy: cppcoreguidelines-no-malloc
467  variable_data_impl_.reset(static_cast<value_type*>(
468  malloc(number_of_grid_points * // NOLINT
469  number_of_independent_components * sizeof(value_type))));
470  number_of_grid_points_ = number_of_grid_points;
471 #if defined(SPECTRE_DEBUG) || defined(SPECTRE_NAN_INIT)
472  std::fill(variable_data_impl_.get(), variable_data_impl_.get() + size_,
473  make_signaling_NaN<value_type>());
474 #endif // SPECTRE_DEBUG
475  variable_data_.reset(variable_data_impl_.get(), size_);
476  add_reference_variable_data(tmpl::list<Tags...>{});
477  }
478 }
479 
480 template <typename... Tags>
481 void Variables<tmpl::list<Tags...>>::initialize(
482  const size_t number_of_grid_points, const value_type value) noexcept {
483  size_ = number_of_grid_points * number_of_independent_components;
484  if (size_ > 0) {
485  // clang-tidy: cppcoreguidelines-no-malloc
486  variable_data_impl_.reset(static_cast<value_type*>(
487  malloc(number_of_grid_points * // NOLINT
488  number_of_independent_components * sizeof(value_type))));
489  number_of_grid_points_ = number_of_grid_points;
490  std::fill(variable_data_impl_.get(), variable_data_impl_.get() + size_,
491  value);
492  variable_data_.reset(variable_data_impl_.get(), size_);
493  add_reference_variable_data(tmpl::list<Tags...>{});
494  }
495 }
496 
497 /// \cond HIDDEN_SYMBOLS
498 template <typename... Tags>
499 Variables<tmpl::list<Tags...>>::Variables(
500  const Variables<tmpl::list<Tags...>>& rhs) noexcept
501  : size_(rhs.size_), number_of_grid_points_(rhs.number_of_grid_points()) {
502  if (size_ > 0) {
503  // clang-tidy: cppcoreguidelines-no-malloc
504  variable_data_impl_.reset(static_cast<value_type*>(
505  malloc(size_ * sizeof(value_type)))); // NOLINT
506  variable_data_.reset(variable_data_impl_.get(), size_);
507  add_reference_variable_data(tmpl::list<Tags...>{});
508  variable_data_ =
509  static_cast<const blaze::Vector<pointer_type, transpose_flag>&>(
510  rhs.variable_data_);
511  }
512 }
513 
514 template <typename... Tags>
515 Variables<tmpl::list<Tags...>>& Variables<tmpl::list<Tags...>>::operator=(
516  const Variables<tmpl::list<Tags...>>& rhs) noexcept {
517  if (&rhs == this) {
518  return *this;
519  }
520  size_ = rhs.size_;
521  if (number_of_grid_points_ != rhs.number_of_grid_points()) {
522  number_of_grid_points_ = rhs.number_of_grid_points();
523  if (size_ > 0) {
524  // clang-tidy: cppcoreguidelines-no-malloc
525  variable_data_impl_.reset(static_cast<value_type*>(
526  malloc(size_ * sizeof(value_type)))); // NOLINT
527  variable_data_.reset(variable_data_impl_.get(), size_);
528  add_reference_variable_data(tmpl::list<Tags...>{});
529  }
530  }
531  if (size_ > 0) {
532  variable_data_ =
533  static_cast<const blaze::Vector<pointer_type, transpose_flag>&>(
534  rhs.variable_data_);
535  }
536  return *this;
537 }
538 
539 template <typename... Tags>
540 Variables<tmpl::list<Tags...>>& Variables<tmpl::list<Tags...>>::operator=(
541  Variables<tmpl::list<Tags...>>&& rhs) noexcept {
542  if (this == &rhs) {
543  return *this;
544  }
545  variable_data_impl_ = std::move(rhs.variable_data_impl_);
546  size_ = rhs.size_;
547  number_of_grid_points_ = std::move(rhs.number_of_grid_points_);
548  variable_data_.reset(variable_data_impl_.get(), size());
549  add_reference_variable_data(tmpl::list<Tags...>{});
550  return *this;
551 }
552 
553 template <typename... Tags>
554 template <typename... WrappedTags,
557  db::remove_all_prefixes<Tags>>::value...>>>
558 Variables<tmpl::list<Tags...>>::Variables(
559  const Variables<tmpl::list<WrappedTags...>>& rhs) noexcept
560  : size_(rhs.size_), number_of_grid_points_(rhs.number_of_grid_points()) {
561  if (size_ > 0) {
562  // clang-tidy: cppcoreguidelines-no-malloc
563  variable_data_impl_.reset(static_cast<value_type*>(
564  malloc(size_ * sizeof(value_type)))); // NOLINT
565  variable_data_.reset(variable_data_impl_.get(), size_);
566  variable_data_ =
567  static_cast<const blaze::Vector<pointer_type, transpose_flag>&>(
568  rhs.variable_data_);
569  add_reference_variable_data(tmpl::list<Tags...>{});
570  }
571 }
572 
573 template <typename... Tags>
574 template <typename... WrappedTags,
576  std::is_same<db::remove_all_prefixes<WrappedTags>,
577  db::remove_all_prefixes<Tags>>::value...>>>
578 Variables<tmpl::list<Tags...>>& Variables<tmpl::list<Tags...>>::operator=(
579  const Variables<tmpl::list<WrappedTags...>>& rhs) noexcept {
580  size_ = rhs.size_;
581  if (number_of_grid_points_ != rhs.number_of_grid_points()) {
582  number_of_grid_points_ = rhs.number_of_grid_points();
583  if (size_ > 0) {
584  // clang-tidy: cppcoreguidelines-no-malloc
585  variable_data_impl_.reset(static_cast<value_type*>(
586  malloc(size_ * sizeof(value_type)))); // NOLINT
587  variable_data_.reset(variable_data_impl_.get(), size_);
588  add_reference_variable_data(tmpl::list<Tags...>{});
589  }
590  }
591  variable_data_ =
592  static_cast<const blaze::Vector<pointer_type, transpose_flag>&>(
593  rhs.variable_data_);
594  return *this;
595 }
596 
597 template <typename... Tags>
598 template <typename... WrappedTags,
600  std::is_same<db::remove_all_prefixes<WrappedTags>,
601  db::remove_all_prefixes<Tags>>::value...>>>
602 Variables<tmpl::list<Tags...>>::Variables(
603  Variables<tmpl::list<WrappedTags...>>&& rhs) noexcept
604  : variable_data_impl_(std::move(rhs.variable_data_impl_)),
605  size_(rhs.size()),
606  number_of_grid_points_(rhs.number_of_grid_points()),
607  variable_data_(variable_data_impl_.get(), size_),
608  reference_variable_data_(std::move(rhs.reference_variable_data_)) {}
609 
610 template <typename... Tags>
611 template <typename... WrappedTags,
613  std::is_same<db::remove_all_prefixes<WrappedTags>,
614  db::remove_all_prefixes<Tags>>::value...>>>
615 Variables<tmpl::list<Tags...>>& Variables<tmpl::list<Tags...>>::operator=(
616  Variables<tmpl::list<WrappedTags...>>&& rhs) noexcept {
617  variable_data_impl_ = std::move(rhs.variable_data_impl_);
618  size_ = rhs.size_;
619  number_of_grid_points_ = std::move(rhs.number_of_grid_points_);
620  variable_data_.reset(variable_data_impl_.get(), size());
621  add_reference_variable_data(tmpl::list<Tags...>{});
622  return *this;
623 }
624 
625 template <typename... Tags>
626 void Variables<tmpl::list<Tags...>>::pup(PUP::er& p) noexcept {
627  p | size_;
628  p | number_of_grid_points_;
629  if (p.isUnpacking()) {
630  // clang-tidy: cppcoreguidelines-no-malloc
631  variable_data_impl_.reset(static_cast<value_type*>(
632  malloc(number_of_grid_points_ * // NOLINT
633  number_of_independent_components * sizeof(value_type))));
634  variable_data_.reset(variable_data_impl_.get(), size());
635  add_reference_variable_data(tmpl::list<Tags...>{});
636  }
637  PUParray(p, variable_data_impl_.get(), size_);
638 }
639 /// \endcond
640 
641 // {@
642 /*!
643  * \ingroup DataStructuresGroup
644  * \brief Return Tag::type pointing into the contiguous array
645  *
646  * \tparam Tag the variable to return
647  */
648 template <typename Tag, typename TagList>
649 constexpr typename Tag::type& get(Variables<TagList>& v) noexcept {
650  static_assert(tmpl::list_contains_v<TagList, Tag>,
651  "Could not retrieve Tag from Variables. See the first "
652  "template parameter of the instantiation for what Tag is "
653  "being retrieved and the second template parameter for "
654  "what Tags are available.");
655  return tuples::get<Tag>(v.reference_variable_data_);
656 }
657 template <typename Tag, typename TagList>
658 constexpr const typename Tag::type& get(const Variables<TagList>& v) noexcept {
659  static_assert(tmpl::list_contains_v<TagList, Tag>,
660  "Could not retrieve Tag from Variables. See the first "
661  "template parameter of the instantiation for what Tag is "
662  "being retrieved and the second template parameter for "
663  "what Tags are available.");
664  return tuples::get<Tag>(v.reference_variable_data_);
665 }
666 // @}
667 
668 template <typename... Tags>
669 template <typename VT, bool VF>
670 Variables<tmpl::list<Tags...>>::Variables(
671  const blaze::Vector<VT, VF>& expression) noexcept
672  : size_((~expression).size()),
673  number_of_grid_points_(size_ / number_of_independent_components) {
674  initialize(number_of_grid_points_);
675  variable_data_ = expression;
676 }
677 
678 /// \cond
679 template <typename... Tags>
680 template <typename VT, bool VF>
681 Variables<tmpl::list<Tags...>>& Variables<tmpl::list<Tags...>>::operator=(
682  const blaze::Vector<VT, VF>& expression) noexcept {
683  if (size_ != (~expression).size()) {
684  size_ = (~expression).size();
685  number_of_grid_points_ = size_ / number_of_independent_components;
686  initialize(number_of_grid_points_);
687  }
688  variable_data_ = expression;
689  return *this;
690 }
691 /// \endcond
692 
693 /// \cond HIDDEN_SYMBOLS
694 template <typename... Tags>
695 template <typename TagToAdd, typename... Rest,
697 void Variables<tmpl::list<Tags...>>::add_reference_variable_data(
698  tmpl::list<TagToAdd, Rest...> /*unused*/,
699  const size_t variable_offset) noexcept {
700  ASSERT(size_ > (variable_offset + TagToAdd::type::size() - 1) *
701  number_of_grid_points_,
702  "This ASSERT is typically triggered because a Variables class was "
703  "default constructed. The only reason the Variables class has a "
704  "default constructor is because Charm++ uses it, you are not "
705  "supposed to use it otherwise.");
706  typename TagToAdd::type& var =
707  tuples::get<TagToAdd>(reference_variable_data_);
708  for (size_t i = 0; i < TagToAdd::type::size(); ++i) {
709  var[i].set_data_ref(
710  &variable_data_[(variable_offset + i) * number_of_grid_points_],
711  number_of_grid_points_);
712  }
713  add_reference_variable_data(tmpl::list<Rest...>{},
714  variable_offset + TagToAdd::type::size());
715 }
716 /// \endcond
717 
718 template <typename... Tags>
719 Variables<tmpl::list<Tags...>>& operator*=(
720  Variables<tmpl::list<Tags...>>& lhs,
721  const typename Variables<tmpl::list<Tags...>>::vector_type& rhs) noexcept {
722  using value_type = typename Variables<tmpl::list<Tags...>>::value_type;
723  ASSERT(lhs.number_of_grid_points() == rhs.size(),
724  "Size mismatch in multiplication: " << lhs.number_of_grid_points()
725  << " and " << rhs.size());
726  value_type* const lhs_data = lhs.data();
727  const value_type* const rhs_data = rhs.data();
728  for (size_t c = 0; c < lhs.number_of_independent_components; ++c) {
729  for (size_t s = 0; s < lhs.number_of_grid_points(); ++s) {
730  // clang-tidy: do not use pointer arithmetic
731  lhs_data[c * lhs.number_of_grid_points() + s] *= rhs_data[s]; // NOLINT
732  }
733  }
734  return lhs;
735 }
736 
737 template <typename... Tags>
738 Variables<tmpl::list<Tags...>> operator*(
739  const Variables<tmpl::list<Tags...>>& lhs,
740  const typename Variables<tmpl::list<Tags...>>::vector_type& rhs) noexcept {
741  auto result = lhs;
742  result *= rhs;
743  return result;
744 }
745 
746 template <typename... Tags>
747 Variables<tmpl::list<Tags...>> operator*(
748  const typename Variables<tmpl::list<Tags...>>::vector_type& lhs,
749  const Variables<tmpl::list<Tags...>>& rhs) noexcept {
750  auto result = rhs;
751  result *= lhs;
752  return result;
753 }
754 
755 template <typename... Tags>
756 Variables<tmpl::list<Tags...>>& operator/=(
757  Variables<tmpl::list<Tags...>>& lhs,
758  const typename Variables<tmpl::list<Tags...>>::vector_type& rhs) noexcept {
759  ASSERT(lhs.number_of_grid_points() == rhs.size(),
760  "Size mismatch in multiplication: " << lhs.number_of_grid_points()
761  << " and " << rhs.size());
762  using value_type = typename Variables<tmpl::list<Tags...>>::value_type;
763  value_type* const lhs_data = lhs.data();
764  const value_type* const rhs_data = rhs.data();
765  for (size_t c = 0; c < lhs.number_of_independent_components; ++c) {
766  for (size_t s = 0; s < lhs.number_of_grid_points(); ++s) {
767  // clang-tidy: do not use pointer arithmetic
768  lhs_data[c * lhs.number_of_grid_points() + s] /= rhs_data[s]; // NOLINT
769  }
770  }
771  return lhs;
772 }
773 
774 template <typename... Tags>
775 Variables<tmpl::list<Tags...>> operator/(
776  const Variables<tmpl::list<Tags...>>& lhs,
777  const typename Variables<tmpl::list<Tags...>>::vector_type& rhs) noexcept {
778  auto result = lhs;
779  result /= rhs;
780  return result;
781 }
782 
783 namespace Variables_detail {
784 template <typename TagsList>
785 std::ostream& print_helper(std::ostream& os, const Variables<TagsList>& /*d*/,
786  tmpl::list<> /*meta*/) noexcept {
787  return os << "Variables is empty!";
788 }
789 
790 template <typename Tag, typename TagsList>
791 std::ostream& print_helper(std::ostream& os, const Variables<TagsList>& d,
792  tmpl::list<Tag> /*meta*/) noexcept {
793  return os << pretty_type::short_name<Tag>() << ":\n" << get<Tag>(d);
794 }
795 
796 template <typename Tag, typename SecondTag, typename... RemainingTags,
797  typename TagsList>
798 std::ostream& print_helper(
799  std::ostream& os, const Variables<TagsList>& d,
800  tmpl::list<Tag, SecondTag, RemainingTags...> /*meta*/) noexcept {
801  os << pretty_type::short_name<Tag>() << ":\n";
802  os << get<Tag>(d) << "\n\n";
803  print_helper(os, d, tmpl::list<SecondTag, RemainingTags...>{});
804  return os;
805 }
806 } // namespace Variables_detail
807 
808 template <typename TagsList>
809 std::ostream& operator<<(std::ostream& os,
810  const Variables<TagsList>& d) noexcept {
811  return Variables_detail::print_helper(os, d, TagsList{});
812 }
813 
814 template <typename TagsList>
815 bool operator!=(const Variables<TagsList>& lhs,
816  const Variables<TagsList>& rhs) noexcept {
817  return not(lhs == rhs);
818 }
819 
820 namespace MakeWithValueImpls {
821 template <typename TagList>
822 struct MakeWithValueImpl<Variables<TagList>,
823  typename Variables<TagList>::vector_type> {
824  /// \brief Returns a Variables whose vectors are the same size as `input`,
825  /// with each element equal to `value`.
826  static SPECTRE_ALWAYS_INLINE Variables<TagList> apply(
827  const typename Variables<TagList>::vector_type& input,
828  const typename Variables<TagList>::value_type value) noexcept {
829  return Variables<TagList>(input.size(), value);
830  }
831 };
832 
833 template <typename TagList, typename... Structure>
835  Variables<TagList>,
836  Tensor<typename Variables<TagList>::vector_type, Structure...>> {
837  /// \brief Returns a Variables whose DataVectors are the same size as `input`,
838  /// with each element equal to `value`.
839  static SPECTRE_ALWAYS_INLINE Variables<TagList> apply(
840  const Tensor<typename Variables<TagList>::vector_type, Structure...>&
841  input,
842  const typename Variables<TagList>::value_type value) noexcept {
843  return Variables<TagList>(input.begin()->size(), value);
844  }
845 };
846 
847 template <typename TagListOut, typename TagListIn>
848 struct MakeWithValueImpl<Variables<TagListOut>, Variables<TagListIn>> {
849  /// \brief Returns a Variables whose DataVectors are the same size as `input`,
850  /// with each element equal to `value`.
851  static SPECTRE_ALWAYS_INLINE Variables<TagListOut> apply(
852  const Variables<TagListIn>& input,
853  const typename Variables<TagListIn>::value_type value) noexcept {
854  return Variables<TagListOut>(input.number_of_grid_points(), value);
855  }
856 };
857 } // namespace MakeWithValueImpls
858 
859 namespace db {
860 template <typename TagList, typename Tag>
861 struct Subitems<TagList, Tag,
862  Requires<tt::is_a_v<Variables, item_type<Tag, TagList>>>> {
863  using type = typename item_type<Tag>::tags_list;
864 
865  template <typename Subtag>
866  static void create_item(
867  const gsl::not_null<item_type<Tag>*> parent_value,
868  const gsl::not_null<item_type<Subtag>*> sub_value) noexcept {
869  auto& vars = get<Subtag>(*parent_value);
870  // Only update the Tensor if the Variables has changed its allocation
871  if (vars.begin()->data() != sub_value->begin()->data()) {
872  for (auto vars_it = vars.begin(), sub_var_it = sub_value->begin();
873  vars_it != vars.end(); ++vars_it, ++sub_var_it) {
874  sub_var_it->set_data_ref(make_not_null(&*vars_it));
875  }
876  }
877  }
878 
879  template <typename Subtag>
880  static const item_type<Subtag>& create_compute_item(
881  const item_type<Tag>& parent_value) noexcept {
882  return get<Subtag>(parent_value);
883  }
884 };
885 } // namespace db
886 
887 namespace Tags {
888 template <size_t N, typename T>
889 struct TempTensor {
890  using type = T;
891  static std::string name() noexcept {
892  return std::string("TempTensor") + std::to_string(N);
893  }
894 };
895 
896 // @{
897 /// \ingroup PeoGroup
898 /// Variables Tags for temporary tensors inside a function.
899 template <size_t N, typename DataType = DataVector>
901 
902 // Rank 1
903 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
904  typename DataType = DataVector>
906 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
907  typename DataType = DataVector>
909 
910 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
911  typename DataType = DataVector>
913 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
914  typename DataType = DataVector>
916 
917 // Rank 2
918 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
919  typename DataType = DataVector>
921 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
922  typename DataType = DataVector>
924 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
925  typename DataType = DataVector>
927 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
928  typename DataType = DataVector>
930 
931 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
932  typename DataType = DataVector>
934 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
935  typename DataType = DataVector>
937 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
938  typename DataType = DataVector>
940 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
941  typename DataType = DataVector>
943 
944 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
945  typename DataType = DataVector>
947 
948 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
949  typename DataType = DataVector>
951 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
952  typename DataType = DataVector>
954 
955 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
956  typename DataType = DataVector>
958 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
959  typename DataType = DataVector>
961 
962 // Rank 3
963 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
964  typename DataType = DataVector>
966 template <size_t N, size_t SpatialDim, typename Fr = Frame::Inertial,
967  typename DataType = DataVector>
969 // @}
970 } // namespace Tags
Implementations of make_with_value.
Definition: DenseVector.hpp:61
static Variables< TagList > apply(const Tensor< typename Variables< TagList >::vector_type, Structure... > &input, const typename Variables< TagList >::value_type value) noexcept
Returns a Variables whose DataVectors are the same size as input, with each element equal to value...
Definition: Variables.hpp:839
Definition: Variables.hpp:46
Defines class tuples::TaggedTuple.
void assign_subset(const Variables< tmpl::list< SubsetOfTags... >> &vars) noexcept
Assign a subset of the Tensors from another Variables or a tuples::TaggedTuple.
Definition: Variables.hpp:267
Definition: Variables.hpp:783
#define EXPAND_PACK_LEFT_TO_RIGHT(...)
Expand a parameter pack evaluating the terms from left to right.
Definition: TMPL.hpp:561
tmpl::list< Tags... > tags_list
A typelist of the Tags whose variables are held.
Definition: Variables.hpp:104
constexpr bool flat_all_v
A non-short-circuiting logical AND between bools &#39;B"".
Definition: TMPL.hpp:504
void void_t
Given a set of types, returns void
Definition: TypeTraits.hpp:214
Definition: Digraph.hpp:11
auto operator*(const TensorExpression< T1, X, Symm1, IndexList1, Args1 > &t1, const TensorExpression< T2, X, Symm2, IndexList2, Args2 > &t2)
Definition: Product.hpp:89
Tags for the DataBox inherit from this type.
Definition: DataBoxTag.hpp:65
#define ASSERT(a, m)
Assert that an expression should be true.
Definition: Assert.hpp:49
Defines the type alias Requires.
static Variables< TagList > apply(const typename Variables< TagList >::vector_type &input, const typename Variables< TagList >::value_type value) noexcept
Returns a Variables whose vectors are the same size as input, with each element equal to value...
Definition: Variables.hpp:826
constexpr size_type size() const noexcept
Number of grid points * number of independent components.
Definition: Variables.hpp:229
A collection of useful type traits.
Definition: TensorExpression.hpp:115
Definition: MakeWithValue.hpp:20
Definition: Variables.hpp:889
#define SPECTRE_ALWAYS_INLINE
Always inline a function. Only use this if you benchmarked the code.
Definition: ForceInline.hpp:20
An associative container that is indexed by structs.
Definition: TaggedTuple.hpp:272
Defines classes and functions used for manipulating DataBox&#39;s.
constexpr bool is_same_v
Variable template for is_same.
Definition: TypeTraits.hpp:221
void assign_subset(const tuples::TaggedTuple< SubsetOfTags... > &vars) noexcept
Assign a subset of the Tensors from another Variables or a tuples::TaggedTuple.
Definition: Variables.hpp:276
static Variables< TagListOut > apply(const Variables< TagListIn > &input, const typename Variables< TagListIn >::value_type value) noexcept
Returns a Variables whose DataVectors are the same size as input, with each element equal to value...
Definition: Variables.hpp:851
constexpr bool is_a_v
Definition: TypeTraits.hpp:543
Struct that can be specialized to allow DataBox items to have subitems. Specializations must define: ...
Definition: DataBoxTag.hpp:648
Defines macro to always inline a function.
Definition: DataBoxTag.hpp:29
value_type * data() noexcept
Access pointer to underlying data.
Definition: Variables.hpp:235
Defines classes for Tensor.
Defines a list of useful type aliases for tensors.
Check if type T is a template specialization of U
Definition: TypeTraits.hpp:536
typename DataBox_detail::remove_all_prefixes_impl< Tag, cpp17::is_base_of_v< db::PrefixTag, Tag > >::type remove_all_prefixes
Completely remove all prefix tags from a Tag.
Definition: DataBoxTag.hpp:551
Namespace for DataBox related things.
Definition: DataBox.hpp:33
Defines macro ASSERT.
Contains a pretty_type library to write types in a "pretty" format.
Stores a collection of function values.
Definition: DataVector.hpp:46
Wraps the template metaprogramming library used (brigand)
typename DataBox_detail::item_type_impl< TagList, Tag >::type item_type
Get the type that is returned by the Tag. If it is a base tag then a TagList must be passed as a seco...
Definition: DataBoxTag.hpp:410
Defines functions and classes from the GSL.
gsl::not_null< T * > make_not_null(T *ptr) noexcept
Construct a not_null from a pointer. Often this will be done as an implicit conversion, but it may be necessary to perform the conversion explicitly when type deduction is desired.
Definition: Gsl.hpp:863
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t ...
Definition: Requires.hpp:67
Definition: IndexType.hpp:44
Defines classes SimpleTag, PrefixTag, ComputeTag and several functions for retrieving tag info...
Defines type traits, some of which are future STL type_traits header.
Require a pointer to not be a nullptr
Definition: ConservativeFromPrimitive.hpp:12
Metaprogramming things that are not planned to be submitted to Brigand.
Definition: TMPL.hpp:476
constexpr void expand_pack(Ts &&...) noexcept
Allows zero-cost unordered expansion of a parameter.
Definition: TMPL.hpp:545
Defines classes representing tensor indices.