Minmod.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <array>
7 #include <boost/functional/hash.hpp> // IWYU pragma: keep
8 #include <cstdlib>
9 #include <limits>
10 #include <memory>
11 #include <string>
12 #include <type_traits>
13 #include <unordered_map>
14 #include <utility>
15 
17 #include "DataStructures/DataVector.hpp"
18 #include "DataStructures/FixedHashMap.hpp"
19 #include "DataStructures/SliceIterator.hpp"
21 #include "Domain/Element.hpp" // IWYU pragma: keep
22 #include "Domain/MaxNumberOfNeighbors.hpp"
23 #include "ErrorHandling/Assert.hpp"
25 #include "Options/Options.hpp"
26 #include "Utilities/Gsl.hpp"
27 #include "Utilities/Literals.hpp"
28 #include "Utilities/MakeArray.hpp"
29 #include "Utilities/Numeric.hpp"
30 #include "Utilities/TMPL.hpp"
32 
33 /// \cond
34 template <size_t VolumeDim>
35 class Direction;
36 template <size_t VolumeDim>
37 class ElementId;
38 template <size_t VolumeDim>
39 class Mesh;
40 template <size_t VolumeDim>
41 class OrientationMap;
42 
43 namespace PUP {
44 class er;
45 } // namespace PUP
46 
47 namespace SlopeLimiters {
48 template <size_t VolumeDim, typename TagsToLimit>
49 class Minmod;
50 } // namespace SlopeLimiters
51 
52 namespace Tags {
53 template <size_t Dim, typename Frame>
54 struct Coordinates;
55 template <size_t VolumeDim>
56 struct Element;
57 template <size_t VolumeDim>
58 struct Mesh;
59 template <size_t VolumeDim>
60 struct SizeOfElement;
61 } // namespace Tags
62 /// \endcond
63 
64 namespace SlopeLimiters {
65 /// \ingroup SlopeLimitersGroup
66 /// \brief Possible types of the minmod slope limiter.
67 ///
68 /// \see SlopeLimiters::Minmod
69 enum class MinmodType { LambdaPi1, LambdaPiN, Muscl };
70 } // namespace SlopeLimiters
71 
72 namespace Minmod_detail {
73 // Encodes the return status of the minmod_tvbm function.
74 struct MinmodResult {
75  const double value;
76  const bool activated;
77 };
78 
79 // The TVBM-corrected minmod function, see e.g. Cockburn reference Eq. 2.26.
80 MinmodResult minmod_tvbm(double a, double b, double c,
81  double tvbm_scale) noexcept;
82 
83 // Implements the minmod limiter for one Tensor<DataVector>.
84 //
85 // The interface is designed to erase the tensor structure information, because
86 // this way the implementation can be moved out of the header file. This is
87 // achieved by receiving Tensor<DataVector>::iterators into the tensor to limit,
88 // and Tensor<double>::iterators into the neighbor tensors.
89 //
90 // Note: because the interface erases the tensor structure information, we can
91 // no longer rely on the compiler to enforce that the local and neighbor tensors
92 // share the same Structure.
93 template <size_t VolumeDim>
94 bool limit_one_tensor(
95  gsl::not_null<DataVector*> tensor_begin,
96  gsl::not_null<DataVector*> tensor_end,
97  gsl::not_null<DataVector*> u_lin_buffer,
99  const SlopeLimiters::MinmodType& minmod_type, double tvbm_constant,
100  const Element<VolumeDim>& element, const Mesh<VolumeDim>& mesh,
101  const tnsr::I<DataVector, VolumeDim, Frame::Logical>& logical_coords,
102  const std::array<double, VolumeDim>& element_size,
103  const FixedHashMap<
104  maximum_number_of_neighbors(VolumeDim),
108  neighbor_tensor_begin,
109  const FixedHashMap<
110  maximum_number_of_neighbors(VolumeDim),
114  neighbor_sizes,
117  VolumeDim>& volume_and_slice_indices) noexcept;
118 
119 template <typename Tag>
120 struct to_tensor_double : db::PrefixTag, db::SimpleTag {
122  using tag = Tag;
123  static std::string name() noexcept {
124  return "TensorDouble(" + Tag::name() + ")";
125  }
126 };
127 } // namespace Minmod_detail
128 
129 namespace SlopeLimiters {
130 /// \ingroup SlopeLimitersGroup
131 /// \brief A generic Minmod slope limiter
132 ///
133 /// Implements the minmod-based slope limiter from
134 /// \ref cockburn_ref "Cockburn (1999)", Section 2.4.
135 /// Three types of minmod limiter from the reference are implemented:
136 /// \f$\Lambda\Pi^1\f$, \f$\Lambda\Pi^N\f$, and MUSCL.
137 ///
138 /// This minmod limiter has a generic implementation that can work on an
139 /// arbitrary set of tensors. The minmod limiting algorithm is applied to each
140 /// component of each tensor independently. In general, the limiter linearizes
141 /// the tensors on every DG element, each time it is applied; additionally, the
142 /// limiter may reduce the spatial slope of some tensor components if the data
143 /// look like they may contain oscillations.
144 ///
145 /// The key features differentiating the three minmod limiter types are:
146 /// 1. The `Muscl` limiter is the most dissipative; it more aggressively reduces
147 /// the slopes of the data. This limiter may better handle strong shocks, but
148 /// also produces the most broadening of features.
149 /// 2. The `LambdaPiN` limiter is the least aggressive; its "troubled cell"
150 /// detector tries to avoid limiting in DG elements where the data look
151 /// smooth enough. Where `LambdaPiN` is able to avoid limiting, the data are
152 /// _not_ linearized, and the post-limiter data are identical to the
153 /// pre-limiter data.
154 /// 3. The `LambdaPi1` limiter is a middle-ground option between the other two.
155 /// It does not try to avoid limiting as much as `LambdaPiN`, but it allows
156 /// larger slopes in the data than `Muscl`.
157 ///
158 /// For all three types of minmod limiter the "total variation bound in the
159 /// means" (TVBM) correction is implemented, enabling the limiter to avoid
160 /// limiting away smooth extrema in the solution that would otherwise look like
161 /// spurious oscillations. The limiter will not reduce the slope (but will still
162 /// linearize) on elements where the slope is less than \f$m h^2\f$, where
163 /// \f$m\f$ is the TVBM constant and \f$h\f$ is the size of the DG element.
164 ///
165 /// The limiter acts in the `Frame::Logical` coordinates, because in these
166 /// coordinates it is straightforward to formulate the algorithm. This means the
167 /// limiter can operate on generic deformed grids. However, if the grid is too
168 /// strongly deformed, some things can start to break down:
169 /// 1. When an element is deformed so that the Jacobian (from `Frame::Logical`
170 /// to `Frame::Inertial`) varies across the element, then the limiter fails
171 /// to be conservative. In other words, the integral of a tensor `u` over the
172 /// element will change after the limiter activates on `u`. This error is
173 /// typically small.
174 /// 2. When there is a sudden change in the size of the elements (perhaps at an
175 /// h-refinement boundary, or at the boundary between two blocks with very
176 /// different mappings), a smooth solution in `Frame::Inertial` can appear
177 /// to have a kink in `Frame::Logical`. The Minmod implementation includes
178 /// some (untested) tweaks that try to reduce spurious limiter activations
179 /// near these fake kinks.
180 ///
181 /// When an element has multiple neighbors in any direction, an effective mean
182 /// and neighbor size in this direction are computed by averaging over the
183 /// multiple neighbors. This simple generalization of the minmod limiter enables
184 /// it to operate on h-refined grids.
185 ///
186 /// \tparam VolumeDim The number of spatial dimensions.
187 /// \tparam Tags A typelist of tags specifying the tensors to limit.
188 ///
189 /// \anchor cockburn_ref [1] B. Cockburn,
190 /// Discontinuous Galerkin Methods for Convection-Dominated Problems,
191 /// [Springer (1999)](https://doi.org/10.1007/978-3-662-03882-6_2)
192 template <size_t VolumeDim, typename... Tags>
193 class Minmod<VolumeDim, tmpl::list<Tags...>> {
194  public:
195  /// \brief The MinmodType
196  ///
197  /// One of `SlopeLimiters::MinmodType`. See `SlopeLimiters::Minmod`
198  /// documentation for details.
199  struct Type {
200  using type = MinmodType;
201  static constexpr OptionString help = {"Type of minmod"};
202  };
203  /// \brief The TVBM constant
204  ///
205  /// See `SlopeLimiters::Minmod` documentation for details.
206  struct TvbmConstant {
207  using type = double;
208  static type default_value() noexcept { return 0.0; }
209  static type lower_bound() noexcept { return 0.0; }
210  static constexpr OptionString help = {"TVBM constant 'm'"};
211  };
212  /// \brief Turn the limiter off
213  ///
214  /// This option exists to temporarily disable the limiter for debugging
215  /// purposes. For problems where limiting is not needed, the preferred
216  /// approach is to not compile the limiter into the executable.
217  struct DisableForDebugging {
218  using type = bool;
219  static type default_value() noexcept { return false; }
220  static constexpr OptionString help = {"Disable the limiter"};
221  };
222  using options = tmpl::list<Type, TvbmConstant, DisableForDebugging>;
223  static constexpr OptionString help = {
224  "A minmod-based slope limiter.\n"
225  "The different types of minmod are more or less aggressive in trying\n"
226  "to reduce slopes. The TVBM correction allows the limiter to ignore\n"
227  "'small' slopes, and helps to avoid limiting of smooth extrema in the\n"
228  "solution.\n"};
229 
230  /// \brief Constuct a Minmod slope limiter
231  ///
232  /// \param minmod_type The type of Minmod slope limiter.
233  /// \param tvbm_constant The value of the TVBM constant (default: 0).
234  /// \param disable_for_debugging Switch to turn the limiter off (default:
235  // false).
236  explicit Minmod(const MinmodType minmod_type,
237  const double tvbm_constant = 0.0,
238  const bool disable_for_debugging = false) noexcept
239  : minmod_type_(minmod_type),
240  tvbm_constant_(tvbm_constant),
241  disable_for_debugging_(disable_for_debugging) {
242  ASSERT(tvbm_constant >= 0.0, "The TVBM constant must be non-negative.");
243  }
244 
245  Minmod() noexcept = default;
246  Minmod(const Minmod& /*rhs*/) = default;
247  Minmod& operator=(const Minmod& /*rhs*/) = default;
248  Minmod(Minmod&& /*rhs*/) noexcept = default;
249  Minmod& operator=(Minmod&& /*rhs*/) noexcept = default;
250  ~Minmod() = default;
251 
252  // clang-tidy: google-runtime-references
253  void pup(PUP::er& p) noexcept { // NOLINT
254  p | minmod_type_;
255  p | tvbm_constant_;
256  p | disable_for_debugging_;
257  }
258 
259  // To facilitate testing
260  /// \cond
261  const MinmodType& minmod_type() const noexcept { return minmod_type_; }
262  /// \endcond
263 
264  /// \brief Data to send to neighbor elements.
265  struct PackagedData {
267  std::array<double, VolumeDim> element_size =
268  make_array<VolumeDim>(std::numeric_limits<double>::signaling_NaN());
269 
270  // clang-tidy: google-runtime-references
271  void pup(PUP::er& p) noexcept { // NOLINT
272  p | means;
273  p | element_size;
274  }
275  };
276 
277  using package_argument_tags = tmpl::list<Tags..., ::Tags::Mesh<VolumeDim>,
279 
280  /// \brief Package data for sending to neighbor elements.
281  ///
282  /// The following quantities are stored in `PackagedData` and communicated
283  /// between neighboring elements:
284  /// - the cell-averaged mean of each tensor component, and
285  /// - the size of the cell along each logical coordinate direction.
286  ///
287  /// \param packaged_data The data package to fill with this element's values.
288  /// \param tensors The tensors to be averaged and packaged.
289  /// \param mesh The mesh on which the tensor values are measured.
290  /// \param element_size The size of the element in inertial coordinates, along
291  /// each dimension of logical coordinates.
292  /// \param orientation_map The orientation of the neighbor
293  void package_data(const gsl::not_null<PackagedData*>& packaged_data,
294  const db::item_type<Tags>&... tensors,
295  const Mesh<VolumeDim>& mesh,
296  const std::array<double, VolumeDim>& element_size,
297  const OrientationMap<VolumeDim>& orientation_map) const
298  noexcept {
299  if (disable_for_debugging_) {
300  // Do not initialize packaged_data
301  return;
302  }
303 
304  const auto wrap_compute_means =
305  [&mesh, &packaged_data ](auto tag, const auto& tensor) noexcept {
306  for (size_t i = 0; i < tensor.size(); ++i) {
307  // Compute the mean using the local orientation of the tensor and mesh:
308  // this avoids the work of reorienting the tensor while giving the same
309  // result.
310  get<Minmod_detail::to_tensor_double<decltype(tag)>>(
311  packaged_data->means)[i] = mean_value(tensor[i], mesh);
312  }
313  return '0';
314  };
315  expand_pack(wrap_compute_means(Tags{}, tensors)...);
316  packaged_data->element_size =
317  orientation_map.permute_from_neighbor(element_size);
318  }
319 
320  using limit_tags = tmpl::list<Tags...>;
321  using limit_argument_tags =
322  tmpl::list<::Tags::Element<VolumeDim>, ::Tags::Mesh<VolumeDim>,
324  ::Tags::SizeOfElement<VolumeDim>>;
325 
326  /// \brief Limits the solution on the element.
327  ///
328  /// For each component of each tensor, the limiter will (in general) linearize
329  /// the data, then possibly reduce its slope, dimension-by-dimension, until it
330  /// no longer looks oscillatory.
331  ///
332  /// \param tensors The tensors to be limited.
333  /// \param element The element on which the tensors to limit live.
334  /// \param mesh The mesh on which the tensor values are measured.
335  /// \param logical_coords The logical coordinates of the mesh gridpoints.
336  /// \param element_size The size of the element, in the inertial coordinates.
337  /// \param neighbor_data The data from each neighbor.
338  ///
339  /// \return whether the limiter modified the solution or not.
340  ///
341  /// \note The return value is false if the limiter knows it has not modified
342  /// the solution. True return values can indicate:
343  /// - The solution was limited to reduce the slope, whether by a large factor
344  /// or by a factor only roundoff away from unity.
345  /// - The solution was linearized but not limited.
346  /// - The solution is identical to the input, if the input was a linear
347  /// function on a higher-order mesh, so that the limiter cannot know that
348  /// the linearization step did not actually modify the data. This is
349  /// somewhat contrived and is unlikely to occur outside of code tests or
350  /// test cases with very clean initial data.
353  const Element<VolumeDim>& element, const Mesh<VolumeDim>& mesh,
354  const tnsr::I<DataVector, VolumeDim, Frame::Logical>& logical_coords,
355  const std::array<double, VolumeDim>& element_size,
356  const std::unordered_map<
359  neighbor_data) const noexcept {
360  if (disable_for_debugging_) {
361  // Do not modify input tensors
362  return false;
363  }
364 
365  // Allocate temporary buffer to be used in `limit_one_tensor` where we
366  // otherwise make 1 + 2 * VolumeDim allocations per tensor component for
367  // MUSCL and LambdaPi1, and 1 + 4 * VolumeDim allocations per tensor
368  // component for LambdaPiN.
369  const size_t half_number_boundary_points = alg::accumulate(
370  alg::iota(std::array<size_t, VolumeDim>{{}}, 0_st),
371  0_st, [&mesh](const size_t state, const size_t d) noexcept {
372  return state + mesh.slice_away(d).number_of_grid_points();
373  });
375  static_cast<double*>(
376  malloc(sizeof(double) * (mesh.number_of_grid_points() +
377  half_number_boundary_points))),
378  &free);
379  size_t alloc_offset = 0;
380  DataVector u_lin_buffer(temp_buffer.get() + alloc_offset,
381  mesh.number_of_grid_points());
382  alloc_offset += mesh.number_of_grid_points();
383  std::array<DataVector, VolumeDim> boundary_buffer{};
384  for (size_t d = 0; d < VolumeDim; ++d) {
385  const size_t num_points = mesh.slice_away(d).number_of_grid_points();
386  gsl::at(boundary_buffer, d)
387  .set_data_ref(temp_buffer.get() + alloc_offset, num_points);
388  alloc_offset += num_points;
389  }
390  // Compute the slice indices once since this is (surprisingly) expensive
391  const auto volume_and_slice_buffer_and_indices =
392  volume_and_slice_indices(mesh.extents());
393  const auto& volume_and_slice_indices =
394  volume_and_slice_buffer_and_indices.second;
395 
396  bool limiter_activated = false;
397  const auto wrap_limit_one_tensor = [
398  this, &limiter_activated, &element, &mesh, &logical_coords, &element_size,
399  &neighbor_data, &u_lin_buffer, &boundary_buffer, &volume_and_slice_indices
400  ](auto tag, const auto& tensor) noexcept {
401  // Because we hide the types of Tags from limit_one_tensor (we do this so
402  // that its implementation isn't templated on Tags and can be moved out of
403  // this header file), we cannot pass it PackagedData as currently
404  // implemented. So we unpack everything from PackagedData. In the future
405  // we may want a PackagedData type that erases types inherently, as this
406  // would avoid the need for unpacking as done here.
407  //
408  // Get iterators into the local and neighbor tensors, because these are
409  // independent from the structure of the tensor being limited.
410  const auto tensor_begin = make_not_null(tensor->begin());
411  const auto tensor_end = make_not_null(tensor->end());
412  const auto neighbor_tensor_begin = [&neighbor_data]() noexcept {
413  FixedHashMap<
414  maximum_number_of_neighbors(VolumeDim),
417  boost::hash<std::pair<Direction<VolumeDim>, ElementId<VolumeDim>>>>
418  result;
419  for (const auto& neighbor_and_data : neighbor_data) {
420  result.insert(std::make_pair(
421  neighbor_and_data.first,
422  make_not_null(get<Minmod_detail::to_tensor_double<decltype(tag)>>(
423  neighbor_and_data.second.means)
424  .cbegin())));
425  }
426  return result;
427  }
428  ();
429  const auto neighbor_sizes = [&neighbor_data]() noexcept {
430  FixedHashMap<
431  maximum_number_of_neighbors(VolumeDim),
434  boost::hash<std::pair<Direction<VolumeDim>, ElementId<VolumeDim>>>>
435  result;
436  for (const auto& neighbor_and_data : neighbor_data) {
437  result.insert(std::make_pair(neighbor_and_data.first,
438  neighbor_and_data.second.element_size));
439  }
440  return result;
441  }
442  ();
443 
444  limiter_activated =
445  Minmod_detail::limit_one_tensor<VolumeDim>(
446  tensor_begin, tensor_end, &u_lin_buffer, &boundary_buffer,
447  minmod_type_, tvbm_constant_, element, mesh, logical_coords,
448  element_size, neighbor_tensor_begin, neighbor_sizes,
450  limiter_activated;
451  return '0';
452  };
453  expand_pack(wrap_limit_one_tensor(Tags{}, tensors)...);
454  return limiter_activated;
455  }
456 
457  private:
458  template <size_t LocalDim, typename LocalTagList>
459  // NOLINTNEXTLINE(readability-redundant-declaration) false positive
460  friend bool operator==(const Minmod<LocalDim, LocalTagList>& lhs,
461  const Minmod<LocalDim, LocalTagList>& rhs) noexcept;
462 
463  MinmodType minmod_type_;
464  double tvbm_constant_;
465  bool disable_for_debugging_;
466 };
467 
468 template <size_t LocalDim, typename LocalTagList>
469 bool operator==(const Minmod<LocalDim, LocalTagList>& lhs,
470  const Minmod<LocalDim, LocalTagList>& rhs) noexcept {
471  return lhs.minmod_type_ == rhs.minmod_type_ and
472  lhs.tvbm_constant_ == rhs.tvbm_constant_ and
473  lhs.disable_for_debugging_ == rhs.disable_for_debugging_;
474 }
475 
476 template <size_t VolumeDim, typename TagList>
477 bool operator!=(const Minmod<VolumeDim, TagList>& lhs,
478  const Minmod<VolumeDim, TagList>& rhs) noexcept {
479  return not(lhs == rhs);
480 }
481 
482 } // namespace SlopeLimiters
483 
484 template <>
486  static SlopeLimiters::MinmodType create(const Option& options);
487 };
Definition: Strahlkorper.hpp:14
The type that options are passed around as. Contains YAML node data and an OptionContext.
Definition: Options.hpp:103
Defines class tuples::TaggedTuple.
constexpr size_t maximum_number_of_neighbors(const size_t dim)
Returns the maximum number of neighbors an element can have in dim dimensions.
Definition: MaxNumberOfNeighbors.hpp:13
std::pair< std::unique_ptr< std::pair< size_t, size_t >[], decltype(&free)>, std::array< std::pair< gsl::span< std::pair< size_t, size_t > >, gsl::span< std::pair< size_t, size_t > > >, VolumeDim > > volume_and_slice_indices(const Index< VolumeDim > &extents) noexcept
Get the mapping between volume and boundary slice indices.
Definition: SliceIterator.cpp:49
void package_data(const gsl::not_null< PackagedData *> &packaged_data, const db::item_type< Tags > &... tensors, const Mesh< VolumeDim > &mesh, const std::array< double, VolumeDim > &element_size, const OrientationMap< VolumeDim > &orientation_map) const noexcept
Package data for sending to neighbor elements.
Definition: Minmod.hpp:293
Definition: Digraph.hpp:11
T signaling_NaN(T... args)
A hash table with a compile-time specified maximum size and ability to efficiently handle perfect has...
Definition: FixedHashMap.hpp:81
Used by the parser to create an object. The default action is to parse options using T::options...
Definition: Options.hpp:143
Defines function make_array.
An ElementId uniquely labels an Element. It is constructed from the BlockId of the Block to which the...
Definition: ElementId.hpp:36
Holds the number of grid points, basis, and quadrature in each direction of the computational grid...
Definition: Mesh.hpp:49
Defines classes and functions for making classes creatable from input files.
MinmodType
Possible types of the minmod slope limiter.
Definition: Minmod.hpp:69
Tags for the DataBox inherit from this type.
Definition: DataBoxTag.hpp:65
constexpr auto create(Args &&... args)
Create a new DataBox.
Definition: DataBox.hpp:1259
#define ASSERT(a, m)
Assert that an expression should be true.
Definition: Assert.hpp:49
Create a span/view on a range, which is cheap to copy (one pointer).
Definition: Gsl.hpp:291
decltype(auto) accumulate(const Container &c, T init)
Convenience wrapper around std::accumulate, returns std::accumulate(begin(c), end(c), init).
Definition: Numeric.hpp:54
Definition: Minmod.cpp:25
const char *const OptionString
The string used in option structs.
Definition: Options.hpp:26
A particular Side along a particular coordinate Axis.
Definition: Direction.hpp:23
An associative container that is indexed by structs.
Definition: TaggedTuple.hpp:272
Things relating to slope limiting.
Definition: LimiterActions.hpp:22
Defines useful literals.
double mean_value(const DataVector &f, const Mesh< Dim > &mesh) noexcept
Compute the mean value of a grid-function over a manifold. .
Definition: MeanValue.hpp:38
A spectral element with knowledge of its neighbors.
Definition: Element.hpp:29
Definition: DataBoxTag.hpp:29
Defines classes for Tensor.
Defines macro ASSERT.
::Tensor< NewType, typename Tensor::symmetry, typename Tensor::index_list > swap_type
Swap the data type of a tensor for a new type.
Definition: Metafunctions.hpp:121
Stores a collection of function values.
Definition: DataVector.hpp:46
Wraps the template metaprogramming library used (brigand)
The computational grid of the Element in the DataBox.
Definition: Tags.hpp:75
typename DataBox_detail::item_type_impl< TagList, Tag >::type item_type
Get the type that is returned by the Tag. If it is a base tag then a TagList must be passed as a seco...
Definition: DataBoxTag.hpp:410
Defines functions and classes from the GSL.
The inertial-coordinate size of an element along each of its logical directions.
Definition: SizeOfElement.hpp:53
gsl::not_null< T * > make_not_null(T *ptr) noexcept
Construct a not_null from a pointer. Often this will be done as an implicit conversion, but it may be necessary to perform the conversion explicitly when type deduction is desired.
Definition: Gsl.hpp:863
Marks an item as being a prefix to another tag.
Definition: DataBoxTag.hpp:112
Defines function mean_value and mean_value_on_boundary.
std::pair< iterator, bool > insert(const value_type &value) noexcept
Inserts the element if it does not exists.
Definition: FixedHashMap.hpp:131
Defines classes SimpleTag, PrefixTag, ComputeTag and several functions for retrieving tag info...
Minmod(const MinmodType minmod_type, const double tvbm_constant=0.0, const bool disable_for_debugging=false) noexcept
Constuct a Minmod slope limiter.
Definition: Minmod.hpp:236
bool operator()(const gsl::not_null< std::add_pointer_t< db::item_type< Tags >>>... tensors, const Element< VolumeDim > &element, const Mesh< VolumeDim > &mesh, const tnsr::I< DataVector, VolumeDim, Frame::Logical > &logical_coords, const std::array< double, VolumeDim > &element_size, const std::unordered_map< std::pair< Direction< VolumeDim >, ElementId< VolumeDim >>, PackagedData, boost::hash< std::pair< Direction< VolumeDim >, ElementId< VolumeDim >>>> &neighbor_data) const noexcept
Limits the solution on the element.
Definition: Minmod.hpp:351
Require a pointer to not be a nullptr
Definition: ConservativeFromPrimitive.hpp:12
constexpr void expand_pack(Ts &&...) noexcept
Allows zero-cost unordered expansion of a parameter.
Definition: TMPL.hpp:545
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:124
Defines class Element.