Namespaces | Classes | Typedefs | Functions
DataBox

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

Namespaces

 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::SimpleTag
 Tags for the DataBox inherit from this type. More...
 
struct  db::BaseTag
 Tags that are base tags, i.e. a simple or compute tag must derive off them for them to be useful. More...
 
struct  db::PrefixTag
 Marks an item as being a prefix to another tag. More...
 
struct  db::ComputeTag
 Marks a DataBoxTag as being a compute item that executes a function. More...
 
struct  db::is_compute_item< Tag, typename >
 Check if Tag derives off of db::ComputeTag. More...
 
struct  db::is_non_base_tag< Tag, typename >
 Check if Tag is a non-base DataBox tag. I.e. a SimpleTag or a ComputeTag. More...
 
struct  db::is_tag< Tag, typename >
 Check if Tag is a BaseTag, SimpleTag, or ComputeTag. More...
 
struct  db::is_base_tag< Tag, typename >
 Check if Tag is a base DataBox tag. More...
 
struct  db::Subitems< TagList, Tag, typename >
 Struct that can be specialized to allow DataBox items to have subitems. Specializations must define: More...
 
class  Deferred< Rt, MakeConstReference >
 Provides deferred or lazy evaluation of a function or function object, as well as efficient storage of an object that is mutable. More...
 

Typedefs

template<typename... Tags>
using db::RemoveTags = tmpl::flatten< tmpl::list< Tags... > >
 List of Tags to remove from the DataBox.
 
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<class TagList >
using db::get_compute_items = tmpl::filter< TagList, db::is_compute_item< tmpl::_1 > >
 Get all the Tags that are compute items from the TagList
 
template<class TagList >
using db::get_items = tmpl::filter< TagList, tmpl::not_< tmpl::bind< db::is_compute_item, tmpl::_1 > >>
 Get all the Tags that are items from the TagList
 
template<class TagList >
using db::compute_databox_type = typename DataBox_detail::compute_dbox_type< get_items< TagList >, get_compute_items< TagList > >::type
 Returns the type of the DataBox that would be constructed from the TagList of tags.
 
template<typename Tag , typename TagList = NoSuchType>
using db::item_type = typename DataBox_detail::item_type_impl< TagList, Tag >::type
 Get the type that is returned by the Tag. If it is a base tag then a TagList must be passed as a second argument.
 
template<typename Tag >
using db::remove_all_prefixes = typename DataBox_detail::remove_all_prefixes_impl< Tag, cpp17::is_base_of_v< db::PrefixTag, Tag > >::type
 Completely remove all prefix tags from a Tag.
 
template<typename Tag , typename NewTagsList >
using db::variables_tag_with_tags_list = typename DataBox_detail::variables_tag_with_tags_list_impl< DataBox_detail::tag_type< Tag > >::template f< Tag, NewTagsList >
 Change the tags contained in a possibly prefixed Variables tag. More...
 
template<typename Tag , typename TagList = NoSuchType>
using db::split_tag = tmpl::conditional_t< tmpl::size< typename Subitems< TagList, Tag >::type >::value==0, tmpl::list< Tag >, typename Subitems< TagList, Tag >::type >
 Split a tag into its subitems. Tag cannot be a base tag.
 

Functions

template<typename... MutateTags, typename TagList , typename Invokable , typename... Args>
void db::mutate (const gsl::not_null< DataBox< TagList > *> box, Invokable &&invokable, Args &&... args) noexcept
 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) noexcept
 Retrieve the item with tag Tag from the DataBox. More...
 
template<typename AddSimpleTags , typename AddComputeTags = tmpl::list<>, typename... Args>
constexpr auto db::create (Args &&... args)
 Create a new DataBox. More...
 
template<typename TagsList >
constexpr DataBox< TagsList > db::create_copy (const DataBox< TagsList > &box) noexcept
 Create a non-aliasing copy of the DataBox. That is, the new DataBox will not share items with the old one. More...
 
template<typename Type , typename TagList >
constexpr const Type & db::get_item_from_box (const DataBox< TagList > &box, const std::string &tag_name) noexcept
 Retrieve an item from the DataBox that has a tag with label tag_name and type Type More...
 
template<typename TagsList , typename F , typename BoxTags , typename... Args>
constexpr auto db::apply (F &&f, const DataBox< BoxTags > &box, Args &&... args)
 Apply the function f with argument Tags TagsList from DataBox box More...
 
