SpECTRE  v2024.02.05
DataBox

Documentation, functions, metafunctions, and classes necessary for using DataBox. More...

Namespaces

namespace  db
 Namespace for DataBox related things.
 

Classes

class  db::DataBox< tmpl::list< Tags... > >
 A DataBox stores objects that can be retrieved by using Tags. More...
 
struct  db::Subitems< Tag, typename >
 Struct that can be specialized to allow DataBox items to have subitems. Specializations must define: More...
 
struct  db::SimpleTag
 Mark a struct as a simple tag by inheriting from this. More...
 
struct  db::BaseTag
 Mark a (usually) empty struct as a base tag by inheriting from this. More...
 
struct  db::PrefixTag
 Mark a struct as a prefix tag by inheriting from this. More...
 
struct  db::ComputeTag
 Mark a struct as a compute tag by inheriting from this. More...
 
struct  db::ReferenceTag
 Mark a struct as a reference tag by inheriting from this. More...
 
struct  db::is_compute_tag< Tag >
 Check if Tag derives off of db::ComputeTag. More...
 
struct  db::is_reference_tag< Tag >
 Check if Tag derives off of db::ReferenceTag. More...
 
struct  db::is_immutable_item_tag< Tag >
 Check if Tag is a DataBox tag for an immutable item, i.e. a ComputeTag or ReferenceTag. More...
 
struct  db::is_mutable_item_tag< Tag >
 Check if Tag is a DataBox tag for a mutable item, i.e. a SimpleTag. More...
 
struct  db::is_simple_tag< Tag >
 Check if Tag is a simple tag. More...
 
struct  db::is_non_base_tag< Tag >
 Check if Tag is not a base tag. More...
 
struct  db::is_tag< Tag >
 Check if Tag is a DataBox tag, i.e. a BaseTag, SimpleTag, ComputeTag, or ReferenceTag. More...
 
struct  db::is_base_tag< Tag >
 Check if Tag is a base DataBox tag. More...
 

Typedefs

template<typename Tag , typename Box >
using db::creation_tag = typename detail::creation_tag_impl< typename Box::tags_list, Tag >::type
 The tag added to Box referred to by Tag. This resolves base tags and converts subitems to full items.
 
template<typename... Tags>
using db::AddSimpleTags = tmpl::flatten< tmpl::list< Tags... > >
 List of Tags to add to the DataBox.
 
template<typename... Tags>
using db::AddComputeTags = tmpl::flatten< tmpl::list< Tags... > >
 List of Compute Item Tags to add to the DataBox.
 
template<typename TagList >
using db::compute_databox_type = typename detail::compute_dbox_type< TagList >::type
 Returns the type of the DataBox that would be constructed from the TagList of tags.
 

Functions

template<typename... MutateTags, typename TagList , typename Invokable , typename... Args>
decltype(auto) db::mutate (Invokable &&invokable, const gsl::not_null< DataBox< TagList > * > box, Args &&... args)
 Allows changing the state of one or more non-computed elements in the DataBox. More...
 
template<typename Tag , typename TagList >
const auto & db::get (const DataBox< TagList > &box)
 Retrieve the item with tag Tag from the DataBox. More...
 
template<typename CopiedItemsTagList , typename DbTagList >
auto db::copy_items (const DataBox< DbTagList > &box)
 Copy the items from the DataBox into a TaggedTuple. More...
 
template<typename Tag , typename TagList >
auto & db::get_mutable_reference (const gsl::not_null< DataBox< TagList > * > box)
 Retrieve a mutable reference to the item with tag Tag from the DataBox. More...
 
template<typename AddMutableItemTags , typename AddImmutableItemTags = tmpl::list<>, typename... Args>
constexpr auto db::create (Args &&... args)
 Create a new DataBox. More...
 
template<size_t VolumeDim, typename TagsList , typename... TagsToSlice>
Variables< tmpl::list< TagsToSlice... > > db::data_on_slice (const db::DataBox< TagsList > &box, const Index< VolumeDim > &element_extents, const size_t sliced_dim, const size_t fixed_index, tmpl::list< TagsToSlice... >)
 Slices volume Tensors from a DataBox into a Variables More...
 
template<typename Tag >
std::string db::tag_name ()
 Get the name of a DataBox tag, including prefixes. More...
 
template<typename MutateTagList , typename BoxTags , typename... Args>
constexpr void Initialization::mutate_assign (const gsl::not_null< db::DataBox< BoxTags > * > box, Args &&... args)
 Perform a mutation to the DataBox box, assigning the args to the tags in MutateTagList in order.
 

Variables

template<typename Tag >
constexpr bool db::is_compute_tag_v = is_compute_tag<Tag>::value
 True if Tag derives from db::ComputeTag.
 
template<typename Tag >
constexpr bool db::is_reference_tag_v = is_reference_tag<Tag>::value
 True if Tag derives from db::ReferenceTag.
 
template<typename Tag >
constexpr bool db::is_immutable_item_tag_v = is_immutable_item_tag<Tag>::value
 True if Tag is a DataBox tag for an immutable item, i.e. a ComputeTag or ReferenceTag.
 
template<typename Tag >
constexpr bool db::is_mutable_item_tag_v = is_mutable_item_tag<Tag>::value
 True if Tag is a DataBox tag for a mutable item, i.e. a SimpleTag.
 
template<typename Tag >
constexpr bool db::is_simple_tag_v = is_simple_tag<Tag>::value
 True if Tag is a simple tag.
 
template<typename Tag >
constexpr bool db::is_non_base_tag_v = is_non_base_tag<Tag>::value
 True if Tag is not a base tag.
 
template<typename Tag >
constexpr bool db::is_tag_v = is_tag<Tag>::value
 True if Tag is a DataBox tag.
 
template<typename Tag >
constexpr bool db::is_base_tag_v = is_base_tag<Tag>::value
 True if Tag is a base tag.
 
template<typename Tag , typename DataBoxType >
using db::tag_is_retrievable = tmpl::or_< std::is_same< Tag, ::Tags::DataBox >, tmpl::any< typename DataBoxType::tags_list, std::is_base_of< tmpl::pin< Tag >, tmpl::_1 > > >
 Equal to true if Tag can be retrieved from a DataBox of type DataBoxType.
 
template<typename Tag , typename DataBoxType >
constexpr bool db::tag_is_retrievable_v
 Equal to true if Tag can be retrieved from a DataBox of type DataBoxType. More...
 
template<typename Consumer , typename Provider , typename Box >
using db::tag_depends_on = std::bool_constant< Box::template tag_depends_on< Consumer, Provider >()>
 Check whether the tag Consumer depends on the tag Provider in a given Box. More...
 
template<typename Consumer , typename Provider , typename Box >
constexpr bool db::tag_depends_on_v
 Check whether the tag Consumer depends on the tag Provider in a given Box. More...
 
template<typename MutateTags , typename ArgumentTags , typename F , typename... Args>
constexpr decltype(auto) db::mutate_apply (F &&f, const gsl::not_null< Access * > box, Args &&... args)
 Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and args. More...
 
template<typename F , typename... Args>
constexpr decltype(auto) db::mutate_apply (F &&f, const gsl::not_null< Access * > box, Args &&... args)
 Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and args. More...
 
template<typename F , typename... Args>
constexpr decltype(auto) db::mutate_apply (const gsl::not_null< Access * > box, Args &&... args)
 Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and args. More...
 
template<typename ArgumentTags , typename F , typename BoxTags , typename... Args>
constexpr auto db::apply (F &&f, const DataBox< BoxTags > &box, Args &&... args)
 Apply the invokable f with argument Tags TagsList from DataBox box More...
 
template<typename F , typename BoxTags , typename... Args>
constexpr auto db::apply (F &&f, const DataBox< BoxTags > &box, Args &&... args)
 Apply the invokable f with argument Tags TagsList from DataBox box More...
 
template<typename F , typename BoxTags , typename... Args>
constexpr auto db::apply (const DataBox< BoxTags > &box, Args &&... args)
 Apply the invokable f with argument Tags TagsList from DataBox box More...
 
template<typename MutateTags , typename ArgumentTags , typename F , typename BoxTags , typename... Args>
constexpr decltype(auto) db::mutate_apply (F &&f, const gsl::not_null< DataBox< BoxTags > * > box, Args &&... args)
 Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and args. More...
 
template<typename F , typename BoxTags , typename... Args>
constexpr decltype(auto) db::mutate_apply (F &&f, const gsl::not_null< DataBox< BoxTags > * > box, Args &&... args)
 Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and args. More...
 
template<typename F , typename BoxTags , typename... Args>
constexpr decltype(auto) db::mutate_apply (const gsl::not_null< DataBox< BoxTags > * > box, Args &&... args)
 Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and args. More...
 

Detailed Description

Documentation, functions, metafunctions, and classes necessary for using DataBox.

DataBox is a heterogeneous compile-time associative container with lazy evaluation of functions. DataBox can not only store data, but can also store functions that depend on other data inside the DataBox. The functions will be evaluated when the data they return is requested. The result is cached, and if a dependency of the function is modified the cache is invalidated.

Simple and Compute Tags and Their Items

