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  {
60  using ::Tpetra::Details::Behavior;
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
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.