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 
25  template<class LO, class GO, class NT>
27  if (impl_ != NULL) {
28  delete impl_;
29  impl_ = NULL;
30  }
31  }
32 
33  template<class LO, class GO, class NT>
34  bool
36  return impl_ != NULL;
37  }
38 
39 
40  template<class LO, class GO, class NT>
41  void
43  initialize (const Map<LO, GO, NT>& map,
44  const Tpetra::Details::TieBreak<LO,GO>& tieBreak)
45  {
46  if (initialized ()) {
47  TEUCHOS_TEST_FOR_EXCEPTION(
48  impl_ == NULL, std::logic_error, "Tpetra::Directory::initialize: "
49  "The Directory claims that it has been initialized, "
50  "but its implementation object has not yet been created. "
51  "Please report this bug to the Tpetra developers.");
52  }
53  else {
54  TEUCHOS_TEST_FOR_EXCEPTION(
55  impl_ != NULL, std::logic_error, "Tpetra::Directory::initialize: "
56  "Directory implementation has already been initialized, "
57  "but initialized() returns false. "
58  "Please report this bug to the Tpetra developers.");
59 
60  // Create an implementation object of the appropriate type,
61  // depending on whether the Map is distributed or replicated,
62  // and contiguous or noncontiguous.
63  //
64  // mfh 06 Apr 2014: When a distributed noncontiguous Directory
65  // takes a TieBreak, all the entries (local indices and process
66  // ranks) owned by the Directory on the calling process pass
67  // through the TieBreak object. This may have side effects,
68  // such as the TieBreak object remembering whether there were
69  // any duplicates on the calling process. We want to extend use
70  // of a TieBreak object to other kinds of Directories. For a
71  // distributed contiguous Directory, the calling process owns
72  // all of the (PID,LID) pairs in the input Map. For a locally
73  // replicated contiguous Directory, Process 0 owns all of the
74  // (PID,LID) pairs in the input Map.
75  //
76  // It may seem silly to pass in a TieBreak when there are no
77  // ties to break. However, the TieBreak object gets to see all
78  // (PID,LID) pairs that the Directory owns on the calling
79  // process, and interface of TieBreak allows side effects.
80  // Users may wish to exploit them regardless of the kind of Map
81  // they pass in.
82  const ::Tpetra::Details::Directory<LO, GO, NT>* dir = NULL;
83  bool usedTieBreak = false;
84  if (map.isDistributed ()) {
85  if (map.isUniform ()) {
86  dir = new ::Tpetra::Details::ContiguousUniformDirectory<LO, GO, NT> (map);
87  }
88  else if (map.isContiguous ()) {
89  dir = new ::Tpetra::Details::DistributedContiguousDirectory<LO, GO, NT> (map);
90  }
91  else {
92  dir = new ::Tpetra::Details::DistributedNoncontiguousDirectory<LO, GO, NT> (map, tieBreak);
93  usedTieBreak = true;
94  }
95  }
96  else {
97  dir = new ::Tpetra::Details::ReplicatedDirectory<LO, GO, NT> (map);
98 
99  if (tieBreak.mayHaveSideEffects () && map.getLocalNumElements () != 0) {
100  // We need the second clause in the above test because Map's
101  // interface provides an inclusive range of local indices.
102  const int myRank = map.getComm ()->getRank ();
103  // In a replicated Directory, Process 0 owns all the
104  // Directory's entries. This is an arbitrary assignment; any
105  // one process would do.
106  if (myRank == 0) {
107  std::vector<std::pair<int, LO> > pidLidList (1);
108  const LO minLocInd = map.getMinLocalIndex ();
109  const LO maxLocInd = map.getMaxLocalIndex ();
110  for (LO locInd = minLocInd; locInd <= maxLocInd; ++locInd) {
111  pidLidList[0] = std::make_pair (myRank, locInd);
112  const GO globInd = map.getGlobalElement (locInd);
113  // We don't care about the return value; we just want to
114  // invoke the side effects.
115  (void) tieBreak.selectedIndex (globInd, pidLidList);
116  }
117  }
118  }
119  usedTieBreak = true;
120  } // done with all different Map cases
121 
122  // If we haven't already used the TieBreak object, use it now.
123  // This code appears twice because ReplicatedDirectory is a
124  // special case: we already know what gets replicated.
125  if (! usedTieBreak && tieBreak.mayHaveSideEffects () &&
126  map.getLocalNumElements () != 0) {
127  // We need the third clause in the above test because Map's
128  // interface provides an inclusive range of local indices.
129  std::vector<std::pair<int, LO> > pidLidList (1);
130  const LO minLocInd = map.getMinLocalIndex ();
131  const LO maxLocInd = map.getMaxLocalIndex ();
132  const int myRank = map.getComm ()->getRank ();
133  for (LO locInd = minLocInd; locInd <= maxLocInd; ++locInd) {
134  pidLidList[0] = std::make_pair (myRank, locInd);
135  const GO globInd = map.getGlobalElement (locInd);
136  // We don't care about the return value; we just want to
137  // invoke the side effects.
138  (void) tieBreak.selectedIndex (globInd, pidLidList);
139  }
140  }
141 
142  impl_ = dir;
143  }
144  }
145 
146  template<class LO, class GO, class NT>
147  void
148  Directory<LO, GO, NT>::initialize (const Map<LO, GO, NT>& map)
149  {
150  if (initialized ()) {
151  TEUCHOS_TEST_FOR_EXCEPTION(
152  impl_ == NULL, std::logic_error, "Tpetra::Directory::initialize: "
153  "The Directory claims that it has been initialized, "
154  "but its implementation object has not yet been created. "
155  "Please report this bug to the Tpetra developers.");
156  }
157  else {
158  TEUCHOS_TEST_FOR_EXCEPTION(
159  impl_ != NULL, std::logic_error, "Tpetra::Directory::initialize: "
160  "Directory implementation has already been initialized, "
161  "but initialized() returns false. "
162  "Please report this bug to the Tpetra developers.");
163 
164  // Create an implementation object of the appropriate type,
165  // depending on whether the Map is distributed or replicated,
166  // and contiguous or noncontiguous.
167  const ::Tpetra::Details::Directory<LO, GO, NT>* dir = NULL;
168  if (map.isDistributed ()) {
169  if (map.isUniform ()) {
170  dir = new ::Tpetra::Details::ContiguousUniformDirectory<LO, GO, NT> (map);
171  }
172  else if (map.isContiguous ()) {
173  dir = new ::Tpetra::Details::DistributedContiguousDirectory<LO, GO, NT> (map);
174  }
175  else {
176  dir = new ::Tpetra::Details::DistributedNoncontiguousDirectory<LO, GO, NT> (map);
177  }
178  }
179  else {
180  dir = new ::Tpetra::Details::ReplicatedDirectory<LO, GO, NT> (map);
181  }
182  TEUCHOS_TEST_FOR_EXCEPTION(
183  dir == NULL, std::logic_error, "Tpetra::Directory::initialize: "
184  "Failed to create Directory implementation. "
185  "Please report this bug to the Tpetra developers.");
186  impl_ = dir;
187  }
188  }
189 
190  template<class LO, class GO, class NT>
193  getDirectoryEntries (const Map<LO, GO, NT>& map,
194  const Teuchos::ArrayView<const GO>& globalIDs,
195  const Teuchos::ArrayView<int>& nodeIDs) const
196  {
197  if (! initialized ()) {
198  // This const_cast is super wrong, but "mutable" is also a lie,
199  // and Map's interface needs this method to be marked const for
200  // some reason.
201  const_cast<Directory<LO, GO, NT>* > (this)->initialize (map);
202  }
203  const bool computeLIDs = false;
204  return impl_->getEntries (map, globalIDs, nodeIDs, Teuchos::null, computeLIDs);
205  }
206 
207  template<class LO, class GO, class NT>
210  getDirectoryEntries (const Map<LO, GO, NT>& map,
211  const Teuchos::ArrayView<const GO>& globalIDs,
212  const Teuchos::ArrayView<int>& nodeIDs,
213  const Teuchos::ArrayView<LO>& localIDs) const
214  {
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  const bool computeLIDs = true;
222  return impl_->getEntries (map, globalIDs, nodeIDs, localIDs, computeLIDs);
223  }
224 
225  template<class LO, class GO, class NT>
226  bool Directory<LO, GO, NT>::isOneToOne (const Map<LO, GO, NT>& map) const {
227  if (! initialized ()) {
228  // This const_cast is super wrong, but "mutable" is also a lie,
229  // and Map's interface needs this method to be marked const for
230  // some reason.
231  const_cast<Directory<LO, GO, NT>* > (this)->initialize (map);
232  }
233  return impl_->isOneToOne (* (map.getComm ()));
234  }
235 
236  template<class LO, class GO, class NT>
237  std::string
239  {
240  using Teuchos::TypeNameTraits;
241 
242  std::ostringstream os;
243  os << "Directory"
244  << "<" << TypeNameTraits<LO>::name ()
245  << ", " << TypeNameTraits<GO>::name ()
246  << ", " << TypeNameTraits<NT>::name () << ">";
247  return os.str ();
248  }
249 
250 } // namespace Tpetra
251 
252 //
253 // Explicit instantiation macro
254 //
255 // Must be expanded from within the Tpetra namespace!
256 //
257 
258 #define TPETRA_DIRECTORY_INSTANT(LO,GO,NODE) \
259  template class Directory< LO , GO , NODE >;
260 
261 #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.