MergeIntoDataBox.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
8 #include "Parallel/Printf.hpp"
9 #include "Utilities/Gsl.hpp"
10 #include "Utilities/Overloader.hpp"
11 #include "Utilities/PrettyType.hpp"
12 #include "Utilities/Requires.hpp"
13 #include "Utilities/TMPL.hpp"
15 #include "Utilities/TypeTraits.hpp"
16 
17 namespace Initialization {
18 /// The merge policy for resolving conflicts in `merge_into_databox` when adding
19 /// simple tags that already exist.
20 enum class MergePolicy {
21  /// Overwrite the existing simple tags
22  Overwrite,
23  /// Cause an error if a simple tag is already in the DataBox.
24  Error,
25  /// Cause an error if a simple tag is in the DataBox but does not compare
26  /// equal to the new value being added. Ignores types that do not have an
27  /// equivalence operator.
28  IgnoreIncomparable
29 };
30 
31 namespace detail {
32 template <typename AddingAction, typename SimpleTag, MergePolicy Policy,
33  typename DbTagsList,
35 void merge_simple_tag_value(
37  db::item_type<SimpleTag>&& simple_tag_value) noexcept {
38  db::mutate<SimpleTag>(
39  box,
40  [](const gsl::not_null<db::item_type<SimpleTag>*> stored_simple_tag_value,
41  db::item_type<SimpleTag>&& local_simple_tag_value) noexcept {
42  *stored_simple_tag_value = std::move(local_simple_tag_value);
43  },
44  std::move(simple_tag_value));
45 }
46 
47 template <typename AddingAction, typename SimpleTag, MergePolicy Policy,
48  typename DbTagsList,
49  Requires<(Policy == MergePolicy::Error or
50  Policy == MergePolicy::IgnoreIncomparable) and
52 void merge_simple_tag_value(const gsl::not_null<db::DataBox<DbTagsList>*> box,
53  db::item_type<SimpleTag>&& simple_tag) noexcept {
54  if (db::get<SimpleTag>(*box) != simple_tag) {
55  ERROR("While adding the simple tag "
56  << db::tag_name<SimpleTag>()
57  << " that is already in the DataBox we found that the value being "
58  "set by the action "
59  << pretty_type::get_name<AddingAction>()
60  << " is not the same as what is already in the DataBox. The "
61  "value in the DataBox is: "
62  << db::get<SimpleTag>(*box) << " while the value being added is "
63  << simple_tag);
64  }
65 }
66 
67 template <
68  typename AddingAction, typename SimpleTag, MergePolicy Policy,
69  typename DbTagsList,
70  Requires<(Policy == MergePolicy::Error or
71  Policy == MergePolicy::IgnoreIncomparable) and
73 void merge_simple_tag_value(
74  const gsl::not_null<db::DataBox<DbTagsList>*> /*box*/,
75  db::item_type<SimpleTag>&& /*simple_tag*/) noexcept {
76  static_assert(Policy != MergePolicy::Error,
77  "The tag being added does not have an equivalence operator and "
78  "is already in the DataBox. See the first template parameter "
79  "of the 'merge_simple_tag_value' function in the error message "
80  "for the action trying to re-add the simple tag and the second "
81  "template parameter for the simple tag being added.");
82 }
83 
84 template <typename AddingAction, typename ComputeTagsList, MergePolicy Policy,
85  typename... SimpleTags, typename DbTagsList,
86  typename... SimpleTagsToAdd, typename... SimpleTagsToCheck>
87 auto merge_into_databox_impl(
90  tmpl::list<SimpleTagsToAdd...> /*meta*/,
91  tmpl::list<SimpleTagsToCheck...> /*meta*/) noexcept {
93  merge_simple_tag_value<AddingAction, SimpleTagsToCheck, Policy>(
94  make_not_null(&box),
95  std::move(tuples::get<SimpleTagsToCheck>(simple_tags))));
96 
97  // Only add compute tags that are not in the DataBox.
98  using compute_tags_to_add = tmpl::remove_if<
99  ComputeTagsList,
100  tmpl::bind<tmpl::list_contains,
101  tmpl::pin<typename db::DataBox<DbTagsList>::compute_item_tags>,
102  tmpl::_1>>;
103 
104  return db::create_from<db::RemoveTags<>,
105  db::AddSimpleTags<SimpleTagsToAdd...>,
106  compute_tags_to_add>(
107  std::move(box), std::move(tuples::get<SimpleTagsToAdd>(simple_tags))...);
108 }
109 } // namespace detail
110 
111 /*!
112  * \ingroup InitializationGroup
113  * \brief Add tags that are not yet in the DataBox.
114  *
115  * How duplicate tags are handled depends on the `MergePolicy` passed. The
116  * default merge policy is to error if the simple tag being added does not have
117  * an equivalence operator and is being added again.
118  * `MergePolicy::IgnoreIncomparable` means that nothing is done if the simple
119  * tag being added does not have an equivalence operator. Tags that have an
120  * equivalence operator are check that the value being added and that is already
121  * in the DataBox are the same. If they aren't, an error occurs. Finally,
122  * `MergePolicy::Overwrite` means the current simple tag in the DataBox is
123  * overwritten with the new value passed in.
124  *
125  * Compute tags that are not in the DataBox are added, ones that are in the
126  * DataBox already are ignored.
127  */
128 template <typename AddingAction, typename SimpleTagsList,
129  typename ComputeTagsList = tmpl::list<>,
130  MergePolicy Policy = MergePolicy::Error, typename... SimpleTags,
131  typename DbTagsList, typename... Args>
133  Args&&... args) noexcept {
134  using simple_tags_to_check = tmpl::filter<
135  SimpleTagsList,
136  tmpl::bind<tmpl::list_contains,
137  tmpl::pin<typename db::DataBox<DbTagsList>::simple_item_tags>,
138  tmpl::_1>>;
139  using simple_tags_to_add =
140  tmpl::remove_if<SimpleTagsList,
141  tmpl::bind<tmpl::list_contains,
142  tmpl::pin<simple_tags_to_check>, tmpl::_1>>;
143  return detail::merge_into_databox_impl<AddingAction, ComputeTagsList, Policy>(
144  std::move(box),
145  tuples::tagged_tuple_from_typelist<SimpleTagsList>{
146  std::forward<Args>(args)...},
147  simple_tags_to_add{}, simple_tags_to_check{});
148 }
149 } // namespace Initialization
Defines class tuples::TaggedTuple.
#define ERROR(m)
prints an error message to the standard error stream and aborts the program.
Definition: Error.hpp:36
Definition: ConservativeSystem.hpp:34
#define EXPAND_PACK_LEFT_TO_RIGHT(...)
Expand a parameter pack evaluating the terms from left to right.
Definition: TMPL.hpp:562
Defines the type alias Requires.
auto merge_into_databox(db::DataBox< DbTagsList > &&box, Args &&... args) noexcept
Add tags that are not yet in the DataBox.
Definition: MergeIntoDataBox.hpp:132
Definition: Determinant.hpp:11
An associative container that is indexed by structs.
Definition: TaggedTuple.hpp:273
Defines classes and functions used for manipulating DataBox&#39;s.
tmpl::flatten< tmpl::list< Tags... > > AddSimpleTags
List of Tags to add to the DataBox.
Definition: DataBox.hpp:1222
constexpr bool has_inequivalence_v
Definition: TypeTraits.hpp:779
Defines Parallel::printf for writing to stdout.
Definition: InterpolationTargetWedgeSectionTorus.hpp:24
Contains a pretty_type library to write types in a "pretty" format.
Wraps the template metaprogramming library used (brigand)
typename DataBox_detail::item_type_impl< TagList, Tag >::type item_type
Get the type that can be written to the Tag. If it is a base tag then a TagList must be passed as a s...
Definition: DataBoxTag.hpp:461
Defines functions and classes from the GSL.
gsl::not_null< T * > make_not_null(T *ptr) noexcept
Construct a not_null from a pointer. Often this will be done as an implicit conversion, but it may be necessary to perform the conversion explicitly when type deduction is desired.
Definition: Gsl.hpp:879
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t ...
Definition: Requires.hpp:67
Defines macro ERROR.
Defines type traits, some of which are future STL type_traits header.
Require a pointer to not be a nullptr
Definition: ConservativeFromPrimitive.hpp:12