ThunderEgg  1.0.0
MPIGhostFiller.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_MPIGHOSTFILLER_H
22 #define THUNDEREGG_MPIGHOSTFILLER_H
23 
30 #include <ThunderEgg/Domain.h>
31 #include <ThunderEgg/GhostFiller.h>
33 
34 namespace ThunderEgg {
44 template<int D>
45 class MPIGhostFiller : public GhostFiller<D>
46 {
47 private:
53  template<int M>
54  class RemoteCallPrototype
55  {
56  public:
60  int id;
64  Face<D, M> face;
68  NbrType nbr_type;
72  Orthant<M> orthant;
76  int local_index;
86  RemoteCallPrototype(int id,
87  Face<D, M> face,
88  NbrType nbr_type,
89  Orthant<M> orthant,
90  int local_index)
91  : id(id)
92  , face(face)
93  , nbr_type(nbr_type)
94  , orthant(orthant)
95  , local_index(local_index)
96  {}
103  bool operator<(const RemoteCallPrototype& other) const
104  {
105  return std::forward_as_tuple(id, face.opposite(), nbr_type, orthant, local_index) <
106  std::forward_as_tuple(
107  other.id, other.face.opposite(), other.nbr_type, other.orthant, other.local_index);
108  }
109  };
110 
116  template<int M>
117  class IncomingGhostPrototype
118  {
119  public:
123  int id;
127  Face<D, M> face;
131  int local_index;
139  IncomingGhostPrototype(int id, Face<D, M> face, int local_index)
140  : id(id)
141  , face(face)
142  , local_index(local_index)
143  {}
150  bool operator<(const IncomingGhostPrototype& other) const
151  {
152  return std::forward_as_tuple(id, face, local_index) <
153  std::forward_as_tuple(other.id, other.face, other.local_index);
154  }
155  };
156 
162  template<int M>
163  struct RemoteCall
164  {
168  Face<D, M> face;
172  NbrType nbr_type;
176  Orthant<M> orthant;
181  int local_index;
185  size_t offset;
192  RemoteCall(const RemoteCallPrototype<M>& prototype, size_t offset)
193  : face(prototype.face)
194  , nbr_type(prototype.nbr_type)
195  , orthant(prototype.orthant)
196  , local_index(prototype.local_index)
197  , offset(offset)
198  {}
199  };
200 
206  template<int M>
207  struct IncomingGhost
208  {
212  Face<D, M> face;
216  int local_index;
220  size_t offset;
227  IncomingGhost(const IncomingGhostPrototype<M>& prototype, size_t offset)
228  : face(prototype.face)
229  , local_index(prototype.local_index)
230  , offset(offset)
231  {}
232  };
233 
239  template<int M>
240  struct LocalCall
241  {
245  Face<D, M> face;
249  NbrType nbr_type;
253  Orthant<M> orthant;
257  int local_index;
261  int nbr_local_index;
271  LocalCall(Face<D, M> face,
272  NbrType nbr_type,
273  Orthant<M> orthant,
274  int local_index,
275  size_t nbr_local_index)
276  : face(face)
277  , nbr_type(nbr_type)
278  , orthant(orthant)
279  , local_index(local_index)
280  , nbr_local_index(nbr_local_index)
281  {}
282  };
283 
287  struct RemoteCallSet
288  {
292  int rank;
296  size_t send_buffer_length = 0;
302  template<int M>
303  using RemoteCallDeque = std::deque<RemoteCall<M>>;
311  size_t recv_buffer_length = 0;
317  template<int M>
318  using IncomingGhostDeque = std::deque<IncomingGhost<M>>;
323 
329  explicit RemoteCallSet(int rank)
330  : rank(rank)
331  {}
332  };
333 
337  std::vector<RemoteCallSet> remote_call_sets;
338 
344  template<int M>
345  using LocalCallDeque = std::deque<LocalCall<M>>;
350 
356  template<int M>
357  class GhostViewInfo
358  {
359  private:
363  std::array<std::array<int, D + 1>, Face<D, M>::number_of> strides;
367  std::array<std::array<int, D + 1>, Face<D, M>::number_of> ghost_start;
371  std::array<std::array<int, D + 1>, Face<D, M>::number_of> start;
375  std::array<std::array<int, D + 1>, Face<D, M>::number_of> end;
379  std::array<std::array<int, D + 1>, Face<D, M>::number_of> ghost_end;
383  std::array<size_t, Face<D, M>::number_of> sizes;
384 
385  public:
389  GhostViewInfo() = default;
395  explicit GhostViewInfo(const Domain<D>& domain)
396  {
397  std::array<int, D + 1> ns;
398  for (int i = 0; i < D; i++) {
399  ns[i] = domain.getNs()[i];
400  }
401  ns[D] = 1;
402  int num_ghost_cells = domain.getNumGhostCells();
403  for (Face<D, M> face : Face<D, M>::getValues()) {
404  std::array<int, D + 1> ghost_ns = ns;
405 
406  std::array<int, D + 1> face_ghost_start;
407  face_ghost_start.fill(0);
408 
409  std::array<int, D + 1> face_start;
410  face_start.fill(0);
411 
412  std::array<int, D + 1> face_end;
413  face_end = ns;
414  for (int& v : face_end) {
415  v--;
416  }
417 
418  std::array<int, D + 1> face_ghost_end;
419  face_ghost_end = ns;
420  for (int& v : face_ghost_end) {
421  v--;
422  }
423 
424  for (Side<D> side : face.getSides()) {
425  ghost_ns[side.getAxisIndex()] = num_ghost_cells;
426  if (side.isLowerOnAxis()) {
427  face_ghost_start[side.getAxisIndex()] = -num_ghost_cells;
428  face_ghost_end[side.getAxisIndex()] = -1;
429  face_end[side.getAxisIndex()] = -1;
430  } else {
431  face_ghost_start[side.getAxisIndex()] = ns[side.getAxisIndex()];
432  face_start[side.getAxisIndex()] = ns[side.getAxisIndex()];
433  face_ghost_end[side.getAxisIndex()] = ns[side.getAxisIndex()] + num_ghost_cells - 1;
434  }
435  }
436  strides[face.getIndex()][0] = 1;
437  for (size_t i = 1; i < D + 1; i++) {
438  strides[face.getIndex()][i] = ghost_ns[i - 1] * strides[face.getIndex()][i - 1];
439  }
440  sizes[face.getIndex()] = ghost_ns[D - 1] * strides[face.getIndex()][D - 1];
441  int offset = 0;
442  for (Side<D> side : face.getSides()) {
443  if (side.isHigherOnAxis()) {
444  offset += -(ns[side.getAxisIndex()] + num_ghost_cells) *
445  strides[face.getIndex()][side.getAxisIndex()];
446  }
447  }
448  ghost_start[face.getIndex()] = face_ghost_start;
449  start[face.getIndex()] = face_start;
450  end[face.getIndex()] = face_end;
451  ghost_end[face.getIndex()] = face_ghost_end;
452  }
453  }
454 
461  size_t getSize(Face<D, M> face) const { return sizes[face.getIndex()]; }
462 
463  PatchView<const double, D> getPatchView(double* buffer_ptr,
464  Face<D, M> face,
465  int num_components) const
466  {
467  std::array<int, D + 1> my_end = end[face.getIndex()];
468  std::array<int, D + 1> my_ghost_end = ghost_end[face.getIndex()];
469  my_end[D] = num_components - 1;
470  my_ghost_end[D] = num_components - 1;
471  return PatchView<const double, D>(buffer_ptr,
472  strides[face.getIndex()],
473  ghost_start[face.getIndex()],
474  start[face.getIndex()],
475  my_end,
476  my_ghost_end);
477  }
478  };
479 
483  DimensionalArray<D, GhostViewInfo> ghost_local_data_infos;
484 
488  Domain<D> domain;
489 
493  GhostFillingType fill_type;
494 
502  template<int M>
503  PatchView<const double, D> getPatchViewForBuffer(double* buffer_ptr,
504  Face<D, M> face,
505  int num_components) const
506  {
507  const GhostViewInfo<M>& gld_info = ghost_local_data_infos.template get<M>();
508  return gld_info.getPatchView(buffer_ptr, face, num_components);
509  }
516  std::vector<MPI_Request> postRecvs(std::vector<std::vector<double>>& buffers) const
517  {
518  std::vector<MPI_Request> recv_requests(buffers.size());
519  for (size_t i = 0; i < recv_requests.size(); i++) {
520  MPI_Irecv(buffers[i].data(),
521  buffers[i].size(),
522  MPI_DOUBLE,
523  remote_call_sets[i].rank,
524  0,
525  MPI_COMM_WORLD,
526  &recv_requests[i]);
527  }
528  return recv_requests;
529  }
530 
539  template<int M>
540  void addRecvBufferToGhost(const RemoteCallSet& remote_call_set,
541  std::vector<double>& buffer,
542  const Vector<D>& u) const
543  {
544  for (const IncomingGhost<M>& incoming_ghost :
545  remote_call_set.incoming_ghosts.template get<M>()) {
546  int local_index = incoming_ghost.local_index;
547  Face<D, M> face = incoming_ghost.face;
548  size_t buffer_offset = incoming_ghost.offset;
549 
550  PatchView<const double, D> local_view = u.getPatchView(local_index);
551  double* buffer_ptr = buffer.data() + buffer_offset * u.getNumComponents();
552  PatchView<const double, D> buffer_view =
553  getPatchViewForBuffer(buffer_ptr, face, u.getNumComponents());
554  std::array<size_t, D - M> start;
555  start.fill(0);
556  std::array<size_t, D - M> end;
557  end.fill(domain.getNumGhostCells() - 1);
558  Loop::Nested<D - M>(start, end, [&](const std::array<size_t, D - M>& offset) {
559  View<double, M + 1> local_slice = local_view.getGhostSliceOn(face, offset);
560  View<double, M + 1> buffer_slice = buffer_view.getGhostSliceOn(face, offset);
561  Loop::OverInteriorIndexes<M + 1>(local_slice, [&](const std::array<int, M + 1>& coord) {
562  local_slice[coord] += buffer_slice[coord];
563  });
564  });
565  }
566  }
574  void processRecvs(std::vector<MPI_Request>& requests,
575  std::vector<std::vector<double>>& buffers,
576  const Vector<D>& u) const
577  {
578  size_t num_requests = requests.size();
579  for (size_t i = 0; i < num_requests; i++) {
580  int finished_index;
581  MPI_Waitany(requests.size(), requests.data(), &finished_index, MPI_STATUS_IGNORE);
582  switch (fill_type) {
584  if constexpr (D >= 2) {
585  addRecvBufferToGhost<0>(remote_call_sets[finished_index], buffers[finished_index], u);
586  }
588  if constexpr (D == 3) {
589  addRecvBufferToGhost<1>(remote_call_sets[finished_index], buffers[finished_index], u);
590  }
592  addRecvBufferToGhost<D - 1>(remote_call_sets[finished_index], buffers[finished_index], u);
593  break;
594  default:
595  throw RuntimeError("Unsupported GhostFilling Type");
596  }
597  }
598  }
599 
608  template<int M>
609  void fillSendBuffer(const RemoteCallSet& remote_call_set,
610  std::vector<double>& buffer,
611  const Vector<D>& u) const
612  {
613  for (const RemoteCall<M>& call : remote_call_set.remote_calls.template get<M>()) {
614  const PatchInfo<D>& pinfo = domain.getPatchInfoVector()[call.local_index];
615  Face<D, M> face = call.face.opposite();
616  PatchView<const double, D> local_view = u.getPatchView(call.local_index);
617  double* buffer_ptr = buffer.data() + call.offset * u.getNumComponents();
618 
619  // create View objects for the buffer
620  PatchView<const double, D> buffer_view =
621  getPatchViewForBuffer(buffer_ptr, face, u.getNumComponents());
622 
623  // make the call
624  fillGhostCellsForNbrPatchPriv(
625  pinfo, local_view, buffer_view, call.face, call.nbr_type, call.orthant);
626  }
627  }
628 
636  std::vector<MPI_Request> postSends(std::vector<std::vector<double>>& buffers,
637  const Vector<D>& u) const
638  {
639  std::vector<MPI_Request> send_requests(remote_call_sets.size());
640  for (size_t i = 0; i < remote_call_sets.size(); i++) {
641  switch (fill_type) {
643  if constexpr (D >= 2) {
644  fillSendBuffer<0>(remote_call_sets[i], buffers[i], u);
645  }
647  if constexpr (D == 3) {
648  fillSendBuffer<1>(remote_call_sets[i], buffers[i], u);
649  }
651  fillSendBuffer<D - 1>(remote_call_sets[i], buffers[i], u);
652  break;
653  default:
654  throw RuntimeError("Unsupported GhostFilling Type");
655  }
656  MPI_Isend(buffers[i].data(),
657  buffers[i].size(),
658  MPI_DOUBLE,
659  remote_call_sets[i].rank,
660  0,
661  MPI_COMM_WORLD,
662  &send_requests[i]);
663  }
664  return send_requests;
665  }
666 
679  template<int M>
680  void fillGhostCellsForNbrPatchPriv(const PatchInfo<D>& pinfo,
681  const PatchView<const double, D>& local_view,
682  const PatchView<const double, D>& nbr_view,
683  Face<D, M> face,
684  NbrType nbr_type,
685  Orthant<M> orthant_on_coarse) const
686  {
687  if constexpr (M == D - 1) {
688  fillGhostCellsForNbrPatch(pinfo, local_view, nbr_view, face, nbr_type, orthant_on_coarse);
689  } else if constexpr (M > 0) {
690  fillGhostCellsForEdgeNbrPatch(pinfo, local_view, nbr_view, face, nbr_type, orthant_on_coarse);
691  } else {
692  fillGhostCellsForCornerNbrPatch(pinfo, local_view, nbr_view, face, nbr_type);
693  }
694  }
695 
704  template<int M>
705  void processLocalFills(const Vector<D>& u) const
706  {
707  for (const LocalCall<M>& call : local_calls.template get<M>()) {
708  const PatchInfo<D>& pinfo = domain.getPatchInfoVector()[call.local_index];
709  PatchView<const double, D> local_view = u.getPatchView(call.local_index);
710  PatchView<const double, D> nbr_view = u.getPatchView(call.nbr_local_index);
711  fillGhostCellsForNbrPatchPriv(
712  pinfo, local_view, nbr_view, call.face, call.nbr_type, call.orthant);
713  }
714  if constexpr (M > 0) {
715  processLocalFills<M - 1>(u);
716  }
717  }
718 
729  template<int M>
730  static void addNormalNbrCalls(
731  const PatchInfo<D>& pinfo,
732  Face<D, M> f,
733  std::deque<LocalCall<M>>& my_local_calls,
734  std::map<int, std::set<RemoteCallPrototype<M>>>& rank_to_remote_call_prototypes,
735  std::map<int, std::set<IncomingGhostPrototype<M>>>& rank_to_incoming_ghost_prototypes)
736  {
737  int rank;
738  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
739  auto nbrinfo = pinfo.getNormalNbrInfo(f);
740  if (nbrinfo.rank == rank) {
741  my_local_calls.emplace_back(
742  f, NbrType::Normal, Orthant<M>::null(), pinfo.local_index, nbrinfo.local_index);
743  } else {
744  rank_to_remote_call_prototypes[nbrinfo.rank].emplace(
745  nbrinfo.id, f, NbrType::Normal, Orthant<M>::null(), pinfo.local_index);
746  rank_to_incoming_ghost_prototypes[nbrinfo.rank].emplace(pinfo.id, f, pinfo.local_index);
747  }
748  }
749 
760  template<int M>
761  static void addFineNbrCalls(
762  const PatchInfo<D>& pinfo,
763  Face<D, M> f,
764  std::deque<LocalCall<M>>& my_local_calls,
765  std::map<int, std::set<RemoteCallPrototype<M>>>& rank_to_remote_call_prototypes,
766  std::map<int, std::set<IncomingGhostPrototype<M>>>& rank_to_incoming_ghost_prototypes)
767  {
768  int rank;
769  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
770  auto nbrinfo = pinfo.getFineNbrInfo(f);
771  for (size_t i = 0; i < Orthant<M>::num_orthants; i++) {
772  if (nbrinfo.ranks[i] == rank) {
773  my_local_calls.emplace_back(
774  f, NbrType::Fine, Orthant<M>(i), pinfo.local_index, nbrinfo.local_indexes[i]);
775  } else {
776  rank_to_remote_call_prototypes[nbrinfo.ranks[i]].emplace(
777  nbrinfo.ids[i], f, NbrType::Fine, Orthant<M>(i), pinfo.local_index);
778  rank_to_incoming_ghost_prototypes[nbrinfo.ranks[i]].emplace(pinfo.id, f, pinfo.local_index);
779  }
780  }
781  }
782 
793  template<int M>
794  static void addCoarseNbrCalls(
795  const PatchInfo<D>& pinfo,
796  Face<D, M> f,
797  std::deque<LocalCall<M>>& my_local_calls,
798  std::map<int, std::set<RemoteCallPrototype<M>>>& rank_to_remote_call_prototypes,
799  std::map<int, std::set<IncomingGhostPrototype<M>>>& rank_to_incoming_ghost_prototypes)
800  {
801  int rank;
802  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
803  auto nbrinfo = pinfo.getCoarseNbrInfo(f);
804  if (nbrinfo.rank == rank) {
805  my_local_calls.emplace_back(
806  f, NbrType::Coarse, nbrinfo.orth_on_coarse, pinfo.local_index, nbrinfo.local_index);
807  } else {
808  rank_to_remote_call_prototypes[nbrinfo.rank].emplace(
809  nbrinfo.id, f, NbrType::Coarse, nbrinfo.orth_on_coarse, pinfo.local_index);
810  rank_to_incoming_ghost_prototypes[nbrinfo.rank].emplace(pinfo.id, f, pinfo.local_index);
811  }
812  }
813 
821  template<int M>
822  void enumerateCalls(std::deque<LocalCall<M>>& my_local_calls,
823  std::map<int, RemoteCallSet>& rank_to_remote_call_sets) const
824  {
825  int rank;
826  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
827  std::map<int, std::set<RemoteCallPrototype<M>>> rank_to_remote_call_prototypes;
828  std::map<int, std::set<IncomingGhostPrototype<M>>> rank_to_incoming_ghost_prototypes;
829 
830  for (const PatchInfo<D>& pinfo : domain.getPatchInfoVector()) {
831  for (Face<D, M> f : Face<D, M>::getValues()) {
832  if (pinfo.hasNbr(f)) {
833  switch (pinfo.getNbrType(f)) {
834  case NbrType::Normal:
835  addNormalNbrCalls(pinfo,
836  f,
837  my_local_calls,
838  rank_to_remote_call_prototypes,
839  rank_to_incoming_ghost_prototypes);
840  break;
841  case NbrType::Fine:
842  addFineNbrCalls(pinfo,
843  f,
844  my_local_calls,
845  rank_to_remote_call_prototypes,
846  rank_to_incoming_ghost_prototypes);
847  break;
848  case NbrType::Coarse:
849  addCoarseNbrCalls(pinfo,
850  f,
851  my_local_calls,
852  rank_to_remote_call_prototypes,
853  rank_to_incoming_ghost_prototypes);
854  break;
855  default:
856  throw RuntimeError("Unsupported NbrType");
857  }
858  }
859  }
860  }
861  const GhostViewInfo<M>& ghost_local_data_info = ghost_local_data_infos.template get<M>();
862  for (const auto& pair : rank_to_remote_call_prototypes) {
863  int rank = pair.first;
864  rank_to_remote_call_sets.emplace(rank, rank);
865  RemoteCallSet& remote_call_set = rank_to_remote_call_sets.at(rank);
866  std::tuple<int, Face<D, M>> prev_id_side;
867  for (const RemoteCallPrototype<M>& call : pair.second) {
868  size_t offset = remote_call_set.send_buffer_length;
869 
870  // calculate length in buffer need for ghost cells
871  size_t length = ghost_local_data_info.getSize(call.face);
872  // add length to buffer length
873  // if its the same side of the patch, resuse the previous buffer space
874  if (std::make_tuple(call.id, call.face) == prev_id_side) {
875  offset -= length;
876  } else {
877  remote_call_set.send_buffer_length += length;
878  }
879  remote_call_set.remote_calls.template get<M>().emplace_back(call, offset);
880  prev_id_side = std::make_tuple(call.id, call.face);
881  }
882  }
883  for (const auto& pair : rank_to_incoming_ghost_prototypes) {
884  RemoteCallSet& remote_call_set = rank_to_remote_call_sets.at(pair.first);
885  for (const IncomingGhostPrototype<M>& prototype : pair.second) {
886  // add length for ghosts to buffer length
887  size_t length = ghost_local_data_info.getSize(prototype.face);
888  size_t offset = remote_call_set.recv_buffer_length;
889  remote_call_set.recv_buffer_length += length;
890 
891  // add ghost to incoming ghosts
892  remote_call_set.incoming_ghosts.template get<M>().emplace_back(prototype, offset);
893  }
894  }
895  }
896 
904  template<int M>
905  void zeroGhostCellsOnAllFaces(const PatchInfo<D>& pinfo, PatchView<const double, D>& view) const
906  {
907  for (Face<D, M> f : Face<D, M>::getValues()) {
908  if (pinfo.hasNbr(f)) {
909  std::array<size_t, D - M> start;
910  start.fill(0);
911  std::array<size_t, D - M> end;
912  end.fill(domain.getNumGhostCells() - 1);
913  Loop::Nested<D - M>(start, end, [&](const std::array<size_t, D - M>& offset) {
914  View<double, M + 1> this_ghost = view.getGhostSliceOn(f, offset);
915  Loop::OverInteriorIndexes<M + 1>(
916  this_ghost, [&](const std::array<int, M + 1>& coord) { this_ghost[coord] = 0; });
917  });
918  }
919  }
920  }
921 
927  void zeroGhostCells(const Vector<D>& u) const
928  {
929  for (const PatchInfo<D>& pinfo : domain.getPatchInfoVector()) {
931  switch (fill_type) {
933  if constexpr (D >= 2) {
934  zeroGhostCellsOnAllFaces<0>(pinfo, this_patch);
935  }
937  if constexpr (D == 3) {
938  zeroGhostCellsOnAllFaces<1>(pinfo, this_patch);
939  }
941  zeroGhostCellsOnAllFaces<D - 1>(pinfo, this_patch);
942  break;
943  default:
944  throw RuntimeError("Unsupported GhostFilling Type");
945  }
946  }
947  }
948 
949 public:
956  MPIGhostFiller(const Domain<D>& domain, GhostFillingType fill_type)
957  : domain(domain)
958  , fill_type(fill_type)
959  {
960  std::map<int, RemoteCallSet> rank_to_remote_call_sets;
961 
962  switch (fill_type) {
964  if constexpr (D >= 2) {
965  ghost_local_data_infos.template get<0>() = GhostViewInfo<0>(domain);
966  enumerateCalls<0>(local_calls.template get<0>(), rank_to_remote_call_sets);
967  }
969  if constexpr (D == 3) {
970  ghost_local_data_infos.template get<1>() = GhostViewInfo<1>(domain);
971  enumerateCalls<1>(local_calls.template get<1>(), rank_to_remote_call_sets);
972  }
974  ghost_local_data_infos.template get<D - 1>() = GhostViewInfo<D - 1>(domain);
975  enumerateCalls<D - 1>(local_calls.template get<D - 1>(), rank_to_remote_call_sets);
976  break;
977  default:
978  throw RuntimeError("Unsupported GhostFilling Type");
979  }
980 
981  remote_call_sets.reserve(rank_to_remote_call_sets.size());
982  for (const auto& pair : rank_to_remote_call_sets) {
983  remote_call_sets.push_back(pair.second);
984  }
985  }
998  virtual void fillGhostCellsForNbrPatch(const PatchInfo<D>& pinfo,
999  const PatchView<const double, D>& local_view,
1000  const PatchView<const double, D>& nbr_view,
1001  Side<D> side,
1002  NbrType nbr_type,
1003  Orthant<D - 1> orthant_on_coarse) const = 0;
1016  virtual void fillGhostCellsForEdgeNbrPatch(const PatchInfo<D>& pinfo,
1017  const PatchView<const double, D>& local_view,
1018  const PatchView<const double, D>& nbr_view,
1019  Edge edge,
1020  NbrType nbr_type,
1021  Orthant<1> orthant_on_coarse) const = 0;
1032  virtual void fillGhostCellsForCornerNbrPatch(const PatchInfo<D>& pinfo,
1033  const PatchView<const double, D>& local_view,
1034  const PatchView<const double, D>& nbr_view,
1035  Corner<D> corner,
1036  NbrType nbr_type) const = 0;
1037 
1047  virtual void fillGhostCellsForLocalPatch(const PatchInfo<D>& pinfo,
1048  const PatchView<const double, D>& view) const = 0;
1049 
1055  void fillGhost(const Vector<D>& u) const override
1056  {
1057  if constexpr (ENABLE_DEBUG) {
1058  if (u.getNumLocalPatches() != domain.getNumLocalPatches()) {
1059  throw RuntimeError("u vector is incorrect length. Expected Lenght of " +
1060  std::to_string(domain.getNumLocalPatches()) + " but vector was length " +
1061  std::to_string(u.getNumLocalPatches()));
1062  }
1063  }
1064  // zero out ghost cells
1065  zeroGhostCells(u);
1066 
1067  // allocate recv buffers and post recvs
1068  std::vector<std::vector<double>> recv_buffers(remote_call_sets.size());
1069  for (size_t i = 0; i < remote_call_sets.size(); i++) {
1070  recv_buffers[i].resize(remote_call_sets[i].recv_buffer_length * u.getNumComponents());
1071  }
1072  std::vector<MPI_Request> recv_requests = postRecvs(recv_buffers);
1073 
1074  // allocate send buffers
1075  std::vector<std::vector<double>> out_buffers(remote_call_sets.size());
1076  for (size_t i = 0; i < remote_call_sets.size(); i++) {
1077  out_buffers[i].resize(remote_call_sets[i].send_buffer_length * u.getNumComponents());
1078  }
1079  std::vector<MPI_Request> send_requests = postSends(out_buffers, u);
1080 
1081  // perform local operations
1082  for (const PatchInfo<D>& pinfo : domain.getPatchInfoVector()) {
1084  fillGhostCellsForLocalPatch(pinfo, view);
1085  }
1086  processLocalFills<D - 1>(u);
1087 
1088  processRecvs(recv_requests, recv_buffers, u);
1089 
1090  // wait for sends for finish
1091  MPI_Waitall(send_requests.size(), send_requests.data(), MPI_STATUS_IGNORE);
1092  }
1093 
1099  GhostFillingType getFillType() const { return fill_type; }
1100 
1106  const Domain<D>& getDomain() const { return domain; }
1107 };
1108 extern template class MPIGhostFiller<1>;
1109 extern template class MPIGhostFiller<2>;
1110 extern template class MPIGhostFiller<3>;
1111 } // namespace ThunderEgg
1112 #endif
ThunderEgg::PatchInfo::getFineNbrInfo
FineNbrInfo< M > & getFineNbrInfo(Face< D, M > s) const
Get the FineNbrInfo object.
Definition: PatchInfo.h:272
ThunderEgg::Loop::Nested
static void Nested(A start, A end, T lambda)
Loop over a range of integer coordinates.
Definition: Loops.h:125
ThunderEgg::View
Array for acessing data of a patch. It supports variable striding.
Definition: View.h:40
ThunderEgg::Orthant< M >
ThunderEgg::PatchInfo::hasNbr
bool hasNbr(Face< D, M > s) const
Return whether the patch has a neighbor.
Definition: PatchInfo.h:284
ThunderEgg::NbrType::Coarse
@ Coarse
The neighbor is at a coarser refinement level.
ThunderEgg::GhostFillingType
GhostFillingType
type of ghost filling.
Definition: GhostFillingType.h:33
ThunderEgg::PatchView::getGhostSliceOn
View< typename std::remove_const< T >::type, M+1 > getGhostSliceOn(Face< D, M > f, const std::array< size_t, D - M > &offset) const
Get the gosts slice on a given face.
Definition: PatchView.h:219
ThunderEgg::PatchInfo::getNormalNbrInfo
NormalNbrInfo< M > & getNormalNbrInfo(Face< D, M > s) const
Get the NormalNbrInfo object for a side.
Definition: PatchInfo.h:245
ThunderEgg::Domain::getNs
const std::array< int, D > & getNs() const
Get the number of cells in each direction.
Definition: Domain.h:264
ThunderEgg::MPIGhostFiller::fillGhostCellsForCornerNbrPatch
virtual void fillGhostCellsForCornerNbrPatch(const PatchInfo< D > &pinfo, const PatchView< const double, D > &local_view, const PatchView< const double, D > &nbr_view, Corner< D > corner, NbrType nbr_type) const =0
Fill the corner ghost cells for the neighboring patch.
ThunderEgg::Domain
Uses a collection of PatchInfo objects to represent the domain of the problem.
Definition: Domain.h:50
ThunderEgg::MPIGhostFiller::getFillType
GhostFillingType getFillType() const
Get the ghost filling type.
Definition: MPIGhostFiller.h:1099
DimensionalArray.h
DimensionalArray class.
ThunderEgg::MPIGhostFiller::fillGhostCellsForEdgeNbrPatch
virtual void fillGhostCellsForEdgeNbrPatch(const PatchInfo< D > &pinfo, const PatchView< const double, D > &local_view, const PatchView< const double, D > &nbr_view, Edge edge, NbrType nbr_type, Orthant< 1 > orthant_on_coarse) const =0
Fill the edge ghost cells for the neighboring patch.
ThunderEgg::MPIGhostFiller::fillGhostCellsForLocalPatch
virtual void fillGhostCellsForLocalPatch(const PatchInfo< D > &pinfo, const PatchView< const double, D > &view) const =0
Perform any on this patches ghost cells.
ThunderEgg::PatchInfo::local_index
int local_index
The local index of the patch in the Domain.
Definition: PatchInfo.h:69
ThunderEgg::Domain::getNumLocalPatches
int getNumLocalPatches() const
Get the number of local patches.
Definition: Domain.h:272
ThunderEgg::DimensionalArray< D, RemoteCallDeque >
ThunderEgg::MPIGhostFiller::fillGhost
void fillGhost(const Vector< D > &u) const override
Fill ghost cells on a vector.
Definition: MPIGhostFiller.h:1055
ThunderEgg::PatchInfo::getNbrType
NbrType getNbrType(Face< D, M > s) const
Get the NbrType for a side.
Definition: PatchInfo.h:232
ThunderEgg::NbrType
NbrType
The type of neighbor.
Definition: NbrType.h:34
ThunderEgg::MPIGhostFiller::MPIGhostFiller
MPIGhostFiller(const Domain< D > &domain, GhostFillingType fill_type)
Construct a new MPIGhostFiller object.
Definition: MPIGhostFiller.h:956
ThunderEgg::MPIGhostFiller
Parallell ghostfiller implimented with MPI.
Definition: MPIGhostFiller.h:45
ThunderEgg::PatchView
View for accessing data of a patch. It supports variable striding.
Definition: PatchView.h:37
ThunderEgg
The ThunderEgg namespace.
Definition: BiLinearGhostFiller.h:31
ThunderEgg::PatchInfo::id
int id
The globally unique ID of the patch This ID only needs to be unique within a Domain.
Definition: PatchInfo.h:65
GhostFillingType.h
GhostFillingType enum.
GhostFiller.h
GhostFiller class.
ThunderEgg::Face::getIndex
size_t getIndex() const
Get the index for this Face.
Definition: Face.h:452
ThunderEgg::MPIGhostFiller::getDomain
const Domain< D > & getDomain() const
Get the domain that is being filled for.
Definition: MPIGhostFiller.h:1106
ThunderEgg::GhostFiller
Fills ghost cells on patches.
Definition: GhostFiller.h:36
ThunderEgg::GhostFillingType::Faces
@ Faces
Fill only faces.
ThunderEgg::PatchInfo
Contains metadata for a patch.
Definition: PatchInfo.h:51
ThunderEgg::Face::getSides
std::array< Face< D, D - 1 >, D - M > getSides() const
Get the Sides that this Face lies on.
Definition: Face.h:496
ThunderEgg::Domain::getNumGhostCells
int getNumGhostCells() const
get the number of ghost cell on each side of a patch
Definition: Domain.h:295
Domain.h
Domain class.
ThunderEgg::MPIGhostFiller::fillGhostCellsForNbrPatch
virtual void fillGhostCellsForNbrPatch(const PatchInfo< D > &pinfo, const PatchView< const double, D > &local_view, const PatchView< const double, D > &nbr_view, Side< D > side, NbrType nbr_type, Orthant< D - 1 > orthant_on_coarse) const =0
Fill the ghost cells for the neighboring patch.
ThunderEgg::NbrType::Fine
@ Fine
The nighbor is at a finer refinement level.
ThunderEgg::NbrType::Normal
@ Normal
The neighbor is at the same refinement level.
ThunderEgg::Vector::getPatchView
PatchView< double, D > getPatchView(int patch_local_index)
Get the View objects for the specified patch index of View object will correspond to component index.
Definition: Vector.h:358
ThunderEgg::Vector
Vector class for use in thunderegg.
Definition: Vector.h:42
ThunderEgg::Domain::getPatchInfoVector
const std::vector< PatchInfo< D > > & getPatchInfoVector() const
Get a vector of PatchInfo pointers where index in the vector corresponds to the patch's local index.
Definition: Domain.h:259
ThunderEgg::Face
Enum-style class for the faces of an n-dimensional cube.
Definition: Face.h:41
ThunderEgg::GhostFillingType::Edges
@ Edges
Fill faces and edges.
ThunderEgg::Vector::getNumLocalPatches
int getNumLocalPatches() const
Get the number of local patches.
Definition: Vector.h:316
ThunderEgg::Face::opposite
Face< D, M > opposite() const
Get the face on the opposite side of the hypercube.
Definition: Face.h:489
ThunderEgg::PatchInfo::getCoarseNbrInfo
CoarseNbrInfo< M > & getCoarseNbrInfo(Face< D, M > s) const
Get the CoarseNbrInfo object.
Definition: PatchInfo.h:258
ThunderEgg::GhostFillingType::Corners
@ Corners
Fill faces, edges, and corners. (or faces and corners in the 2d case)
ThunderEgg::RuntimeError
ThunderEgg runtime exception.
Definition: RuntimeError.h:36