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