template<typename MutateTags , typename ArgumentTags , typename F , typename BoxTags , typename... Args>
constexpr auto db::mutate_apply (F f, const gsl::not_null< DataBox< BoxTags > *> box, Args &&... args) noexcept(DataBox_detail::check_mutate_apply_mutate_tags(BoxTags{}, MutateTags{}) and DataBox_detail::check_mutate_apply_argument_tags(BoxTags{}, ArgumentTags{}) and noexcept(DataBox_detail::mutate_apply(f, box, MutateTags{}, ArgumentTags{}, std::forward< Args >(args)...)))
 Apply the function f mutating items MutateTags and taking as additional arguments ArgumentTags and args. More...
 
template<typename Tag >
std::string db::get_tag_name ()
 Get the name of a DataBoxTag, including prefixes. 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... >) noexcept
 Slices volume Tensors from a DataBox into a Variables More...
 
template<typename Rt , typename Fp , typename... Args>
Deferred< Rt > make_deferred (Fp f, Args &&... args) noexcept
 Create a deferred function call object. More...
 
template<typename RemoveTags , typename AddTags = tmpl::list<>, typename AddComputeTags = tmpl::list<>, typename TagsList , typename... Args>
constexpr auto db::create_from (db::DataBox< TagsList > &&box, Args &&... args) noexcept
 Create a new DataBox from an existing one adding or removing items and compute items. More...
 
template<typename Rt , typename Fp , typename... Args>
void update_deferred_args (const gsl::not_null< Deferred< Rt > *> deferred, Fp, Args &&... args) noexcept
 Change the arguments to the Deferred function. More...
 
template<typename Rt , typename Fp , typename... Args>
void update_deferred_args (const gsl::not_null< Deferred< Rt > *> deferred, Args &&... args) noexcept
 Change the arguments to the Deferred function. 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;
static std::string name() noexcept { return "Tag0"; }
};

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

struct ComputeTag0 : db::ComputeTag {
static std::string name() noexcept { return "ComputeTag0"; }
static constexpr auto function = multiply_by_two;
using argument_tags = tmpl::list<Tag0>;
};

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

