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