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/Tags.hpp" 20 : #include "IO/Observer/TypeOfObservation.hpp" 21 : #include "IO/Observer/VolumeActions.hpp" 22 : #include "NumericalAlgorithms/Spectral/Mesh.hpp" 23 : #include "Parallel/AlgorithmExecution.hpp" 24 : #include "Parallel/ArrayComponentId.hpp" 25 : #include "Parallel/GlobalCache.hpp" 26 : #include "Parallel/TypeTraits.hpp" 27 : #include "ParallelAlgorithms/Amr/Tags.hpp" 28 : #include "ParallelAlgorithms/LinearSolver/Multigrid/Tags.hpp" 29 : #include "Utilities/Algorithm.hpp" 30 : #include "Utilities/Gsl.hpp" 31 : #include "Utilities/MakeString.hpp" 32 : #include "Utilities/PrettyType.hpp" 33 : #include "Utilities/TMPL.hpp" 34 : #include "Utilities/TaggedTuple.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