struct ComputeLambda0 : db::ComputeTag {
static std::string name() noexcept { return "ComputeLambda0"; }
static constexpr double function(const double& a) { return 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 OverloadType : db::ComputeTag {
static std::string name() noexcept { return "OverloadType"; }
static constexpr double function(const int& a) noexcept { return 5 * a; }
static constexpr double function(const double& a) noexcept { return 3.2 * a; }
using argument_tags = tmpl::list<ArgumentTag>;
};

or be overloaded on the number of arguments:

template <typename ArgumentTag0, typename ArgumentTag1 = void>
struct OverloadNumberOfArgs : db::ComputeTag {
static std::string name() noexcept { return "OverloadNumberOfArgs"; }
static constexpr double function(const double& a) noexcept { return 3.2 * a; }
static constexpr double function(const double& a, const double& b) noexcept {
return a * b;
}
using argument_tags =
tmpl::conditional_t<cpp17::is_same_v<void, ArgumentTag1>,
tmpl::list<ArgumentTag0>,
tmpl::list<ArgumentTag0, ArgumentTag1>>;
};

Compute tag function templates are implemented as follows:

template <typename ArgumentTag>
struct ComputeTemplate : db::ComputeTag {
static std::string name() noexcept { return "ComputeTemplate"; }
template <typename T>
static constexpr T function(const T& a) noexcept {
return 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 ArrayComputeBase : Array<I>, db::ComputeTag {
static std::string name() noexcept { return "ArrayComputeBase"; }
static std::array<int, 3> function(const std::vector<double>& t) noexcept {
return {{static_cast<int>(t.size()), static_cast<int>(t[0]), -8}};
}
template <typename... Args>
static std::array<int, 2 + sizeof...(Args)> function(
const std::vector<double>& t, const Args&... args) noexcept {
return {{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 Subitms. 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 functions db::create and db::create_from 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::ComputeTag0,
test_databox_tags::ComputeTag1,
test_databox_tags::ComputeLambda0,
test_databox_tags::ComputeLambda1>>(
3.14, std::vector<double>{8.7, 93.2, 84.7}, "My Sample String"s);

To create a new DataBox from an existing one use the db::create_from function. The only time a new DataBox needs to be created is when tags need to be removed or added. Like db::create, db::create_from also takes typelists as explicit template parameter. The first template parameter is the list of tags to be removed, which is passed using db::RemoveTags, second is the list of simple tags to add, and the third is the list of compute tags to add. If tags are only removed then only the first template parameter needs to be specified. If tags are being removed and only simple tags are being added then only the first two template parameters need to be specified. Here is an example of removing a tag or compute tag:

const auto& box =
db::create_from<db::RemoveTags<test_databox_tags::Tag1>>(original_box);

Adding a simple tag is done using:

const auto& box =
db::create_from<db::RemoveTags<>,
original_box, "Yet another test string"s);

Adding a compute tag is done using:

auto simple_box = db::create<
db::AddSimpleTags<test_databox_tags::Tag0, test_databox_tags::Tag1,
test_databox_tags::Tag2>>(
3.14, std::vector<double>{8.7, 93.2, 84.7}, "My Sample String"s);
const auto& box =
db::create_from<db::RemoveTags<>, db::AddSimpleTags<>,
simple_box);

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>(
make_not_null(&original_box),
[](const gsl::not_null<double*> tag0,
const double& compute_tag0) {
CHECK(6.28 == compute_tag0);
*tag0 = 10.32;
(*tag1)[0] = 837.2;
},
db::get<test_databox_tags::ComputeTag0>(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>;
static std::string name() noexcept { return "Vector"; }
};

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 ArrayComputeBase : Array<I>, db::ComputeTag {
static std::string name() noexcept { return "ArrayComputeBase"; }
static std::array<int, 3> function(const std::vector<double>& t) noexcept {
return {{static_cast<int>(t.size()), static_cast<int>(t[0]), -8}};
}
template <typename... Args>
static std::array<int, 2 + sizeof...(Args)> function(
const std::vector<double>& t, const Args&... args) noexcept {
return {{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>
struct Array : virtual db::SimpleTag, ArrayBase<I> {
using type = std::array<int, 3>;
static std::string name() noexcept { return "Array"; }
};

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

We can even remove tags using their base tags with db::create_from:

const auto& box6 = db::create_from<
db::RemoveTags<TestTags::VectorBase<1>, TestTags::VectorBase<2>,
TestTags::ArrayBase<1>>>(box4);

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

◆ variables_tag_with_tags_list

template<typename Tag , typename NewTagsList >
using db::variables_tag_with_tags_list = typedef typename DataBox_detail::variables_tag_with_tags_list_impl< DataBox_detail::tag_type<Tag> >::template f<Tag, NewTagsList>

Change the tags contained in a possibly prefixed Variables tag.

Example

static_assert(
Prefix<Tags::Variables<tmpl::list<Prefix<Var>>>>,
tmpl::list<Prefix<Var2>>>,
Prefix<Tags::Variables<tmpl::list<Prefix<Var2>>>>>,
"Failed testing variables_tag_with_tags_list");

Function Documentation

◆ apply()

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

Apply the function f with argument Tags TagsList from DataBox box

Details

f must either be invokable with the arguments of type db::item_type<TagsList>..., Args... where the first pack expansion is over the elements in the type list TagsList, or have a static apply function that is callable with the same types.

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::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}));
};
tmpl::list<test_databox_tags::Tag2, test_databox_tags::ComputeTag1>>(
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) noexcept {
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}));
}
};
tmpl::list<test_databox_tags::Tag2, test_databox_tags::ComputeTag1>>(
ApplyCallable{}, original_box,
db::get<test_databox_tags::Tag1>(original_box));
See also
DataBox
Template Parameters
TagsListtypelist of Tags in the order that they are to be passed to f
Parameters
fthe function to apply
boxthe DataBox out of which to retrieve the Tags and to pass to f
argsthe arguments to pass to the function that are not in the DataBox, box

◆ create()

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

Create a new DataBox.

Details

Creates a new DataBox holding types Tags::type filled with the arguments passed to the function. Compute items must be added so that the dependencies of a compute item are added before the compute item. For example, say you have compute items A and B where B depends on A, then you must add them using db::AddComputeTags<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::ComputeTag0,
test_databox_tags::ComputeTag1,
test_databox_tags::ComputeLambda0,
test_databox_tags::ComputeLambda1>>(
3.14, std::vector<double>{8.7, 93.2, 84.7}, "My Sample String"s);
See also
create_from
Template Parameters
AddSimpleTagsthe tags of the args being added
AddComputeTagslist of compute item tags to add to the DataBox
Parameters
argsthe data to be added to the DataBox

◆ create_copy()

template<typename TagsList >
constexpr DataBox<TagsList> db::create_copy ( const DataBox< TagsList > &  box)
noexcept

Create a non-aliasing copy of the DataBox. That is, the new DataBox will not share items with the old one.

Warning
Currently all compute items will be reset in the new DataBox because copying of DataBoxes shouldn't be done in general. This does not lead to incorrect behavior, but is less efficient.
See also
db::create_from

◆ create_from()

template<typename RemoveTags , typename AddTags = tmpl::list<>, typename AddComputeTags = tmpl::list<>, typename TagsList , typename... Args>
constexpr auto db::create_from ( db::DataBox< TagsList > &&  box,
Args &&...  args 
)
noexcept

Create a new DataBox from an existing one adding or removing items and compute items.

When passed an lvalue this function will return a const DataBox whose members cannot be modified. When passed a (mutable) rvalue this function will return a mutable DataBox.

Note that in the const lvalue case the output DataBox shares all items that were not removed with the input DataBox. This means if an item is mutated in the input DataBox it is also mutated in the output DataBox. Similarly, if a compute item is evaluated in either the returned DataBox or the input DataBox it is evaluated in both (at the cost of only evaluating it once).

Example

Removing an item or compute item is done using:

const auto& box =
db::create_from<db::RemoveTags<test_databox_tags::Tag1>>(original_box);

Adding an item is done using:

const auto& box =
db::create_from<db::RemoveTags<>,
original_box, "Yet another test string"s);

Adding a compute item is done using:

auto simple_box = db::create<
db::AddSimpleTags<test_databox_tags::Tag0, test_databox_tags::Tag1,
test_databox_tags::Tag2>>(
3.14, std::vector<double>{8.7, 93.2, 84.7}, "My Sample String"s);
const auto& box =
db::create_from<db::RemoveTags<>, db::AddSimpleTags<>,
simple_box);
See also
create DataBox
Template Parameters
RemoveTagstypelist of Tags to remove
AddTagstypelist of Tags corresponding to the arguments to be added
AddComputeTagslist of compute item tags to add to the DataBox
Parameters
boxthe DataBox the new box should be based off
argsthe values for the items to add to the DataBox

Returns: DataBox like box but altered by RemoveTags and AddTags

◆ 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... >   
)
noexcept

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>{})

