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_degrees_of_freedom,
64 : double slab_size, double min_time_step,
65 : double max_time_step, double effective_time_step,
66 : double min_wall_time, 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 : * - `Number of degrees of freedom`
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 degrees of freedom:
86 : *
87 : * \f{equation}
88 : * (\Delta t)_{\text{eff}}^{-1} =
89 : * \frac{\sum_{i \in \text{dof}} (\Delta t)_i^{-1}}{N_{\text{dof}}}.
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 : /// @{
99 : template <typename System,
100 : typename = tmpl::conditional_t<
101 : tt::is_a_v<tmpl::list, typename System::variables_tag>,
102 : typename System::variables_tag,
103 : tmpl::list<typename System::variables_tag>>>
104 1 : class ObserveTimeStep;
105 :
106 : template <typename System, typename... VariablesTags>
107 0 : class ObserveTimeStep<System, tmpl::list<VariablesTags...>> : public Event {
108 : private:
109 0 : using ReductionData = Events::detail::ObserveTimeStepReductionData;
110 :
111 : public:
112 : /// The name of the subfile inside the HDF5 file
113 1 : struct SubfileName {
114 0 : using type = std::string;
115 0 : static constexpr Options::String help = {
116 : "The name of the subfile inside the HDF5 file without an extension and "
117 : "without a preceding '/'."};
118 : };
119 :
120 0 : struct PrintTimeToTerminal {
121 0 : using type = bool;
122 0 : static constexpr Options::String help = {
123 : "Whether to print the time to screen."};
124 : };
125 :
126 0 : struct ObservePerCore {
127 0 : using type = bool;
128 0 : static constexpr Options::String help = {
129 : "Also write the data per-core in a file per-node."};
130 : };
131 :
132 : /// \cond
133 : explicit ObserveTimeStep(CkMigrateMessage* /*m*/);
134 : using PUP::able::register_constructor;
135 : WRAPPED_PUPable_decl_template(ObserveTimeStep); // NOLINT
136 : /// \endcond
137 :
138 0 : using options = tmpl::list<SubfileName, PrintTimeToTerminal, ObservePerCore>;
139 0 : static constexpr Options::String help =
140 : "Observe the size of the time steps.\n"
141 : "\n"
142 : "Writes reduction quantities:\n"
143 : "- Time\n"
144 : "- Number of degrees of freedom\n"
145 : "- Slab size\n"
146 : "- Minimum time step\n"
147 : "- Maximum time step\n"
148 : "- Effective time step\n"
149 : "\n"
150 : "The effective time step is the step size of a global-time-stepping\n"
151 : "method that would perform a similar amount of work.\n"
152 : "\n"
153 : "All values are reported as positive numbers, even for backwards\n"
154 : "evolutions.";
155 :
156 0 : ObserveTimeStep();
157 0 : ObserveTimeStep(const std::string& subfile_name, bool output_time,
158 : bool observe_per_core);
159 :
160 0 : using observed_reduction_data_tags =
161 : observers::make_reduction_data_tags<tmpl::list<ReductionData>>;
162 :
163 0 : using compute_tags_for_observation_box = tmpl::list<>;
164 :
165 0 : using return_tags = tmpl::list<>;
166 : // We obtain the grid size from the variables, rather than the mesh,
167 : // so that this observer is not DG-specific.
168 0 : using argument_tags = tmpl::list<::Tags::TimeStep, VariablesTags...>;
169 :
170 : template <typename ArrayIndex, typename ParallelComponent,
171 : typename Metavariables>
172 0 : void operator()(const TimeDelta& time_step,
173 : const typename VariablesTags::type&... variables,
174 : Parallel::GlobalCache<Metavariables>& cache,
175 : const ArrayIndex& array_index,
176 : const ParallelComponent* const /*meta*/,
177 : const ObservationValue& observation_value) const {
178 : auto [observation_id, legend, reduction_data, formatter] =
179 : assemble_data(time_step, variables..., observation_value);
180 :
181 : auto& local_observer = *Parallel::local_branch(
182 : Parallel::get_parallel_component<
183 : tmpl::conditional_t<Parallel::is_nodegroup_v<ParallelComponent>,
184 : observers::ObserverWriter<Metavariables>,
185 : observers::Observer<Metavariables>>>(cache));
186 :
187 : Parallel::ArrayComponentId array_component_id{
188 : std::add_pointer_t<ParallelComponent>{nullptr},
189 : Parallel::ArrayIndex<ArrayIndex>(array_index)};
190 :
191 : if constexpr (Parallel::is_nodegroup_v<ParallelComponent>) {
192 : const std::optional<int> observe_with_core_id =
193 : observe_per_core_
194 : ? std::make_optional(Parallel::my_node<int>(local_observer))
195 : : std::nullopt;
196 : Parallel::threaded_action<
197 : observers::ThreadedActions::CollectReductionDataOnNode>(
198 : local_observer, std::move(observation_id),
199 : std::move(array_component_id), subfile_path_, std::move(legend),
200 : std::move(reduction_data), std::move(formatter),
201 : observe_with_core_id);
202 : } else {
203 : Parallel::simple_action<observers::Actions::ContributeReductionData>(
204 : local_observer, std::move(observation_id),
205 : std::move(array_component_id), subfile_path_, std::move(legend),
206 : std::move(reduction_data), std::move(formatter), observe_per_core_);
207 : }
208 : }
209 :
210 0 : using observation_registration_tags = tmpl::list<>;
211 : std::pair<observers::TypeOfObservation, observers::ObservationKey>
212 0 : get_observation_type_and_key_for_registration() const;
213 :
214 0 : using is_ready_argument_tags = tmpl::list<>;
215 :
216 : template <typename Metavariables, typename ArrayIndex, typename Component>
217 0 : bool is_ready(Parallel::GlobalCache<Metavariables>& /*cache*/,
218 : const ArrayIndex& /*array_index*/,
219 : const Component* const /*meta*/) const {
220 : return true;
221 : }
222 :
223 1 : bool needs_evolved_variables() const override;
224 :
225 : // NOLINTNEXTLINE(google-runtime-references)
226 0 : void pup(PUP::er& p) override;
227 :
228 : private:
229 0 : auto assemble_data(const TimeDelta& time_step,
230 : const typename VariablesTags::type&... variables,
231 : const ObservationValue& observation_value) const
232 : -> std::tuple<observers::ObservationId, std::vector<std::string>,
233 : ReductionData,
234 : std::optional<Events::detail::FormatTimeOutput>>;
235 :
236 0 : std::string subfile_path_;
237 0 : bool output_time_;
238 0 : bool observe_per_core_;
239 : };
240 : /// @}
241 : } // namespace Events
|