Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
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
50namespace Tpetra {
51
52 template<class LO, class GO, class NT>
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
77 {
78 if (initialized ()) {
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
Struct that holds views of the contents of a CrsMatrix.
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.
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()).