The compile-time keys are structs called tags, while the values are called items. Tags are quite minimal, containing only the information necessary to store the data and evaluate functions. There are two different types of tags that a DataBox can hold: simple tags and compute tags. Simple tags are for data that is inserted into the DataBox at the time of creation, while compute tags are for data that will be computed from a function when the compute item is retrieved. If a compute item is never retrieved from the DataBox then it is never evaluated.

Simple tags must have a member type alias type that is the type of the data to be stored and a static std::string name() method that returns the name of the tag. Simple tags must inherit from db::SimpleTag.

Compute tags must also have a static std::string name() method that returns the name of the tag, but they cannot have a type type alias. Instead, compute tags must have a static member function or static member function pointer named function. function can be a function template if necessary. The function must take all its arguments by const reference. The arguments to the function are retrieved using tags from the DataBox that the compute tag is in. The tags for the arguments are set in the member type alias argument_tags, which must be a tmpl::list of the tags corresponding to each argument. Note that the order of the tags in the argument_list is the order that they will be passed to the function. Compute tags must inherit from db::ComputeTag.

Here is an example of a simple tag:

struct Tag0 : db::SimpleTag {
using type = double;
};
Mark a struct as a simple tag by inheriting from this.
Definition: Tag.hpp:36

and an example of a compute tag with a function pointer:

struct MutateVariablesCompute : MutateVariables, db::ComputeTag {
using base = MutateVariables;
static constexpr auto function = mutate_variables;
using return_type = Variables<
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>>;
using argument_tags = tmpl::list<Tag0>;
};
Mark a struct as a compute tag by inheriting from this.
Definition: Tag.hpp:157

If the compute item's tag is inline then the compute item is of the form:

struct Lambda0 : db::SimpleTag {
using type = double;
};
struct Lambda0Compute : Lambda0, db::ComputeTag {
using base = Lambda0;
using return_type = double;
static constexpr void function(const gsl::not_null<double*> result,
const double a) {
*result = 3.0 * a;
}
using argument_tags = tmpl::list<Tag0>;
};
Require a pointer to not be a nullptr
Definition: Gsl.hpp:183

Compute tags can also have their functions be overloaded on the type of its arguments:

template <typename ArgumentTag>
struct OverloadTypeCompute : OverloadType<ArgumentTag>, db::ComputeTag {
using base = OverloadType<ArgumentTag>;
using return_type = double;
static constexpr void function(const gsl::not_null<double*> result,
const int& a) {
*result = 5 * a;
}
static constexpr void function(const gsl::not_null<double*> result,
const double a) {
*result = 3.2 * a;
}
using argument_tags = tmpl::list<ArgumentTag>;
};

or be overloaded on the number of arguments:

template <typename ArgumentTag0, typename ArgumentTag1 = void>
struct OverloadNumberOfArgsCompute
: OverloadNumberOfArgs<ArgumentTag0, ArgumentTag1>,
using base = OverloadNumberOfArgs<ArgumentTag0, ArgumentTag1>;
using return_type = double;
static constexpr void function(const gsl::not_null<double*> result,
const double a) {
*result = 3.2 * a;
}
static constexpr void function(const gsl::not_null<double*> result,
const double a, const double b) {
*result = a * b;
}
using argument_tags =
tmpl::conditional_t<std::is_same_v<void, ArgumentTag1>,
tmpl::list<ArgumentTag0>,
tmpl::list<ArgumentTag0, ArgumentTag1>>;
};

Compute tag function templates are implemented as follows:

template <typename ArgumentTag>
struct TemplateCompute : Template<ArgumentTag>, db::ComputeTag {
using base = Template<ArgumentTag>;
using return_type = typename ArgumentTag::type;
template <typename T>
static constexpr void function(const gsl::not_null<T*> result, const T& a) {
*result = 5 * a;
}
using argument_tags = tmpl::list<ArgumentTag>;
};

Finally, overloading, function templates, and variadic functions can be combined to produce extremely generic compute tags. The below compute tag takes as template parameters a parameter pack of integers, which is used to specify several of the arguments. The function is overloaded for the single argument case, and a variadic function template is provided for the multiple arguments case. Note that in practice few compute tags will be this complex.

template <int I, int VectorBaseIndex = 0, int... VectorBaseExtraIndices>
struct ArrayCompute : Array<I, sizeof...(VectorBaseExtraIndices) == 0
? 3
: 2 + sizeof...(VectorBaseExtraIndices)>,
using base = Array<I, sizeof...(VectorBaseExtraIndices) == 0
? 3
: 2 + sizeof...(VectorBaseExtraIndices)>;
using return_type = typename base::type;
static void function(const gsl::not_null<std::array<int, 3>*> result,
const std::vector<double>& t) {
*result = {{static_cast<int>(t.size()), static_cast<int>(t[0]), -8}};
}
template <typename... Args>
static void function(
const gsl::not_null<std::array<int, 2 + sizeof...(Args)>*> result,
const std::vector<double>& t, const Args&... args) {
static_assert(sizeof...(VectorBaseExtraIndices) == sizeof...(Args));
*result = {{static_cast<int>(t.size()), static_cast<int>(t[0]),
static_cast<int>(args[0])...}};
}
using argument_tags = tmpl::list<VectorBase<VectorBaseIndex>,
VectorBase<VectorBaseExtraIndices>...>;
};

Subitems and Prefix Tags

A simple or compute tag might also hold a collection of data, such as a container of Tensors. In many cases you will want to be able to retrieve individual elements of the collection from the DataBox without having to first retrieve the collection. The infrastructure that allows for this is called Subitems. The subitems of the parent tag must refer to a subset of the data inside the parent tag, e.g. one Tensor in the collection. If the parent tag is Parent and the subitems tags are Sub<0>, Sub<1>, then when Parent is added to the DataBox, so are Sub<0> and Sub<1>. This means the retrieval mechanisms described below will work on Parent, Sub<0>, and Sub<1>.

Subitems specify requirements on the tags they act on. For example, there could be a requirement that all tags with a certain type are to be treated as a Subitems. Let's say that the Parent tag holds a Variables, and Variables can be used with the Subitems infrastructure to add the nested Tensors. Then all tags that hold a Variables will have their subitems added into the DataBox. To add a new type as a subitem the db::Subitems struct must be specialized. See the documentation of db::Subitems for more details.

The DataBox also supports prefix tags, which are commonly used for items that are related to a different item by some operation. Specifically, say you have a tag MyTensor and you want to also have the time derivative of MyTensor, then you can use the prefix tag dt to get dt<MyTensor>. The benefit of a prefix tag over, say, a separate tag dtMyTensor is that prefix tags can be added and removed by the compute tags acting on the original tag. Prefix tags can also be composed, so a second time derivative would be dt<dt<MyTensor>>. The net result of the prefix tags infrastructure is that the compute tag that returns dt<MyTensor> only needs to know its input tags, it knows how to name its output based off that. In addition to the normal things a simple or a compute tag must hold, prefix tags must have a nested type alias tag, which is the tag being prefixed. Prefix tags must also inherit from db::PrefixTag in addition to inheriting from db::SimpleTag or db::ComputeTag.

Creating a DataBox

You should never call the constructor of a DataBox directly. DataBox construction is quite complicated and the helper function db::create should be used instead. db::create is used to construct a new DataBox. It takes two typelists as explicit template parameters, the first being a list of the simple tags to add and the second being a list of compute tags to add. If no compute tags are being added then only the simple tags list must be specified. The tags lists should be passed as db::create<db::AddSimpleTags<simple_tags...>, db::AddComputeTags<compute_tags...>>. The arguments to db::create are the initial values of the simple tags and must be passed in the same order as the tags in the db::AddSimpleTags list. If the type of an argument passed to db::create does not match the type of the corresponding simple tag a static assertion will trigger. Here is an example of how to use db::create:

auto original_box = db::create<
db::AddSimpleTags<test_databox_tags::Tag0, test_databox_tags::Tag1,
test_databox_tags::Tag2>,
db::AddComputeTags<test_databox_tags::Tag4Compute,
test_databox_tags::Tag5Compute,
test_databox_tags::Lambda0Compute,
test_databox_tags::Lambda1Compute>>(
3.14, std::vector<double>{8.7, 93.2, 84.7}, "My Sample String"s);
constexpr auto create(Args &&... args)
Create a new DataBox.
Definition: DataBox.hpp:1455
tmpl::flatten< tmpl::list< Tags... > > AddSimpleTags
List of Tags to add to the DataBox.
Definition: DataBox.hpp:1404
tmpl::flatten< tmpl::list< Tags... > > AddComputeTags
List of Compute Item Tags to add to the DataBox.
Definition: DataBox.hpp:1411

Accessing and Mutating Items

To retrieve an item from a DataBox use the db::get function. db::get will always return a const reference to the object stored in the DataBox and will also have full type information available. This means you are able to use const auto& when retrieving tags from the DataBox. For example,

const auto& tag0 = db::get<test_databox_tags::Tag0>(original_box);

If you want to mutate the value of a simple item in the DataBox use db::mutate. Any compute item that depends on the mutated item will have its cached value invalidated and be recomputed the next time it is retrieved from the DataBox. db::mutate takes a parameter pack of tags to mutate as explicit template parameters, a gsl::not_null of the DataBox whose items will be mutated, an invokable, and extra arguments to forward to the invokable. The invokable takes the arguments passed from the DataBox by const gsl::not_null while the extra arguments are forwarded to the invokable. The invokable is not allowed to retrieve anything from the DataBox, so any items must be passed as extra arguments using db::get to retrieve them. For example,

