SpECTRE Documentation Coverage Report
Current view: top level - Evolution/DgSubcell - Reconstruction.hpp Hit Total Coverage
Commit: c3e43f8d41800b0ecefb9d1393f1de1d5a280c8f Lines: 4 5 80.0 %
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 <algorithm>
       7             : #include <cstddef>
       8             : 
       9             : #include "DataStructures/DataVector.hpp"
      10             : #include "DataStructures/Variables.hpp"
      11             : #include "Evolution/DgSubcell/ReconstructionMethod.hpp"
      12             : #include "NumericalAlgorithms/Spectral/Basis.hpp"
      13             : #include "NumericalAlgorithms/Spectral/Parity.hpp"
      14             : #include "NumericalAlgorithms/Spectral/ParityFromSymmetry.hpp"
      15             : #include "Utilities/ErrorHandling/Assert.hpp"
      16             : #include "Utilities/Gsl.hpp"
      17             : #include "Utilities/MemoryHelpers.hpp"
      18             : #include "Utilities/TMPL.hpp"
      19             : 
      20             : /// \cond
      21             : template <size_t>
      22             : class Index;
      23             : template <size_t>
      24             : class Mesh;
      25             : /// \endcond
      26             : 
      27             : namespace evolution::dg::subcell::fd {
      28             : namespace detail {
      29             : template <size_t Dim>
      30             : void reconstruct_impl(gsl::span<double> dg_u,
      31             :                       gsl::span<const double> subcell_u_times_projected_det_jac,
      32             :                       const Mesh<Dim>& dg_mesh,
      33             :                       const Index<Dim>& subcell_extents,
      34             :                       ReconstructionMethod reconstruction_method,
      35             :                       Spectral::Parity parity);
      36             : 
      37             : /*!
      38             :  * \brief Reconstruct `subcell_u` onto the DG grid, sorting even- and
      39             :  * odd-parity components into separate batches when a ZernikeB1 basis is
      40             :  * present.
      41             :  *
      42             :  * For non-ZernikeB1 meshes this falls through to `reconstruct_impl` with
      43             :  * `Parity::Uninitialized`. The `TagList` must be the full Variables tag list
      44             :  * so that `Spectral::compute_parity_list` can determine per-component parity.
      45             :  */
      46             : template <typename TagList, size_t Dim>
      47             : void reconstruct_impl_with_tag_list(
      48             :     gsl::span<double> dg_u, gsl::span<const double> subcell_u,
      49             :     const Mesh<Dim>& dg_mesh, const Index<Dim>& subcell_extents,
      50             :     const ReconstructionMethod reconstruction_method) {
      51             :   if (dg_mesh.basis(0) == Spectral::Basis::ZernikeB1) {
      52             :     ASSERT(Variables<TagList>::number_of_independent_components *
      53             :                    dg_mesh.number_of_grid_points() ==
      54             :                dg_u.size(),
      55             :            "Passed TagList does not have the same components, "
      56             :                << Variables<TagList>::number_of_independent_components
      57             :                << ", as dg_u holds, "
      58             :                << dg_u.size() / dg_mesh.number_of_grid_points());
      59             :     constexpr auto parity_info = Spectral::compute_parity_list<TagList>();
      60             :     constexpr auto parity_list = std::get<0>(parity_info);
      61             :     constexpr size_t num_even = std::get<1>(parity_info);
      62             :     constexpr size_t num_odd = std::get<2>(parity_info);
      63             : 
      64             :     const size_t num_dg_pts = dg_mesh.number_of_grid_points();
      65             :     const size_t num_subcell_pts = subcell_extents.product();
      66             : 
      67             :     // NOLINTNEXTLINE(modernize-avoid-c-arrays)
      68             :     auto buffer = cpp20::make_unique_for_overwrite<double[]>(
      69             :         (num_even + num_odd) * (num_subcell_pts + num_dg_pts));
      70             :     DataVector even_subcell_input{&buffer[0], num_even * num_subcell_pts};
      71             :     DataVector odd_subcell_input{&buffer[num_even * num_subcell_pts],
      72             :                                  num_odd * num_subcell_pts};
      73             :     DataVector even_dg_output{&buffer[(num_even + num_odd) * num_subcell_pts],
      74             :                               num_even * num_dg_pts};
      75             :     DataVector odd_dg_output{
      76             :         &buffer[(num_even + num_odd) * num_subcell_pts + num_even * num_dg_pts],
      77             :         num_odd * num_dg_pts};
      78             : 
      79             :     // Sort subcell input into even/odd parity buffers
      80             :     const double* p_in = subcell_u.data();
      81             :     double* p_even_in = even_subcell_input.data();
      82             :     double* p_odd_in = odd_subcell_input.data();
      83             :     bool is_even = true;
      84             :     for (const size_t seg_size : parity_list) {
      85             :       if (seg_size == 0) {
      86             :         if (is_even) {
      87             :           is_even = false;
      88             :           continue;
      89             :         } else {
      90             :           break;
      91             :         }
      92             :       }
      93             :       if (is_even) {
      94             :         std::copy(p_in, p_in + seg_size * num_subcell_pts,  // NOLINT
      95             :                   p_even_in);
      96             :         p_even_in += seg_size * num_subcell_pts;  // NOLINT
      97             :       } else {
      98             :         std::copy(p_in, p_in + seg_size * num_subcell_pts,  // NOLINT
      99             :                   p_odd_in);
     100             :         p_odd_in += seg_size * num_subcell_pts;  // NOLINT
     101             :       }
     102             :       p_in += seg_size * num_subcell_pts;  // NOLINT
     103             :       is_even = not is_even;
     104             :     }
     105             : 
     106             :     // Reconstruct each parity batch with the appropriate reconstruction
     107             :     // matrix
     108             :     if constexpr (num_even > 0) {
     109             :       reconstruct_impl(
     110             :           gsl::span<double>{even_dg_output.data(), even_dg_output.size()},
     111             :           gsl::span<const double>{even_subcell_input.data(),
     112             :                                   even_subcell_input.size()},
     113             :           dg_mesh, subcell_extents, reconstruction_method,
     114             :           Spectral::Parity::Even);
     115             :     }
     116             :     if constexpr (num_odd > 0) {
     117             :       reconstruct_impl(
     118             :           gsl::span<double>{odd_dg_output.data(), odd_dg_output.size()},
     119             :           gsl::span<const double>{odd_subcell_input.data(),
     120             :                                   odd_subcell_input.size()},
     121             :           dg_mesh, subcell_extents, reconstruction_method,
     122             :           Spectral::Parity::Odd);
     123             :     }
     124             : 
     125             :     // Reassemble output in original component order
     126             :     double* p_out = dg_u.data();
     127             :     const double* p_even_out = even_dg_output.data();
     128             :     const double* p_odd_out = odd_dg_output.data();
     129             :     is_even = true;
     130             :     for (const size_t seg_size : parity_list) {
     131             :       if (seg_size == 0) {
     132             :         if (is_even) {
     133             :           is_even = false;
     134             :           continue;
     135             :         } else {
     136             :           break;
     137             :         }
     138             :       }
     139             :       if (is_even) {
     140             :         // NOLINTNEXTLINE
     141             :         std::copy(p_even_out, p_even_out + seg_size * num_dg_pts, p_out);
     142             :         p_even_out += seg_size * num_dg_pts;  // NOLINT
     143             :       } else {
     144             :         // NOLINTNEXTLINE
     145             :         std::copy(p_odd_out, p_odd_out + seg_size * num_dg_pts, p_out);
     146             :         p_odd_out += seg_size * num_dg_pts;  // NOLINT
     147             :       }
     148             :       p_out += seg_size * num_dg_pts;  // NOLINT
     149             :       is_even = not is_even;
     150             :     }
     151             :     return;
     152             :   }
     153             :   reconstruct_impl(dg_u, subcell_u, dg_mesh, subcell_extents,
     154             :                    reconstruction_method, Spectral::Parity::Uninitialized);
     155             : }
     156             : }  // namespace detail
     157             : 
     158             : /// @{
     159             : /*!
     160             :  * \ingroup DgSubcellGroup
     161             :  * \brief reconstruct the variable `subcell_u_times_projected_det_jac` onto the
     162             :  * DG grid `dg_mesh`.
     163             :  *
     164             :  * In general we wish that the reconstruction operator is the pseudo-inverse of
     165             :  * the projection operator. On curved meshes this means we either need to
     166             :  * compute a (time-dependent) reconstruction and projection matrix on each DG
     167             :  * element, or we expand the determinant of the Jacobian on the basis, accepting
     168             :  * the aliasing errors from that. We accept the aliasing errors in favor of the
     169             :  * significantly reduced computational overhead. This means that the projection
     170             :  * and reconstruction operators are only inverses of each other if both operate
     171             :  * on \f$u J\f$ where \f$u\f$ is the variable being projected and \f$J\f$ is the
     172             :  * determinant of the Jacobian. That is, the matrices are guaranteed to satisfy
     173             :  * \f$\mathcal{R}(\mathcal{P}(u J))=u J\f$. If the mesh is regular Cartesian,
     174             :  * then this isn't an issue. Furthermore, if we reconstruct
     175             :  * \f$uJ/\mathcal{P}(J)\f$ we again recover the exact DG solution. Doing the
     176             :  * latter has the advantage that, in general, we are ideally projecting to the
     177             :  * subcells much more often than reconstructing from them (a statement that we
     178             :  * would rather use DG more than the subcells).
     179             :  *
     180             :  * When the DG mesh uses a ZernikeB1 basis the Variables overloads deduce
     181             :  * per-component parity from the tag list automatically. The raw `DataVector`
     182             :  * overloads accepting a `Spectral::Parity` are for single-component data where
     183             :  * the caller already knows the parity. Only `DimByDim` reconstruction is
     184             :  * supported for ZernikeB1 meshes.
     185             :  */
     186             : template <size_t Dim>
     187           1 : DataVector reconstruct(
     188             :     const DataVector& subcell_u_times_projected_det_jac,
     189             :     const Mesh<Dim>& dg_mesh, const Index<Dim>& subcell_extents,
     190             :     ReconstructionMethod reconstruction_method,
     191             :     Spectral::Parity parity = Spectral::Parity::Uninitialized);
     192             : 
     193             : template <size_t Dim>
     194           1 : void reconstruct(gsl::not_null<DataVector*> dg_u,
     195             :                  const DataVector& subcell_u_times_projected_det_jac,
     196             :                  const Mesh<Dim>& dg_mesh, const Index<Dim>& subcell_extents,
     197             :                  ReconstructionMethod reconstruction_method,
     198             :                  Spectral::Parity parity = Spectral::Parity::Uninitialized);
     199             : 
     200             : template <typename SubcellTagList, typename DgTagList, size_t Dim>
     201           1 : void reconstruct(const gsl::not_null<Variables<DgTagList>*> dg_u,
     202             :                  const Variables<SubcellTagList>& subcell_u,
     203             :                  const Mesh<Dim>& dg_mesh, const Index<Dim>& subcell_extents,
     204             :                  const ReconstructionMethod reconstruction_method) {
     205             :   ASSERT(subcell_u.number_of_grid_points() == subcell_extents.product(),
     206             :          "Incorrect subcell size of u: " << subcell_u.number_of_grid_points()
     207             :                                          << " but should be "
     208             :                                          << subcell_extents.product());
     209             :   if (UNLIKELY(dg_u->number_of_grid_points() !=
     210             :                dg_mesh.number_of_grid_points())) {
     211             :     dg_u->initialize(dg_mesh.number_of_grid_points(), 0.0);
     212             :   }
     213             :   detail::reconstruct_impl_with_tag_list<DgTagList>(
     214             :       gsl::span<double>{dg_u->data(), dg_u->size()},
     215             :       gsl::span<const double>{subcell_u.data(), subcell_u.size()}, dg_mesh,
     216             :       subcell_extents, reconstruction_method);
     217             : }
     218             : 
     219             : template <typename TagList, size_t Dim>
     220           1 : Variables<TagList> reconstruct(
     221             :     const Variables<TagList>& subcell_u, const Mesh<Dim>& dg_mesh,
     222             :     const Index<Dim>& subcell_extents,
     223             :     const ReconstructionMethod reconstruction_method) {
     224             :   Variables<TagList> dg_u(dg_mesh.number_of_grid_points());
     225             :   reconstruct(make_not_null(&dg_u), subcell_u, dg_mesh, subcell_extents,
     226             :               reconstruction_method);
     227             :   return dg_u;
     228             : }
     229             : /// @}
     230             : }  // namespace evolution::dg::subcell::fd

Generated by: LCOV version 1.14