Skip to content

Commit

Permalink
Add event ObserveAmrCriteria
Browse files Browse the repository at this point in the history
ObserveAmrCriteria can be used to monitor the decisions made by each
AMR criteria even when not adapting the grid.
  • Loading branch information
kidder committed Nov 11, 2024
1 parent 8e3634b commit 25b66d8
Show file tree
Hide file tree
Showing 4 changed files with 333 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/ParallelAlgorithms/Amr/Events/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ spectre_target_headers(
INCLUDE_DIRECTORY ${CMAKE_SOURCE_DIR}/src
HEADERS
Events.hpp
ObserveAmrCriteria.hpp
RefineMesh.hpp
)

Expand Down
149 changes: 149 additions & 0 deletions src/ParallelAlgorithms/Amr/Events/ObserveAmrCriteria.hpp
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
1 change: 1 addition & 0 deletions tests/Unit/ParallelAlgorithms/Amr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ set(LIBRARY_SOURCES
Criteria/Test_Persson.cpp
Criteria/Test_Random.cpp
Criteria/Test_TruncationError.cpp
Events/Test_ObserveAmrCriteria.cpp
Events/Test_RefineMesh.cpp
Policies/Test_EnforcePolicies.cpp
Policies/Test_Isotropy.cpp
Expand Down
182 changes: 182 additions & 0 deletions tests/Unit/ParallelAlgorithms/Amr/Events/Test_ObserveAmrCriteria.cpp
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

0 comments on commit 25b66d8

Please sign in to comment.