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 <memory>
8 : #include <optional>
9 : #include <string>
10 : #include <utility>
11 :
12 : #include "DataStructures/ComplexModalVector.hpp"
13 : #include "DataStructures/DataBox/PrefixHelpers.hpp"
14 : #include "DataStructures/DataBox/Prefixes.hpp"
15 : #include "DataStructures/DataBox/Tag.hpp"
16 : #include "DataStructures/DataBox/TagName.hpp"
17 : #include "DataStructures/DataVector.hpp"
18 : #include "DataStructures/Matrix.hpp"
19 : #include "Evolution/Systems/Cce/Tags.hpp"
20 : #include "IO/H5/Dat.hpp"
21 : #include "IO/H5/File.hpp"
22 : #include "IO/H5/Version.hpp"
23 : #include "NumericalAlgorithms/SpinWeightedSphericalHarmonics/SwshTags.hpp"
24 : #include "PointwiseFunctions/GeneralRelativity/Tags.hpp"
25 : #include "Utilities/ErrorHandling/Assert.hpp"
26 : #include "Utilities/Gsl.hpp"
27 : #include "Utilities/Serialization/CharmPupable.hpp"
28 : #include "Utilities/Serialization/PupStlCpp17.hpp"
29 : #include "Utilities/TMPL.hpp"
30 : #include "Utilities/TaggedTuple.hpp"
31 :
32 : namespace Cce {
33 : namespace Tags {
34 : namespace detail {
35 : // tags for use in the buffers for the modal input worldtube data management
36 : // classes
37 : using SpatialMetric = gr::Tags::SpatialMetric<ComplexModalVector, 3>;
38 : using Shift = gr::Tags::Shift<ComplexModalVector, 3>;
39 : using Lapse = gr::Tags::Lapse<ComplexModalVector>;
40 :
41 : // radial derivative prefix tag to be used with the modal input worldtube data
42 : template <typename Tag>
43 : struct Dr : db::SimpleTag, db::PrefixTag {
44 : using type = typename Tag::type;
45 : using tag = Tag;
46 : };
47 :
48 : // tag for the string for accessing the quantity associated with `Tag` in
49 : // worldtube h5 file
50 : template <typename Tag>
51 : struct InputDataSet : db::SimpleTag, db::PrefixTag {
52 : using type = std::string;
53 : using tag = Tag;
54 : };
55 : } // namespace detail
56 : } // namespace Tags
57 :
58 : namespace detail {
59 : // generates the component dataset name in the worldtube file based on the
60 : // tensor indices requested. For instance, if called with arguments ("/g", 0,1),
61 : // it returns the dataset name "/gxy".
62 : template <typename... T>
63 : std::string dataset_name_for_component(std::string base_name,
64 : const T... indices) { // NOLINT
65 : const auto add_index = [&base_name](size_t index) {
66 : ASSERT(index < 3, "The character-arithmetic index must be less than 3.");
67 : base_name += static_cast<char>('x' + index);
68 : };
69 : EXPAND_PACK_LEFT_TO_RIGHT(add_index(indices));
70 : // void cast so that compilers can tell it's used.
71 : (void)add_index;
72 : return base_name;
73 : }
74 :
75 : // creates a pair of indices such that the difference is `2 *
76 : // interpolator_length + pad`, centered around `time`, and bounded by
77 : // `lower_bound` and `upper_bound`. If it cannot be centered, it gives a span
78 : // that is appropriately sized and bounded by the supplied bounds. If the bounds
79 : // are too constraining for the necessary size, it gives a span that is the
80 : // correct size starting at `lower bound`, but not constrained by `upper_bound`
81 : std::pair<size_t, size_t> create_span_for_time_value(
82 : double time, size_t pad, size_t interpolator_length, size_t lower_bound,
83 : size_t upper_bound, const DataVector& time_buffer);
84 :
85 : // retrieves time stamps and lmax the from the specified file.
86 : void set_time_buffer_and_lmax(gsl::not_null<DataVector*> time_buffer,
87 : size_t& l_max, const h5::Dat& data);
88 :
89 : // retrieves modal data from Bondi or Klein-Gordon worldtube H5 file.
90 : void update_buffer_with_modal_data(
91 : gsl::not_null<ComplexModalVector*> buffer_to_update,
92 : const h5::Dat& read_data, size_t computation_l_max, size_t l_max,
93 : size_t time_span_start, size_t time_span_end, bool is_real);
94 :
95 : // updates `time_span_start` and `time_span_end` based on the provided `time`,
96 : // and inserts the cooresponding modal data (for `InputTags`) from worldtube H5
97 : // file into `buffers`. The function is used by Bondi and Klein-Gordon systems.
98 : template <typename InputTags>
99 : double update_buffers_for_time(
100 : gsl::not_null<Variables<InputTags>*> buffers,
101 : gsl::not_null<size_t*> time_span_start,
102 : gsl::not_null<size_t*> time_span_end, double time, size_t computation_l_max,
103 : size_t l_max, size_t interpolator_length, size_t buffer_depth,
104 : const DataVector& time_buffer,
105 : const tuples::tagged_tuple_from_typelist<
106 : db::wrap_tags_in<Tags::detail::InputDataSet, InputTags>>& dataset_names,
107 : const h5::H5File<h5::AccessType::ReadOnly>& cce_data_file);
108 : } // namespace detail
109 :
110 : /// the full set of tensors to be extracted from the worldtube h5 file
111 1 : using cce_metric_input_tags = tmpl::list<
112 : Tags::detail::SpatialMetric, Tags::detail::Dr<Tags::detail::SpatialMetric>,
113 : ::Tags::dt<Tags::detail::SpatialMetric>, Tags::detail::Shift,
114 : Tags::detail::Dr<Tags::detail::Shift>, ::Tags::dt<Tags::detail::Shift>,
115 : Tags::detail::Lapse, Tags::detail::Dr<Tags::detail::Lapse>,
116 : ::Tags::dt<Tags::detail::Lapse>>;
117 :
118 : /// the full set of tensors to be extracted from the reduced form of the
119 : /// worldtube h5 file
120 1 : using cce_bondi_input_tags =
121 : tmpl::list<Spectral::Swsh::Tags::SwshTransform<Tags::BondiBeta>,
122 : Spectral::Swsh::Tags::SwshTransform<Tags::BondiU>,
123 : Spectral::Swsh::Tags::SwshTransform<Tags::BondiQ>,
124 : Spectral::Swsh::Tags::SwshTransform<Tags::BondiW>,
125 : Spectral::Swsh::Tags::SwshTransform<Tags::BondiJ>,
126 : Spectral::Swsh::Tags::SwshTransform<Tags::Dr<Tags::BondiJ>>,
127 : Spectral::Swsh::Tags::SwshTransform<Tags::Du<Tags::BondiJ>>,
128 : Spectral::Swsh::Tags::SwshTransform<Tags::BondiR>,
129 : Spectral::Swsh::Tags::SwshTransform<Tags::Du<Tags::BondiR>>>;
130 :
131 0 : using klein_gordon_input_tags =
132 : tmpl::list<Spectral::Swsh::Tags::SwshTransform<Tags::KleinGordonPsi>,
133 : Spectral::Swsh::Tags::SwshTransform<Tags::KleinGordonPi>>;
134 :
135 : /// \cond
136 : class MetricWorldtubeH5BufferUpdater;
137 : class BondiWorldtubeH5BufferUpdater;
138 : class KleinGordonWorldtubeH5BufferUpdater;
139 : /// \endcond
140 :
141 : /*!
142 : * \brief Abstract base class for utilities that are able to perform the buffer
143 : * updating procedure needed by the `WorldtubeDataManager`.
144 : *
145 : * \details The methods that are required to be overridden in the derived
146 : * classes are:
147 : * - `WorldtubeBufferUpdater::update_buffers_for_time()`:
148 : * updates the buffers passed by pointer and the `time_span_start` and
149 : * `time_span_end` to be appropriate for the requested `time`,
150 : * `interpolator_length`, and `buffer_depth`.
151 : * - `WorldtubeBufferUpdater::get_clone()`
152 : * clone function to obtain a `std::unique_ptr` of the base
153 : * `WorldtubeBufferUpdater`, needed to pass around the factory-created
154 : * object.
155 : * - `WorldtubeBufferUpdater::time_is_outside_range()`
156 : * the override should return `true` if the `time` could be used in a
157 : * `update_buffers_for_time` call given the data available to the derived
158 : * class, and `false` otherwise
159 : * - `WorldtubeBufferUpdater::get_l_max()`
160 : * The override should return the `l_max` it uses in the
161 : * Goldberg modal data placed in the buffers.
162 : * - `WorldtubeBufferUpdater::get_extraction_radius()`
163 : * The override should return the coordinate radius associated with the modal
164 : * worldtube data that it supplies in the buffer update function. This is
165 : * currently assumed to be a single double, but may be generalized in future
166 : * to be time-dependent.
167 : * - `WorldtubeBufferUpdater::get_time_buffer`
168 : * The override should return the vector of times that it can produce modal
169 : * data at. For instance, if associated with a file input, this will be the
170 : * times at each of the rows of the time-series data.
171 : */
172 : template <typename BufferTags>
173 1 : class WorldtubeBufferUpdater : public PUP::able {
174 : public:
175 0 : using creatable_classes =
176 : tmpl::list<MetricWorldtubeH5BufferUpdater, BondiWorldtubeH5BufferUpdater,
177 : KleinGordonWorldtubeH5BufferUpdater>;
178 :
179 0 : WRAPPED_PUPable_abstract(WorldtubeBufferUpdater); // NOLINT
180 :
181 0 : virtual double update_buffers_for_time(
182 : gsl::not_null<Variables<BufferTags>*> buffers,
183 : gsl::not_null<size_t*> time_span_start,
184 : gsl::not_null<size_t*> time_span_end, double time,
185 : size_t computation_l_max, size_t interpolator_length,
186 : size_t buffer_depth) const = 0;
187 :
188 0 : virtual std::unique_ptr<WorldtubeBufferUpdater> get_clone() const = 0;
189 :
190 0 : virtual bool time_is_outside_range(double time) const = 0;
191 :
192 0 : virtual size_t get_l_max() const = 0;
193 :
194 0 : virtual double get_extraction_radius() const = 0;
195 :
196 0 : virtual bool has_version_history() const = 0;
197 :
198 0 : virtual DataVector& get_time_buffer() = 0;
199 : };
200 :
201 : /// A `WorldtubeBufferUpdater` specialized to the CCE input worldtube H5 file
202 : /// produced by SpEC.
203 1 : class MetricWorldtubeH5BufferUpdater
204 : : public WorldtubeBufferUpdater<cce_metric_input_tags> {
205 : public:
206 : // charm needs the empty constructor
207 0 : MetricWorldtubeH5BufferUpdater() = default;
208 :
209 : /// The constructor takes the filename of the SpEC h5 file that will be used
210 : /// for boundary data. The extraction radius can either be passed in directly,
211 : /// or if it takes the value `std::nullopt`, then the extraction radius is
212 : /// retrieved as an integer in the filename.
213 1 : explicit MetricWorldtubeH5BufferUpdater(
214 : const std::string& cce_data_filename,
215 : std::optional<double> extraction_radius = std::nullopt);
216 :
217 0 : WRAPPED_PUPable_decl_template(MetricWorldtubeH5BufferUpdater); // NOLINT
218 :
219 0 : explicit MetricWorldtubeH5BufferUpdater(CkMigrateMessage* /*unused*/) {}
220 :
221 : /// update the `buffers`, `time_span_start`, and `time_span_end` with
222 : /// time-varies-fastest, Goldberg modal data and the start and end index in
223 : /// the member `time_buffer_` covered by the newly updated `buffers`. The
224 : /// function returns the next time at which a full update will occur. If
225 : /// called again at times earlier than the next full update time, it will
226 : /// leave the `buffers` unchanged and again return the next needed time.
227 1 : double update_buffers_for_time(
228 : gsl::not_null<Variables<cce_metric_input_tags>*> buffers,
229 : gsl::not_null<size_t*> time_span_start,
230 : gsl::not_null<size_t*> time_span_end, double time,
231 : size_t computation_l_max, size_t interpolator_length,
232 : size_t buffer_depth) const override;
233 :
234 0 : std::unique_ptr<WorldtubeBufferUpdater<cce_metric_input_tags>> get_clone()
235 : const override;
236 :
237 : /// The time can only be supported in the buffer update if it is between the
238 : /// first and last time of the input file.
239 1 : bool time_is_outside_range(double time) const override;
240 :
241 : /// retrieves the l_max of the input file
242 1 : size_t get_l_max() const override { return l_max_; }
243 :
244 : /// retrieves the extraction radius
245 1 : double get_extraction_radius() const override { return extraction_radius_; }
246 :
247 : /// The time buffer is supplied by non-const reference to allow views to
248 : /// easily point into the buffer.
249 : ///
250 : /// \warning Altering this buffer outside of the constructor of this class
251 : /// results in undefined behavior! This should be supplied by const reference
252 : /// once there is a convenient method of producing a const view of a vector
253 : /// type.
254 1 : DataVector& get_time_buffer() override { return time_buffer_; }
255 :
256 0 : bool has_version_history() const override { return has_version_history_; }
257 :
258 : /// Serialization for Charm++.
259 1 : void pup(PUP::er& p) override;
260 :
261 : private:
262 0 : void update_buffer(gsl::not_null<ComplexModalVector*> buffer_to_update,
263 : const h5::Dat& read_data, size_t computation_l_max,
264 : size_t time_span_start, size_t time_span_end) const;
265 :
266 0 : bool has_version_history_ = true;
267 0 : double extraction_radius_ = std::numeric_limits<double>::signaling_NaN();
268 0 : size_t l_max_ = 0;
269 :
270 0 : h5::H5File<h5::AccessType::ReadOnly> cce_data_file_;
271 0 : std::string filename_;
272 :
273 : tuples::tagged_tuple_from_typelist<
274 : db::wrap_tags_in<Tags::detail::InputDataSet, cce_metric_input_tags>>
275 0 : dataset_names_;
276 :
277 : // stores all the times in the input file
278 0 : DataVector time_buffer_;
279 : };
280 :
281 : /// A `WorldtubeBufferUpdater` specialized to the CCE input worldtube H5 file
282 : /// produced by the reduced SpEC format.
283 1 : class BondiWorldtubeH5BufferUpdater
284 : : public WorldtubeBufferUpdater<cce_bondi_input_tags> {
285 : public:
286 : // charm needs the empty constructor
287 0 : BondiWorldtubeH5BufferUpdater() = default;
288 :
289 : /// The constructor takes the filename of the SpEC h5 file that will be used
290 : /// for boundary data. The extraction radius can either be passed in directly,
291 : /// or if it takes the value `std::nullopt`, then the extraction radius is
292 : /// retrieved as an integer in the filename.
293 1 : explicit BondiWorldtubeH5BufferUpdater(
294 : const std::string& cce_data_filename,
295 : std::optional<double> extraction_radius = std::nullopt);
296 :
297 0 : WRAPPED_PUPable_decl_template(BondiWorldtubeH5BufferUpdater); // NOLINT
298 :
299 0 : explicit BondiWorldtubeH5BufferUpdater(CkMigrateMessage* /*unused*/) {}
300 :
301 : /// update the `buffers`, `time_span_start`, and `time_span_end` with
302 : /// time-varies-fastest, Goldberg modal data and the start and end index in
303 : /// the member `time_buffer_` covered by the newly updated `buffers`.
304 1 : double update_buffers_for_time(
305 : gsl::not_null<Variables<cce_bondi_input_tags>*> buffers,
306 : gsl::not_null<size_t*> time_span_start,
307 : gsl::not_null<size_t*> time_span_end, double time,
308 : size_t computation_l_max, size_t interpolator_length,
309 : size_t buffer_depth) const override;
310 :
311 0 : std::unique_ptr<WorldtubeBufferUpdater<cce_bondi_input_tags>> get_clone()
312 : const override {
313 : return std::make_unique<BondiWorldtubeH5BufferUpdater>(filename_);
314 : }
315 :
316 : /// The time can only be supported in the buffer update if it is between the
317 : /// first and last time of the input file.
318 1 : bool time_is_outside_range(const double time) const override {
319 : return time < time_buffer_[0] or
320 : time > time_buffer_[time_buffer_.size() - 1];
321 : }
322 :
323 : /// retrieves the l_max of the input file
324 1 : size_t get_l_max() const override { return l_max_; }
325 :
326 : /// retrieves the extraction radius. In most normal circumstances, this will
327 : /// not be needed for Bondi data.
328 1 : double get_extraction_radius() const override {
329 : if (not extraction_radius_.has_value()) {
330 : ERROR(
331 : "Extraction radius has not been set, and was not successfully parsed "
332 : "from the filename. The extraction radius has been used, so must be "
333 : "set either by the input file or via the filename.");
334 : }
335 : return *extraction_radius_;
336 : }
337 :
338 : /// The time buffer is supplied by non-const reference to allow views to
339 : /// easily point into the buffer.
340 : ///
341 : /// \warning Altering this buffer outside of the constructor of this class
342 : /// results in undefined behavior! This should be supplied by const reference
343 : /// once there is a convenient method of producing a const view of a vector
344 : /// type.
345 1 : DataVector& get_time_buffer() override { return time_buffer_; }
346 :
347 0 : bool has_version_history() const override { return true; }
348 :
349 : /// Serialization for Charm++.
350 1 : void pup(PUP::er& p) override;
351 :
352 : private:
353 0 : void update_buffer(gsl::not_null<ComplexModalVector*> buffer_to_update,
354 : const h5::Dat& read_data, size_t computation_l_max,
355 : size_t time_span_start, size_t time_span_end,
356 : bool is_real) const;
357 :
358 0 : std::optional<double> extraction_radius_ = std::nullopt;
359 0 : size_t l_max_ = 0;
360 :
361 0 : h5::H5File<h5::AccessType::ReadOnly> cce_data_file_;
362 0 : std::string filename_;
363 :
364 : tuples::tagged_tuple_from_typelist<
365 : db::wrap_tags_in<Tags::detail::InputDataSet, cce_bondi_input_tags>>
366 0 : dataset_names_;
367 :
368 : // stores all the times in the input file
369 0 : DataVector time_buffer_;
370 : };
371 :
372 : /// A `WorldtubeBufferUpdater` specialized to the Klein-Gordon input worldtube
373 : /// H5 file produced by the SpEC format. We assume the scalar field is
374 : /// real-valued.
375 1 : class KleinGordonWorldtubeH5BufferUpdater
376 : : public WorldtubeBufferUpdater<klein_gordon_input_tags> {
377 : public:
378 : // charm needs the empty constructor
379 0 : KleinGordonWorldtubeH5BufferUpdater() = default;
380 :
381 : /// The constructor takes the filename of the SpEC h5 file that will be used
382 : /// for boundary data. The extraction radius can either be passed in directly,
383 : /// or if it takes the value `std::nullopt`, then the extraction radius is
384 : /// retrieved as an integer in the filename.
385 1 : explicit KleinGordonWorldtubeH5BufferUpdater(
386 : const std::string& cce_data_filename,
387 : std::optional<double> extraction_radius = std::nullopt);
388 :
389 0 : WRAPPED_PUPable_decl_template(KleinGordonWorldtubeH5BufferUpdater); // NOLINT
390 :
391 0 : explicit KleinGordonWorldtubeH5BufferUpdater(CkMigrateMessage* /*unused*/) {}
392 :
393 : /// update the `buffers`, `time_span_start`, and `time_span_end` with
394 : /// time-varies-fastest, Goldberg modal data and the start and end index in
395 : /// the member `time_buffer_` covered by the newly updated `buffers`.
396 1 : double update_buffers_for_time(
397 : gsl::not_null<Variables<klein_gordon_input_tags>*> buffers,
398 : gsl::not_null<size_t*> time_span_start,
399 : gsl::not_null<size_t*> time_span_end, double time,
400 : size_t computation_l_max, size_t interpolator_length,
401 : size_t buffer_depth) const override;
402 :
403 0 : std::unique_ptr<WorldtubeBufferUpdater<klein_gordon_input_tags>> get_clone()
404 : const override {
405 : return std::make_unique<KleinGordonWorldtubeH5BufferUpdater>(filename_);
406 : }
407 :
408 : /// The time can only be supported in the buffer update if it is between the
409 : /// first and last time of the input file.
410 1 : bool time_is_outside_range(const double time) const override {
411 : return time < time_buffer_[0] or
412 : time > time_buffer_[time_buffer_.size() - 1];
413 : }
414 :
415 : /// retrieves the l_max of the input file
416 1 : size_t get_l_max() const override { return l_max_; }
417 :
418 : /// retrieves the extraction radius. In most normal circumstances, this will
419 : /// not be needed for Klein-Gordon data.
420 1 : double get_extraction_radius() const override {
421 : if (not static_cast<bool>(extraction_radius_)) {
422 : ERROR(
423 : "Extraction radius has not been set, and was not successfully parsed "
424 : "from the filename. The extraction radius has been used, so must be "
425 : "set either by the input file or via the filename.");
426 : }
427 : return *extraction_radius_;
428 : }
429 :
430 : /// The time buffer is supplied by non-const reference to allow views to
431 : /// easily point into the buffer.
432 : ///
433 : /// \warning Altering this buffer outside of the constructor of this class
434 : /// results in undefined behavior! This should be supplied by const reference
435 : /// once there is a convenient method of producing a const view of a vector
436 : /// type.
437 1 : DataVector& get_time_buffer() override { return time_buffer_; }
438 :
439 0 : bool has_version_history() const override { return true; }
440 :
441 : /// Serialization for Charm++.
442 1 : void pup(PUP::er& p) override;
443 :
444 : private:
445 : // The scalar field is assumed to be real-valued.
446 0 : void update_buffer(gsl::not_null<ComplexModalVector*> buffer_to_update,
447 : const h5::Dat& read_data, size_t computation_l_max,
448 : size_t time_span_start, size_t time_span_end) const;
449 :
450 0 : std::optional<double> extraction_radius_ = std::nullopt;
451 0 : size_t l_max_ = 0;
452 :
453 0 : h5::H5File<h5::AccessType::ReadOnly> cce_data_file_;
454 0 : std::string filename_;
455 :
456 : tuples::tagged_tuple_from_typelist<
457 : db::wrap_tags_in<Tags::detail::InputDataSet, klein_gordon_input_tags>>
458 0 : dataset_names_;
459 :
460 : // stores all the times in the input file
461 0 : DataVector time_buffer_;
462 : };
463 : } // namespace Cce
|