◆ get()

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

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_item_from_box()

template<typename Type , typename TagList >
constexpr const Type& db::get_item_from_box ( const DataBox< TagList > &  box,
const std::string tag_name 
)
noexcept

Retrieve an item from the DataBox that has a tag with label tag_name and type Type

Details

The type that the tag represents must be of the type Type, and the tag must have the label tag_name. The function iterates over all tags in the DataBox box that have the type Type searching linearly for one whose label matches tag_name.

Example

auto original_box = db::create<
db::AddSimpleTags<test_databox_tags::Tag0, test_databox_tags::Tag1,
test_databox_tags::Tag2,
test_databox_tags::TagPrefix<test_databox_tags::Tag0>>,
db::AddComputeTags<test_databox_tags::ComputeTag0,
test_databox_tags::ComputeTag1>>(
3.14, std::vector<double>{8.7, 93.2, 84.7}, "My Sample String"s, 8.7);
const auto& compute_string =
db::get_item_from_box<std::string>(original_box, "ComputeTag1");
Template Parameters
Typethe type of the tag with the label tag_name
Parameters
boxthe DataBox through which to search
tag_namethe label of the tag to retrieve

◆ get_tag_name()

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

Get the name of a DataBoxTag, including prefixes.

Details

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

Template Parameters
Tagthe DataBoxTag whose name to get

Returns: string holding the DataBoxTag's name

◆ make_deferred()

template<typename Rt , typename Fp , typename... Args>
Deferred<Rt> make_deferred ( Fp  f,
Args &&...  args 
)
noexcept

Create a deferred function call object.

If creating a Deferred with a function object the call operator of the function object must be marked const currently. Since the function object will only be evaluated once there currently seems to be no reason to allow mutating call operators.

Example

The examples below use the following functions:

struct func {
double operator()() const { return 8.2; }
};
double dummy() { return 6.7; }
struct func2 {
double operator()(const double& t) const { return t; }
};
double lazy_function(const double t) { return 10.0 * t; }
void mutate_function(const gsl::not_null<double*> t, const double t0) {
*t = t0;
}
void mutate_function_vector(const gsl::not_null<std::vector<double>*> t,
const std::vector<double>& t0) {
if (t->size() != t0.size()) {
t->resize(t0.size(), 0.0);
}
// Check the size again just to be sure the resize above happened.
CHECK(t->size() == t0.size());
for (size_t i = 0; i < t->size(); ++i) {
t->operator[](i) = 10.0 * t0[i];
}
}

To create a Deferred using a function object use:

auto def = make_deferred<double>(func{});
CHECK_FALSE(def.evaluated());
CHECK(8.2 == def.get());

or using a regular function:

auto def2 = make_deferred<double>(dummy);
CHECK(6.7 == def2.get());

It is also possible to pass Deferred objects to a deferred function call:

