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 <iomanip>
8 : #include <map>
9 : #include <sstream>
10 : #include <string>
11 : #include <unordered_map>
12 : #include <unordered_set>
13 : #include <variant>
14 :
15 : #include "DataStructures/DataBox/Tag.hpp"
16 : #include "DataStructures/TaggedTuple.hpp"
17 : #include "DataStructures/Tensor/TypeAliases.hpp"
18 : #include "IO/Importers/ObservationSelector.hpp"
19 : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
20 : #include "Options/Auto.hpp"
21 : #include "Options/String.hpp"
22 : #include "Parallel/ArrayComponentId.hpp"
23 : #include "Parallel/InboxInserters.hpp"
24 : #include "Utilities/PrettyType.hpp"
25 :
26 : /// Items related to loading data from files
27 : namespace importers {
28 :
29 : /// The input file options associated with the data importer
30 1 : namespace OptionTags {
31 :
32 : /*!
33 : * \brief The file to read data from.
34 : */
35 1 : struct FileGlob {
36 0 : using type = std::string;
37 0 : static constexpr Options::String help = "Path to the data file";
38 : };
39 :
40 : /*!
41 : * \brief The subgroup within the file to read data from.
42 : *
43 : * This subgroup should conform to the `h5::VolumeData` format.
44 : */
45 1 : struct Subgroup {
46 0 : using type = std::string;
47 0 : static constexpr Options::String help =
48 : "The subgroup within the file, excluding extensions";
49 : };
50 :
51 : /*!
52 : * \brief The observation value at which to read data from the file.
53 : */
54 1 : struct ObservationValue {
55 0 : using type = std::variant<double, ObservationSelector>;
56 0 : static constexpr Options::String help =
57 : "The observation value at which to read data";
58 : };
59 :
60 0 : struct ObservationValueEpsilon {
61 0 : using type = Options::Auto<double>;
62 0 : static constexpr Options::String help =
63 : "Look for observations in the data within this epsilon of the "
64 : "'ObservationValue'. Set to 'Auto' to use default of 1e-12. This option "
65 : "is ignored if the 'ObservationValue' is a selector like 'First' or "
66 : "'Last'.";
67 : };
68 :
69 : /*!
70 : * \brief Toggle interpolation of numeric data to the target domain
71 : */
72 1 : struct ElementsAreIdentical {
73 0 : using type = bool;
74 0 : static constexpr Options::String help =
75 : "Indicate that the elements of the source and target domain are the "
76 : "same, meaning that the domains are the same and their h-refinement is "
77 : "the same. In this case, data can be transferred between the source and "
78 : "target elements one-to-one, and interpolations only happen if the "
79 : "elements have different meshes (p-refinement). "
80 : "For example, you can enable this option if you have generated data "
81 : "on the target points, or if you have already interpolated your data, "
82 : "or if you import data from a simulation that differs only by "
83 : "p-refinement. "
84 : "When this option is enabled, datasets "
85 : "'InertialCoordinates(_x,_y,_z)' must exist in the files. They are used "
86 : "to verify that the target points indeed match the source data.";
87 : };
88 :
89 : /*!
90 : * \brief Extrapolate data into excised regions of the source domain.
91 : */
92 1 : struct ExtrapolateIntoExcisions {
93 0 : using type = bool;
94 0 : static constexpr Options::String help =
95 : "Fill target points that fall inside excised regions of the source "
96 : "domain by extrapolating the source data into the excision (see "
97 : "'spectre::Exporter::interpolate_to_points').";
98 : };
99 :
100 : /*!
101 : * \brief Number of threads to use to accelerate the import with OpenMP, or
102 : * 'Auto' to use all available threads.
103 : */
104 1 : struct NumThreads {
105 0 : using type = Options::Auto<size_t>;
106 0 : static constexpr Options::String help =
107 : "Number of threads to use to read and interpolate the volume data with "
108 : "OpenMP, or 'Auto' to use all available threads. Keep this at 1 (serial) "
109 : "unless you know the node is otherwise idle during the import (e.g. when "
110 : "loading initial data), because the importer shares the node with the "
111 : "Charm++ worker threads and additional threads can oversubscribe them. "
112 : "Has no effect if the code was built without OpenMP support.";
113 : };
114 : } // namespace OptionTags
115 :
116 : /// Options that specify the volume data to load. See the option tags for
117 : /// details.
118 1 : struct ImporterOptions
119 : : tuples::TaggedTuple<
120 : OptionTags::FileGlob, OptionTags::Subgroup,
121 : OptionTags::ObservationValue, OptionTags::ObservationValueEpsilon,
122 : OptionTags::ElementsAreIdentical,
123 : OptionTags::ExtrapolateIntoExcisions, OptionTags::NumThreads> {
124 0 : using options = tags_list;
125 0 : static constexpr Options::String help = "The volume data to load.";
126 : using TaggedTuple::TaggedTuple;
127 : };
128 :
129 : namespace OptionTags {
130 : /// Bundles all \ref importers::ImporterOptions for use in factory-creatable
131 : /// classes
132 1 : struct VolumeData {
133 0 : using type = ImporterOptions;
134 0 : static constexpr Options::String help = ImporterOptions::help;
135 : };
136 : } // namespace OptionTags
137 :
138 : /// The \ref DataBoxGroup tags associated with the data importer
139 : namespace Tags {
140 :
141 : /// Options that specify the volume data to load. See the option tags for
142 : /// details.
143 : template <typename OptionsGroup>
144 1 : struct ImporterOptions : db::SimpleTag {
145 0 : static std::string name() { return "VolumeData"; }
146 0 : using type = importers::ImporterOptions;
147 0 : static constexpr Options::String help = importers::ImporterOptions::help;
148 0 : using group = OptionsGroup;
149 0 : using option_tags = tmpl::list<ImporterOptions>;
150 0 : static constexpr bool pass_metavariables = false;
151 0 : static type create_from_options(type value) { return value; }
152 : };
153 :
154 : /*!
155 : * \brief The elements that will receive data from the importer.
156 : *
157 : * \details Identifiers for elements from multiple parallel components can be
158 : * stored. Each element is identified by an `Parallel::ArrayComponentId` and
159 : * also needs to provide the inertial coordinates of its grid points. The
160 : * imported data will be interpolated to these grid points.
161 : */
162 : template <size_t Dim>
163 1 : struct RegisteredElements : db::SimpleTag {
164 0 : using type = std::unordered_map<
165 : Parallel::ArrayComponentId,
166 : std::pair<tnsr::I<DataVector, Dim, Frame::Inertial>, ::Mesh<Dim>>>;
167 : };
168 :
169 : /// Indicates which volume data files have already been read.
170 1 : struct ElementDataAlreadyRead : db::SimpleTag {
171 0 : using type = std::unordered_set<size_t>;
172 : };
173 :
174 : /*!
175 : * \brief Inbox tag that carries the data read from a volume data file.
176 : *
177 : * Since we read a volume data file only once, this tag's map will only ever
178 : * hold data at the index (i.e. the temporal ID) with value `0`.
179 : */
180 : template <typename FieldTagsList>
181 1 : struct VolumeData : Parallel::InboxInserters::Value<VolumeData<FieldTagsList>> {
182 0 : using temporal_id = size_t;
183 0 : using type =
184 : std::map<temporal_id, tuples::tagged_tuple_from_typelist<FieldTagsList>>;
185 :
186 0 : static std::string output_inbox(const type& inbox,
187 : const size_t padding_size) {
188 : std::stringstream ss{};
189 : const std::string pad(padding_size, ' ');
190 :
191 : ss << std::scientific << std::setprecision(16);
192 : ss << pad << "VolumeDataInbox:\n";
193 : // We don't really care about the variables, just the times
194 : for (const auto& [index, variables] : inbox) {
195 : (void)variables;
196 : ss << pad << " Index: " << index << "\n";
197 : }
198 :
199 : return ss.str();
200 : }
201 : };
202 : } // namespace Tags
203 :
204 : } // namespace importers
|