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
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>
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>
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
Namespace Tpetra contains the class and methods constituting the Tpetra library.
bool initialized() const
Whether the Directory is initialized.
LocalOrdinal getMinLocalIndex() const
The minimum local index.
LookupStatus
Return status of Map remote index lookup (getRemoteIndexList()).
LocalOrdinal getMaxLocalIndex() const
The maximum local index on the calling process.
GlobalOrdinal getGlobalElement(LocalOrdinal localIndex) const
The global index corresponding to the given local index.
size_t getNodeNumElements() const
The number of elements belonging to the calling process.
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.
void initialize(const map_type &map)
Initialize the Directory with its Map.
bool isOneToOne(const map_type &map) const
Whether the Directory&#39;s input Map is (globally) one to one.
bool isContiguous() const
True if this Map is distributed contiguously, else false.
Directory()
Default constructor: the only one you should use.
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.
Implement mapping from global ID to process ID and local ID.
std::string description() const
A one-line human-readable description of this object.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
bool isDistributed() const
Whether this Map is globally distributed or locally replicated.
virtual bool isOneToOne(const Teuchos::Comm< int > &comm) const =0
Whether the Directory&#39;s input Map is (globally) one to one.
virtual bool mayHaveSideEffects() const
Whether selectedIndex() may have side effects.
LookupStatus getEntries(const map_type &map, const Teuchos::ArrayView< const GlobalOrdinal > &globalIDs, const Teuchos::ArrayView< int > &nodeIDs, const Teuchos::ArrayView< LocalOrdinal > &localIDs, const bool computeLIDs) const
Interface for breaking ties in ownership.
bool isUniform() const
Whether the range of global indices is uniform.