db::mutate<test_databox_tags::Tag0, test_databox_tags::Tag1>(
[](const gsl::not_null<double*> tag0,
const double compute_tag0) {
CHECK(6.28 == compute_tag0);
*tag0 = 10.32;
(*tag1)[0] = 837.2;
},
make_not_null(&original_box),
db::get<test_databox_tags::Tag4>(original_box));
CHECK(10.32 == db::get<test_databox_tags::Tag0>(original_box));
CHECK(837.2 == db::get<test_databox_tags::Tag1>(original_box)[0]);

In addition to retrieving items using db::get and mutating them using db::mutate, there is a facility to invoke an invokable with tags from the DataBox. db::apply takes a tmpl::list of tags as an explicit template parameter, will retrieve all the tags from the DataBox passed in and then invoke the invokable with the items in the tag list. Similarly, db::mutate_apply invokes the invokable but allows for mutating some of the tags. See the documentation of db::apply and db::mutate_apply for examples of how to use them.

The Base Tags Mechanism

Retrieving items by tags should not require knowing whether the item being retrieved was computed using a compute tag or simply added using a simple tag. The framework that handles this falls under the umbrella term base tags. The reason is that a compute tag can inherit from a simple tag with the same item type, and then calls to db::get with the simple tag can be used to retrieve the compute item as well. That is, say you have a compute tag ArrayCompute that derives off of the simple tag Array, then you can retrieve the compute tag ArrayCompute and Array by calling db::get<Array>(box). The base tags mechanism requires that only one Array tag be present in the DataBox, otherwise a static assertion is triggered.

The inheritance idea can be generalized further with what are called base tags. A base tag is an empty struct that inherits from db::BaseTag. Any simple or compute item that derives off of the base tag can be retrieved using db::get. Consider the following VectorBase and Vector tag:

template <int I>
struct VectorBase : db::BaseTag {};
template <int I>
struct Vector : db::SimpleTag, VectorBase<I> {
using type = std::vector<double>;
};
Mark a (usually) empty struct as a base tag by inheriting from this.
Definition: Tag.hpp:69

It is possible to retrieve Vector<1> from the DataBox using VectorBase<1>. Most importantly, base tags can also be used in compute tag arguments, as follows:

template <int I, int VectorBaseIndex = 0, int... VectorBaseExtraIndices>
struct ArrayCompute : Array<I, sizeof...(VectorBaseExtraIndices) == 0
? 3
: 2 + sizeof...(VectorBaseExtraIndices)>,
using base = Array<I, sizeof...(VectorBaseExtraIndices) == 0
? 3
: 2 + sizeof...(VectorBaseExtraIndices)>;
using return_type = typename base::type;
static void function(const gsl::not_null<std::array<int, 3>*> result,
const std::vector<double>& t) {
*result = {{static_cast<int>(t.size()), static_cast<int>(t[0]), -8}};
}
template <typename... Args>
static void function(
const gsl::not_null<std::array<int, 2 + sizeof...(Args)>*> result,
const std::vector<double>& t, const Args&... args) {
static_assert(sizeof...(VectorBaseExtraIndices) == sizeof...(Args));
*result = {{static_cast<int>(t.size()), static_cast<int>(t[0]),
static_cast<int>(args[0])...}};
}
using argument_tags = tmpl::list<VectorBase<VectorBaseIndex>,
VectorBase<VectorBaseExtraIndices>...>;
};

As shown in the code example, the base tag mechanism works with function template compute tags, enabling generic programming to be combined with the lazy evaluation and automatic dependency analysis offered by the DataBox. To really demonstrate the power of base tags, let's also have ArrayComputeBase inherit from a simple tag Array, which inherits from a base tag ArrayBase as follows:

template <int I>
struct ArrayBase : db::BaseTag {};
template <int I, size_t Size = 3>
struct Array : db::SimpleTag, ArrayBase<I> {
using type = std::array<int, Size>;
};

To start, let's create a DataBox that holds a Vector<0> and an ArrayComputeBase<0> (the concrete tag must be used when creating the DataBox, not the base tags), retrieve the tags using the base tag mechanism, including mutating Vector<0>, and then verifying that the dependencies are handled correctly.

auto box = db::create<db::AddSimpleTags<TestTags::Vector<0>>,
std::vector<double>{-10.0, 10.0});
// Check retrieving simple tag Vector<0> using base tag VectorBase<0>
CHECK(db::get<TestTags::VectorBase<0>>(box) ==
std::vector<double>{-10.0, 10.0});
// Check retrieving compute tag ArrayCompute<0> using simple tag Array<0>
CHECK(db::get<TestTags::Array<0>>(box) == std::array<int, 3>{{2, -10, -8}});
// Check mutating Vector<0> using VectorBase<0>
db::mutate<TestTags::VectorBase<0>>(
[](const auto vector) { (*vector)[0] = 101.8; }, make_not_null(&box));
CHECK(db::get<TestTags::VectorBase<0>>(box) ==
std::vector<double>{101.8, 10.0});
// Check retrieving ArrayCompute<0> using base tag ArrayBase<0>.
// ArrayCompute was reset after mutating Vector<0>
CHECK(db::get<TestTags::ArrayBase<0>>(box) ==
std::array<int, 3>{{2, 101, -8}});
// Check retrieving ArrayCompute<0> using simple tag Array<0>.
CHECK(db::get<TestTags::Array<0>>(box) == std::array<int, 3>{{2, 101, -8}});
CHECK(db::get<TestTags::ArrayCompute<0>>(box) ==
std::array<int, 3>{{2, 101, -8}});
const auto & get(const Access &box)
Retrieve a tag from a db::Access
Definition: Access.hpp:60

Notice that we are able to retrieve ArrayComputeBase<0> with ArrayBase<0> and Array<0>. We were also able to mutate Vector<0> using VectorBase<0>.

The base tags infrastructure even works with Subitems. Even if you mutate the subitem of a parent using a base tag, the appropriate compute item caches will be invalidated.

Note
All of the base tags infrastructure works for db::get, db::mutate, db::apply and db::mutate_apply.

DataBox is a heterogeneous compile-time associative container with lazy evaluation of functions. DataBox can not only store data, but can also store functions that depend on other data inside the DataBox. The functions will be evaluated when the data they return is requested. The result is cached, and if a dependency of the function is modified the cache is invalidated.

Simple and Compute Tags and Their Items

The compile-time keys are structs called tags, while the values are called items. Tags are quite minimal, containing only the information necessary to store the data and evaluate functions. There are two different types of tags that a DataBox can hold: simple tags and compute tags. Simple tags are for data that is inserted into the DataBox at the time of creation, while compute tags are for data that will be computed from a function when the compute item is retrieved. If a compute item is never retrieved from the DataBox then it is never evaluated.

Simple tags must have a member type alias type that is the type of the data to be stored and a static std::string name() method that returns the name of the tag. Simple tags must inherit from db::SimpleTag.

Compute tags must also have a static std::string name() method that returns the name of the tag, but they cannot have a type type alias. Instead, compute tags must have a static member function or static member function pointer named function. function can be a function template if necessary. The function must take all its arguments by const reference. The arguments to the function are retrieved using tags from the DataBox that the compute tag is in. The tags for the arguments are set in the member type alias argument_tags, which must be a tmpl::list of the tags corresponding to each argument. Note that the order of the tags in the argument_list is the order that they will be passed to the function. Compute tags must inherit from db::ComputeTag.

Here is an example of a simple tag:

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

and an example of a compute tag with a function pointer:

struct MutateVariablesCompute : MutateVariables, db::ComputeTag {
using base = MutateVariables;
static constexpr auto function = mutate_variables;
using return_type = Variables<
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>>;
using argument_tags = tmpl::list<Tag0>;
};

If the compute item's tag is inline then the compute item is of the form:

struct Lambda0 : db::SimpleTag {
using type = double;
};
struct Lambda0Compute : Lambda0, db::ComputeTag {
using base = Lambda0;
using return_type = double;
static constexpr void function(const gsl::not_null<double*> result,
const double a) {
*result = 3.0 * a;
}
using argument_tags = tmpl::list<Tag0>;
};

Compute tags can also have their functions be overloaded on the type of its arguments:

template <typename ArgumentTag>
struct OverloadTypeCompute : OverloadType<ArgumentTag>, db::ComputeTag {
using base = OverloadType<ArgumentTag>;
using return_type = double;
static constexpr void function(const gsl::not_null<double*> result,
const int& a) {
*result = 5 * a;
}
static constexpr void function(const gsl::not_null<double*> result,
const double a) {
*result = 3.2 * a;
}
using argument_tags = tmpl::list<ArgumentTag>;
};

or be overloaded on the number of arguments:

