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 <optional>
8 : #include <string>
9 : #include <tuple>
10 : #include <type_traits>
11 : #include <utility>
12 : #include <vector>
13 :
14 : #include "DataStructures/DataBox/DataBox.hpp"
15 : #include "DataStructures/TaggedTuple.hpp"
16 : #include "Domain/Structure/ElementId.hpp"
17 : #include "Domain/Tags.hpp"
18 : #include "IO/H5/TensorData.hpp"
19 : #include "IO/Observer/ObservationId.hpp"
20 : #include "IO/Observer/Tags.hpp"
21 : #include "IO/Observer/TypeOfObservation.hpp"
22 : #include "IO/Observer/VolumeActions.hpp"
23 : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
24 : #include "Parallel/AlgorithmExecution.hpp"
25 : #include "Parallel/ArrayComponentId.hpp"
26 : #include "Parallel/GlobalCache.hpp"
27 : #include "Parallel/TypeTraits.hpp"
28 : #include "ParallelAlgorithms/Amr/Tags.hpp"
29 : #include "ParallelAlgorithms/LinearSolver/Multigrid/Tags.hpp"
30 : #include "Utilities/Algorithm.hpp"
31 : #include "Utilities/Gsl.hpp"
32 : #include "Utilities/MakeString.hpp"
33 : #include "Utilities/PrettyType.hpp"
34 : #include "Utilities/TMPL.hpp"
35 :
36 : namespace LinearSolver::multigrid::detail {
37 :
38 : template <typename OptionsGroup>
39 : struct RegisterWithVolumeObserver {
40 : template <typename ParallelComponent, typename DbTagsList,
41 : typename ArrayIndex>
42 : static std::pair<observers::TypeOfObservation, observers::ObservationKey>
43 : register_info(const db::DataBox<DbTagsList>& box,
44 : const ArrayIndex& /*array_index*/) {
45 : const std::string& level_observation_key =
46 : *db::get<observers::Tags::ObservationKey<::amr::Tags::GridIndex>>(box);
47 : const std::string subfile_path =
48 : "/" + pretty_type::name<OptionsGroup>() + level_observation_key;
49 : return {observers::TypeOfObservation::Volume,
50 : observers::ObservationKey(subfile_path)};
51 : }
52 : };
53 :
54 : // Contribute the volume data recorded in the other actions to the observer at
55 : // the end of a step.
56 : template <typename FieldsTag, typename OptionsGroup, typename SourceTag>
57 : struct ObserveVolumeData {
58 : private:
59 : using volume_data_tag = Tags::VolumeDataForOutput<OptionsGroup, FieldsTag>;
60 : using VolumeDataVars = typename volume_data_tag::type;
61 :
62 : public:
63 : template <typename DbTagsList, typename... InboxTags, typename Metavariables,
64 : size_t Dim, typename ActionList, typename ParallelComponent>
65 : static Parallel::iterable_action_return_t apply(
66 : db::DataBox<DbTagsList>& box,
67 : const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
68 : Parallel::GlobalCache<Metavariables>& cache,
69 : const ElementId<Dim>& element_id, const ActionList /*meta*/,
70 : const ParallelComponent* const /*meta*/) {
71 : if (not db::get<LinearSolver::Tags::OutputVolumeData<OptionsGroup>>(box)) {
72 : return {Parallel::AlgorithmExecution::Continue, std::nullopt};
73 : }
74 : const auto& volume_data = db::get<volume_data_tag>(box);
75 : const auto& observation_id =
76 : db::get<LinearSolver::Tags::ObservationId<OptionsGroup>>(box);
77 : const auto& mesh = db::get<domain::Tags::Mesh<Dim>>(box);
78 : const auto& inertial_coords =
79 : db::get<domain::Tags::Coordinates<Dim, Frame::Inertial>>(box);
80 : // Collect tensor components to observe
81 : std::vector<TensorComponent> components{};
82 : components.reserve(inertial_coords.size() +
83 : VolumeDataVars::number_of_independent_components);
84 : const auto record_tensor_components = [&components](const auto tensor_tag_v,
85 : const auto& tensor) {
86 : using tensor_tag = std::decay_t<decltype(tensor_tag_v)>;
87 : using TensorType = std::decay_t<decltype(tensor)>;
88 : using VectorType = typename TensorType::type;
89 : using ValueType = typename VectorType::value_type;
90 : for (size_t i = 0; i < tensor.size(); ++i) {
91 : const std::string component_name =
92 : db::tag_name<tensor_tag>() + tensor.component_suffix(i);
93 : if constexpr (std::is_same_v<ValueType, std::complex<double>>) {
94 : components.emplace_back("Re(" + component_name + ")",
95 : real(tensor[i]));
96 : components.emplace_back("Im(" + component_name + ")",
97 : imag(tensor[i]));
98 : } else {
99 : components.emplace_back(component_name, tensor[i]);
100 : }
101 : }
102 : };
103 : record_tensor_components(domain::Tags::Coordinates<Dim, Frame::Inertial>{},
104 : inertial_coords);
105 : tmpl::for_each<typename VolumeDataVars::tags_list>(
106 : [&volume_data, &record_tensor_components](auto tag_v) {
107 : using tag = tmpl::type_from<decltype(tag_v)>;
108 : record_tensor_components(tag{}, get<tag>(volume_data));
109 : });
110 :
111 : // Contribute tensor components to observer
112 : const auto& level_observation_key =
113 : *db::get<observers::Tags::ObservationKey<::amr::Tags::GridIndex>>(box);
114 : const std::string subfile_path =
115 : "/" + pretty_type::name<OptionsGroup>() + level_observation_key;
116 : observers::contribute_volume_data<
117 : not Parallel::is_nodegroup_v<ParallelComponent>>(
118 : cache, observers::ObservationId(observation_id, subfile_path),
119 : subfile_path,
120 : Parallel::make_array_component_id<ParallelComponent>(element_id),
121 : ElementVolumeData{element_id, std::move(components), mesh});
122 :
123 : // Increment observation ID
124 : db::mutate<LinearSolver::Tags::ObservationId<OptionsGroup>>(
125 : [](const auto local_observation_id) { ++(*local_observation_id); },
126 : make_not_null(&box));
127 : return {Parallel::AlgorithmExecution::Continue, std::nullopt};
128 : }
129 : };
130 :
131 : } // namespace LinearSolver::multigrid::detail
|