Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_Details_makeOptimizedColMap.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Tpetra: Templated Linear Algebra Services Package
4//
5// Copyright 2008 NTESS and the Tpetra contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
27
28#include "Tpetra_Map.hpp"
29#include "Tpetra_Import.hpp"
30#include "Tpetra_Util.hpp"
32#include "Teuchos_FancyOStream.hpp"
33#include <memory>
34
35namespace Tpetra {
36namespace Details {
37
44 template<class MapType>
45 class OptColMap {
46 public:
47 using local_ordinal_type = typename MapType::local_ordinal_type;
48 using global_ordinal_type = typename MapType::global_ordinal_type;
49 using node_type = typename MapType::node_type;
52
53 static Teuchos::RCP<const map_type>
54 makeOptColMap (std::ostream& errStream,
55 bool& lclErr,
56 const map_type& domMap,
57 const map_type& colMap,
58 const import_type* /* oldImport */)
59 {
61 using Teuchos::Array;
62 using Teuchos::ArrayView;
63 using Teuchos::FancyOStream;
64 using Teuchos::getFancyOStream;
65 using Teuchos::RCP;
66 using Teuchos::rcp;
67 using Teuchos::rcpFromRef;
68 using std::endl;
69 using LO = local_ordinal_type;
70 using GO = global_ordinal_type;
71 const char prefix[] = "Tpetra::Details::makeOptimizedColMap: ";
72
73 RCP<const Teuchos::Comm<int> > comm = colMap.getComm ();
74 std::ostream& err = errStream;
75
76 const bool verbose = Behavior::verbose ("Tpetra::Details::makeOptimizedColMap");
77
78 RCP<FancyOStream> outPtr = getFancyOStream (rcpFromRef (std::cerr));
79 TEUCHOS_TEST_FOR_EXCEPTION
80 (outPtr.is_null (), std::logic_error,
81 "outPtr is null; this should never happen!");
82 FancyOStream& out = *outPtr;
83 Teuchos::OSTab tab1 (out);
84
85 std::unique_ptr<std::string> verboseHeader;
86 if (verbose) {
87 std::ostringstream os;
88 const int myRank = comm->getRank ();
89 os << "Proc " << myRank << ": ";
90 verboseHeader = std::unique_ptr<std::string> (new std::string (os.str ()));
91 }
92 if (verbose) {
93 std::ostringstream os;
94 os << *verboseHeader << "Tpetra::Details::makeOptimizedColMap" << endl;
95 out << os.str ();
96 }
97
98 if (verbose) {
99 std::ostringstream os;
100 os << *verboseHeader << "Domain Map GIDs: [";
101 const LO domMapLclNumInds = static_cast<LO> (domMap.getLocalNumElements ());
102 for (LO lid = 0; lid < domMapLclNumInds; ++lid) {
103 const GO gid = domMap.getGlobalElement (lid);
104 os << gid;
105 if (lid + LO (1) < domMapLclNumInds) {
106 os << ", ";
107 }
108 }
109 os << "]" << endl;
110 out << os.str ();
111 }
112
113 const LO colMapLclNumInds = static_cast<LO> (colMap.getLocalNumElements ());
114
115 if (verbose) {
116 std::ostringstream os;
117 os << *verboseHeader << "Column Map GIDs: [";
118 for (LO lid = 0; lid < colMapLclNumInds; ++lid) {
119 const GO gid = colMap.getGlobalElement (lid);
120 os << gid;
121 if (lid + LO (1) < colMapLclNumInds) {
122 os << ", ";
123 }
124 }
125 os << "]" << endl;
126 out << os.str ();
127 }
128
129 // Count remote GIDs.
130 LO numOwnedGids = 0;
131 LO numRemoteGids = 0;
132 for (LO colMapLid = 0; colMapLid < colMapLclNumInds; ++colMapLid) {
133 const GO colMapGid = colMap.getGlobalElement (colMapLid);
134 if (domMap.isNodeGlobalElement (colMapGid)) {
135 ++numOwnedGids;
136 }
137 else {
138 ++numRemoteGids;
139 }
140 }
141
142 if (verbose) {
143 std::ostringstream os;
144 os << *verboseHeader << "- numOwnedGids: " << numOwnedGids << endl
145 << *verboseHeader << "- numRemoteGids: " << numRemoteGids << endl;
146 out << os.str ();
147 }
148
149 // Put all colMap GIDs on the calling process in a single array.
150 // Owned GIDs go in front, and remote GIDs at the end.
151 Array<GO> allGids (numOwnedGids + numRemoteGids);
152 ArrayView<GO> ownedGids = allGids.view (0, numOwnedGids);
153 ArrayView<GO> remoteGids = allGids.view (numOwnedGids, numRemoteGids);
154
155 // Fill ownedGids and remoteGids (and therefore allGids). We use
156 // two loops, one to count (above) and one to fill (here), in
157 // order to avoid dynamic memory allocation during the loop (in
158 // this case, lots of calls to push_back()). That will simplify
159 // use of Kokkos to parallelize these loops later.
160 LO ownedPos = 0;
161 LO remotePos = 0;
162 for (LO colMapLid = 0; colMapLid < colMapLclNumInds; ++colMapLid) {
163 const GO colMapGid = colMap.getGlobalElement (colMapLid);
164 if (domMap.isNodeGlobalElement (colMapGid)) {
165 ownedGids[ownedPos++] = colMapGid;
166 }
167 else {
168 remoteGids[remotePos++] = colMapGid;
169 }
170 }
171
172 // If, for some reason, the running count doesn't match the
173 // orignal count, fill in any remaining GID spots with an
174 // obviously invalid value. We don't want to stop yet, because
175 // other processes might not have noticed this error; Map
176 // construction is a collective, so we can't stop now.
177 if (ownedPos != numOwnedGids) {
178 lclErr = true;
179 err << prefix << "On Process " << comm->getRank () << ", ownedPos = "
180 << ownedPos << " != numOwnedGids = " << numOwnedGids << endl;
181 for (LO colMapLid = ownedPos; colMapLid < numOwnedGids; ++colMapLid) {
182 ownedGids[colMapLid] = Teuchos::OrdinalTraits<GO>::invalid ();
183 }
184 }
185 if (remotePos != numRemoteGids) {
186 lclErr = true;
187 err << prefix << "On Process " << comm->getRank () << ", remotePos = "
188 << remotePos << " != numRemoteGids = " << numRemoteGids << endl;
189 for (LO colMapLid = remotePos; colMapLid < numRemoteGids; ++colMapLid) {
190 remoteGids[colMapLid] = Teuchos::OrdinalTraits<GO>::invalid ();
191 }
192 }
193
194 // Figure out what processes own what GIDs in the domain Map.
195 // Initialize the output array of remote PIDs with the "invalid
196 // process rank" -1, to help us test whether getRemoteIndexList
197 // did its job.
198 Array<int> remotePids (numRemoteGids, -1);
199 const LookupStatus lookupStatus =
200 domMap.getRemoteIndexList (remoteGids, remotePids ());
201
202 // If any process returns IDNotPresent, then at least one of the
203 // remote indices was not present in the domain Map. This means
204 // that the Import object cannot be constructed, because of
205 // incongruity between the column Map and domain Map. This
206 // means that either the column Map or domain Map, or both, is
207 // incorrect.
208 const bool getRemoteIndexListFailed = (lookupStatus == IDNotPresent);
209 if (getRemoteIndexListFailed) {
210 lclErr = true;
211 err << prefix << "On Process " << comm->getRank () << ", some indices "
212 "in the input colMap (the original column Map) are not in domMap (the "
213 "domain Map). Either these indices or the domain Map is invalid. "
214 "Likely cause: For a nonsquare matrix, you must give the domain and "
215 "range Maps as input to fillComplete." << endl;
216 }
217
218 // Check that getRemoteIndexList actually worked, by making sure
219 // that none of the remote PIDs are -1.
220 for (LO k = 0; k < numRemoteGids; ++k) {
221 bool foundInvalidPid = false;
222 if (remotePids[k] == -1) {
223 foundInvalidPid = true;
224 break;
225 }
226 if (foundInvalidPid) {
227 lclErr = true;
228 err << prefix << "On Process " << comm->getRank () << ", "
229 "getRemoteIndexList returned -1 for the process ranks of "
230 "one or more GIDs on this process." << endl;
231 }
232 }
233
234 if (verbose) {
235 std::ostringstream os;
236 os << *verboseHeader << "- Before sort2:" << endl
237 << *verboseHeader << "-- ownedGids: " << Teuchos::toString (ownedGids) << endl
238 << *verboseHeader << "-- remoteGids: " << Teuchos::toString (remoteGids) << endl
239 << *verboseHeader << "-- allGids: " << Teuchos::toString (allGids ()) << endl;
240 out << os.str ();
241 }
242 using Tpetra::sort2;
243 sort2 (remotePids.begin (), remotePids.end (), remoteGids.begin (), true);
244 if (verbose) {
245 std::ostringstream os;
246 os << *verboseHeader << "- After sort2:" << endl
247 << *verboseHeader << "-- ownedGids: " << Teuchos::toString (ownedGids) << endl
248 << *verboseHeader << "-- remoteGids: " << Teuchos::toString (remoteGids) << endl
249 << *verboseHeader << "-- allGids: " << Teuchos::toString (allGids ()) << endl;
250 out << os.str ();
251 }
252
253 auto optColMap = rcp (new map_type (colMap.getGlobalNumElements (),
254 allGids (),
255 colMap.getIndexBase (),
256 comm));
257 if (verbose) {
258 std::ostringstream os;
259 os << *verboseHeader << "Tpetra::Details::makeOptimizedColMap: Done" << endl;
260 out << os.str ();
261 }
262 return optColMap;
263 }
264
295 static std::pair<Teuchos::RCP<const map_type>,
296 Teuchos::RCP<import_type> >
297 makeOptColMapAndImport (std::ostream& errStream,
298 bool& lclErr,
299 const map_type& domMap,
300 const map_type& colMap,
301 const import_type* oldImport)
302 {
303 using Teuchos::RCP;
304 using Teuchos::rcp;
305
306 // mfh 15 May 2018: For now, just call makeOptColMap, and use
307 // the conventional two-Map (source and target) Import
308 // constructor.
309 RCP<const map_type> newColMap =
310 makeOptColMap (errStream, lclErr, domMap, colMap, oldImport);
311 RCP<import_type> imp (new import_type (rcp (new map_type (domMap)), newColMap));
312
313 // FIXME (mfh 06 Jul 2014) This constructor throws a runtime
314 // error, so I'm not using it for now.
315 //
316 // imp = rcp (new import_type (domMap, newColMap, remoteGids,
317 // remotePids (), remoteLids (),
318 // Teuchos::null, Teuchos::null));
319 return std::make_pair (newColMap, imp);
320 }
321 };
322
347 template<class MapType>
348 Teuchos::RCP<const MapType>
349 makeOptimizedColMap (std::ostream& errStream,
350 bool& lclErr,
351 const MapType& domMap,
352 const MapType& colMap,
353 const Tpetra::Import<
354 typename MapType::local_ordinal_type,
355 typename MapType::global_ordinal_type,
356 typename MapType::node_type>* oldImport = nullptr)
357 {
358 using map_type = ::Tpetra::Map<
359 typename MapType::local_ordinal_type,
360 typename MapType::global_ordinal_type,
361 typename MapType::node_type>;
362 using impl_type = OptColMap<map_type>;
363 auto mapPtr = impl_type::makeOptColMap (errStream, lclErr,
364 domMap, colMap, oldImport);
365 return mapPtr;
366 }
367
424 template<class MapType>
425 std::pair<Teuchos::RCP<const MapType>,
426 Teuchos::RCP<typename OptColMap<MapType>::import_type> >
427 makeOptimizedColMapAndImport (std::ostream& errStream,
428 bool& lclErr,
429 const MapType& domMap,
430 const MapType& colMap,
431 const typename OptColMap<MapType>::import_type* oldImport = nullptr)
432 {
433 using local_ordinal_type = typename MapType::local_ordinal_type;
434 using global_ordinal_type = typename MapType::global_ordinal_type;
435 using node_type = typename MapType::node_type;
437 using impl_type = OptColMap<map_type>;
438
439 auto mapAndImp = impl_type::makeOptColMapAndImport (errStream, lclErr, domMap, colMap, oldImport);
440 return std::make_pair (mapAndImp.first, mapAndImp.second);
441 }
442
443} // namespace Details
444} // namespace Tpetra
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.
Stand-alone utility functions and macros.
Description of Tpetra's behavior.
static bool verbose()
Whether Tpetra is in verbose mode.
Implementation detail of makeOptimizedColMap, and makeOptimizedColMapAndImport.
static std::pair< Teuchos::RCP< const map_type >, Teuchos::RCP< import_type > > makeOptColMapAndImport(std::ostream &errStream, bool &lclErr, const map_type &domMap, const map_type &colMap, const import_type *oldImport)
Return an optimized reordering of the given column Map. Optionally, recompute an Import from the inpu...
Communication plan for data redistribution from a uniquely-owned to a (possibly) multiply-owned distr...
A parallel distribution of indices over processes.
global_ordinal_type getGlobalElement(local_ordinal_type localIndex) const
The global index corresponding to the given local index.
LookupStatus getRemoteIndexList(const Teuchos::ArrayView< const global_ordinal_type > &GIDList, const Teuchos::ArrayView< int > &nodeIDList, const Teuchos::ArrayView< local_ordinal_type > &LIDList) const
Return the process ranks and corresponding local indices for the given global indices.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
global_ordinal_type getIndexBase() const
The index base for this Map.
global_size_t getGlobalNumElements() const
The number of elements in this Map.
bool isNodeGlobalElement(global_ordinal_type globalIndex) const
Whether the given global index is owned by this Map on the calling process.
size_t getLocalNumElements() const
The number of elements belonging to the calling process.
Nonmember function that computes a residual Computes R = B - A * X.
std::pair< Teuchos::RCP< const MapType >, Teuchos::RCP< typename OptColMap< MapType >::import_type > > makeOptimizedColMapAndImport(std::ostream &errStream, bool &lclErr, const MapType &domMap, const MapType &colMap, const typename OptColMap< MapType >::import_type *oldImport=nullptr)
Return an optimized reordering of the given column Map. Optionally, recompute an Import from the inpu...
Teuchos::RCP< const MapType > makeOptimizedColMap(std::ostream &errStream, bool &lclErr, const MapType &domMap, const MapType &colMap, const Tpetra::Import< typename MapType::local_ordinal_type, typename MapType::global_ordinal_type, typename MapType::node_type > *oldImport=nullptr)
Return an optimized reordering of the given column Map.
Namespace Tpetra contains the class and methods constituting the Tpetra library.
void sort2(const IT1 &first1, const IT1 &last1, const IT2 &first2, const bool stableSort=false)
Sort the first array, and apply the resulting permutation to the second array.
LookupStatus
Return status of Map remote index lookup (getRemoteIndexList()).