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 <limits>
8 : #include <memory>
9 : #include <optional>
10 : #include <string>
11 : #include <type_traits>
12 : #include <utility>
13 :
14 : #include "DataStructures/ComplexDataVector.hpp"
15 : #include "DataStructures/ComplexModalVector.hpp"
16 : #include "DataStructures/DataBox/PrefixHelpers.hpp"
17 : #include "DataStructures/DataBox/Prefixes.hpp"
18 : #include "DataStructures/DataBox/Tag.hpp"
19 : #include "DataStructures/DataBox/TagName.hpp"
20 : #include "DataStructures/DataVector.hpp"
21 : #include "DataStructures/Matrix.hpp"
22 : #include "Evolution/Systems/Cce/BoundaryData.hpp"
23 : #include "Evolution/Systems/Cce/Tags.hpp"
24 : #include "IO/H5/Dat.hpp"
25 : #include "IO/H5/File.hpp"
26 : #include "IO/H5/Version.hpp"
27 : #include "NumericalAlgorithms/SpinWeightedSphericalHarmonics/SwshTags.hpp"
28 : #include "Options/Options.hpp"
29 : #include "PointwiseFunctions/GeneralRelativity/Tags.hpp"
30 : #include "Utilities/ErrorHandling/Assert.hpp"
31 : #include "Utilities/Gsl.hpp"
32 : #include "Utilities/Serialization/CharmPupable.hpp"
33 : #include "Utilities/Serialization/PupStlCpp17.hpp"
34 : #include "Utilities/TMPL.hpp"
35 : #include "Utilities/TaggedTuple.hpp"
36 :
37 : namespace Cce {
38 : namespace Tags::detail {
39 : // tags for use in the buffers for the input worldtube data management classes
40 : template <typename T>
41 : using SpatialMetric = gr::Tags::SpatialMetric<T, 3>;
42 : template <typename T>
43 : using Shift = gr::Tags::Shift<T, 3>;
44 : template <typename T>
45 : using Lapse = gr::Tags::Lapse<T>;
46 : // This is B^i in the 3+1 equations
47 : template <typename T>
48 : struct AuxiliaryShift : db::SimpleTag {
49 : using type = tnsr::I<T, 3, ::Frame::Inertial>;
50 : };
51 : // This is \Gamma^i in the Z4c equations
52 : template <typename T>
53 : struct ConformalChristoffel : db::SimpleTag {
54 : using type = tnsr::I<T, 3, ::Frame::Inertial>;
55 : };
56 : template <typename T>
57 : using ExtrinsicCurvature = gr::Tags::ExtrinsicCurvature<T, 3>;
58 :
59 : // The three metric quantities we read in from disk (no derivatives)
60 : template <typename T>
61 : using metric_tags = tmpl::list<SpatialMetric<T>, Shift<T>, Lapse<T>>;
62 :
63 : // radial derivative prefix tag to be used with the input worldtube data
64 : template <typename Tag>
65 : struct Dr : db::SimpleTag, db::PrefixTag {
66 : using type = typename Tag::type;
67 : using tag = Tag;
68 : };
69 : // For cartesian derivs. Each dataset is stored separately in the file, so it
70 : // doesn't make sense to use ::Tags::deriv here
71 : template <typename Tag>
72 : struct Dx : db::SimpleTag, db::PrefixTag {
73 : static constexpr size_t index = 0;
74 : using type = typename Tag::type;
75 : };
76 : template <typename Tag>
77 : struct Dy : db::SimpleTag, db::PrefixTag {
78 : static constexpr size_t index = 1;
79 : using type = typename Tag::type;
80 : };
81 : template <typename Tag>
82 : struct Dz : db::SimpleTag, db::PrefixTag {
83 : static constexpr size_t index = 2;
84 : using type = typename Tag::type;
85 : };
86 : template <typename Tag>
87 : using cartesian_derivs_t = tmpl::list<Dx<Tag>, Dy<Tag>, Dz<Tag>>;
88 :
89 : // tag for the string for accessing the quantity associated with `Tag` in
90 : // worldtube h5 file
91 : template <typename Tag>
92 : struct InputDataSet : db::SimpleTag, db::PrefixTag {
93 : using type = std::string;
94 : using tag = Tag;
95 : };
96 :
97 : // Puts `Tag`, `::Tags::dt<Tag>`, and `Cce::Tags::Dr<Tag>` into a `tmpl::list`
98 : template <typename Tag>
99 : struct apply_derivs {
100 : using type = tmpl::list<Tag, ::Tags::dt<Tag>, Dr<Tag>>;
101 : };
102 : template <typename Tag>
103 : using apply_derivs_t = typename apply_derivs<Tag>::type;
104 :
105 : // Puts `Tag`, `::Tags::dt<Tag>`, `Dx<Tag>`, `Dy<Tag>`, `Dz<Tag>` into a
106 : // `tmpl::list`
107 : template <typename Tag>
108 : struct apply_derivs_adm {
109 : using type =
110 : tmpl::flatten<tmpl::list<Tag, ::Tags::dt<Tag>, cartesian_derivs_t<Tag>>>;
111 : };
112 : template <typename Tag>
113 : using apply_derivs_adm_t = typename apply_derivs_adm<Tag>::type;
114 : } // namespace Tags::detail
115 :
116 : namespace detail {
117 : // generates the component dataset name in the worldtube file based on the
118 : // tensor indices requested. For instance, if called with arguments ("/g", 0,1),
119 : // it returns the dataset name "/gxy".
120 : template <typename... T>
121 : std::string dataset_name_for_component(std::string base_name,
122 : const T... indices) { // NOLINT
123 : const auto add_index = [&base_name](size_t index) {
124 : ASSERT(index < 3, "The character-arithmetic index must be less than 3.");
125 : base_name += static_cast<char>('x' + index);
126 : };
127 : EXPAND_PACK_LEFT_TO_RIGHT(add_index(indices));
128 : // void cast so that compilers can tell it's used.
129 : (void)add_index;
130 : return base_name;
131 : }
132 :
133 : // creates a pair of indices such that the difference is `2 *
134 : // interpolator_length + pad`, centered around `time`, and bounded by
135 : // `lower_bound` and `upper_bound`. If it cannot be centered, it gives a span
136 : // that is appropriately sized and bounded by the supplied bounds. If the bounds
137 : // are too constraining for the necessary size, it gives a span that is the
138 : // correct size starting at `lower bound`, but not constrained by `upper_bound`
139 : std::pair<size_t, size_t> create_span_for_time_value(
140 : double time, size_t pad, size_t interpolator_length, size_t lower_bound,
141 : size_t upper_bound, const DataVector& time_buffer);
142 :
143 : // retrieves time stamps and lmax the from the specified file. the bools
144 : // `is_real`, `is_modal_data`, and `is_complex` are used to predict the number
145 : // of columns in the dat file and possibly error if that number is incorrect.
146 : // Note that if `is_modal_data` is true, then we use `is_real` but `is_complex`
147 : // is unneeded. If `is_modal_data` if false, then `is_complex` is used, but
148 : // `is_real` is unneeded.
149 : void set_time_buffer_and_lmax(gsl::not_null<DataVector*> time_buffer,
150 : size_t& l_max, const h5::Dat& data, bool is_real,
151 : bool is_modal_data, bool is_complex);
152 :
153 : // updates `time_span_start` and `time_span_end` based on the provided `time`,
154 : // and inserts the cooresponding modal data (for `InputTags`) from worldtube H5
155 : // file into `buffers`. The function is used by Bondi and Klein-Gordon systems.
156 : template <typename InputTags>
157 : double update_buffers_for_time(
158 : gsl::not_null<Variables<InputTags>*> buffers,
159 : gsl::not_null<size_t*> time_span_start,
160 : gsl::not_null<size_t*> time_span_end, double time, size_t computation_l_max,
161 : size_t l_max, size_t interpolator_length, size_t buffer_depth,
162 : const DataVector& time_buffer,
163 : const tuples::tagged_tuple_from_typelist<
164 : db::wrap_tags_in<Tags::detail::InputDataSet, InputTags>>& dataset_names,
165 : const h5::H5File<h5::AccessType::ReadOnly>& cce_data_file);
166 : } // namespace detail
167 :
168 : /// the full set of metric tensors to be extracted from the worldtube h5 file
169 : template <typename T>
170 1 : using cce_metric_input_tags =
171 : tmpl::flatten<tmpl::transform<Tags::detail::metric_tags<T>,
172 : Tags::detail::apply_derivs<tmpl::_1>>>;
173 :
174 : template <typename T>
175 0 : using cce_metric_adm_input_tags = tmpl::flatten<tmpl::push_back<
176 : tmpl::transform<Tags::detail::metric_tags<T>,
177 : Tags::detail::apply_derivs_adm<tmpl::_1>>,
178 : Tags::detail::ExtrinsicCurvature<T>, Tags::detail::AuxiliaryShift<T>,
179 : Tags::detail::ConformalChristoffel<T>>>;
180 :
181 0 : using klein_gordon_input_tags =
182 : tmpl::list<Spectral::Swsh::Tags::SwshTransform<Tags::KleinGordonPsi>,
183 : Spectral::Swsh::Tags::SwshTransform<Tags::KleinGordonPi>>;
184 :
185 : /// \cond
186 : template <typename T>
187 : class MetricWorldtubeH5BufferUpdater;
188 : template <typename T>
189 : class BondiWorldtubeH5BufferUpdater;
190 : class KleinGordonWorldtubeH5BufferUpdater;
191 : /// \endcond
192 :
193 : /*!
194 : * \brief Abstract base class for utilities that are able to perform the buffer
195 : * updating procedure needed by the `WorldtubeDataManager` or by the
196 : * `PreprocessCceWorldtube` executable.
197 : *
198 : * \details The methods that are required to be overridden in the derived
199 : * classes are:
200 : * - `WorldtubeBufferUpdater::update_buffers_for_time()`:
201 : * updates the buffers passed by pointer and the `time_span_start` and
202 : * `time_span_end` to be appropriate for the requested `time`,
203 : * `interpolator_length`, and `buffer_depth`.
204 : * - `WorldtubeBufferUpdater::get_clone()`
205 : * clone function to obtain a `std::unique_ptr` of the base
206 : * `WorldtubeBufferUpdater`, needed to pass around the factory-created
207 : * object.
208 : * - `WorldtubeBufferUpdater::time_is_outside_range()`
209 : * the override should return `true` if the `time` could be used in a
210 : * `update_buffers_for_time` call given the data available to the derived
211 : * class, and `false` otherwise
212 : * - `WorldtubeBufferUpdater::get_l_max()`
213 : * The override should return the `l_max` it uses in the
214 : * Goldberg modal data placed in the buffers.
215 : * - `WorldtubeBufferUpdater::get_extraction_radius()`
216 : * The override should return the coordinate radius associated with the modal
217 : * worldtube data that it supplies in the buffer update function. This is
218 : * currently assumed to be a single double, but may be generalized in future
219 : * to be time-dependent.
220 : * - `WorldtubeBufferUpdater::get_time_buffer`
221 : * The override should return the vector of times that it can produce
222 : * data at. For instance, if associated with a file input, this will be the
223 : * times at each of the rows of the time-series data.
224 : */
225 : template <typename BufferTags>
226 1 : class WorldtubeBufferUpdater : public PUP::able {
227 : public:
228 0 : using creatable_classes =
229 : tmpl::list<MetricWorldtubeH5BufferUpdater<ComplexModalVector>,
230 : MetricWorldtubeH5BufferUpdater<DataVector>,
231 : BondiWorldtubeH5BufferUpdater<ComplexModalVector>,
232 : BondiWorldtubeH5BufferUpdater<ComplexDataVector>,
233 : KleinGordonWorldtubeH5BufferUpdater>;
234 :
235 0 : WRAPPED_PUPable_abstract(WorldtubeBufferUpdater); // NOLINT
236 :
237 0 : virtual double update_buffers_for_time(
238 : gsl::not_null<Variables<BufferTags>*> buffers,
239 : gsl::not_null<size_t*> time_span_start,
240 : gsl::not_null<size_t*> time_span_end, double time,
241 : size_t computation_l_max, size_t interpolator_length, size_t buffer_depth,
242 : bool time_varies_fastest = true) const = 0;
243 :
244 0 : virtual std::unique_ptr<WorldtubeBufferUpdater> get_clone() const = 0;
245 :
246 0 : virtual bool time_is_outside_range(double time) const = 0;
247 :
248 0 : virtual size_t get_l_max() const = 0;
249 :
250 0 : virtual double get_extraction_radius() const = 0;
251 :
252 0 : virtual bool has_version_history() const = 0;
253 :
254 0 : virtual DataVector& get_time_buffer() = 0;
255 : };
256 :
257 : /*!
258 : * \brief A `WorldtubeBufferUpdater` specialized to CCE input worldtube H5 files
259 : * that have cartesian metric components stored in either modal or nodal form.
260 : *
261 : * \details To read in modal data, template this class as
262 : * `MetricWorldtubeH5BufferUpdater<ComplexModalVector>`. To read in nodal data,
263 : * template the class as `MetricWorldtubeH5BufferUpdater<DataVector>`. This
264 : * class also has the ability to read in data specifically written by SpEC.
265 : */
266 : template <typename T>
267 1 : class MetricWorldtubeH5BufferUpdater
268 : : public WorldtubeBufferUpdater<cce_metric_input_tags<T>> {
269 : static_assert(std::is_same_v<T, ComplexModalVector> or
270 : std::is_same_v<T, DataVector>,
271 : "Can only use ComplexModalVector or DataVector in a "
272 : "MetricWorldtubeH5BufferUpdater.");
273 :
274 : public:
275 0 : static constexpr bool is_modal = std::is_same_v<T, ComplexModalVector>;
276 :
277 : /*!
278 : * \brief Options needed when reading in the extrinsic curvature and auxiliary
279 : * shift (BSSN) or the trace of the conformal christoffel (Z4c) from a non-GH
280 : * evolution code.
281 : *
282 : * \details Can also be used as an option tag
283 : */
284 1 : struct AdmOptions {
285 0 : static std::string name() { return "AdmMetricNodal"; }
286 :
287 0 : struct Advective {
288 0 : using type = bool;
289 0 : static constexpr Options::String help =
290 : "Add advective term to time derivative.";
291 : };
292 :
293 0 : struct Lapse {
294 0 : using type = Lapse;
295 0 : Lapse() = default;
296 0 : using options = tmpl::list<Advective>;
297 0 : static constexpr Options::String help =
298 : "Options for 1+log slicing of the lapse.";
299 0 : explicit Lapse(const bool advective) : is_advective(advective) {}
300 :
301 0 : void pup(PUP::er& p) { p | is_advective; }
302 :
303 0 : bool is_advective;
304 : };
305 :
306 0 : struct Shift {
307 0 : using type = Shift;
308 0 : struct SecondOrderDriverEta {
309 0 : using type = double;
310 0 : static constexpr Options::String help =
311 : "Factor 'eta' in front of shift vector in Eq. 12 of Hilditch 2013 "
312 : "(typically 2/M). To use this, the trace conformal christoffel "
313 : "must be dumped.";
314 : };
315 0 : struct ConformalChristoffelFactor {
316 0 : using type = double;
317 0 : static constexpr Options::String help =
318 : "Factor A in mu_S=A/lapse^2 in front of conformal Christoffel term "
319 : "in Eq. 12 of Hilditch 2013 (typically A=1). To use this, the "
320 : "trace conformal Christoffel must be dumped.";
321 : };
322 0 : struct FirstOrderDriverFactor {
323 0 : using type = double;
324 0 : static constexpr Options::String help =
325 : "Factor in front of auxiliary shift vector B^i in left Eq. 4.89 of "
326 : "B&S (typically 0.75). To use this, the auxiliary shift vector B^i "
327 : "must be dumped. Here mu_S is assumed to be 1/lapse^2.";
328 : };
329 0 : Shift() = default;
330 0 : using options = tmpl::list<
331 : Advective,
332 : Options::Alternatives<
333 : tmpl::list<SecondOrderDriverEta, ConformalChristoffelFactor>,
334 : tmpl::list<FirstOrderDriverFactor>>>;
335 :
336 0 : static constexpr Options::String help =
337 : "Options for Gamma driver shift condition.";
338 0 : Shift(const bool advective, const double second_order_factor,
339 : const double conformal_christoffel_factor_in)
340 : : is_advective(advective),
341 : is_first_order(false),
342 : extra_factor(second_order_factor),
343 : conformal_christoffel_factor(conformal_christoffel_factor_in) {}
344 0 : Shift(const bool advective, const double first_order_factor)
345 : : is_advective(advective),
346 : is_first_order(true),
347 : extra_factor(first_order_factor),
348 : conformal_christoffel_factor(std::numeric_limits<double>::max()) {}
349 :
350 0 : void pup(PUP::er& p) {
351 : p | is_advective;
352 : p | is_first_order;
353 : p | extra_factor;
354 : }
355 :
356 0 : bool is_advective;
357 0 : bool is_first_order;
358 0 : double extra_factor;
359 0 : double conformal_christoffel_factor;
360 : };
361 :
362 0 : using options = tmpl::list<Lapse, Shift>;
363 0 : static constexpr Options::String help =
364 : "Gauge options when reading in extrinsic curvature additional variable "
365 : "from non-GH evolutions.";
366 :
367 0 : AdmOptions() = default;
368 0 : AdmOptions(const Lapse& lapse_in, const Shift& shift_in)
369 : : lapse(lapse_in), shift(shift_in) {}
370 :
371 0 : void pup(PUP::er& p) {
372 : p | lapse;
373 : p | shift;
374 : }
375 :
376 0 : Lapse lapse;
377 0 : Shift shift;
378 : };
379 :
380 : // charm needs the empty constructor
381 0 : MetricWorldtubeH5BufferUpdater() = default;
382 :
383 : /// The constructor takes the filename of the H5 file that will be used
384 : /// for boundary data. The extraction radius can either be passed in directly,
385 : /// or if it takes the value `std::nullopt`, then the extraction radius is
386 : /// retrieved as an integer in the filename. Also the user can specify if the
387 : /// H5 file was written by SpEC or not, because SpEC has some different
388 : /// conventions than we use here.
389 1 : explicit MetricWorldtubeH5BufferUpdater(
390 : const std::string& cce_data_filename,
391 : std::optional<double> extraction_radius = std::nullopt,
392 : bool descending_m = true,
393 : const std::optional<AdmOptions>& adm_options = std::nullopt);
394 :
395 : // NOLINTNEXTLINE
396 0 : WRAPPED_PUPable_decl_base_template(
397 : WorldtubeBufferUpdater<cce_metric_input_tags<T>>,
398 : MetricWorldtubeH5BufferUpdater);
399 :
400 0 : explicit MetricWorldtubeH5BufferUpdater(CkMigrateMessage* /*unused*/) {}
401 :
402 : /// \brief Update the `buffers`, `time_span_start`, and `time_span_end` with
403 : /// data (either Goldberg modal data or just nodal data depending on the
404 : /// template parameter to this class) and the start and end index in the
405 : /// member `time_buffer_` covered by the newly updated `buffers`.
406 : ///
407 : /// The function returns the next time at which a full update will occur. If
408 : /// called again at times earlier than the next full update time, it will
409 : /// leave the `buffers` unchanged and again return the next needed time.
410 1 : double update_buffers_for_time(
411 : gsl::not_null<Variables<cce_metric_input_tags<T>>*> buffers,
412 : gsl::not_null<size_t*> time_span_start,
413 : gsl::not_null<size_t*> time_span_end, double time,
414 : size_t computation_l_max, size_t interpolator_length, size_t buffer_depth,
415 : bool time_varies_fastest = true) const override;
416 :
417 0 : std::unique_ptr<WorldtubeBufferUpdater<cce_metric_input_tags<T>>> get_clone()
418 : const override;
419 :
420 : /// The time can only be supported in the buffer update if it is between the
421 : /// first and last time of the input file.
422 1 : bool time_is_outside_range(double time) const override;
423 :
424 : /// retrieves the l_max of the input file
425 1 : size_t get_l_max() const override { return l_max_; }
426 :
427 : /// retrieves the extraction radius
428 1 : double get_extraction_radius() const override { return extraction_radius_; }
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 has_version_history_; }
440 :
441 : /// Serialization for Charm++.
442 1 : void pup(PUP::er& p) override;
443 :
444 : private:
445 0 : void update_radial_formulation(
446 : gsl::not_null<Variables<cce_metric_input_tags<T>>*> buffers,
447 : size_t computation_l_max, size_t time_span_start, size_t time_span_end,
448 : bool time_varies_fastest) const;
449 : template <typename U = T>
450 : typename std::enable_if_t<std::is_same_v<U, DataVector>>
451 0 : update_adm_formulation(
452 : gsl::not_null<Variables<cce_metric_input_tags<DataVector>>*> buffers,
453 : size_t computation_l_max, size_t time_span_start, size_t time_span_end,
454 : bool time_varies_fastest) const;
455 0 : void update_buffer(gsl::not_null<T*> buffer_to_update,
456 : const h5::Dat& read_data, size_t computation_l_max,
457 : size_t time_span_start, size_t time_span_end,
458 : bool time_varies_fastest) const;
459 :
460 0 : bool has_version_history_ = true;
461 0 : double extraction_radius_ = std::numeric_limits<double>::signaling_NaN();
462 0 : size_t l_max_ = 0;
463 :
464 0 : h5::H5File<h5::AccessType::ReadOnly> cce_data_file_;
465 0 : std::string filename_;
466 0 : bool descending_m_ = true;
467 0 : std::optional<AdmOptions> adm_options_;
468 :
469 : tuples::tagged_tuple_from_typelist<db::wrap_tags_in<
470 : Tags::detail::InputDataSet,
471 : tmpl::remove_duplicates<tmpl::append<cce_metric_input_tags<T>,
472 : cce_metric_adm_input_tags<T>>>>>
473 0 : dataset_names_;
474 :
475 : // stores all the times in the input file
476 0 : DataVector time_buffer_;
477 : };
478 :
479 : /*!
480 : * \brief A `WorldtubeBufferUpdater` specialized to CCE input worldtube H5 files
481 : * that have metric data stored in Bondi-Sachs format in either either modal or
482 : * nodal form.
483 : *
484 : * \details To read in modal data, template this class as
485 : * `MetricWorldtubeH5BufferUpdater<ComplexModalVector>`. To read in nodal data,
486 : * template the class as `MetricWorldtubeH5BufferUpdater<ComplexDataVector>`.
487 : */
488 : template <typename T>
489 1 : class BondiWorldtubeH5BufferUpdater
490 : : public WorldtubeBufferUpdater<tmpl::conditional_t<
491 : std::is_same_v<T, ComplexModalVector>,
492 : Tags::worldtube_boundary_tags_for_writing<
493 : Spectral::Swsh::Tags::SwshTransform>,
494 : Tags::worldtube_boundary_tags_for_writing<Tags::BoundaryValue>>> {
495 : static_assert(std::is_same_v<T, ComplexModalVector> or
496 : std::is_same_v<T, ComplexDataVector>,
497 : "Can only use ComplexModalVector or ComplexDataVector in a "
498 : "BondiWorldtubeH5BufferUpdater.");
499 :
500 : public:
501 0 : using tags_for_writing = tmpl::conditional_t<
502 : std::is_same_v<T, ComplexModalVector>,
503 : Tags::worldtube_boundary_tags_for_writing<
504 : Spectral::Swsh::Tags::SwshTransform>,
505 : Tags::worldtube_boundary_tags_for_writing<Tags::BoundaryValue>>;
506 :
507 0 : static constexpr bool is_modal = std::is_same_v<T, ComplexModalVector>;
508 :
509 : // charm needs the empty constructor
510 0 : BondiWorldtubeH5BufferUpdater() = default;
511 :
512 : /// The constructor takes the filename of the H5 file that will be used
513 : /// for boundary data. The extraction radius can either be passed in directly,
514 : /// or if it takes the value `std::nullopt`, then the extraction radius is
515 : /// retrieved as an integer in the filename.
516 1 : explicit BondiWorldtubeH5BufferUpdater(
517 : const std::string& cce_data_filename,
518 : std::optional<double> extraction_radius = std::nullopt);
519 :
520 : // NOLINTNEXTLINE
521 0 : WRAPPED_PUPable_decl_base_template(
522 : SINGLE_ARG(WorldtubeBufferUpdater<tags_for_writing>),
523 : BondiWorldtubeH5BufferUpdater);
524 :
525 0 : explicit BondiWorldtubeH5BufferUpdater(CkMigrateMessage* /*unused*/) {}
526 :
527 : /// update the `buffers`, `time_span_start`, and `time_span_end` with Goldberg
528 : /// modal data (either Goldberg modal data or complex nodal data depending on
529 : /// the template parameter to this class) and the start and end index in the
530 : /// member `time_buffer_` covered by the newly updated `buffers`.
531 1 : double update_buffers_for_time(
532 : gsl::not_null<Variables<tags_for_writing>*> buffers,
533 : gsl::not_null<size_t*> time_span_start,
534 : gsl::not_null<size_t*> time_span_end, double time,
535 : size_t computation_l_max, size_t interpolator_length, size_t buffer_depth,
536 : bool time_varies_fastest = true) const override;
537 :
538 0 : std::unique_ptr<WorldtubeBufferUpdater<tags_for_writing>> get_clone()
539 : const override {
540 : return std::make_unique<BondiWorldtubeH5BufferUpdater>(filename_);
541 : }
542 :
543 : /// The time can only be supported in the buffer update if it is between the
544 : /// first and last time of the input file.
545 1 : bool time_is_outside_range(const double time) const override {
546 : return time < time_buffer_[0] or
547 : time > time_buffer_[time_buffer_.size() - 1];
548 : }
549 :
550 : /// retrieves the l_max of the input file
551 1 : size_t get_l_max() const override { return l_max_; }
552 :
553 : /// retrieves the extraction radius. In most normal circumstances, this will
554 : /// not be needed for Bondi data.
555 1 : double get_extraction_radius() const override {
556 : if (not extraction_radius_.has_value()) {
557 : ERROR(
558 : "Extraction radius has not been set, and was not successfully parsed "
559 : "from the filename. The extraction radius has been used, so must be "
560 : "set either by the input file or via the filename.");
561 : }
562 : return *extraction_radius_;
563 : }
564 :
565 : /// The time buffer is supplied by non-const reference to allow views to
566 : /// easily point into the buffer.
567 : ///
568 : /// \warning Altering this buffer outside of the constructor of this class
569 : /// results in undefined behavior! This should be supplied by const reference
570 : /// once there is a convenient method of producing a const view of a vector
571 : /// type.
572 1 : DataVector& get_time_buffer() override { return time_buffer_; }
573 :
574 0 : bool has_version_history() const override { return true; }
575 :
576 : /// Serialization for Charm++.
577 1 : void pup(PUP::er& p) override;
578 :
579 : private:
580 0 : std::optional<double> extraction_radius_ = std::nullopt;
581 0 : size_t l_max_ = 0;
582 :
583 0 : h5::H5File<h5::AccessType::ReadOnly> cce_data_file_;
584 0 : std::string filename_;
585 :
586 : tuples::tagged_tuple_from_typelist<
587 : db::wrap_tags_in<Tags::detail::InputDataSet, tags_for_writing>>
588 0 : dataset_names_;
589 :
590 : // stores all the times in the input file
591 0 : DataVector time_buffer_;
592 : };
593 :
594 : /// A `WorldtubeBufferUpdater` specialized to the Klein-Gordon input worldtube
595 : /// H5 file produced by the SpEC format. We assume the scalar field is
596 : /// real-valued.
597 1 : class KleinGordonWorldtubeH5BufferUpdater
598 : : public WorldtubeBufferUpdater<klein_gordon_input_tags> {
599 : public:
600 : // charm needs the empty constructor
601 0 : KleinGordonWorldtubeH5BufferUpdater() = default;
602 :
603 : /// The constructor takes the filename of the SpEC h5 file that will be used
604 : /// for boundary data. The extraction radius can either be passed in directly,
605 : /// or if it takes the value `std::nullopt`, then the extraction radius is
606 : /// retrieved as an integer in the filename.
607 1 : explicit KleinGordonWorldtubeH5BufferUpdater(
608 : const std::string& cce_data_filename,
609 : std::optional<double> extraction_radius = std::nullopt);
610 :
611 0 : WRAPPED_PUPable_decl_template(KleinGordonWorldtubeH5BufferUpdater); // NOLINT
612 :
613 0 : explicit KleinGordonWorldtubeH5BufferUpdater(CkMigrateMessage* /*unused*/) {}
614 :
615 : /// update the `buffers`, `time_span_start`, and `time_span_end` with Goldberg
616 : /// modal data and the start and end index in the member `time_buffer_`
617 : /// covered by the newly updated `buffers`.
618 1 : double update_buffers_for_time(
619 : gsl::not_null<Variables<klein_gordon_input_tags>*> buffers,
620 : gsl::not_null<size_t*> time_span_start,
621 : gsl::not_null<size_t*> time_span_end, double time,
622 : size_t computation_l_max, size_t interpolator_length, size_t buffer_depth,
623 : bool time_varies_fastest = true) const override;
624 :
625 0 : std::unique_ptr<WorldtubeBufferUpdater<klein_gordon_input_tags>> get_clone()
626 : const override {
627 : return std::make_unique<KleinGordonWorldtubeH5BufferUpdater>(filename_);
628 : }
629 :
630 : /// The time can only be supported in the buffer update if it is between the
631 : /// first and last time of the input file.
632 1 : bool time_is_outside_range(const double time) const override {
633 : return time < time_buffer_[0] or
634 : time > time_buffer_[time_buffer_.size() - 1];
635 : }
636 :
637 : /// retrieves the l_max of the input file
638 1 : size_t get_l_max() const override { return l_max_; }
639 :
640 : /// retrieves the extraction radius. In most normal circumstances, this will
641 : /// not be needed for Klein-Gordon data.
642 1 : double get_extraction_radius() const override {
643 : if (not static_cast<bool>(extraction_radius_)) {
644 : ERROR(
645 : "Extraction radius has not been set, and was not successfully parsed "
646 : "from the filename. The extraction radius has been used, so must be "
647 : "set either by the input file or via the filename.");
648 : }
649 : return *extraction_radius_;
650 : }
651 :
652 : /// The time buffer is supplied by non-const reference to allow views to
653 : /// easily point into the buffer.
654 : ///
655 : /// \warning Altering this buffer outside of the constructor of this class
656 : /// results in undefined behavior! This should be supplied by const reference
657 : /// once there is a convenient method of producing a const view of a vector
658 : /// type.
659 1 : DataVector& get_time_buffer() override { return time_buffer_; }
660 :
661 0 : bool has_version_history() const override { return true; }
662 :
663 : /// Serialization for Charm++.
664 1 : void pup(PUP::er& p) override;
665 :
666 : private:
667 0 : std::optional<double> extraction_radius_ = std::nullopt;
668 0 : size_t l_max_ = 0;
669 :
670 0 : h5::H5File<h5::AccessType::ReadOnly> cce_data_file_;
671 0 : std::string filename_;
672 :
673 : tuples::tagged_tuple_from_typelist<
674 : db::wrap_tags_in<Tags::detail::InputDataSet, klein_gordon_input_tags>>
675 0 : dataset_names_;
676 :
677 : // stores all the times in the input file
678 0 : DataVector time_buffer_;
679 : };
680 : } // namespace Cce
|