Skip to content

Commit

Permalink
Merge pull request #4707 from kidder/amr_criterion_docs
Browse files Browse the repository at this point in the history
Improve documentation for amr::Criterion
  • Loading branch information
nilsvu committed Feb 8, 2023
2 parents 56726fa + 39ae07b commit 2a84e89
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 19 deletions.
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();
}

0 comments on commit 2a84e89

Please sign in to comment.