MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_RepartitionUtilities_def.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// MueLu: A package for multigrid based preconditioning
4//
5// Copyright 2012 NTESS and the MueLu contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef MUELU_REPARTITIONUTILITIES_DEF_HPP
11#define MUELU_REPARTITIONUTILITIES_DEF_HPP
12
13#include <algorithm>
14#include <iostream>
15#include <sstream>
16
17#include "MueLu_RepartitionUtilities_decl.hpp" // TMP JG NOTE: before other includes, otherwise I cannot test the fwd declaration in _def
18
19#ifdef HAVE_MPI
20#include <Teuchos_DefaultMpiComm.hpp>
21#include <Teuchos_CommHelpers.hpp>
22#include <Teuchos_Details_MpiTypeTraits.hpp>
23
24#include <Xpetra_Map.hpp>
25#include <Xpetra_MapFactory.hpp>
26#include <Xpetra_MultiVectorFactory.hpp>
27#include <Xpetra_VectorFactory.hpp>
28#include <Xpetra_Import.hpp>
29#include <Xpetra_ImportFactory.hpp>
30#include <Xpetra_Export.hpp>
31#include <Xpetra_ExportFactory.hpp>
32
33#include "MueLu_Utilities.hpp"
34
35#include "MueLu_CloneRepartitionInterface.hpp"
36
37#include "MueLu_Level.hpp"
38#include "MueLu_MasterList.hpp"
39#include "MueLu_Monitor.hpp"
40#include "MueLu_PerfUtils.hpp"
41
42namespace MueLu {
43
44template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
45std::tuple<Teuchos::Array<GlobalOrdinal>, GlobalOrdinal>
47 ArrayRCP<const GO> decompEntries;
48 if (decomposition->getLocalLength() > 0)
49 decompEntries = decomposition->getData(0);
50
51 auto rowMap = decomposition->getMap();
52 auto comm = rowMap->getComm();
53 const auto myRank = comm->getRank();
54
55 Array<GO> myGIDs;
56 myGIDs.reserve(decomposition->getLocalLength());
57
58 // Step 0: Construct mapping
59 // part number -> GIDs I own which belong to this part
60 // NOTE: my own part GIDs are not part of the map
61 typedef std::map<GO, Array<GO> > map_type;
62 map_type sendMap;
63 for (LO i = 0; i < decompEntries.size(); i++) {
64 GO id = decompEntries[i];
65 GO GID = rowMap->getGlobalElement(i);
66
67 if (id == myRank)
68 myGIDs.push_back(GID);
69 else
70 sendMap[id].push_back(GID);
71 }
72 decompEntries = Teuchos::null;
73
74 int numSend = sendMap.size(), numRecv;
75
76 // Arrayify map keys
77 Array<GO> myParts(numSend), myPart(1);
78 int cnt = 0;
79 myPart[0] = myRank;
80 for (typename map_type::const_iterator it = sendMap.begin(); it != sendMap.end(); it++)
81 myParts[cnt++] = it->first;
82
83 const GO numLocalKept = myGIDs.size();
84
85 // Step 1: Find out how many processors send me data
86 // partsIndexBase starts from zero, as the processors ids start from zero
87 {
88 const int root = 0;
89 Kokkos::View<int*, Kokkos::HostSpace> mySends("mySends", comm->getSize());
90 for (typename map_type::const_iterator it = sendMap.begin(); it != sendMap.end(); it++)
91 mySends(it->first) = 1;
92 Kokkos::View<int*, Kokkos::HostSpace> numRecvsOnEachProc;
93 if (comm->getRank() == root)
94 numRecvsOnEachProc = Kokkos::View<int*, Kokkos::HostSpace>("numRecvsOnEachProc", comm->getSize());
95 Teuchos::reduce<int, int>(mySends.data(), numRecvsOnEachProc.data(), comm->getSize(), Teuchos::REDUCE_SUM, root, *comm);
96 Teuchos::scatter<int, int>(numRecvsOnEachProc.data(), 1, &numRecv, 1, root, *comm);
97 }
98
99 RCP<const Teuchos::MpiComm<int> > tmpic = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(comm);
100 TEUCHOS_TEST_FOR_EXCEPTION(tmpic == Teuchos::null, Exceptions::RuntimeError, "Cannot cast base Teuchos::Comm to Teuchos::MpiComm object.");
101 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > rawMpiComm = tmpic->getRawMpiComm();
102
103 // Step 2: Get my GIDs from everybody else
104 MPI_Datatype MpiType = Teuchos::Details::MpiTypeTraits<GO>::getType();
105 int msgTag = 12345; // TODO: use Comm::dup for all internal messaging
106
107 // Post sends
108 Array<MPI_Request> sendReqs(numSend);
109 cnt = 0;
110 for (typename map_type::iterator it = sendMap.begin(); it != sendMap.end(); it++)
111 MPI_Isend(static_cast<void*>(it->second.getRawPtr()), it->second.size(), MpiType, Teuchos::as<GO>(it->first), msgTag, *rawMpiComm, &sendReqs[cnt++]);
112
113 map_type recvMap;
114 size_t totalGIDs = myGIDs.size();
115 for (int i = 0; i < numRecv; i++) {
116 MPI_Status status;
117 MPI_Probe(MPI_ANY_SOURCE, msgTag, *rawMpiComm, &status);
118
119 // Get rank and number of elements from status
120 int fromRank = status.MPI_SOURCE, count;
121 MPI_Get_count(&status, MpiType, &count);
122
123 recvMap[fromRank].resize(count);
124 MPI_Recv(static_cast<void*>(recvMap[fromRank].getRawPtr()), count, MpiType, fromRank, msgTag, *rawMpiComm, &status);
125
126 totalGIDs += count;
127 }
128
129 // Do waits on send requests
130 if (numSend) {
131 Array<MPI_Status> sendStatuses(numSend);
132 MPI_Waitall(numSend, sendReqs.getRawPtr(), sendStatuses.getRawPtr());
133 }
134
135 // Merge GIDs
136 myGIDs.reserve(totalGIDs);
137 for (typename map_type::const_iterator it = recvMap.begin(); it != recvMap.end(); it++) {
138 int offset = myGIDs.size(), len = it->second.size();
139 if (len) {
140 myGIDs.resize(offset + len);
141 memcpy(myGIDs.getRawPtr() + offset, it->second.getRawPtr(), len * sizeof(GO));
142 }
143 }
144 // NOTE 2: The general sorting algorithm could be sped up by using the knowledge that original myGIDs and all received chunks
145 // (i.e. it->second) are sorted. Therefore, a merge sort would work well in this situation.
146 std::sort(myGIDs.begin(), myGIDs.end());
147
148 return std::make_tuple(myGIDs, numLocalKept);
149}
150
151} // namespace MueLu
152
153#endif // ifdef HAVE_MPI
154
155#endif // MUELU_REPARTITIONUTILITIES_DEF_HPP
MueLu::DefaultGlobalOrdinal GlobalOrdinal
Exception throws to report errors in the internal logical of the program.
Namespace for MueLu classes and methods.
static std::tuple< Array< GO >, GO > ConstructGIDs(RCP< GOVector > decomposition)