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 "IO/Observer/Helpers.hpp"
15 : #include "IO/Observer/ObservationId.hpp"
16 : #include "IO/Observer/ObserverComponent.hpp"
17 : #include "IO/Observer/Protocols/ReductionDataFormatter.hpp"
18 : #include "IO/Observer/ReductionActions.hpp"
19 : #include "IO/Observer/TypeOfObservation.hpp"
20 : #include "Options/String.hpp"
21 : #include "Parallel/ArrayComponentId.hpp"
22 : #include "Parallel/ArrayIndex.hpp"
23 : #include "Parallel/GlobalCache.hpp"
24 : #include "Parallel/Info.hpp"
25 : #include "Parallel/Invoke.hpp"
26 : #include "Parallel/Local.hpp"
27 : #include "Parallel/Reduction.hpp"
28 : #include "Parallel/TypeTraits.hpp"
29 : #include "ParallelAlgorithms/EventsAndTriggers/Event.hpp"
30 : #include "Utilities/Functional.hpp"
31 : #include "Utilities/ProtocolHelpers.hpp"
32 : #include "Utilities/Serialization/CharmPupable.hpp"
33 : #include "Utilities/TMPL.hpp"
34 :
35 : /// \cond
36 : class TimeDelta;
37 : namespace PUP {
38 : class er;
39 : } // namespace PUP
40 : namespace Tags {
41 : struct TimeStep;
42 : } // namespace Tags
43 : /// \endcond
44 :
45 : namespace Events {
46 : namespace detail {
47 : using ObserveTimeStepReductionData = Parallel::ReductionData<
48 : Parallel::ReductionDatum<double, funcl::AssertEqual<>>,
49 : Parallel::ReductionDatum<size_t, funcl::Plus<>>,
50 : Parallel::ReductionDatum<double, funcl::AssertEqual<>>,
51 : Parallel::ReductionDatum<double, funcl::Min<>>,
52 : Parallel::ReductionDatum<double, funcl::Max<>>,
53 : Parallel::ReductionDatum<
54 : double, funcl::Plus<>,
55 : funcl::Divides<funcl::Literal<1, double>, funcl::Divides<>>,
56 : std::index_sequence<1>>,
57 : Parallel::ReductionDatum<double, funcl::Min<>>,
58 : Parallel::ReductionDatum<double, funcl::Max<>>>;
59 :
60 : struct FormatTimeOutput
61 : : tt::ConformsTo<observers::protocols::ReductionDataFormatter> {
62 : using reduction_data = ObserveTimeStepReductionData;
63 : std::string operator()(double time, size_t num_points, double slab_size,
64 : double min_time_step, double max_time_step,
65 : double effective_time_step, double min_wall_time,
66 : double max_wall_time) const;
67 : // NOLINTNEXTLINE
68 : void pup(PUP::er& p);
69 : };
70 : } // namespace detail
71 :
72 : /*!
73 : * \brief %Observe the size of the time steps.
74 : *
75 : * Writes reduction quantities:
76 : * - `%Time`
77 : * - `NumberOfPoints`
78 : * - `%Slab size`
79 : * - `Minimum time step`
80 : * - `Maximum time step`
81 : * - `Effective time step`
82 : *
83 : * The effective time step is the step size of a global-time-stepping
84 : * method that would perform a similar amount of work. This is the
85 : * harmonic mean of the step size over all grid points:
86 : *
87 : * \f{equation}
88 : * (\Delta t)_{\text{eff}}^{-1} =
89 : * \frac{\sum_{i \in \text{points}} (\Delta t)_i^{-1}}{N_{\text{points}}}.
90 : * \f}
91 : *
92 : * This corresponds to averaging the number of steps per unit time
93 : * taken by all points.
94 : *
95 : * All values are reported as positive numbers, even for backwards
96 : * evolutions.
97 : */
98 : template <typename System>
99 1 : class ObserveTimeStep : public Event {
100 : private:
101 0 : using ReductionData = Events::detail::ObserveTimeStepReductionData;
102 :
103 : public:
104 : /// The name of the subfile inside the HDF5 file
105 1 : struct SubfileName {
106 0 : using type = std::string;
107 0 : static constexpr Options::String help = {
108 : "The name of the subfile inside the HDF5 file without an extension and "
109 : "without a preceding '/'."};
110 : };
111 :
112 0 : struct PrintTimeToTerminal {
113 0 : using type = bool;
114 0 : static constexpr Options::String help = {
115 : "Whether to print the time to screen."};
116 : };
117 :
118 0 : struct ObservePerCore {
119 0 : using type = bool;
120 0 : static constexpr Options::String help = {
121 : "Also write the data per-core in a file per-node."};
122 : };
123 :
124 : /// \cond
125 : explicit ObserveTimeStep(CkMigrateMessage* /*m*/);
126 : using PUP::able::register_constructor;
127 : WRAPPED_PUPable_decl_template(ObserveTimeStep); // NOLINT
128 : /// \endcond
129 :
130 0 : using options = tmpl::list<SubfileName, PrintTimeToTerminal, ObservePerCore>;
131 0 : static constexpr Options::String help =
132 : "Observe the size of the time steps.\n"
133 : "\n"
134 : "Writes reduction quantities:\n"
135 : "- Time\n"
136 : "- NumberOfPoints\n"
137 : "- Slab size\n"
138 : "- Minimum time step\n"
139 : "- Maximum time step\n"
140 : "- Effective time step\n"
141 : "\n"
142 : "The effective time step is the step size of a global-time-stepping\n"
143 : "method that would perform a similar amount of work.\n"
144 : "\n"
145 : "All values are reported as positive numbers, even for backwards\n"
146 : "evolutions.";
147 :
148 0 : ObserveTimeStep();
149 0 : ObserveTimeStep(const std::string& subfile_name, bool output_time,
150 : bool observe_per_core);
151 :
152 0 : using observed_reduction_data_tags =
153 : observers::make_reduction_data_tags<tmpl::list<ReductionData>>;
154 :
155 0 : using compute_tags_for_observation_box = tmpl::list<>;
156 :
157 0 : using return_tags = tmpl::list<>;
158 : // We obtain the grid size from the variables, rather than the mesh,
159 : // so that this observer is not DG-specific.
160 0 : using argument_tags =
161 : tmpl::list<::Tags::TimeStep, typename System::variables_tag>;
162 :
163 : template <typename ArrayIndex, typename ParallelComponent,
164 : typename Metavariables>
165 0 : void operator()(const TimeDelta& time_step,
166 : const typename System::variables_tag::type& variables,
167 : Parallel::GlobalCache<Metavariables>& cache,
168 : const ArrayIndex& array_index,
169 : const ParallelComponent* const /*meta*/,
170 : const ObservationValue& observation_value) const {
171 : auto [observation_id, legend, reduction_data, formatter] =
172 : assemble_data(time_step, variables, observation_value);
173 :
174 : auto& local_observer = *Parallel::local_branch(
175 : Parallel::get_parallel_component<
176 : tmpl::conditional_t<Parallel::is_nodegroup_v<ParallelComponent>,
177 : observers::ObserverWriter<Metavariables>,
178 : observers::Observer<Metavariables>>>(cache));
179 :
180 : Parallel::ArrayComponentId array_component_id{
181 : std::add_pointer_t<ParallelComponent>{nullptr},
182 : Parallel::ArrayIndex<ArrayIndex>(array_index)};
183 :
184 : if constexpr (Parallel::is_nodegroup_v<ParallelComponent>) {
185 : const std::optional<int> observe_with_core_id =
186 : observe_per_core_
187 : ? std::make_optional(Parallel::my_node<int>(local_observer))
188 : : std::nullopt;
189 : Parallel::threaded_action<
190 : observers::ThreadedActions::CollectReductionDataOnNode>(
191 : local_observer, std::move(observation_id),
192 : std::move(array_component_id), subfile_path_, std::move(legend),
193 : std::move(reduction_data), std::move(formatter),
194 : observe_with_core_id);
195 : } else {
196 : Parallel::simple_action<observers::Actions::ContributeReductionData>(
197 : local_observer, std::move(observation_id),
198 : std::move(array_component_id), subfile_path_, std::move(legend),
199 : std::move(reduction_data), std::move(formatter), observe_per_core_);
200 : }
201 : }
202 :
203 0 : using observation_registration_tags = tmpl::list<>;
204 : std::pair<observers::TypeOfObservation, observers::ObservationKey>
205 0 : get_observation_type_and_key_for_registration() const;
206 :
207 0 : using is_ready_argument_tags = tmpl::list<>;
208 :
209 : template <typename Metavariables, typename ArrayIndex, typename Component>
210 0 : bool is_ready(Parallel::GlobalCache<Metavariables>& /*cache*/,
211 : const ArrayIndex& /*array_index*/,
212 : const Component* const /*meta*/) const {
213 : return true;
214 : }
215 :
216 1 : bool needs_evolved_variables() const override;
217 :
218 : // NOLINTNEXTLINE(google-runtime-references)
219 0 : void pup(PUP::er& p) override;
220 :
221 : private:
222 0 : auto assemble_data(const TimeDelta& time_step,
223 : const typename System::variables_tag::type& variables,
224 : const ObservationValue& observation_value) const
225 : -> std::tuple<observers::ObservationId, std::vector<std::string>,
226 : ReductionData,
227 : std::optional<Events::detail::FormatTimeOutput>>;
228 :
229 0 : std::string subfile_path_;
230 0 : bool output_time_;
231 0 : bool observe_per_core_;
232 : };
233 : } // namespace Events
|