SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/FiniteDifference - HighOrderFluxCorrection.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 <array>
       7              : #include <cstddef>
       8              : #include <iterator>
       9              : #include <limits>
      10              : #include <type_traits>
      11              : #include <utility>
      12              : 
      13              : #include "DataStructures/DataBox/Prefixes.hpp"
      14              : #include "DataStructures/DataVector.hpp"
      15              : #include "DataStructures/Index.hpp"
      16              : #include "DataStructures/Tensor/Tensor.hpp"
      17              : #include "DataStructures/Variables.hpp"
      18              : #include "Domain/Structure/Direction.hpp"
      19              : #include "Domain/Structure/DirectionMap.hpp"
      20              : #include "Domain/Structure/DirectionalIdMap.hpp"
      21              : #include "Domain/Structure/ElementId.hpp"
      22              : #include "Evolution/DgSubcell/GhostData.hpp"
      23              : #include "NumericalAlgorithms/FiniteDifference/DerivativeOrder.hpp"
      24              : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
      25              : #include "Utilities/Algorithm.hpp"
      26              : #include "Utilities/ErrorHandling/Error.hpp"
      27              : #include "Utilities/Gsl.hpp"
      28              : #include "Utilities/OptionalHelpers.hpp"
      29              : #include "Utilities/TMPL.hpp"
      30              : 
      31              : namespace fd {
      32              : /// @{
      33              : /*!
      34              :  * \brief Computes a high-order boundary correction $G$ at the FD interface.
      35              :  *
      36              :  * The correction to the second-order boundary correction is given by
      37              :  *
      38              :  * \f{align*}{
      39              :  *  G=G^{(2)}-G^{(4)}+G^{(6)}-G^{(8)}+G^{(10)},
      40              :  * \f}
      41              :  *
      42              :  * where
      43              :  *
      44              :  *\f{align*}{
      45              :  * G^{(4)}_{j+1/2}&=\frac{1}{6}\left(G_j -2 G^{(2)} +
      46              :  *                         G_{j+1}\right), \\
      47              :  * G^{(6)}_{j+1/2}&=\frac{1}{180}\left(G_{j-1} - 9 G_j + 16 G^{(2)}
      48              :  *                         -9 G_{j+1} + G_{j+2}\right), \\
      49              :  * G^{(8)}_{j+1/2}&=\frac{1}{2100}\left(G_{j-2} - \frac{25}{3} G_{j-1}
      50              :  *                         + 50 G_j - \frac{256}{3} G^{(2)} + 50 G_{j+1}
      51              :  *                         - \frac{25}{3} G_{j+2} +G_{j+3}\right), \\
      52              :  * G^{(10)}_{j+1/2}&=\frac{1}{17640}
      53              :  *                         \left(G_{j-3} - \frac{49}{5} G_{j-2}
      54              :  *                     + 49 G_{j-1} - 245 G_j + \frac{2048}{5} G^{(2)}\right.
      55              :  *                         \nonumber \\
      56              :  *                       &\left.- 245 G_{j+1}+ 49 G_{j+2} - \frac{49}{5} G_{j+3}
      57              :  *                         + G_{j+4}\right),
      58              :  * \f}
      59              :  *
      60              :  * where
      61              :  *
      62              :  * \f{align*}{
      63              :  *  G_{j} &= F^i_j n_i^{j+1/2}, \\
      64              :  *  G_{j\pm1} &= F^i_{j\pm1} n_i^{j+1/2}, \\
      65              :  *  G_{j\pm2} &= F^i_{j\pm2} n_i^{j+1/2}, \\
      66              :  *  G_{j\pm3} &= F^i_{j\pm3} n_i^{j+1/2}, \\
      67              :  *  G_{j\pm4} &= F^i_{j\pm4} n_i^{j+1/2}.
      68              :  * \f}
      69              :  *
      70              :  * This is a generalization of the correction presented in \cite CHEN2016604.
      71              :  *
      72              :  * This high-order flux can be fed into a flux limiter, e.g. to guarantee
      73              :  * positivity.
      74              :  *
      75              :  * \note This implementation should be profiled and optimized.
      76              :  *
      77              :  * \warning This documentation is for the general case. In the restricted
      78              :  * Cartesian case we use the cell-centered flux as opposed to `G^{(4)}`, which
      79              :  * differs by a minus sign. This amounts to a minus sign change in front of the
      80              :  * $G^{(k)}$ terms in computing $G$ for $k>2$, and also a sign change in front
      81              :  * of $G^{(2)}$ in all $G^{(k)}$ for $k>2$.
      82              :  */
      83              : template <DerivativeOrder DerivOrder, size_t Dim, typename... EvolvedVarsTags>
      84            1 : void cartesian_high_order_fluxes_using_nodes(
      85              :     const gsl::not_null<
      86              :         std::array<Variables<tmpl::list<EvolvedVarsTags...>>, Dim>*>
      87              :         high_order_boundary_corrections_in_logical_direction,
      88              : 
      89              :     const std::array<Variables<tmpl::list<EvolvedVarsTags...>>, Dim>&
      90              :         second_order_boundary_corrections_in_logical_direction,
      91              :     const Variables<tmpl::list<
      92              :         ::Tags::Flux<EvolvedVarsTags, tmpl::size_t<Dim>, Frame::Inertial>...>>&
      93              :         cell_centered_inertial_flux,
      94              :     const DirectionMap<
      95              :         Dim, Variables<tmpl::list<::Tags::Flux<
      96              :                  EvolvedVarsTags, tmpl::size_t<Dim>, Frame::Inertial>...>>>&
      97              :         ghost_cell_inertial_flux,
      98              :     const Mesh<Dim>& subcell_mesh, const size_t number_of_ghost_cells,
      99              :     const std::array<gsl::span<std::uint8_t>, Dim>& reconstruction_order = {},
     100              :     const bool aligned_coordinates = true,
     101              :     const std::array<tnsr::i<DataVector, Dim, Frame::Inertial>, Dim>& normal =
     102              :         {},
     103              :     const std::array<
     104              :         DirectionMap<Dim, tnsr::i<DataVector, Dim, Frame::Inertial>>, Dim>&
     105              :         ghost_cell_normal = {}) {
     106              :   using std::min;
     107              :   static_assert(Dim > 0 and Dim <= 3, "Dim must be 1, 2, or 3");
     108              :   constexpr int max_correction_order = 10;
     109              :   static_assert(static_cast<int>(DerivOrder) <= max_correction_order);
     110              :   constexpr size_t stencil_size = static_cast<int>(DerivOrder) < 0
     111              :                                       ? 8
     112              :                                       : (static_cast<size_t>(DerivOrder) - 2);
     113              :   const size_t correction_width =
     114              :       min(static_cast<size_t>(DerivOrder) / 2 - 1,
     115              :           min(number_of_ghost_cells, stencil_size / 2));
     116              :   ASSERT(correction_width <= number_of_ghost_cells,
     117              :          "The width of the derivative correction ("
     118              :              << correction_width
     119              :              << ") must be less than or equal to the number of ghost cells "
     120              :              << number_of_ghost_cells);
     121              :   ASSERT(alg::all_of(reconstruction_order,
     122              :                      [](const auto& t) { return not t.empty(); }) or
     123              :              static_cast<int>(DerivOrder) > 0,
     124              :          "For adaptive derivative orders the reconstruction_order must be set");
     125              :   ASSERT(normal[0][0].size() != 0 or aligned_coordinates,
     126              :          "Normal vectors must be specified when coordinate systems are not "
     127              :          "aligned");
     128              :   for (size_t dim = 0; dim < Dim; ++dim) {
     129              :     gsl::at(*high_order_boundary_corrections_in_logical_direction, dim)
     130              :         .initialize(
     131              :             gsl::at(second_order_boundary_corrections_in_logical_direction, dim)
     132              :                 .number_of_grid_points());
     133              :   }
     134              : 
     135              :   // Reconstruction order is always first-varying fastest since we don't
     136              :   // transpose that back to {x,y,z} ordering.
     137              :   Index<Dim> reconstruction_extents = subcell_mesh.extents();
     138              :   reconstruction_extents[0] += 2;
     139              : 
     140              :   const auto impl = [&cell_centered_inertial_flux, &ghost_cell_inertial_flux,
     141              :                      &high_order_boundary_corrections_in_logical_direction,
     142              :                      number_of_ghost_cells,
     143              :                      &second_order_boundary_corrections_in_logical_direction,
     144              :                      &subcell_mesh, &correction_width, &reconstruction_order,
     145              :                      &reconstruction_extents, &normal,
     146              :                      &ghost_cell_normal]<typename tag, size_t dim,
     147              :                                          bool AlignedCoordinates>(
     148              :                         tmpl::type_<tag> /*meta*/,
     149              :                         std::integral_constant<size_t, dim> /*meta*/,
     150              :                         std::integral_constant<bool,
     151              :                                                AlignedCoordinates> /*meta*/) {
     152              :     (void)reconstruction_extents;
     153              : 
     154              :     auto& high_order_var_correction =
     155              :         get<tag>((*high_order_boundary_corrections_in_logical_direction)[dim]);
     156              :     const auto& second_order_var_correction =
     157              :         get<tag>(second_order_boundary_corrections_in_logical_direction[dim]);
     158              :     const auto& recons_order = reconstruction_order[dim];
     159              :     const auto& cell_centered_flux =
     160              :         get<::Tags::Flux<tag, tmpl::size_t<Dim>, Frame::Inertial>>(
     161              :             cell_centered_inertial_flux);
     162              :     const auto& lower_neighbor_cell_centered_flux =
     163              :         get<::Tags::Flux<tag, tmpl::size_t<Dim>, Frame::Inertial>>(
     164              :             ghost_cell_inertial_flux.at(Direction<Dim>{dim, Side::Lower}));
     165              :     const auto& upper_neighbor_cell_centered_flux =
     166              :         get<::Tags::Flux<tag, tmpl::size_t<Dim>, Frame::Inertial>>(
     167              :             ghost_cell_inertial_flux.at(Direction<Dim>{dim, Side::Upper}));
     168              :     using FluxTensor = std::decay_t<decltype(cell_centered_flux)>;
     169              :     const auto& subcell_extents = subcell_mesh.extents();
     170              :     auto subcell_face_extents = subcell_extents;
     171              :     ++subcell_face_extents[dim];
     172              :     auto neighbor_extents = subcell_extents;
     173              :     neighbor_extents[dim] = number_of_ghost_cells;
     174              :     const size_t number_of_components = second_order_var_correction.size();
     175              :     for (size_t storage_index = 0; storage_index < number_of_components;
     176              :          ++storage_index) {
     177              :       std::array<size_t, Dim> flux_storage_indices;
     178              :       for (size_t n = 0; n < Dim; ++n) {
     179              :         const auto temp_multi_index = prepend(
     180              :             second_order_var_correction.get_tensor_index(storage_index), n);
     181              :         flux_storage_indices[n] =
     182              :             FluxTensor::get_storage_index(temp_multi_index);
     183              :       }
     184              :       for (size_t k = 0; k < (Dim == 3 ? subcell_face_extents[2] : 1); ++k) {
     185              :         for (size_t j = 0; j < (Dim >= 2 ? subcell_face_extents[1] : 1); ++j) {
     186              :           for (size_t i = 0; i < subcell_face_extents[0]; ++i) {
     187              :             const Index<Dim> face_index = [i, j, k]() -> Index<Dim> {
     188              :               if constexpr (Dim == 3) {
     189              :                 return Index<Dim>{i, j, k};
     190              :               } else if constexpr (Dim == 2) {
     191              :                 (void)k;
     192              :                 return Index<Dim>{i, j};
     193              :               } else {
     194              :                 (void)k, (void)j;
     195              :                 return Index<Dim>{i};
     196              :               }
     197              :             }();
     198              :             const size_t face_storage_index =
     199              :                 collapsed_index(face_index, subcell_face_extents);
     200              :             Index<Dim> neighbor_index{};
     201              :             for (size_t l = 0; l < Dim; ++l) {
     202              :               if (l != dim) {
     203              :                 neighbor_index[l] = face_index[l];
     204              :               }
     205              :             }
     206              : 
     207              :             double& correction =
     208              :                 high_order_var_correction[storage_index][face_storage_index] =
     209              :                     0.0;
     210              : 
     211              :             std::array<double, stencil_size> cell_centered_fluxes_for_stencil{};
     212              :             // fill if we have to retrieve from lower neighbor; compute a
     213              :             // dot-product with normal components when coordinates are not
     214              :             // aligned
     215              :             size_t stencil_index = 0;
     216              :             for (int grid_index = static_cast<int>(face_index[dim]) -
     217              :                                   static_cast<int>(correction_width);
     218              :                  grid_index < static_cast<int>(face_index[dim]) +
     219              :                                   static_cast<int>(correction_width);
     220              :                  ++grid_index, ++stencil_index) {
     221              :               if (grid_index < 0) {
     222              :                 neighbor_index[dim] =
     223              :                     number_of_ghost_cells + static_cast<size_t>(grid_index);
     224              :                 const size_t idx_flat =
     225              :                     collapsed_index(neighbor_index, neighbor_extents);
     226              :                 double normal_flux = 0.0;
     227              :                 for (size_t n = 0; n < Dim; ++n) {
     228              :                   const double normal_in_direction =
     229              :                       AlignedCoordinates
     230              :                           ? (n == dim ? 1.0 : 0.0)
     231              :                           : ghost_cell_normal[dim]
     232              :                                 .at(Direction<Dim>{dim, Side::Lower})
     233              :                                 .get(n)[idx_flat];
     234              :                   normal_flux +=
     235              :                       lower_neighbor_cell_centered_flux[flux_storage_indices[n]]
     236              :                                                        [idx_flat] *
     237              :                       normal_in_direction;
     238              :                 }
     239              :                 gsl::at(cell_centered_fluxes_for_stencil, stencil_index) =
     240              :                     normal_flux;
     241              :               } else if (grid_index >= static_cast<int>(subcell_extents[dim])) {
     242              :                 neighbor_index[dim] = static_cast<size_t>(
     243              :                     grid_index - static_cast<int>(subcell_extents[dim]));
     244              :                 const size_t idx_flat =
     245              :                     collapsed_index(neighbor_index, neighbor_extents);
     246              :                 double normal_flux = 0.0;
     247              :                 for (size_t n = 0; n < Dim; ++n) {
     248              :                   const double normal_in_direction =
     249              :                       AlignedCoordinates
     250              :                           ? (n == dim ? 1.0 : 0.0)
     251              :                           : ghost_cell_normal[dim]
     252              :                                 .at(Direction<Dim>{dim, Side::Upper})
     253              :                                 .get(n)[idx_flat];
     254              :                   normal_flux +=
     255              :                       upper_neighbor_cell_centered_flux[flux_storage_indices[n]]
     256              :                                                        [idx_flat] *
     257              :                       normal_in_direction;
     258              :                 }
     259              :                 gsl::at(cell_centered_fluxes_for_stencil, stencil_index) =
     260              :                     normal_flux;
     261              :               } else {
     262              :                 Index<Dim> volume_index = face_index;
     263              :                 volume_index[dim] = static_cast<size_t>(grid_index);
     264              :                 const size_t idx_flat =
     265              :                     collapsed_index(volume_index, subcell_extents);
     266              :                 double normal_flux = 0.0;
     267              :                 for (size_t n = 0; n < Dim; ++n) {
     268              :                   const double normal_in_direction =
     269              :                       AlignedCoordinates ? (n == dim ? 1.0 : 0.0)
     270              :                                          : normal[dim].get(n)[idx_flat];
     271              :                   normal_flux +=
     272              :                       cell_centered_flux[flux_storage_indices[n]][idx_flat] *
     273              :                       normal_in_direction;
     274              :                 }
     275              :                 gsl::at(cell_centered_fluxes_for_stencil, stencil_index) =
     276              :                     normal_flux;
     277              :               }
     278              :             }
     279              : 
     280              :             size_t lower_neighbor_index = std::numeric_limits<size_t>::max();
     281              :             size_t upper_neighbor_index = std::numeric_limits<size_t>::max();
     282              :             if constexpr (static_cast<int>(DerivOrder) < 0) {
     283              :               Index<Dim> lower_n{};
     284              :               Index<Dim> upper_n{};
     285              :               if constexpr (dim == 0) {
     286              :                 if constexpr (Dim == 1) {
     287              :                   lower_n = Index<Dim>{i};
     288              :                   upper_n = Index<Dim>{i + 1};
     289              :                 } else if constexpr (Dim == 2) {
     290              :                   lower_n = Index<Dim>{i, j};
     291              :                   upper_n = Index<Dim>{i + 1, j};
     292              :                 } else if constexpr (Dim == 3) {
     293              :                   lower_n = Index<Dim>{i, j, k};
     294              :                   upper_n = Index<Dim>{i + 1, j, k};
     295              :                 }
     296              :               } else if constexpr (dim == 1) {
     297              :                 if constexpr (Dim == 2) {
     298              :                   lower_n = Index<Dim>{j, i};
     299              :                   upper_n = Index<Dim>{j + 1, i};
     300              :                 } else if constexpr (Dim == 3) {
     301              :                   lower_n = Index<Dim>{j, k, i};
     302              :                   upper_n = Index<Dim>{j + 1, k, i};
     303              :                 }
     304              :               } else if constexpr (dim == 2) {
     305              :                 if constexpr (Dim == 3) {
     306              :                   lower_n = Index<Dim>{k, i, j};
     307              :                   upper_n = Index<Dim>{k + 1, i, j};
     308              :                 }
     309              :               }
     310              :               lower_neighbor_index =
     311              :                   collapsed_index(lower_n, reconstruction_extents);
     312              :               upper_neighbor_index =
     313              :                   collapsed_index(upper_n, reconstruction_extents);
     314              :             }
     315              : 
     316              :             if (static_cast<int>(DerivOrder) >= 10 or
     317              :                 (static_cast<int>(DerivOrder) < 0 and
     318              :                  min(recons_order[lower_neighbor_index],
     319              :                      recons_order[upper_neighbor_index]) >= 9)) {
     320              :               correction -=
     321              :                   5.6689342403628117913e-5 *
     322              :                   (gsl::at(cell_centered_fluxes_for_stencil,
     323              :                            correction_width - 4) +
     324              :                    gsl::at(cell_centered_fluxes_for_stencil,
     325              :                            correction_width + 3) -
     326              :                    9.8 * (gsl::at(cell_centered_fluxes_for_stencil,
     327              :                                   correction_width - 3) +
     328              :                           gsl::at(cell_centered_fluxes_for_stencil,
     329              :                                   correction_width + 2)) +
     330              :                    49.0 * (gsl::at(cell_centered_fluxes_for_stencil,
     331              :                                    correction_width - 2) +
     332              :                            gsl::at(cell_centered_fluxes_for_stencil,
     333              :                                    correction_width + 1)) -
     334              :                    245.0 * (gsl::at(cell_centered_fluxes_for_stencil,
     335              :                                     correction_width - 1) +
     336              :                             gsl::at(cell_centered_fluxes_for_stencil,
     337              :                                     correction_width)) -
     338              :                    409.6 * second_order_var_correction[storage_index]
     339              :                                                       [face_storage_index]);
     340              :             }
     341              :             if (static_cast<int>(DerivOrder) >= 8 or
     342              :                 (static_cast<int>(DerivOrder) < 0 and
     343              :                  min(recons_order[lower_neighbor_index],
     344              :                      recons_order[upper_neighbor_index]) >= 7)) {
     345              :               correction +=
     346              :                   4.7619047619047619047e-4 *
     347              :                   (gsl::at(cell_centered_fluxes_for_stencil,
     348              :                            correction_width - 3) +
     349              :                    gsl::at(cell_centered_fluxes_for_stencil,
     350              :                            correction_width + 2) -
     351              :                    8.3333333333333333333 *
     352              :                        (gsl::at(cell_centered_fluxes_for_stencil,
     353              :                                 correction_width - 2) +
     354              :                         gsl::at(cell_centered_fluxes_for_stencil,
     355              :                                 correction_width + 1)) +
     356              :                    50.0 * (gsl::at(cell_centered_fluxes_for_stencil,
     357              :                                    correction_width - 1) +
     358              :                            gsl::at(cell_centered_fluxes_for_stencil,
     359              :                                    correction_width)) +
     360              :                    85.333333333333333333 *
     361              :                        second_order_var_correction[storage_index]
     362              :                                                   [face_storage_index]);
     363              :             }
     364              :             if (static_cast<int>(DerivOrder) >= 6 or
     365              :                 (static_cast<int>(DerivOrder) < 0 and
     366              :                  min(recons_order[lower_neighbor_index],
     367              :                      recons_order[upper_neighbor_index]) >=
     368              :                      (DerivOrder ==
     369              :                               DerivativeOrder::OneHigherThanReconsButFiveToFour
     370              :                           ? 6
     371              :                           : 5))) {
     372              :               correction -=
     373              :                   5.5555555555555555555e-3 *
     374              :                   (gsl::at(cell_centered_fluxes_for_stencil,
     375              :                            correction_width - 2) +
     376              :                    gsl::at(cell_centered_fluxes_for_stencil,
     377              :                            correction_width + 1) -
     378              :                    9.0 * (gsl::at(cell_centered_fluxes_for_stencil,
     379              :                                   correction_width - 1) +
     380              :                           gsl::at(cell_centered_fluxes_for_stencil,
     381              :                                   correction_width)) -
     382              :                    16.0 * second_order_var_correction[storage_index]
     383              :                                                      [face_storage_index]);
     384              :             }
     385              :             if (static_cast<int>(DerivOrder) >= 4 or
     386              :                 (static_cast<int>(DerivOrder) < 0 and
     387              :                  min(recons_order[lower_neighbor_index],
     388              :                      recons_order[upper_neighbor_index]) >= 3)) {
     389              :               correction +=
     390              :                   0.166666666666666666 *
     391              :                   (gsl::at(cell_centered_fluxes_for_stencil,
     392              :                            correction_width - 1) +
     393              :                    gsl::at(cell_centered_fluxes_for_stencil, correction_width) +
     394              :                    2.0 * second_order_var_correction[storage_index]
     395              :                                                     [face_storage_index]);
     396              :             }
     397              : 
     398              :             // Add second-order correction last
     399              :             correction +=
     400              :                 second_order_var_correction[storage_index][face_storage_index];
     401              :           }
     402              :         }
     403              :       }
     404              :     }
     405              :   };
     406              : 
     407              :   if (aligned_coordinates) {
     408              :     EXPAND_PACK_LEFT_TO_RIGHT(impl(tmpl::type_<EvolvedVarsTags>{},
     409              :                                    std::integral_constant<size_t, 0>{},
     410              :                                    std::true_type{}));
     411              :     if constexpr (Dim > 1) {
     412              :       EXPAND_PACK_LEFT_TO_RIGHT(impl(tmpl::type_<EvolvedVarsTags>{},
     413              :                                      std::integral_constant<size_t, 1>{},
     414              :                                      std::true_type{}));
     415              :       if constexpr (Dim > 2) {
     416              :         EXPAND_PACK_LEFT_TO_RIGHT(impl(tmpl::type_<EvolvedVarsTags>{},
     417              :                                        std::integral_constant<size_t, 2>{},
     418              :                                        std::true_type{}));
     419              :       }
     420              :     }
     421              :   } else {
     422              :     EXPAND_PACK_LEFT_TO_RIGHT(impl(tmpl::type_<EvolvedVarsTags>{},
     423              :                                    std::integral_constant<size_t, 0>{},
     424              :                                    std::false_type{}));
     425              :     if constexpr (Dim > 1) {
     426              :       EXPAND_PACK_LEFT_TO_RIGHT(impl(tmpl::type_<EvolvedVarsTags>{},
     427              :                                      std::integral_constant<size_t, 1>{},
     428              :                                      std::false_type{}));
     429              :       if constexpr (Dim > 2) {
     430              :         EXPAND_PACK_LEFT_TO_RIGHT(impl(tmpl::type_<EvolvedVarsTags>{},
     431              :                                        std::integral_constant<size_t, 2>{},
     432              :                                        std::false_type{}));
     433              :       }
     434              :     }
     435              :   }
     436              : }
     437              : 
     438              : template <size_t Dim, typename... EvolvedVarsTags>
     439            1 : void cartesian_high_order_fluxes_using_nodes(
     440              :     const gsl::not_null<
     441              :         std::array<Variables<tmpl::list<EvolvedVarsTags...>>, Dim>*>
     442              :         high_order_boundary_corrections_in_logical_direction,
     443              : 
     444              :     const std::array<Variables<tmpl::list<EvolvedVarsTags...>>, Dim>&
     445              :         second_order_boundary_corrections_in_logical_direction,
     446              :     const Variables<tmpl::list<
     447              :         ::Tags::Flux<EvolvedVarsTags, tmpl::size_t<Dim>, Frame::Inertial>...>>&
     448              :         cell_centered_inertial_flux,
     449              :     const DirectionMap<
     450              :         Dim, Variables<tmpl::list<::Tags::Flux<
     451              :                  EvolvedVarsTags, tmpl::size_t<Dim>, Frame::Inertial>...>>>&
     452              :         ghost_cell_inertial_flux,
     453              :     const Mesh<Dim>& subcell_mesh, const size_t number_of_ghost_cells,
     454              :     const DerivativeOrder derivative_order,
     455              :     const std::array<gsl::span<std::uint8_t>, Dim>& reconstruction_order = {},
     456              :     const bool aligned_coordinates = true,
     457              :     const std::array<tnsr::i<DataVector, Dim, Frame::Inertial>, Dim>& normal =
     458              :         {},
     459              :     const std::array<
     460              :         DirectionMap<Dim, tnsr::i<DataVector, Dim, Frame::Inertial>>, Dim>&
     461              :         ghost_cell_normal = {}) {
     462              :   switch (derivative_order) {
     463              :     case DerivativeOrder::OneHigherThanRecons:
     464              :       cartesian_high_order_fluxes_using_nodes<
     465              :           DerivativeOrder::OneHigherThanRecons>(
     466              :           high_order_boundary_corrections_in_logical_direction,
     467              :           second_order_boundary_corrections_in_logical_direction,
     468              :           cell_centered_inertial_flux, ghost_cell_inertial_flux, subcell_mesh,
     469              :           number_of_ghost_cells, reconstruction_order, aligned_coordinates,
     470              :           normal, ghost_cell_normal);
     471              :       break;
     472              :     case DerivativeOrder::OneHigherThanReconsButFiveToFour:
     473              :       cartesian_high_order_fluxes_using_nodes<
     474              :           DerivativeOrder::OneHigherThanReconsButFiveToFour>(
     475              :           high_order_boundary_corrections_in_logical_direction,
     476              :           second_order_boundary_corrections_in_logical_direction,
     477              :           cell_centered_inertial_flux, ghost_cell_inertial_flux, subcell_mesh,
     478              :           number_of_ghost_cells, reconstruction_order, aligned_coordinates,
     479              :           normal, ghost_cell_normal);
     480              :       break;
     481              :     case DerivativeOrder::Two:
     482              :       cartesian_high_order_fluxes_using_nodes<DerivativeOrder::Two>(
     483              :           high_order_boundary_corrections_in_logical_direction,
     484              :           second_order_boundary_corrections_in_logical_direction,
     485              :           cell_centered_inertial_flux, ghost_cell_inertial_flux, subcell_mesh,
     486              :           number_of_ghost_cells, reconstruction_order, aligned_coordinates,
     487              :           normal, ghost_cell_normal);
     488              :       break;
     489              :     case DerivativeOrder::Four:
     490              :       cartesian_high_order_fluxes_using_nodes<DerivativeOrder::Four>(
     491              :           high_order_boundary_corrections_in_logical_direction,
     492              :           second_order_boundary_corrections_in_logical_direction,
     493              :           cell_centered_inertial_flux, ghost_cell_inertial_flux, subcell_mesh,
     494              :           number_of_ghost_cells, reconstruction_order, aligned_coordinates,
     495              :           normal, ghost_cell_normal);
     496              :       break;
     497              :     case DerivativeOrder::Six:
     498              :       cartesian_high_order_fluxes_using_nodes<DerivativeOrder::Six>(
     499              :           high_order_boundary_corrections_in_logical_direction,
     500              :           second_order_boundary_corrections_in_logical_direction,
     501              :           cell_centered_inertial_flux, ghost_cell_inertial_flux, subcell_mesh,
     502              :           number_of_ghost_cells, reconstruction_order, aligned_coordinates,
     503              :           normal, ghost_cell_normal);
     504              :       break;
     505              :     case DerivativeOrder::Eight:
     506              :       cartesian_high_order_fluxes_using_nodes<DerivativeOrder::Eight>(
     507              :           high_order_boundary_corrections_in_logical_direction,
     508              :           second_order_boundary_corrections_in_logical_direction,
     509              :           cell_centered_inertial_flux, ghost_cell_inertial_flux, subcell_mesh,
     510              :           number_of_ghost_cells, reconstruction_order, aligned_coordinates,
     511              :           normal, ghost_cell_normal);
     512              :       break;
     513              :     case DerivativeOrder::Ten:
     514              :       cartesian_high_order_fluxes_using_nodes<DerivativeOrder::Ten>(
     515              :           high_order_boundary_corrections_in_logical_direction,
     516              :           second_order_boundary_corrections_in_logical_direction,
     517              :           cell_centered_inertial_flux, ghost_cell_inertial_flux, subcell_mesh,
     518              :           number_of_ghost_cells, reconstruction_order, aligned_coordinates,
     519              :           normal, ghost_cell_normal);
     520              :       break;
     521              :     default:
     522              :       ERROR("Unsupported correction order " << derivative_order);
     523              :   };
     524              : }
     525              : /// @}
     526              : 
     527              : /*!
     528              :  * \brief Fill the `flux_neighbor_data` with pointers into the
     529              :  * `all_ghost_data`.
     530              :  *
     531              :  * The `all_ghost_data` is stored in the tag
     532              :  * `evolution::dg::subcell::Tags::GhostDataForReconstruction`, and the
     533              :  * `ghost_zone_size` should come from the FD reconstructor.
     534              :  */
     535              : template <size_t Dim, typename FluxesTags>
     536            1 : void set_cartesian_neighbor_cell_centered_fluxes(
     537              :     const gsl::not_null<DirectionMap<Dim, Variables<FluxesTags>>*>
     538              :         flux_neighbor_data,
     539              :     const DirectionalIdMap<Dim, evolution::dg::subcell::GhostData>&
     540              :         all_ghost_data,
     541              :     const Mesh<Dim>& subcell_mesh, const size_t ghost_zone_size,
     542              :     const size_t number_of_rdmp_values_in_ghost_data) {
     543              :   for (const auto& [direction_id, ghost_data] : all_ghost_data) {
     544              :     const size_t neighbor_flux_size =
     545              :         subcell_mesh.number_of_grid_points() /
     546              :         subcell_mesh.extents(direction_id.direction().dimension()) *
     547              :         ghost_zone_size *
     548              :         Variables<FluxesTags>::number_of_independent_components;
     549              :     const DataVector& neighbor_data =
     550              :         ghost_data.neighbor_ghost_data_for_reconstruction();
     551              :     (*flux_neighbor_data)[direction_id.direction()].set_data_ref(
     552              :         // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
     553              :         const_cast<double*>(std::next(
     554              :             neighbor_data.data(),
     555              :             static_cast<std::ptrdiff_t>(neighbor_data.size() -
     556              :                                         number_of_rdmp_values_in_ghost_data -
     557              :                                         neighbor_flux_size))),
     558              :         neighbor_flux_size);
     559              :   }
     560              : }
     561              : 
     562              : /*!
     563              :  * \brief Computes the high-order Cartesian flux corrections if necessary.
     564              :  *
     565              :  * The `cell_centered_fluxes` is stored in the tag
     566              :  * `evolution::dg::subcell::Tags::CellCenteredFlux`, `fd_derivative_order` is
     567              :  * from `evolution::dg::subcell::Tags::SubcellOptions`
     568              :  * (`.finite_difference_derivative_order()`), the `all_ghost_data`
     569              :  * is stored in the tag
     570              :  * `evolution::dg::subcell::Tags::GhostDataForReconstruction`, the
     571              :  * `ghost_zone_size` should come from the FD reconstructor.
     572              :  *
     573              :  * By default we assume no RDMP data is in the `ghost_data` buffer. In the
     574              :  * future we will want to update how we store the data in order to eliminate
     575              :  * more memory allocations and copies, in which case that value will be
     576              :  * non-zero.
     577              :  *
     578              :  * \note `high_order_corrections` must either not have a value or have all
     579              :  * elements be of the same size as
     580              :  * `second_order_boundary_corrections[0].number_of_grid_points()`, where we've
     581              :  * assumed `second_order_boundary_corrections` is the same in all directions.
     582              :  */
     583              : template <size_t Dim, typename... EvolvedVarsTags,
     584              :           typename FluxesTags = tmpl::list<::Tags::Flux<
     585              :               EvolvedVarsTags, tmpl::size_t<Dim>, Frame::Inertial>...>>
     586            1 : void cartesian_high_order_flux_corrections(
     587              :     const gsl::not_null<std::optional<
     588              :         std::array<Variables<tmpl::list<EvolvedVarsTags...>>, Dim>>*>
     589              :         high_order_corrections,
     590              : 
     591              :     const std::optional<Variables<FluxesTags>>& cell_centered_fluxes,
     592              :     const std::array<Variables<tmpl::list<EvolvedVarsTags...>>, Dim>&
     593              :         second_order_boundary_corrections,
     594              :     const fd::DerivativeOrder& fd_derivative_order,
     595              :     const DirectionalIdMap<Dim, evolution::dg::subcell::GhostData>&
     596              :         all_ghost_data,
     597              :     const Mesh<Dim>& subcell_mesh, const size_t ghost_zone_size,
     598              :     const std::array<gsl::span<std::uint8_t>, Dim>& reconstruction_order = {},
     599              :     const bool aligned_coordinates = true,
     600              :     const std::array<tnsr::i<DataVector, Dim, Frame::Inertial>, Dim>& normal =
     601              :         {},
     602              :     const std::array<
     603              :         DirectionMap<Dim, tnsr::i<DataVector, Dim, Frame::Inertial>>, Dim>&
     604              :         ghost_cell_normal = {},
     605              :     const size_t number_of_rdmp_values_in_ghost_data = 0) {
     606              :   if (cell_centered_fluxes.has_value()) {
     607              :     ASSERT(alg::all_of(
     608              :                second_order_boundary_corrections,
     609              :                [expected_size = second_order_boundary_corrections[0]
     610              :                                     .number_of_grid_points()](const auto& e) {
     611              :                  return e.number_of_grid_points() == expected_size;
     612              :                }),
     613              :            "All second-order boundary corrections must be of the same size, "
     614              :                << second_order_boundary_corrections[0].number_of_grid_points());
     615              :     if (fd_derivative_order != DerivativeOrder::Two) {
     616              :       if (not high_order_corrections->has_value()) {
     617              :         (*high_order_corrections) =
     618              :             make_array<Dim>(Variables<tmpl::list<EvolvedVarsTags...>>{
     619              :                 second_order_boundary_corrections[0].number_of_grid_points()});
     620              :       }
     621              :       ASSERT(
     622              :           high_order_corrections->has_value() and
     623              :               alg::all_of(high_order_corrections->value(),
     624              :                           [expected_size =
     625              :                                second_order_boundary_corrections[0]
     626              :                                    .number_of_grid_points()](const auto& e) {
     627              :                             return e.number_of_grid_points() == expected_size;
     628              :                           }),
     629              :           "The high_order_corrections must all have size "
     630              :               << second_order_boundary_corrections[0].number_of_grid_points());
     631              :       DirectionMap<Dim, Variables<FluxesTags>> flux_neighbor_data{};
     632              :       set_cartesian_neighbor_cell_centered_fluxes(
     633              :           make_not_null(&flux_neighbor_data), all_ghost_data, subcell_mesh,
     634              :           ghost_zone_size, number_of_rdmp_values_in_ghost_data);
     635              : 
     636              :       cartesian_high_order_fluxes_using_nodes(
     637              :           make_not_null(&(high_order_corrections->value())),
     638              :           second_order_boundary_corrections, cell_centered_fluxes.value(),
     639              :           flux_neighbor_data, subcell_mesh, ghost_zone_size,
     640              :           fd_derivative_order, reconstruction_order, aligned_coordinates,
     641              :           normal, ghost_cell_normal);
     642              :     }
     643              :   }
     644              : }
     645              : }  // namespace fd
        

Generated by: LCOV version 2.0-1