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 <map>
8 : #include <memory>
9 : #include <string>
10 : #include <utility>
11 :
12 : #include "Domain/Structure/DirectionalId.hpp"
13 : #include "Domain/Structure/DirectionalIdMap.hpp"
14 : #include "Evolution/DiscontinuousGalerkin/AtomicInboxBoundaryData.hpp"
15 : #include "Evolution/DiscontinuousGalerkin/BoundaryData.hpp"
16 : #include "Evolution/DiscontinuousGalerkin/InboxBoundaryData.hpp"
17 : #include "Evolution/DiscontinuousGalerkin/Messages/BoundaryMessage.hpp"
18 : #include "Time/TimeStepId.hpp"
19 : #include "Utilities/ErrorHandling/Error.hpp"
20 : #include "Utilities/Gsl.hpp"
21 : #include "Utilities/TMPL.hpp"
22 :
23 : namespace evolution::dg::Tags {
24 : /*!
25 : * \brief The inbox tag for boundary correction communication and DG-subcell
26 : * ghost zone cells.
27 : *
28 : * The stored data consists of the following:
29 : *
30 : * 1. the volume mesh of the element.
31 : * 2. the volume mesh corresponding to the ghost cell data. This allows eliding
32 : * projection when all neighboring elements are doing DG.
33 : * 3. the mortar mesh of the data on the mortar
34 : * 4. the variables at the ghost zone cells for finite difference/volume
35 : * reconstruction
36 : * 5. the data on the mortar needed for computing the boundary corrections (e.g.
37 : * fluxes, characteristic speeds, conserved variables)
38 : * 6. the TimeStepId beyond which the boundary terms are no longer valid, when
39 : * using local time stepping.
40 : * 7. the troublade cell indicator status using for determining halos around
41 : * troubled cells.
42 : * 8. the integration order of the time-stepper.
43 : * 9. the InterpolatedBoundaryData sent by a non-conforming Element that
44 : * interpolates its data to a subset of the points of the Element receiving
45 : * this BoundaryData
46 : *
47 : * The TimeStepId is the neighboring element's next time step. When using local
48 : * time stepping, the neighbor's boundary data is valid up until this time,
49 : * which may include multiple local time steps. By receiving and storing the
50 : * neighbor time step, the local element knows whether or not it should remove
51 : * boundary data and expect new data to be sent from the neighbor.
52 : *
53 : * The ghost cell data will be valid whenever a DG-subcell scheme is being used.
54 : * Whenever a DG-subcell scheme is being used, elements using DG and not FD/FV
55 : * always send both the ghost cells and boundary correction data together.
56 : * Elements using FD/FV send the ghost cells first followed by the boundary
57 : * correction data once the element has received all neighbor ghost cell data.
58 : * Note that the second send/receive only modifies the flux and the TimeStepId
59 : * used for the flux validity range.
60 : *
61 : * When only a DG scheme (not a DG-subcell scheme) is used the ghost cell data
62 : * will never be valid.
63 : *
64 : * In the DG-subcell scheme this tag is used both for communicating the ghost
65 : * cell data needed for the FD/FV reconstruction step and the data needed for
66 : * the boundary corrections.
67 : * - For an element using DG, both ghost cells and boundary corrections are
68 : * sent using a single communication. After receiving all neighbor
69 : * boundary corrections the element can finish computing the time step.
70 : * The ghost cell data from neighbors is unused.
71 : * - For an element using FD/FV, first the ghost cells are sent. Once all
72 : * neighboring ghost cell data is received, reconstruction is done and the
73 : * boundary terms are computed and sent to the neighbors. After receiving all
74 : * neighbor boundary corrections the element can finish computing the time
75 : * step.
76 : * - Whether or not an extra communication is needed when an element switches
77 : * from DG to FD/FV depends on how exactly the decision to switch is
78 : * implemented. If the volume terms are integrated and verified to be
79 : * valid before a DG element sends ghost cell and boundary data then no
80 : * additional communication is needed when switching from DG to FD/FV. In this
81 : * case a second check of the data that includes the boundary correction needs
82 : * to be done. If the second check determines a switch from DG to FD/FV is
83 : * needed, we can continue to use the DG fluxes since the evolution in the
84 : * small was valid, thus avoiding an additional communication. However, to
85 : * fully guarantee physical realizability a second communication or evolving
86 : * the neighboring ghost cells needs to be done. We have not yet decided how
87 : * to deal with the possible need for an additional communication since it
88 : * also depends on whether or not we decide to couple to Voronoi instead of
89 : * just Neumann neighbors.
90 : * - The data for the inbox tags is erased after the boundary correction is
91 : * complete and the solution has been verified to be valid at the new time
92 : * step. The ghost cells could be invalidated immediately after
93 : * reconstruction, thus using the ghost cell data after reconstruction is
94 : * complete is considered undefined behavior. That is, we make no guarantee as
95 : * to whether or not it will work.
96 : * - The reason for minimizing the number of communications rather than having a
97 : * more uniform implementation between DG and FD/FV is that it is the number
98 : * of communications that adds the most overhead, not the size of each
99 : * communication. Thus, one large communication is cheaper than several small
100 : * communications.
101 : *
102 : * #### DG Element Nodegroup Support
103 : * If you are using the `DgElementCollection` then you must set
104 : * `UseNodegroupDgElements` to `true`. The actions that use this tag check
105 : * that the parallel component and the `UseNodegroupDgElements` is consistent.
106 : */
107 : template <size_t Dim, bool UseNodegroupDgElements, bool IsAuxiliary = false>
108 1 : struct BoundaryCorrectionAndGhostCellsInbox {
109 0 : using stored_type = evolution::dg::BoundaryData<Dim>;
110 :
111 : public:
112 0 : using temporal_id = TimeStepId;
113 : // Used by array implementation
114 0 : using type_map = evolution::dg::InboxBoundaryData<Dim>;
115 :
116 : // Used by nodegroup implementation
117 0 : using type_spsc = evolution::dg::AtomicInboxBoundaryData<Dim>;
118 :
119 : // The actual type being used.
120 0 : using type = tmpl::conditional_t<UseNodegroupDgElements, type_spsc, type_map>;
121 0 : using value_type = type;
122 :
123 0 : static bool insert_into_inbox(
124 : gsl::not_null<type_spsc*> inbox, const temporal_id& time_step_id,
125 : std::pair<DirectionalId<Dim>, evolution::dg::BoundaryData<Dim>> data);
126 :
127 0 : static bool insert_into_inbox(
128 : gsl::not_null<type_map*> inbox, const temporal_id& time_step_id,
129 : std::pair<DirectionalId<Dim>, evolution::dg::BoundaryData<Dim>> data);
130 :
131 0 : static std::string output_inbox(const type_spsc& inbox, size_t padding_size);
132 :
133 0 : static std::string output_inbox(const type_map& inbox, size_t padding_size);
134 : };
135 :
136 : /*!
137 : * \brief The inbox tag for boundary correction communication and DG-subcell
138 : * ghost zone cells using a `BoundaryMessage` object
139 : *
140 : * To see what is stored within a `BoundaryMessage`, see its documentation.
141 : *
142 : * This inbox tag is very similar to `BoundaryCorrectionAndGhostCellsInbox` in
143 : * that it stores subcell/DG data sent from neighboring elements. To see exactly
144 : * when data is stored and how it's used, see the docs for
145 : * `BoundaryCorrectionAndGhostCellsInbox`. This inbox tag is different than
146 : * `BoundaryCorrectionAndGhostCellsInbox` in that it only takes a pointer to a
147 : * `BoundaryMessage` as an argument to `insert_into_inbox` and stores a
148 : * `std::unique_ptr<BoundaryMessage>` inside the inbox.
149 : *
150 : * This inbox tag is meant to be used to avoid unnecessary copies between
151 : * elements on the same node which share a block of memory. If two elements
152 : * aren't on the same node, then a copy/send is done regardless.
153 : *
154 : * \warning The `boundary_message` argument to `insert_into_inbox()` will be
155 : * invalid after the function is called because a `std::unique_ptr` now controls
156 : * the memory. Calling a method on the `boundary_message` pointer after the
157 : * `insert_into_inbox()` function is called can result in undefined behaviour.
158 : */
159 : template <size_t Dim>
160 1 : struct BoundaryMessageInbox {
161 0 : using stored_type = std::unique_ptr<BoundaryMessage<Dim>>;
162 :
163 : public:
164 0 : using temporal_id = TimeStepId;
165 0 : using type = std::map<TimeStepId, DirectionalIdMap<Dim, stored_type>>;
166 0 : using message_type = BoundaryMessage<Dim>;
167 :
168 : template <typename Inbox>
169 0 : static bool insert_into_inbox(const gsl::not_null<Inbox*> inbox,
170 : BoundaryMessage<Dim>* boundary_message) {
171 : const auto& time_step_id = boundary_message->current_time_step_id;
172 : auto& current_inbox = (*inbox)[time_step_id];
173 :
174 : const auto key = DirectionalId<Dim>{boundary_message->neighbor_direction,
175 : boundary_message->element_id};
176 :
177 : // Once we insert boundary_message into the unique_ptr we cannot use
178 : // boundary_message anymore because it is invalidated. The unique_ptr now
179 : // owns the memory.
180 : if (not current_inbox
181 : .insert(std::pair{key, std::unique_ptr<BoundaryMessage<Dim>>(
182 : boundary_message)})
183 : .second) {
184 : ERROR("Failed to insert data to receive at instance '"
185 : << time_step_id << "' with tag 'BoundaryMessageInbox'.\n");
186 : }
187 : return true;
188 : }
189 : };
190 : } // namespace evolution::dg::Tags
|