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 : #include <optional>
9 :
10 : #include "DataStructures/DataVector.hpp"
11 : #include "Domain/Structure/DirectionalId.hpp"
12 : #include "Domain/Structure/DirectionalIdMap.hpp"
13 : #include "Domain/Structure/ElementId.hpp"
14 : #include "Evolution/DgSubcell/GhostData.hpp"
15 : #include "Evolution/DgSubcell/RdmpTciData.hpp"
16 : #include "NumericalAlgorithms/Interpolation/IrregularInterpolant.hpp"
17 : #include "NumericalAlgorithms/Spectral/ParityFromSymmetry.hpp"
18 : #include "Utilities/Gsl.hpp"
19 : #include "Utilities/TMPL.hpp"
20 :
21 : /// \cond
22 : template <size_t Dim>
23 : class Element;
24 : template <size_t Dim>
25 : class Mesh;
26 : /// \endcond
27 :
28 : namespace evolution::dg::subcell::detail {
29 : /*!
30 : * \brief Implementation of insert_or_update_neighbor_volume_data, accepting
31 : * parity information as runtime arguments so the caller can be a thin
32 : * template wrapper without needing VolumeFields in the function body.
33 : *
34 : * The impl-unique parameters are specifically for a ZernikeB1 basis:
35 : * - **`parity_list`** Run-length encoded even/odd parity of each component
36 : * (ignored when Dim != 3 or when the mesh is not ZernikeB1).
37 : * - **`num_even`** Number of even-parity components (0 when unused).
38 : * - **`num_odd`** Number of odd-parity components (0 when unused).
39 : */
40 : template <bool InsertIntoMap, size_t Dim>
41 : void insert_or_update_neighbor_volume_data_impl(
42 : gsl::not_null<DirectionalIdMap<Dim, GhostData>*> ghost_data_ptr,
43 : const DataVector& neighbor_subcell_data,
44 : size_t number_of_rdmp_vars_in_buffer,
45 : const DirectionalId<Dim>& directional_element_id,
46 : const Mesh<Dim>& neighbor_mesh, const Element<Dim>& element,
47 : const Mesh<Dim>& subcell_mesh, size_t number_of_ghost_zones,
48 : const DirectionalIdMap<Dim, std::optional<intrp::Irregular<Dim>>>&
49 : neighbor_dg_to_fd_interpolants,
50 : gsl::span<const size_t> parity_list, size_t num_even, size_t num_odd);
51 : } // namespace evolution::dg::subcell::detail
52 :
53 : namespace evolution::dg::subcell {
54 : /*!
55 : * \brief Check whether `neighbor_subcell_data` is FD or DG, and either insert
56 : * or copy into `ghost_data_ptr` the FD data (projecting if
57 : * `neighbor_subcell_data` is DG data).
58 : *
59 : * This is intended to be used during a rollback from DG to make sure neighbor
60 : * data is projected to the FD grid.
61 : *
62 : * The `VolumeFields` meta parameter is the tag list (a `tmpl::list`) of the
63 : * packed ghost DataVector so that per-component parity information can be
64 : * deduced for ZernikeB1 meshes.
65 : */
66 : template <bool InsertIntoMap, size_t Dim, typename VolumeFields>
67 1 : void insert_or_update_neighbor_volume_data(
68 : const gsl::not_null<DirectionalIdMap<Dim, GhostData>*> ghost_data_ptr,
69 : const DataVector& neighbor_subcell_data,
70 : const size_t number_of_rdmp_vars_in_buffer,
71 : const DirectionalId<Dim>& directional_element_id,
72 : const Mesh<Dim>& neighbor_mesh, const Element<Dim>& element,
73 : const Mesh<Dim>& subcell_mesh, const size_t number_of_ghost_zones,
74 : const DirectionalIdMap<Dim, std::optional<intrp::Irregular<Dim>>>&
75 : neighbor_dg_to_fd_interpolants,
76 : VolumeFields /*meta*/) {
77 : if constexpr (Dim == 3) {
78 : const auto parity_info = Spectral::compute_parity_list<VolumeFields>();
79 : const auto& parity_list = std::get<0>(parity_info);
80 : detail::insert_or_update_neighbor_volume_data_impl<InsertIntoMap, Dim>(
81 : ghost_data_ptr, neighbor_subcell_data, number_of_rdmp_vars_in_buffer,
82 : directional_element_id, neighbor_mesh, element, subcell_mesh,
83 : number_of_ghost_zones, neighbor_dg_to_fd_interpolants,
84 : gsl::span<const size_t>{parity_list.data(), parity_list.size()},
85 : std::get<1>(parity_info), std::get<2>(parity_info));
86 : } else {
87 : detail::insert_or_update_neighbor_volume_data_impl<InsertIntoMap, Dim>(
88 : ghost_data_ptr, neighbor_subcell_data, number_of_rdmp_vars_in_buffer,
89 : directional_element_id, neighbor_mesh, element, subcell_mesh,
90 : number_of_ghost_zones, neighbor_dg_to_fd_interpolants, {}, 0, 0);
91 : }
92 : }
93 :
94 : /*!
95 : * \brief Check whether the neighbor sent is DG volume or FD ghost data, and
96 : * orient project DG volume data if necessary.
97 : *
98 : * This is intended to be used by the `ReceiveDataForReconstruction` action.
99 : *
100 : * The `VolumeFields` parameter is the tag list (a `tmpl::list`) of the
101 : * packed ghost DataVector so that per-component parity information can be
102 : * deduced for ZernikeB1 meshes.
103 : */
104 : template <size_t Dim, typename VolumeFields>
105 1 : void insert_neighbor_rdmp_and_volume_data(
106 : const gsl::not_null<RdmpTciData*> rdmp_tci_data_ptr,
107 : const gsl::not_null<DirectionalIdMap<Dim, GhostData>*> ghost_data_ptr,
108 : const DataVector& received_neighbor_subcell_data,
109 : const size_t number_of_rdmp_vars,
110 : const DirectionalId<Dim>& directional_element_id,
111 : const Mesh<Dim>& neighbor_mesh, const Element<Dim>& element,
112 : const Mesh<Dim>& subcell_mesh, const size_t number_of_ghost_zones,
113 : const DirectionalIdMap<Dim, std::optional<intrp::Irregular<Dim>>>&
114 : neighbor_dg_to_fd_interpolants,
115 : VolumeFields volume_fields) {
116 : ASSERT(received_neighbor_subcell_data.size() != 0,
117 : "received_neighbor_subcell_data must be non-empty");
118 : // Note: since we determine the starting point of the RDMP vars
119 : // from how many RDMP vars there are, we don't need to account for
120 : // the mesh the neighbor sent (DG or FD)
121 : const size_t max_offset =
122 : received_neighbor_subcell_data.size() - 2 * number_of_rdmp_vars;
123 : const size_t min_offset =
124 : received_neighbor_subcell_data.size() - number_of_rdmp_vars;
125 : for (size_t var_index = 0; var_index < number_of_rdmp_vars; ++var_index) {
126 : rdmp_tci_data_ptr->max_variables_values[var_index] =
127 : std::max(rdmp_tci_data_ptr->max_variables_values[var_index],
128 : received_neighbor_subcell_data[max_offset + var_index]);
129 : rdmp_tci_data_ptr->min_variables_values[var_index] =
130 : std::min(rdmp_tci_data_ptr->min_variables_values[var_index],
131 : received_neighbor_subcell_data[min_offset + var_index]);
132 : }
133 : // Note: it would be good to assert that the neighbor is at the same
134 : // refinement level as us, but such a function does not yet exist.
135 :
136 : insert_or_update_neighbor_volume_data<true>(
137 : ghost_data_ptr, received_neighbor_subcell_data, number_of_rdmp_vars,
138 : directional_element_id, neighbor_mesh, element, subcell_mesh,
139 : number_of_ghost_zones, neighbor_dg_to_fd_interpolants, volume_fields);
140 : }
141 : } // namespace evolution::dg::subcell
|