ObserveTimeStep.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <cmath>
7 #include <cstddef>
8 #include <pup.h>
9 #include <pup_stl.h>
10 #include <string>
11 #include <type_traits>
12 #include <utility>
13 #include <vector>
14 
15 #include "IO/Observer/ArrayComponentId.hpp"
16 #include "IO/Observer/Helpers.hpp"
17 #include "IO/Observer/ObservationId.hpp"
18 #include "IO/Observer/ObserverComponent.hpp" // IWYU pragma: keep
19 #include "IO/Observer/Protocols/ReductionDataFormatter.hpp"
20 #include "IO/Observer/ReductionActions.hpp" // IWYU pragma: keep
21 #include "IO/Observer/TypeOfObservation.hpp"
22 #include "Options/Options.hpp"
23 #include "Parallel/ArrayIndex.hpp"
25 #include "Parallel/GlobalCache.hpp"
26 #include "Parallel/Invoke.hpp"
27 #include "Parallel/Reduction.hpp"
28 #include "ParallelAlgorithms/EventsAndTriggers/Event.hpp"
29 #include "Time/Slab.hpp"
30 #include "Time/Time.hpp"
31 #include "Utilities/Functional.hpp"
32 #include "Utilities/ProtocolHelpers.hpp"
33 #include "Utilities/Registration.hpp"
34 #include "Utilities/TMPL.hpp"
35 
36 /// \cond
37 namespace Tags {
38 struct Time;
39 struct TimeStep;
40 } // namespace Tags
41 /// \endcond
42 
43 namespace Events {
44 /// \cond
45 template <typename Metavariables, typename EventRegistrars>
46 class ObserveTimeStep;
47 /// \endcond
48 
49 namespace Registrars {
50 template <typename Metavariables>
51 using ObserveTimeStep =
53 } // namespace Registrars
54 
55 namespace detail {
56 using ObserveTimeStepReductionData = Parallel::ReductionData<
63  double, funcl::Plus<>,
66 
67 struct FormatTimeOutput
68  : tt::ConformsTo<observers::protocols::ReductionDataFormatter> {
69  using reduction_data = ObserveTimeStepReductionData;
70  std::string operator()(const double time, const size_t /* num_points */,
71  const double /* slab_size */,
72  const double /* min_time_step */,
73  const double /* max_time_step */,
74  const double /* effective_time_step */) const
75  noexcept {
76  return "Current time: " + std::to_string(time);
77  }
78  // NOLINTNEXTLINE
79  void pup(PUP::er& /*p*/) noexcept {}
80 };
81 } // namespace detail
82 
83 /*!
84  * \brief %Observe the size of the time steps.
85  *
86  * Writes reduction quantities:
87  * - `%Time`
88  * - `NumberOfPoints`
89  * - `%Slab size`
90  * - `Minimum time step`
91  * - `Maximum time step`
92  * - `Effective time step`
93  *
94  * The effective time step is the step size of a global-time-stepping
95  * method that would perform a similar amount of work. This is the
96  * harmonic mean of the step size over all grid points:
97  *
98  * \f{equation}
99  * (\Delta t)_{\text{eff}}^{-1} =
100  * \frac{\sum_{i \in \text{points}} (\Delta t)_i^{-1}}{N_{\text{points}}}.
101  * \f}
102  *
103  * This corresponds to averaging the number of steps per unit time
104  * taken by all points.
105  *
106  * All values are reported as positive numbers, even for backwards
107  * evolutions.
108  */
109 template <typename Metavariables,
110  typename EventRegistrars =
111  tmpl::list<Registrars::ObserveTimeStep<Metavariables>>>
112 class ObserveTimeStep : public Event<EventRegistrars> {
113  private:
114  using ReductionData = Events::detail::ObserveTimeStepReductionData;
115 
116  public:
117  /// The name of the subfile inside the HDF5 file
118  struct SubfileName {
119  using type = std::string;
120  static constexpr Options::String help = {
121  "The name of the subfile inside the HDF5 file without an extension and "
122  "without a preceding '/'."};
123  };
124 
126  using type = bool;
127  static constexpr Options::String help = {
128  "Whether to print the time to screen."};
129  };
130 
131  /// \cond
132  explicit ObserveTimeStep(CkMigrateMessage* /*unused*/) noexcept {}
133  using PUP::able::register_constructor;
135  /// \endcond
136 
137  using options = tmpl::list<SubfileName, PrintTimeToTerminal>;
138  static constexpr Options::String help =
139  "Observe the size of the time steps.\n"
140  "\n"
141  "Writes reduction quantities:\n"
142  "- Time\n"
143  "- NumberOfPoints\n"
144  "- Slab size\n"
145  "- Minimum time step\n"
146  "- Maximum time step\n"
147  "- Effective time step\n"
148  "\n"
149  "The effective time step is the step size of a global-time-stepping\n"
150  "method that would perform a similar amount of work.\n"
151  "\n"
152  "All values are reported as positive numbers, even for backwards\n"
153  "evolutions.";
154 
155  ObserveTimeStep() = default;
156  explicit ObserveTimeStep(const std::string& subfile_name,
157  const bool output_time) noexcept;
158 
159  using observed_reduction_data_tags =
160  observers::make_reduction_data_tags<tmpl::list<ReductionData>>;
161 
162  // We obtain the grid size from the variables, rather than the mesh,
163  // so that this observer is not DG-specific.
164  using argument_tags =
165  tmpl::list<Tags::Time, Tags::TimeStep,
166  typename Metavariables::system::variables_tag>;
167 
168  template <typename ArrayIndex, typename ParallelComponent>
169  void operator()(
170  const double& time, const TimeDelta& time_step,
171  const typename Metavariables::system::variables_tag::type& variables,
173  const ArrayIndex& array_index,
174  const ParallelComponent* const /*meta*/) const noexcept {
175  const size_t number_of_grid_points = variables.number_of_grid_points();
176  const double slab_size = time_step.slab().duration().value();
177  const double step_size = abs(time_step.value());
178 
179  auto& local_observer =
180  *Parallel::get_parallel_component<observers::Observer<Metavariables>>(
181  cache)
182  .ckLocalBranch();
183  auto formatter =
184  output_time_ ? std::make_optional(Events::detail::FormatTimeOutput{})
185  : std::nullopt;
186  Parallel::simple_action<observers::Actions::ContributeReductionData>(
187  local_observer, observers::ObservationId(time, subfile_path_ + ".dat"),
190  Parallel::ArrayIndex<ArrayIndex>(array_index)},
191  subfile_path_,
192  std::vector<std::string>{"Time", "NumberOfPoints", "Slab size",
193  "Minimum time step", "Maximum time step",
194  "Effective time step"},
195  ReductionData{time, number_of_grid_points, slab_size, step_size,
196  step_size, number_of_grid_points / step_size},
197  std::move(formatter));
198  }
199 
200  using observation_registration_tags = tmpl::list<>;
202  get_observation_type_and_key_for_registration() const noexcept {
204  observers::ObservationKey(subfile_path_ + ".dat")};
205  }
206 
207  bool needs_evolved_variables() const noexcept override { return false; }
208 
209  // NOLINTNEXTLINE(google-runtime-references)
210  void pup(PUP::er& p) override {
212  p | subfile_path_;
213  p | output_time_;
214  }
215 
216  private:
217  std::string subfile_path_;
218  bool output_time_;
219 };
220 
221 template <typename Metavariables, typename EventRegistrars>
222 ObserveTimeStep<Metavariables, EventRegistrars>::ObserveTimeStep(
223  const std::string& subfile_name, const bool output_time) noexcept
224  : subfile_path_("/" + subfile_name), output_time_(output_time) {}
225 
226 /// \cond
227 template <typename Metavariables, typename EventRegistrars>
228 PUP::able::PUP_ID ObserveTimeStep<Metavariables, EventRegistrars>::my_PUP_ID =
229  0; // NOLINT
230 /// \endcond
231 } // namespace Events
observers::ObservationId
A unique identifier for an observation representing the type of observation and the instance (e....
Definition: ObservationId.hpp:71
funcl::Divides
Functional for computing / of two objects.
Definition: Functional.hpp:235
std::string
CharmPupable.hpp
utility
Parallel::GlobalCache
Definition: ElementReceiveInterpPoints.hpp:15
Parallel::ReductionDatum
The data to be reduced, and invokables to be called whenever two reduction messages are combined and ...
Definition: Reduction.hpp:63
std::pair
GlobalCache.hpp
std::index_sequence
Options.hpp
vector
Tags::TimeStep
Tag for step size.
Definition: Tags.hpp:42
observers::ObservationKey
Used as a key in maps to keep track of how many elements have registered.
Definition: ObservationId.hpp:28
Events::ObserveTimeStep::SubfileName
The name of the subfile inside the HDF5 file.
Definition: ObserveTimeStep.hpp:118
cmath
Registration::Registrar
A template for defining a registrar.
Definition: Registration.hpp:42
std::add_pointer_t
WRAPPED_PUPable_decl_template
#define WRAPPED_PUPable_decl_template(className)
Mark derived classes as serializable.
Definition: CharmPupable.hpp:22
Event
Definition: Event.hpp:30
cstddef
funcl::Plus
Functional for computing + of two objects.
Definition: Functional.hpp:238
TimeDelta
Definition: Time.hpp:88
Tags::Time
Tag for the current time as a double.
Definition: Tags.hpp:73
Time.hpp
ActionTesting::cache
Parallel::GlobalCache< Metavariables > & cache(MockRuntimeSystem< Metavariables > &runner, const ArrayIndex &array_index) noexcept
Returns the GlobalCache of Component with index array_index.
Definition: MockRuntimeSystemFreeFunctions.hpp:382
Time
Definition: Time.hpp:29
Options::String
const char *const String
The string used in option structs.
Definition: Options.hpp:32
observers::TypeOfObservation::Reduction
@ Reduction
The sender will only perform reduction observations.
Slab.hpp
Events::ObserveTimeStep::PrintTimeToTerminal
Definition: ObserveTimeStep.hpp:125
observers::ArrayComponentId
An ID type that identifies both the parallel component and the index in the parallel component.
Definition: ArrayComponentId.hpp:27
Events::ObserveTimeStep
Observe the size of the time steps.
Definition: ObserveTimeStep.hpp:112
std::time
T time(T... args)
Parallel::ArrayIndex
The array index used for indexing Chare Arrays, mostly an implementation detail.
Definition: ArrayIndex.hpp:28
tt::ConformsTo
Indicate a class conforms to the Protocol.
Definition: ProtocolHelpers.hpp:22
type_traits
TMPL.hpp
string