FirstOrderInternalPenalty.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <cstddef>
7 #include <pup.h>
8 #include <string>
9 
11 #include "DataStructures/DataBox/Tag.hpp"
12 #include "DataStructures/Tensor/EagerMath/Magnitude.hpp"
16 #include "Domain/FaceNormal.hpp"
17 #include "Domain/Tags.hpp"
18 #include "Elliptic/DiscontinuousGalerkin/Penalty.hpp"
19 #include "NumericalAlgorithms/DiscontinuousGalerkin/NormalDotFlux.hpp"
20 #include "NumericalAlgorithms/DiscontinuousGalerkin/Protocols.hpp"
22 #include "Options/Options.hpp"
23 #include "Utilities/Gsl.hpp"
24 #include "Utilities/ProtocolHelpers.hpp"
25 #include "Utilities/TMPL.hpp"
26 
27 /// \cond
28 class DataVector;
29 namespace Tags {
30 template <typename>
31 struct Normalized;
32 } // namespace Tags
33 /// \endcond
34 
35 /// Numerical fluxes for elliptic systems
37 
38 /*!
39  * \ingroup DiscontinuousGalerkinGroup
40  * \ingroup NumericalFluxesGroup
41  * \brief The internal penalty flux for first-order elliptic equations.
42  *
43  * \details Computes the internal penalty numerical flux (see e.g.
44  * \cite HesthavenWarburton, section 7.2) dotted with the interface unit normal.
45  *
46  * We implement here a suggested generalization of the internal penalty flux
47  * for any set of elliptic PDEs up to second order in derivatives. It is
48  * designed for fluxes (i.e. principal parts of the PDEs) that may depend on the
49  * dynamic fields, but do so at most linearly. This is the case for the velocity
50  * potential equation of binary neutron stars, for example. The linearity is
51  * only necessary to impose inhomogeneous boundary conditions as contributions
52  * to the fixed source (see
53  * `elliptic::dg::Actions::ImposeInhomogeneousBoundaryConditionsOnSource`).
54  *
55  * We reduce the second-order elliptic PDEs to first-order form by introducing
56  * an _auxiliary_ variable \f$v\f$ for each _primal_ variable \f$u\f$ (i.e. for
57  * each variable whose second derivative appears in the equations). Then, the
58  * equations take the _flux-form_
59  *
60  * \f{align}
61  * -\partial_i F^i_A + S_A = f_A
62  * \f}
63  *
64  * where the fluxes \f$F^i_A(u,v)\f$ and sources \f$S_A(u,v)\f$ are indexed
65  * (with capital letters) by the variables and we have defined \f$f_A(x)\f$ as
66  * those sources that are independent of the variables. Note that the fluxes are
67  * functions of the primal and auxiliary variables; e.g. for a Poisson system
68  * \f$\{u,v_i\}\f$ on a spatial metric \f$\gamma_{ij}\f$ they are simply
69  * \f$F^i_u(v)=\sqrt{\gamma}\gamma^{ij} v_j\f$ and
70  * \f$F^i_{v_j}(u)=u\delta^i_j\f$ (see `Poisson::FirstOrderSystem`) or for an
71  * Elasticity system \f$\{\xi^i,S_{ij}\}\f$ with Young's tensor
72  * \f$Y^{ijkl}\f$ they are \f$F^i_{\xi^j}(S)=Y^{ijkl}S_{kl}\f$ and
73  * \f$F^i_{S_{jk}}(\xi)=\delta^i_{(j}\xi_{k)}\f$. Since each primal flux is
74  * commonly only a function of the corresponding auxiliary variable and
75  * vice-versa, we omit the other function arguments here to lighten the
76  * notational load.
77  *
78  * We now choose the internal penalty numerical fluxes \f$(n_i F^i_A)^*\f$ as
79  * follows for each primal variable \f$u\f$ and their corresponding auxiliary
80  * variable \f$v\f$:
81  *
82  * \f{align}
83  * (n_i F^i_u)^* &= \frac{1}{2} n_i \left( F^i_u(\partial_j
84  * F^j_v(u^\mathrm{int})) + F^i_u(\partial_j F^j_v(u^\mathrm{ext}))
85  * \right) - \sigma n_i \left(F^i_u(n_j F^j_v(u^\mathrm{int})) - F^i_u(
86  * n_j F^j_v(u^\mathrm{ext}))\right) \\
87  * (n_i F^i_v)^* &= \frac{1}{2} n_i \left(F^i_v(u^\mathrm{int}) +
88  * F^i_v(u^\mathrm{ext})\right)
89  * \f}
90  *
91  * Note that we have assumed \f$n^\mathrm{ext}_i=-n_i\f$ here, i.e. face normals
92  * don't depend on the dynamic variables (which may be discontinuous on element
93  * faces). This is the case for the problems we are expecting to solve, because
94  * those will be on fixed background metrics (e.g. a conformal metric for the
95  * XCTS system).
96  *
97  * Also note that the numerical fluxes intentionally don't depend on the
98  * auxiliary field values \f$v\f$. This property allows us to use the numerical
99  * fluxes also for the second-order (or _primal_) DG formulation, where we
100  * remove the need for an auxiliary variable. For the first-order system we
101  * could replace the divergence in \f$(n_i F^i_u)^*\f$ with \f$v\f$, which would
102  * result in a generalized "stabilized central flux" that is slightly less
103  * sparse than the internal penalty flux (see e.g. \cite HesthavenWarburton,
104  * section 7.2). We could also choose to ignore the fluxes in the penalty term,
105  * but preliminary tests suggest that this may hurt convergence.
106  *
107  * For a Poisson system (see above) this numeric flux reduces to the standard
108  * internal penalty flux (see e.g. \cite HesthavenWarburton, section 7.2, or
109  * \cite Arnold2002)
110  *
111  * \f{align}
112  * (n_i F^i_u)^* &= n_i v_i^* = \frac{1}{2} n_i \left(\partial_i u^\mathrm{int}
113  * + \partial_i u^\mathrm{ext}\right) - \sigma \left(u^\mathrm{int} -
114  * u^\mathrm{ext}\right) \\
115  * (n_i F^i_{v_j})^* &= n_j u^* = \frac{1}{2} n_j \left(u^\mathrm{int} +
116  * u^\mathrm{ext}\right)
117  * \f}
118  *
119  * where a sum over repeated indices is assumed, since the equation is
120  * formulated on a Euclidean geometry.
121  *
122  * This generalization of the internal penalty flux is based on unpublished work
123  * by Nils L. Fischer (nils.fischer@aei.mpg.de).
124  *
125  * The penalty factor \f$\sigma\f$ is responsible for removing zero eigenmodes
126  * and impacts the conditioning of the linear operator to be solved. It can be
127  * chosen as \f$\sigma=C\frac{N_\mathrm{points}^2}{h}\f$ where
128  * \f$N_\mathrm{points}\f$ is the number of collocation points (i.e. the
129  * polynomial degree plus 1), \f$h\f$ is a measure of the element size in
130  * inertial coordinates (both measured perpendicular to the interface under
131  * consideration) and \f$C\geq 1\f$ is a free parameter (see e.g.
132  * \cite HesthavenWarburton, section 7.2). For the element size we choose
133  * \f$h=\frac{J_\mathrm{volume}}{J_\mathrm{face}}\f$, i.e. the ratio of Jacobi
134  * determinants from logical to inertial coordinates in the element volume and
135  * on the element face, both evaluated on the face (see \cite Vincent2019qpd).
136  * Since both \f$N_\mathrm{points}\f$ and \f$h\f$ can be different on either
137  * side of the element boundary we take the maximum of \f$N_\mathrm{points}\f$
138  * and the pointwise minimum of \f$h\f$ across the element boundary as is done
139  * in \cite Vincent2019qpd. Note that we use the number of points
140  * \f$N_\mathrm{points}\f$ where \cite Vincent2019qpd uses the polynomial degree
141  * \f$N_\mathrm{points} - 1\f$ because we found unstable configurations on
142  * curved meshes when using the polynomial degree. Optimizing the penalty on
143  * curved meshes is subject to further investigation.
144  */
145 template <size_t Dim, typename FluxesComputerTag, typename FieldTagsList,
146  typename AuxiliaryFieldTagsList>
148 
149 template <size_t Dim, typename FluxesComputerTag, typename... FieldTags,
150  typename... AuxiliaryFieldTags>
151 struct FirstOrderInternalPenalty<Dim, FluxesComputerTag,
152  tmpl::list<FieldTags...>,
153  tmpl::list<AuxiliaryFieldTags...>>
154  : tt::ConformsTo<::dg::protocols::NumericalFlux> {
155  private:
156  using fluxes_computer_tag = FluxesComputerTag;
157  using FluxesComputer = typename fluxes_computer_tag::type;
158 
159  struct PerpendicularNumPoints : db::SimpleTag {
160  using type = size_t;
161  };
162 
163  struct ElementSize : db::SimpleTag {
164  using type = Scalar<DataVector>;
165  };
166 
167  template <typename Tag>
168  struct NormalDotDivFlux : db::PrefixTag, db::SimpleTag {
169  using tag = Tag;
171  };
172 
173  template <typename Tag>
174  struct NormalDotNormalDotFlux : db::PrefixTag, db::SimpleTag {
175  using tag = Tag;
177  };
178 
179  public:
180  struct PenaltyParameter {
181  using type = double;
182  static constexpr Options::String help = {
183  "The prefactor to the penalty term of the flux. Values closer to one "
184  "lead to better-conditioned problems, but on curved meshes the penalty "
185  "parameter may need to be increased to keep the problem well-defined."};
186  static type lower_bound() noexcept { return 1.; }
187  };
188  using options = tmpl::list<PenaltyParameter>;
189  static constexpr Options::String help = {
190  "The internal penalty flux for elliptic systems."};
191  static std::string name() noexcept { return "InternalPenalty"; }
192 
193  FirstOrderInternalPenalty() = default;
194  explicit FirstOrderInternalPenalty(const double penalty_parameter) noexcept
195  : penalty_parameter_(penalty_parameter) {}
196 
197  // clang-tidy: non-const reference
198  void pup(PUP::er& p) noexcept { p | penalty_parameter_; } // NOLINT
199 
200  using variables_tags = tmpl::list<FieldTags..., AuxiliaryFieldTags...>;
201 
202  using argument_tags = tmpl::push_front<
203  typename FluxesComputer::argument_tags, domain::Tags::Mesh<Dim>,
208  Frame::Inertial>>...,
210  fluxes_computer_tag>;
211  using volume_tags =
212  tmpl::push_front<get_volume_tags<FluxesComputer>, domain::Tags::Mesh<Dim>,
213  fluxes_computer_tag>;
214 
215  using package_field_tags =
216  tmpl::list<::Tags::NormalDotFlux<AuxiliaryFieldTags>...,
217  NormalDotDivFlux<AuxiliaryFieldTags>...,
218  NormalDotNormalDotFlux<AuxiliaryFieldTags>..., ElementSize>;
219  using package_extra_tags = tmpl::list<PerpendicularNumPoints>;
220 
221  template <typename... FluxesArgs>
222  void package_data(
223  const gsl::not_null<typename ::Tags::NormalDotFlux<
224  AuxiliaryFieldTags>::type*>... packaged_n_dot_aux_fluxes,
225  const gsl::not_null<typename NormalDotDivFlux<
226  AuxiliaryFieldTags>::type*>... packaged_n_dot_div_aux_fluxes,
227  const gsl::not_null<
228  typename NormalDotNormalDotFlux<AuxiliaryFieldTags>::
229  type*>... packaged_n_dot_principal_n_dot_aux_fluxes,
230  const gsl::not_null<Scalar<DataVector>*> element_size,
231  const gsl::not_null<size_t*> perpendicular_num_points,
232  const Mesh<Dim>& volume_mesh, const Direction<Dim>& direction,
233  const Scalar<DataVector>& face_normal_magnitude,
234  const typename ::Tags::NormalDotFlux<
235  AuxiliaryFieldTags>::type&... normal_dot_auxiliary_field_fluxes,
236  const typename ::Tags::div<
237  ::Tags::Flux<AuxiliaryFieldTags, tmpl::size_t<Dim>,
238  Frame::Inertial>>::type&... div_auxiliary_field_fluxes,
239  const tnsr::i<DataVector, Dim, Frame::Inertial>& interface_unit_normal,
240  const FluxesComputer& fluxes_computer,
241  const FluxesArgs&... fluxes_args) const noexcept {
242  *perpendicular_num_points = volume_mesh.extents(direction.dimension());
243  get(*element_size) = 2. / get(face_normal_magnitude);
244  auto principal_div_aux_field_fluxes = make_with_value<Variables<tmpl::list<
246  interface_unit_normal, std::numeric_limits<double>::signaling_NaN());
247  auto principal_ndot_aux_field_fluxes = make_with_value<Variables<tmpl::list<
249  interface_unit_normal, std::numeric_limits<double>::signaling_NaN());
250  fluxes_computer.apply(
252  &get<::Tags::Flux<FieldTags, tmpl::size_t<Dim>, Frame::Inertial>>(
253  principal_div_aux_field_fluxes))...,
254  fluxes_args..., div_auxiliary_field_fluxes...);
255  fluxes_computer.apply(
257  &get<::Tags::Flux<FieldTags, tmpl::size_t<Dim>, Frame::Inertial>>(
258  principal_ndot_aux_field_fluxes))...,
259  fluxes_args..., normal_dot_auxiliary_field_fluxes...);
260  const auto apply_normal_dot =
261  [&principal_div_aux_field_fluxes, &principal_ndot_aux_field_fluxes,
262  &interface_unit_normal](
263  auto field_tag_v, auto packaged_normal_dot_auxiliary_field_flux,
264  auto packaged_normal_dot_div_auxiliary_field_flux,
265  auto packaged_normal_dot_principal_ndot_aux_field_flux,
266  const auto& normal_dot_auxiliary_field_flux) noexcept {
267  using field_tag = decltype(field_tag_v);
268  // Compute n.F_v(u)
269  *packaged_normal_dot_auxiliary_field_flux =
270  normal_dot_auxiliary_field_flux;
271  // Compute n.F_u(div(F_v(u))) and n.F_u(n.F_v(u))
272  normal_dot_flux(
273  packaged_normal_dot_div_auxiliary_field_flux,
274  interface_unit_normal,
275  get<::Tags::Flux<field_tag, tmpl::size_t<Dim>, Frame::Inertial>>(
276  principal_div_aux_field_fluxes));
277  normal_dot_flux(
278  packaged_normal_dot_principal_ndot_aux_field_flux,
279  interface_unit_normal,
280  get<::Tags::Flux<field_tag, tmpl::size_t<Dim>, Frame::Inertial>>(
281  principal_ndot_aux_field_fluxes));
282  };
283  EXPAND_PACK_LEFT_TO_RIGHT(apply_normal_dot(
284  FieldTags{}, packaged_n_dot_aux_fluxes, packaged_n_dot_div_aux_fluxes,
285  packaged_n_dot_principal_n_dot_aux_fluxes,
286  normal_dot_auxiliary_field_fluxes));
287  }
288 
289  void operator()(
290  const gsl::not_null<typename ::Tags::NormalDotNumericalFlux<
291  FieldTags>::type*>... numerical_flux_for_fields,
292  const gsl::not_null<typename ::Tags::NormalDotNumericalFlux<
293  AuxiliaryFieldTags>::type*>... numerical_flux_for_auxiliary_fields,
294  const typename ::Tags::NormalDotFlux<
295  AuxiliaryFieldTags>::type&... normal_dot_auxiliary_flux_interiors,
296  const typename NormalDotDivFlux<
297  AuxiliaryFieldTags>::type&... normal_dot_div_auxiliary_flux_interiors,
298  const typename NormalDotNormalDotFlux<
299  AuxiliaryFieldTags>::type&... ndot_ndot_aux_flux_interiors,
300  const Scalar<DataVector>& element_size_interior,
301  const size_t perpendicular_num_points_interior,
302  const typename ::Tags::NormalDotFlux<AuxiliaryFieldTags>::
303  type&... minus_normal_dot_auxiliary_flux_exteriors,
304  const typename NormalDotDivFlux<
305  AuxiliaryFieldTags>::type&... minus_normal_dot_div_aux_flux_exteriors,
306  const typename NormalDotDivFlux<
307  AuxiliaryFieldTags>::type&... ndot_ndot_aux_flux_exteriors,
308  const Scalar<DataVector>& element_size_exterior,
309  const size_t perpendicular_num_points_exterior) const noexcept {
310  const auto penalty = ::elliptic::dg::penalty(
311  min(get(element_size_interior), get(element_size_exterior)),
312  std::max(perpendicular_num_points_interior,
313  perpendicular_num_points_exterior),
314  penalty_parameter_);
315 
316  const auto assemble_numerical_fluxes = [&penalty](
317  const auto numerical_flux_for_field,
318  const auto numerical_flux_for_auxiliary_field,
319  const auto& normal_dot_auxiliary_flux_interior,
320  const auto& normal_dot_div_auxiliary_flux_interior,
321  const auto& ndot_ndot_aux_flux_interior,
322  const auto& minus_normal_dot_auxiliary_flux_exterior,
323  const auto& minus_normal_dot_div_aux_flux_exterior,
324  const auto& ndot_ndot_aux_flux_exterior) noexcept {
325  for (auto it = numerical_flux_for_auxiliary_field->begin();
326  it != numerical_flux_for_auxiliary_field->end(); it++) {
327  const auto index =
328  numerical_flux_for_auxiliary_field->get_tensor_index(it);
329  // We are working with the n.F_v(u) computed on either side of the
330  // interface, so (assuming the normal is independent of the dynamic
331  // variables) the data we get from the other element contains _minus_
332  // the normal from this element. So we cancel the minus sign when
333  // computing the average here.
334  *it = 0.5 * (normal_dot_auxiliary_flux_interior.get(index) -
335  minus_normal_dot_auxiliary_flux_exterior.get(index));
336  }
337  for (auto it = numerical_flux_for_field->begin();
338  it != numerical_flux_for_field->end(); it++) {
339  const auto index = numerical_flux_for_field->get_tensor_index(it);
340  *it = 0.5 * (normal_dot_div_auxiliary_flux_interior.get(index) -
341  minus_normal_dot_div_aux_flux_exterior.get(index)) -
342  penalty * (ndot_ndot_aux_flux_interior.get(index) -
343  ndot_ndot_aux_flux_exterior.get(index));
344  }
345  };
346  EXPAND_PACK_LEFT_TO_RIGHT(assemble_numerical_fluxes(
347  numerical_flux_for_fields, numerical_flux_for_auxiliary_fields,
348  normal_dot_auxiliary_flux_interiors,
349  normal_dot_div_auxiliary_flux_interiors, ndot_ndot_aux_flux_interiors,
350  minus_normal_dot_auxiliary_flux_exteriors,
351  minus_normal_dot_div_aux_flux_exteriors, ndot_ndot_aux_flux_exteriors));
352  }
353 
354  // This function computes the boundary contributions from Dirichlet boundary
355  // conditions. This data is what remains to be added to the boundaries when
356  // homogeneous (i.e. zero) boundary conditions are assumed in the calculation
357  // of the numerical fluxes, but we wish to impose inhomogeneous (i.e. nonzero)
358  // boundary conditions. Since this contribution does not depend on the
359  // numerical field values, but only on the Dirichlet boundary data, it may be
360  // added as contribution to the source of the elliptic systems. Then, it
361  // remains to solve the homogeneous problem with the modified source.
362  template <typename... FluxesArgs>
363  void compute_dirichlet_boundary(
364  const gsl::not_null<typename ::Tags::NormalDotNumericalFlux<
365  FieldTags>::type*>... numerical_flux_for_fields,
366  const gsl::not_null<typename ::Tags::NormalDotNumericalFlux<
367  AuxiliaryFieldTags>::type*>... numerical_flux_for_auxiliary_fields,
368  const typename FieldTags::type&... dirichlet_fields,
369  const Mesh<Dim>& volume_mesh, const Direction<Dim>& direction,
370  const tnsr::i<DataVector, Dim, Frame::Inertial>& interface_unit_normal,
371  const Scalar<DataVector>& face_normal_magnitude,
372  const FluxesComputer& fluxes_computer,
373  const FluxesArgs&... fluxes_args) const noexcept {
374  const auto penalty = ::elliptic::dg::penalty(
375  2. / get(face_normal_magnitude),
376  volume_mesh.extents(direction.dimension()), penalty_parameter_);
377 
378  // Compute n.F_v(u)
379  auto dirichlet_auxiliary_field_fluxes =
380  make_with_value<Variables<tmpl::list<::Tags::Flux<
381  AuxiliaryFieldTags, tmpl::size_t<Dim>, Frame::Inertial>...>>>(
382  interface_unit_normal,
384  fluxes_computer.apply(
385  make_not_null(&get<::Tags::Flux<AuxiliaryFieldTags, tmpl::size_t<Dim>,
386  Frame::Inertial>>(
387  dirichlet_auxiliary_field_fluxes))...,
388  fluxes_args..., dirichlet_fields...);
389  const auto apply_normal_dot_aux =
390  [&interface_unit_normal, &dirichlet_auxiliary_field_fluxes ](
391  auto auxiliary_field_tag_v,
392  const auto numerical_flux_for_auxiliary_field) noexcept {
393  using auxiliary_field_tag = decltype(auxiliary_field_tag_v);
394  normal_dot_flux(
395  numerical_flux_for_auxiliary_field, interface_unit_normal,
396  get<::Tags::Flux<auxiliary_field_tag, tmpl::size_t<Dim>,
397  Frame::Inertial>>(dirichlet_auxiliary_field_fluxes));
398  };
399  EXPAND_PACK_LEFT_TO_RIGHT(apply_normal_dot_aux(
400  AuxiliaryFieldTags{}, numerical_flux_for_auxiliary_fields));
401 
402  // Compute 2 * sigma * n.F_u(n.F_v(u))
403  auto principal_dirichlet_auxiliary_field_fluxes =
404  make_with_value<Variables<tmpl::list<
406  interface_unit_normal,
408  fluxes_computer.apply(
410  &get<::Tags::Flux<FieldTags, tmpl::size_t<Dim>, Frame::Inertial>>(
411  principal_dirichlet_auxiliary_field_fluxes))...,
412  fluxes_args..., *numerical_flux_for_auxiliary_fields...);
413  const auto assemble_dirichlet_penalty = [
414  &interface_unit_normal, &penalty,
415  &principal_dirichlet_auxiliary_field_fluxes
416  ](auto field_tag_v, const auto numerical_flux_for_field) noexcept {
417  using field_tag = decltype(field_tag_v);
418  normal_dot_flux(
419  numerical_flux_for_field, interface_unit_normal,
420  get<::Tags::Flux<field_tag, tmpl::size_t<Dim>, Frame::Inertial>>(
421  principal_dirichlet_auxiliary_field_fluxes));
422  for (auto it = numerical_flux_for_field->begin();
423  it != numerical_flux_for_field->end(); it++) {
424  *it *= 2 * penalty;
425  }
426  };
428  assemble_dirichlet_penalty(FieldTags{}, numerical_flux_for_fields));
429  }
430 
431  private:
432  double penalty_parameter_ = std::numeric_limits<double>::signaling_NaN();
433 };
434 
435 } // namespace elliptic::dg::NumericalFluxes
domain::push_front
CoordinateMap< SourceFrame, TargetFrame, NewMap, Maps... > push_front(CoordinateMap< SourceFrame, TargetFrame, Maps... > old_map, NewMap new_map) noexcept
Creates a CoordinateMap by prepending the new map to the beginning of the old maps.
std::string
EXPAND_PACK_LEFT_TO_RIGHT
#define EXPAND_PACK_LEFT_TO_RIGHT(...)
Expand a parameter pack evaluating the terms from left to right.
Definition: TMPL.hpp:565
Frame::Inertial
Definition: IndexType.hpp:44
Divergence.hpp
get
constexpr Tag::type & get(Variables< TagList > &v) noexcept
Return Tag::type pointing into the contiguous array.
Definition: Variables.hpp:660
db::PrefixTag
Mark a struct as a prefix tag by inheriting from this.
Definition: Tag.hpp:103
elliptic::dg::NumericalFluxes
Numerical fluxes for elliptic systems.
Definition: FirstOrderInternalPenalty.hpp:36
Options.hpp
FaceNormal.hpp
Tags.hpp
domain::Tags::Mesh
The computational grid of the Element in the DataBox.
Definition: Tags.hpp:107
db::SimpleTag
Mark a struct as a simple tag by inheriting from this.
Definition: Tag.hpp:36
Tags::NormalDotFlux
Prefix indicating a boundary unit normal vector dotted into the flux.
Definition: Prefixes.hpp:96
Tags::Flux
Prefix indicating a flux.
Definition: Prefixes.hpp:40
Direction< Dim >
Tags::div
Prefix indicating the divergence.
Definition: Divergence.hpp:44
Tags::Normalized
Definition: Magnitude.hpp:137
make_with_value
std::remove_const_t< R > make_with_value(const T &input, const ValueType &value) noexcept
Given an object of type T, create an object of type R whose elements are initialized to value.
Definition: MakeWithValue.hpp:88
cstddef
TensorMetafunctions::remove_first_index
::Tensor< typename Tensor::type, tmpl::pop_front< typename Tensor::symmetry >, tmpl::pop_front< typename Tensor::index_list > > remove_first_index
remove the first index of a tensor
Definition: Metafunctions.hpp:113
DataVector
Stores a collection of function values.
Definition: DataVector.hpp:46
std::numeric_limits::signaling_NaN
T signaling_NaN(T... args)
Metafunctions.hpp
elliptic::dg::NumericalFluxes::FirstOrderInternalPenalty
The internal penalty flux for first-order elliptic equations.
Definition: FirstOrderInternalPenalty.hpp:147
std::min
T min(T... args)
Variables.hpp
Mesh
Holds the number of grid points, basis, and quadrature in each direction of the computational grid.
Definition: Mesh.hpp:48
Scalar
Tensor< T, Symmetry<>, index_list<> > Scalar
Definition: TypeAliases.hpp:21
Tags::Magnitude
Definition: Magnitude.hpp:98
Gsl.hpp
Options::String
const char *const String
The string used in option structs.
Definition: Options.hpp:32
domain::Tags::Direction
Definition: Tags.hpp:382
Tensor.hpp
elliptic::dg::penalty
DataVector penalty(const DataVector &element_size, size_t num_points, double penalty_parameter) noexcept
The penalty factor in internal penalty fluxes.
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
Prefixes.hpp
tt::ConformsTo
Indicate a class conforms to the Protocol.
Definition: ProtocolHelpers.hpp:22
TMPL.hpp
gsl::not_null
Require a pointer to not be a nullptr
Definition: ReadSpecThirdOrderPiecewisePolynomial.hpp:13
string