Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <cstddef>
7 : #include <pup.h>
8 : #include <utility>
9 :
10 : #include "DataStructures/Variables.hpp"
11 : #include "Domain/Structure/DirectionMap.hpp"
12 : #include "Utilities/ErrorHandling/Assert.hpp"
13 : #include "Utilities/Gsl.hpp"
14 : #include "Utilities/MakeWithValue.hpp"
15 :
16 : /*!
17 : * \ingroup DataStructuresGroup
18 : * \brief A data structure holding Variables associated with directions.
19 : *
20 : * This class holds Variables of sizes `points_per_direction`, all
21 : * referencing a single memory allocation. The individual Variables
22 : * can be accessed through the `variables()` member. Access to the
23 : * underlying buffer is provided so that the class can, for example,
24 : * be used as the evolved variables for an evolution system.
25 : */
26 : template <size_t Dim, typename Tags>
27 1 : class BoundaryVariables {
28 : static_assert(
29 : DirectionMap<Dim, size_t>::hash_is_perfect,
30 : "Map must use a perfect hash to ensure consistent data ordering.");
31 :
32 : public:
33 0 : using tags_list = Tags;
34 0 : using VariablesType = Variables<tags_list>;
35 0 : using Vector = typename VariablesType::vector_type;
36 :
37 0 : BoundaryVariables() = default;
38 0 : BoundaryVariables(BoundaryVariables&& other)
39 : : points_per_direction_(std::move(other.points_per_direction_)),
40 : buffer_(std::move(other.buffer_)) {
41 : other.clear();
42 : setup_variables();
43 : }
44 0 : BoundaryVariables(const BoundaryVariables& other)
45 : : points_per_direction_(other.points_per_direction_),
46 : buffer_(other.buffer_) {
47 : setup_variables();
48 : }
49 :
50 0 : BoundaryVariables& operator=(BoundaryVariables&& other) {
51 : if (this == &other) {
52 : return *this;
53 : }
54 : points_per_direction_ = std::move(other.points_per_direction_);
55 : buffer_ = std::move(other.buffer_);
56 : other.clear();
57 : setup_variables();
58 : return *this;
59 : }
60 0 : BoundaryVariables& operator=(const BoundaryVariables& other) {
61 : points_per_direction_ = other.points_per_direction_;
62 : buffer_ = other.buffer_;
63 : setup_variables();
64 : return *this;
65 : }
66 :
67 0 : ~BoundaryVariables() = default;
68 :
69 0 : explicit BoundaryVariables(DirectionMap<Dim, size_t> points_per_direction) {
70 : initialize(std::move(points_per_direction));
71 : }
72 :
73 0 : BoundaryVariables(DirectionMap<Dim, size_t> points_per_direction,
74 : const typename Vector::value_type& initial_value) {
75 : initialize(std::move(points_per_direction), initial_value);
76 : }
77 :
78 0 : void initialize(DirectionMap<Dim, size_t> points_per_direction) {
79 : points_per_direction_ = std::move(points_per_direction);
80 : buffer_ = Vector(buffer_size());
81 : setup_variables();
82 : }
83 :
84 0 : void initialize(DirectionMap<Dim, size_t> points_per_direction,
85 : const typename Vector::value_type& initial_value) {
86 : points_per_direction_ = std::move(points_per_direction);
87 : buffer_ = Vector(buffer_size(), initial_value);
88 : setup_variables();
89 : }
90 :
91 0 : size_t size() const { return buffer_.size(); }
92 0 : bool empty() const { return buffer_.size() == 0; }
93 :
94 0 : void clear() {
95 : points_per_direction_.clear();
96 : buffer_.clear();
97 : variables_.clear();
98 : }
99 :
100 0 : const DirectionMap<Dim, size_t>& points_per_direction() const {
101 : return points_per_direction_;
102 : }
103 :
104 0 : const Vector& buffer() const {
105 : check_pointers();
106 : return buffer_;
107 : }
108 0 : Vector& buffer() {
109 : check_pointers();
110 : return buffer_;
111 : }
112 :
113 0 : DirectionMap<Dim, VariablesType>& variables() {
114 : check_pointers();
115 : return variables_;
116 : }
117 0 : const DirectionMap<Dim, VariablesType>& variables() const {
118 : check_pointers();
119 : return variables_;
120 : }
121 :
122 0 : void pup(PUP::er& p) {
123 : p | points_per_direction_;
124 : p | buffer_;
125 : if (p.isUnpacking()) {
126 : setup_variables();
127 : }
128 : }
129 :
130 : private:
131 0 : size_t buffer_size() const {
132 : size_t num_points = 0;
133 : for (const auto& [direction, points] : points_per_direction_) {
134 : num_points += points;
135 : }
136 : return num_points * VariablesType::number_of_independent_components;
137 : }
138 :
139 0 : void setup_variables() {
140 : variables_.clear();
141 : size_t offset = 0;
142 : for (const auto& [direction, points] : points_per_direction_) {
143 : const size_t vars_size =
144 : points * VariablesType::number_of_independent_components;
145 : variables_.emplace(direction,
146 : VariablesType(buffer_.data() + offset, vars_size));
147 : offset += vars_size;
148 : }
149 : }
150 :
151 0 : void check_pointers() const {
152 : #ifdef SPECTRE_DEBUG
153 : if (points_per_direction_.empty()) {
154 : return;
155 : }
156 : ASSERT(buffer_.size() == buffer_size(),
157 : "Buffer has been manually resized. Have "
158 : << buffer_.size() << " entries but should be " << buffer_size());
159 : const auto first_direction = points_per_direction_.begin()->first;
160 : ASSERT(variables_.at(first_direction).data() == buffer_.data(),
161 : "Pointer mismatch. Data buffers have been replaced.");
162 : #endif
163 : }
164 :
165 0 : DirectionMap<Dim, size_t> points_per_direction_{};
166 0 : Vector buffer_{};
167 0 : DirectionMap<Dim, VariablesType> variables_{};
168 : };
169 :
170 : template <size_t Dim, typename Tags>
171 0 : bool operator==(const BoundaryVariables<Dim, Tags>& a,
172 : const BoundaryVariables<Dim, Tags>& b) {
173 : return a.points_per_direction() == b.points_per_direction() and
174 : a.buffer() == b.buffer();
175 : }
176 :
177 : template <size_t Dim, typename Tags>
178 0 : bool operator!=(const BoundaryVariables<Dim, Tags>& a,
179 : const BoundaryVariables<Dim, Tags>& b) {
180 : return not(a == b);
181 : }
182 :
183 : template <size_t Dim, typename Tags>
184 0 : auto make_math_wrapper(
185 : const gsl::not_null<BoundaryVariables<Dim, Tags>*> data) {
186 : return make_math_wrapper(&data->buffer());
187 : }
188 :
189 : template <size_t Dim, typename Tags>
190 0 : auto make_math_wrapper(const BoundaryVariables<Dim, Tags>& data) {
191 : return make_math_wrapper(data.buffer());
192 : }
193 :
194 : template <size_t Dim, typename Tags>
195 0 : auto into_math_wrapper_type(BoundaryVariables<Dim, Tags>&& data) {
196 : auto result = into_math_wrapper_type(std::move(data.buffer()));
197 : data.clear();
198 : return result;
199 : }
200 :
201 : // We can't set the size from an arbitrary object, but we can copy
202 : // sizes from one BoundaryVariables to another.
203 : template <size_t Dim, typename Tags1, typename Tags2>
204 0 : struct MakeWithValueImpls::MakeWithValueImpl<BoundaryVariables<Dim, Tags1>,
205 : BoundaryVariables<Dim, Tags2>> {
206 : template <typename ValueType>
207 0 : static BoundaryVariables<Dim, Tags1> apply(
208 : const BoundaryVariables<Dim, Tags2>& input, const ValueType value) {
209 : return {input.points_per_direction(), value};
210 : }
211 : };
212 :
213 : template <size_t Dim, typename Tags1, typename Tags2>
214 0 : void set_number_of_grid_points(
215 : const gsl::not_null<BoundaryVariables<Dim, Tags1>*> result,
216 : const BoundaryVariables<Dim, Tags2>& pattern) {
217 : if (UNLIKELY(result->points_per_direction() !=
218 : pattern.points_per_direction())) {
219 : *result = BoundaryVariables<Dim, Tags1>(pattern.points_per_direction());
220 : }
221 : }
222 :
223 : template <size_t Dim, typename Tags>
224 0 : bool contains_allocations(const BoundaryVariables<Dim, Tags>& value) {
225 : return contains_allocations(value.buffer());
226 : }
|