template <typename ArgumentTag0, typename ArgumentTag1 = void>
struct OverloadNumberOfArgsCompute
: OverloadNumberOfArgs<ArgumentTag0, ArgumentTag1>,
using base = OverloadNumberOfArgs<ArgumentTag0, ArgumentTag1>;
using return_type = double;
static constexpr void function(const gsl::not_null<double*> result,
const double a) {
*result = 3.2 * a;
}
static constexpr void function(const gsl::not_null<double*> result,
const double a, const double b) {
*result = a * b;
}
using argument_tags =
tmpl::conditional_t<std::is_same_v<void, ArgumentTag1>,
tmpl::list<ArgumentTag0>,
tmpl::list<ArgumentTag0, ArgumentTag1>>;
};

Compute tag function templates are implemented as follows:

template <typename ArgumentTag>
struct TemplateCompute : Template<ArgumentTag>, db::ComputeTag {
using base = Template<ArgumentTag>;
using return_type = typename ArgumentTag::type;
template <typename T>
static constexpr void function(const gsl::not_null<T*> result, const T& a) {
*result = 5 * a;
}
using argument_tags = tmpl::list<ArgumentTag>;
};

Finally, overloading, function templates, and variadic functions can be combined to produce extremely generic compute tags. The below compute tag takes as template parameters a parameter pack of integers, which is used to specify several of the arguments. The function is overloaded for the single argument case, and a variadic function template is provided for the multiple arguments case. Note that in practice few compute tags will be this complex.

template <int I, int VectorBaseIndex = 0, int... VectorBaseExtraIndices>
struct ArrayCompute : Array<I, sizeof...(VectorBaseExtraIndices) == 0
? 3
: 2 + sizeof...(VectorBaseExtraIndices)>,
using base = Array<I, sizeof...(VectorBaseExtraIndices) == 0
? 3
: 2 + sizeof...(VectorBaseExtraIndices)>;
using return_type = typename base::type;
static void function(const gsl::not_null<std::array<int, 3>*> result,
const std::vector<double>& t) {
*result = {{static_cast<int>(t.size()), static_cast<int>(t[0]), -8}};
}
template <typename... Args>
static void function(
const gsl::not_null<std::array<int, 2 + sizeof...(Args)>*> result,
const std::vector<double>& t, const Args&... args) {
static_assert(sizeof...(VectorBaseExtraIndices) == sizeof...(Args));
*result = {{static_cast<int>(t.size()), static_cast<int>(t[0]),
static_cast<int>(args[0])...}};
}
using argument_tags = tmpl::list<VectorBase<VectorBaseIndex>,
VectorBase<VectorBaseExtraIndices>...>;
};

Subitems and Prefix Tags

A simple or compute tag might also hold a collection of data, such as a container of Tensors. In many cases you will want to be able to retrieve individual elements of the collection from the DataBox without having to first retrieve the collection. The infrastructure that allows for this is called Subitems. The subitems of the parent tag must refer to a subset of the data inside the parent tag, e.g. one Tensor in the collection. If the parent tag is Parent and the subitems tags are Sub<0>, Sub<1>, then when Parent is added to the DataBox, so are Sub<0> and Sub<1>. This means the retrieval mechanisms described below will work on Parent, Sub<0>, and Sub<1>.

Subitems specify requirements on the tags they act on. For example, there could be a requirement that all tags with a certain type are to be treated as a Subitems. Let's say that the Parent tag holds a Variables, and Variables can be used with the Subitems infrastructure to add the nested Tensors. Then all tags that hold a Variables will have their subitems added into the DataBox. To add a new type as a subitem the db::Subitems struct must be specialized. See the documentation of db::Subitems for more details.

The DataBox also supports prefix tags, which are commonly used for items that are related to a different item by some operation. Specifically, say you have a tag MyTensor and you want to also have the time derivative of MyTensor, then you can use the prefix tag dt to get dt<MyTensor>. The benefit of a prefix tag over, say, a separate tag dtMyTensor is that prefix tags can be added and removed by the compute tags acting on the original tag. Prefix tags can also be composed, so a second time derivative would be dt<dt<MyTensor>>. The net result of the prefix tags infrastructure is that the compute tag that returns dt<MyTensor> only needs to know its input tags, it knows how to name its output based off that. In addition to the normal things a simple or a compute tag must hold, prefix tags must have a nested type alias tag, which is the tag being prefixed. Prefix tags must also inherit from db::PrefixTag in addition to inheriting from db::SimpleTag or db::ComputeTag.

Creating a DataBox

You should never call the constructor of a DataBox directly. DataBox construction is quite complicated and the helper function db::create should be used instead. db::create is used to construct a new DataBox. It takes two typelists as explicit template parameters, the first being a list of the simple tags to add and the second being a list of compute tags to add. If no compute tags are being added then only the simple tags list must be specified. The tags lists should be passed as db::create<db::AddSimpleTags<simple_tags...>, db::AddComputeTags<compute_tags...>>. The arguments to db::create are the initial values of the simple tags and must be passed in the same order as the tags in the db::AddSimpleTags list. If the type of an argument passed to db::create does not match the type of the corresponding simple tag a static assertion will trigger. Here is an example of how to use db::create:

auto original_box = db::create<
db::AddSimpleTags<test_databox_tags::Tag0, test_databox_tags::Tag1,
test_databox_tags::Tag2>,
db::AddComputeTags<test_databox_tags::Tag4Compute,
test_databox_tags::Tag5Compute,
test_databox_tags::Lambda0Compute,
test_databox_tags::Lambda1Compute>>(
3.14, std::vector<double>{8.7, 93.2, 84.7}, "My Sample String"s);

Accessing and Mutating Items

To retrieve an item from a DataBox use the db::get function. db::get will always return a const reference to the object stored in the DataBox and will also have full type information available. This means you are able to use const auto& when retrieving tags from the DataBox. For example,

const auto& tag0 = db::get<test_databox_tags::Tag0>(original_box);

If you want to mutate the value of a simple item in the DataBox use db::mutate. Any compute item that depends on the mutated item will have its cached value invalidated and be recomputed the next time it is retrieved from the DataBox. db::mutate takes a parameter pack of tags to mutate as explicit template parameters, a gsl::not_null of the DataBox whose items will be mutated, an invokable, and extra arguments to forward to the invokable. The invokable takes the arguments passed from the DataBox by const gsl::not_null while the extra arguments are forwarded to the invokable. The invokable is not allowed to retrieve anything from the DataBox, so any items must be passed as extra arguments using db::get to retrieve them. For example,

db::mutate<test_databox_tags::Tag0, test_databox_tags::Tag1>(
[](const gsl::not_null<double*> tag0,
const double compute_tag0) {
CHECK(6.28 == compute_tag0);
*tag0 = 10.32;
(*tag1)[0] = 837.2;
},
make_not_null(&original_box),
db::get<test_databox_tags::Tag4>(original_box));
CHECK(10.32 == db::get<test_databox_tags::Tag0>(original_box));
CHECK(837.2 == db::get<test_databox_tags::Tag1>(original_box)[0]);

In addition to retrieving items using db::get and mutating them using db::mutate, there is a facility to invoke an invokable with tags from the DataBox. db::apply takes a tmpl::list of tags as an explicit template parameter, will retrieve all the tags from the DataBox passed in and then invoke the invokable with the items in the tag list. Similarly, db::mutate_apply invokes the invokable but allows for mutating some of the tags. See the documentation of db::apply and db::mutate_apply for examples of how to use them.

The Base Tags Mechanism

Retrieving items by tags should not require knowing whether the item being retrieved was computed using a compute tag or simply added using a simple tag. The framework that handles this falls under the umbrella term base tags. The reason is that a compute tag can inherit from a simple tag with the same item type, and then calls to db::get with the simple tag can be used to retrieve the compute item as well. That is, say you have a compute tag ArrayCompute that derives off of the simple tag Array, then you can retrieve the compute tag ArrayCompute and Array by calling db::get<Array>(box). The base tags mechanism requires that only one Array tag be present in the DataBox, otherwise a static assertion is triggered.

The inheritance idea can be generalized further with what are called base tags. A base tag is an empty struct that inherits from db::BaseTag. Any simple or compute item that derives off of the base tag can be retrieved using db::get. Consider the following VectorBase and Vector tag:

template <int I>
struct VectorBase : db::BaseTag {};
template <int I>
struct Vector : db::SimpleTag, VectorBase<I> {
using type = std::vector<double>;
};

It is possible to retrieve Vector<1> from the DataBox using VectorBase<1>. Most importantly, base tags can also be used in compute tag arguments, as follows:

template <int I, int VectorBaseIndex = 0, int... VectorBaseExtraIndices>
struct ArrayCompute : Array<I, sizeof...(VectorBaseExtraIndices) == 0
? 3
: 2 + sizeof...(VectorBaseExtraIndices)>,
using base = Array<I, sizeof...(VectorBaseExtraIndices) == 0
? 3
: 2 + sizeof...(VectorBaseExtraIndices)>;
using return_type = typename base::type;
static void function(const gsl::not_null<std::array<int, 3>*> result,
const std::vector<double>& t) {
*result = {{static_cast<int>(t.size()), static_cast<int>(t[0]), -8}};
}
template <typename... Args>
static void function(
const gsl::not_null<std::array<int, 2 + sizeof...(Args)>*> result,
const std::vector<double>& t, const Args&... args) {
static_assert(sizeof...(VectorBaseExtraIndices) == sizeof...(Args));
*result = {{static_cast<int>(t.size()), static_cast<int>(t[0]),
static_cast<int>(args[0])...}};
}
using argument_tags = tmpl::list<VectorBase<VectorBaseIndex>,
VectorBase<VectorBaseExtraIndices>...>;
};

