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