auto def2 = make_deferred<double>(func2{}, 6.82);
auto def3 = make_deferred<double>(lazy_function, def2);
CHECK(68.2 == def3.get());
CHECK(6.82 == def2.get());

in which case the first function will be evaluated just before the second function is evaluated.

In addition to functions that return by value, it is also possible to use functions that return by reference. The first argument of the function must then be a gsl::not_null<Rt*>, and can be mutated inside the function. The mutating functions are primarily useful if Rt performs heap allocations and is frequently recomputed in a manner where the heap allocation could be avoided.

Template Parameters
Rtthe type of the object returned by the function

Returns: Deferred object that will lazily evaluate the function

◆ mutate()

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

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

mutate()'s first 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>(
make_not_null(&original_box),
[](const gsl::not_null<double*> tag0,
const double& compute_tag0) {
CHECK(6.28 == compute_tag0);
*tag0 = 10.32;
(*tag1)[0] = 837.2;
},
db::get<test_databox_tags::ComputeTag0>(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]);

◆ mutate_apply()

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

Apply the function 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::item_type<ArgumentTags>..., Args... where the first two pack expansions are over the elements in the type lists MutateTags and ArgumentTags, or have a static apply function that is callable with the same types.

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 test_databox_mutate_apply {
static void apply(const gsl::not_null<Scalar<DataVector>*> scalar,
const gsl::not_null<tnsr::I<DataVector, 3>*> vector,
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

tmpl::list<test_databox_tags::ScalarTag, test_databox_tags::VectorTag>,
tmpl::list<>>(test_databox_mutate_apply{}, make_not_null(&box),
db::get<test_databox_tags::Tag2>(box));
See also
box
Template Parameters
MutateTagstypelist of Tags to mutate
ArgumentTagstypelist of additional items to retrieve from the DataBox
Parameters
fthe function to apply
boxthe DataBox out of which to retrieve the Tags and to pass to f
argsthe arguments to pass to the function that are not in the DataBox, box

◆ update_deferred_args() [1/2]

template<typename Rt , typename Fp , typename... Args>
void update_deferred_args ( const gsl::not_null< Deferred< Rt > *>  deferred,
Fp  ,
Args &&...  args 
)
noexcept

Change the arguments to the Deferred function.

In order to make mutating Deferred functions really powerful, the args to them must be updated without destructing the held Rt object. The type of Fp (the invokable being lazily evaluated) as well as the types of the std::decay_t<Args>... must match their respective types at the time of creation of the Deferred object.

Example

You can avoid specifying the type of the function held by the Deferred class by passing the function as a second argument:

auto mutate_deferred = make_deferred<std::vector<double>>(
mutate_function_vector, std::vector<double>{1.3, 7.8, 9.8});
CHECK(mutate_deferred.get() == (std::vector<double>{13., 78., 98.}));
update_deferred_args(make_not_null(&mutate_deferred), mutate_function_vector,
std::vector<double>{10., 70., 90.});
CHECK(mutate_deferred.get() == (std::vector<double>{100., 700., 900.}));

You can also specify the type of the function held by the Deferred explicitly as follows:

update_deferred_args<std::vector<double>, decltype(mutate_function_vector)>(
&mutate_deferred, std::vector<double>{20., 8., 9.});
CHECK(mutate_deferred.get() == (std::vector<double>{200., 80., 90.}));

◆ update_deferred_args() [2/2]

template<typename Rt , typename Fp , typename... Args>
void update_deferred_args ( const gsl::not_null< Deferred< Rt > *>  deferred,
Args &&...  args 
)
noexcept

Change the arguments to the Deferred function.

In order to make mutating Deferred functions really powerful, the args to them must be updated without destructing the held Rt object. The type of Fp (the invokable being lazily evaluated) as well as the types of the std::decay_t<Args>... must match their respective types at the time of creation of the Deferred object.

Example

You can avoid specifying the type of the function held by the Deferred class by passing the function as a second argument:

auto mutate_deferred = make_deferred<std::vector<double>>(
mutate_function_vector, std::vector<double>{1.3, 7.8, 9.8});
CHECK(mutate_deferred.get() == (std::vector<double>{13., 78., 98.}));
update_deferred_args(make_not_null(&mutate_deferred), mutate_function_vector,
std::vector<double>{10., 70., 90.});
CHECK(mutate_deferred.get() == (std::vector<double>{100., 700., 900.}));

You can also specify the type of the function held by the Deferred explicitly as follows:

update_deferred_args<std::vector<double>, decltype(mutate_function_vector)>(
&mutate_deferred, std::vector<double>{20., 8., 9.});
CHECK(mutate_deferred.get() == (std::vector<double>{200., 80., 90.}));