As shown in the code example, the base tag mechanism works with function template compute tags, enabling generic programming to be combined with the lazy evaluation and automatic dependency analysis offered by the DataBox. To really demonstrate the power of base tags, let's also have ArrayComputeBase inherit from a simple tag Array, which inherits from a base tag ArrayBase as follows:

template <int I>
struct ArrayBase : db::BaseTag {};
template <int I, size_t Size = 3>
struct Array : db::SimpleTag, ArrayBase<I> {
using type = std::array<int, Size>;
};

To start, let's create a DataBox that holds a Vector<0> and an ArrayComputeBase<0> (the concrete tag must be used when creating the DataBox, not the base tags), retrieve the tags using the base tag mechanism, including mutating Vector<0>, and then verifying that the dependencies are handled correctly.

auto box = db::create<db::AddSimpleTags<TestTags::Vector<0>>,
std::vector<double>{-10.0, 10.0});
// Check retrieving simple tag Vector<0> using base tag VectorBase<0>
CHECK(db::get<TestTags::VectorBase<0>>(box) ==
std::vector<double>{-10.0, 10.0});
// Check retrieving compute tag ArrayCompute<0> using simple tag Array<0>
CHECK(db::get<TestTags::Array<0>>(box) == std::array<int, 3>{{2, -10, -8}});
// Check mutating Vector<0> using VectorBase<0>
db::mutate<TestTags::VectorBase<0>>(
[](const auto vector) { (*vector)[0] = 101.8; }, make_not_null(&box));
CHECK(db::get<TestTags::VectorBase<0>>(box) ==
std::vector<double>{101.8, 10.0});
// Check retrieving ArrayCompute<0> using base tag ArrayBase<0>.
// ArrayCompute was reset after mutating Vector<0>
CHECK(db::get<TestTags::ArrayBase<0>>(box) ==
std::array<int, 3>{{2, 101, -8}});
// Check retrieving ArrayCompute<0> using simple tag Array<0>.
CHECK(db::get<TestTags::Array<0>>(box) == std::array<int, 3>{{2, 101, -8}});
CHECK(db::get<TestTags::ArrayCompute<0>>(box) ==
std::array<int, 3>{{2, 101, -8}});

Notice that we are able to retrieve ArrayComputeBase<0> with ArrayBase<0> and Array<0>. We were also able to mutate Vector<0> using VectorBase<0>.

The base tags infrastructure even works with Subitems. Even if you mutate the subitem of a parent using a base tag, the appropriate compute item caches will be invalidated.

Note
All of the base tags infrastructure works for db::get, db::mutate, db::apply and db::mutate_apply.

Typedef Documentation

◆ tag_depends_on

template<typename Consumer , typename Provider , typename Box >
using db::tag_depends_on = typedef std::bool_constant<Box::template tag_depends_on<Consumer, Provider>()>

Check whether the tag Consumer depends on the tag Provider in a given Box.

This is equivalent to the question of whether changing Provider (through db::mutate, updating one of its dependencies, etc.) could change the value of db::get<Consumer>. Tags depend on themselves, and an item and its subitems all depend on one another.

Function Documentation

◆ apply() [1/3]

template<typename F , typename BoxTags , typename... Args>
constexpr auto db::apply ( const DataBox< BoxTags > &  box,
Args &&...  args 
)
constexpr

Apply the invokable f with argument Tags TagsList from DataBox box

Details

f must either be invokable with the arguments of type db::const_item_type<TagsList>..., Args... where the first pack expansion is over the elements in the type list ArgumentTags, or have a static apply function that is callable with the same types. If the class that implements the static apply functions also provides an argument_tags typelist, then it is used and no explicit ArgumentTags template parameter should be specified.

Usage

Given a function func that takes arguments of types T1, T2, A1 and A2. Let the Tags for the quantities of types T1 and T2 in the DataBox box be Tag1 and Tag2, and objects a1 of type A1 and a2 of type A2, then

auto result = db::apply<tmpl::list<Tag1, Tag2>>(func, box, a1, a2);

Returns: decltype(func(db::get<Tag1>(box), db::get<Tag2>(box), a1, a2))

Semantics: For tags Tags... in a DataBox box, and a function func that takes sizeof...(Tags) arguments of types db::const_item_type<Tags>..., and sizeof...(Args) arguments of types Args...,

result = func(box, db::get<Tags>(box)..., args...);

Example

auto check_result_args = [](const std::string& sample_string,
const auto& computed_string, const auto& vector) {
CHECK(sample_string == "My Sample String"s);
CHECK(computed_string == "My Sample String6.28"s);
CHECK(vector == (std::vector<double>{8.7, 93.2, 84.7}));
};
db::apply<tmpl::list<test_databox_tags::Tag2, test_databox_tags::Tag5>>(
check_result_args, original_box,
db::get<test_databox_tags::Tag1>(original_box));

Using a struct with an apply method:

struct ApplyCallable {
static void apply(const std::string& sample_string,
const std::string& computed_string,
const std::vector<double>& vector) {
CHECK(sample_string == "My Sample String"s);
CHECK(computed_string == "My Sample String6.28"s);
CHECK(vector == (std::vector<double>{8.7, 93.2, 84.7}));
}
};
db::apply<tmpl::list<test_databox_tags::Tag2, test_databox_tags::Tag5>>(
ApplyCallable{}, original_box,
db::get<test_databox_tags::Tag1>(original_box));
constexpr auto apply(F &&f, const DataBox< BoxTags > &box, Args &&... args)
Apply the invokable f with argument Tags TagsList from DataBox box
Definition: DataBox.hpp:1574

If the class F has no state, you can also use the stateless overload of apply:

struct StatelessApplyCallable {
using argument_tags =
tmpl::list<test_databox_tags::Tag2, test_databox_tags::Tag5>;
static void apply(const std::string& sample_string,
const std::string& computed_string,
const std::vector<double>& vector) {
CHECK(sample_string == "My Sample String"s);
CHECK(computed_string == "My Sample String6.28"s);
CHECK(vector == (std::vector<double>{8.7, 93.2, 84.7}));
}
};
db::apply<StatelessApplyCallable>(
original_box, db::get<test_databox_tags::Tag1>(original_box));
See also
DataBox
Template Parameters
ArgumentTagstypelist of Tags in the order that they are to be passed to f
FThe invokable to apply

◆ apply() [2/3]

template<typename ArgumentTags , typename F , typename BoxTags , typename... Args>
constexpr auto db::apply ( F &&  f,
const DataBox< BoxTags > &  box,
Args &&...  args 
)
constexpr

Apply the invokable f with argument Tags TagsList from DataBox box

Details

f must either be invokable with the arguments of type db::const_item_type<TagsList>..., Args... where the first pack expansion is over the elements in the type list ArgumentTags, or have a static apply function that is callable with the same types. If the class that implements the static apply functions also provides an argument_tags typelist, then it is used and no explicit ArgumentTags template parameter should be specified.

Usage

Given a function func that takes arguments of types T1, T2, A1 and A2. Let the Tags for the quantities of types T1 and T2 in the DataBox box be Tag1 and Tag2, and objects a1 of type A1 and a2 of type A2, then

auto result = db::apply<tmpl::list<Tag1, Tag2>>(func, box, a1, a2);

Returns: decltype(func(db::get<Tag1>(box), db::get<Tag2>(box), a1, a2))

Semantics: For tags Tags... in a DataBox box, and a function func that takes sizeof...(Tags) arguments of types db::const_item_type<Tags>..., and sizeof...(Args) arguments of types Args...,

result = func(box, db::get<Tags>(box)..., args...);

Example

auto check_result_args = [](const std::string& sample_string,
const auto& computed_string, const auto& vector) {
CHECK(sample_string == "My Sample String"s);
CHECK(computed_string == "My Sample String6.28"s);
CHECK(vector == (std::vector<double>{8.7, 93.2, 84.7}));
};
db::apply<tmpl::list<test_databox_tags::Tag2, test_databox_tags::Tag5>>(
check_result_args, original_box,
db::get<test_databox_tags::Tag1>(original_box));

Using a struct with an apply method:

struct ApplyCallable {
static void apply(const std::string& sample_string,
const std::string& computed_string,
const std::vector<double>& vector) {
CHECK(sample_string == "My Sample String"s);
CHECK(computed_string == "My Sample String6.28"s);
CHECK(vector == (std::vector<double>{8.7, 93.2, 84.7}));
}
};
db::apply<tmpl::list<test_databox_tags::Tag2, test_databox_tags::Tag5>>(
ApplyCallable{}, original_box,
db::get<test_databox_tags::Tag1>(original_box));

If the class F has no state, you can also use the stateless overload of apply:

struct StatelessApplyCallable {
using argument_tags =
tmpl::list<test_databox_tags::Tag2, test_databox_tags::Tag5>;
static void apply(const std::string& sample_string,
const std::string& computed_string,
const std::vector<double>& vector) {
CHECK(sample_string == "My Sample String"s);
CHECK(computed_string == "My Sample String6.28"s);
CHECK(vector == (std::vector<double>{8.7, 93.2, 84.7}));
}
};
db::apply<StatelessApplyCallable>(
original_box, db::get<test_databox_tags::Tag1>(original_box));
See also
DataBox
Template Parameters
ArgumentTagstypelist of Tags in the order that they are to be passed to f
FThe invokable to apply

