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