ElementActions.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <cstddef>
7 #include <map>
8 #include <string>
9 #include <tuple>
10 #include <unordered_map>
11 #include <utility>
12 #include <vector>
13 
15 #include "DataStructures/DataBox/PrefixHelpers.hpp"
16 #include "DataStructures/DataBox/Tag.hpp"
17 #include "DataStructures/Index.hpp"
18 #include "Domain/InterfaceComputeTags.hpp"
19 #include "Domain/InterfaceHelpers.hpp"
22 #include "Domain/Structure/OrientationMapHelpers.hpp"
23 #include "Domain/Tags.hpp"
24 #include "IO/Observer/Actions/RegisterWithObservers.hpp"
25 #include "IO/Observer/ArrayComponentId.hpp"
26 #include "IO/Observer/ObservationId.hpp"
27 #include "IO/Observer/ReductionActions.hpp"
28 #include "IO/Observer/TypeOfObservation.hpp"
29 #include "Informer/Tags.hpp"
30 #include "Informer/Verbosity.hpp"
31 #include "NumericalAlgorithms/Convergence/Tags.hpp"
32 #include "NumericalAlgorithms/LinearSolver/Gmres.hpp"
35 #include "Options/Options.hpp"
36 #include "Parallel/GlobalCache.hpp"
37 #include "Parallel/InboxInserters.hpp"
38 #include "Parallel/Info.hpp"
39 #include "Parallel/Invoke.hpp"
40 #include "Parallel/ParallelComponentHelpers.hpp"
41 #include "Parallel/Printf.hpp"
42 #include "Parallel/Reduction.hpp"
43 #include "ParallelAlgorithms/DiscontinuousGalerkin/HasReceivedFromAllMortars.hpp"
44 #include "ParallelAlgorithms/Initialization/MergeIntoDataBox.hpp"
45 #include "ParallelAlgorithms/Initialization/MutateAssign.hpp"
47 #include "ParallelAlgorithms/LinearSolver/Schwarz/ComputeTags.hpp"
48 #include "ParallelAlgorithms/LinearSolver/Schwarz/ElementCenteredSubdomainData.hpp"
49 #include "ParallelAlgorithms/LinearSolver/Schwarz/OverlapHelpers.hpp"
50 #include "ParallelAlgorithms/LinearSolver/Schwarz/Protocols.hpp"
51 #include "ParallelAlgorithms/LinearSolver/Schwarz/Tags.hpp"
53 #include "Utilities/Gsl.hpp"
54 #include "Utilities/PrettyType.hpp"
55 #include "Utilities/ProtocolHelpers.hpp"
56 #include "Utilities/TMPL.hpp"
57 #include "Utilities/TaggedTuple.hpp"
58 
59 namespace LinearSolver::Schwarz::detail {
60 
61 using reduction_data = Parallel::ReductionData<
62  // Iteration
64  // Number of subdomains (= number of elements)
66  // Average number of subdomain solver iterations
69  // Minimum number of subdomain solver iterations
71  // Maximum number of subdomain solver iterations
73 
74 template <typename OptionsGroup>
75 struct RegisterObservers {
76  template <typename ParallelComponent, typename DbTagsList,
77  typename ArrayIndex>
79  register_info(const db::DataBox<DbTagsList>& /*box*/,
80  const ArrayIndex& /*array_index*/) noexcept {
82  observers::ObservationKey{pretty_type::get_name<OptionsGroup>() +
83  "SubdomainSolves"}};
84  }
85 };
86 
87 template <typename FieldsTag, typename OptionsGroup, typename SourceTag>
88 using RegisterElement =
90 
91 template <typename OptionsGroup, typename ParallelComponent,
92  typename Metavariables, typename ArrayIndex>
93 void contribute_to_subdomain_stats_observation(
94  const size_t iteration_id, const size_t subdomain_solve_num_iterations,
96  const ArrayIndex& array_index) noexcept {
97  auto& local_observer =
98  *Parallel::get_parallel_component<observers::Observer<Metavariables>>(
99  cache)
100  .ckLocalBranch();
101  Parallel::simple_action<observers::Actions::ContributeReductionData>(
102  local_observer,
104  iteration_id,
105  pretty_type::get_name<OptionsGroup>() + "SubdomainSolves"),
108  Parallel::ArrayIndex<ArrayIndex>(array_index)},
109  std::string{"/" + Options::name<OptionsGroup>() + "SubdomainSolves"},
110  std::vector<std::string>{"Iteration", "NumSubdomains", "AvgNumIterations",
111  "MinNumIterations", "MaxNumIterations"},
112  reduction_data{iteration_id, 1, subdomain_solve_num_iterations,
113  subdomain_solve_num_iterations,
114  subdomain_solve_num_iterations});
115 }
116 
117 template <typename SubdomainDataType, typename OptionsGroup>
118 struct SubdomainDataBufferTag : db::SimpleTag {
119  static std::string name() noexcept {
120  return "SubdomainData(" + Options::name<OptionsGroup>() + ")";
121  }
122  using type = SubdomainDataType;
123 };
124 
125 template <typename FieldsTag, typename OptionsGroup, typename SubdomainOperator>
126 struct InitializeElement {
127  private:
128  using fields_tag = FieldsTag;
129  using residual_tag =
131  static constexpr size_t Dim = SubdomainOperator::volume_dim;
132  using SubdomainData =
133  ElementCenteredSubdomainData<Dim, typename residual_tag::tags_list>;
134  // Here we choose a serial GMRES linear solver to solve subdomain problems.
135  // This can be generalized to allow the user to make this choice once that
136  // becomes necessary.
137  using subdomain_solver_tag =
138  Tags::SubdomainSolver<LinearSolver::Serial::Gmres<SubdomainData>,
139  OptionsGroup>;
140 
141  public:
142  using initialization_tags =
143  tmpl::list<domain::Tags::InitialExtents<Dim>, subdomain_solver_tag>;
144  using initialization_tags_to_keep = tmpl::list<subdomain_solver_tag>;
145  using const_global_cache_tags = tmpl::list<Tags::MaxOverlap<OptionsGroup>>;
146 
147  using simple_tags =
148  tmpl::list<Tags::Overlaps<residual_tag, Dim, OptionsGroup>,
149  SubdomainDataBufferTag<SubdomainData, OptionsGroup>>;
150  using compute_tags = tmpl::list<
158  Tags::IntrudingExtentsCompute<Dim, OptionsGroup>,
159  Tags::IntrudingOverlapWidthsCompute<Dim, OptionsGroup>,
161  Tags::ElementWeightCompute<Dim, OptionsGroup>,
164  Tags::IntrudingOverlapWeightCompute<Dim, OptionsGroup>>>;
165  template <typename DbTagsList, typename... InboxTags, typename Metavariables,
166  typename ActionList, typename ParallelComponent>
167  static auto apply(db::DataBox<DbTagsList>& box,
168  const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
169  const Parallel::GlobalCache<Metavariables>& /*cache*/,
170  const ElementId<Dim>& /*element_id*/,
171  const ActionList /*meta*/,
172  const ParallelComponent* const /*meta*/) noexcept {
173  const auto& element_mesh = db::get<domain::Tags::Mesh<Dim>>(box);
174  const size_t element_num_points = element_mesh.number_of_grid_points();
176  tmpl::list<SubdomainDataBufferTag<SubdomainData, OptionsGroup>>>(
177  make_not_null(&box), SubdomainData{element_num_points});
178  return std::make_tuple(std::move(box));
179  }
180 };
181 
182 // Restrict the residual to neighboring subdomains that overlap with this
183 // element and send the data to those elements
184 template <typename FieldsTag, typename OptionsGroup, typename SubdomainOperator>
186  tmpl::list<db::add_tag_prefix<LinearSolver::Tags::Residual, FieldsTag>>,
187  OptionsGroup, true>;
188 
189 // Wait for the residual data on regions of this element's subdomain that
190 // overlap with other elements.
191 template <typename FieldsTag, typename OptionsGroup, typename SubdomainOperator>
193  SubdomainOperator::volume_dim,
194  tmpl::list<db::add_tag_prefix<LinearSolver::Tags::Residual, FieldsTag>>,
195  OptionsGroup>;
196 
197 template <size_t Dim, typename OptionsGroup, typename OverlapSolution>
198 struct OverlapSolutionInboxTag
200  OverlapSolutionInboxTag<Dim, OptionsGroup, OverlapSolution>> {
201  using temporal_id = size_t;
203 };
204 
205 // Once the residual data is available on all overlaps, solve the restricted
206 // problem for this element-centered subdomain. Apply the weighted solution on
207 // this element directly and send the solution on overlap regions to the
208 // neighbors that they overlap with.
209 template <typename FieldsTag, typename OptionsGroup, typename SubdomainOperator>
210 struct SolveSubdomain {
211  private:
212  using fields_tag = FieldsTag;
213  using residual_tag =
215  static constexpr size_t Dim = SubdomainOperator::volume_dim;
216  using SubdomainData =
217  ElementCenteredSubdomainData<Dim, typename residual_tag::tags_list>;
218  using OverlapData = typename SubdomainData::OverlapData;
219  using overlap_solution_inbox_tag =
220  OverlapSolutionInboxTag<Dim, OptionsGroup, OverlapData>;
221 
222  public:
223  using const_global_cache_tags =
224  tmpl::list<Tags::MaxOverlap<OptionsGroup>,
226 
227  template <typename DbTagsList, typename... InboxTags, typename Metavariables,
228  typename ActionList, typename ParallelComponent>
230  db::DataBox<DbTagsList>& box,
231  const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
233  const ElementId<Dim>& element_id, const ActionList /*meta*/,
234  const ParallelComponent* const /*meta*/) noexcept {
235  const size_t iteration_id =
236  get<Convergence::Tags::IterationId<OptionsGroup>>(box);
237 
238  // Do some logging
240  ::Verbosity::Debug)) {
242  "%s " + Options::name<OptionsGroup>() + "(%zu): Solve subdomain\n",
243  element_id, iteration_id);
244  }
245 
246  const auto& element = db::get<domain::Tags::Element<Dim>>(box);
247  const size_t max_overlap = db::get<Tags::MaxOverlap<OptionsGroup>>(box);
248 
249  // Assemble the subdomain data from the data on the element and the
250  // communicated overlap data
251  db::mutate<SubdomainDataBufferTag<SubdomainData, OptionsGroup>,
252  Tags::Overlaps<residual_tag, Dim, OptionsGroup>>(
253  make_not_null(&box),
254  [max_overlap, &element](
255  const gsl::not_null<SubdomainData*> subdomain_data,
256  const auto overlap_residuals, const auto& residual) noexcept {
257  subdomain_data->element_data = residual;
258  // Nothing was communicated if the overlaps are empty
259  if (LIKELY(max_overlap > 0 and element.number_of_neighbors() > 0)) {
260  subdomain_data->overlap_data = std::move(*overlap_residuals);
261  }
262  },
263  db::get<residual_tag>(box));
264  const auto& subdomain_residual =
265  db::get<SubdomainDataBufferTag<SubdomainData, OptionsGroup>>(box);
266 
267  // Allocate workspace memory for repeatedly applying the subdomain operator
268  const size_t num_points =
269  db::get<domain::Tags::Mesh<Dim>>(box).number_of_grid_points();
270  SubdomainOperator subdomain_operator{num_points};
271  auto subdomain_result_buffer =
272  make_with_value<SubdomainData>(subdomain_residual, 0.);
273 
274  // Construct the subdomain operator
275  const auto apply_subdomain_operator = [&box, &subdomain_result_buffer,
276  &subdomain_operator](
277  const SubdomainData&
278  arg) noexcept {
279  // The subdomain operator can retrieve any information on the subdomain
280  // geometry that is available through the DataBox. The user is responsible
281  // for communicating this information across neighbors if necessary.
282  db::apply<typename SubdomainOperator::element_operator>(
283  box, arg, make_not_null(&subdomain_result_buffer),
284  make_not_null(&subdomain_operator));
285  tmpl::for_each<tmpl::list<domain::Tags::InternalDirections<Dim>,
287  [&box, &arg, &subdomain_result_buffer,
288  &subdomain_operator](auto directions_v) noexcept {
289  using directions = tmpl::type_from<decltype(directions_v)>;
290  using face_operator =
291  typename SubdomainOperator::template face_operator<directions>;
292  interface_apply<directions, face_operator>(
293  box, arg, make_not_null(&subdomain_result_buffer),
294  make_not_null(&subdomain_operator));
295  });
296  return subdomain_result_buffer;
297  };
298 
299  // Solve the subdomain problem
300  const auto& subdomain_solver =
301  get<Tags::SubdomainSolverBase<OptionsGroup>>(box);
302  Convergence::HasConverged subdomain_solve_has_converged{};
303  std::tie(subdomain_solve_has_converged, subdomain_result_buffer) =
304  subdomain_solver(
305  apply_subdomain_operator, subdomain_residual,
306  make_with_value<SubdomainData>(subdomain_residual, 0.));
307  // We're re-using the buffer to store the subdomain solution. Re-naming it
308  // here for the code below.
309  auto& subdomain_solution = subdomain_result_buffer;
310 
311  // Do some logging and observing
313  ::Verbosity::Quiet)) {
314  if (not subdomain_solve_has_converged or
315  subdomain_solve_has_converged.reason() ==
316  Convergence::Reason::MaxIterations) {
318  "%s WARNING: Subdomain solver did not converge in %zu iterations: "
319  "%e -> %e\n",
320  element_id, subdomain_solve_has_converged.num_iterations(),
321  subdomain_solve_has_converged.initial_residual_magnitude(),
322  subdomain_solve_has_converged.residual_magnitude());
324  ::Verbosity::Debug)) {
326  "%s Subdomain solver converged in %zu iterations (%s): %e -> %e\n",
327  element_id, subdomain_solve_has_converged.num_iterations(),
328  subdomain_solve_has_converged.reason(),
329  subdomain_solve_has_converged.initial_residual_magnitude(),
330  subdomain_solve_has_converged.residual_magnitude());
331  }
332  }
333  contribute_to_subdomain_stats_observation<OptionsGroup, ParallelComponent>(
334  iteration_id + 1, subdomain_solve_has_converged.num_iterations(), cache,
335  element_id);
336 
337  // Apply weighting
338  if (LIKELY(max_overlap > 0)) {
339  subdomain_solution.element_data *=
340  get(db::get<Tags::Weight<OptionsGroup>>(box));
341  }
342 
343  // Apply solution to central element
344  db::mutate<fields_tag>(make_not_null(&box),
345  [&subdomain_solution](const auto fields) noexcept {
346  *fields += subdomain_solution.element_data;
347  });
348 
349  // Send overlap solutions back to the neighbors that they are on
350  if (LIKELY(max_overlap > 0)) {
351  auto& receiver_proxy =
352  Parallel::get_parallel_component<ParallelComponent>(cache);
353  for (auto& [overlap_id, overlap_solution] :
354  subdomain_solution.overlap_data) {
355  const auto& direction = overlap_id.first;
356  const auto& neighbor_id = overlap_id.second;
357  const auto& orientation =
358  element.neighbors().at(direction).orientation();
359  const auto direction_from_neighbor = orientation(direction.opposite());
360  Parallel::receive_data<overlap_solution_inbox_tag>(
361  receiver_proxy[neighbor_id], iteration_id,
362  std::make_pair(
363  OverlapId<Dim>{direction_from_neighbor, element.id()},
364  std::move(overlap_solution)));
365  }
366  }
367  return {std::move(box)};
368  }
369 };
370 
371 // Wait for the subdomain solutions on regions within this element that overlap
372 // with neighboring element-centered subdomains. Combine the solutions as a
373 // weighted sum.
374 template <typename FieldsTag, typename OptionsGroup, typename SubdomainOperator>
375 struct ReceiveOverlapSolution {
376  private:
377  using fields_tag = FieldsTag;
378  using residual_tag =
380  static constexpr size_t Dim = SubdomainOperator::volume_dim;
381  using SubdomainData =
382  ElementCenteredSubdomainData<Dim, typename residual_tag::tags_list>;
383  using OverlapSolution = typename SubdomainData::OverlapData;
384  using overlap_solution_inbox_tag =
385  OverlapSolutionInboxTag<Dim, OptionsGroup, OverlapSolution>;
386 
387  public:
388  using const_global_cache_tags = tmpl::list<Tags::MaxOverlap<OptionsGroup>>;
389  using inbox_tags = tmpl::list<overlap_solution_inbox_tag>;
390 
391  template <typename DbTagsList, typename... InboxTags, typename Metavariables,
392  size_t Dim>
393  static bool is_ready(const db::DataBox<DbTagsList>& box,
394  const tuples::TaggedTuple<InboxTags...>& inboxes,
395  const Parallel::GlobalCache<Metavariables>& /*cache*/,
396  const ElementId<Dim>& /*element_id*/) noexcept {
397  if (UNLIKELY(db::get<Tags::MaxOverlap<OptionsGroup>>(box) == 0)) {
398  return true;
399  }
400  return dg::has_received_from_all_mortars<overlap_solution_inbox_tag>(
402  get<domain::Tags::Element<Dim>>(box), inboxes);
403  }
404 
405  template <typename DbTagsList, typename... InboxTags, typename Metavariables,
406  typename ActionList, typename ParallelComponent>
408  db::DataBox<DbTagsList>& box, tuples::TaggedTuple<InboxTags...>& inboxes,
409  const Parallel::GlobalCache<Metavariables>& /*cache*/,
410  const ElementId<Dim>& element_id, const ActionList /*meta*/,
411  const ParallelComponent* const /*meta*/) noexcept {
412  const size_t iteration_id =
413  get<Convergence::Tags::IterationId<OptionsGroup>>(box);
414  const auto& element = db::get<domain::Tags::Element<Dim>>(box);
415 
416  // Nothing to do if overlap is empty
417  if (UNLIKELY(db::get<Tags::MaxOverlap<OptionsGroup>>(box) == 0 or
418  element.number_of_neighbors() == 0)) {
419  return {std::move(box)};
420  }
421 
422  // Do some logging
424  ::Verbosity::Debug)) {
425  Parallel::printf("%s " + Options::name<OptionsGroup>() +
426  "(%zu): Receive overlap solution\n",
427  element_id, iteration_id);
428  }
429 
430  // Add solutions on overlaps to this element's solution in a weighted sum
431  const auto received_overlap_solutions =
432  std::move(tuples::get<overlap_solution_inbox_tag>(inboxes)
433  .extract(iteration_id)
434  .mapped());
435  db::mutate<fields_tag>(
436  make_not_null(&box),
437  [&received_overlap_solutions](
438  const auto fields, const Index<Dim>& full_extents,
439  const std::array<size_t, Dim>& all_intruding_extents,
441  all_intruding_overlap_weights) noexcept {
442  for (const auto& [overlap_id, overlap_solution] :
443  received_overlap_solutions) {
444  const auto& direction = overlap_id.first;
445  const auto& intruding_extents =
446  gsl::at(all_intruding_extents, direction.dimension());
447  const auto& overlap_weight =
448  all_intruding_overlap_weights.at(direction);
450  fields, overlap_solution * get(overlap_weight), full_extents,
451  intruding_extents, direction);
452  }
453  },
454  db::get<domain::Tags::Mesh<Dim>>(box).extents(),
455  db::get<Tags::IntrudingExtents<Dim, OptionsGroup>>(box),
457  Tags::Weight<OptionsGroup>>>(box));
458  return {std::move(box)};
459  }
460 };
461 
462 } // namespace LinearSolver::Schwarz::detail
gsl::at
constexpr T & at(std::array< T, N > &arr, Size index)
Retrieve a entry from a container, with checks in Debug mode that the index being retrieved is valid.
Definition: Gsl.hpp:125
observers::ObservationId
A unique identifier for an observation representing the type of observation and the instance (e....
Definition: ObservationId.hpp:71
std::apply
T apply(T... args)
funcl::Divides
Functional for computing / of two objects.
Definition: Functional.hpp:235
std::string
utility
UNLIKELY
#define UNLIKELY(x)
Definition: Gsl.hpp:73
get
constexpr Tag::type & get(Variables< TagList > &v) noexcept
Return Tag::type pointing into the contiguous array.
Definition: Variables.hpp:638
Parallel::GlobalCache
Definition: ElementReceiveInterpPoints.hpp:15
Parallel::ReductionDatum
The data to be reduced, and invokables to be called whenever two reduction messages are combined and ...
Definition: Reduction.hpp:63
std::pair
GlobalCache.hpp
std::index_sequence
Options.hpp
CommunicateOverlapFields.hpp
Tags.hpp
vector
domain::Tags::Element
Definition: Tags.hpp:97
LinearSolver::Schwarz::Actions::ReceiveOverlapFields
Receive data from regions of this element's subdomain that overlap with other elements.
Definition: CommunicateOverlapFields.hpp:160
PrettyType.hpp
Parallel::printf
void printf(const std::string &format, Args &&... args)
Print an atomic message to stdout with C printf usage.
Definition: Printf.hpp:103
db::add_tag_prefix
typename detail::add_tag_prefix_impl< Prefix, Tag, Args... >::type add_tag_prefix
Definition: PrefixHelpers.hpp:51
observers::ObservationKey
Used as a key in maps to keep track of how many elements have registered.
Definition: ObservationId.hpp:28
tuple
db::get
const auto & get(const DataBox< TagList > &box) noexcept
Retrieve the item with tag Tag from the DataBox.
Definition: DataBox.hpp:969
Index
Definition: Index.hpp:31
db::SimpleTag
Mark a struct as a simple tag by inheriting from this.
Definition: Tag.hpp:36
domain::Tags::InternalDirectionsCompute
Definition: Tags.hpp:275
Convergence::HasConverged
Signals convergence of the algorithm.
Definition: HasConverged.hpp:59
Info.hpp
domain::Tags::BoundaryDirectionsInterior
Definition: Tags.hpp:296
Spectral.hpp
Tags.hpp
Direction
Definition: Direction.hpp:23
LinearSolver::Schwarz::Actions::SendOverlapFields
Send data on regions that overlap with other subdomains to their corresponding elements.
Definition: CommunicateOverlapFields.hpp:68
Initialization::mutate_assign
constexpr void mutate_assign(const gsl::not_null< db::DataBox< BoxTags > * > box, Args &&... args) noexcept
Perform a mutation to the DataBox box, assigning the args to the tags in MutateTagList in order.
Definition: MutateAssign.hpp:40
ElementId< Dim >
ElementId.hpp
std::add_pointer_t
LinearSolver::Schwarz::add_overlap_data
void add_overlap_data(const gsl::not_null< Variables< VolumeTagsList > * > volume_data, const Variables< OverlapTagsList > &overlap_data, const Index< Dim > &volume_extents, const size_t overlap_extent, const Direction< Dim > &direction) noexcept
Add the overlap_data to the volume_data
Definition: OverlapHelpers.hpp:226
ActionTesting::is_ready
bool is_ready(MockRuntimeSystem< Metavariables > &runner, const typename Component::array_index &array_index) noexcept
Runs the is_ready function and returns the result for the next action in the current phase on the arr...
Definition: ActionTesting.hpp:2057
Printf.hpp
DataBox.hpp
cstddef
logging::Tags::Verbosity
Tag for putting Verbosity in a DataBox.
Definition: Tags.hpp:33
std::array< size_t, Dim >
domain::Tags::LogicalCoordinates
Definition: LogicalCoordinates.hpp:78
Index.hpp
tuples::TaggedTuple
An associative container that is indexed by structs.
Definition: TaggedTuple.hpp:271
map
Element.hpp
Convergence::Tags::IterationId
Identifies a step in an iterative algorithm.
Definition: Tags.hpp:74
Scalar
Tensor< T, Symmetry<>, index_list<> > Scalar
Definition: TypeAliases.hpp:21
Gsl.hpp
domain::Tags::Interface
Tag which is either a SimpleTag for quantities on an interface, base tag to a compute item which acts...
Definition: Tags.hpp:365
domain::Tags::InterfaceCompute
Compute tag for representing items computed on a set of interfaces. Can be retrieved using Tags::Inte...
Definition: InterfaceComputeTags.hpp:66
domain::Tags::Direction
Definition: Tags.hpp:381
domain::Tags::InternalDirections
Definition: Tags.hpp:269
observers::TypeOfObservation::Reduction
@ Reduction
The sender will only perform reduction observations.
LIKELY
#define LIKELY(x)
Definition: Gsl.hpp:67
observers::ArrayComponentId
An ID type that identifies both the parallel component and the index in the parallel component.
Definition: ArrayComponentId.hpp:27
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
Parallel::ArrayIndex
The array index used for indexing Chare Arrays, mostly an implementation detail.
Definition: ArrayIndex.hpp:27
Mesh.hpp
domain::Tags::BoundaryDirectionsInteriorCompute
Definition: Tags.hpp:302
unordered_map
TMPL.hpp
gsl::not_null
Require a pointer to not be a nullptr
Definition: Gsl.hpp:183
Parallel::InboxInserters::Map
Inserter for inserting data that is received as the value_type (with non-const key_type) of a map dat...
Definition: InboxInserters.hpp:36
observers::Actions::RegisterWithObservers
Register an observation ID with the observers.
Definition: RegisterWithObservers.hpp:39
string