VolumeDataReaderActions.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <cstddef>
7 #include <iterator>
8 #include <unordered_map>
9 
12 #include "DataStructures/DataBox/TagName.hpp"
13 #include "DataStructures/Index.hpp"
14 #include "DataStructures/Tensor/TensorData.hpp"
15 #include "ErrorHandling/Error.hpp"
16 #include "IO/H5/AccessType.hpp"
17 #include "IO/H5/File.hpp"
18 #include "IO/H5/VolumeData.hpp"
19 #include "IO/Importers/Tags.hpp"
20 #include "IO/Observer/ArrayComponentId.hpp"
21 #include "Parallel/GlobalCache.hpp"
22 #include "Parallel/Info.hpp"
23 #include "Parallel/Invoke.hpp"
24 #include "Utilities/Algorithm.hpp"
25 #include "Utilities/Requires.hpp"
26 #include "Utilities/TaggedTuple.hpp"
27 
28 namespace importers {
29 /// Actions related to importers
30 namespace Actions {
31 
32 /*!
33  * \brief Invoked on the `importers::VolumeDataReader` component to store the
34  * registered data.
35  *
36  * The `importers::Actions::RegisterWithVolumeDataReader` action, which is
37  * performed on each element of an array parallel component, invokes this action
38  * on the `importers::VolumeDataReader` component.
39  */
41  template <
42  typename ParallelComponent, typename DbTagsList, typename Metavariables,
43  typename ArrayIndex, typename DataBox = db::DataBox<DbTagsList>,
45  nullptr>
46  static void apply(db::DataBox<DbTagsList>& box,
47  const Parallel::GlobalCache<Metavariables>& /*cache*/,
48  const ArrayIndex& /*array_index*/,
49  const observers::ArrayComponentId& array_component_id,
50  const std::string& grid_name) noexcept {
51  db::mutate<Tags::RegisteredElements>(
52  make_not_null(&box),
53  [&array_component_id, &grid_name](
55  registered_elements) noexcept {
56  (*registered_elements)[array_component_id] = grid_name;
57  });
58  }
59 };
60 
61 } // namespace Actions
62 
63 /// Threaded actions related to importers
64 namespace ThreadedActions {
65 
66 /*!
67  * \brief Read a volume data file and distribute the data to the registered
68  * elements.
69  *
70  * This action can be invoked on the `importers::VolumeDataReader` component
71  * once all elements have been registered with it. It opens the data file, reads
72  * the data for each registered element and calls the `CallbackAction` on each
73  * element providing the data.
74  *
75  * - The `ImporterOptionsGroup` parameter specifies the \ref OptionGroupsGroup
76  * "options group" in the input file that provides the following run-time
77  * options:
78  * - `importers::OptionTags::FileName`
79  * - `importers::OptionTags::Subgroup`
80  * - `importers::OptionTags::ObservationValue`
81  * - The `FieldTagsList` parameter specifies a typelist of tensor tags that
82  * are read from the file and provided to each element. It is assumed that the
83  * tensor data is stored in datasets named `db::tag_name<Tag>() + suffix`, where
84  * the `suffix` is empty for scalars or `"_"` followed by the
85  * `Tensor::component_name` for each independent tensor component.
86  * - The `CallbackAction` is invoked on each registered element of the
87  * `CallbackComponent` with a
88  * `tuples::tagged_tuple_from_typelist<FieldTagsList>` containing the
89  * tensor data for that element. Use `Actions::SetData` to write the data
90  * directly into their respective tags in the DataBox. The `CallbackComponent`
91  * must the the same that was encoded into the `observers::ArrayComponentId`
92  * used to register the elements.
93  */
94 template <typename ImporterOptionsGroup, typename FieldTagsList,
95  typename CallbackAction, typename CallbackComponent>
97  using const_global_cache_tags =
98  tmpl::list<Tags::FileName<ImporterOptionsGroup>,
101 
102  template <typename ParallelComponent, typename DataBox,
103  typename Metavariables, typename ArrayIndex,
104  Requires<db::tag_is_retrievable_v<Tags::RegisteredElements,
105  DataBox>> = nullptr>
106  static void apply(
107  DataBox& box, Parallel::GlobalCache<Metavariables>& cache,
108  const ArrayIndex& /*array_index*/,
109  const gsl::not_null<Parallel::NodeLock*> node_lock) noexcept {
110  node_lock->lock();
111  {
112  // The scoping is to close the file before unlocking
115  constexpr size_t version_number = 0;
116  const auto& volume_file = h5file.get<h5::VolumeData>(
117  "/" + Parallel::get<Tags::Subgroup<ImporterOptionsGroup>>(cache),
118  version_number);
119  const auto observation_id = volume_file.find_observation_id(
121  // Read the tensor data for all elements at once, since that's how it's
122  // stored in the file
123  tuples::tagged_tuple_from_typelist<FieldTagsList> all_tensor_data{};
124  tmpl::for_each<FieldTagsList>([
125  &all_tensor_data, &volume_file, &observation_id
126  ](auto field_tag_v) noexcept {
127  using field_tag = tmpl::type_from<decltype(field_tag_v)>;
128  auto& tensor_data = get<field_tag>(all_tensor_data);
129  for (size_t i = 0; i < tensor_data.size(); i++) {
130  tensor_data[i] = volume_file.get_tensor_component(
131  observation_id,
132  db::tag_name<field_tag>() + tensor_data.component_suffix(
133  tensor_data.get_tensor_index(i)));
134  }
135  });
136  // Retrieve the information needed to reconstruct which element the data
137  // belongs to
138  const auto all_grid_names = volume_file.get_grid_names(observation_id);
139  const auto all_extents = volume_file.get_extents(observation_id);
140  // Distribute the tensor data to the registered elements
141  for (auto& element_and_name : get<Tags::RegisteredElements>(box)) {
142  const CkArrayIndex& raw_element_index =
143  element_and_name.first.array_index();
144  // Check if the parallel component of the registered element matches the
145  // callback, because it's possible that elements from other components
146  // with the same index are also registered.
147  // Since the way the component is encoded in `ArrayComponentId` is
148  // private to that class, we construct one and compare.
149  if (element_and_name.first !=
152  raw_element_index)) {
153  continue;
154  }
155  // Find the data offset that corresponds to this element
156  const auto element_data_offset_and_length =
157  h5::offset_and_length_for_grid(element_and_name.second,
158  all_grid_names, all_extents);
159  // Extract this element's data from the read-in dataset
160  tuples::tagged_tuple_from_typelist<FieldTagsList> element_data{};
161  tmpl::for_each<FieldTagsList>([
162  &element_data, &element_data_offset_and_length, &all_tensor_data
163  ](auto field_tag_v) noexcept {
164  using field_tag = tmpl::type_from<decltype(field_tag_v)>;
165  auto& element_tensor_data = get<field_tag>(element_data);
166  // Iterate independent components of the tensor
167  for (size_t i = 0; i < element_tensor_data.size(); i++) {
168  const DataVector& data_tensor_component =
169  get<field_tag>(all_tensor_data)[i];
170  DataVector element_tensor_component{
171  element_data_offset_and_length.second};
172  // Retrieve data from slice of the contigious dataset
173  for (size_t j = 0; j < element_tensor_component.size(); j++) {
174  element_tensor_component[j] =
175  data_tensor_component[element_data_offset_and_length.first +
176  j];
177  }
178  element_tensor_data[i] = element_tensor_component;
179  }
180  });
181  // Pass the data to the element in a simple action
182  const auto element_index =
184  raw_element_index)
185  .get_index();
186  Parallel::simple_action<CallbackAction>(
187  Parallel::get_parallel_component<CallbackComponent>(
188  cache)[element_index],
189  std::move(element_data));
190  }
191  }
192  node_lock->unlock();
193  }
194 };
195 
196 } // namespace ThreadedActions
197 } // namespace importers
AccessType.hpp
std::string
DataBoxTag.hpp
importers::Tags::Subgroup
The subgroup within the file to read data from.
Definition: Tags.hpp:131
Parallel::GlobalCache
Definition: ElementReceiveInterpPoints.hpp:16
GlobalCache.hpp
Error.hpp
iterator
importers::Tags::RegisteredElements
The elements that will receive data from the importer.
Definition: Tags.hpp:170
importers
Items related to loading data from files.
Definition: ElementActions.hpp:18
Info.hpp
File.hpp
h5::H5File< h5::AccessType::ReadOnly >
std::add_pointer_t
DataBox.hpp
h5::offset_and_length_for_grid
std::pair< size_t, size_t > offset_and_length_for_grid(const std::string &grid_name, const std::vector< std::string > &all_grid_names, const std::vector< std::vector< size_t >> &all_extents) noexcept
Find the interval within the contiguous dataset stored in h5::VolumeData that holds data for a partic...
cstddef
importers::Tags::ObservationValue
The observation value at which to read data from the file.
Definition: Tags.hpp:148
db::item_type
typename DataBox_detail::item_type_impl< TagList, Tag >::type item_type
Get the type that can be written to the Tag. If it is a base tag then a TagList must be passed as a s...
Definition: DataBoxTag.hpp:247
importers::ThreadedActions::ReadVolumeData
Read a volume data file and distribute the data to the registered elements.
Definition: VolumeDataReaderActions.hpp:96
Index.hpp
DataVector
Stores a collection of function values.
Definition: DataVector.hpp:42
h5::H5File::get
ObjectType & get(const std::string &path, Args &&... args)
Definition: File.hpp:192
Requires.hpp
importers::Actions::RegisterElementWithSelf
Invoked on the importers::VolumeDataReader component to store the registered data.
Definition: VolumeDataReaderActions.hpp:40
observers::ArrayComponentId
An ID type that identifies both the parallel component and the index in the parallel component.
Definition: ArrayComponentId.hpp:27
make_not_null
gsl::not_null< T * > make_not_null(T *ptr) noexcept
Construct a not_null from a pointer. Often this will be done as an implicit conversion,...
Definition: Gsl.hpp:880
Parallel::ArrayIndex
The array index used for indexing Chare Arrays, mostly an implementation detail.
Definition: ArrayIndex.hpp:27
Requires
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t
Definition: Requires.hpp:67
importers::Tags::FileName
The file to read data from.
Definition: Tags.hpp:112
unordered_map
db::DataBox
Definition: InterpolationTargetWedgeSectionTorus.hpp:24
Parallel::get
auto get(const GlobalCache< Metavariables > &cache) noexcept -> const GlobalCache_detail::type_for_get< GlobalCacheTag, Metavariables > &
Access data in the cache.
Definition: GlobalCache.hpp:254
h5::VolumeData
A volume data subfile written inside an H5 file.
Definition: VolumeData.hpp:68
gsl::not_null
Require a pointer to not be a nullptr
Definition: Gsl.hpp:183