SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/DiscontinuousGalerkin - LiftFlux.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 100.0 % 3 3
Test Date: 2026-10-22 17:29:42
Legend: Lines:     hit not hit

            Line data    Source code
       1            1 : // Distributed under the MIT License.
       2              : // See LICENSE.txt for details.
       3              : 
       4              : /// \file
       5              : /// Defines function lift_flux.
       6              : 
       7              : #pragma once
       8              : 
       9              : #include <cstddef>
      10              : #include <utility>
      11              : 
      12              : #include "DataStructures/DataBox/PrefixHelpers.hpp"
      13              : #include "DataStructures/DataVector.hpp"
      14              : #include "DataStructures/Tensor/Tensor.hpp"
      15              : #include "DataStructures/Variables.hpp"
      16              : #include "NumericalAlgorithms/Spectral/Basis.hpp"
      17              : #include "Utilities/Gsl.hpp"
      18              : #include "Utilities/TMPL.hpp"
      19              : 
      20              : namespace dg {
      21              : /// @{
      22              : /// \ingroup DiscontinuousGalerkinGroup
      23              : /// \brief Lifts the flux contribution from an interface to the volume.
      24              : ///
      25              : /// The lifting operation takes the (d-1)-dimensional flux term at the
      26              : /// interface and computes the corresponding d-dimensional term in the
      27              : /// volume. SpECTRE implements an efficient DG method in which each
      28              : /// interface grid point contributes only to that same grid point of the
      29              : /// volume.
      30              : ///
      31              : /// \details
      32              : /// SpECTRE implements a DG method with a diagonalized mass matrix (also
      33              : /// known as a mass-lumping scheme). This choice gives a large
      34              : /// reduction in the computational cost of the lifting operation, however,
      35              : /// the scheme is slightly less accurate, especially when the grid is
      36              : /// deformed by non-trivial Jacobians. For more details on the
      37              : /// diagonalization of the mass matrix and its implications,
      38              : /// \cite Teukolsky2015ega, especially Section 3.
      39              : ///
      40              : /// This function is implemented to handle Legendre, Chebyshev, and Zernike
      41              : /// bases.
      42              : ///
      43              : /// \note The result is still provided only on the boundary grid.  The
      44              : /// values away from the boundary are zero and are not stored.
      45              : template <typename... BoundaryCorrectionTags>
      46            1 : void lift_flux(
      47              :     const gsl::not_null<Variables<tmpl::list<BoundaryCorrectionTags...>>*>
      48              :         boundary_correction_terms,
      49              :     const size_t extent_perpendicular_to_boundary,
      50              :     const Scalar<DataVector>& magnitude_of_face_normal,
      51              :     const Spectral::Basis basis = Spectral::Basis::Legendre) {
      52              :   if (basis == Spectral::Basis::Legendre) {
      53              :     // For an Nth degree basis (i.e., one with N+1 basis functions), the LGL
      54              :     // weights are:
      55              :     //   w_i = 2 / ((N + 1) * N * (P_{N}(xi_i))^2)
      56              :     // and so at the end points (xi = +/- 1) we get:
      57              :     //   w_0 = 2 / ((N + 1) * N)
      58              :     //   w_N = 2 / ((N + 1) * N)
      59              :     // The negative sign comes from bringing the boundary correction over to the
      60              :     // RHS of the equal sign (e.g. `du/dt=Source - div Flux - boundary corr`),
      61              :     // while the magnitude of the normal vector above accounts for the ratios of
      62              :     // spatial metrics and Jacobians.
      63              :     *boundary_correction_terms *=
      64              :         -0.5 *
      65              :         static_cast<double>((extent_perpendicular_to_boundary *
      66              :                              (extent_perpendicular_to_boundary - 1))) *
      67              :         get(magnitude_of_face_normal);
      68              :   } else if (basis == Spectral::Basis::Chebyshev) {
      69              :     // Chebyshev with GaussLobotto, with N grid points, has the weight at
      70              :     // the upper and lower sides
      71              :     // w_0 = 1 / ((N - 1)^2 - a)
      72              :     // w_N = 1 / ((N - 1)^2 - a)
      73              :     // where a = 0 if N is even, else it is 1
      74              :     // The negative sign follows from the Legendre discussion
      75              :     *boundary_correction_terms *=
      76              :         -static_cast<double>((extent_perpendicular_to_boundary - 1) *
      77              :                                  (extent_perpendicular_to_boundary - 1) -
      78              :                              extent_perpendicular_to_boundary % 2) *
      79              :         get(magnitude_of_face_normal);
      80              :   } else if (basis == Spectral::Basis::ZernikeB1) {
      81              :     // ZernikeB1 with GaussRadauUpper, with N grid points, has the weight at
      82              :     // the upper side
      83              :     // w_N = 1 / (N * (2 * N - 1))
      84              :     // The negative sign follows from the Legendre discussion
      85              :     *boundary_correction_terms *=
      86              :         -1.0 *
      87              :         static_cast<double>((extent_perpendicular_to_boundary *
      88              :                              (2 * extent_perpendicular_to_boundary - 1))) *
      89              :         get(magnitude_of_face_normal);
      90              :   } else if (basis == Spectral::Basis::ZernikeB2) {
      91              :     // ZernikeB2 with GaussRadauUpper, with N grid points, has the weight at
      92              :     // the upper side
      93              :     // w_N = 1 / (2 * N^2)
      94              :     // The negative sign follows from the Legendre discussion
      95              :     *boundary_correction_terms *=
      96              :         -1.0 *
      97              :         static_cast<double>((2 * extent_perpendicular_to_boundary *
      98              :                              extent_perpendicular_to_boundary)) *
      99              :         get(magnitude_of_face_normal);
     100              :   } else if (basis == Spectral::Basis::ZernikeB3) {
     101              :     // ZernikeB3 with GaussRadauUpper, with N grid points, has the weight at
     102              :     // the upper side
     103              :     // w_N = 1 / (N * (2 * N + 1))
     104              :     // The negative sign follows from the Legendre discussion
     105              :     *boundary_correction_terms *=
     106              :         -1.0 *
     107              :         static_cast<double>((extent_perpendicular_to_boundary *
     108              :                              (2 * extent_perpendicular_to_boundary + 1))) *
     109              :         get(magnitude_of_face_normal);
     110              :   } else {
     111              :     ERROR("Got unexpected basis " << basis);
     112              :   }
     113              : }
     114              : 
     115              : template <typename... FluxTags>
     116            1 : auto lift_flux(Variables<tmpl::list<FluxTags...>> flux,
     117              :                const size_t extent_perpendicular_to_boundary,
     118              :                const Scalar<DataVector>& magnitude_of_face_normal,
     119              :                const Spectral::Basis basis = Spectral::Basis::Legendre)
     120              :     -> Variables<tmpl::list<db::remove_tag_prefix<FluxTags>...>> {
     121              :   Variables<tmpl::list<db::remove_tag_prefix<FluxTags>...>> lifted_data(
     122              :       std::move(flux));
     123              :   lift_flux(make_not_null(&lifted_data), extent_perpendicular_to_boundary,
     124              :             magnitude_of_face_normal, basis);
     125              :   return lifted_data;
     126              : }
     127              : /// @}
     128              : }  // namespace dg
        

Generated by: LCOV version 2.0-1