Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <cmath>
7 : #include <cstddef>
8 : #include <limits>
9 : #include <optional>
10 : #include <pup.h>
11 : #include <string>
12 : #include <type_traits>
13 : #include <unordered_set>
14 : #include <vector>
15 :
16 : #include "DataStructures/DataBox/ObservationBox.hpp"
17 : #include "DataStructures/DataBox/TagName.hpp"
18 : #include "DataStructures/DataBox/ValidateSelection.hpp"
19 : #include "DataStructures/DataVector.hpp"
20 : #include "DataStructures/ExtractPoint.hpp"
21 : #include "DataStructures/Tensor/Tensor.hpp"
22 : #include "DataStructures/Tensor/TypeAliases.hpp"
23 : #include "Domain/Tags.hpp"
24 : #include "Options/String.hpp"
25 : #include "ParallelAlgorithms/EventsAndTriggers/Event.hpp"
26 : #include "Utilities/ErrorHandling/Error.hpp"
27 : #include "Utilities/Serialization/CharmPupable.hpp"
28 : #include "Utilities/TMPL.hpp"
29 : #include "Utilities/TypeTraits/IsA.hpp"
30 :
31 : /// \cond
32 : namespace Frame {
33 : struct Inertial;
34 : } // namespace Frame
35 : namespace Parallel {
36 : template <typename Metavariables>
37 : class GlobalCache;
38 : } // namespace Parallel
39 : namespace domain::Tags {
40 : template <size_t Dim, typename Frame>
41 : struct Coordinates;
42 : } // namespace domain::Tags
43 : /// \endcond
44 :
45 : namespace Events {
46 : /*!
47 : * \brief ERROR if tensors get too big.
48 : *
49 : * The magnitudes of the components of the specified tensors are
50 : * checked, and if any exceed the specified threshold an ERROR is
51 : * thrown, terminating the evolution.
52 : *
53 : * Any `Tensor` in the `db::DataBox` can be checked but must be listed
54 : * in the `Tensors` template parameter. Any additional compute tags
55 : * that hold a `Tensor` can also be added to the `Tensors` template
56 : * parameter. Finally, `Variables` and other non-tensor compute tags
57 : * used to calculate tensors can be listed in the
58 : * `NonTensorComputeTags`.
59 : *
60 : * \note The `NonTensorComputeTags` are intended to be used for `Variables`
61 : * compute tags like `Tags::DerivCompute`
62 : */
63 : template <size_t Dim, typename Tensors, typename NonTensorComputeTags>
64 1 : class ErrorIfDataTooBig : public Event {
65 : public:
66 : /// \cond
67 : explicit ErrorIfDataTooBig(CkMigrateMessage* /*unused*/) {}
68 : using PUP::able::register_constructor;
69 : WRAPPED_PUPable_decl_template(ErrorIfDataTooBig); // NOLINT
70 : /// \endcond
71 :
72 0 : struct VariablesToCheck {
73 0 : static constexpr Options::String help = "Subset of variables to check";
74 0 : using type = std::vector<std::string>;
75 0 : static size_t lower_bound_on_size() { return 1; }
76 : };
77 :
78 0 : struct Threshold {
79 0 : static constexpr Options::String help = "Threshold at which to ERROR";
80 0 : using type = double;
81 0 : static type lower_bound() { return 0.0; }
82 : };
83 :
84 0 : using options = tmpl::list<VariablesToCheck, Threshold>;
85 :
86 0 : static constexpr Options::String help = "ERROR if tensors get too big";
87 :
88 0 : ErrorIfDataTooBig() = default;
89 :
90 0 : ErrorIfDataTooBig(const std::vector<std::string>& variables_to_check,
91 : const double threshold, const Options::Context& context)
92 : : variables_to_check_(variables_to_check.begin(),
93 : variables_to_check.end()),
94 : threshold_(threshold) {
95 : db::validate_selection<Tensors>(variables_to_check, context);
96 : }
97 :
98 0 : using compute_tags_for_observation_box =
99 : tmpl::append<Tensors, NonTensorComputeTags>;
100 :
101 0 : using return_tags = tmpl::list<>;
102 0 : using argument_tags =
103 : tmpl::list<::Tags::ObservationBox,
104 : ::domain::Tags::Coordinates<Dim, Frame::Inertial>>;
105 :
106 : template <typename ComputeTagsList, typename DataBoxType,
107 : typename Metavariables, typename ArrayIndex,
108 : typename ParallelComponent>
109 0 : void operator()(const ObservationBox<ComputeTagsList, DataBoxType>& box,
110 : const tnsr::I<DataVector, Dim>& coordinates,
111 : Parallel::GlobalCache<Metavariables>& /*cache*/,
112 : const ArrayIndex& /*array_index*/,
113 : const ParallelComponent* const /*component*/,
114 : const ObservationValue& /*observation_value*/) const {
115 : tmpl::for_each<Tensors>([&](const auto tensor_tag_v) {
116 : using tensor_tag = tmpl::type_from<decltype(tensor_tag_v)>;
117 : const std::string tag_name = db::tag_name<tensor_tag>();
118 : if (variables_to_check_.count(tag_name) != 0) {
119 : const auto check_components = [&](const auto& tensor) {
120 : for (const auto& component : tensor) {
121 : for (size_t point = 0; point < component.size(); ++point) {
122 : if (std::abs(component[point]) > threshold_) {
123 : ERROR_NO_TRACE(
124 : tag_name
125 : << " too big with value " << extract_point(tensor, point)
126 : << " at position\n"
127 : << extract_point(coordinates, point) << "\nwith ElementId: "
128 : << get<::domain::Tags::Element<Dim>>(box).id());
129 : }
130 : }
131 : }
132 : };
133 : const auto& tensor = get<tensor_tag>(box);
134 : if constexpr (tt::is_a_v<std::optional,
135 : std::decay_t<decltype(tensor)>>) {
136 : if (tensor.has_value()) {
137 : check_components(*tensor);
138 : }
139 : } else {
140 : check_components(tensor);
141 : }
142 : }
143 : });
144 : }
145 :
146 0 : using is_ready_argument_tags = tmpl::list<>;
147 :
148 : template <typename Metavariables, typename ArrayIndex, typename Component>
149 0 : bool is_ready(Parallel::GlobalCache<Metavariables>& /*cache*/,
150 : const ArrayIndex& /*array_index*/,
151 : const Component* const /*meta*/) const {
152 : return true;
153 : }
154 :
155 1 : bool needs_evolved_variables() const override { return true; }
156 :
157 : // NOLINTNEXTLINE(google-runtime-references)
158 0 : void pup(PUP::er& p) override {
159 : Event::pup(p);
160 : p | variables_to_check_;
161 : p | threshold_;
162 : }
163 :
164 : private:
165 0 : std::unordered_set<std::string> variables_to_check_{};
166 0 : double threshold_ = std::numeric_limits<double>::signaling_NaN();
167 : };
168 :
169 : /// \cond
170 : template <size_t Dim, typename Tensors, typename NonTensorComputeTags>
171 : PUP::able::PUP_ID
172 : ErrorIfDataTooBig<Dim, Tensors,
173 : NonTensorComputeTags>::my_PUP_ID = 0; // NOLINT
174 : /// \endcond
175 : } // namespace Events
|