Xpetra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Xpetra_MapUtils.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Xpetra: A linear algebra interface package
4 //
5 // Copyright 2012 NTESS and the Xpetra contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef PACKAGES_XPETRA_SUP_MAP_UTILS_HPP_
11 #define PACKAGES_XPETRA_SUP_MAP_UTILS_HPP_
12 
13 #include "Xpetra_ConfigDefs.hpp"
14 
15 #include "Xpetra_Exceptions.hpp"
16 #include "Xpetra_Map.hpp"
17 #include "Xpetra_MapFactory.hpp"
18 
19 namespace Xpetra {
20 
21 #ifndef DOXYGEN_SHOULD_SKIP_THIS
22 // forward declaration of BlockedMap, needed to prevent circular inclusions
23 template <class LO, class GO, class N>
24 class BlockedMap;
25 #endif
26 
34 template <class LocalOrdinal,
35  class GlobalOrdinal,
36  class Node = Tpetra::KokkosClassic::DefaultNode::DefaultNodeType>
37 class MapUtils {
38 #undef XPETRA_MAPUTILS_SHORT
40 
41  public:
56  static Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node> > concatenateMaps(const std::vector<Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node> > >& subMaps) {
57  // ToDo Resolve header issues to allow for using this routing in Xpetra::BlockedMap.
58 
59  // merge submaps to global map
60  std::vector<GlobalOrdinal> gids;
61  for (size_t tt = 0; tt < subMaps.size(); ++tt) {
62  Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node> > subMap = subMaps[tt];
63  Teuchos::ArrayView<const GlobalOrdinal> subMapGids = subMap->getLocalElementList();
64  gids.insert(gids.end(), subMapGids.begin(), subMapGids.end());
65  }
66 
67  const GlobalOrdinal INVALID = Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid();
68  // std::sort(gids.begin(), gids.end());
69  // gids.erase(std::unique(gids.begin(), gids.end()), gids.end());
70  Teuchos::ArrayView<GlobalOrdinal> gidsView(&gids[0], gids.size());
71  Teuchos::RCP<Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node> > fullMap = Xpetra::MapFactory<LocalOrdinal, GlobalOrdinal, Node>::Build(subMaps[0]->lib(), INVALID, gidsView, subMaps[0]->getIndexBase(), subMaps[0]->getComm());
72  return fullMap;
73  }
74 
90  static Teuchos::RCP<Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node> >
93  TEUCHOS_TEST_FOR_EXCEPTION(nonOvlInput.getLocalNumElements() > input.getLocalNumElements(),
95  "Xpetra::MatrixUtils::shrinkMapGIDs: the non-overlapping map must not have more local ids than the overlapping map.")
96 
97  TEUCHOS_TEST_FOR_EXCEPTION(nonOvlInput.getMaxAllGlobalIndex() != input.getMaxAllGlobalIndex(),
99  "Xpetra::MatrixUtils::shrinkMapGIDs: the maximum GIDs of the overlapping and non-overlapping maps must be the same.")
100 
101  RCP<const Teuchos::Comm<int> > comm = input.getComm();
102 
103  // we expect input to be the potentially overlapping map associated with nonOvlInput as the non-overlapping
104  // map with the same GIDs over all processors (e.g. column map and domain map). We use the nonOvlInput map
105  // to determine which GIDs are owned by which processor.
106 
107  // calculate offset for new global Ids
108  std::vector<int> myGIDs(comm->getSize(), 0);
109  std::vector<int> numGIDs(comm->getSize(), 0);
110  myGIDs[comm->getRank()] = nonOvlInput.getLocalNumElements();
111  Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, comm->getSize(), &myGIDs[0], &numGIDs[0]);
112  size_t gidOffset = 0;
113  for (int p = 0; p < comm->getRank(); p++) gidOffset += numGIDs[p];
114 
115  // we use nonOvlInput to assign the globally unique shrinked GIDs and communicate them to input.
116  std::map<const GlobalOrdinal, GlobalOrdinal> origGID2newGID;
117  for (size_t i = 0; i < nonOvlInput.getLocalNumElements(); i++) {
118  origGID2newGID[nonOvlInput.getGlobalElement(i)] = Teuchos::as<GlobalOrdinal>(i) + Teuchos::as<GlobalOrdinal>(gidOffset);
119  }
120  // build an overlapping version of mySpecialMap
121  Teuchos::Array<GlobalOrdinal> ovlUnknownStatusGids;
122  Teuchos::Array<GlobalOrdinal> ovlFoundStatusGids;
123  // loop over global column map of A and find all GIDs where it is not sure, whether they are special or not
124  for (size_t i = 0; i < input.getLocalNumElements(); i++) {
125  GlobalOrdinal gcid = input.getGlobalElement(i);
126  if (nonOvlInput.isNodeGlobalElement(gcid) == false) {
127  ovlUnknownStatusGids.push_back(gcid);
128  }
129  }
130 
131  // Communicate the number of DOFs on each processor
132  std::vector<int> myUnknownDofGIDs(comm->getSize(), 0);
133  std::vector<int> numUnknownDofGIDs(comm->getSize(), 0);
134  myUnknownDofGIDs[comm->getRank()] = ovlUnknownStatusGids.size();
135  Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, comm->getSize(), &myUnknownDofGIDs[0], &numUnknownDofGIDs[0]);
136 
137  // create array containing all DOF GIDs
138  size_t cntUnknownDofGIDs = 0;
139  for (int p = 0; p < comm->getSize(); p++) cntUnknownDofGIDs += numUnknownDofGIDs[p];
140  std::vector<GlobalOrdinal> lUnknownDofGIDs(cntUnknownDofGIDs, 0); // local version to be filled
141  std::vector<GlobalOrdinal> gUnknownDofGIDs(cntUnknownDofGIDs, 0); // global version after communication
142  // calculate the offset and fill chunk of memory with local data on each processor
143  size_t cntUnknownOffset = 0;
144  for (int p = 0; p < comm->getRank(); p++) cntUnknownOffset += numUnknownDofGIDs[p];
145  for (size_t k = 0; k < Teuchos::as<size_t>(ovlUnknownStatusGids.size()); k++) {
146  lUnknownDofGIDs[k + cntUnknownOffset] = ovlUnknownStatusGids[k];
147  }
148  if (cntUnknownDofGIDs > 0) // only perform communication if there are unknown DOF GIDs
149  Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, Teuchos::as<int>(cntUnknownDofGIDs), &lUnknownDofGIDs[0], &gUnknownDofGIDs[0]);
150  std::vector<GlobalOrdinal> lTranslatedDofGIDs(cntUnknownDofGIDs, 0); // local version to be filled
151  std::vector<GlobalOrdinal> gTranslatedDofGIDs(cntUnknownDofGIDs, 0); // global version after communication
152  // loop through all GIDs with unknown status
153  for (size_t k = 0; k < gUnknownDofGIDs.size(); k++) {
154  GlobalOrdinal curgid = gUnknownDofGIDs[k];
155  if (nonOvlInput.isNodeGlobalElement(curgid)) {
156  lTranslatedDofGIDs[k] = origGID2newGID[curgid]; // curgid is in special map (on this processor)
157  }
158  }
159  if (cntUnknownDofGIDs > 0) // only perform communication if there are unknown DOF GIDs
160  Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, Teuchos::as<int>(cntUnknownDofGIDs), &lTranslatedDofGIDs[0], &gTranslatedDofGIDs[0]);
161 
162  for (size_t k = 0; k < Teuchos::as<size_t>(ovlUnknownStatusGids.size()); k++) {
163  origGID2newGID[ovlUnknownStatusGids[k]] = gTranslatedDofGIDs[k + cntUnknownOffset];
164  }
165  Teuchos::Array<GlobalOrdinal> ovlDomainMapArray;
166  for (size_t i = 0; i < input.getLocalNumElements(); i++) {
167  GlobalOrdinal gcid = input.getGlobalElement(i);
168  ovlDomainMapArray.push_back(origGID2newGID[gcid]);
169  }
170  RCP<Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node> > ovlDomainMap =
171  Xpetra::MapFactory<LocalOrdinal, GlobalOrdinal, Node>::Build(nonOvlInput.lib(), Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(), ovlDomainMapArray(), 0, comm);
172  return ovlDomainMap;
173  }
174 
191  static Teuchos::RCP<Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node> > transformThyra2XpetraGIDs(
194  const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& nonOvlReferenceInput) {
195  // TEUCHOS_TEST_FOR_EXCEPTION(nonOvlInput.getLocalNumElements() > input.getLocalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::transformThyra2XpetraGIDs: the non-overlapping map must not have more local ids than the overlapping map.");
196  TEUCHOS_TEST_FOR_EXCEPTION(nonOvlInput.getLocalNumElements() != nonOvlReferenceInput.getLocalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::transformThyra2XpetraGIDs: the number of local Xpetra reference GIDs and local Thyra GIDs of the non-overlapping maps must be the same!");
197  // TEUCHOS_TEST_FOR_EXCEPTION(nonOvlInput.getMaxAllGlobalIndex() != input.getMaxAllGlobalIndex(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::transformThyra2XpetraGIDs: the maximum GIDs of the overlapping and non-overlapping maps must be the same. nonOvlInput.getMaxAllGlobalIndex() = " << nonOvlInput.getMaxAllGlobalIndex() << " ovlInput.getMaxAllGlobalIndex() = " << input.getMaxAllGlobalIndex());
198 
199  RCP<const Teuchos::Comm<int> > comm = input.getComm();
200 
201  // fill translation map as far as possible
202  std::map<const GlobalOrdinal, GlobalOrdinal> thyra2xpetraGID;
203  for (size_t i = 0; i < nonOvlInput.getLocalNumElements(); i++) {
204  thyra2xpetraGID[nonOvlInput.getGlobalElement(i)] =
205  nonOvlReferenceInput.getGlobalElement(i);
206  }
207 
208  // find all GIDs of the overlapping Thyra map which are not owned by this proc
209  Teuchos::Array<GlobalOrdinal> ovlUnknownStatusGids;
210  // loop over global column map of A and find all GIDs where it is not sure, whether they are special or not
211  for (size_t i = 0; i < input.getLocalNumElements(); i++) {
212  GlobalOrdinal gcid = input.getGlobalElement(i);
213  if (nonOvlInput.isNodeGlobalElement(gcid) == false) {
214  ovlUnknownStatusGids.push_back(gcid);
215  }
216  }
217 
218  // Communicate the number of DOFs on each processor
219  std::vector<int> myUnknownDofGIDs(comm->getSize(), 0);
220  std::vector<int> numUnknownDofGIDs(comm->getSize(), 0);
221  myUnknownDofGIDs[comm->getRank()] = ovlUnknownStatusGids.size();
222  Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, comm->getSize(), &myUnknownDofGIDs[0], &numUnknownDofGIDs[0]);
223 
224  // create array containing all DOF GIDs
225  size_t cntUnknownDofGIDs = 0;
226  for (int p = 0; p < comm->getSize(); p++) cntUnknownDofGIDs += numUnknownDofGIDs[p];
227  std::vector<GlobalOrdinal> lUnknownDofGIDs(cntUnknownDofGIDs, 0); // local version to be filled
228  std::vector<GlobalOrdinal> gUnknownDofGIDs(cntUnknownDofGIDs, 0); // global version after communication
229  // calculate the offset and fill chunk of memory with local data on each processor
230  size_t cntUnknownOffset = 0;
231  for (int p = 0; p < comm->getRank(); p++) cntUnknownOffset += numUnknownDofGIDs[p];
232  for (size_t k = 0; k < Teuchos::as<size_t>(ovlUnknownStatusGids.size()); k++) {
233  lUnknownDofGIDs[k + cntUnknownOffset] = ovlUnknownStatusGids[k];
234  }
235  if (cntUnknownDofGIDs > 0) // only perform communication if there are unknown DOF GIDs
236  Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, Teuchos::as<int>(cntUnknownDofGIDs), &lUnknownDofGIDs[0], &gUnknownDofGIDs[0]);
237  std::vector<GlobalOrdinal> lTranslatedDofGIDs(cntUnknownDofGIDs, 0); // local version to be filled
238  std::vector<GlobalOrdinal> gTranslatedDofGIDs(cntUnknownDofGIDs, 0); // global version after communication
239  // loop through all GIDs with unknown status
240  for (size_t k = 0; k < gUnknownDofGIDs.size(); k++) {
241  GlobalOrdinal curgid = gUnknownDofGIDs[k];
242  if (nonOvlInput.isNodeGlobalElement(curgid)) {
243  lTranslatedDofGIDs[k] = thyra2xpetraGID[curgid];
244  }
245  }
246  if (cntUnknownDofGIDs > 0) // only perform communication if there are unknown DOF GIDs
247  Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, Teuchos::as<int>(cntUnknownDofGIDs), &lTranslatedDofGIDs[0], &gTranslatedDofGIDs[0]);
248 
249  for (size_t k = 0; k < Teuchos::as<size_t>(ovlUnknownStatusGids.size()); k++) {
250  thyra2xpetraGID[ovlUnknownStatusGids[k]] = gTranslatedDofGIDs[k + cntUnknownOffset];
251  }
252  Teuchos::Array<GlobalOrdinal> ovlDomainMapArray;
253  for (size_t i = 0; i < input.getLocalNumElements(); i++) {
254  GlobalOrdinal gcid = input.getGlobalElement(i);
255  ovlDomainMapArray.push_back(thyra2xpetraGID[gcid]);
256  }
257  RCP<Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node> > ovlDomainMap =
258  Xpetra::MapFactory<LocalOrdinal, GlobalOrdinal, Node>::Build(nonOvlInput.lib(), Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(), ovlDomainMapArray(), 0, comm);
259 
260  TEUCHOS_TEST_FOR_EXCEPTION(input.getLocalNumElements() != ovlDomainMap->getLocalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::transformThyra2XpetraGIDs: the number of local Thyra reference GIDs (overlapping) and local Xpetra GIDs (overlapping) must be the same!");
261  // TEUCHOS_TEST_FOR_EXCEPTION(nonOvlReferenceInput.getMaxAllGlobalIndex() != ovlDomainMap->getMaxAllGlobalIndex(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::transformThyra2XpetraGIDs: the maximum GIDs of the overlapping and non-overlapping Xpetra maps must be the same.");
262 
263  return ovlDomainMap;
264  }
265 
272  static Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node> > transformThyra2XpetraGIDs(
273  const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& input, GlobalOrdinal offset) {
274  const GO INVALID = Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid();
275  RCP<const Teuchos::Comm<int> > comm = input.getComm();
276 
277  RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node> > rcpInput = Teuchos::rcpFromRef(input);
278 
279  // check whether input map is a BlockedMap or a standard Map
280  RCP<const Xpetra::BlockedMap<LocalOrdinal, GlobalOrdinal, Node> > rcpBlockedInput = Teuchos::rcp_dynamic_cast<const Xpetra::BlockedMap<LocalOrdinal, GlobalOrdinal, Node> >(rcpInput);
281  if (rcpBlockedInput.is_null() == true) {
282  // create a new map with Xpetra GIDs (may start not from GID = 0)
283  std::vector<GlobalOrdinal> gids;
284  for (LocalOrdinal l = 0; l < Teuchos::as<LocalOrdinal>(rcpInput->getLocalNumElements()); ++l) {
285  GlobalOrdinal gid = rcpInput->getGlobalElement(l) + offset;
286  gids.push_back(gid);
287  }
288  Teuchos::ArrayView<GO> gidsView(&gids[0], gids.size());
289  RCP<Map> fullMap = MapFactory::Build(rcpInput->lib(), INVALID, gidsView, rcpInput->getIndexBase(), comm);
290  return fullMap;
291  }
292 
293  // SPECIAL CASE: input is a blocked map
294  // we have to recursively call this routine to get a BlockedMap containing (unique) Xpetra style GIDs
295 
296  size_t numMaps = rcpBlockedInput->getNumMaps();
297 
298  // first calucale GID offsets in submaps
299  // we need that for generating Xpetra GIDs
300  std::vector<GlobalOrdinal> gidOffsets(numMaps, 0);
301  for (size_t i = 1; i < numMaps; ++i) {
302  gidOffsets[i] = rcpBlockedInput->getMap(i - 1, true)->getMaxAllGlobalIndex() + gidOffsets[i - 1] + 1;
303  }
304 
305  std::vector<RCP<const Map> > mapsXpetra(rcpBlockedInput->getNumMaps(), Teuchos::null);
306  std::vector<RCP<const Map> > mapsThyra(rcpBlockedInput->getNumMaps(), Teuchos::null);
307  for (size_t b = 0; b < rcpBlockedInput->getNumMaps(); ++b) {
308  // extract sub map with Thyra style gids
309  // this can be an underlying Map or BlockedMap object
310  RCP<const Map> subMapThyra = rcpBlockedInput->getMap(b, true);
311  RCP<const Map> subMapXpetra = MapUtils::transformThyra2XpetraGIDs(*subMapThyra, gidOffsets[b] + offset); // recursive call
312  mapsXpetra[b] = subMapXpetra; // map can be of type Map or BlockedMap
313  mapsThyra[b] = subMapThyra; // map can be of type Map or BlockedMap
314  }
315 
316  Teuchos::RCP<Map> resultMap = Teuchos::rcp(new Xpetra::BlockedMap<LocalOrdinal, GlobalOrdinal, Node>(mapsXpetra, mapsThyra));
317  return resultMap;
318  }
319 };
320 
321 } // end namespace Xpetra
322 
323 #define XPETRA_MAPUTILS_SHORT
324 
325 #endif // PACKAGES_XPETRA_SUP_MAP_UTILS_HPP_
virtual Teuchos::RCP< const Teuchos::Comm< int > > getComm() const =0
Get this Map&#39;s Comm object.
virtual size_t getLocalNumElements() const =0
The number of elements belonging to the calling process.
static Teuchos::RCP< const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > concatenateMaps(const std::vector< Teuchos::RCP< const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > > &subMaps)
Helper function to concatenate several maps.
virtual bool isNodeGlobalElement(GlobalOrdinal globalIndex) const =0
Whether the given global index is valid for this Map on this process.
static Teuchos::RCP< Map< LocalOrdinal, GlobalOrdinal, Node > > Build(UnderlyingLib lib, global_size_t numGlobalElements, GlobalOrdinal indexBase, const Teuchos::RCP< const Teuchos::Comm< int >> &comm, LocalGlobal lg=Xpetra::GloballyDistributed)
Map constructor with Xpetra-defined contiguous uniform distribution.
static Teuchos::RCP< Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > transformThyra2XpetraGIDs(const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &input, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &nonOvlInput, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &nonOvlReferenceInput)
replace set of global ids by new global ids
virtual GlobalOrdinal getMaxAllGlobalIndex() const =0
The maximum global index over all processes in the communicator.
virtual GlobalOrdinal getGlobalElement(LocalOrdinal localIndex) const =0
The global index corresponding to the given local index.
static Teuchos::RCP< Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > shrinkMapGIDs(const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &input, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &nonOvlInput)
Helper function to shrink the GIDs and generate a standard map whith GIDs starting at 0...
virtual GlobalOrdinal getGlobalElement(LocalOrdinal localIndex) const
The global index corresponding to the given local index.
Exception throws to report incompatible objects (like maps).
static Teuchos::RCP< const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > transformThyra2XpetraGIDs(const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &input, GlobalOrdinal offset)
replace set of global ids by new global ids
virtual UnderlyingLib lib() const =0
Get the library used by this object (Tpetra or Epetra?)