-
Notifications
You must be signed in to change notification settings - Fork 191
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ObserveAmrCriteria can be used to monitor the decisions made by each AMR criteria even when not adapting the grid.
- Loading branch information
Showing
4 changed files
with
333 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
149 changes: 149 additions & 0 deletions
149
src/ParallelAlgorithms/Amr/Events/ObserveAmrCriteria.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
// Distributed under the MIT License. | ||
// See LICENSE.txt for details. | ||
|
||
#pragma once | ||
|
||
#include <cstddef> | ||
#include <pup.h> | ||
#include <string> | ||
#include <vector> | ||
|
||
#include "DataStructures/DataBox/ObservationBox.hpp" | ||
#include "DataStructures/FloatingPointType.hpp" | ||
#include "DataStructures/Tensor/IndexType.hpp" | ||
#include "DataStructures/Tensor/Tensor.hpp" | ||
#include "DataStructures/Tensor/TypeAliases.hpp" | ||
#include "Domain/Amr/Flag.hpp" | ||
#include "IO/H5/TensorData.hpp" | ||
#include "Options/String.hpp" | ||
#include "ParallelAlgorithms/Amr/Criteria/Criterion.hpp" | ||
#include "ParallelAlgorithms/Amr/Criteria/Tags/Criteria.hpp" | ||
#include "ParallelAlgorithms/Events/ObserveConstantsPerElement.hpp" | ||
#include "ParallelAlgorithms/EventsAndTriggers/Event.hpp" | ||
#include "Utilities/Gsl.hpp" | ||
#include "Utilities/Serialization/CharmPupable.hpp" | ||
#include "Utilities/TMPL.hpp" | ||
|
||
/// \cond | ||
template <size_t VolumeDim> | ||
class Domain; | ||
template <size_t VolumeDim> | ||
class ElementId; | ||
namespace domain { | ||
namespace FunctionsOfTime { | ||
class FunctionOfTime; | ||
} // namespace FunctionsOfTime | ||
namespace Tags { | ||
template <size_t VolumeDim> | ||
struct Domain; | ||
struct FunctionsOfTime; | ||
} // namespace Tags | ||
} // namespace domain | ||
namespace Parallel { | ||
template <typename Metavariables> | ||
class GlobalCache; | ||
} // namespace Parallel | ||
namespace Tags { | ||
struct Time; | ||
struct TimeStep; | ||
} // namespace Tags | ||
/// \endcond | ||
|
||
namespace amr::Events { | ||
namespace detail { | ||
template <typename Criterion> | ||
struct get_compute_tags { | ||
using type = typename Criterion::compute_tags_for_observation_box; | ||
}; | ||
} // namespace detail | ||
|
||
/// \brief Observe the desired decisions of AMR criteria | ||
/// | ||
/// \details The event will return a vector of decisions (an independent choice | ||
/// in each logical dimension) for each of the AMR criteria. These are the raw | ||
/// choices made by each AMR critera, not taking into account any AMR policies. | ||
/// Each element is output as a single cell with two points per dimension and | ||
/// the observation constant on all those points. The decisions are converted | ||
/// to values as follows (in each logical dimension): | ||
/// - 1.0 is for join with sibling (if possible) | ||
/// - 2.0 is for decrease number of grid points | ||
/// - 3.0 is for no change | ||
/// - 4.0 is for increase number of grid points | ||
/// - 5.0 is for splitting the element | ||
template <typename Metavariables> | ||
class ObserveAmrCriteria | ||
: public dg::Events::ObserveConstantsPerElement<Metavariables::volume_dim> { | ||
public: | ||
static constexpr size_t volume_dim = Metavariables::volume_dim; | ||
/// \cond | ||
explicit ObserveAmrCriteria(CkMigrateMessage* m) | ||
: dg::Events::ObserveConstantsPerElement<volume_dim>(m) {} | ||
using PUP::able::register_constructor; | ||
WRAPPED_PUPable_decl_template(ObserveAmrCriteria); // NOLINT | ||
/// \endcond | ||
|
||
static constexpr Options::String help = | ||
"Observe the desired decisions of AMR criteria in the volume."; | ||
|
||
ObserveAmrCriteria() = default; | ||
|
||
ObserveAmrCriteria(const std::string& subfile_name, | ||
::FloatingPointType coordinates_floating_point_type, | ||
::FloatingPointType floating_point_type) | ||
: dg::Events::ObserveConstantsPerElement<volume_dim>( | ||
subfile_name, coordinates_floating_point_type, | ||
floating_point_type) {} | ||
|
||
using compute_tags_for_observation_box = | ||
tmpl::remove_duplicates<tmpl::flatten<tmpl::transform< | ||
tmpl::at<typename Metavariables::factory_creation::factory_classes, | ||
Criterion>, | ||
detail::get_compute_tags<tmpl::_1>>>>; | ||
|
||
using return_tags = tmpl::list<>; | ||
using argument_tags = tmpl::list<::Tags::ObservationBox>; | ||
|
||
template <typename DataBoxType, typename ComputeTagsList, | ||
typename ParallelComponent> | ||
void operator()(const ObservationBox<DataBoxType, ComputeTagsList>& box, | ||
Parallel::GlobalCache<Metavariables>& cache, | ||
const ElementId<Metavariables::volume_dim>& element_id, | ||
const ParallelComponent* const component, | ||
const Event::ObservationValue& observation_value) const { | ||
const auto& refinement_criteria = get<amr::Criteria::Tags::Criteria>(box); | ||
const double time = get<::Tags::Time>(box); | ||
const auto& functions_of_time = get<::domain::Tags::FunctionsOfTime>(box); | ||
const Domain<volume_dim>& domain = | ||
get<::domain::Tags::Domain<volume_dim>>(box); | ||
|
||
std::vector<TensorComponent> components = this->allocate_and_insert_coords( | ||
volume_dim * refinement_criteria.size(), time, functions_of_time, | ||
domain, element_id); | ||
|
||
for (const auto& criterion : refinement_criteria) { | ||
const auto decision = criterion->evaluate(box, cache, element_id); | ||
for (size_t d = 0; d < volume_dim; ++d) { | ||
this->add_constant( | ||
make_not_null(&components), | ||
criterion->observation_name() + | ||
tnsr::i<double, volume_dim, | ||
Frame::ElementLogical>::component_suffix(d), | ||
static_cast<double>(gsl::at(decision, d))); | ||
} | ||
} | ||
|
||
this->observe(components, cache, element_id, component, observation_value); | ||
} | ||
|
||
bool needs_evolved_variables() const override { return true; } | ||
|
||
void pup(PUP::er& p) override { | ||
dg::Events::ObserveConstantsPerElement<volume_dim>::pup(p); | ||
} | ||
}; | ||
|
||
/// \cond | ||
template <typename Metavariables> | ||
PUP::able::PUP_ID ObserveAmrCriteria<Metavariables>::my_PUP_ID = 0; // NOLINT | ||
/// \endcond | ||
} // namespace amr::Events |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
182 changes: 182 additions & 0 deletions
182
tests/Unit/ParallelAlgorithms/Amr/Events/Test_ObserveAmrCriteria.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
// Distributed under the MIT License. | ||
// See LICENSE.txt for details. | ||
|
||
#include "Framework/TestingFramework.hpp" | ||
|
||
#include <cstddef> | ||
|
||
#include "Domain/CoordinateMaps/CoordinateMap.hpp" | ||
#include "Domain/CoordinateMaps/CoordinateMap.tpp" | ||
#include "Domain/CoordinateMaps/Identity.hpp" | ||
#include "Domain/CoordinateMaps/TimeDependent/Translation.hpp" | ||
#include "Domain/Creators/Tags/Domain.hpp" | ||
#include "Domain/Domain.hpp" | ||
#include "Domain/FunctionsOfTime/FunctionOfTime.hpp" | ||
#include "Domain/FunctionsOfTime/PiecewisePolynomial.hpp" | ||
#include "Domain/FunctionsOfTime/Tags.hpp" | ||
#include "Domain/Structure/ElementId.hpp" | ||
#include "Domain/Structure/SegmentId.hpp" | ||
#include "Domain/Tags.hpp" | ||
#include "Framework/ActionTesting.hpp" | ||
#include "Framework/TestCreation.hpp" | ||
#include "Helpers/ParallelAlgorithms/Events/ObserveFields.hpp" | ||
#include "Options/Protocols/FactoryCreation.hpp" | ||
#include "ParallelAlgorithms/Amr/Criteria/DriveToTarget.hpp" | ||
#include "ParallelAlgorithms/Amr/Criteria/Tags/Criteria.hpp" | ||
#include "ParallelAlgorithms/Amr/Events/ObserveAmrCriteria.hpp" | ||
#include "ParallelAlgorithms/Amr/Policies/Isotropy.hpp" | ||
#include "ParallelAlgorithms/Amr/Policies/Limits.hpp" | ||
#include "ParallelAlgorithms/Amr/Policies/Policies.hpp" | ||
#include "ParallelAlgorithms/Amr/Policies/Tags.hpp" | ||
#include "ParallelAlgorithms/EventsAndTriggers/Event.hpp" | ||
#include "ParallelAlgorithms/EventsAndTriggers/EventsAndTriggers.hpp" | ||
#include "ParallelAlgorithms/EventsAndTriggers/LogicalTriggers.hpp" | ||
#include "ParallelAlgorithms/EventsAndTriggers/Trigger.hpp" | ||
#include "Time/Tags/Time.hpp" | ||
#include "Utilities/Literals.hpp" | ||
#include "Utilities/MakeArray.hpp" | ||
#include "Utilities/MakeVector.hpp" | ||
#include "Utilities/ProtocolHelpers.hpp" | ||
#include "Utilities/TMPL.hpp" | ||
|
||
namespace { | ||
namespace LocalTags { | ||
struct FunctionsOfTime : domain::Tags::FunctionsOfTime, db::SimpleTag { | ||
using type = domain::FunctionsOfTimeMap; | ||
}; | ||
} // namespace LocalTags | ||
|
||
struct Metavariables { | ||
static constexpr size_t volume_dim = 1; | ||
using component_list = tmpl::list< | ||
TestHelpers::dg::Events::ObserveFields::ElementComponent<Metavariables>, | ||
TestHelpers::dg::Events::ObserveFields::MockObserverComponent< | ||
Metavariables>>; | ||
|
||
struct factory_creation | ||
: tt::ConformsTo<Options::protocols::FactoryCreation> { | ||
using factory_classes = tmpl::map< | ||
tmpl::pair<amr::Criterion, tmpl::list<amr::Criteria::DriveToTarget<1>>>, | ||
tmpl::pair<Event, | ||
tmpl::list<amr::Events::ObserveAmrCriteria<Metavariables>>>>; | ||
}; | ||
}; | ||
|
||
void test() { | ||
std::vector<std::unique_ptr<amr::Criterion>> criteria; | ||
criteria.emplace_back(std::make_unique<amr::Criteria::DriveToTarget<1>>( | ||
std::array{4_st}, std::array{1_st}, std::array{amr::Flag::DoNothing})); | ||
criteria.emplace_back(std::make_unique<amr::Criteria::DriveToTarget<1>>( | ||
std::array{3_st}, std::array{1_st}, std::array{amr::Flag::DoNothing})); | ||
criteria.emplace_back(std::make_unique<amr::Criteria::DriveToTarget<1>>( | ||
std::array{5_st}, std::array{1_st}, std::array{amr::Flag::DoNothing})); | ||
criteria.emplace_back(std::make_unique<amr::Criteria::DriveToTarget<1>>( | ||
std::array{4_st}, std::array{0_st}, std::array{amr::Flag::DoNothing})); | ||
criteria.emplace_back(std::make_unique<amr::Criteria::DriveToTarget<1>>( | ||
std::array{4_st}, std::array{2_st}, std::array{amr::Flag::DoNothing})); | ||
const size_t number_of_criteria = criteria.size(); | ||
const std::vector<double> expected_values{3.0, 2.0, 4.0, 1.0, 5.0}; | ||
register_factory_classes_with_charm<Metavariables>(); | ||
using element_component = | ||
TestHelpers::dg::Events::ObserveFields::ElementComponent<Metavariables>; | ||
using observer_component = | ||
TestHelpers::dg::Events::ObserveFields::MockObserverComponent< | ||
Metavariables>; | ||
element_component* const element_component_p = nullptr; | ||
|
||
const ElementId<1> element_id(0, make_array<1>(SegmentId(1, 0))); | ||
const Mesh<1> mesh{4_st, Spectral::Basis::Legendre, | ||
Spectral::Quadrature::GaussLobatto}; | ||
|
||
using MockRuntimeSystem = ActionTesting::MockRuntimeSystem<Metavariables>; | ||
MockRuntimeSystem runner{{}}; | ||
ActionTesting::emplace_component<element_component>(make_not_null(&runner), | ||
element_id); | ||
ActionTesting::emplace_group_component<observer_component>(&runner); | ||
auto& cache = ActionTesting::cache<element_component>(runner, element_id); | ||
|
||
const auto event = | ||
TestHelpers::test_creation<std::unique_ptr<Event>, Metavariables>( | ||
"ObserveAmrCriteria:\n" | ||
" SubfileName: amr_criteria\n" | ||
" CoordinatesFloatingPointType: Double\n" | ||
" FloatingPointType: Float"); | ||
const double time = 3.0; | ||
Domain domain(make_vector( | ||
domain::make_coordinate_map_base<Frame::BlockLogical, Frame::Inertial>( | ||
domain::CoordinateMaps::Identity<1>{}))); | ||
domain.inject_time_dependent_map_for_block( | ||
0, domain::make_coordinate_map_base<Frame::Grid, Frame::Inertial>( | ||
domain::CoordinateMaps::TimeDependent::Translation<1>( | ||
"translation"))); | ||
|
||
domain::FunctionsOfTimeMap functions_of_time{}; | ||
functions_of_time.emplace( | ||
"translation", | ||
std::make_unique<domain::FunctionsOfTime::PiecewisePolynomial<1>>( | ||
1.0, std::array{DataVector(1, 2.0), DataVector(1, 5.0)}, 4.0)); | ||
const double expected_offset = 2.0 + (time - 1.0) * 5.0; | ||
|
||
auto box = db::create< | ||
db::AddSimpleTags<Parallel::Tags::MetavariablesImpl<Metavariables>, | ||
Tags::Time, LocalTags::FunctionsOfTime, | ||
domain::Tags::Domain<1>, domain::Tags::Mesh<1>, | ||
amr::Criteria::Tags::Criteria, amr::Tags::Policies>>( | ||
Metavariables{}, time, std::move(functions_of_time), std::move(domain), | ||
mesh, std::move(criteria), | ||
amr::Policies{amr::Isotropy::Anisotropic, amr::Limits{}, true}); | ||
|
||
const double observation_value = 1.23; | ||
|
||
auto observation_box = | ||
make_observation_box<typename amr::Events::ObserveAmrCriteria< | ||
Metavariables>::compute_tags_for_observation_box>( | ||
make_not_null(&box)); | ||
|
||
event->run(make_not_null(&observation_box), cache, element_id, | ||
element_component_p, {"value_name", observation_value}); | ||
|
||
runner.template invoke_queued_simple_action<observer_component>(0); | ||
CHECK(runner.template is_simple_action_queue_empty<observer_component>(0)); | ||
|
||
const auto& results = | ||
TestHelpers::dg::Events::ObserveFields::MockContributeVolumeData::results; | ||
CHECK(results.observation_id.value() == observation_value); | ||
CHECK(results.observation_id.observation_key().tag() == "/amr_criteria.vol"); | ||
CHECK(results.subfile_name == "/amr_criteria"); | ||
CHECK(results.array_component_id == | ||
Parallel::make_array_component_id<element_component>(element_id)); | ||
CHECK(results.received_volume_data.element_name == get_output(element_id)); | ||
CHECK(results.received_volume_data.extents == std::vector<size_t>(1, 2)); | ||
const auto& components = results.received_volume_data.tensor_components; | ||
REQUIRE(components.size() == 1 + number_of_criteria); | ||
for (const auto& component : components) { | ||
std::visit([](const auto& data) { CHECK(data.size() == 2); }, | ||
component.data); | ||
} | ||
CHECK(components[0].name == "InertialCoordinates_x"); | ||
std::visit( | ||
[&](const auto& data) { | ||
for (size_t i = 0; i < data.size(); ++i) { | ||
CHECK(data[i] == | ||
(i % 2 < 1 ? -1.0 + expected_offset : expected_offset)); | ||
} | ||
}, | ||
components[0].data); | ||
for (size_t i = 0; i < number_of_criteria; ++i) { | ||
CHECK(components[i + 1].name == "DriveToTarget_x"); | ||
std::visit( | ||
[&](const auto& data) { | ||
for (size_t j = 0; j < data.size(); ++j) { | ||
CHECK(data[j] == expected_values[i]); | ||
} | ||
}, | ||
components[i + 1].data); | ||
} | ||
} | ||
|
||
SPECTRE_TEST_CASE("Unit.ParallelAlgorithms.Amr.Events.ObserveAmrCriteria", | ||
"[Unit][ParallelAlgorithms]") { | ||
test(); | ||
} | ||
} // namespace |