Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <array>
7 : #include <cstddef>
8 : #include <optional>
9 : #include <string>
10 : #include <utility>
11 : #include <vector>
12 :
13 : #include "DataStructures/DataBox/DataBox.hpp"
14 : #include "DataStructures/DataBox/ObservationBox.hpp"
15 : #include "Domain/Structure/ElementId.hpp"
16 : #include "Domain/Tags.hpp"
17 : #include "IO/Observer/Helpers.hpp"
18 : #include "IO/Observer/ObservationId.hpp"
19 : #include "IO/Observer/ObserverComponent.hpp"
20 : #include "IO/Observer/Protocols/ReductionDataFormatter.hpp"
21 : #include "IO/Observer/ReductionActions.hpp"
22 : #include "IO/Observer/TypeOfObservation.hpp"
23 : #include "Options/String.hpp"
24 : #include "Parallel/GlobalCache.hpp"
25 : #include "Parallel/Reduction.hpp"
26 : #include "ParallelAlgorithms/EventsAndTriggers/Event.hpp"
27 : #include "Utilities/TMPL.hpp"
28 :
29 : namespace PUP {
30 : class er;
31 : } // namespace PUP
32 :
33 : namespace amr::Events {
34 : namespace detail {
35 : using AmrStatsReductionData = Parallel::ReductionData<
36 : // Observation value / time
37 : Parallel::ReductionDatum<double, funcl::AssertEqual<>>,
38 : // Total number of elements
39 : Parallel::ReductionDatum<size_t, funcl::Plus<>>,
40 : // Total number of grid points
41 : Parallel::ReductionDatum<size_t, funcl::Plus<>>,
42 : // Number of grid points per dimension: total, min, max
43 : Parallel::ReductionDatum<std::vector<size_t>,
44 : funcl::ElementWise<funcl::Plus<>>>,
45 : Parallel::ReductionDatum<std::vector<size_t>,
46 : funcl::ElementWise<funcl::Min<>>>,
47 : Parallel::ReductionDatum<std::vector<size_t>,
48 : funcl::ElementWise<funcl::Max<>>>>;
49 :
50 : struct FormatAmrStatsOutput
51 : : tt::ConformsTo<observers::protocols::ReductionDataFormatter> {
52 : using reduction_data = AmrStatsReductionData;
53 : std::string operator()(double time, size_t total_num_elements,
54 : size_t total_num_points,
55 : const std::vector<size_t>& num_points_per_dim,
56 : const std::vector<size_t>& min_points_per_dim,
57 : const std::vector<size_t>& max_points_per_dim) const;
58 : // NOLINTNEXTLINE
59 : void pup(PUP::er& p);
60 : };
61 : } // namespace detail
62 :
63 : /*!
64 : * \ingroup AmrGroup
65 : * \brief Observes AMR statistics, such as number of elements and grid points
66 : */
67 : template <size_t Dim>
68 1 : class ObserveAmrStats : public Event {
69 : public:
70 0 : struct PrintToTerminal {
71 0 : using type = bool;
72 0 : static constexpr Options::String help = {
73 : "Whether to print reduction info to terminal."};
74 : };
75 0 : struct ObservePerCore {
76 0 : using type = bool;
77 0 : static constexpr Options::String help = {
78 : "Also write reduction observations per-core in a file per-node."};
79 : };
80 :
81 : /// \cond
82 : explicit ObserveAmrStats(CkMigrateMessage* m);
83 : using PUP::able::register_constructor;
84 : WRAPPED_PUPable_decl_template(ObserveAmrStats); // NOLINT
85 : /// \endcond
86 :
87 0 : using options = tmpl::list<PrintToTerminal, ObservePerCore>;
88 0 : static constexpr Options::String help = {"Observe AMR statistics"};
89 :
90 0 : ObserveAmrStats();
91 0 : ObserveAmrStats(bool print_to_terminal, bool observe_per_core);
92 :
93 0 : using observed_reduction_data_tags = observers::make_reduction_data_tags<
94 : tmpl::list<detail::AmrStatsReductionData>>;
95 :
96 0 : using compute_tags_for_observation_box = tmpl::list<>;
97 0 : using argument_tags = tmpl::list<domain::Tags::Mesh<Dim>>;
98 0 : using return_tags = tmpl::list<>;
99 :
100 : template <typename Metavariables, typename ParallelComponent>
101 0 : void operator()(const Mesh<Dim>& mesh,
102 : Parallel::GlobalCache<Metavariables>& cache,
103 : const ElementId<Dim>& element_id,
104 : const ParallelComponent* const /*meta*/,
105 : const ObservationValue& observation_value) const {
106 : const auto& mesh_extents = mesh.extents();
107 : const std::vector<size_t> mesh_extents_vec{mesh_extents.begin(),
108 : mesh_extents.end()};
109 : detail::AmrStatsReductionData reduction_data{observation_value.value,
110 : 1_st,
111 : mesh.number_of_grid_points(),
112 : mesh_extents_vec,
113 : mesh_extents_vec,
114 : mesh_extents_vec};
115 : std::vector<std::string> legend{observation_value.name, "NumElements",
116 : "TotalNumPoints"};
117 : std::vector<std::string> legend_num_p;
118 : std::vector<std::string> legend_min_p;
119 : std::vector<std::string> legend_max_p;
120 : legend_num_p.reserve(Dim);
121 : legend_min_p.reserve(Dim);
122 : legend_max_p.reserve(Dim);
123 : for (size_t d = 0; d < Dim; ++d) {
124 : legend_num_p.push_back("NumPointsPerDim_" + std::to_string(d));
125 : legend_min_p.push_back("MinPointsPerDim_" + std::to_string(d));
126 : legend_max_p.push_back("MaxPointsPerDim_" + std::to_string(d));
127 : }
128 : legend.insert(legend.end(), legend_num_p.begin(), legend_num_p.end());
129 : legend.insert(legend.end(), legend_min_p.begin(), legend_min_p.end());
130 : legend.insert(legend.end(), legend_max_p.begin(), legend_max_p.end());
131 :
132 : auto& local_observer = *Parallel::local_branch(
133 : Parallel::get_parallel_component<
134 : tmpl::conditional_t<Parallel::is_nodegroup_v<ParallelComponent>,
135 : observers::ObserverWriter<Metavariables>,
136 : observers::Observer<Metavariables>>>(cache));
137 : observers::ObservationId observation_id{observation_value.value,
138 : subfile_path_ + ".dat"};
139 : Parallel::ArrayComponentId array_component_id{
140 : std::add_pointer_t<ParallelComponent>{nullptr},
141 : Parallel::ArrayIndex<ElementId<Dim>>(element_id)};
142 : auto formatter = print_to_terminal_
143 : ? std::make_optional(detail::FormatAmrStatsOutput{})
144 : : std::nullopt;
145 : if constexpr (Parallel::is_nodegroup_v<ParallelComponent>) {
146 : const std::optional<int> observe_with_core_id =
147 : observe_per_core_
148 : ? std::make_optional(Parallel::my_node<int>(local_observer))
149 : : std::nullopt;
150 : Parallel::threaded_action<
151 : observers::ThreadedActions::CollectReductionDataOnNode>(
152 : local_observer, std::move(observation_id),
153 : std::move(array_component_id), subfile_path_, std::move(legend),
154 : std::move(reduction_data), std::move(formatter),
155 : observe_with_core_id);
156 : } else {
157 : Parallel::simple_action<observers::Actions::ContributeReductionData>(
158 : local_observer, std::move(observation_id),
159 : std::move(array_component_id), subfile_path_, std::move(legend),
160 : std::move(reduction_data), std::move(formatter), observe_per_core_);
161 : }
162 : }
163 :
164 0 : using observation_registration_tags = tmpl::list<>;
165 :
166 : std::optional<
167 : std::pair<observers::TypeOfObservation, observers::ObservationKey>>
168 0 : get_observation_type_and_key_for_registration() const {
169 : return {{observers::TypeOfObservation::Reduction,
170 : observers::ObservationKey(subfile_path_ + ".dat")}};
171 : }
172 :
173 0 : using is_ready_argument_tags = tmpl::list<>;
174 :
175 : template <typename Metavariables, typename ArrayIndex, typename Component>
176 0 : bool is_ready(Parallel::GlobalCache<Metavariables>& /*cache*/,
177 : const ArrayIndex& /*array_index*/,
178 : const Component* const /*meta*/) const {
179 : return true;
180 : }
181 :
182 1 : bool needs_evolved_variables() const override { return false; }
183 :
184 : // NOLINTNEXTLINE(google-runtime-references)
185 0 : void pup(PUP::er& p) override;
186 :
187 : private:
188 0 : bool print_to_terminal_{false};
189 0 : bool observe_per_core_{false};
190 0 : std::string subfile_path_{"Amr"};
191 : };
192 : } // namespace amr::Events
|