Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve documentation for amr::Criterion #4707

Merged
merged 2 commits into from
Feb 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,11 @@ namespace amr::Actions {
/// - Sends the (possibly updated) decision to all of the neighboring Elements
struct EvaluateRefinementCriteria {
template <typename ParallelComponent, typename DbTagList,
typename Metavariables, typename ArrayIndex>
typename Metavariables>
static void apply(db::DataBox<DbTagList>& box,
Parallel::GlobalCache<Metavariables>& cache,
const ArrayIndex& array_index) {
const ElementId<Metavariables::volume_dim>& element_id) {
constexpr size_t volume_dim = Metavariables::volume_dim;
ElementId<volume_dim> element_id{array_index};
auto overall_decision =
make_array<volume_dim>(amr::domain::Flag::Undefined);

Expand All @@ -95,7 +94,7 @@ struct EvaluateRefinementCriteria {
const auto& refinement_criteria =
db::get<amr::Criteria::Tags::Criteria>(box);
for (const auto& criterion : refinement_criteria) {
auto decision = criterion->evaluate(observation_box, cache, array_index);
auto decision = criterion->evaluate(observation_box, cache, element_id);
for (size_t d = 0; d < volume_dim; ++d) {
overall_decision[d] = std::max(overall_decision[d], decision[d]);
}
Expand Down
4 changes: 2 additions & 2 deletions src/ParallelAlgorithms/Amr/Actions/UpdateAmrDecision.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ namespace amr::Actions {
///
struct UpdateAmrDecision {
template <typename ParallelComponent, typename DbTagList,
typename Metavariables, typename ArrayIndex>
typename Metavariables>
static void apply(
db::DataBox<DbTagList>& box, Parallel::GlobalCache<Metavariables>& cache,
const ArrayIndex& /*array_index*/,
const ElementId<Metavariables::volume_dim>& /*element_id*/,
const ElementId<Metavariables::volume_dim>& neighbor_id,
const std::array<amr::domain::Flag, Metavariables::volume_dim>&
neighbor_amr_flags) {
Expand Down
40 changes: 33 additions & 7 deletions src/ParallelAlgorithms/Amr/Criteria/Criterion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "DataStructures/DataBox/ObservationBox.hpp"
#include "Domain/Amr/Flag.hpp"
#include "Domain/Structure/ElementId.hpp"
#include "Parallel/CharmPupable.hpp"
#include "Parallel/GlobalCache.hpp"
#include "Parallel/Tags/Metavariables.hpp"
Expand All @@ -20,9 +21,23 @@ namespace amr {
/// \brief Base class for something that determines how an adaptive mesh should
/// be changed
///
/// \details When AMR criteria are evaluated for each element, they should
/// return a std::array<amr::domain::Flag, Dim> containing the recommended
/// refinement choice in each logical dimension of the Element.
/// \details Each class derived from this class should (see the examples below):
/// - Be option-creatable
/// - Be serializable
/// - Define a call operator that returns a std::array<amr::domain::Flag, Dim>
/// containing the recommended refinement choice in each logical dimension of
/// the Element.
/// - Define the type aliases `argument_tags` and
/// `compute_tags_for_observation_box` that are type lists of tags used in the
/// call operator.
/// The call operator should take as arguments the values corresponding to each
/// tag in `argument_tags` (in order), followed by the Parallel::GlobalCache,
/// and the ElementId. The tags listed in `argument_tags` should either be tags
/// in the DataBox of the array component, or listed in
/// `compute_tags_for_observation_box`.
///
/// \example
/// \snippet Test_Criterion.cpp criterion_examples
class Criterion : public PUP::able {
protected:
/// \cond
Expand All @@ -39,18 +54,29 @@ class Criterion : public PUP::able {

WRAPPED_PUPable_abstract(Criterion); // NOLINT

/// Evaluates the AMR criteria by selecting the appropriate derived class
/// and forwarding its `argument_tags` from the ObservationBox (along with the
/// GlobalCache and ArrayIndex) to the call operator of the derived class
///
/// \note In order to be available, a derived Criterion must be listed in
/// the entry for Criterion in
/// Metavarialbes::factory_creation::factory_classes
///
/// \note The ComputeTagsList of the ObservationBox should contain the union
/// of the tags listed in `compute_tags_for_observation_box` for each derived
/// Criterion listed in the `factory_classes`.
template <typename ComputeTagsList, typename DataBoxType,
typename Metavariables, typename ArrayIndex>
typename Metavariables>
auto evaluate(const ObservationBox<ComputeTagsList, DataBoxType>& box,
Parallel::GlobalCache<Metavariables>& cache,
const ArrayIndex& array_index) const {
const ElementId<Metavariables::volume_dim>& element_id) const {
using factory_classes =
typename std::decay_t<Metavariables>::factory_creation::factory_classes;
return call_with_dynamic_type<
std::array<amr::domain::Flag, Metavariables::volume_dim>,
tmpl::at<factory_classes, Criterion>>(
this, [&box, &cache, &array_index](auto* const criterion) {
return apply(*criterion, box, cache, array_index);
this, [&box, &cache, &element_id](auto* const criterion) {
return apply(*criterion, box, cache, element_id);
});
}
};
Expand Down
12 changes: 6 additions & 6 deletions src/ParallelAlgorithms/Amr/Criteria/Random.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ class Random : public Criterion {

using argument_tags = tmpl::list<>;

template <typename ArrayIndex, typename Metavariables>
template <typename Metavariables>
auto operator()(Parallel::GlobalCache<Metavariables>& /*cache*/,
const ArrayIndex& array_index) const;
const ElementId<Metavariables::volume_dim>& element_id) const;

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

Expand All @@ -83,12 +83,12 @@ class Random : public Criterion {
size_t maximum_refinement_level_{0};
};

template <typename ArrayIndex, typename Metavariables>
auto Random::operator()(Parallel::GlobalCache<Metavariables>& /*cache*/,
const ArrayIndex& array_index) const {
template <typename Metavariables>
auto Random::operator()(
Parallel::GlobalCache<Metavariables>& /*cache*/,
const ElementId<Metavariables::volume_dim>& element_id) const {
constexpr size_t volume_dim = Metavariables::volume_dim;
auto result = make_array<volume_dim>(amr::domain::Flag::Undefined);
const ElementId<volume_dim> element_id{array_index};
for (size_t d = 0; d < volume_dim; ++d) {
result[d] = random_flag(element_id.segment_ids()[d].refinement_level());
}
Expand Down
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_Criterion.cpp
Criteria/Test_DriveToTarget.cpp
Criteria/Test_Random.cpp
Projectors/Test_Mesh.cpp
Expand Down
196 changes: 196 additions & 0 deletions tests/Unit/ParallelAlgorithms/Amr/Criteria/Test_Criterion.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#include "Framework/TestingFramework.hpp"

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

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

namespace {
// [criterion_examples]
struct FieldOne : db::SimpleTag {
using type = double;
};

struct FieldTwo : db::SimpleTag {
using type = double;
};

struct Constraint : db::SimpleTag {
using type = double;
};

struct ConstraintCompute : db::ComputeTag, Constraint {
using base = Constraint;
using return_type = double;
using argument_tags = tmpl::list<FieldOne, FieldTwo>;
static void function(const gsl::not_null<double*> result,
const double field_one, const double field_two) {
*result = field_one - field_two;
}
};

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
class CriterionOne : public amr::Criterion {
public:
struct CriticalValue {
using type = double;
static constexpr Options::String help = {
"The critical value of field one ."};
};
using options = tmpl::list<CriticalValue>;

static constexpr Options::String help = {
"h-refine the grid if field one is above a critical value"};

CriterionOne() = default;
explicit CriterionOne(const double critical_value)
: critical_value_(critical_value) {}
explicit CriterionOne(CkMigrateMessage* msg) : Criterion(msg) {}
using PUP::able::register_constructor;
WRAPPED_PUPable_decl_template(CriterionOne); // NOLINT

using compute_tags_for_observartion_box = tmpl::list<>;
using argument_tags = tmpl::list<FieldOne>;

template <typename Metavariables>
auto operator()(
const double field_one, Parallel::GlobalCache<Metavariables>& /*cache*/,
const ElementId<Metavariables::volume_dim>& /*element_id*/) const {
return field_one > critical_value_
? std::array{amr::domain::Flag::Split}
: std::array{amr::domain::Flag::DoNothing};
}

void pup(PUP::er& p) override {
Criterion::pup(p);
p | critical_value_;
}

private:
double critical_value_{0.0};
};

PUP::able::PUP_ID CriterionOne::my_PUP_ID = 0; // NOLINT

class CriterionTwo : public amr::Criterion {
public:
struct TargetValue {
using type = double;
static constexpr Options::String help = {"The target value."};
};
using options = tmpl::list<TargetValue>;

static constexpr Options::String help = {
"h-refine if the absolute value of the constraint is above the target "
"value. h-coarsen if the constraint is an order of magnitude below the "
"target value"};

CriterionTwo() = default;
explicit CriterionTwo(const double target_value)
: target_value_(target_value) {}
explicit CriterionTwo(CkMigrateMessage* /*msg*/) {}
using PUP::able::register_constructor;
WRAPPED_PUPable_decl_template(CriterionTwo); // NOLINT

using compute_tags_for_observartion_box = tmpl::list<ConstraintCompute>;
using argument_tags = tmpl::list<Constraint>;

template <typename Metavariables>
auto operator()(
const double constraint, Parallel::GlobalCache<Metavariables>& /*cache*/,
const ElementId<Metavariables::volume_dim>& /*element_id*/) const {
return std::abs(constraint) > target_value_
? std::array{amr::domain::Flag::Split}
: (std::abs(constraint) < 0.1 * target_value_
? std::array{amr::domain::Flag::Join}
: std::array{amr::domain::Flag::DoNothing});
}

void pup(PUP::er& p) override {
Criterion::pup(p);
p | target_value_;
}

private:
double target_value_{0.0};
};

PUP::able::PUP_ID CriterionTwo::my_PUP_ID = 0; // NOLINT
#pragma GCC diagnostic pop

struct Metavariables {
static constexpr size_t volume_dim = 1;
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<CriterionOne, CriterionTwo>>>;
};
};
// [criterion_examples]

void test_criterion(const amr::Criterion& criterion, const double field_one,
const double field_two,
const amr::domain::Flag expected_flag) {
Parallel::GlobalCache<Metavariables> empty_cache{};
using simple_tags = tmpl::list<FieldOne, FieldTwo>;
const auto databox = db::create<simple_tags>(field_one, field_two);
// This list is the union of all compute_tags_for_observation_box for all
// criteria listed in Metavariables::factory_creation::factory_classes
// It can be constructed with a metafunction, but for this simple test
// we just explicitly list them
using compute_tags = tmpl::list<ConstraintCompute>;
ObservationBox<compute_tags, db::DataBox<simple_tags>> box{databox};
ElementId<1> element_id{0};
auto flags = criterion.evaluate(box, empty_cache, element_id);
CHECK(flags == std::array{expected_flag});
}

void test() {
Parallel::register_factory_classes_with_charm<Metavariables>();
const CriterionOne one{1.0};
test_criterion(one, 2.0, 0.0, amr::domain::Flag::Split);

test_criterion(serialize_and_deserialize(one), 0.5, 0.0,
amr::domain::Flag::DoNothing);
const auto one_option =
TestHelpers::test_creation<std::unique_ptr<amr::Criterion>,
Metavariables>(
"CriterionOne:\n"
" CriticalValue: 3.0\n");
test_criterion(*one_option, 2.0, 0.0, amr::domain::Flag::DoNothing);
test_criterion(*serialize_and_deserialize(one_option), 2.0, 0.0,
amr::domain::Flag::DoNothing);
const CriterionTwo two{1.e-6};
test_criterion(two, 4.e-6, 6.e-6, amr::domain::Flag::Split);
test_criterion(serialize_and_deserialize(two), 4.e-6, 4.5e-6,
amr::domain::Flag::DoNothing);
const auto two_option =
TestHelpers::test_creation<std::unique_ptr<amr::Criterion>,
Metavariables>(
"CriterionTwo:\n"
" TargetValue: 1.e-5\n");
test_criterion(*two_option, 4.e-7, 3.e-7, amr::domain::Flag::Join);
}
} // namespace

SPECTRE_TEST_CASE("Unit.Amr.Criteria.Criterion", "[Unit][ParallelAlgorithms]") {
test();
}