Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <optional> 7 : #include <set> 8 : #include <sstream> 9 : #include <string> 10 : #include <type_traits> 11 : 12 : #include "DataStructures/LinkedMessageId.hpp" 13 : #include "DataStructures/Variables.hpp" 14 : #include "Domain/Creators/Tags/Domain.hpp" 15 : #include "Domain/FunctionsOfTime/Tags.hpp" 16 : #include "Domain/Structure/ElementId.hpp" 17 : #include "IO/Logging/Verbosity.hpp" 18 : #include "Parallel/ArrayComponentId.hpp" 19 : #include "Parallel/Callback.hpp" 20 : #include "Parallel/GlobalCache.hpp" 21 : #include "Parallel/Invoke.hpp" 22 : #include "Parallel/ParallelComponentHelpers.hpp" 23 : #include "Parallel/Printf/Printf.hpp" 24 : #include "ParallelAlgorithms/ApparentHorizonFinder/HorizonAliases.hpp" 25 : #include "ParallelAlgorithms/ApparentHorizonFinder/Storage.hpp" 26 : #include "Utilities/ErrorHandling/Assert.hpp" 27 : #include "Utilities/Gsl.hpp" 28 : 29 : /// \cond 30 : namespace ah { 31 : template <class Metavariables, typename HorizonMetavars> 32 : struct Component; 33 : template <typename HorizonMetavars> 34 : struct FindApparentHorizon; 35 : } // namespace ah 36 : /// \endcond 37 : 38 : namespace ah { 39 : /*! 40 : * \brief Determines what the current time should be. 41 : * 42 : * \details If there's already a current time, or there are no pending times 43 : * available, then there's nothing to do. Otherwise, checks if the first pending 44 : * time is the next to use. If so, sets it as the current time and removes it 45 : * from pending. 46 : */ 47 : template <typename Fr> 48 1 : void set_current_time( 49 : gsl::not_null<std::optional<LinkedMessageId<double>>*> current_time, 50 : gsl::not_null<std::set<LinkedMessageId<double>>*> pending_times, 51 : const std::set<LinkedMessageId<double>>& completed_times, 52 : const std::unordered_map<LinkedMessageId<double>, 53 : ah::Storage::SingleTimeStorage<Fr>>& all_storage, 54 : const ::Verbosity& verbosity, const std::string& name); 55 : 56 : /*! 57 : * \brief Checks if the current time is ready. 58 : * 59 : * \details If the current time is after any expiration time, registers a 60 : * callback for the `ah::FindApparentHorizon` action (but doesn't send the 61 : * volume variables again because we already did that). Returns if the current 62 : * time is ready or not. 63 : */ 64 : template <typename HorizonMetavars, typename Metavariables> 65 1 : bool check_if_current_time_is_ready( 66 : const LinkedMessageId<double>& current_time, 67 : Parallel::GlobalCache<Metavariables>& cache, 68 : const LinkedMessageId<double>& incoming_time, 69 : const ElementId<3>& incoming_element_id, const ::Mesh<3>& incoming_mesh, 70 : const std::optional<std::string>& dependency) { 71 : const auto& domain = get<domain::Tags::Domain<3>>(cache); 72 : 73 : // Now we need to check the functions of time for the current time 74 : if constexpr (Parallel::is_in_global_cache<Metavariables, 75 : domain::Tags::FunctionsOfTime>) { 76 : if (domain.is_time_dependent()) { 77 : auto& this_proxy = Parallel::get_parallel_component< 78 : Component<Metavariables, HorizonMetavars>>(cache); 79 : double min_expiration_time = std::numeric_limits<double>::max(); 80 : const Parallel::ArrayComponentId array_component_id = 81 : Parallel::make_array_component_id< 82 : Component<Metavariables, HorizonMetavars>>(0); 83 : // If the functions of time aren't ready, this will set a callback to 84 : // FindApparentHorizon that will be called by the GlobalCache when 85 : // domain::Tags::FunctionsOfTime is updated. 86 : return ::Parallel::mutable_cache_item_is_ready< 87 : domain::Tags::FunctionsOfTime>( 88 : cache, array_component_id, 89 : [&](const std::unordered_map< 90 : std::string, 91 : std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>& 92 : functions_of_time) -> std::unique_ptr<Parallel::Callback> { 93 : min_expiration_time = 94 : std::min_element(functions_of_time.begin(), 95 : functions_of_time.end(), 96 : [](const auto& a, const auto& b) { 97 : return a.second->time_bounds()[1] < 98 : b.second->time_bounds()[1]; 99 : }) 100 : ->second->time_bounds()[1]; 101 : 102 : // Success: the current time is ok. 103 : // Failure: the current time is not ok. 104 : using horizon_frame = typename HorizonMetavars::frame; 105 : return current_time.id <= min_expiration_time 106 : ? std::unique_ptr<Parallel::Callback>{} 107 : : std::unique_ptr<Parallel::Callback>( 108 : new Parallel::SimpleActionCallback< 109 : FindApparentHorizon<HorizonMetavars>, 110 : decltype(this_proxy), LinkedMessageId<double>, 111 : ElementId<3>, Mesh<3>, 112 : Variables<ah::vars_to_interpolate_to_target< 113 : 3, horizon_frame>>, 114 : std::optional<std::string>, bool>( 115 : this_proxy, incoming_time, incoming_element_id, 116 : incoming_mesh, 117 : Variables<ah::vars_to_interpolate_to_target< 118 : 3, horizon_frame>>{}, 119 : dependency, 120 : /* vars_have_already_been_received */ true)); 121 : }); 122 : } // if (domain.is_time_dependent()) 123 : } else { 124 : if (domain.is_time_dependent()) { 125 : // We error here because the maps are time-dependent, yet 126 : // the cache does not contain FunctionsOfTime. It would be 127 : // nice to make this a compile-time error; however, we want 128 : // the code to compile for the completely time-independent 129 : // case where there are no FunctionsOfTime in the cache at 130 : // all. Unfortunately, checking whether the maps are 131 : // time-dependent is currently not constexpr. 132 : ERROR( 133 : "There is a time-dependent CoordinateMap in at least one " 134 : "of the Blocks, but FunctionsOfTime are not in the " 135 : "GlobalCache. If you intend to use a time-dependent " 136 : "CoordinateMap, please add FunctionsOfTime to the GlobalCache."); 137 : } 138 : } 139 : 140 : // The current time is ready 141 : return true; 142 : } 143 : } // namespace ah