◆ apply() [3/3]

template<typename F , typename BoxTags , typename... Args>
constexpr auto db::apply ( F &&  f,
const DataBox< BoxTags > &  box,
Args &&...  args 
)
constexpr

Apply the invokable f with argument Tags TagsList from DataBox box

Details

f must either be invokable with the arguments of type db::const_item_type<TagsList>..., Args... where the first pack expansion is over the elements in the type list ArgumentTags, or have a static apply function that is callable with the same types. If the class that implements the static apply functions also provides an argument_tags typelist, then it is used and no explicit ArgumentTags template parameter should be specified.

Usage

Given a function func that takes arguments of types T1, T2, A1 and A2. Let the Tags for the quantities of types T1 and T2 in the DataBox box be Tag1 and Tag2, and objects a1 of type A1 and a2 of type A2, then

auto result = db::apply<tmpl::list<Tag1, Tag2>>(func, box, a1, a2);

Returns: decltype(func(db::get<Tag1>(box), db::get<Tag2>(box), a1, a2))

Semantics: For tags Tags... in a DataBox box, and a function func that takes sizeof...(Tags) arguments of types db::const_item_type<Tags>..., and sizeof...(Args) arguments of types Args...,

result = func(box, db::get<Tags>(box)..., args...);

Example

auto check_result_args = [](const std::string& sample_string,
const auto& computed_string, const auto& vector) {
CHECK(sample_string == "My Sample String"s);
CHECK(computed_string == "My Sample String6.28"s);
CHECK(vector == (std::vector<double>{8.7, 93.2, 84.7}));
};
db::apply<tmpl::list<test_databox_tags::Tag2, test_databox_tags::Tag5>>(
check_result_args, original_box,
db::get<test_databox_tags::Tag1>(original_box));

Using a struct with an apply method:

struct ApplyCallable {
static void apply(const std::string& sample_string,
const std::string& computed_string,
const std::vector<double>& vector) {
CHECK(sample_string == "My Sample String"s);
CHECK(computed_string == "My Sample String6.28"s);
CHECK(vector == (std::vector<double>{8.7, 93.2, 84.7}));
}
};
db::apply<tmpl::list<test_databox_tags::Tag2, test_databox_tags::Tag5>>(
ApplyCallable{}, original_box,
db::get<test_databox_tags::Tag1>(original_box));

If the class F has no state, you can also use the stateless overload of apply:

struct StatelessApplyCallable {
using argument_tags =
tmpl::list<test_databox_tags::Tag2, test_databox_tags::Tag5>;
static void apply(const std::string& sample_string,
const std::string& computed_string,
const std::vector<double>& vector) {
CHECK(sample_string == "My Sample String"s);
CHECK(computed_string == "My Sample String6.28"s);
CHECK(vector == (std::vector<double>{8.7, 93.2, 84.7}));
}
};
db::apply<StatelessApplyCallable>(
original_box, db::get<test_databox_tags::Tag1>(original_box));
See also
DataBox
Template Parameters
ArgumentTagstypelist of Tags in the order that they are to be passed to f
FThe invokable to apply

◆ copy_items()

template<typename CopiedItemsTagList , typename DbTagList >
auto db::copy_items ( const DataBox< DbTagList > &  box)

Copy the items from the DataBox into a TaggedTuple.

Returns: The objects corresponding to CopiedItemsTagList

Note
The tags in CopiedItemsTagList must be a subset of the mutable_item_creation_tags of the DataBox

◆ create()

template<typename AddMutableItemTags , typename AddImmutableItemTags = tmpl::list<>, typename... Args>
constexpr auto db::create ( Args &&...  args)
constexpr

Create a new DataBox.

Details

Creates a new DataBox holding types Tags::type filled with the arguments passed to the function. Compute and reference items must be added so that their dependencies are added before themselves. For example, say you have compute items A and B where B depends on A, then you must add them using db::AddImmutableItemTags<A, B>.

Example

auto original_box = db::create<
db::AddSimpleTags<test_databox_tags::Tag0, test_databox_tags::Tag1,
test_databox_tags::Tag2>,
db::AddComputeTags<test_databox_tags::Tag4Compute,
test_databox_tags::Tag5Compute,
test_databox_tags::Lambda0Compute,
test_databox_tags::Lambda1Compute>>(
3.14, std::vector<double>{8.7, 93.2, 84.7}, "My Sample String"s);
See also
create_from
Template Parameters
AddMutableItemTagsthe tags of the mutable items that are being added
AddImmutableItemTagslist of compute item tags and refernce item tags to add to the DataBox
Parameters
argsthe initial values for the mutable items to add to the DataBox

◆ data_on_slice()

template<size_t VolumeDim, typename TagsList , typename... TagsToSlice>
Variables< tmpl::list< TagsToSlice... > > db::data_on_slice ( const db::DataBox< TagsList > &  box,
const Index< VolumeDim > &  element_extents,
const size_t  sliced_dim,
const size_t  fixed_index,
tmpl::list< TagsToSlice... >   
)

Slices volume Tensors from a DataBox into a Variables

The slice has a constant logical coordinate in direction sliced_dim, slicing the volume at fixed_index in that dimension. For example, to get the lower boundary of sliced_dim, pass 0 for fixed_index; to get the upper boundary, pass extents[sliced_dim] - 1. The last argument to the function is the typelist holding the tags to slice.

db::data_on_slice(box, extents, 0, x_offset,
tmpl::list<DataBoxTest_detail::vector>{})
Variables< tmpl::list< TagsToSlice... > > data_on_slice(const db::DataBox< TagsList > &box, const Index< VolumeDim > &element_extents, const size_t sliced_dim, const size_t fixed_index, tmpl::list< TagsToSlice... >)
Slices volume Tensors from a DataBox into a Variables
Definition: DataOnSlice.hpp:33

◆ get()

template<typename Tag , typename TagList >
const auto & db::get ( const DataBox< TagList > &  box)

Retrieve the item with tag Tag from the DataBox.

Requires: Type Tag is one of the Tags corresponding to an object stored in the DataBox

Returns: The object corresponding to the tag Tag

◆ get_mutable_reference()

template<typename Tag , typename TagList >
auto & db::get_mutable_reference ( const gsl::not_null< DataBox< TagList > * >  box)

Retrieve a mutable reference to the item with tag Tag from the DataBox.

The tag retrieved cannot be used by any compute tags, cannot have subitems, and cannot itself be a subitem. These requirements prevent changes to the retrieved item from affecting any other tags in the DataBox, so it can safely be modified without causing internal inconsistencies.

◆ mutate()

template<typename... MutateTags, typename TagList , typename Invokable , typename... Args>
decltype(auto) db::mutate ( Invokable &&  invokable,
const gsl::not_null< DataBox< TagList > * >  box,
Args &&...  args 
)

Allows changing the state of one or more non-computed elements in the DataBox.

mutate()'s second argument is the DataBox from which to retrieve the tags MutateTags. The objects corresponding to the MutateTags are then passed to invokable, which is a lambda or a function object taking as many arguments as there are MutateTags and with the arguments being of types gsl::not_null<db::item_type<MutateTags>*>.... Inside the invokable no items can be retrieved from the DataBox box. This is to avoid confusing subtleties with order of evaluation of compute items, as well as dangling references. If an invokable needs read access to items in box they should be passed as additional arguments to mutate. Capturing them by reference in a lambda does not work because of a bug in GCC 6.3 and earlier. For a function object the read-only items can also be stored as const references inside the object by passing db::get<TAG>(t) to the constructor.

Example

db::mutate<test_databox_tags::Tag0, test_databox_tags::Tag1>(
[](const gsl::not_null<double*> tag0,
const double compute_tag0) {
CHECK(6.28 == compute_tag0);
*tag0 = 10.32;
(*tag1)[0] = 837.2;
},
make_not_null(&original_box),
db::get<test_databox_tags::Tag4>(original_box));
CHECK(10.32 == db::get<test_databox_tags::Tag0>(original_box));
CHECK(837.2 == db::get<test_databox_tags::Tag1>(original_box)[0]);

The invokable may have function return values, and any returns are forwarded as returns to the db::mutate call.

For convenience in generic programming, if Tags::DataBox is passed as the sole MutateTags parameter, this function will simply call its first argument with its remaining arguments. Except for this case, Tags::DataBox is not usable with this function.

Warning
Using db::mutate returns to obtain non-const references or pointers to box items is potentially very dangerous. The DataBox cannot track any subsequent changes to quantities that have been "unsafely" extracted in this manner, so we consider it undefined behavior to return pointers or references to DataBox contents.

◆ mutate_apply() [1/6]

template<typename F , typename... Args>
constexpr decltype(auto) db::mutate_apply ( const gsl::not_null< Access * >  box,
Args &&...  args 
)
constexpr

Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and args.

Details

