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 
52  template<class LO, class GO, class NT>
54  impl_ (NULL)
55  {}
56 
57  template<class LO, class GO, class NT>
59  if (impl_ != NULL) {
60  delete impl_;
61  impl_ = NULL;
62  }
63  }
64 
65  template<class LO, class GO, class NT>
66  bool
68  return impl_ != NULL;
69  }
70 
71 
72  template<class LO, class GO, class NT>
73  void
75  initialize (const Map<LO, GO, NT>& map,
76  const Tpetra::Details::TieBreak<LO,GO>& tieBreak)
77  {
78  if (initialized ()) {
79  TEUCHOS_TEST_FOR_EXCEPTION(
80  impl_ == NULL, std::logic_error, "Tpetra::Directory::initialize: "
81  "The Directory claims that it has been initialized, "
82  "but its implementation object has not yet been created. "
83  "Please report this bug to the Tpetra developers.");
84  }
85  else {
86  TEUCHOS_TEST_FOR_EXCEPTION(
87  impl_ != NULL, std::logic_error, "Tpetra::Directory::initialize: "
88  "Directory implementation has already been initialized, "
89  "but initialized() returns false. "
90  "Please report this bug to the Tpetra developers.");
91 
92  // Create an implementation object of the appropriate type,
93  // depending on whether the Map is distributed or replicated,
94  // and contiguous or noncontiguous.
95  //
96  // mfh 06 Apr 2014: When a distributed noncontiguous Directory
97  // takes a TieBreak, all the entries (local indices and process
98  // ranks) owned by the Directory on the calling process pass
99  // through the TieBreak object. This may have side effects,
100  // such as the TieBreak object remembering whether there were
101  // any duplicates on the calling process. We want to extend use
102  // of a TieBreak object to other kinds of Directories. For a
103  // distributed contiguous Directory, the calling process owns
104  // all of the (PID,LID) pairs in the input Map. For a locally
105  // replicated contiguous Directory, Process 0 owns all of the
106  // (PID,LID) pairs in the input Map.
107  //
108  // It may seem silly to pass in a TieBreak when there are no
109  // ties to break. However, the TieBreak object gets to see all
110  // (PID,LID) pairs that the Directory owns on the calling
111  // process, and interface of TieBreak allows side effects.
112  // Users may wish to exploit them regardless of the kind of Map
113  // they pass in.
114  const ::Tpetra::Details::Directory<LO, GO, NT>* dir = NULL;
115  bool usedTieBreak = false;
116  if (map.isDistributed ()) {
117  if (map.isUniform ()) {
118  dir = new ::Tpetra::Details::ContiguousUniformDirectory<LO, GO, NT> (map);
119  }
120  else if (map.isContiguous ()) {
121  dir = new ::Tpetra::Details::DistributedContiguousDirectory<LO, GO, NT> (map);
122  }
123  else {
124  dir = new ::Tpetra::Details::DistributedNoncontiguousDirectory<LO, GO, NT> (map, tieBreak);
125  usedTieBreak = true;
126  }
127  }
128  else {
129  dir = new ::Tpetra::Details::ReplicatedDirectory<LO, GO, NT> (map);
130 
131  if (tieBreak.mayHaveSideEffects () && map.getNodeNumElements () != 0) {
132  // We need the second clause in the above test because Map's
133  // interface provides an inclusive range of local indices.
134  const int myRank = map.getComm ()->getRank ();
135  // In a replicated Directory, Process 0 owns all the
136  // Directory's entries. This is an arbitrary assignment; any
137  // one process would do.
138  if (myRank == 0) {
139  std::vector<std::pair<int, LO> > pidLidList (1);
140  const LO minLocInd = map.getMinLocalIndex ();
141  const LO maxLocInd = map.getMaxLocalIndex ();
142  for (LO locInd = minLocInd; locInd <= maxLocInd; ++locInd) {
143  pidLidList[0] = std::make_pair (myRank, locInd);
144  const GO globInd = map.getGlobalElement (locInd);
145  // We don't care about the return value; we just want to
146  // invoke the side effects.
147  (void) tieBreak.selectedIndex (globInd, pidLidList);
148  }
149  }
150  }
151  usedTieBreak = true;
152  } // done with all different Map cases
153 
154  // If we haven't already used the TieBreak object, use it now.
155  // This code appears twice because ReplicatedDirectory is a
156  // special case: we already know what gets replicated.
157  if (! usedTieBreak && tieBreak.mayHaveSideEffects () &&
158  map.getNodeNumElements () != 0) {
159  // We need the third clause in the above test because Map's
160  // interface provides an inclusive range of local indices.
161  std::vector<std::pair<int, LO> > pidLidList (1);
162  const LO minLocInd = map.getMinLocalIndex ();
163  const LO maxLocInd = map.getMaxLocalIndex ();
164  const int myRank = map.getComm ()->getRank ();
165  for (LO locInd = minLocInd; locInd <= maxLocInd; ++locInd) {
166  pidLidList[0] = std::make_pair (myRank, locInd);
167  const GO globInd = map.getGlobalElement (locInd);
168  // We don't care about the return value; we just want to
169  // invoke the side effects.
170  (void) tieBreak.selectedIndex (globInd, pidLidList);
171  }
172  }
173 
174  impl_ = dir;
175  }
176  }
177 
178  template<class LO, class GO, class NT>
179  void
180  Directory<LO, GO, NT>::initialize (const Map<LO, GO, NT>& map)
181  {
182  if (initialized ()) {
183  TEUCHOS_TEST_FOR_EXCEPTION(
184  impl_ == NULL, std::logic_error, "Tpetra::Directory::initialize: "
185  "The Directory claims that it has been initialized, "
186  "but its implementation object has not yet been created. "
187  "Please report this bug to the Tpetra developers.");
188  }
189  else {
190  TEUCHOS_TEST_FOR_EXCEPTION(
191  impl_ != NULL, std::logic_error, "Tpetra::Directory::initialize: "
192  "Directory implementation has already been initialized, "
193  "but initialized() returns false. "
194  "Please report this bug to the Tpetra developers.");
195 
196  // Create an implementation object of the appropriate type,
197  // depending on whether the Map is distributed or replicated,
198  // and contiguous or noncontiguous.
199  const ::Tpetra::Details::Directory<LO, GO, NT>* dir = NULL;
200  if (map.isDistributed ()) {
201  if (map.isUniform ()) {
202  dir = new ::Tpetra::Details::ContiguousUniformDirectory<LO, GO, NT> (map);
203  }
204  else if (map.isContiguous ()) {
205  dir = new ::Tpetra::Details::DistributedContiguousDirectory<LO, GO, NT> (map);
206  }
207  else {
208  dir = new ::Tpetra::Details::DistributedNoncontiguousDirectory<LO, GO, NT> (map);
209  }
210  }
211  else {
212  dir = new ::Tpetra::Details::ReplicatedDirectory<LO, GO, NT> (map);
213  }
214  TEUCHOS_TEST_FOR_EXCEPTION(
215  dir == NULL, std::logic_error, "Tpetra::Directory::initialize: "
216  "Failed to create Directory implementation. "
217  "Please report this bug to the Tpetra developers.");
218  impl_ = dir;
219  }
220  }
221 
222  template<class LO, class GO, class NT>
225  getDirectoryEntries (const Map<LO, GO, NT>& map,
226  const Teuchos::ArrayView<const GO>& globalIDs,
227  const Teuchos::ArrayView<int>& nodeIDs) const
228  {
229  if (! initialized ()) {
230  // This const_cast is super wrong, but "mutable" is also a lie,
231  // and Map's interface needs this method to be marked const for
232  // some reason.
233  const_cast<Directory<LO, GO, NT>* > (this)->initialize (map);
234  }
235  const bool computeLIDs = false;
236  return impl_->getEntries (map, globalIDs, nodeIDs, Teuchos::null, computeLIDs);
237  }
238 
239  template<class LO, class GO, class NT>
242  getDirectoryEntries (const Map<LO, GO, NT>& map,
243  const Teuchos::ArrayView<const GO>& globalIDs,
244  const Teuchos::ArrayView<int>& nodeIDs,
245  const Teuchos::ArrayView<LO>& localIDs) const
246  {
247  if (! initialized ()) {
248  // This const_cast is super wrong, but "mutable" is also a lie,
249  // and Map's interface needs this method to be marked const for
250  // some reason.
251  const_cast<Directory<LO, GO, NT>* > (this)->initialize (map);
252  }
253  const bool computeLIDs = true;
254  return impl_->getEntries (map, globalIDs, nodeIDs, localIDs, computeLIDs);
255  }
256 
257  template<class LO, class GO, class NT>
258  bool Directory<LO, GO, NT>::isOneToOne (const Map<LO, GO, NT>& map) const {
259  if (! initialized ()) {
260  // This const_cast is super wrong, but "mutable" is also a lie,
261  // and Map's interface needs this method to be marked const for
262  // some reason.
263  const_cast<Directory<LO, GO, NT>* > (this)->initialize (map);
264  }
265  return impl_->isOneToOne (* (map.getComm ()));
266  }
267 
268  template<class LO, class GO, class NT>
269  std::string
271  {
272  using Teuchos::TypeNameTraits;
273 
274  std::ostringstream os;
275  os << "Directory"
276  << "<" << TypeNameTraits<LO>::name ()
277  << ", " << TypeNameTraits<GO>::name ()
278  << ", " << TypeNameTraits<NT>::name () << ">";
279  return os.str ();
280  }
281 
282 } // namespace Tpetra
283 
284 //
285 // Explicit instantiation macro
286 //
287 // Must be expanded from within the Tpetra namespace!
288 //
289 
290 #define TPETRA_DIRECTORY_INSTANT(LO,GO,NODE) \
291  template class Directory< LO , GO , NODE >;
292 
293 #endif // TPETRA_DIRECTORY_HPP
Interface for breaking ties in ownership.
virtual bool mayHaveSideEffects() const
Whether selectedIndex() may have side effects.
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.
Implement mapping from global ID to process ID and local ID.
std::string description() const
A one-line human-readable description of this object.
bool isOneToOne(const map_type &map) const
Whether the Directory's input Map is (globally) one to one.
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.
void initialize(const map_type &map)
Initialize the Directory with its Map.
bool initialized() const
Whether the Directory is initialized.
bool isDistributed() const
Whether this Map is globally distributed or locally replicated.
global_ordinal_type getGlobalElement(local_ordinal_type localIndex) const
The global index corresponding to the given local index.
bool isUniform() const
Whether the range of global indices is uniform.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
bool isContiguous() const
True if this Map is distributed contiguously, else false.
local_ordinal_type getMinLocalIndex() const
The minimum local index.
size_t getNodeNumElements() const
The number of elements belonging to the calling process.
local_ordinal_type getMaxLocalIndex() const
The maximum local index on the calling process.
Namespace Tpetra contains the class and methods constituting the Tpetra library.
void initialize(int *argc, char ***argv)
Initialize Tpetra.
LookupStatus
Return status of Map remote index lookup (getRemoteIndexList()).