ThunderEgg  1.0.0
PatchIfaceScatter.h
Go to the documentation of this file.
1 /***************************************************************************
2  * ThunderEgg, a library for solvers on adaptively refined block-structured
3  * Cartesian grids.
4  *
5  * Copyright (c) 2020-2021 Scott Aiton
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19  ***************************************************************************/
20 
21 #ifndef THUNDEREGG_SCHUR_PATCHIFACESCATTER_H
22 #define THUNDEREGG_SCHUR_PATCHIFACESCATTER_H
23 
30 #include <ThunderEgg/Vector.h>
31 namespace ThunderEgg {
32 namespace Schur {
41 template<int D>
43 {
44 private:
45  class StatePrivate
46  {
47  public:
48  std::vector<std::vector<double>> send_buffers;
49  std::vector<std::vector<double>> recv_buffers;
50  std::vector<MPI_Request> send_requests;
51  std::vector<MPI_Request> recv_requests;
52  bool communicating = true;
56  const Vector<D - 1>* curr_global_vector = nullptr;
60  const Vector<D - 1>* curr_local_vector = nullptr;
61 
62  StatePrivate(size_t send_buffers_size, size_t recv_buffers_size)
63  : send_buffers(send_buffers_size)
64  , recv_buffers(recv_buffers_size)
65  , send_requests(send_buffers_size)
66  , recv_requests(recv_buffers_size)
67  {}
68  ~StatePrivate()
69  {
70  if (communicating) {
71  MPI_Waitall(recv_requests.size(), recv_requests.data(), MPI_STATUSES_IGNORE);
72  MPI_Waitall(send_requests.size(), send_requests.data(), MPI_STATUSES_IGNORE);
73  }
74  }
75  };
76 
77  class State
78  {
79  public:
80  std::shared_ptr<StatePrivate> ptr;
81  State(size_t num_send, size_t num_recv)
82  : ptr(new StatePrivate(num_send, num_recv))
83  {}
84  };
85 
86 public:
90  std::array<int, D - 1> lengths;
106  std::vector<int> send_ranks;
110  std::vector<std::vector<int>> send_local_indexes;
118  std::vector<int> recv_ranks;
122  std::vector<std::vector<int>> recv_local_indexes;
123 
131  {
132  int rank;
133  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
134 
135  std::map<int, std::set<std::pair<int, int>>> incoming_ranks_to_id_local_index_pairs;
136 
137  for (auto piinfo : iface_domain.getPatchIfaceInfos()) {
138  for (Side<D> s : Side<D>::getValues()) {
139  if (piinfo->pinfo.hasNbr(s)) {
140  auto iface_info = piinfo->getIfaceInfo(s);
141  if (iface_info->rank != rank) {
142  incoming_ranks_to_id_local_index_pairs[iface_info->rank].emplace(
143  iface_info->id, iface_info->patch_local_index);
144  }
145  }
146  }
147  }
148  int local_vector_size = 0;
149  for (auto rank_to_id_local_index_pairs : incoming_ranks_to_id_local_index_pairs) {
150  local_vector_size += rank_to_id_local_index_pairs.second.size();
151  }
152  local_vector_size += iface_domain.getNumLocalInterfaces();
153  num_local_patch_ifaces = local_vector_size;
154 
155  num_recvs = incoming_ranks_to_id_local_index_pairs.size();
156  recv_ranks.resize(num_recvs);
158 
159  int recv_index = 0;
160  for (const auto& rank_to_id_local_index_pairs : incoming_ranks_to_id_local_index_pairs) {
161  recv_ranks[recv_index] = rank_to_id_local_index_pairs.first;
162  std::vector<int>& local_index_vector = recv_local_indexes[recv_index];
163 
164  local_index_vector.reserve(rank_to_id_local_index_pairs.second.size());
165 
166  for (auto id_local_index_pair : rank_to_id_local_index_pairs.second) {
167  local_index_vector.push_back(id_local_index_pair.second);
168  }
169  recv_index++;
170  }
171  }
177  void setOutgoingBufferMaps(const InterfaceDomain<D>& iface_domain)
178  {
179  int rank;
180  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
181 
182  std::map<int, std::set<std::pair<int, int>>> outgoing_ranks_to_id_local_index_pairs;
183  for (auto iface : iface_domain.getInterfaces()) {
184  for (auto patch : iface->patches) {
185  if ((patch.type.isNormal() || patch.type.isFineToFine() || patch.type.isCoarseToCoarse()) &&
186  patch.piinfo->pinfo.rank != rank) {
187  outgoing_ranks_to_id_local_index_pairs[patch.piinfo->pinfo.rank].emplace(
188  iface->id, iface->local_index);
189  }
190  }
191  }
192 
193  num_sends = outgoing_ranks_to_id_local_index_pairs.size();
194  send_ranks.resize(num_sends);
196 
197  int send_index = 0;
198  for (const auto& rank_to_id_local_index_pairs : outgoing_ranks_to_id_local_index_pairs) {
199  send_ranks[send_index] = rank_to_id_local_index_pairs.first;
200  std::vector<int>& local_index_vector = send_local_indexes[send_index];
201 
202  local_index_vector.reserve(rank_to_id_local_index_pairs.second.size());
203 
204  for (auto id_local_index_pair : rank_to_id_local_index_pairs.second) {
205  local_index_vector.push_back(id_local_index_pair.second);
206  }
207  send_index++;
208  }
209  }
213  State initializeMPIBuffers() const
214  {
215  State state(send_ranks.size(), recv_ranks.size());
216 
217  for (int send_index = 0; send_index < num_sends; send_index++) {
218  state.ptr->send_buffers[send_index].resize(send_local_indexes[send_index].size() *
219  iface_stride);
220  }
221 
222  for (int recv_index = 0; recv_index < num_recvs; recv_index++) {
223  state.ptr->recv_buffers[recv_index].resize(recv_local_indexes[recv_index].size() *
224  iface_stride);
225  }
226 
227  return state;
228  }
229 
230 public:
236  explicit PatchIfaceScatter(const InterfaceDomain<D>& iface_domain)
237  {
238  std::array<int, D> ns = iface_domain.getDomain().getNs();
239  for (int i = 1; i < D; i++) {
240  if (ns[0] != ns[i]) {
241  throw RuntimeError(
242  "Cannot form Schur compliment vector for Domain with non-square patches");
243  }
244  }
245 
246  lengths.fill(ns[0]);
247  iface_stride = std::pow(ns[0], D - 1);
249  setOutgoingBufferMaps(iface_domain);
250  }
256  std::shared_ptr<Vector<D - 1>> getNewLocalPatchIfaceVector() const
257  {
258  return std::make_shared<Vector<D - 1>>(
259  Communicator(MPI_COMM_SELF), lengths, 1, num_local_patch_ifaces, 0);
260  }
273  State scatterStart(const Vector<D - 1>& global_vector,
274  Vector<D - 1>& local_patch_iface_vector) const
275  {
276  for (int i = 0; i < global_vector.getNumLocalPatches(); i++) {
277  auto global_data = global_vector.getComponentView(0, i);
278  auto local_data = local_patch_iface_vector.getComponentView(0, i);
279  Loop::Nested<D - 1>(
280  local_data.getStart(), local_data.getEnd(), [&](const std::array<int, D - 1>& coord) {
281  local_data[coord] = global_data[coord];
282  });
283  }
284 
285  State state = initializeMPIBuffers();
286 
287  for (int recv_index = 0; recv_index < num_recvs; recv_index++) {
288  MPI_Irecv(state.ptr->recv_buffers[recv_index].data(),
289  state.ptr->recv_buffers[recv_index].size(),
290  MPI_DOUBLE,
291  recv_ranks[recv_index],
292  0,
293  MPI_COMM_WORLD,
294  &state.ptr->recv_requests[recv_index]);
295  }
296 
297  for (int send_index = 0; send_index < num_sends; send_index++) {
298  std::vector<double>& buffer = state.ptr->send_buffers[send_index];
299 
300  int buffer_index = 0;
301  for (int local_index : send_local_indexes[send_index]) {
302  auto local_data = global_vector.getComponentView(0, local_index);
303  Loop::OverInteriorIndexes<D - 1>(local_data, [&](const std::array<int, D - 1>& coord) {
304  buffer[buffer_index] = local_data[coord];
305  buffer_index++;
306  });
307  }
308 
309  MPI_Isend(buffer.data(),
310  buffer.size(),
311  MPI_DOUBLE,
312  send_ranks[send_index],
313  0,
314  MPI_COMM_WORLD,
315  &state.ptr->send_requests[send_index]);
316  }
317 
318  for (int local_iface = 0; local_iface < global_vector.getNumLocalPatches(); local_iface++) {
319  auto global_data = global_vector.getComponentView(0, local_iface);
320  auto local_data = local_patch_iface_vector.getComponentView(0, local_iface);
321  Loop::OverInteriorIndexes<D - 1>(local_data, [&](const std::array<int, D - 1>& coord) {
322  local_data[coord] = global_data[coord];
323  });
324  }
325 
326  state.ptr->curr_global_vector = &global_vector;
327  state.ptr->curr_local_vector = &local_patch_iface_vector;
328  return state;
329  }
340  void scatterFinish(const State& state,
341  const Vector<D - 1>& global_vector,
342  Vector<D - 1>& local_patch_iface_vector) const
343  {
344  if (&global_vector != state.ptr->curr_global_vector ||
345  &local_patch_iface_vector != state.ptr->curr_local_vector) {
346  throw RuntimeError(
347  "Different vectors were passed ot scatterFinish than were passed to scatterStart");
348  }
349 
350  for (int i = 0; i < num_recvs; i++) {
351  MPI_Status status;
352  int recv_index;
353  MPI_Waitany(num_recvs, state.ptr->recv_requests.data(), &recv_index, &status);
354 
355  std::vector<double>& buffer = state.ptr->recv_buffers[recv_index];
356 
357  int buffer_index = 0;
358  for (int local_index : recv_local_indexes[recv_index]) {
359  auto local_data = local_patch_iface_vector.getComponentView(0, local_index);
360  Loop::OverInteriorIndexes<D - 1>(local_data, [&](const std::array<int, D - 1>& coord) {
361  local_data[coord] = buffer[buffer_index];
362  buffer_index++;
363  });
364  }
365  }
366 
367  MPI_Waitall(num_sends, state.ptr->send_requests.data(), MPI_STATUSES_IGNORE);
368 
369  state.ptr->communicating = false;
370  }
371 };
372 extern template class PatchIfaceScatter<2>;
373 extern template class PatchIfaceScatter<3>;
374 } // namespace Schur
375 } // namespace ThunderEgg
376 #endif
ThunderEgg::Vector::getComponentView
ComponentView< double, D > getComponentView(int component_index, int patch_local_index)
Get the ComponentView for the specified patch and component.
Definition: Vector.h:336
RuntimeError.h
RuntimeError struct.
ThunderEgg::Loop::Nested
static void Nested(A start, A end, T lambda)
Loop over a range of integer coordinates.
Definition: Loops.h:125
Vector.h
Vector class.
ThunderEgg::Schur::PatchIfaceScatter::setIncomingBufferMapsAndDetermineLocalVectorSize
void setIncomingBufferMapsAndDetermineLocalVectorSize(const InterfaceDomain< D > &iface_domain)
Set the incoming buffer maps (incoming_rank_to_local_indexes) and set num_local_patch_ifaces.
Definition: PatchIfaceScatter.h:130
ThunderEgg::Schur::PatchIfaceScatter::setOutgoingBufferMaps
void setOutgoingBufferMaps(const InterfaceDomain< D > &iface_domain)
Set the outgoing buffer maps (outgoing_rank_to_local_indexes)
Definition: PatchIfaceScatter.h:177
ThunderEgg::Schur::InterfaceDomain::getNumLocalInterfaces
int getNumLocalInterfaces() const
Get the number of local Interfaces on this rank.
Definition: InterfaceDomain.h:620
ThunderEgg::Schur::PatchIfaceScatter::send_ranks
std::vector< int > send_ranks
MPI Send ranks.
Definition: PatchIfaceScatter.h:106
ThunderEgg::Schur::PatchIfaceScatter::initializeMPIBuffers
State initializeMPIBuffers() const
Initialize the mpi buffers.
Definition: PatchIfaceScatter.h:213
ThunderEgg::Schur::PatchIfaceScatter::scatterStart
State scatterStart(const Vector< D - 1 > &global_vector, Vector< D - 1 > &local_patch_iface_vector) const
Start the scatter from the global Schur compliment vector to the local patch iface vector.
Definition: PatchIfaceScatter.h:273
ThunderEgg::Schur::PatchIfaceScatter::getNewLocalPatchIfaceVector
std::shared_ptr< Vector< D - 1 > > getNewLocalPatchIfaceVector() const
Get a nw local patch iface vector.
Definition: PatchIfaceScatter.h:256
ThunderEgg::Schur::PatchIfaceScatter::scatterFinish
void scatterFinish(const State &state, const Vector< D - 1 > &global_vector, Vector< D - 1 > &local_patch_iface_vector) const
Finish the scatter from the global Schur compliment vector to the local patch iface vector.
Definition: PatchIfaceScatter.h:340
ThunderEgg::Schur::PatchIfaceScatter::recv_ranks
std::vector< int > recv_ranks
MPI recv ranks.
Definition: PatchIfaceScatter.h:118
ThunderEgg::Schur::PatchIfaceScatter
Scatters between a global Schur compliment vector and a local patch iface vector.
Definition: PatchIfaceScatter.h:42
ThunderEgg::Schur::InterfaceDomain::getInterfaces
const std::vector< std::shared_ptr< const Interface< D > > > getInterfaces() const
Get the vector Interfaces objects for this rank.
Definition: InterfaceDomain.h:636
ThunderEgg
The ThunderEgg namespace.
Definition: BiLinearGhostFiller.h:31
ThunderEgg::Schur::InterfaceDomain::getPatchIfaceInfos
const std::vector< std::shared_ptr< const PatchIfaceInfo< D > > > & getPatchIfaceInfos() const
Get the vector PatchIfaceInfo objects for this rank.
Definition: InterfaceDomain.h:649
InterfaceDomain.h
InterfaceDomain class.
ThunderEgg::Schur::PatchIfaceScatter::num_local_patch_ifaces
int num_local_patch_ifaces
the number of interfaces in the local vector
Definition: PatchIfaceScatter.h:94
ThunderEgg::Schur::PatchIfaceScatter::num_recvs
int num_recvs
number of MPI recvs
Definition: PatchIfaceScatter.h:114
ThunderEgg::Loop::OverInteriorIndexes
static void OverInteriorIndexes(const V &view, T lambda)
Loop over all the interior coordinates of a view.
Definition: Loops.h:140
ThunderEgg::Schur::PatchIfaceScatter::PatchIfaceScatter
PatchIfaceScatter(const InterfaceDomain< D > &iface_domain)
Construct a new PatchIfaceScatter object.
Definition: PatchIfaceScatter.h:236
ThunderEgg::Schur::PatchIfaceScatter::send_local_indexes
std::vector< std::vector< int > > send_local_indexes
the local indexes of the local vector to send
Definition: PatchIfaceScatter.h:110
ThunderEgg::Communicator
wrapper arount MPI_Comm, provides proper copy operators. Classes that have a communicator are meant t...
Definition: Communicator.h:36
ThunderEgg::Schur::InterfaceDomain::getDomain
const Domain< D > & getDomain() const
Get the Domain object that cooresponds to this InterfaceDomain.
Definition: InterfaceDomain.h:658
ThunderEgg::Schur::PatchIfaceScatter::num_sends
int num_sends
number of MPI sends
Definition: PatchIfaceScatter.h:102
ThunderEgg::Vector
Vector class for use in thunderegg.
Definition: Vector.h:42
ThunderEgg::Schur::PatchIfaceScatter::recv_local_indexes
std::vector< std::vector< int > > recv_local_indexes
local indexes of the local vector to receive
Definition: PatchIfaceScatter.h:122
ThunderEgg::Face
Enum-style class for the faces of an n-dimensional cube.
Definition: Face.h:41
ThunderEgg::Schur::PatchIfaceScatter::iface_stride
int iface_stride
the number of interfaces in the local vector
Definition: PatchIfaceScatter.h:98
ThunderEgg::Vector::getNumLocalPatches
int getNumLocalPatches() const
Get the number of local patches.
Definition: Vector.h:316
ThunderEgg::Schur::InterfaceDomain
Represents the Schur compliment domain of the problem.
Definition: InterfaceDomain.h:55
ThunderEgg::Schur::PatchIfaceScatter::lengths
std::array< int, D - 1 > lengths
the number of cells in each direction of the interface
Definition: PatchIfaceScatter.h:90
ThunderEgg::RuntimeError
ThunderEgg runtime exception.
Definition: RuntimeError.h:36