SpECTRE Documentation Coverage Report
Current view: top level - Evolution/DiscontinuousGalerkin/Limiters - Weno.hpp Hit Total Coverage
Commit: 664546099c4dbf27a1b708fac45e39c82dd743d2 Lines: 8 47 17.0 %
Date: 2024-04-19 16:28:01
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // 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 <cstddef>
       9             : #include <limits>
      10             : #include <string>
      11             : #include <type_traits>
      12             : #include <unordered_map>
      13             : #include <utility>
      14             : 
      15             : #include "DataStructures/DataBox/Prefixes.hpp"
      16             : #include "DataStructures/Tensor/Tensor.hpp"
      17             : #include "DataStructures/Variables.hpp"
      18             : #include "Domain/SizeOfElement.hpp"
      19             : #include "Domain/Structure/Element.hpp"  // IWYU pragma: keep
      20             : #include "Domain/Structure/OrientationMapHelpers.hpp"
      21             : #include "Domain/Tags.hpp"  // IWYU pragma: keep
      22             : #include "Evolution/DiscontinuousGalerkin/Limiters/HwenoImpl.hpp"
      23             : #include "Evolution/DiscontinuousGalerkin/Limiters/MinmodTci.hpp"
      24             : #include "Evolution/DiscontinuousGalerkin/Limiters/MinmodType.hpp"
      25             : #include "Evolution/DiscontinuousGalerkin/Limiters/SimpleWenoImpl.hpp"
      26             : #include "Evolution/DiscontinuousGalerkin/Limiters/WenoGridHelpers.hpp"
      27             : #include "Evolution/DiscontinuousGalerkin/Limiters/WenoHelpers.hpp"
      28             : #include "Evolution/DiscontinuousGalerkin/Limiters/WenoType.hpp"
      29             : #include "NumericalAlgorithms/Interpolation/RegularGridInterpolant.hpp"
      30             : #include "NumericalAlgorithms/LinearOperators/MeanValue.hpp"
      31             : #include "NumericalAlgorithms/Spectral/Basis.hpp"
      32             : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
      33             : #include "NumericalAlgorithms/Spectral/Quadrature.hpp"
      34             : #include "Options/String.hpp"
      35             : #include "Utilities/Algorithm.hpp"
      36             : #include "Utilities/ErrorHandling/Assert.hpp"
      37             : #include "Utilities/Gsl.hpp"
      38             : #include "Utilities/MakeArray.hpp"
      39             : #include "Utilities/TMPL.hpp"
      40             : #include "Utilities/TaggedTuple.hpp"
      41             : 
      42             : /// \cond
      43             : template <size_t VolumeDim>
      44             : class Direction;
      45             : template <size_t VolumeDim>
      46             : class ElementId;
      47             : 
      48             : namespace PUP {
      49             : class er;
      50             : }  // namespace PUP
      51             : /// \endcond
      52             : 
      53             : namespace Limiters {
      54             : /// \ingroup LimitersGroup
      55             : /// \brief A compact-stencil WENO limiter for DG
      56             : ///
      57             : /// Implements the simple WENO limiter of \cite Zhong2013 and the Hermite WENO
      58             : /// (HWENO) limiter of \cite Zhu2016. The implementation is system-agnostic and
      59             : /// can act on an arbitrary set of tensors.
      60             : ///
      61             : /// #### Summary of the compact-stencil WENO algorithms:
      62             : //
      63             : /// The compact-stencil WENO limiters require communication only between
      64             : /// nearest-neighbor elements, but aim to preserve the full order of the DG
      65             : /// solution when the solution is smooth. To achieve this, full volume data is
      66             : /// communicated between neighbors.
      67             : //
      68             : /// For each tensor component to limit, the new solution is obtained by a
      69             : /// standard WENO procedure --- the new solution is a linear combination of
      70             : /// different polynomials, with weights chosen so that the smoother (i.e., less
      71             : /// oscillatory) polynomials contribute the most to the sum.
      72             : ///
      73             : /// For the simple WENO and HWENO limiters, the polynomials used are the local
      74             : /// DG solution as well as a "modified" solution from each neighbor element. For
      75             : /// the simple WENO limiter, the modified solution is obtained by simply
      76             : /// extrapolating the neighbor solution onto the troubled element. For the HWENO
      77             : /// limiter, the modified solution is obtained by a least-squares fit to the
      78             : /// solution across multiple neighboring elements.
      79             : ///
      80             : /// #### Notes on the SpECTRE implemention of the WENO limiters:
      81             : ///
      82             : /// There are a few differences between the limiters as implemented in SpECTRE
      83             : /// and as presented in the references. We list them here and discuss them
      84             : /// further below.
      85             : /// 1. The choice of basis to represent the DG solution
      86             : /// 2. The system-agnostic implementation
      87             : /// 3. The oscillation indicator
      88             : ///
      89             : /// Finally, in 4., we will discuss the geometric limitations of the
      90             : /// implementation (which are not a deviation from the references).
      91             : ///
      92             : /// ##### 1. The choice of basis
      93             : ///
      94             : /// SpECTRE uses a Legendre basis, rather than the polynomial basis that we
      95             : /// understand to be used in the references. Because the construction of the
      96             : /// modified neighbor solutions and the WENO sum is geometrically motivated, the
      97             : /// overall algorithm should work similarly. However, the precise numerics may
      98             : /// differ.
      99             : ///
     100             : /// ##### 2. The system-agnostic implementation
     101             : //
     102             : /// This implementation can act on an arbitrary set of tensors. To reach this
     103             : /// generality, our HWENO implementation uses a different troubled-cell
     104             : /// indicator (TCI) than the reference, which instead specializes the TCI to the
     105             : /// Newtonian Euler system of equations.
     106             : ///
     107             : /// This implementation uses the minmod-based TVB TCI of \cite Cockburn1999 to
     108             : /// identify elements that need limiting. The simple WENO implementation follows
     109             : /// its reference: it checks the TCI independently for each tensor component, so
     110             : /// that only certain tensor components may be limited. The HWENO implementation
     111             : /// checks the TVB TCI for all tensor components, and if any single component is
     112             : /// troubled, then all components of all tensors are limited.
     113             : ///
     114             : /// When the evolution system has multiple evolved variables, the recommendation
     115             : /// of the references is to apply the limiter to the system's characteristic
     116             : /// variables to reduce spurious post-limiting oscillations. In SpECTRE,
     117             : /// applying the limiter to the characteristic variables requires specializing
     118             : /// the limiter to each evolution system. The system-specific limiter can also
     119             : /// implement a system-specific TCI (as the HWENO reference does) to more
     120             : /// precisely trigger the limiter.
     121             : ///
     122             : /// ##### 3. The oscillation indicator
     123             : ///
     124             : /// We use the oscillation indicator of \cite Dumbser2007, modified for use on
     125             : /// the square/cube grids of SpECTRE. We favor this indicator because portions
     126             : /// of the work can be precomputed, leading to an oscillation measure that is
     127             : /// efficient to evaluate.
     128             : ///
     129             : /// ##### 4. The geometric limitations
     130             : ///
     131             : /// Does not support non-Legendre bases; this is checked in DEBUG mode. In
     132             : /// principle other bases could be supported, but this would require
     133             : /// generalizing the many internal algorithms that assume a Legendre basis.
     134             : ///
     135             : /// Does not support h- or p-refinement; this is checked always. In principle
     136             : /// this could be supported. The modified neighbor solution algorithm would
     137             : /// need to be generalized (reasonable for simple WENO, extremely tedious for
     138             : /// HWENO), and the sum of neighbor solutions may need to be updated as well.
     139             : ///
     140             : /// Does not support curved elements; this is not enforced. The code will run
     141             : /// but we make no guarantees about the results. Specifically, the limiter acts
     142             : /// in the `Frame::ElementLogical` coordinates, because in these coordinates it
     143             : /// is straightforward to formulate the algorithm. This means the limiter can
     144             : /// operate on generic deformed grids --- however, some things can start to
     145             : /// break down, especially on strongly deformed grids:
     146             : /// 1. When the Jacobian (from `Frame::ElementLogical` to `Frame::Inertial`)
     147             : ///    varies across the element, then the limiter fails to be conservative.
     148             : ///    This is because the integral of a tensor `u` over the element will change
     149             : ///    after the limiter activates on `u`.
     150             : /// 2. When computing the modified neighbor solution for the WENO sum, the
     151             : ///    extrapolation or fitting procedure may not properly account for the
     152             : ///    coordinates of the source data. If the coordinate map of the neighbor
     153             : ///    differs from that of the local element, then the logical-coordinate
     154             : ///    representation of the neighbor data may be incorrect. This may be a
     155             : ///    large error at Block boundaries with discontinuous map changes, and may
     156             : ///    be a small error from smoothly-varying maps that are not sufficiently
     157             : ///    resolved from one element to the next.
     158             : template <size_t VolumeDim, typename TagsToLimit>
     159           1 : class Weno;
     160             : 
     161             : template <size_t VolumeDim, typename... Tags>
     162           0 : class Weno<VolumeDim, tmpl::list<Tags...>> {
     163             :  public:
     164             :   /// \brief The WenoType
     165             :   ///
     166             :   /// One of `Limiters::WenoType`. See the `Limiters::Weno`
     167             :   /// documentation for details.
     168           1 :   struct Type {
     169           0 :     using type = WenoType;
     170           0 :     static constexpr Options::String help = {"Type of WENO limiter"};
     171             :   };
     172             :   /// \brief The linear weight given to each neighbor
     173             :   ///
     174             :   /// This linear weight gets combined with the oscillation indicator to
     175             :   /// compute the weight for each WENO estimated solution. The standard value
     176             :   /// in the literature is 0.001; larger values may be better suited for
     177             :   /// problems with strong shocks, and smaller values may be better suited to
     178             :   /// smooth problems.
     179           1 :   struct NeighborWeight {
     180           0 :     using type = double;
     181           0 :     static type lower_bound() { return 1e-6; }
     182           0 :     static type upper_bound() { return 0.1; }
     183           0 :     static constexpr Options::String help = {
     184             :         "Linear weight for each neighbor element's solution"};
     185             :   };
     186             :   /// \brief The TVB constant for the minmod TCI
     187             :   ///
     188             :   /// See `Limiters::Minmod` documentation for details.
     189           1 :   struct TvbConstant {
     190           0 :     using type = double;
     191           0 :     static type lower_bound() { return 0.0; }
     192           0 :     static constexpr Options::String help = {"TVB constant 'm'"};
     193             :   };
     194             :   /// \brief Turn the limiter off
     195             :   ///
     196             :   /// This option exists to temporarily disable the limiter for debugging
     197             :   /// purposes. For problems where limiting is not needed, the preferred
     198             :   /// approach is to not compile the limiter into the executable.
     199           1 :   struct DisableForDebugging {
     200           0 :     using type = bool;
     201           0 :     static type suggested_value() { return false; }
     202           0 :     static constexpr Options::String help = {"Disable the limiter"};
     203             :   };
     204           0 :   using options =
     205             :       tmpl::list<Type, NeighborWeight, TvbConstant, DisableForDebugging>;
     206           0 :   static constexpr Options::String help = {"A WENO limiter for DG"};
     207             : 
     208           0 :   Weno(WenoType weno_type, double neighbor_linear_weight, double tvb_constant,
     209             :        bool disable_for_debugging = false);
     210             : 
     211           0 :   Weno() = default;
     212           0 :   Weno(const Weno& /*rhs*/) = default;
     213           0 :   Weno& operator=(const Weno& /*rhs*/) = default;
     214           0 :   Weno(Weno&& /*rhs*/) = default;
     215           0 :   Weno& operator=(Weno&& /*rhs*/) = default;
     216           0 :   ~Weno() = default;
     217             : 
     218             :   // NOLINTNEXTLINE(google-runtime-references)
     219           0 :   void pup(PUP::er& p);
     220             : 
     221             :   /// \brief Data to send to neighbor elements
     222           1 :   struct PackagedData {
     223           0 :     Variables<tmpl::list<Tags...>> volume_data;
     224           0 :     tuples::TaggedTuple<::Tags::Mean<Tags>...> means;
     225           0 :     Mesh<VolumeDim> mesh;
     226           0 :     std::array<double, VolumeDim> element_size =
     227             :         make_array<VolumeDim>(std::numeric_limits<double>::signaling_NaN());
     228             : 
     229             :     // NOLINTNEXTLINE(google-runtime-references)
     230           0 :     void pup(PUP::er& p) {
     231             :       p | volume_data;
     232             :       p | means;
     233             :       p | mesh;
     234             :       p | element_size;
     235             :     }
     236             :   };
     237             : 
     238           0 :   using package_argument_tags =
     239             :       tmpl::list<Tags..., domain::Tags::Mesh<VolumeDim>,
     240             :                  domain::Tags::SizeOfElement<VolumeDim>>;
     241             : 
     242             :   /// \brief Package data for sending to neighbor elements
     243           1 :   void package_data(gsl::not_null<PackagedData*> packaged_data,
     244             :                     const typename Tags::type&... tensors,
     245             :                     const Mesh<VolumeDim>& mesh,
     246             :                     const std::array<double, VolumeDim>& element_size,
     247             :                     const OrientationMap<VolumeDim>& orientation_map) const;
     248             : 
     249           0 :   using limit_tags = tmpl::list<Tags...>;
     250           0 :   using limit_argument_tags =
     251             :       tmpl::list<domain::Tags::Mesh<VolumeDim>,
     252             :                  domain::Tags::Element<VolumeDim>,
     253             :                  domain::Tags::SizeOfElement<VolumeDim>>;
     254             : 
     255             :   /// \brief Limit the solution on the element
     256           1 :   bool operator()(
     257             :       const gsl::not_null<std::add_pointer_t<typename Tags::type>>... tensors,
     258             :       const Mesh<VolumeDim>& mesh, const Element<VolumeDim>& element,
     259             :       const std::array<double, VolumeDim>& element_size,
     260             :       const std::unordered_map<DirectionalId<VolumeDim>, PackagedData,
     261             :                                boost::hash<DirectionalId<VolumeDim>>>&
     262             :           neighbor_data) const;
     263             : 
     264             :  private:
     265             :   template <size_t LocalDim, typename LocalTagList>
     266             :   // NOLINTNEXTLINE(readability-redundant-declaration) false positive
     267           0 :   friend bool operator==(const Weno<LocalDim, LocalTagList>& lhs,
     268             :                          const Weno<LocalDim, LocalTagList>& rhs);
     269             : 
     270           0 :   WenoType weno_type_;
     271           0 :   double neighbor_linear_weight_;
     272           0 :   double tvb_constant_;
     273           0 :   bool disable_for_debugging_;
     274             : };
     275             : 
     276             : template <size_t VolumeDim, typename... Tags>
     277             : Weno<VolumeDim, tmpl::list<Tags...>>::Weno(const WenoType weno_type,
     278             :                                            const double neighbor_linear_weight,
     279             :                                            const double tvb_constant,
     280             :                                            const bool disable_for_debugging)
     281             :     : weno_type_(weno_type),
     282             :       neighbor_linear_weight_(neighbor_linear_weight),
     283             :       tvb_constant_(tvb_constant),
     284             :       disable_for_debugging_(disable_for_debugging) {}
     285             : 
     286             : template <size_t VolumeDim, typename... Tags>
     287             : // NOLINTNEXTLINE(google-runtime-references)
     288             : void Weno<VolumeDim, tmpl::list<Tags...>>::pup(PUP::er& p) {
     289             :   p | weno_type_;
     290             :   p | neighbor_linear_weight_;
     291             :   p | tvb_constant_;
     292             :   p | disable_for_debugging_;
     293             : }
     294             : 
     295             : template <size_t VolumeDim, typename... Tags>
     296             : void Weno<VolumeDim, tmpl::list<Tags...>>::package_data(
     297             :     const gsl::not_null<PackagedData*> packaged_data,
     298             :     const typename Tags::type&... tensors, const Mesh<VolumeDim>& mesh,
     299             :     const std::array<double, VolumeDim>& element_size,
     300             :     const OrientationMap<VolumeDim>& orientation_map) const {
     301             :   // By always initializing the PackagedData Variables member, we avoid an
     302             :   // assertion that arises from having a default-constructed Variables in a
     303             :   // disabled limiter. There is a performance cost, because the package_data()
     304             :   // function does non-zero work even for a disabled limiter... but since the
     305             :   // limiter should never be disabled in a production simulation, this cost
     306             :   // should never matter.
     307             :   (packaged_data->volume_data).initialize(mesh.number_of_grid_points());
     308             : 
     309             :   if (UNLIKELY(disable_for_debugging_)) {
     310             :     // Do not initialize packaged_data
     311             :     // (except for the Variables member "volume_data", see above)
     312             :     return;
     313             :   }
     314             : 
     315             :   const auto wrap_compute_means = [&mesh, &packaged_data](auto tag,
     316             :                                                           const auto tensor) {
     317             :     for (size_t i = 0; i < tensor.size(); ++i) {
     318             :       // Compute the mean using the local orientation of the tensor and mesh.
     319             :       get<::Tags::Mean<decltype(tag)>>(packaged_data->means)[i] =
     320             :           mean_value(tensor[i], mesh);
     321             :     }
     322             :     return '0';
     323             :   };
     324             :   expand_pack(wrap_compute_means(Tags{}, tensors)...);
     325             : 
     326             :   packaged_data->element_size =
     327             :       orientation_map.permute_from_neighbor(element_size);
     328             : 
     329             :   const auto wrap_copy_tensor = [&packaged_data](auto tag, const auto tensor) {
     330             :     get<decltype(tag)>(packaged_data->volume_data) = tensor;
     331             :     return '0';
     332             :   };
     333             :   expand_pack(wrap_copy_tensor(Tags{}, tensors)...);
     334             :   packaged_data->volume_data = orient_variables(
     335             :       packaged_data->volume_data, mesh.extents(), orientation_map);
     336             : 
     337             :   // Warning: the WENO limiter is currently only tested with aligned meshes.
     338             :   // The orientation of the mesh, the `element_size` computed above, and the
     339             :   // variables should be carefully tested when used with domains that involve
     340             :   // orientation maps
     341             :   packaged_data->mesh = orientation_map(mesh);
     342             : }
     343             : 
     344             : template <size_t VolumeDim, typename... Tags>
     345             : bool Weno<VolumeDim, tmpl::list<Tags...>>::operator()(
     346             :     const gsl::not_null<std::add_pointer_t<typename Tags::type>>... tensors,
     347             :     const Mesh<VolumeDim>& mesh, const Element<VolumeDim>& element,
     348             :     const std::array<double, VolumeDim>& element_size,
     349             :     const std::unordered_map<DirectionalId<VolumeDim>, PackagedData,
     350             :                              boost::hash<DirectionalId<VolumeDim>>>&
     351             :         neighbor_data) const {
     352             :   if (UNLIKELY(disable_for_debugging_)) {
     353             :     // Do not modify input tensors
     354             :     return false;
     355             :   }
     356             : 
     357             :   // Check that basis is LGL or LG
     358             :   // A Legendre basis is assumed for the oscillation indicator (used in both
     359             :   // SimpleWeno and Hweno) and in the Hweno reconstruction.
     360             :   ASSERT(mesh.basis() == make_array<VolumeDim>(Spectral::Basis::Legendre),
     361             :          "Unsupported basis: " << mesh);
     362             :   ASSERT(mesh.quadrature() ==
     363             :                  make_array<VolumeDim>(Spectral::Quadrature::GaussLobatto) or
     364             :              mesh.quadrature() ==
     365             :                  make_array<VolumeDim>(Spectral::Quadrature::Gauss),
     366             :          "Unsupported quadrature: " << mesh);
     367             : 
     368             :   // Enforce restrictions on h-refinement, p-refinement
     369             :   if (UNLIKELY(
     370             :           alg::any_of(element.neighbors(), [](const auto& direction_neighbors) {
     371             :             return direction_neighbors.second.size() != 1;
     372             :           }))) {
     373             :     ERROR("The Weno limiter does not yet support h-refinement");
     374             :     // Removing this limitation will require:
     375             :     // - Generalizing the computation of the modified neighbor solutions.
     376             :     // - Generalizing the WENO weighted sum for multiple neighbors in each
     377             :     //   direction.
     378             :   }
     379             :   alg::for_each(neighbor_data, [&mesh](const auto& neighbor_and_data) {
     380             :     if (UNLIKELY(neighbor_and_data.second.mesh != mesh)) {
     381             :       ERROR("The Weno limiter does not yet support p-refinement");
     382             :       // Removing this limitation will require generalizing the
     383             :       // computation of the modified neighbor solutions.
     384             :     }
     385             :   });
     386             : 
     387             :   if (weno_type_ == WenoType::Hweno) {
     388             :     // Troubled-cell detection for HWENO flags the element for limiting if any
     389             :     // component of any tensor needs limiting.
     390             :     const bool cell_is_troubled =
     391             :         Tci::tvb_minmod_indicator<VolumeDim, PackagedData, Tags...>(
     392             :             tvb_constant_, (*tensors)..., mesh, element, element_size,
     393             :             neighbor_data);
     394             :     if (not cell_is_troubled) {
     395             :       // No limiting is needed
     396             :       return false;
     397             :     }
     398             : 
     399             :     std::unordered_map<DirectionalId<VolumeDim>, DataVector,
     400             :                        boost::hash<DirectionalId<VolumeDim>>>
     401             :         modified_neighbor_solution_buffer{};
     402             :     for (const auto& neighbor_and_data : neighbor_data) {
     403             :       const auto& neighbor = neighbor_and_data.first;
     404             :       modified_neighbor_solution_buffer.insert(
     405             :           std::make_pair(neighbor, DataVector(mesh.number_of_grid_points())));
     406             :     }
     407             : 
     408             :     EXPAND_PACK_LEFT_TO_RIGHT(Weno_detail::hweno_impl<Tags>(
     409             :         make_not_null(&modified_neighbor_solution_buffer), tensors,
     410             :         neighbor_linear_weight_, mesh, element, neighbor_data));
     411             :     return true;  // cell_is_troubled
     412             : 
     413             :   } else if (weno_type_ == WenoType::SimpleWeno) {
     414             :     // Buffers and pre-computations for TCI
     415             :     Minmod_detail::BufferWrapper<VolumeDim> tci_buffer(mesh);
     416             :     const auto effective_neighbor_sizes =
     417             :         Minmod_detail::compute_effective_neighbor_sizes(element, neighbor_data);
     418             : 
     419             :     // Buffers for simple WENO implementation
     420             :     std::unordered_map<DirectionalId<VolumeDim>, intrp::RegularGrid<VolumeDim>,
     421             :                        boost::hash<DirectionalId<VolumeDim>>>
     422             :         interpolator_buffer{};
     423             :     std::unordered_map<DirectionalId<VolumeDim>, DataVector,
     424             :                        boost::hash<DirectionalId<VolumeDim>>>
     425             :         modified_neighbor_solution_buffer{};
     426             : 
     427             :     bool some_component_was_limited = false;
     428             : 
     429             :     const auto wrap_minmod_tci_and_simple_weno_impl =
     430             :         [this, &some_component_was_limited, &tci_buffer, &interpolator_buffer,
     431             :          &modified_neighbor_solution_buffer, &mesh, &element, &element_size,
     432             :          &neighbor_data,
     433             :          &effective_neighbor_sizes](auto tag, const auto tensor) {
     434             :           for (size_t tensor_storage_index = 0;
     435             :                tensor_storage_index < tensor->size(); ++tensor_storage_index) {
     436             :             // Check TCI
     437             :             const auto effective_neighbor_means =
     438             :                 Minmod_detail::compute_effective_neighbor_means<decltype(tag)>(
     439             :                     tensor_storage_index, element, neighbor_data);
     440             :             const bool component_needs_limiting = Tci::tvb_minmod_indicator(
     441             :                 make_not_null(&tci_buffer), tvb_constant_,
     442             :                 (*tensor)[tensor_storage_index], mesh, element, element_size,
     443             :                 effective_neighbor_means, effective_neighbor_sizes);
     444             : 
     445             :             if (component_needs_limiting) {
     446             :               if (modified_neighbor_solution_buffer.empty()) {
     447             :                 // Allocate the neighbor solution buffers only if the limiter is
     448             :                 // triggered. This reduces allocation when no limiting occurs.
     449             :                 for (const auto& neighbor_and_data : neighbor_data) {
     450             :                   const auto& neighbor = neighbor_and_data.first;
     451             :                   modified_neighbor_solution_buffer.insert(std::make_pair(
     452             :                       neighbor, DataVector(mesh.number_of_grid_points())));
     453             :                 }
     454             :               }
     455             :               Weno_detail::simple_weno_impl<decltype(tag)>(
     456             :                   make_not_null(&interpolator_buffer),
     457             :                   make_not_null(&modified_neighbor_solution_buffer), tensor,
     458             :                   neighbor_linear_weight_, tensor_storage_index, mesh, element,
     459             :                   neighbor_data);
     460             :               some_component_was_limited = true;
     461             :             }
     462             :           }
     463             :           return '0';
     464             :         };
     465             :     expand_pack(wrap_minmod_tci_and_simple_weno_impl(Tags{}, tensors)...);
     466             :     return some_component_was_limited;  // cell_is_troubled
     467             :   } else {
     468             :     ERROR("WENO limiter not implemented for WenoType: " << weno_type_);
     469             :   }
     470             : 
     471             :   return false;  // cell_is_troubled
     472             : }
     473             : 
     474             : template <size_t LocalDim, typename LocalTagList>
     475           0 : bool operator==(const Weno<LocalDim, LocalTagList>& lhs,
     476             :                 const Weno<LocalDim, LocalTagList>& rhs) {
     477             :   return lhs.weno_type_ == rhs.weno_type_ and
     478             :          lhs.neighbor_linear_weight_ == rhs.neighbor_linear_weight_ and
     479             :          lhs.tvb_constant_ == rhs.tvb_constant_ and
     480             :          lhs.disable_for_debugging_ == rhs.disable_for_debugging_;
     481             : }
     482             : 
     483             : template <size_t VolumeDim, typename TagList>
     484           0 : bool operator!=(const Weno<VolumeDim, TagList>& lhs,
     485             :                 const Weno<VolumeDim, TagList>& rhs) {
     486             :   return not(lhs == rhs);
     487             : }
     488             : 
     489             : }  // namespace Limiters

Generated by: LCOV version 1.14