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 //
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.getLocalNumElements () != 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.getLocalNumElements () != 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.
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.