Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Tpetra_Directory_def.hpp
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 
10 #ifndef TPETRA_DIRECTORY_HPP
11 #define TPETRA_DIRECTORY_HPP
12 
13 #include "Tpetra_Distributor.hpp"
14 #include "Tpetra_Map.hpp"
15 #include "Tpetra_DirectoryImpl.hpp"
16 #include "Tpetra_Directory_decl.hpp"
17 
18 namespace Tpetra {
19 
20 template <class LO, class GO, class NT>
22  : impl_(NULL) {}
23 
24 template <class LO, class GO, class NT>
26  if (impl_ != NULL) {
27  delete impl_;
28  impl_ = NULL;
29  }
30 }
31 
32 template <class LO, class GO, class NT>
34  return impl_ != NULL;
35 }
36 
37 template <class LO, class GO, class NT>
39  initialize(const Map<LO, GO, NT>& map,
40  const Tpetra::Details::TieBreak<LO, GO>& tieBreak) {
41  if (initialized()) {
42  TEUCHOS_TEST_FOR_EXCEPTION(
43  impl_ == NULL, std::logic_error,
44  "Tpetra::Directory::initialize: "
45  "The Directory claims that it has been initialized, "
46  "but its implementation object has not yet been created. "
47  "Please report this bug to the Tpetra developers.");
48  } else {
49  TEUCHOS_TEST_FOR_EXCEPTION(
50  impl_ != NULL, std::logic_error,
51  "Tpetra::Directory::initialize: "
52  "Directory implementation has already been initialized, "
53  "but initialized() returns false. "
54  "Please report this bug to the Tpetra developers.");
55 
56  // Create an implementation object of the appropriate type,
57  // depending on whether the Map is distributed or replicated,
58  // and contiguous or noncontiguous.
59  //
60  // mfh 06 Apr 2014: When a distributed noncontiguous Directory
61  // takes a TieBreak, all the entries (local indices and process
62  // ranks) owned by the Directory on the calling process pass
63  // through the TieBreak object. This may have side effects,
64  // such as the TieBreak object remembering whether there were
65  // any duplicates on the calling process. We want to extend use
66  // of a TieBreak object to other kinds of Directories. For a
67  // distributed contiguous Directory, the calling process owns
68  // all of the (PID,LID) pairs in the input Map. For a locally
69  // replicated contiguous Directory, Process 0 owns all of the
70  // (PID,LID) pairs in the input Map.
71  //
72  // It may seem silly to pass in a TieBreak when there are no
73  // ties to break. However, the TieBreak object gets to see all
74  // (PID,LID) pairs that the Directory owns on the calling
75  // process, and interface of TieBreak allows side effects.
76  // Users may wish to exploit them regardless of the kind of Map
77  // they pass in.
78  const ::Tpetra::Details::Directory<LO, GO, NT>* dir = NULL;
79  bool usedTieBreak = false;
80  if (map.isDistributed()) {
81  if (map.isUniform()) {
82  dir = new ::Tpetra::Details::ContiguousUniformDirectory<LO, GO, NT>(map);
83  } else if (map.isContiguous()) {
84  dir = new ::Tpetra::Details::DistributedContiguousDirectory<LO, GO, NT>(map);
85  } else {
86  dir = new ::Tpetra::Details::DistributedNoncontiguousDirectory<LO, GO, NT>(map, tieBreak);
87  usedTieBreak = true;
88  }
89  } else {
90  dir = new ::Tpetra::Details::ReplicatedDirectory<LO, GO, NT>(map);
91 
92  if (tieBreak.mayHaveSideEffects() && map.getLocalNumElements() != 0) {
93  // We need the second clause in the above test because Map's
94  // interface provides an inclusive range of local indices.
95  const int myRank = map.getComm()->getRank();
96  // In a replicated Directory, Process 0 owns all the
97  // Directory's entries. This is an arbitrary assignment; any
98  // one process would do.
99  if (myRank == 0) {
100  std::vector<std::pair<int, LO> > pidLidList(1);
101  const LO minLocInd = map.getMinLocalIndex();
102  const LO maxLocInd = map.getMaxLocalIndex();
103  for (LO locInd = minLocInd; locInd <= maxLocInd; ++locInd) {
104  pidLidList[0] = std::make_pair(myRank, locInd);
105  const GO globInd = map.getGlobalElement(locInd);
106  // We don't care about the return value; we just want to
107  // invoke the side effects.
108  (void)tieBreak.selectedIndex(globInd, pidLidList);
109  }
110  }
111  }
112  usedTieBreak = true;
113  } // done with all different Map cases
114 
115  // If we haven't already used the TieBreak object, use it now.
116  // This code appears twice because ReplicatedDirectory is a
117  // special case: we already know what gets replicated.
118  if (!usedTieBreak && tieBreak.mayHaveSideEffects() &&
119  map.getLocalNumElements() != 0) {
120  // We need the third clause in the above test because Map's
121  // interface provides an inclusive range of local indices.
122  std::vector<std::pair<int, LO> > pidLidList(1);
123  const LO minLocInd = map.getMinLocalIndex();
124  const LO maxLocInd = map.getMaxLocalIndex();
125  const int myRank = map.getComm()->getRank();
126  for (LO locInd = minLocInd; locInd <= maxLocInd; ++locInd) {
127  pidLidList[0] = std::make_pair(myRank, locInd);
128  const GO globInd = map.getGlobalElement(locInd);
129  // We don't care about the return value; we just want to
130  // invoke the side effects.
131  (void)tieBreak.selectedIndex(globInd, pidLidList);
132  }
133  }
134 
135  impl_ = dir;
136  }
137 }
138 
139 template <class LO, class GO, class NT>
140 void Directory<LO, GO, NT>::initialize(const Map<LO, GO, NT>& map) {
141  if (initialized()) {
142  TEUCHOS_TEST_FOR_EXCEPTION(
143  impl_ == NULL, std::logic_error,
144  "Tpetra::Directory::initialize: "
145  "The Directory claims that it has been initialized, "
146  "but its implementation object has not yet been created. "
147  "Please report this bug to the Tpetra developers.");
148  } else {
149  TEUCHOS_TEST_FOR_EXCEPTION(
150  impl_ != NULL, std::logic_error,
151  "Tpetra::Directory::initialize: "
152  "Directory implementation has already been initialized, "
153  "but initialized() returns false. "
154  "Please report this bug to the Tpetra developers.");
155 
156  // Create an implementation object of the appropriate type,
157  // depending on whether the Map is distributed or replicated,
158  // and contiguous or noncontiguous.
159  const ::Tpetra::Details::Directory<LO, GO, NT>* dir = NULL;
160  if (map.isDistributed()) {
161  if (map.isUniform()) {
162  dir = new ::Tpetra::Details::ContiguousUniformDirectory<LO, GO, NT>(map);
163  } else if (map.isContiguous()) {
164  dir = new ::Tpetra::Details::DistributedContiguousDirectory<LO, GO, NT>(map);
165  } else {
166  dir = new ::Tpetra::Details::DistributedNoncontiguousDirectory<LO, GO, NT>(map);
167  }
168  } else {
169  dir = new ::Tpetra::Details::ReplicatedDirectory<LO, GO, NT>(map);
170  }
171  TEUCHOS_TEST_FOR_EXCEPTION(
172  dir == NULL, std::logic_error,
173  "Tpetra::Directory::initialize: "
174  "Failed to create Directory implementation. "
175  "Please report this bug to the Tpetra developers.");
176  impl_ = dir;
177  }
178 }
179 
180 template <class LO, class GO, class NT>
183  getDirectoryEntries(const Map<LO, GO, NT>& map,
184  const Teuchos::ArrayView<const GO>& globalIDs,
185  const Teuchos::ArrayView<int>& nodeIDs) const {
186  if (!initialized()) {
187  // This const_cast is super wrong, but "mutable" is also a lie,
188  // and Map's interface needs this method to be marked const for
189  // some reason.
190  const_cast<Directory<LO, GO, NT>*>(this)->initialize(map);
191  }
192  const bool computeLIDs = false;
193  return impl_->getEntries(map, globalIDs, nodeIDs, Teuchos::null, computeLIDs);
194 }
195 
196 template <class LO, class GO, class NT>
199  getDirectoryEntries(const Map<LO, GO, NT>& map,
200  const Teuchos::ArrayView<const GO>& globalIDs,
201  const Teuchos::ArrayView<int>& nodeIDs,
202  const Teuchos::ArrayView<LO>& localIDs) const {
203  if (!initialized()) {
204  // This const_cast is super wrong, but "mutable" is also a lie,
205  // and Map's interface needs this method to be marked const for
206  // some reason.
207  const_cast<Directory<LO, GO, NT>*>(this)->initialize(map);
208  }
209  const bool computeLIDs = true;
210  return impl_->getEntries(map, globalIDs, nodeIDs, localIDs, computeLIDs);
211 }
212 
213 template <class LO, class GO, class NT>
214 bool Directory<LO, GO, NT>::isOneToOne(const Map<LO, GO, NT>& map) const {
215  if (!initialized()) {
216  // This const_cast is super wrong, but "mutable" is also a lie,
217  // and Map's interface needs this method to be marked const for
218  // some reason.
219  const_cast<Directory<LO, GO, NT>*>(this)->initialize(map);
220  }
221  return impl_->isOneToOne(*(map.getComm()));
222 }
223 
224 template <class LO, class GO, class NT>
225 std::string
227  using Teuchos::TypeNameTraits;
228 
229  std::ostringstream os;
230  os << "Directory"
231  << "<" << TypeNameTraits<LO>::name()
232  << ", " << TypeNameTraits<GO>::name()
233  << ", " << TypeNameTraits<NT>::name() << ">";
234  return os.str();
235 }
236 
237 } // namespace Tpetra
238 
239 //
240 // Explicit instantiation macro
241 //
242 // Must be expanded from within the Tpetra namespace!
243 //
244 
245 #define TPETRA_DIRECTORY_INSTANT(LO, GO, NODE) \
246  template class Directory<LO, GO, NODE>;
247 
248 #endif // TPETRA_DIRECTORY_HPP
Interface for breaking ties in ownership.
void initialize(int *argc, char ***argv)
Initialize Tpetra.
bool isContiguous() const
True if this Map is distributed contiguously, else false.
LookupStatus
Return status of Map remote index lookup (getRemoteIndexList()).
size_t getLocalNumElements() const
The number of elements belonging to the calling process.
bool isUniform() const
Whether the range of global indices is uniform.
bool isDistributed() const
Whether this Map is globally distributed or locally replicated.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
local_ordinal_type getMinLocalIndex() const
The minimum local index.
global_ordinal_type getGlobalElement(local_ordinal_type localIndex) const
The global index corresponding to the given local index.
bool isOneToOne(const map_type &map) const
Whether the Directory&#39;s input Map is (globally) one to one.
local_ordinal_type getMaxLocalIndex() const
The maximum local index on the calling process.
LookupStatus getDirectoryEntries(const map_type &map, const Teuchos::ArrayView< const GlobalOrdinal > &globalIDs, const Teuchos::ArrayView< int > &nodeIDs) const
Given a global ID list, return the list of their owning process IDs.
virtual std::size_t selectedIndex(GlobalOrdinal GID, const std::vector< std::pair< int, LocalOrdinal > > &pid_and_lid) const =0
Break any ties in ownership of the given global index GID.
A parallel distribution of indices over processes.
bool initialized() const
Whether the Directory is initialized.
void initialize(const map_type &map)
Initialize the Directory with its Map.
Directory()
Default constructor: the only one you should use.
std::string description() const
A one-line human-readable description of this object.
virtual bool mayHaveSideEffects() const
Whether selectedIndex() may have side effects.