Tpetra parallel linear algebra  Version of the Day
Tpetra_Directory_def.hpp
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Tpetra: Templated Linear Algebra Services Package
5 // Copyright (2008) Sandia Corporation
6 //
7 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8 // the U.S. Government retains certain rights in this software.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ************************************************************************
40 // @HEADER
41 
42 #ifndef TPETRA_DIRECTORY_HPP
43 #define TPETRA_DIRECTORY_HPP
44 
45 #include "Tpetra_Distributor.hpp"
46 #include "Tpetra_Map.hpp"
47 #include "Tpetra_DirectoryImpl.hpp"
48 #include "Tpetra_Directory_decl.hpp"
49 
50 namespace Tpetra {
51 namespace Classes {
52 
53  template<class LO, class GO, class NT>
55  impl_ (NULL)
56  {}
57 
58  template<class LO, class GO, class NT>
60  if (impl_ != NULL) {
61  delete impl_;
62  impl_ = NULL;
63  }
64  }
65 
66  template<class LO, class GO, class NT>
67  bool
69  return impl_ != NULL;
70  }
71 
72 
73  template<class LO, class GO, class NT>
74  void
76  initialize (const Map<LO, GO, NT>& map,
77  const Tpetra::Details::TieBreak<LO,GO>& tieBreak)
78  {
79  if (initialized ()) {
80  TEUCHOS_TEST_FOR_EXCEPTION(
81  impl_ == NULL, std::logic_error, "Tpetra::Directory::initialize: "
82  "The Directory claims that it has been initialized, "
83  "but its implementation object has not yet been created. "
84  "Please report this bug to the Tpetra developers.");
85  }
86  else {
87  TEUCHOS_TEST_FOR_EXCEPTION(
88  impl_ != NULL, std::logic_error, "Tpetra::Directory::initialize: "
89  "Directory implementation has already been initialized, "
90  "but initialized() returns false. "
91  "Please report this bug to the Tpetra developers.");
92 
93  // Create an implementation object of the appropriate type,
94  // depending on whether the Map is distributed or replicated,
95  // and contiguous or noncontiguous.
96  //
97  // mfh 06 Apr 2014: When a distributed noncontiguous Directory
98  // takes a TieBreak, all the entries (local indices and process
99  // ranks) owned by the Directory on the calling process pass
100  // through the TieBreak object. This may have side effects,
101  // such as the TieBreak object remembering whether there were
102  // any duplicates on the calling process. We want to extend use
103  // of a TieBreak object to other kinds of Directories. For a
104  // distributed contiguous Directory, the calling process owns
105  // all of the (PID,LID) pairs in the input Map. For a locally
106  // replicated contiguous Directory, Process 0 owns all of the
107  // (PID,LID) pairs in the input Map.
108  //
109  // It may seem silly to pass in a TieBreak when there are no
110  // ties to break. However, the TieBreak object gets to see all
111  // (PID,LID) pairs that the Directory owns on the calling
112  // process, and interface of TieBreak allows side effects.
113  // Users may wish to exploit them regardless of the kind of Map
114  // they pass in.
115  const ::Tpetra::Details::Directory<LO, GO, NT>* dir = NULL;
116  bool usedTieBreak = false;
117  if (map.isDistributed ()) {
118  if (map.isUniform ()) {
119  dir = new ::Tpetra::Details::ContiguousUniformDirectory<LO, GO, NT> (map);
120  }
121  else if (map.isContiguous ()) {
122  dir = new ::Tpetra::Details::DistributedContiguousDirectory<LO, GO, NT> (map);
123  }
124  else {
125  dir = new ::Tpetra::Details::DistributedNoncontiguousDirectory<LO, GO, NT> (map, tieBreak);
126  usedTieBreak = true;
127  }
128  }
129  else {
130  dir = new ::Tpetra::Details::ReplicatedDirectory<LO, GO, NT> (map);
131 
132  if (tieBreak.mayHaveSideEffects () && map.getNodeNumElements () != 0) {
133  // We need the second clause in the above test because Map's
134  // interface provides an inclusive range of local indices.
135  const int myRank = map.getComm ()->getRank ();
136  // In a replicated Directory, Process 0 owns all the
137  // Directory's entries. This is an arbitrary assignment; any
138  // one process would do.
139  if (myRank == 0) {
140  std::vector<std::pair<int, LO> > pidLidList (1);
141  const LO minLocInd = map.getMinLocalIndex ();
142  const LO maxLocInd = map.getMaxLocalIndex ();
143  for (LO locInd = minLocInd; locInd <= maxLocInd; ++locInd) {
144  pidLidList[0] = std::make_pair (myRank, locInd);
145  const GO globInd = map.getGlobalElement (locInd);
146  // We don't care about the return value; we just want to
147  // invoke the side effects.
148  (void) tieBreak.selectedIndex (globInd, pidLidList);
149  }
150  }
151  }
152  usedTieBreak = true;
153  } // done with all different Map cases
154 
155  // If we haven't already used the TieBreak object, use it now.
156  // This code appears twice because ReplicatedDirectory is a
157  // special case: we already know what gets replicated.
158  if (! usedTieBreak && tieBreak.mayHaveSideEffects () &&
159  map.getNodeNumElements () != 0) {
160  // We need the third clause in the above test because Map's
161  // interface provides an inclusive range of local indices.
162  std::vector<std::pair<int, LO> > pidLidList (1);
163  const LO minLocInd = map.getMinLocalIndex ();
164  const LO maxLocInd = map.getMaxLocalIndex ();
165  const int myRank = map.getComm ()->getRank ();
166  for (LO locInd = minLocInd; locInd <= maxLocInd; ++locInd) {
167  pidLidList[0] = std::make_pair (myRank, locInd);
168  const GO globInd = map.getGlobalElement (locInd);
169  // We don't care about the return value; we just want to
170  // invoke the side effects.
171  (void) tieBreak.selectedIndex (globInd, pidLidList);
172  }
173  }
174 
175  impl_ = dir;
176  }
177  }
178 
179  template<class LO, class GO, class NT>
180  void
181  Directory<LO, GO, NT>::initialize (const Map<LO, GO, NT>& map)
182  {
183  if (initialized ()) {
184  TEUCHOS_TEST_FOR_EXCEPTION(
185  impl_ == NULL, std::logic_error, "Tpetra::Directory::initialize: "
186  "The Directory claims that it has been initialized, "
187  "but its implementation object has not yet been created. "
188  "Please report this bug to the Tpetra developers.");
189  }
190  else {
191  TEUCHOS_TEST_FOR_EXCEPTION(
192  impl_ != NULL, std::logic_error, "Tpetra::Directory::initialize: "
193  "Directory implementation has already been initialized, "
194  "but initialized() returns false. "
195  "Please report this bug to the Tpetra developers.");
196 
197  // Create an implementation object of the appropriate type,
198  // depending on whether the Map is distributed or replicated,
199  // and contiguous or noncontiguous.
200  const ::Tpetra::Details::Directory<LO, GO, NT>* dir = NULL;
201  if (map.isDistributed ()) {
202  if (map.isUniform ()) {
203  dir = new ::Tpetra::Details::ContiguousUniformDirectory<LO, GO, NT> (map);
204  }
205  else if (map.isContiguous ()) {
206  dir = new ::Tpetra::Details::DistributedContiguousDirectory<LO, GO, NT> (map);
207  }
208  else {
209  dir = new ::Tpetra::Details::DistributedNoncontiguousDirectory<LO, GO, NT> (map);
210  }
211  }
212  else {
213  dir = new ::Tpetra::Details::ReplicatedDirectory<LO, GO, NT> (map);
214  }
215  TEUCHOS_TEST_FOR_EXCEPTION(
216  dir == NULL, std::logic_error, "Tpetra::Directory::initialize: "
217  "Failed to create Directory implementation. "
218  "Please report this bug to the Tpetra developers.");
219  impl_ = dir;
220  }
221  }
222 
223  template<class LO, class GO, class NT>
226  getDirectoryEntries (const Map<LO, GO, NT>& map,
227  const Teuchos::ArrayView<const GO>& globalIDs,
228  const Teuchos::ArrayView<int>& nodeIDs) const
229  {
230  if (! initialized ()) {
231  // This const_cast is super wrong, but "mutable" is also a lie,
232  // and Map's interface needs this method to be marked const for
233  // some reason.
234  const_cast<Directory<LO, GO, NT>* > (this)->initialize (map);
235  }
236  const bool computeLIDs = false;
237  return impl_->getEntries (map, globalIDs, nodeIDs, Teuchos::null, computeLIDs);
238  }
239 
240  template<class LO, class GO, class NT>
243  getDirectoryEntries (const Map<LO, GO, NT>& map,
244  const Teuchos::ArrayView<const GO>& globalIDs,
245  const Teuchos::ArrayView<int>& nodeIDs,
246  const Teuchos::ArrayView<LO>& localIDs) const
247  {
248  if (! initialized ()) {
249  // This const_cast is super wrong, but "mutable" is also a lie,
250  // and Map's interface needs this method to be marked const for
251  // some reason.
252  const_cast<Directory<LO, GO, NT>* > (this)->initialize (map);
253  }
254  const bool computeLIDs = true;
255  return impl_->getEntries (map, globalIDs, nodeIDs, localIDs, computeLIDs);
256  }
257 
258  template<class LO, class GO, class NT>
259  bool Directory<LO, GO, NT>::isOneToOne (const Map<LO, GO, NT>& map) const {
260  if (! initialized ()) {
261  // This const_cast is super wrong, but "mutable" is also a lie,
262  // and Map's interface needs this method to be marked const for
263  // some reason.
264  const_cast<Directory<LO, GO, NT>* > (this)->initialize (map);
265  }
266  return impl_->isOneToOne (* (map.getComm ()));
267  }
268 
269  template<class LO, class GO, class NT>
270  std::string
272  {
273  using Teuchos::TypeNameTraits;
274 
275  std::ostringstream os;
276  os << "Directory"
277  << "<" << TypeNameTraits<LO>::name ()
278  << ", " << TypeNameTraits<GO>::name ()
279  << ", " << TypeNameTraits<NT>::name () << ">";
280  return os.str ();
281  }
282 
283 } // namespace Classes
284 } // namespace Tpetra
285 
286 //
287 // Explicit instantiation macro
288 //
289 // Must be expanded from within the Tpetra namespace!
290 //
291 
292 #define TPETRA_DIRECTORY_INSTANT(LO,GO,NODE) \
293  \
294  namespace Classes { \
295  template class Directory< LO , GO , NODE >; \
296  }
297 
298 #endif // TPETRA_DIRECTORY_HPP
Tpetra::Classes::Directory::getDirectoryEntries
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.
Tpetra::Classes::Directory::~Directory
~Directory()
Destructor.
Definition: Tpetra_Directory_def.hpp:59
Tpetra::Classes::Directory::initialize
void initialize(const map_type &map)
Initialize the Directory with its Map.
Tpetra::Classes::Directory::Directory
Directory()
Default constructor: the only one you should use.
Definition: Tpetra_Directory_def.hpp:54
Tpetra::Classes::Map::isDistributed
bool isDistributed() const
Whether this Map is globally distributed or locally replicated.
Definition: Tpetra_Map_def.hpp:1535
Tpetra::Classes::Map::getGlobalElement
GlobalOrdinal getGlobalElement(LocalOrdinal localIndex) const
The global index corresponding to the given local index.
Definition: Tpetra_Map_def.hpp:1114
Tpetra::Classes::Directory::description
std::string description() const
A one-line human-readable description of this object.
Definition: Tpetra_Directory_def.hpp:271
Tpetra::Classes::Map::isUniform
bool isUniform() const
Whether the range of global indices is uniform.
Definition: Tpetra_Map_def.hpp:1152
Tpetra::Details::Classes::TieBreak::mayHaveSideEffects
virtual bool mayHaveSideEffects() const
Whether selectedIndex() may have side effects.
Definition: Tpetra_TieBreak.hpp:99
Tpetra::initialize
void initialize(int *argc, char ***argv)
Initialize Tpetra.
Definition: Tpetra_Core.cpp:230
Tpetra::Classes::Directory::initialized
bool initialized() const
Whether the Directory is initialized.
Definition: Tpetra_Directory_def.hpp:68
Tpetra::Classes::Map::getMaxLocalIndex
LocalOrdinal getMaxLocalIndex() const
The maximum local index on the calling process.
Definition: Tpetra_Map_decl.hpp:610
Tpetra::LookupStatus
LookupStatus
Return status of Map remote index lookup (getRemoteIndexList()).
Definition: Tpetra_ConfigDefs.hpp:124
Tpetra::Details::Classes::TieBreak
Interface for breaking ties in ownership.
Definition: Tpetra_TieBreak.hpp:69
Tpetra::Classes::Map< LO, GO, NT >
Tpetra::Classes::Map::getComm
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
Definition: Tpetra_Map_def.hpp:1967
Tpetra::Classes::Map::getNodeNumElements
size_t getNodeNumElements() const
The number of elements belonging to the calling process.
Definition: Tpetra_Map_decl.hpp:578
Tpetra::Classes::Map::getMinLocalIndex
LocalOrdinal getMinLocalIndex() const
The minimum local index.
Definition: Tpetra_Map_decl.hpp:596
Tpetra
Namespace Tpetra contains the class and methods constituting the Tpetra library.
Tpetra::Classes::Map::isContiguous
bool isContiguous() const
True if this Map is distributed contiguously, else false.
Definition: Tpetra_Map_def.hpp:1157
Tpetra::Details::Classes::TieBreak::selectedIndex
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.
Tpetra::Classes::Directory::isOneToOne
bool isOneToOne(const map_type &map) const
Whether the Directory's input Map is (globally) one to one.