Skip to content

Commit

Permalink
Add refinement criteria DriveToTargetAndOscillate
Browse files Browse the repository at this point in the history
This is useful for testing AMR actions.
  • Loading branch information
kidder committed Feb 2, 2023
1 parent 818c94c commit 5192648
Show file tree
Hide file tree
Showing 5 changed files with 338 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/ParallelAlgorithms/Amr/Criteria/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ add_spectre_library(${LIBRARY})
spectre_target_sources(
${LIBRARY}
PRIVATE
DriveToTargetAndOscillate.cpp
Random.cpp
)

Expand All @@ -17,6 +18,7 @@ spectre_target_headers(
HEADERS
Criteria.hpp
Criterion.hpp
DriveToTargetAndOscillate.hpp
Random.hpp
)

Expand All @@ -32,6 +34,7 @@ target_link_libraries(
DomainStructure
Options
Parallel
Spectral
Utilities
)

Expand Down
42 changes: 42 additions & 0 deletions src/ParallelAlgorithms/Amr/Criteria/DriveToTargetAndOscillate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#include "ParallelAlgorithms/Amr/Criteria/DriveToTargetAndOscillate.hpp"

#include <array>
#include <cstddef>
#include <pup.h>
#include <pup_stl.h>

#include "Domain/Amr/Flag.hpp"

namespace amr::Criteria {
template <size_t Dim>
DriveToTargetAndOscillate<Dim>::DriveToTargetAndOscillate(
const std::array<size_t, Dim>& target_resolution,
const std::array<size_t, Dim>& target_refinement_levels,
const std::array<domain::Flag, Dim>& flags_at_target)
: target_resolution_(target_resolution),
target_refinement_levels_(target_refinement_levels),
flags_at_target_(flags_at_target) {}

template <size_t Dim>
DriveToTargetAndOscillate<Dim>::DriveToTargetAndOscillate(CkMigrateMessage* msg)
: Criterion(msg) {}

// NOLINTNEXTLINE(google-runtime-references)
template <size_t Dim>
void DriveToTargetAndOscillate<Dim>::pup(PUP::er& p) {
Criterion::pup(p);
p | target_resolution_;
p | target_refinement_levels_;
p | flags_at_target_;
}

template <size_t Dim>
PUP::able::PUP_ID DriveToTargetAndOscillate<Dim>::my_PUP_ID = 0; // NOLINT

template class DriveToTargetAndOscillate<1>;
template class DriveToTargetAndOscillate<2>;
template class DriveToTargetAndOscillate<3>;
} // namespace amr::Criteria
122 changes: 122 additions & 0 deletions src/ParallelAlgorithms/Amr/Criteria/DriveToTargetAndOscillate.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#pragma once

#include <array>
#include <cstddef>
#include <pup.h>

#include "Domain/Amr/Flag.hpp"
#include "Domain/Structure/ElementId.hpp"
#include "Domain/Tags.hpp"
#include "NumericalAlgorithms/Spectral/Mesh.hpp"
#include "ParallelAlgorithms/Amr/Criteria/Criterion.hpp"
#include "Utilities/Gsl.hpp"
#include "Utilities/TMPL.hpp"

