Skip to content

Commit

Permalink
Add FoTAreReady function for simple actions
Browse files Browse the repository at this point in the history
  • Loading branch information
knelli2 committed Sep 28, 2023
1 parent 63c0c16 commit 1f3c8da
Show file tree
Hide file tree
Showing 3 changed files with 300 additions and 61 deletions.
4 changes: 3 additions & 1 deletion src/ControlSystem/Trigger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <string>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "ControlSystem/CombinedName.hpp"
Expand Down Expand Up @@ -136,7 +137,8 @@ class Trigger : public DenseTrigger {
// At least one control system is active
const bool is_ready = domain::functions_of_time_are_ready<
control_system::Tags::MeasurementTimescales>(
cache, array_index, component, time, std::array{measurement_name_});
cache, array_index, component, time,
std::unordered_set{measurement_name_});
if (not is_ready) {
if (Parallel::get<Tags::Verbosity>(cache) >= ::Verbosity::Debug) {
Parallel::printf(
Expand Down
131 changes: 90 additions & 41 deletions src/Domain/FunctionsOfTime/FunctionsOfTimeAreReady.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>

#include "DataStructures/DataBox/DataBox.hpp"
Expand All @@ -18,6 +19,7 @@
#include "Parallel/ArrayComponentId.hpp"
#include "Parallel/Callback.hpp"
#include "Parallel/GlobalCache.hpp"
#include "Parallel/ParallelComponentHelpers.hpp"
#include "Utilities/Algorithm.hpp"
#include "Utilities/ErrorHandling/Assert.hpp"
#include "Utilities/StdHelpers.hpp"
Expand All @@ -36,55 +38,102 @@ class TaggedTuple;
/// \endcond

namespace domain {
namespace detail {
template <typename CacheTag, typename Callback, typename Metavariables,
typename ArrayIndex, typename Component, typename... Args>
bool functions_of_time_are_ready_impl(
Parallel::GlobalCache<Metavariables>& cache, const ArrayIndex& array_index,
const Component* /*meta*/, const double time,
const std::optional<std::unordered_set<std::string>>& functions_to_check,
Args... args) {
if constexpr (Parallel::is_in_global_cache<Metavariables, CacheTag>) {
const auto& proxy =
::Parallel::get_parallel_component<Component>(cache)[array_index];
const Parallel::ArrayComponentId array_component_id =
Parallel::make_array_component_id<Component>(array_index);

return Parallel::mutable_cache_item_is_ready<CacheTag>(
cache, array_component_id,
[&functions_to_check, &proxy, &time,
&args...](const std::unordered_map<
std::string,
std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
functions_of_time) {
using ::operator<<;
ASSERT(
alg::all_of(
functions_to_check.value_or(
std::unordered_set<std::string>{}),
[&functions_of_time](const std::string& function_to_check) {
return functions_of_time.count(function_to_check) == 1;
}),
"Not all functions to check ("
<< functions_to_check.value() << ") are in the global cache ("
<< keys_of(functions_of_time) << ")");
for (const auto& [name, f_of_t] : functions_of_time) {
if (functions_to_check.has_value() and
functions_to_check->count(name) == 0) {
continue;
}
const double expiration_time = f_of_t->time_bounds()[1];
if (time > expiration_time) {
return std::unique_ptr<Parallel::Callback>(
new Callback(proxy, std::move(args)...));
}
}
return std::unique_ptr<Parallel::Callback>{};
});
} else {
return true;
}
}
} // namespace detail

/// \ingroup ComputationalDomainGroup
/// Check that functions of time are up-to-date.
///
/// Check that functions of time in \p CacheTag with names in \p
/// functions_to_check are ready at time \p time. If no names are
/// listed in \p functions_to_check, checks all functions in \p
/// CacheTag. If any function is not ready, schedules a
/// `Parallel::PerformAlgorithmCallback` with the GlobalCache.
/// functions_to_check are ready at time \p time. If \p functions_to_check is
/// a `std::nullopt`, checks all functions in \p CacheTag. If any function is
/// not ready, schedules a `Parallel::PerformAlgorithmCallback` with the
/// GlobalCache..
template <typename CacheTag, typename Metavariables, typename ArrayIndex,
typename Component, size_t N = 0>
typename Component>
bool functions_of_time_are_ready(
Parallel::GlobalCache<Metavariables>& cache, const ArrayIndex& array_index,
const Component* /*meta*/, const double time,
const std::array<std::string, N>& functions_to_check =
std::array<std::string, 0>{}) {
const auto& proxy =
::Parallel::get_parallel_component<Component>(cache)[array_index];
const Parallel::ArrayComponentId array_component_id =
Parallel::make_array_component_id<Component>(array_index);
const Component* component_p, const double time,
const std::optional<std::unordered_set<std::string>>& functions_to_check =
std::nullopt) {
using ProxyType = std::decay_t<decltype(
::Parallel::get_parallel_component<Component>(cache)[array_index])>;
return detail::functions_of_time_are_ready_impl<
CacheTag, Parallel::PerformAlgorithmCallback<ProxyType>>(
cache, array_index, component_p, time, functions_to_check);
}

return Parallel::mutable_cache_item_is_ready<CacheTag>(
cache, array_component_id,
[&functions_to_check, &proxy,
&time](const std::unordered_map<
std::string,
std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
functions_of_time) {
using ::operator<<;
ASSERT(alg::all_of(
functions_to_check,
[&functions_of_time](const std::string& function_to_check) {
return functions_of_time.count(function_to_check) == 1;
}),
"Not all functions to check ("
<< functions_to_check << ") are in the global cache ("
<< keys_of(functions_of_time) << ")");
for (const auto& [name, f_of_t] : functions_of_time) {
if ((not functions_to_check.empty()) and
alg::find(functions_to_check, name) == functions_to_check.end()) {
continue;
}
const double expiration_time = f_of_t->time_bounds()[1];
if (time > expiration_time) {
return std::unique_ptr<Parallel::Callback>(
new Parallel::PerformAlgorithmCallback(proxy));
}
}
return std::unique_ptr<Parallel::Callback>{};
});
/// \ingroup ComputationalDomainGroup
/// Check that functions of time are up-to-date.
///
/// Check that functions of time in \p CacheTag with names in \p
/// functions_to_check are ready at time \p time. If \p functions_to_check is
/// a `std::nullopt`, checks all functions in \p CacheTag. If any function is
/// ready, schedules a `Parallel::SimpleActionCallback` with the GlobalCache
/// which calls the simple action passed in as a template parameter. The `Args`
/// are moved into the callback.
template <typename CacheTag, typename SimpleAction, typename Metavariables,
typename ArrayIndex, typename Component, typename... Args>
bool functions_of_time_are_ready(
Parallel::GlobalCache<Metavariables>& cache, const ArrayIndex& array_index,
const Component* component_p, const double time,
const std::optional<std::unordered_set<std::string>>& functions_to_check,
Args... args) {
using ProxyType = std::decay_t<decltype(
::Parallel::get_parallel_component<Component>(cache)[array_index])>;
return detail::functions_of_time_are_ready_impl<
CacheTag,
Parallel::SimpleActionCallback<SimpleAction, ProxyType, Args...>>(
cache, array_index, component_p, time, functions_to_check,
std::move(args)...);
}

namespace Actions {
Expand Down
Loading

0 comments on commit 1f3c8da

Please sign in to comment.