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