Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <algorithm>
7 : #include <cstddef>
8 : #include <memory>
9 : #include <utility>
10 :
11 : #include "DataStructures/ComplexModalVector.hpp"
12 : #include "DataStructures/DataBox/Tag.hpp"
13 : #include "Evolution/Systems/Cce/BoundaryData.hpp"
14 : #include "Evolution/Systems/Cce/Tags.hpp"
15 : #include "Evolution/Systems/Cce/WorldtubeBufferUpdater.hpp"
16 : #include "NumericalAlgorithms/Interpolation/SpanInterpolator.hpp"
17 : #include "Parallel/NodeLock.hpp"
18 : #include "Utilities/ErrorHandling/Error.hpp"
19 : #include "Utilities/Gsl.hpp"
20 : #include "Utilities/Serialization/CharmPupable.hpp"
21 : #include "Utilities/TMPL.hpp"
22 :
23 : namespace Cce {
24 :
25 : namespace detail {
26 :
27 : template <typename InputTags>
28 : void set_non_pupped_members(
29 : gsl::not_null<size_t*> time_span_start,
30 : gsl::not_null<size_t*> time_span_end,
31 : gsl::not_null<Variables<InputTags>*> coefficients_buffers,
32 : gsl::not_null<Variables<InputTags>*> interpolated_coefficients,
33 : size_t buffer_depth, size_t interpolator_length, size_t l_max);
34 :
35 : template <typename InputTags>
36 : void initialize_buffers(
37 : gsl::not_null<size_t*> buffer_depth,
38 : gsl::not_null<Variables<InputTags>*> coefficients_buffers,
39 : size_t buffer_size, size_t interpolator_length, size_t l_max);
40 :
41 : template <typename InputTags, typename OutputTags>
42 : void populate_hypersurface_boundary_data(
43 : gsl::not_null<Variables<OutputTags>*> boundary_data_variables,
44 : gsl::not_null<Variables<InputTags>*> interpolated_coefficients,
45 : gsl::not_null<Variables<InputTags>*> coefficients_buffers,
46 : gsl::not_null<size_t*> time_span_start,
47 : gsl::not_null<size_t*> time_span_end,
48 : gsl::not_null<Parallel::NodeLock*> hdf5_lock, double time,
49 : const std::unique_ptr<intrp::SpanInterpolator>& interpolator,
50 : const std::unique_ptr<WorldtubeBufferUpdater<InputTags>>& buffer_updater,
51 : size_t l_max, size_t buffer_depth);
52 : } // namespace detail
53 :
54 : /// \cond
55 : class MetricWorldtubeDataManager;
56 : class BondiWorldtubeDataManager;
57 : class KleinGordonWorldtubeDataManager;
58 : /// \endcond
59 :
60 : /*!
61 : * \brief Abstract base class for managers of CCE worldtube data that is
62 : * provided in large time-series chunks, especially the type provided by input
63 : * h5 files. `BoundaryTags` is a `tmpl::list` of tags on the worldtube boundary.
64 : *
65 : * \details The methods that are required to be overridden in the derived
66 : * classes are:
67 : *
68 : * - `WorldtubeDataManager::populate_hypersurface_boundary_data()`:
69 : * updates the Variables passed by pointer to contain correct boundary data
70 : * for the time value passed in. This function should update all of the tags
71 : * in `Tags::characteristic_worldtube_boundary_tags<Tags::BoundaryValue>`.
72 : * - `WorldtubeDataManager::get_clone()`: clone function to obtain a
73 : * `std::unique_ptr` of the base `WorldtubeDataManager`, needed to pass around
74 : * the factory-created object.
75 : * - `WorldtubeDataManager::get_l_max()`: The override should return the
76 : * `l_max` that it computes for the collocation data calculated during
77 : * `WorldtubeDataManager::populate_hypersurface_boundary_data()`.
78 : * - `WorldtubeBufferUpdater::get_time_span()`: The override should return the
79 : * `std::pair` of indices that represent the start and end point of the
80 : * underlying data source. This is primarily used for monitoring the frequency
81 : * and size of the buffer updates.
82 : */
83 : template <typename BoundaryTags>
84 1 : class WorldtubeDataManager : public PUP::able {
85 : public:
86 0 : using creatable_classes =
87 : tmpl::list<MetricWorldtubeDataManager, BondiWorldtubeDataManager,
88 : KleinGordonWorldtubeDataManager>;
89 :
90 0 : WRAPPED_PUPable_abstract(WorldtubeDataManager); // NOLINT
91 :
92 0 : virtual bool populate_hypersurface_boundary_data(
93 : gsl::not_null<Variables<BoundaryTags>*> boundary_data_variables,
94 : double time, gsl::not_null<Parallel::NodeLock*> hdf5_lock) const = 0;
95 :
96 0 : virtual std::unique_ptr<WorldtubeDataManager> get_clone() const = 0;
97 :
98 0 : virtual size_t get_l_max() const = 0;
99 :
100 0 : virtual std::pair<size_t, size_t> get_time_span() const = 0;
101 :
102 : /// \brief Use `interpolator` in place of the one supplied at construction
103 : /// when building the boundary value of `Du<Dr<BondiJ>>`.
104 : ///
105 : /// \details That boundary value is consumed only by the initial-data
106 : /// generator, which may want a different time-interpolation order from the
107 : /// one the evolution runs with. A manager that does not produce
108 : /// `Du<Dr<BondiJ>>` at all cannot honor the request, so rather than drop it
109 : /// silently the default implementation aborts; `nullptr` (nothing was asked
110 : /// for) is always accepted.
111 1 : virtual void set_du_dr_j_interpolator(
112 : std::unique_ptr<intrp::SpanInterpolator> interpolator) {
113 : if (interpolator != nullptr) {
114 : ERROR(
115 : "A `DuDrJInterpolator` was requested, but this worldtube data "
116 : "manager does not produce the `Du<Dr<BondiJ>>` boundary value that "
117 : "the option controls, so the request would have no effect. Only the "
118 : "Bondi-type worldtube data manager supports it; remove the option or "
119 : "supply Bondi-Sachs worldtube data.");
120 : }
121 : }
122 : };
123 :
124 : /*!
125 : * \brief Manages the cached buffer data associated with a CCE worldtube and
126 : * interpolates to requested time points to provide worldtube boundary data to
127 : * the main evolution routines.
128 : *
129 : * \details The maintained buffer will be maintained at a length that is set by
130 : * the `Interpolator` and the `buffer_depth` also passed to the constructor. A
131 : * longer depth will ensure that the buffer updater is called less frequently,
132 : * which is useful for slow updaters (e.g. those that perform file access).
133 : * The main functionality is provided by the
134 : * `WorldtubeDataManager::populate_hypersurface_boundary_data()` member
135 : * function that handles buffer updating and boundary computation.
136 : */
137 1 : class MetricWorldtubeDataManager
138 : : public WorldtubeDataManager<
139 : Tags::characteristic_worldtube_boundary_tags<Tags::BoundaryValue>> {
140 0 : using input_tags = cce_metric_input_tags<ComplexModalVector>;
141 :
142 : public:
143 : // charm needs an empty constructor.
144 0 : MetricWorldtubeDataManager() = default;
145 :
146 0 : MetricWorldtubeDataManager(
147 : std::unique_ptr<WorldtubeBufferUpdater<input_tags>> buffer_updater,
148 : size_t l_max, size_t buffer_depth,
149 : std::unique_ptr<intrp::SpanInterpolator> interpolator,
150 : bool fix_spec_normalization);
151 :
152 0 : WRAPPED_PUPable_decl_template(MetricWorldtubeDataManager); // NOLINT
153 :
154 0 : explicit MetricWorldtubeDataManager(CkMigrateMessage* /*unused*/) {}
155 :
156 : /*!
157 : * \brief Update the `boundary_data_box` entries for all tags in
158 : * `Tags::characteristic_worldtube_boundary_tags` to the boundary data at
159 : * `time`.
160 : *
161 : * \details First, if the stored buffer requires updating, it will be updated
162 : * via the `buffer_updater_` supplied in the constructor. Then, each of the
163 : * spatial metric, shift, lapse, and each of their radial and time derivatives
164 : * are interpolated across buffer points to the requested time value (via the
165 : * `Interpolator` provided in the constructor). Finally, that data is supplied
166 : * to the `create_bondi_boundary_data()`, which updates the
167 : * `boundary_data_box` with the Bondi spin-weighted scalars determined from
168 : * the interpolated Cartesian data.
169 : *
170 : * Returns `true` if the time can be supplied from the `buffer_updater_`, and
171 : * `false` otherwise. No tags are updated if `false` is returned.
172 : */
173 1 : bool populate_hypersurface_boundary_data(
174 : gsl::not_null<Variables<
175 : Tags::characteristic_worldtube_boundary_tags<Tags::BoundaryValue>>*>
176 : boundary_data_variables,
177 : double time, gsl::not_null<Parallel::NodeLock*> hdf5_lock) const override;
178 :
179 0 : std::unique_ptr<WorldtubeDataManager> get_clone() const override;
180 :
181 : /// retrieves the l_max that will be supplied to the \ref DataBoxGroup in
182 : /// `populate_hypersurface_boundary_data()`
183 1 : size_t get_l_max() const override { return l_max_; }
184 :
185 : /// retrieves the current time span associated with the `buffer_updater_` for
186 : /// diagnostics
187 1 : std::pair<size_t, size_t> get_time_span() const override;
188 :
189 : /// Serialization for Charm++.
190 1 : void pup(PUP::er& p) override; // NOLINT
191 :
192 : private:
193 0 : std::unique_ptr<WorldtubeBufferUpdater<input_tags>> buffer_updater_;
194 : // NOLINTNEXTLINE(spectre-mutable)
195 0 : mutable size_t time_span_start_ = 0;
196 : // NOLINTNEXTLINE(spectre-mutable)
197 0 : mutable size_t time_span_end_ = 0;
198 0 : size_t l_max_ = 0;
199 0 : bool fix_spec_normalization_ = false;
200 :
201 : // These buffers are just kept around to avoid allocations; they're
202 : // updated every time a time is requested
203 : // NOLINTNEXTLINE(spectre-mutable)
204 0 : mutable Variables<input_tags> interpolated_coefficients_;
205 :
206 : // note: buffers store data in a 'time-varies-fastest' manner
207 : // NOLINTNEXTLINE(spectre-mutable)
208 0 : mutable Variables<input_tags> coefficients_buffers_;
209 :
210 0 : size_t buffer_depth_ = 0;
211 :
212 0 : std::unique_ptr<intrp::SpanInterpolator> interpolator_;
213 : };
214 :
215 : /*!
216 : * \brief Manages the bondi cached buffer dataset associated with a CCE
217 : * worldtube and interpolates to requested time points to provide worldtube
218 : * boundary data to the main evolution routines.
219 : *
220 : * \details The maintained buffer will be kept at a length that is set by
221 : * the `Interpolator` and the `buffer_depth` also passed to the constructor. A
222 : * longer depth will ensure that the buffer updater is called less frequently,
223 : * which is useful for slow updaters (e.g. those that perform file access).
224 : * The main functionality is provided by the
225 : * `WorldtubeDataManager::populate_hypersurface_boundary_data()` member
226 : * function that handles buffer updating and boundary computation. This version
227 : * of the data manager handles the 9 scalars of
228 : * `worldtube_boundary_tags_for_writing<Spectral::Swsh::Tags::SwshTransform>`,
229 : * rather than direct metric components handled by `WorldtubeDataManager`. The
230 : * set of 9 scalars is a far leaner (factor of ~4) data storage format.
231 : */
232 1 : class BondiWorldtubeDataManager
233 : : public WorldtubeDataManager<
234 : Tags::characteristic_worldtube_boundary_tags<Tags::BoundaryValue>> {
235 : public:
236 : // charm needs an empty constructor.
237 0 : BondiWorldtubeDataManager() = default;
238 :
239 0 : BondiWorldtubeDataManager(
240 : std::unique_ptr<
241 : WorldtubeBufferUpdater<Tags::worldtube_boundary_tags_for_writing<
242 : Spectral::Swsh::Tags::SwshTransform>>>
243 : buffer_updater,
244 : size_t l_max, size_t buffer_depth,
245 : std::unique_ptr<intrp::SpanInterpolator> interpolator);
246 :
247 0 : WRAPPED_PUPable_decl_template(BondiWorldtubeDataManager); // NOLINT
248 :
249 0 : explicit BondiWorldtubeDataManager(CkMigrateMessage* /*unused*/) {}
250 :
251 : /*!
252 : * \brief Update the `boundary_data_box` entries for all tags in
253 : * `Tags::characteristic_worldtube_boundary_tags` to the boundary data at
254 : * `time`.
255 : *
256 : * \details First, if the stored buffer requires updating, it will be updated
257 : * via the `buffer_updater_` supplied in the constructor. Then, each of the
258 : * 9 spin-weighted scalars in
259 : * `worldtube_boundary_tags_for_writing<Spectral::Swsh::Tags::SwshTransform>`
260 : * are interpolated across buffer points to the requested time value (via the
261 : * `Interpolator` provided in the constructor). Finally, the remaining two
262 : * scalars not directly supplied in the input file are calculated in-line and
263 : * put in the \ref DataBoxGroup.
264 : *
265 : * Returns `true` if the time can be supplied from the `buffer_updater_`, and
266 : * `false` otherwise. No tags are updated if `false` is returned.
267 : */
268 1 : bool populate_hypersurface_boundary_data(
269 : gsl::not_null<Variables<
270 : Tags::characteristic_worldtube_boundary_tags<Tags::BoundaryValue>>*>
271 : boundary_data_variables,
272 : double time, gsl::not_null<Parallel::NodeLock*> hdf5_lock) const override;
273 :
274 0 : std::unique_ptr<WorldtubeDataManager> get_clone() const override;
275 :
276 : /// retrieves the l_max that will be supplied to the \ref DataBoxGroup in
277 : /// `populate_hypersurface_boundary_data()`
278 1 : size_t get_l_max() const override { return l_max_; }
279 :
280 : /// retrieves the current time span associated with the `buffer_updater_` for
281 : /// diagnostics
282 1 : std::pair<size_t, size_t> get_time_span() const override;
283 :
284 : /// \brief Use `interpolator` in place of `interpolator_` for the time
285 : /// derivative that produces the `Du<Dr<BondiJ>>` boundary value.
286 : ///
287 : /// \details Passing `nullptr` (the default state) leaves that derivative on
288 : /// `interpolator_`. This derivative is taken inside the window the evolution
289 : /// already caches, which `interpolator_` sizes, so `interpolator` must not
290 : /// need a wider stencil than `interpolator_` does; it is meant for a *lower*
291 : /// order than the evolution runs with. A wider one is rejected here rather
292 : /// than left to fail deep inside the interpolator.
293 1 : void set_du_dr_j_interpolator(
294 : std::unique_ptr<intrp::SpanInterpolator> interpolator) override;
295 :
296 : /// Serialization for Charm++.
297 1 : void pup(PUP::er& p) override; // NOLINT
298 :
299 : private:
300 : // Compute the boundary value of `Du<Dr<BondiJ>>` at the requested time by
301 : // numerically time-differentiating the buffered `Dr<BondiJ>` with
302 : // `interpolator_`, holding the angular coordinate fixed (i.e. following the
303 : // worldtube). This is the time derivative at constant numerical coordinate
304 : // y = -1, i.e. d_ubreve d_r J|_Gamma = d/du (d_r J|_Gamma), and is *not* a
305 : // derivative at constant Bondi r.
306 0 : void populate_boundary_du_dr_j(
307 : gsl::not_null<Variables<
308 : Tags::characteristic_worldtube_boundary_tags<Tags::BoundaryValue>>*>
309 : boundary_data_variables,
310 : double time) const;
311 :
312 : std::unique_ptr<
313 : WorldtubeBufferUpdater<Tags::worldtube_boundary_tags_for_writing<
314 : Spectral::Swsh::Tags::SwshTransform>>>
315 0 : buffer_updater_;
316 : // NOLINTNEXTLINE(spectre-mutable)
317 0 : mutable size_t time_span_start_ = 0;
318 : // NOLINTNEXTLINE(spectre-mutable)
319 0 : mutable size_t time_span_end_ = 0;
320 0 : size_t l_max_ = 0;
321 :
322 : // These buffers are just kept around to avoid allocations; they're
323 : // updated every time a time is requested
324 : // NOLINTNEXTLINE(spectre-mutable)
325 : mutable Variables<Tags::worldtube_boundary_tags_for_writing<
326 : Spectral::Swsh::Tags::SwshTransform>>
327 0 : interpolated_coefficients_;
328 :
329 : // note: buffers store data in an 'time-varies-fastest' manner
330 : // NOLINTNEXTLINE(spectre-mutable)
331 : mutable Variables<Tags::worldtube_boundary_tags_for_writing<
332 : Spectral::Swsh::Tags::SwshTransform>>
333 0 : coefficients_buffers_;
334 :
335 0 : size_t buffer_depth_ = 0;
336 :
337 0 : std::unique_ptr<intrp::SpanInterpolator> interpolator_;
338 :
339 : // Used instead of `interpolator_` for the `Du<Dr<BondiJ>>` time derivative
340 : // when the initial-data generator asks for its own; null otherwise.
341 0 : std::unique_ptr<intrp::SpanInterpolator> du_dr_j_interpolator_;
342 : };
343 :
344 0 : class KleinGordonWorldtubeDataManager
345 : : public WorldtubeDataManager<Tags::klein_gordon_worldtube_boundary_tags> {
346 : public:
347 : // charm needs an empty constructor.
348 0 : KleinGordonWorldtubeDataManager() = default;
349 :
350 0 : KleinGordonWorldtubeDataManager(
351 : std::unique_ptr<WorldtubeBufferUpdater<klein_gordon_input_tags>>
352 : buffer_updater,
353 : size_t l_max, size_t buffer_depth,
354 : std::unique_ptr<intrp::SpanInterpolator> interpolator);
355 :
356 0 : WRAPPED_PUPable_decl_template(KleinGordonWorldtubeDataManager); // NOLINT
357 :
358 0 : explicit KleinGordonWorldtubeDataManager(CkMigrateMessage* /*unused*/) {}
359 :
360 : /*!
361 : * \brief Update the `boundary_data_box` entries for all tags in
362 : * `Tags::klein_gordon_worldtube_boundary_tags` to the boundary data at
363 : * `time`.
364 : *
365 : * \details First, if the stored buffer requires updating, it will be updated
366 : * via the `buffer_updater_` supplied in the constructor. Then, each of the
367 : * 2 spin-weighted scalars in `Tags::klein_gordon_worldtube_boundary_tags`
368 : * are interpolated across buffer points to the requested time value (via the
369 : * `Interpolator` provided in the constructor).
370 : *
371 : * Returns `true` if the time can be supplied from the `buffer_updater_`, and
372 : * `false` otherwise. No tags are updated if `false` is returned.
373 : */
374 1 : bool populate_hypersurface_boundary_data(
375 : gsl::not_null<Variables<Tags::klein_gordon_worldtube_boundary_tags>*>
376 : boundary_data_variables,
377 : double time, gsl::not_null<Parallel::NodeLock*> hdf5_lock) const override;
378 :
379 0 : std::unique_ptr<WorldtubeDataManager> get_clone() const override;
380 :
381 : /// retrieves the l_max that will be supplied to the \ref DataBoxGroup in
382 : /// `populate_hypersurface_boundary_data()`
383 1 : size_t get_l_max() const override { return l_max_; }
384 :
385 : /// retrieves the current time span associated with the `buffer_updater_` for
386 : /// diagnostics
387 1 : std::pair<size_t, size_t> get_time_span() const override;
388 :
389 : /// Serialization for Charm++.
390 1 : void pup(PUP::er& p) override; // NOLINT
391 :
392 : private:
393 : std::unique_ptr<WorldtubeBufferUpdater<klein_gordon_input_tags>>
394 0 : buffer_updater_;
395 : // NOLINTNEXTLINE(spectre-mutable)
396 0 : mutable size_t time_span_start_ = 0;
397 : // NOLINTNEXTLINE(spectre-mutable)
398 0 : mutable size_t time_span_end_ = 0;
399 0 : size_t l_max_ = 0;
400 :
401 : // These buffers are just kept around to avoid allocations; they're
402 : // updated every time a time is requested
403 : // NOLINTNEXTLINE(spectre-mutable)
404 0 : mutable Variables<klein_gordon_input_tags> interpolated_coefficients_;
405 :
406 : // note: buffers store data in an 'time-varies-fastest' manner
407 : // NOLINTNEXTLINE(spectre-mutable)
408 0 : mutable Variables<klein_gordon_input_tags> coefficients_buffers_;
409 :
410 0 : size_t buffer_depth_ = 0;
411 :
412 0 : std::unique_ptr<intrp::SpanInterpolator> interpolator_;
413 : };
414 : } // namespace Cce
|