FirstOrderSystem.hpp
Go to the documentation of this file.
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 /// \file
5 /// Helper functions to test elliptic first-order systems
6 
7 #pragma once
8 
9 #include <cstddef>
10 #include <limits>
11 #include <random>
12 #include <tuple>
13 
15 #include "DataStructures/DataBox/PrefixHelpers.hpp"
17 #include "DataStructures/DataBox/Tag.hpp"
18 #include "DataStructures/DataVector.hpp"
20 #include "DataStructures/VariablesTag.hpp"
24 #include "Utilities/Gsl.hpp"
25 #include "Utilities/TMPL.hpp"
26 #include "Utilities/TaggedTuple.hpp"
27 
28 namespace TestHelpers {
29 /// \ingroup TestingFrameworkGroup
30 /// Helper functions to test elliptic first-order systems
31 namespace elliptic {
32 namespace detail {
33 
34 template <typename FluxesComputer, typename... PrimalFields,
35  typename... AuxiliaryFields, typename... PrimalFluxes,
36  typename... AuxiliaryFluxes, typename... FluxesArgsTags>
37 void test_first_order_fluxes_computer_impl(
38  const DataVector& used_for_size, tmpl::list<PrimalFields...> /*meta*/,
39  tmpl::list<AuxiliaryFields...> /*meta*/,
40  tmpl::list<PrimalFluxes...> /*meta*/,
41  tmpl::list<AuxiliaryFluxes...> /*meta*/,
42  tmpl::list<FluxesArgsTags...> /*meta*/) {
43  using vars_tag =
44  ::Tags::Variables<tmpl::list<PrimalFields..., AuxiliaryFields...>>;
45  using VarsType = typename vars_tag::type;
46  using fluxes_tag =
47  ::Tags::Variables<tmpl::list<PrimalFluxes..., AuxiliaryFluxes...>>;
48  using FluxesType = typename fluxes_tag::type;
49 
50  MAKE_GENERATOR(generator);
52 
53  // Generate random variables
54  const auto vars = make_with_random_values<VarsType>(
55  make_not_null(&generator), make_not_null(&dist), used_for_size);
56 
57  // Generate fluxes from the variables with random arguments
58  tuples::TaggedTuple<FluxesArgsTags...> fluxes_args{
59  make_with_random_values<typename FluxesArgsTags::type>(
60  make_not_null(&generator), make_not_null(&dist), used_for_size)...};
61  // Silence unused variable warning when fluxes args is empty
62  (void)fluxes_args;
63  FluxesType expected_fluxes{used_for_size.size()};
64  FluxesComputer::apply(make_not_null(&get<PrimalFluxes>(expected_fluxes))...,
65  get<FluxesArgsTags>(fluxes_args)...,
66  get<AuxiliaryFields>(vars)...);
67  FluxesComputer::apply(
68  make_not_null(&get<AuxiliaryFluxes>(expected_fluxes))...,
69  get<FluxesArgsTags>(fluxes_args)..., get<PrimalFields>(vars)...);
70 
71  // Create a DataBox
72  auto box =
73  db::create<db::AddSimpleTags<vars_tag, fluxes_tag, FluxesArgsTags...>>(
74  vars,
75  make_with_value<typename fluxes_tag::type>(
77  get<FluxesArgsTags>(fluxes_args)...);
78 
79  // Apply the fluxes computer to the DataBox
80  db::mutate_apply<tmpl::list<PrimalFluxes...>,
81  tmpl::list<FluxesArgsTags..., AuxiliaryFields...>>(
82  FluxesComputer{}, make_not_null(&box));
83  db::mutate_apply<tmpl::list<AuxiliaryFluxes...>,
84  tmpl::list<FluxesArgsTags..., PrimalFields...>>(
85  FluxesComputer{}, make_not_null(&box));
86  CHECK(expected_fluxes == get<fluxes_tag>(box));
87 }
88 
89 } // namespace detail
90 
91 /*!
92  * \brief Test the `System::fluxes_computer` is functional
93  *
94  * This function tests the following properties of the
95  * `System::fluxes_computer`:
96  *
97  * - It works with the fields and fluxes specified in the `System`.
98  * - It can be applied to a DataBox, i.e. its argument tags are consistent with
99  * its apply function.
100  */
101 template <typename System>
102 void test_first_order_fluxes_computer(const DataVector& used_for_size) {
103  detail::test_first_order_fluxes_computer_impl<
104  typename System::fluxes_computer>(
105  used_for_size, typename System::primal_fields{},
106  typename System::auxiliary_fields{}, typename System::primal_fluxes{},
107  typename System::auxiliary_fluxes{},
108  typename System::fluxes_computer::argument_tags{});
109 }
110 
111 namespace detail {
112 
113 template <typename SourcesComputer, typename... PrimalFields,
114  typename... AuxiliaryFields, typename... PrimalFluxes,
115  typename... SourcesArgsTags>
116 void test_first_order_sources_computer_impl(
117  const DataVector& used_for_size, tmpl::list<PrimalFields...> /*meta*/,
118  tmpl::list<AuxiliaryFields...> /*meta*/,
119  tmpl::list<PrimalFluxes...> /*meta*/,
120  tmpl::list<SourcesArgsTags...> /*meta*/) {
121  using vars_tag =
122  ::Tags::Variables<tmpl::list<PrimalFields..., AuxiliaryFields...>>;
123  using VarsType = typename vars_tag::type;
124  using fluxes_tag = ::Tags::Variables<tmpl::list<PrimalFluxes...>>;
125  using FluxesType = typename fluxes_tag::type;
127  using SourcesType = typename sources_tag::type;
128 
129  MAKE_GENERATOR(generator);
130  std::uniform_real_distribution<> dist(0.5, 2.);
131 
132  // Generate random variables and fluxes. Note that the sources make use of the
133  // pre-computed fluxes as an optimization (see elliptic::first_order_sources),
134  // but for the purpose of this random-value test the fluxes don't have to be
135  // computed from the variables.
136  const auto vars = make_with_random_values<VarsType>(
137  make_not_null(&generator), make_not_null(&dist), used_for_size);
138  const auto fluxes = make_with_random_values<FluxesType>(
139  make_not_null(&generator), make_not_null(&dist), used_for_size);
140 
141  // Generate sources from the variables with random arguments
142  tuples::TaggedTuple<SourcesArgsTags...> sources_args{
143  make_with_random_values<typename SourcesArgsTags::type>(
144  make_not_null(&generator), make_not_null(&dist), used_for_size)...};
145  // Silence unused variable warning when sources args is empty
146  (void)sources_args;
147  SourcesType expected_sources{used_for_size.size(), 0.};
148  SourcesComputer::apply(
149  make_not_null(&get<::Tags::Source<AuxiliaryFields>>(expected_sources))...,
150  get<SourcesArgsTags>(sources_args)..., get<PrimalFields>(vars)...);
151  SourcesComputer::apply(
152  make_not_null(&get<::Tags::Source<PrimalFields>>(expected_sources))...,
153  get<SourcesArgsTags>(sources_args)..., get<PrimalFields>(vars)...,
154  get<PrimalFluxes>(fluxes)...);
155 
156  // Create a DataBox
157  auto box = db::create<
158  db::AddSimpleTags<vars_tag, fluxes_tag, sources_tag, SourcesArgsTags...>>(
159  vars, fluxes,
160  make_with_value<typename sources_tag::type>(used_for_size, 0.),
161  get<SourcesArgsTags>(sources_args)...);
162 
163  // Apply the sources computer to the DataBox
164  db::mutate_apply<tmpl::list<::Tags::Source<AuxiliaryFields>...>,
165  tmpl::list<SourcesArgsTags..., PrimalFields...>>(
166  SourcesComputer{}, make_not_null(&box));
168  tmpl::list<::Tags::Source<PrimalFields>...>,
169  tmpl::list<SourcesArgsTags..., PrimalFields..., PrimalFluxes...>>(
170  SourcesComputer{}, make_not_null(&box));
171  CHECK(expected_sources == get<sources_tag>(box));
172 }
173 
174 } // namespace detail
175 
176 /*!
177  * \brief Test the `System::sources_computer` is functional
178  *
179  * This function tests the following properties of the
180  * `System::sources_computer`:
181  *
182  * - It works with the fields and fluxes specified in the `System`.
183  * - It can be applied to a DataBox, i.e. its argument tags are consistent with
184  * its apply function.
185  */
186 template <typename System>
187 void test_first_order_sources_computer(const DataVector& used_for_size) {
188  using sources_computer = typename System::sources_computer;
189  detail::test_first_order_sources_computer_impl<sources_computer>(
190  used_for_size, typename System::primal_fields{},
191  typename System::auxiliary_fields{}, typename System::primal_fluxes{},
192  typename sources_computer::argument_tags{});
193 }
194 
195 } // namespace elliptic
196 } // namespace TestHelpers
get
constexpr Tag::type & get(Variables< TagList > &v) noexcept
Return Tag::type pointing into the contiguous array.
Definition: Variables.hpp:660
TestingFramework.hpp
db::add_tag_prefix
typename detail::add_tag_prefix_impl< Prefix, Tag, Args... >::type add_tag_prefix
Definition: PrefixHelpers.hpp:51
random
Tags::Variables
Definition: VariablesTag.hpp:21
MakeWithRandomValues.hpp
tuple
TestHelpers::elliptic::test_first_order_sources_computer
void test_first_order_sources_computer(const DataVector &used_for_size)
Test the System::sources_computer is functional.
Definition: FirstOrderSystem.hpp:187
std::uniform_real_distribution
TestHelpers.hpp
db::create
constexpr auto create(Args &&... args)
Create a new DataBox.
Definition: DataBox.hpp:853
DataBox.hpp
cstddef
tuples::TaggedTuple
An associative container that is indexed by structs.
Definition: TaggedTuple.hpp:271
DataVector
Stores a collection of function values.
Definition: DataVector.hpp:46
MAKE_GENERATOR
#define MAKE_GENERATOR(...)
MAKE_GENERATOR(NAME [, SEED]) declares a variable of name NAME containing a generator of type std::mt...
Definition: TestHelpers.hpp:433
Variables.hpp
db::AddSimpleTags
tmpl::flatten< tmpl::list< Tags... > > AddSimpleTags
List of Tags to add to the DataBox.
Definition: DataBox.hpp:802
limits
Gsl.hpp
elliptic
Functionality related to solving elliptic partial differential equations.
Definition: InitializeAnalyticSolution.hpp:29
db::mutate_apply
constexpr decltype(auto) mutate_apply(F &&f, const gsl::not_null< DataBox< BoxTags > * > box, Args &&... args) noexcept
Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and a...
Definition: DataBox.hpp:1193
make_not_null
gsl::not_null< T * > make_not_null(T *ptr) noexcept
Construct a not_null from a pointer. Often this will be done as an implicit conversion,...
Definition: Gsl.hpp:880
Tags::Source
Prefix indicating a source term.
Definition: Prefixes.hpp:66
Prefixes.hpp
std::numeric_limits
TMPL.hpp
TestHelpers::elliptic::test_first_order_fluxes_computer
void test_first_order_fluxes_computer(const DataVector &used_for_size)
Test the System::fluxes_computer is functional.
Definition: FirstOrderSystem.hpp:102