namespace amr::Criteria {
/*!
* \brief Refine the grid towards the target resolution and refinement levels in
* each dimension and then oscillate about the target.
*
* \details If the grid is at neither target in a given dimension, the
* flag chosen will be in the priority order Split,
* IncreaseResolution, DecreaseResolution, Join.
*
* \note This criterion is primarily for testing the mechanics of refinement.
*/
template <size_t Dim>
class DriveToTargetAndOscillate : public Criterion {
public:
/// The target resolution
struct TargetResolution {
using type = std::array<size_t, Dim>;
static constexpr Options::String help = {
"The target resolution in each dimension."};
};

/// The target resolution
struct TargetRefinementLevels {
using type = std::array<size_t, Dim>;
static constexpr Options::String help = {
"The target refinement levels in each dimension."};
};

/// The AMR flags chosen when the target resolution and refinement levels are
/// reached
struct DecisionAtTarget {
using type = std::array<domain::Flag, Dim>;
static constexpr Options::String help = {
"The flags returned when at the target."};
};

using options =
tmpl::list<TargetResolution, TargetRefinementLevels, DecisionAtTarget>;

static constexpr Options::String help = {
"Refine the grid towards the TargetResolution and "
"TargetRefinementLevels, and then oscillate about them by applying "
"DecisionAtTarget."};

DriveToTargetAndOscillate() = default;

explicit DriveToTargetAndOscillate(
const std::array<size_t, Dim>& target_resolution,
const std::array<size_t, Dim>& target_refinement_levels,
const std::array<domain::Flag, Dim>& flags_at_target);

/// \cond
explicit DriveToTargetAndOscillate(CkMigrateMessage* msg);
using PUP::able::register_constructor;
WRAPPED_PUPable_decl_template(DriveToTargetAndOscillate); // NOLINT
/// \endcond

using compute_tags_for_observation_box = tmpl::list<>;

using argument_tags = tmpl::list<::domain::Tags::Mesh<Dim>>;

template <typename ArrayIndex, typename Metavariables>
auto operator()(const Mesh<Dim>& current_mesh,
Parallel::GlobalCache<Metavariables>& /*cache*/,
const ArrayIndex& array_index) const;

void pup(PUP::er& p) override;

private:
std::array<size_t, Dim> target_resolution_{};
std::array<size_t, Dim> target_refinement_levels_{};
std::array<domain::Flag, Dim> flags_at_target_{};
};

template <size_t Dim>
template <typename ArrayIndex, typename Metavariables>
auto DriveToTargetAndOscillate<Dim>::operator()(
const Mesh<Dim>& current_mesh,
Parallel::GlobalCache<Metavariables>& /*cache*/,
const ArrayIndex& array_index) const {
auto result = make_array<Dim>(domain::Flag::DoNothing);
const std::array<size_t, Dim> levels = array_index.refinement_levels();
bool is_at_target = true;
for (size_t d = 0; d < Dim; ++d) {
if (gsl::at(levels, d) < gsl::at(target_refinement_levels_, d)) {
gsl::at(result, d) = domain::Flag::Split;
is_at_target = false;
} else if (current_mesh.extents(d) < gsl::at(target_resolution_, d)) {
gsl::at(result, d) = domain::Flag::IncreaseResolution;
is_at_target = false;
} else if (current_mesh.extents(d) > gsl::at(target_resolution_, d)) {
gsl::at(result, d) = domain::Flag::DecreaseResolution;
is_at_target = false;
} else if (gsl::at(levels, d) > gsl::at(target_refinement_levels_, d)) {
gsl::at(result, d) = domain::Flag::Join;
is_at_target = false;
}
}
if (is_at_target) {
return flags_at_target_;
}

return result;
}
} // namespace amr::Criteria
1 change: 1 addition & 0 deletions tests/Unit/ParallelAlgorithms/Amr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(LIBRARY_SOURCES
Actions/Test_EvaluateRefinementCriteria.cpp
Actions/Test_Initialize.cpp
Actions/Test_UpdateAmrDecision.cpp
Criteria/Test_DriveToTargetAndOscillate.cpp
Criteria/Test_Random.cpp
Projectors/Test_Mesh.cpp
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#include "Framework/TestingFramework.hpp"

#include <cstddef>
#include <memory>

#include "DataStructures/DataBox/DataBox.hpp"
#include "DataStructures/DataBox/ObservationBox.hpp"
#include "Domain/Amr/Flag.hpp"
#include "Domain/Structure/ElementId.hpp"
#include "Domain/Structure/SegmentId.hpp"
#include "Framework/TestCreation.hpp"
#include "Framework/TestHelpers.hpp"
#include "Helpers/DataStructures/DataBox/TestHelpers.hpp"
#include "Options/Protocols/FactoryCreation.hpp"
#include "Parallel/GlobalCache.hpp"
#include "Parallel/RegisterDerivedClassesWithCharm.hpp"
#include "ParallelAlgorithms/Amr/Criteria/Criterion.hpp"
#include "ParallelAlgorithms/Amr/Criteria/DriveToTargetAndOscillate.hpp"
#include "ParallelAlgorithms/Amr/Criteria/Tags/Criteria.hpp"
#include "Utilities/MakeArray.hpp"
#include "Utilities/TMPL.hpp"

namespace {
template <size_t VolumeDim>
struct Metavariables {
static constexpr size_t volume_dim = VolumeDim;
using component_list = tmpl::list<>;
using const_global_cache_tags = tmpl::list<>;
struct factory_creation
: tt::ConformsTo<Options::protocols::FactoryCreation> {
using factory_classes = tmpl::map<tmpl::pair<
amr::Criterion,
tmpl::list<amr::Criteria::DriveToTargetAndOscillate<VolumeDim>>>>;
};
};
struct TestComponent {};

template <size_t VolumeDim>
void test_criterion(
const amr::Criterion& criterion,
const std::array<size_t, VolumeDim> mesh_extents,
const std::array<size_t, VolumeDim>& element_refinement_levels,
const std::array<amr::domain::Flag, VolumeDim>& expected_flags) {
Parallel::GlobalCache<Metavariables<VolumeDim>> empty_cache{};
const auto databox = db::create<tmpl::list<::domain::Tags::Mesh<VolumeDim>>>(
Mesh<VolumeDim>{mesh_extents, Spectral::Basis::Legendre,
Spectral::Quadrature::GaussLobatto});
ObservationBox<tmpl::list<>,
db::DataBox<tmpl::list<::domain::Tags::Mesh<VolumeDim>>>>
box{databox};

std::array<SegmentId, VolumeDim> segment_ids;
alg::transform(element_refinement_levels, segment_ids.begin(),
[](const size_t extent) {
return SegmentId{extent, 0_st};
});
ElementId<VolumeDim> element_id{0, segment_ids};
auto flags = criterion.evaluate(box, empty_cache, element_id);
CHECK(flags == expected_flags);
}

template <size_t VolumeDim>
void test(
const std::array<size_t, VolumeDim>& target_extents,
const std::array<size_t, VolumeDim>& target_levels,
const std::array<amr::domain::Flag, VolumeDim>& flags_at_target,
const std::vector<
std::tuple<std::array<size_t, VolumeDim>, std::array<size_t, VolumeDim>,
std::array<amr::domain::Flag, VolumeDim>>>& test_cases,
const std::string& option_string) {
Parallel::register_factory_classes_with_charm<Metavariables<VolumeDim>>();

const amr::Criteria::DriveToTargetAndOscillate criterion{
target_extents, target_levels, flags_at_target};
const auto criterion_from_option_string =
TestHelpers::test_creation<std::unique_ptr<amr::Criterion>,
Metavariables<VolumeDim>>(option_string);
for (const auto& [extents, levels, expected_flags] : test_cases) {
test_criterion(criterion, extents, levels, expected_flags);
test_criterion(*criterion_from_option_string, extents, levels,
expected_flags);
test_criterion(*serialize_and_deserialize(criterion_from_option_string),
extents, levels, expected_flags);
}
}
} // namespace

SPECTRE_TEST_CASE("Unit.Amr.Criteria.DriveToTargetAndOscillate",
"[Unit][ParallelAlgorithms]") {
const std::array target_extents_1d{4_st};
const std::array target_levels_1d{3_st};
const std::array flags_at_target_1d{amr::domain::Flag::Join};
const auto test_cases_1d = std::vector{
std::tuple{std::array{4_st}, std::array{3_st},
std::array{amr::domain::Flag::Join}},
std::tuple{std::array{3_st}, std::array{3_st},
std::array{amr::domain::Flag::IncreaseResolution}},
std::tuple{std::array{5_st}, std::array{3_st},
std::array{amr::domain::Flag::DecreaseResolution}},
std::tuple{std::array{4_st}, std::array{2_st},
std::array{amr::domain::Flag::Split}},
std::tuple{std::array{3_st}, std::array{2_st},
std::array{amr::domain::Flag::Split}},
std::tuple{std::array{5_st}, std::array{2_st},
std::array{amr::domain::Flag::Split}},
std::tuple{std::array{4_st}, std::array{4_st},
std::array{amr::domain::Flag::Join}},
std::tuple{std::array{3_st}, std::array{4_st},
std::array{amr::domain::Flag::IncreaseResolution}},
std::tuple{std::array{5_st}, std::array{4_st},
std::array{amr::domain::Flag::DecreaseResolution}}};
const std::string option_1d =
"DriveToTargetAndOscillate:\n"
" TargetResolution: [4]\n"
" TargetRefinementLevels: [3]\n"
" DecisionAtTarget: [Join]\n";
test(target_extents_1d, target_levels_1d, flags_at_target_1d, test_cases_1d,
option_1d);
const std::array target_extents_2d{4_st, 6_st};
const std::array target_levels_2d{8_st, 3_st};
const std::array flags_at_target_2d{amr::domain::Flag::IncreaseResolution,
amr::domain::Flag::Split};
const auto test_cases_2d = std::vector{
std::tuple{std::array{4_st, 6_st}, std::array{8_st, 3_st},
std::array{amr::domain::Flag::IncreaseResolution,
amr::domain::Flag::Split}},
std::tuple{std::array{5_st, 6_st}, std::array{8_st, 3_st},
std::array{amr::domain::Flag::DecreaseResolution,
amr::domain::Flag::DoNothing}},
std::tuple{std::array{3_st, 6_st}, std::array{7_st, 4_st},
std::array{amr::domain::Flag::Split, amr::domain::Flag::Join}},
std::tuple{
std::array{4_st, 6_st}, std::array{8_st, 2_st},
std::array{amr::domain::Flag::DoNothing, amr::domain::Flag::Split}}};
const std::string option_2d =
"DriveToTargetAndOscillate:\n"
" TargetResolution: [4, 6]\n"
" TargetRefinementLevels: [8, 3]\n"
" DecisionAtTarget: [IncreaseResolution, Split]\n";
test(target_extents_2d, target_levels_2d, flags_at_target_2d, test_cases_2d,
option_2d);
const std::array target_extents_3d{3_st, 9_st, 5_st};
const std::array target_levels_3d{5_st, 2_st, 4_st};
const std::array flags_at_target_3d{amr::domain::Flag::Split,
amr::domain::Flag::DecreaseResolution,
amr::domain::Flag::DoNothing};
const auto test_cases_3d = std::vector{
std::tuple{std::array{3_st, 9_st, 5_st}, std::array{5_st, 2_st, 4_st},
std::array{amr::domain::Flag::Split,
amr::domain::Flag::DecreaseResolution,
amr::domain::Flag::DoNothing}},
std::tuple{
std::array{3_st, 9_st, 5_st}, std::array{5_st, 5_st, 4_st},
std::array{amr::domain::Flag::DoNothing, amr::domain::Flag::Join,
amr::domain::Flag::DoNothing}},
std::tuple{
std::array{3_st, 9_st, 3_st}, std::array{5_st, 2_st, 4_st},
std::array{amr::domain::Flag::DoNothing, amr::domain::Flag::DoNothing,
amr::domain::Flag::IncreaseResolution}}};
const std::string option_3d =
"DriveToTargetAndOscillate:\n"
" TargetResolution: [3, 9, 5]\n"
" TargetRefinementLevels: [5, 2, 4]\n"
" DecisionAtTarget: [Split, DecreaseResolution, DoNothing]\n";
test(target_extents_3d, target_levels_3d, flags_at_target_3d, test_cases_3d,
option_3d);
}

0 comments on commit 5192648

Please sign in to comment.