SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/LinearOperators/Filters - Hypercube.hpp Hit Total Coverage
Commit: c3e43f8d41800b0ecefb9d1393f1de1d5a280c8f Lines: 21 57 36.8 %
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 <optional>
       8             : #include <pup.h>
       9             : #include <string>
      10             : #include <unordered_map>
      11             : #include <unordered_set>
      12             : #include <vector>
      13             : 
      14             : #include "DataStructures/Tensor/TypeAliases.hpp"
      15             : #include "NumericalAlgorithms/LinearOperators/Filters/Filter.hpp"
      16             : #include "NumericalAlgorithms/Spectral/Parity.hpp"
      17             : #include "Options/Auto.hpp"
      18             : #include "Options/Context.hpp"
      19             : #include "Options/String.hpp"
      20             : #include "Utilities/Gsl.hpp"
      21             : #include "Utilities/TMPL.hpp"
      22             : 
      23             : /// \cond
      24             : class DataVector;
      25             : template <size_t Dim>
      26             : class Mesh;
      27             : class Matrix;
      28             : template <typename TagsList>
      29             : class Variables;
      30             : /// \endcond
      31             : 
      32             : namespace Filters {
      33             : /*!
      34             :  * \ingroup DiscontinuousGalerkinGroup
      35             :  * \brief An exponential spectral filter applied in each logical direction of
      36             :  * a tensor-product (line, square, cube, ...) element.
      37             :  *
      38             :  * Concrete implementation of `Filters::Filter` for tensor-product
      39             :  * (hypercube) elements, driven by the DG filtering action. See
      40             :  * `Filters::Filter` for the framing of volume vs. boundary application, the
      41             :  * substep / every-N-steps cadence controls, and the `blocks_to_filter`
      42             :  * semantics.
      43             :  *
      44             :  * For each component of the tensors in `TagList`, the filter rescales the
      45             :  * 1-D modal coefficients \f$c_i\f$ in each logical direction as
      46             :  *
      47             :  * \f{align*}{
      48             :  *  c_i \to c_i \exp\!\left[-36 \left(\frac{i}{N}\right)^{2m}\right],
      49             :  * \f}
      50             :  *
      51             :  * where \f$N\f$ is the basis degree (number of grid points per element per
      52             :  * dimension minus one) and \f$m\f$ is the `HalfPower` option. The same
      53             :  * coefficient and `HalfPower` are used in every logical direction. With the
      54             :  * fixed coefficient 36 the highest mode is rescaled by approximately machine
      55             :  * epsilon, i.e. effectively zeroed. For a discussion of filtering see
      56             :  * section 5.3 of \cite HesthavenWarburton.
      57             :  *
      58             :  * #### Design decision:
      59             :  *
      60             :  * The exponential coefficient is hardcoded to 36 since this is what has
      61             :  * worked well in practice for several decades in SpEC. If we ever use
      62             :  * quad or double-double types, we may want to try 72, but that is unlikely to
      63             :  * be necessary since 36 decreases the highest coefficient by 1e-16. I.e.,
      64             :  * this is not relative to the largest coefficient.
      65             :  */
      66             : template <size_t Dim, typename TagList>
      67           1 : class Hypercube : public Filter<Dim, TagList> {
      68             :  public:
      69             :   /*!
      70             :    * \brief Half of the exponent in the exponential.
      71             :    *
      72             :    * I.e., this is \f$m\f$ in
      73             :    *
      74             :    * \f{align*}{
      75             :    *  c_i\to c_i \exp\left[-\alpha \left(\frac{i}{N}\right)^{2m}\right]
      76             :    * \f}
      77             :    */
      78           1 :   struct HalfPower {
      79           0 :     using type = unsigned;
      80           0 :     static constexpr Options::String help =
      81             :         "Half of the exponent in the generalized Gaussian";
      82           0 :     static type lower_bound() { return 1; }
      83             :   };
      84             : 
      85             :   /// \brief Enable the filter
      86           1 :   struct Enable {
      87           0 :     using type = bool;
      88           0 :     static constexpr Options::String help = {"Enable the filter"};
      89             :   };
      90             : 
      91             :   /// \brief Which blocks and block groups the filter should be applied to.
      92           1 :   struct BlocksToFilter {
      93           0 :     using type =
      94             :         Options::Auto<std::vector<std::string>, Options::AutoLabel::All>;
      95           0 :     static constexpr Options::String help = {
      96             :         "List of blocks or block groups to apply filtering to. All other "
      97             :         "blocks will have no filtering. You can also specify 'All' to do "
      98             :         "filtering in all blocks of the domain that are hypercubes."};
      99             :   };
     100             : 
     101             :   /// \brief Apply the volume filter inside every substep instead of only at
     102             :   /// step boundaries.
     103           1 :   struct VolumeFilterOnSubstep {
     104           0 :     using type = bool;
     105           0 :     static constexpr Options::String help = {
     106             :         "Enable the volume filter on every substep."};
     107             :   };
     108             : 
     109             :   /// \brief Apply the boundary correction filter inside every substep instead
     110             :   /// of only at step boundaries.
     111           1 :   struct BoundaryCorrectionFilterOnSubstep {
     112           0 :     using type = bool;
     113           0 :     static constexpr Options::String help = {
     114             :         "Enable the boundary filter on every substep."};
     115             :   };
     116             : 
     117             :   /// \brief Apply the volume filter once every `N` steps. `None`
     118             :   /// (`std::nullopt`) disables the every-N-steps trigger.
     119             :   ///
     120             :   /// \note Currently the check for whether to filter on every `N` steps is done
     121             :   /// relative to the start of the current Slab. This means that for GTS,
     122             :   /// independent of the value of `N` for every `N` steps, every step has a
     123             :   /// filter applied since GTS has one step per slab.
     124           1 :   struct VolumeFilterEveryNSteps {
     125           0 :     using type = Options::Auto<size_t, Options::AutoLabel::None>;
     126           0 :     static constexpr Options::String help = {
     127             :         "Enable the volume filter on every N steps. 'None' to disable."};
     128             :   };
     129             : 
     130             :   /// \brief Apply the boundary correction filter once every `N` steps. `None`
     131             :   /// (`std::nullopt`) disables the every-N-steps trigger.
     132             :   ///
     133             :   /// \note Currently the check for whether to filter on every `N` steps is done
     134             :   /// relative to the start of the current Slab. This means that for GTS,
     135             :   /// independent of the value of `N` for every `N` steps, every step has a
     136             :   /// filter applied since GTS has one step per slab.
     137           1 :   struct BoundaryCorrectionFilterEveryNSteps {
     138           0 :     using type = Options::Auto<size_t, Options::AutoLabel::None>;
     139           0 :     static constexpr Options::String help = {
     140             :         "Enable the boundary filter on every N steps. 'None' to disable."};
     141             :   };
     142             : 
     143           0 :   using options =
     144             :       tmpl::list<HalfPower, Enable, BlocksToFilter, VolumeFilterOnSubstep,
     145             :                  BoundaryCorrectionFilterOnSubstep, VolumeFilterEveryNSteps,
     146             :                  BoundaryCorrectionFilterEveryNSteps>;
     147             : 
     148           0 :   static constexpr Options::String help = {
     149             :       "An exponential filter applied in each direction of a line, square, or "
     150             :       "cube (hypercube)."};
     151             : 
     152           0 :   Hypercube();
     153             : 
     154           0 :   Hypercube(unsigned half_power, bool enable,
     155             :             const std::optional<std::vector<std::string>>& blocks_to_filter,
     156             :             bool volume_filter_on_substep, bool boundary_filter_on_substep,
     157             :             std::optional<size_t> volume_filter_every_n_steps,
     158             :             std::optional<size_t> boundary_filter_every_n_steps,
     159             :             const Options::Context& context = {});
     160             : 
     161           0 :   WRAPPED_PUPable_decl_base_template(  // NOLINT
     162             :       SINGLE_ARG(Filter<Dim, TagList>), Hypercube);
     163           0 :   explicit Hypercube(CkMigrateMessage* msg) : Filter<Dim, TagList>(msg) {}
     164             : 
     165             :   // NOLINTNEXTLINE(google-runtime-references)
     166           0 :   void pup(PUP::er& p) override;
     167             : 
     168           1 :   std::unique_ptr<Filter<Dim, TagList>> get_clone() const override;
     169             : 
     170           1 :   bool apply_volume_filter_on_substep() const override;
     171           1 :   bool apply_volume_filter_on_this_step(size_t step_number) const override;
     172             : 
     173           1 :   bool apply_boundary_filter_on_substep() const override;
     174           1 :   bool apply_boundary_filter_on_this_step(size_t step_number) const override;
     175             : 
     176           1 :   bool need_jacobians() const override { return false; }
     177             : 
     178           1 :   bool supports_mesh(const Mesh<Dim>& mesh) const override;
     179             : 
     180           1 :   std::string name() const override { return "Hypercube"; }
     181             : 
     182           1 :   const std::optional<std::vector<size_t>>& blocks_to_filter() const override;
     183             : 
     184           1 :   void set_blocks_to_filter(
     185             :       const std::vector<std::string>& all_block_names,
     186             :       const std::unordered_map<std::string, std::unordered_set<std::string>>&
     187             :           block_groups) override;
     188             : 
     189           1 :   void apply_in_volume(
     190             :       gsl::not_null<Variables<TagList>*> vars, const Mesh<Dim>& mesh,
     191             :       const std::optional<
     192             :           InverseJacobian<DataVector, Dim, Frame::Grid, Frame::Inertial>>&
     193             :           inv_jac_grid_to_inertial,
     194             :       const std::optional<
     195             :           Jacobian<DataVector, Dim, Frame::Grid, Frame::Inertial>>&
     196             :           jac_grid_to_inertial) const override;
     197             : 
     198           1 :   void apply_on_boundary(
     199             :       gsl::not_null<Variables<TagList>*> vars, const Mesh<Dim - 1>& mesh,
     200             :       const std::optional<
     201             :           InverseJacobian<DataVector, Dim, Frame::Grid, Frame::Inertial>>&
     202             :           inv_jac_grid_to_inertial,
     203             :       const std::optional<
     204             :           Jacobian<DataVector, Dim, Frame::Grid, Frame::Inertial>>&
     205             :           jac_grid_to_inertial) const override;
     206             : 
     207           1 :   bool is_equal(const Filter<Dim, TagList>& other) const override;
     208             : 
     209             :  private:
     210           0 :   const Matrix& filter_matrix(
     211             :       const Mesh<1>& mesh,
     212             :       Spectral::Parity parity = Spectral::Parity::Uninitialized) const;
     213             : 
     214             :   // Apply the parity-aware ZernikeB1 filter to a LocalDim-dimensional mesh
     215             :   // where direction 0 uses ZernikeB1. Each tensor component is filtered with
     216             :   // the Even or Odd direction-0 matrix according to its radial parity;
     217             :   // directions 1..LocalDim-1 use the ordinary parity-independent filter matrix.
     218             :   template <size_t LocalDim>
     219           0 :   void apply_zernikeb1_filter(gsl::not_null<Variables<TagList>*> vars,
     220             :                               const Mesh<LocalDim>& mesh) const;
     221             : 
     222             :   template <size_t LocalDim, typename LocalTagList>
     223             :   // NOLINTNEXTLINE(readability-redundant-declaration)
     224           0 :   friend bool operator==(const Hypercube<LocalDim, LocalTagList>& lhs,
     225             :                          const Hypercube<LocalDim, LocalTagList>& rhs);
     226             : 
     227           0 :   unsigned half_power_{0};
     228           0 :   bool enable_{true};
     229           0 :   std::optional<std::vector<std::string>> blocks_and_groups_to_filter_{};
     230           0 :   std::optional<std::vector<size_t>> blocks_to_filter_{};
     231           0 :   bool volume_filter_on_substep_{false};
     232           0 :   bool boundary_filter_on_substep_{false};
     233           0 :   std::optional<size_t> volume_filter_every_n_steps_{std::nullopt};
     234           0 :   std::optional<size_t> boundary_filter_every_n_steps_{std::nullopt};
     235             : };
     236             : 
     237             : template <size_t Dim, typename TagList>
     238           0 : bool operator==(const Hypercube<Dim, TagList>& lhs,
     239             :                 const Hypercube<Dim, TagList>& rhs);
     240             : 
     241             : template <size_t Dim, typename TagList>
     242           0 : bool operator!=(const Hypercube<Dim, TagList>& lhs,
     243             :                 const Hypercube<Dim, TagList>& rhs);
     244             : }  // namespace Filters

Generated by: LCOV version 1.14