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 <unordered_map> 10 : #include <utility> 11 : #include <vector> 12 : 13 : #include "DataStructures/FloatingPointType.hpp" 14 : #include "Domain/Structure/ElementId.hpp" 15 : #include "IO/H5/TensorData.hpp" 16 : #include "IO/Observer/ObservationId.hpp" 17 : #include "IO/Observer/ObserverComponent.hpp" 18 : #include "IO/Observer/VolumeActions.hpp" 19 : #include "NumericalAlgorithms/Spectral/Basis.hpp" 20 : #include "NumericalAlgorithms/Spectral/Mesh.hpp" 21 : #include "NumericalAlgorithms/Spectral/Quadrature.hpp" 22 : #include "Options/String.hpp" 23 : #include "Parallel/ArrayComponentId.hpp" 24 : #include "Parallel/ArrayIndex.hpp" 25 : #include "Parallel/Invoke.hpp" 26 : #include "Parallel/Local.hpp" 27 : #include "Parallel/TypeTraits.hpp" 28 : #include "ParallelAlgorithms/Actions/FunctionsOfTimeAreReady.hpp" 29 : #include "ParallelAlgorithms/EventsAndTriggers/Event.hpp" 30 : #include "Utilities/TMPL.hpp" 31 : 32 : /// \cond 33 : template <size_t VolumeDim> 34 : class Domain; 35 : namespace domain::FunctionsOfTime { 36 : class FunctionOfTime; 37 : } // namespace domain::FunctionsOfTime 38 : namespace domain::Tags { 39 : struct FunctionsOfTime; 40 : } // namespace domain::Tags 41 : namespace observers { 42 : class ObservationKey; 43 : enum class TypeOfObservation; 44 : } // namespace observers 45 : namespace Parallel { 46 : template <typename Metavariables> 47 : class GlobalCache; 48 : } // namespace Parallel 49 : namespace PUP { 50 : class er; 51 : } // namespace PUP 52 : namespace Tags { 53 : struct Time; 54 : } // namespace Tags 55 : /// \endcond 56 : 57 : namespace dg::Events { 58 : /// \brief Base class for Observers that write data that is constant within an 59 : /// Element 60 : template <size_t VolumeDim> 61 1 : class ObserveConstantsPerElement : public Event { 62 : public: 63 : /// The name of the subfile inside the HDF5 file 64 1 : struct SubfileName { 65 0 : using type = std::string; 66 0 : static constexpr Options::String help = { 67 : "The name of the subfile inside the HDF5 file without an extension and " 68 : "without a preceding '/'."}; 69 : }; 70 : 71 : /// The floating point type/precision with which to write the data to disk. 72 1 : struct FloatingPointType { 73 0 : static constexpr Options::String help = 74 : "The floating point type/precision with which to write the data to " 75 : "disk."; 76 0 : using type = ::FloatingPointType; 77 : }; 78 : 79 : /// The floating point type/precision with which to write the coordinates to 80 : /// disk. 81 1 : struct CoordinatesFloatingPointType { 82 0 : static constexpr Options::String help = 83 : "The floating point type/precision with which to write the coordinates " 84 : "to disk."; 85 0 : using type = ::FloatingPointType; 86 : }; 87 : 88 0 : using options = 89 : tmpl::list<SubfileName, CoordinatesFloatingPointType, FloatingPointType>; 90 : 91 0 : ObserveConstantsPerElement() = default; 92 : 93 0 : ObserveConstantsPerElement( 94 : const std::string& subfile_name, 95 : ::FloatingPointType coordinates_floating_point_type, 96 : ::FloatingPointType floating_point_type); 97 : 98 : /// \cond 99 : explicit ObserveConstantsPerElement(CkMigrateMessage* /*unused*/); 100 : /// \endcond 101 : 102 0 : using observation_registration_tags = tmpl::list<>; 103 : 104 : std::optional< 105 : std::pair<observers::TypeOfObservation, observers::ObservationKey>> 106 0 : get_observation_type_and_key_for_registration() const; 107 : 108 0 : using is_ready_argument_tags = tmpl::list<::Tags::Time>; 109 : 110 : template <typename Metavariables, typename ArrayIndex, typename Component> 111 0 : bool is_ready(const double time, Parallel::GlobalCache<Metavariables>& cache, 112 : const ArrayIndex& array_index, 113 : const Component* const component) const { 114 : return ::domain::functions_of_time_are_ready_algorithm_callback< 115 : ::domain::Tags::FunctionsOfTime, VolumeDim>(cache, array_index, 116 : component, time); 117 : } 118 : 119 0 : void pup(PUP::er& p) override; 120 : 121 : protected: 122 : /// \brief Creates the vector of tensor components that will be observed 123 : /// and starts to fill it with the inertial coordinates 124 : /// 125 : /// \details number_of_constants is the number of additional tensor components 126 : /// that will be observed. These are added by calling add_constant 127 1 : std::vector<TensorComponent> allocate_and_insert_coords( 128 : size_t number_of_constants, double time, 129 : const std::unordered_map< 130 : std::string, 131 : std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>& 132 : functions_of_time, 133 : const Domain<VolumeDim>& domain, 134 : const ElementId<VolumeDim>& element_id) const; 135 : 136 : /// \brief Adds a TensorComponent to components with the given name and the 137 : /// given value. 138 : /// 139 : /// \details Should be called after allocate_and_insert_coords 140 1 : void add_constant(gsl::not_null<std::vector<TensorComponent>*> components, 141 : std::string name, double value) const; 142 : 143 : /// Observes the components as volume data 144 : template <typename Metavariables, typename ParallelComponent> 145 1 : void observe(std::vector<TensorComponent> components, 146 : Parallel::GlobalCache<Metavariables>& cache, 147 : const ElementId<VolumeDim>& element_id, 148 : const ParallelComponent* /*component*/, 149 : const ObservationValue& observation_value) const; 150 : private: 151 0 : std::string subfile_path_; 152 0 : ::FloatingPointType coordinates_floating_point_type_ = 153 : ::FloatingPointType::Double; 154 0 : ::FloatingPointType floating_point_type_ = ::FloatingPointType::Double; 155 : }; 156 : 157 : template <size_t VolumeDim> 158 : template <typename Metavariables, typename ParallelComponent> 159 : void ObserveConstantsPerElement<VolumeDim>::observe( 160 : std::vector<TensorComponent> components, 161 : Parallel::GlobalCache<Metavariables>& cache, 162 : const ElementId<VolumeDim>& element_id, 163 : const ParallelComponent* const /*component*/, 164 : const ObservationValue& observation_value) const { 165 : const Mesh<VolumeDim> single_cell_mesh(2, Spectral::Basis::Legendre, 166 : Spectral::Quadrature::GaussLobatto); 167 : const Parallel::ArrayComponentId array_component_id{ 168 : std::add_pointer_t<ParallelComponent>{nullptr}, 169 : Parallel::ArrayIndex<ElementId<VolumeDim>>{element_id}}; 170 : ElementVolumeData element_volume_data{element_id, std::move(components), 171 : single_cell_mesh}; 172 : observers::ObservationId observation_id{observation_value.value, 173 : subfile_path_ + ".vol"}; 174 : 175 : auto& local_observer = *Parallel::local_branch( 176 : Parallel::get_parallel_component< 177 : tmpl::conditional_t<Parallel::is_nodegroup_v<ParallelComponent>, 178 : observers::ObserverWriter<Metavariables>, 179 : observers::Observer<Metavariables>>>(cache)); 180 : 181 : if constexpr (Parallel::is_nodegroup_v<ParallelComponent>) { 182 : // Send data to reduction observer writer (nodegroup) 183 : std::unordered_map<Parallel::ArrayComponentId, 184 : std::vector<ElementVolumeData>> 185 : data_to_send{}; 186 : data_to_send[array_component_id] = 187 : std::vector{std::move(element_volume_data)}; 188 : Parallel::threaded_action< 189 : observers::ThreadedActions::ContributeVolumeDataToWriter>( 190 : local_observer, std::move(observation_id), array_component_id, 191 : subfile_path_, std::move(data_to_send)); 192 : } else { 193 : // Send data to volume observer 194 : Parallel::simple_action<observers::Actions::ContributeVolumeData>( 195 : local_observer, std::move(observation_id), subfile_path_, 196 : array_component_id, std::move(element_volume_data)); 197 : } 198 : } 199 : 200 : } // namespace dg::Events