SpECTRE Documentation Coverage Report
Current view: top level - Evolution/DgSubcell - Reconstruction.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 80.0 % 5 4
Test Date: 2026-10-22 17:29:42
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 2.0-1