SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/LinearOperators/Filters - Filter.hpp Hit Total Coverage
Commit: c3e43f8d41800b0ecefb9d1393f1de1d5a280c8f Lines: 14 19 73.7 %
Date: 2026-07-24 22:09:25
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 <cstddef>
       7             : #include <memory>
       8             : #include <optional>
       9             : #include <pup.h>
      10             : #include <string>
      11             : #include <unordered_map>
      12             : #include <unordered_set>
      13             : #include <vector>
      14             : 
      15             : #include "DataStructures/Tensor/TypeAliases.hpp"
      16             : #include "Utilities/Gsl.hpp"
      17             : #include "Utilities/Serialization/CharmPupable.hpp"
      18             : #include "Utilities/TMPL.hpp"
      19             : 
      20             : /// \cond
      21             : class DataVector;
      22             : template <size_t Dim>
      23             : class Mesh;
      24             : template <typename TagsList>
      25             : class Variables;
      26             : /// \endcond
      27             : 
      28             : namespace Filters {
      29             : /*!
      30             :  * \ingroup DiscontinuousGalerkinGroup
      31             :  * \brief Abstract base class for spectral filters.
      32             :  *
      33             :  * Derived classes implement spectral filters that suppress high-frequency
      34             :  * modes in the modal expansion of a discontinuous Galerkin solution. Writing
      35             :  * the 1-D modal coefficients of a tensor component as \f$c_i\f$, a spectral
      36             :  * filter rescales them as
      37             :  *
      38             :  * \f{align*}{
      39             :  *  c_i \to \sigma\!\left(\frac{i}{N}\right) c_i,
      40             :  * \f}
      41             :  *
      42             :  * where \f$N\f$ is the basis degree (number of grid points per element per
      43             :  * dimension minus one) and \f$\sigma\f$ is a derived-class-specific damping
      44             :  * factor (for example, an exponential in `Filters::Hypercube`). For a
      45             :  * discussion of filtering see section 5.3 of \cite HesthavenWarburton.
      46             :  *
      47             :  * The interface is organized along two axes:
      48             :  *
      49             :  * - **Volume vs. boundary.** `apply_in_volume` filters the evolved
      50             :  *   `Variables` on the element's `Dim`-dimensional mesh, while
      51             :  *   `apply_on_boundary` filters data on a `Dim - 1` face mesh. The boundary
      52             :  *   hook is intended for filtering the lifted boundary corrections produced
      53             :  *   by the DG numerical flux before they enter the volume right-hand side.
      54             :  *
      55             :  * - **Substep vs. every-N-steps.** The driving action queries
      56             :  *   `apply_volume_filter_on_substep()` (and the boundary analogue) to decide
      57             :  *   whether to filter inside every Runge-Kutta substep, and
      58             :  *   `apply_volume_filter_on_this_step(step_number)` (and the boundary
      59             :  *   analogue) to gate filtering at coarser cadences such as every `N` full
      60             :  *   steps. The two return values are independent so a derived class may pick
      61             :  *   any combination.
      62             :  *
      63             :  * Derived classes additionally declare via `need_jacobians()` whether they
      64             :  * require the grid-to-inertial Jacobian and its inverse in `apply_in_volume`
      65             :  * / `apply_on_boundary`. When `need_jacobians()` returns `false`, the
      66             :  * driving action passes `std::nullopt` for both Jacobian arguments and skips
      67             :  * computing them.
      68             :  *
      69             :  * The set of domain blocks to which the filter applies is reported by
      70             :  * `blocks_to_filter()`; a `std::nullopt` return value means the filter
      71             :  * applies to every block in the domain.
      72             :  */
      73             : template <size_t Dim, typename TagList>
      74           1 : class Filter : public PUP::able {
      75             :  public:
      76           0 :   Filter() = default;
      77           0 :   ~Filter() noexcept override = default;
      78             : 
      79           0 :   WRAPPED_PUPable_abstract(Filter);  // NOLINT
      80           0 :   explicit Filter(CkMigrateMessage* m) : PUP::able(m) {}
      81             : 
      82             :   /// Return a heap-allocated deep copy of this filter.
      83           1 :   virtual std::unique_ptr<Filter<Dim, TagList>> get_clone() const = 0;
      84             : 
      85             :   /// Whether the volume filter should be applied inside every Runge-Kutta
      86             :   /// substep.
      87           1 :   virtual bool apply_volume_filter_on_substep() const = 0;
      88             : 
      89             :   /// Whether the volume filter should be applied at the given `step_number`.
      90             :   ///
      91             :   /// \note Currently the check for whether to filter on every `N` steps is done
      92             :   /// relative to the start of the current Slab. This means that for GTS,
      93             :   /// independent of the value of `N` for every `N` steps, every step has a
      94             :   /// filter applied since GTS has one step per slab.
      95           1 :   virtual bool apply_volume_filter_on_this_step(size_t step_number) const = 0;
      96             : 
      97             :   /// Whether the boundary filter should be applied inside every Runge-Kutta
      98             :   /// substep.
      99           1 :   virtual bool apply_boundary_filter_on_substep() const = 0;
     100             : 
     101             :   /// Whether the boundary filter should be applied at the given
     102             :   /// `step_number`.
     103             :   ///
     104             :   /// \note Currently the check for whether to filter on every `N` steps is done
     105             :   /// relative to the start of the current Slab. This means that for GTS,
     106             :   /// independent of the value of `N` for every `N` steps, every step has a
     107             :   /// filter applied since GTS has one step per slab.
     108           1 :   virtual bool apply_boundary_filter_on_this_step(size_t step_number) const = 0;
     109             : 
     110             :   /// \brief Whether the filter needs the grid-to-inertial Jacobian and its
     111             :   /// inverse.
     112             :   ///
     113             :   /// When `false`, the driving action passes `std::nullopt` for the Jacobian
     114             :   /// arguments of `apply_in_volume` and `apply_on_boundary` and avoids
     115             :   /// constructing them.
     116           1 :   virtual bool need_jacobians() const = 0;
     117             : 
     118             :   /// \brief Returns `true` if this filter can filter the `mesh`.
     119           1 :   virtual bool supports_mesh(const Mesh<Dim>& mesh) const = 0;
     120             : 
     121             :   /// \brief A human-readable name for the concrete filter type, used in
     122             :   /// diagnostics.
     123           1 :   virtual std::string name() const = 0;
     124             : 
     125             :   /// \brief Returns `true` if `other` is the same concrete filter type and is
     126             :   /// equivalent to `*this`.
     127           1 :   virtual bool is_equal(const Filter& other) const = 0;
     128             : 
     129             :   /// \brief The set of block (or block group) names the filter applies to.
     130             :   ///
     131             :   /// `std::nullopt` means the filter applies to every block in the domain.
     132           1 :   virtual const std::optional<std::vector<size_t>>& blocks_to_filter()
     133             :       const = 0;
     134             : 
     135             :   /// \brief Used after construction to change blocks and groups labeled by
     136             :   /// strings to `size_t`s, which is what is used throughout the code.
     137           1 :   virtual void set_blocks_to_filter(
     138             :       const std::vector<std::string>& all_block_names,
     139             :       const std::unordered_map<std::string, std::unordered_set<std::string>>&
     140             :           block_groups) = 0;
     141             : 
     142             :   /*!
     143             :    * \brief Apply the filter in place to the volume `vars` on the
     144             :    * `Dim`-dimensional `mesh`.
     145             :    *
     146             :    * The grid-to-inertial Jacobian `jac_grid_to_inertial` and its inverse
     147             :    * `inv_jac_grid_to_inertial` are populated only when `need_jacobians()`
     148             :    * returns `true`; otherwise both arguments are `std::nullopt`.
     149             :    */
     150           1 :   virtual void apply_in_volume(
     151             :       gsl::not_null<Variables<TagList>*> vars, const Mesh<Dim>& mesh,
     152             :       const std::optional<
     153             :           InverseJacobian<DataVector, Dim, Frame::Grid, Frame::Inertial>>&
     154             :           inv_jac_grid_to_inertial,
     155             :       const std::optional<
     156             :           Jacobian<DataVector, Dim, Frame::Grid, Frame::Inertial>>&
     157             :           jac_grid_to_inertial) const = 0;
     158             : 
     159             :   /*!
     160             :    * \brief Apply the filter in place to face `vars` on the `Dim - 1` face
     161             :    * `mesh`.
     162             :    *
     163             :    * Used to filter the lifted boundary corrections produced by the DG numerical
     164             :    * flux before they enter the volume right-hand side. The grid-to-inertial
     165             :    * Jacobian `jac_grid_to_inertial` and its inverse `inv_jac_grid_to_inertial`
     166             :    * are populated only when `need_jacobians()` returns `true`; otherwise both
     167             :    * arguments are `std::nullopt`.
     168             :    */
     169           1 :   virtual void apply_on_boundary(
     170             :       gsl::not_null<Variables<TagList>*> vars, const Mesh<Dim - 1>& mesh,
     171             :       const std::optional<
     172             :           InverseJacobian<DataVector, Dim, Frame::Grid, Frame::Inertial>>&
     173             :           inv_jac_grid_to_inertial,
     174             :       const std::optional<
     175             :           Jacobian<DataVector, Dim, Frame::Grid, Frame::Inertial>>&
     176             :           jac_grid_to_inertial) const = 0;
     177             : };
     178             : }  // namespace Filters

Generated by: LCOV version 1.14