f must either be invokable with the arguments of type gsl::not_null<db::item_type<MutateTags>*>..., db::const_item_type<ArgumentTags>..., Args... where the first two pack expansions are over the elements in the typelists MutateTags and ArgumentTags, or have a static apply function that is callable with the same types. If the type of f specifies return_tags and argument_tags typelists, these are used for the MutateTags and ArgumentTags, respectively.

Any return values of the invokable f are forwarded as returns to the mutate_apply call.

Example

An example of using mutate_apply with a lambda:

tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>,
tmpl::list<test_databox_tags::Tag2>>(
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
},
make_not_null(&box));
constexpr decltype(auto) mutate_apply(F &&f, const gsl::not_null< Access * > box, Args &&... args)
Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and a...
Definition: Access.hpp:175

An example of a class with a static apply function

struct TestDataboxMutateApply {
// delete copy semantics just to make sure it works. Not necessary in general.
TestDataboxMutateApply() = default;
TestDataboxMutateApply(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply& operator=(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply(TestDataboxMutateApply&&) = default;
TestDataboxMutateApply& operator=(TestDataboxMutateApply&&) = default;
~TestDataboxMutateApply() = default;
// These typelists are used by the `db::mutate_apply` overload that does not
// require these lists as template arguments
using return_tags =
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>;
using argument_tags = tmpl::list<test_databox_tags::Tag2>;
static void apply(const gsl::not_null<Scalar<DataVector>*> scalar,
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
}
};
Definition: ContractFirstNIndices.hpp:16

and how to use mutate_apply with the above class

db::mutate_apply(TestDataboxMutateApply{}, make_not_null(&box));

Note that the class exposes return_tags and argument_tags typelists, so we don't specify the template parameters explicitly. If the class F has no state, like in this example,

struct TestDataboxMutateApply {
// delete copy semantics just to make sure it works. Not necessary in general.
TestDataboxMutateApply() = default;
TestDataboxMutateApply(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply& operator=(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply(TestDataboxMutateApply&&) = default;
TestDataboxMutateApply& operator=(TestDataboxMutateApply&&) = default;
~TestDataboxMutateApply() = default;
// These typelists are used by the `db::mutate_apply` overload that does not
// require these lists as template arguments
using return_tags =
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>;
using argument_tags = tmpl::list<test_databox_tags::Tag2>;
static void apply(const gsl::not_null<Scalar<DataVector>*> scalar,
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
}
};

you can also use the stateless overload of mutate_apply:

db::mutate_apply<TestDataboxMutateApply>(make_not_null(&box));
Template Parameters
MutateTagstypelist of Tags to mutate
ArgumentTagstypelist of additional items to retrieve from the Access
FThe invokable to apply

◆ mutate_apply() [2/6]

template<typename F , typename BoxTags , typename... Args>
constexpr decltype(auto) db::mutate_apply ( const gsl::not_null< DataBox< BoxTags > * >  box,
Args &&...  args 
)
constexpr

Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and args.

Details

f must either be invokable with the arguments of type gsl::not_null<db::item_type<MutateTags>*>..., db::const_item_type<ArgumentTags>..., Args... where the first two pack expansions are over the elements in the typelists MutateTags and ArgumentTags, or have a static apply function that is callable with the same types. If the type of f specifies return_tags and argument_tags typelists, these are used for the MutateTags and ArgumentTags, respectively.

Any return values of the invokable f are forwarded as returns to the mutate_apply call.

Note
If MutateTags is empty this will forward to db::apply, so Tags::DataBox will be available. Otherwise it will call db::mutate. See those functions for more details on retrieving the entire box.

Example

An example of using mutate_apply with a lambda:

tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>,
tmpl::list<test_databox_tags::Tag2>>(
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
},
make_not_null(&box));

An example of a class with a static apply function

struct TestDataboxMutateApply {
// delete copy semantics just to make sure it works. Not necessary in general.
TestDataboxMutateApply() = default;
TestDataboxMutateApply(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply& operator=(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply(TestDataboxMutateApply&&) = default;
TestDataboxMutateApply& operator=(TestDataboxMutateApply&&) = default;
~TestDataboxMutateApply() = default;
// These typelists are used by the `db::mutate_apply` overload that does not
// require these lists as template arguments
using return_tags =
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>;
using argument_tags = tmpl::list<test_databox_tags::Tag2>;
static void apply(const gsl::not_null<Scalar<DataVector>*> scalar,
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
}
};

and how to use mutate_apply with the above class

db::mutate_apply(TestDataboxMutateApply{}, make_not_null(&box));

Note that the class exposes return_tags and argument_tags typelists, so we don't specify the template parameters explicitly. If the class F has no state, like in this example,

struct TestDataboxMutateApply {
// delete copy semantics just to make sure it works. Not necessary in general.
TestDataboxMutateApply() = default;
TestDataboxMutateApply(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply& operator=(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply(TestDataboxMutateApply&&) = default;
TestDataboxMutateApply& operator=(TestDataboxMutateApply&&) = default;
~TestDataboxMutateApply() = default;
// These typelists are used by the `db::mutate_apply` overload that does not
// require these lists as template arguments
using return_tags =
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>;
using argument_tags = tmpl::list<test_databox_tags::Tag2>;
static void apply(const gsl::not_null<Scalar<DataVector>*> scalar,
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
}
};

you can also use the stateless overload of mutate_apply:

db::mutate_apply<TestDataboxMutateApply>(make_not_null(&box));
Template Parameters
MutateTagstypelist of Tags to mutate
ArgumentTagstypelist of additional items to retrieve from the DataBox
FThe invokable to apply

◆ mutate_apply() [3/6]

template<typename MutateTags , typename ArgumentTags , typename F , typename... Args>
constexpr decltype(auto) db::mutate_apply ( F &&  f,
const gsl::not_null< Access * >  box,
Args &&...  args 
)
constexpr

Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and args.

Details

f must either be invokable with the arguments of type gsl::not_null<db::item_type<MutateTags>*>..., db::const_item_type<ArgumentTags>..., Args... where the first two pack expansions are over the elements in the typelists MutateTags and ArgumentTags, or have a static apply function that is callable with the same types. If the type of f specifies return_tags and argument_tags typelists, these are used for the MutateTags and ArgumentTags, respectively.

Any return values of the invokable f are forwarded as returns to the mutate_apply call.

Example

An example of using mutate_apply with a lambda:

tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>,
tmpl::list<test_databox_tags::Tag2>>(
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
},
make_not_null(&box));

An example of a class with a static apply function

struct TestDataboxMutateApply {
// delete copy semantics just to make sure it works. Not necessary in general.
TestDataboxMutateApply() = default;
TestDataboxMutateApply(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply& operator=(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply(TestDataboxMutateApply&&) = default;
TestDataboxMutateApply& operator=(TestDataboxMutateApply&&) = default;
~TestDataboxMutateApply() = default;
// These typelists are used by the `db::mutate_apply` overload that does not
// require these lists as template arguments
using return_tags =
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>;
using argument_tags = tmpl::list<test_databox_tags::Tag2>;
static void apply(const gsl::not_null<Scalar<DataVector>*> scalar,
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
}
};

and how to use mutate_apply with the above class

db::mutate_apply(TestDataboxMutateApply{}, make_not_null(&box));

Note that the class exposes return_tags and argument_tags typelists, so we don't specify the template parameters explicitly. If the class F has no state, like in this example,

struct TestDataboxMutateApply {
// delete copy semantics just to make sure it works. Not necessary in general.
TestDataboxMutateApply() = default;
TestDataboxMutateApply(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply& operator=(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply(TestDataboxMutateApply&&) = default;
TestDataboxMutateApply& operator=(TestDataboxMutateApply&&) = default;
~TestDataboxMutateApply() = default;
// These typelists are used by the `db::mutate_apply` overload that does not
// require these lists as template arguments
using return_tags =
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>;
using argument_tags = tmpl::list<test_databox_tags::Tag2>;
static void apply(const gsl::not_null<Scalar<DataVector>*> scalar,
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
}
};

you can also use the stateless overload of mutate_apply:

db::mutate_apply<TestDataboxMutateApply>(make_not_null(&box));
Template Parameters
MutateTagstypelist of Tags to mutate
ArgumentTagstypelist of additional items to retrieve from the Access
FThe invokable to apply

◆ mutate_apply() [4/6]

template<typename F , typename... Args>
constexpr decltype(auto) db::mutate_apply ( F &&  f,
const gsl::not_null< Access * >  box,
Args &&...  args 
)
constexpr

Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and args.

Details

f must either be invokable with the arguments of type gsl::not_null<db::item_type<MutateTags>*>..., db::const_item_type<ArgumentTags>..., Args... where the first two pack expansions are over the elements in the typelists MutateTags and ArgumentTags, or have a static apply function that is callable with the same types. If the type of f specifies return_tags and argument_tags typelists, these are used for the MutateTags and ArgumentTags, respectively.

Any return values of the invokable f are forwarded as returns to the mutate_apply call.

Example

An example of using mutate_apply with a lambda:

tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>,
tmpl::list<test_databox_tags::Tag2>>(
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
},
make_not_null(&box));

An example of a class with a static apply function

struct TestDataboxMutateApply {
// delete copy semantics just to make sure it works. Not necessary in general.
TestDataboxMutateApply() = default;
TestDataboxMutateApply(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply& operator=(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply(TestDataboxMutateApply&&) = default;
TestDataboxMutateApply& operator=(TestDataboxMutateApply&&) = default;
~TestDataboxMutateApply() = default;
// These typelists are used by the `db::mutate_apply` overload that does not
// require these lists as template arguments
using return_tags =
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>;
using argument_tags = tmpl::list<test_databox_tags::Tag2>;
static void apply(const gsl::not_null<Scalar<DataVector>*> scalar,
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
}
};

and how to use mutate_apply with the above class

db::mutate_apply(TestDataboxMutateApply{}, make_not_null(&box));

Note that the class exposes return_tags and argument_tags typelists, so we don't specify the template parameters explicitly. If the class F has no state, like in this example,

struct TestDataboxMutateApply {
// delete copy semantics just to make sure it works. Not necessary in general.
TestDataboxMutateApply() = default;
TestDataboxMutateApply(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply& operator=(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply(TestDataboxMutateApply&&) = default;
TestDataboxMutateApply& operator=(TestDataboxMutateApply&&) = default;
~TestDataboxMutateApply() = default;
// These typelists are used by the `db::mutate_apply` overload that does not
// require these lists as template arguments
using return_tags =
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>;
using argument_tags = tmpl::list<test_databox_tags::Tag2>;
static void apply(const gsl::not_null<Scalar<DataVector>*> scalar,
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
}
};

you can also use the stateless overload of mutate_apply:

db::mutate_apply<TestDataboxMutateApply>(make_not_null(&box));
Template Parameters
MutateTagstypelist of Tags to mutate
ArgumentTagstypelist of additional items to retrieve from the Access
FThe invokable to apply

◆ mutate_apply() [5/6]

template<typename MutateTags , typename ArgumentTags , typename F , typename BoxTags , typename... Args>
constexpr decltype(auto) db::mutate_apply ( F &&  f,
const gsl::not_null< DataBox< BoxTags > * >  box,
Args &&...  args 
)
constexpr

Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and args.

Details

f must either be invokable with the arguments of type gsl::not_null<db::item_type<MutateTags>*>..., db::const_item_type<ArgumentTags>..., Args... where the first two pack expansions are over the elements in the typelists MutateTags and ArgumentTags, or have a static apply function that is callable with the same types. If the type of f specifies return_tags and argument_tags typelists, these are used for the MutateTags and ArgumentTags, respectively.

Any return values of the invokable f are forwarded as returns to the mutate_apply call.

Note
If MutateTags is empty this will forward to db::apply, so Tags::DataBox will be available. Otherwise it will call db::mutate. See those functions for more details on retrieving the entire box.

Example

An example of using mutate_apply with a lambda:

tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>,
tmpl::list<test_databox_tags::Tag2>>(
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
},
make_not_null(&box));

An example of a class with a static apply function

struct TestDataboxMutateApply {
// delete copy semantics just to make sure it works. Not necessary in general.
TestDataboxMutateApply() = default;
TestDataboxMutateApply(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply& operator=(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply(TestDataboxMutateApply&&) = default;
TestDataboxMutateApply& operator=(TestDataboxMutateApply&&) = default;
~TestDataboxMutateApply() = default;
// These typelists are used by the `db::mutate_apply` overload that does not
// require these lists as template arguments
using return_tags =
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>;
using argument_tags = tmpl::list<test_databox_tags::Tag2>;
static void apply(const gsl::not_null<Scalar<DataVector>*> scalar,
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
}
};

and how to use mutate_apply with the above class

db::mutate_apply(TestDataboxMutateApply{}, make_not_null(&box));

Note that the class exposes return_tags and argument_tags typelists, so we don't specify the template parameters explicitly. If the class F has no state, like in this example,

struct TestDataboxMutateApply {
// delete copy semantics just to make sure it works. Not necessary in general.
TestDataboxMutateApply() = default;
TestDataboxMutateApply(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply& operator=(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply(TestDataboxMutateApply&&) = default;
TestDataboxMutateApply& operator=(TestDataboxMutateApply&&) = default;
~TestDataboxMutateApply() = default;
// These typelists are used by the `db::mutate_apply` overload that does not
// require these lists as template arguments
using return_tags =
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>;
using argument_tags = tmpl::list<test_databox_tags::Tag2>;
static void apply(const gsl::not_null<Scalar<DataVector>*> scalar,
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
}
};

you can also use the stateless overload of mutate_apply:

db::mutate_apply<TestDataboxMutateApply>(make_not_null(&box));
Template Parameters
MutateTagstypelist of Tags to mutate
ArgumentTagstypelist of additional items to retrieve from the DataBox
FThe invokable to apply

◆ mutate_apply() [6/6]

template<typename F , typename BoxTags , typename... Args>
constexpr decltype(auto) db::mutate_apply ( F &&  f,
const gsl::not_null< DataBox< BoxTags > * >  box,
Args &&...  args 
)
constexpr

Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and args.

Details

f must either be invokable with the arguments of type gsl::not_null<db::item_type<MutateTags>*>..., db::const_item_type<ArgumentTags>..., Args... where the first two pack expansions are over the elements in the typelists MutateTags and ArgumentTags, or have a static apply function that is callable with the same types. If the type of f specifies return_tags and argument_tags typelists, these are used for the MutateTags and ArgumentTags, respectively.

Any return values of the invokable f are forwarded as returns to the mutate_apply call.

Note
If MutateTags is empty this will forward to db::apply, so Tags::DataBox will be available. Otherwise it will call db::mutate. See those functions for more details on retrieving the entire box.

Example

An example of using mutate_apply with a lambda:

tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>,
tmpl::list<test_databox_tags::Tag2>>(
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
},
make_not_null(&box));

An example of a class with a static apply function

struct TestDataboxMutateApply {
// delete copy semantics just to make sure it works. Not necessary in general.
TestDataboxMutateApply() = default;
TestDataboxMutateApply(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply& operator=(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply(TestDataboxMutateApply&&) = default;
TestDataboxMutateApply& operator=(TestDataboxMutateApply&&) = default;
~TestDataboxMutateApply() = default;
// These typelists are used by the `db::mutate_apply` overload that does not
// require these lists as template arguments
using return_tags =
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>;
using argument_tags = tmpl::list<test_databox_tags::Tag2>;
static void apply(const gsl::not_null<Scalar<DataVector>*> scalar,
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
}
};

and how to use mutate_apply with the above class

db::mutate_apply(TestDataboxMutateApply{}, make_not_null(&box));

Note that the class exposes return_tags and argument_tags typelists, so we don't specify the template parameters explicitly. If the class F has no state, like in this example,

struct TestDataboxMutateApply {
// delete copy semantics just to make sure it works. Not necessary in general.
TestDataboxMutateApply() = default;
TestDataboxMutateApply(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply& operator=(const TestDataboxMutateApply&) = delete;
TestDataboxMutateApply(TestDataboxMutateApply&&) = default;
TestDataboxMutateApply& operator=(TestDataboxMutateApply&&) = default;
~TestDataboxMutateApply() = default;
// These typelists are used by the `db::mutate_apply` overload that does not
// require these lists as template arguments
using return_tags =
tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>;
using argument_tags = tmpl::list<test_databox_tags::Tag2>;
static void apply(const gsl::not_null<Scalar<DataVector>*> scalar,
const std::string& tag2) {
scalar->get() *= 2.0;
get<0>(*vector) *= 3.0;
get<1>(*vector) *= 4.0;
get<2>(*vector) *= 5.0;
CHECK(tag2 == "My Sample String"s);
}
};

you can also use the stateless overload of mutate_apply:

db::mutate_apply<TestDataboxMutateApply>(make_not_null(&box));
Template Parameters
MutateTagstypelist of Tags to mutate
ArgumentTagstypelist of additional items to retrieve from the DataBox
FThe invokable to apply

◆ tag_name()

template<typename Tag >
std::string db::tag_name ( )

Get the name of a DataBox tag, including prefixes.

Details

Given a DataBox tag returns the name of the DataBox tag as a std::string. If the DataBox tag is also a PrefixTag then the prefix is added.

Template Parameters
Tagthe DataBox tag whose name to get

Returns: string holding the DataBox tag's name

Variable Documentation

◆ tag_depends_on_v

template<typename Consumer , typename Provider , typename Box >
constexpr bool db::tag_depends_on_v
constexpr
Initial value:

Check whether the tag Consumer depends on the tag Provider in a given Box.

This is equivalent to the question of whether changing Provider (through db::mutate, updating one of its dependencies, etc.) could change the value of db::get<Consumer>. Tags depend on themselves, and an item and its subitems all depend on one another.

◆ tag_is_retrievable_v

template<typename Tag , typename DataBoxType >
constexpr bool db::tag_is_retrievable_v
constexpr
Initial value:
=
tmpl::or_< std::is_same< Tag, ::Tags::DataBox >, tmpl::any< typename DataBoxType::tags_list, std::is_base_of< tmpl::pin< Tag >, tmpl::_1 > > > tag_is_retrievable
Equal to true if Tag can be retrieved from a DataBox of type DataBoxType.
Definition: DataBox.hpp:68

Equal to true if Tag can be retrieved from a DataBox of type DataBoxType.