|
Tpetra Matrix/Vector Services
Version of the Day
|
00001 // @HEADER 00002 // *********************************************************************** 00003 // 00004 // Tpetra: Templated Linear Algebra Services Package 00005 // Copyright (2008) Sandia Corporation 00006 // 00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, 00008 // the U.S. Government retains certain rights in this software. 00009 // 00010 // Redistribution and use in source and binary forms, with or without 00011 // modification, are permitted provided that the following conditions are 00012 // met: 00013 // 00014 // 1. Redistributions of source code must retain the above copyright 00015 // notice, this list of conditions and the following disclaimer. 00016 // 00017 // 2. Redistributions in binary form must reproduce the above copyright 00018 // notice, this list of conditions and the following disclaimer in the 00019 // documentation and/or other materials provided with the distribution. 00020 // 00021 // 3. Neither the name of the Corporation nor the names of the 00022 // contributors may be used to endorse or promote products derived from 00023 // this software without specific prior written permission. 00024 // 00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00036 // 00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 00038 // 00039 // ************************************************************************ 00040 // @HEADER 00041 00042 #ifndef TPETRA_IMPORT_DEF_HPP 00043 #define TPETRA_IMPORT_DEF_HPP 00044 00045 #ifdef DOXYGEN_USE_ONLY 00046 # include <Tpetra_Import_decl.hpp> 00047 #endif // DOXYGEN_USE_ONLY 00048 00049 #include <Tpetra_Distributor.hpp> 00050 #include <Tpetra_Map.hpp> 00051 #include <Tpetra_ImportExportData.hpp> 00052 #include <Tpetra_Util.hpp> 00053 #include <Tpetra_Import_Util.hpp> 00054 #include <Tpetra_Export.hpp> 00055 #include <Teuchos_as.hpp> 00056 00057 00058 namespace { 00059 // Default value of Import's "Debug" parameter. 00060 const bool tpetraImportDebugDefault = false; 00061 } // namespace (anonymous) 00062 00063 namespace Tpetra { 00064 00065 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00066 void 00067 Import<LocalOrdinal,GlobalOrdinal,Node>:: 00068 setParameterList (const Teuchos::RCP<Teuchos::ParameterList>& plist) 00069 { 00070 bool debug = tpetraImportDebugDefault; 00071 if (! plist.is_null ()) { 00072 try { 00073 debug = plist->get<bool> ("Debug"); 00074 } catch (Teuchos::Exceptions::InvalidParameter&) {} 00075 } 00076 debug_ = debug; 00077 ImportData_->distributor_.setParameterList (plist); 00078 } 00079 00080 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00081 void 00082 Import<LocalOrdinal,GlobalOrdinal,Node>:: 00083 init (const Teuchos::RCP<const map_type>& source, 00084 const Teuchos::RCP<const map_type>& target, 00085 bool useRemotePIDs, 00086 Teuchos::Array<int> & remotePIDs, 00087 const Teuchos::RCP<Teuchos::ParameterList>& plist) 00088 { 00089 using Teuchos::null; 00090 using Teuchos::Ptr; 00091 using Teuchos::rcp; 00092 using std::endl; 00093 typedef ImportExportData<LocalOrdinal,GlobalOrdinal,Node> data_type; 00094 00095 // Read "Debug" parameter from the input ParameterList. 00096 bool debug = tpetraImportDebugDefault; 00097 if (! plist.is_null ()) { 00098 try { 00099 debug = plist->get<bool> ("Debug"); 00100 } catch (Teuchos::Exceptions::InvalidParameter&) {} 00101 } 00102 debug_ = debug; 00103 00104 if (! out_.is_null ()) { 00105 out_->pushTab (); 00106 } 00107 if (debug_) { 00108 std::ostringstream os; 00109 const int myRank = source->getComm ()->getRank (); 00110 os << myRank << ": Import ctor" << endl; 00111 *out_ << os.str (); 00112 } 00113 ImportData_ = rcp (new data_type (source, target, out_, plist)); 00114 00115 Array<GlobalOrdinal> remoteGIDs; 00116 setupSamePermuteRemote (remoteGIDs); 00117 if (debug_) { 00118 std::ostringstream os; 00119 const int myRank = source->getComm ()->getRank (); 00120 os << myRank << ": Import ctor: " 00121 << "setupSamePermuteRemote done" << endl; 00122 *out_ << os.str (); 00123 } 00124 if (source->isDistributed ()) { 00125 setupExport (remoteGIDs,useRemotePIDs,remotePIDs); 00126 } 00127 if (debug_) { 00128 std::ostringstream os; 00129 const int myRank = source->getComm ()->getRank (); 00130 os << myRank << ": Import ctor: done" << endl; 00131 *out_ << os.str (); 00132 } 00133 if (! out_.is_null ()) { 00134 out_->popTab (); 00135 } 00136 } 00137 00138 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00139 Import<LocalOrdinal,GlobalOrdinal,Node>:: 00140 Import (const RCP<const map_type >& source, 00141 const RCP<const map_type >& target) : 00142 out_ (Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr))), 00143 debug_ (tpetraImportDebugDefault) 00144 { 00145 Teuchos::Array<int> dummy; 00146 init (source, target, false, dummy, Teuchos::null); 00147 } 00148 00149 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00150 Import<LocalOrdinal,GlobalOrdinal,Node>:: 00151 Import (const RCP<const map_type >& source, 00152 const RCP<const map_type >& target, 00153 const RCP<Teuchos::FancyOStream>& out) : 00154 out_ (out), 00155 debug_ (tpetraImportDebugDefault) 00156 { 00157 Teuchos::Array<int> dummy; 00158 init (source, target, false, dummy, Teuchos::null); 00159 } 00160 00161 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00162 Import<LocalOrdinal,GlobalOrdinal,Node>:: 00163 Import (const Teuchos::RCP<const map_type >& source, 00164 const Teuchos::RCP<const map_type >& target, 00165 const Teuchos::RCP<Teuchos::ParameterList>& plist) : 00166 out_ (Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr))), 00167 debug_ (tpetraImportDebugDefault) 00168 { 00169 Teuchos::Array<int> dummy; 00170 init (source, target, false, dummy, plist); 00171 } 00172 00173 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00174 Import<LocalOrdinal,GlobalOrdinal,Node>:: 00175 Import (const Teuchos::RCP<const map_type >& source, 00176 const Teuchos::RCP<const map_type >& target, 00177 const RCP<Teuchos::FancyOStream>& out, 00178 const Teuchos::RCP<Teuchos::ParameterList>& plist) : 00179 out_ (out), 00180 debug_ (tpetraImportDebugDefault) 00181 { 00182 Teuchos::Array<int> dummy; 00183 init (source, target, false, dummy, plist); 00184 } 00185 00186 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00187 Import<LocalOrdinal,GlobalOrdinal,Node>:: 00188 Import (const Teuchos::RCP<const map_type >& source, 00189 const Teuchos::RCP<const map_type >& target, 00190 Teuchos::Array<int> & remotePIDs) : 00191 debug_ (tpetraImportDebugDefault) 00192 { 00193 init (source, target, true, remotePIDs, Teuchos::null); 00194 } 00195 00196 00197 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00198 Import<LocalOrdinal,GlobalOrdinal,Node>:: 00199 Import (const Import<LocalOrdinal,GlobalOrdinal,Node>& rhs) 00200 : ImportData_ (rhs.ImportData_) 00201 , out_ (rhs.out_) 00202 , debug_ (rhs.debug_) 00203 {} 00204 00205 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00206 Import<LocalOrdinal,GlobalOrdinal,Node>:: 00207 Import (const Export<LocalOrdinal,GlobalOrdinal,Node>& exporter) 00208 : out_ (exporter.out_) 00209 , debug_ (exporter.debug_) 00210 { 00211 if (! exporter.ExportData_.is_null ()) { 00212 ImportData_ = exporter.ExportData_->reverseClone (); 00213 } 00214 } 00215 00216 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00217 Import<LocalOrdinal,GlobalOrdinal,Node>:: 00218 Import (const Teuchos::RCP<const map_type>& source, 00219 const Teuchos::RCP<const map_type>& target, 00220 const size_t numSameIDs, 00221 Teuchos::Array<LocalOrdinal>& permuteToLIDs, 00222 Teuchos::Array<LocalOrdinal>& permuteFromLIDs, 00223 Teuchos::Array<LocalOrdinal>& remoteLIDs, 00224 Teuchos::Array<LocalOrdinal>& exportLIDs, 00225 Teuchos::Array<int>& exportPIDs, 00226 Distributor& distributor, 00227 const Teuchos::RCP<Teuchos::FancyOStream>& out, 00228 const Teuchos::RCP<Teuchos::ParameterList>& plist) : 00229 out_ (out.is_null () ? Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr)) : out), 00230 debug_ (tpetraImportDebugDefault) 00231 { 00232 using Teuchos::null; 00233 using Teuchos::Ptr; 00234 using Teuchos::rcp; 00235 using std::cerr; 00236 using std::endl; 00237 typedef ImportExportData<LocalOrdinal,GlobalOrdinal,Node> data_type; 00238 00239 // Read "Debug" parameter from the input ParameterList. 00240 bool debug = tpetraImportDebugDefault; 00241 if (! plist.is_null ()) { 00242 try { 00243 debug = plist->get<bool> ("Debug"); 00244 } catch (Teuchos::Exceptions::InvalidParameter&) {} 00245 } 00246 debug_ = debug; 00247 00248 if (! out_.is_null ()) { 00249 out_->pushTab (); 00250 } 00251 if (debug_ && ! out_.is_null ()) { 00252 std::ostringstream os; 00253 const int myRank = source->getComm ()->getRank (); 00254 os << myRank << ": Import expert ctor" << endl; 00255 *out_ << os.str (); 00256 } 00257 ImportData_ = rcp (new data_type (source, target, out_, plist)); 00258 00259 ImportData_->numSameIDs_ = numSameIDs; 00260 ImportData_->permuteToLIDs_.swap (permuteToLIDs); 00261 ImportData_->permuteFromLIDs_.swap (permuteFromLIDs); 00262 ImportData_->remoteLIDs_.swap (remoteLIDs); 00263 ImportData_->distributor_.swap (distributor); 00264 ImportData_->exportLIDs_.swap (exportLIDs); 00265 ImportData_->exportPIDs_.swap (exportPIDs); 00266 } 00267 00268 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00269 Import<LocalOrdinal,GlobalOrdinal,Node>::~Import() 00270 {} 00271 00272 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00273 size_t Import<LocalOrdinal,GlobalOrdinal,Node>::getNumSameIDs() const { 00274 return ImportData_->numSameIDs_; 00275 } 00276 00277 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00278 size_t Import<LocalOrdinal,GlobalOrdinal,Node>::getNumPermuteIDs() const { 00279 return ImportData_->permuteFromLIDs_.size(); 00280 } 00281 00282 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00283 ArrayView<const LocalOrdinal> 00284 Import<LocalOrdinal,GlobalOrdinal,Node>::getPermuteFromLIDs() const { 00285 return ImportData_->permuteFromLIDs_(); 00286 } 00287 00288 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00289 ArrayView<const LocalOrdinal> 00290 Import<LocalOrdinal,GlobalOrdinal,Node>::getPermuteToLIDs() const { 00291 return ImportData_->permuteToLIDs_(); 00292 } 00293 00294 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00295 size_t Import<LocalOrdinal,GlobalOrdinal,Node>::getNumRemoteIDs() const { 00296 return ImportData_->remoteLIDs_.size(); 00297 } 00298 00299 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00300 ArrayView<const LocalOrdinal> 00301 Import<LocalOrdinal,GlobalOrdinal,Node>::getRemoteLIDs() const { 00302 return ImportData_->remoteLIDs_(); 00303 } 00304 00305 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00306 size_t Import<LocalOrdinal,GlobalOrdinal,Node>::getNumExportIDs() const { 00307 return ImportData_->exportLIDs_.size(); 00308 } 00309 00310 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00311 ArrayView<const LocalOrdinal> 00312 Import<LocalOrdinal,GlobalOrdinal,Node>::getExportLIDs() const { 00313 return ImportData_->exportLIDs_(); 00314 } 00315 00316 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00317 ArrayView<const int> 00318 Import<LocalOrdinal,GlobalOrdinal,Node>::getExportPIDs() const { 00319 return ImportData_->exportPIDs_(); 00320 } 00321 00322 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00323 Teuchos::RCP<const typename Import<LocalOrdinal,GlobalOrdinal,Node>::map_type> 00324 Import<LocalOrdinal,GlobalOrdinal,Node>::getSourceMap() const { 00325 return ImportData_->source_; 00326 } 00327 00328 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00329 Teuchos::RCP<const typename Import<LocalOrdinal,GlobalOrdinal,Node>::map_type> 00330 Import<LocalOrdinal,GlobalOrdinal,Node>::getTargetMap() const { 00331 return ImportData_->target_; 00332 } 00333 00334 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00335 Distributor & 00336 Import<LocalOrdinal,GlobalOrdinal,Node>::getDistributor() const { 00337 return ImportData_->distributor_; 00338 } 00339 00340 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00341 Import<LocalOrdinal,GlobalOrdinal,Node>& 00342 Import<LocalOrdinal,GlobalOrdinal,Node>:: 00343 operator= (const Import<LocalOrdinal,GlobalOrdinal,Node>& rhs) { 00344 if (&rhs != this) { 00345 ImportData_ = rhs.ImportData_; 00346 } 00347 return *this; 00348 } 00349 00350 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00351 void Import<LocalOrdinal,GlobalOrdinal,Node>:: 00352 print (std::ostream& os) const 00353 { 00354 using Teuchos::Comm; 00355 using Teuchos::getFancyOStream; 00356 using Teuchos::RCP; 00357 using Teuchos::rcpFromRef; 00358 using Teuchos::toString; 00359 using std::endl; 00360 00361 RCP<const Comm<int> > comm = getSourceMap ()->getComm (); 00362 const int myImageID = comm->getRank (); 00363 const int numImages = comm->getSize (); 00364 for (int imageCtr = 0; imageCtr < numImages; ++imageCtr) { 00365 if (myImageID == imageCtr) { 00366 os << endl; 00367 if (myImageID == 0) { // I'm the root node (only output this info once) 00368 os << "Import Data Members:" << endl; 00369 } 00370 os << "Image ID : " << myImageID << endl; 00371 00372 os << "permuteFromLIDs: " << toString (getPermuteFromLIDs ()) << endl; 00373 os << "permuteToLIDs : " << toString (getPermuteToLIDs ()) << endl; 00374 os << "remoteLIDs : " << toString (getRemoteLIDs ()) << endl; 00375 os << "exportLIDs : " << toString (getExportLIDs ()) << endl; 00376 os << "exportPIDs : " << toString (getExportPIDs ()) << endl; 00377 00378 os << "numSameIDs : " << getNumSameIDs () << endl; 00379 os << "numPermuteIDs : " << getNumPermuteIDs () << endl; 00380 os << "numRemoteIDs : " << getNumRemoteIDs () << endl; 00381 os << "numExportIDs : " << getNumExportIDs () << endl; 00382 } 00383 // A few global barriers give output a chance to complete. 00384 comm->barrier(); 00385 comm->barrier(); 00386 comm->barrier(); 00387 } 00388 00389 const bool printMaps = false; 00390 if (printMaps) { 00391 if (myImageID == 0) { 00392 os << endl << endl << "Source Map:" << endl << std::flush; 00393 } 00394 comm->barrier(); 00395 os << *getSourceMap(); 00396 comm->barrier(); 00397 00398 if (myImageID == 0) { 00399 os << endl << endl << "Target Map:" << endl << std::flush; 00400 } 00401 comm->barrier(); 00402 os << *getTargetMap(); 00403 comm->barrier(); 00404 } 00405 00406 // It's also helpful for debugging to print the Distributor 00407 // object. Epetra_Import::Print() does this, so we can do a 00408 // side-by-side comparison. 00409 if (myImageID == 0) { 00410 os << endl << endl << "Distributor:" << endl << std::flush; 00411 } 00412 comm->barrier(); 00413 getDistributor().describe (*(getFancyOStream (rcpFromRef (os))), 00414 Teuchos::VERB_EXTREME); 00415 } 00416 00417 00418 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00419 void 00420 Import<LocalOrdinal,GlobalOrdinal,Node>:: 00421 setupSamePermuteRemote (Teuchos::Array<GlobalOrdinal>& remoteGIDs) 00422 { 00423 using Teuchos::arcp; 00424 using Teuchos::Array; 00425 using Teuchos::ArrayRCP; 00426 using Teuchos::ArrayView; 00427 using Teuchos::as; 00428 using Teuchos::null; 00429 typedef LocalOrdinal LO; 00430 typedef GlobalOrdinal GO; 00431 typedef typename ArrayView<const GO>::size_type size_type; 00432 const map_type& source = * (getSourceMap ()); 00433 const map_type& target = * (getTargetMap ()); 00434 ArrayView<const GO> sourceGIDs = source.getNodeElementList (); 00435 ArrayView<const GO> targetGIDs = target.getNodeElementList (); 00436 00437 #ifdef HAVE_TPETRA_DEBUG 00438 ArrayView<const GO> rawSrcGids = sourceGIDs; 00439 ArrayView<const GO> rawTgtGids = targetGIDs; 00440 #else 00441 const GO* const rawSrcGids = sourceGIDs.getRawPtr (); 00442 const GO* const rawTgtGids = targetGIDs.getRawPtr (); 00443 #endif // HAVE_TPETRA_DEBUG 00444 const size_type numSrcGids = sourceGIDs.size (); 00445 const size_type numTgtGids = targetGIDs.size (); 00446 const size_type numGids = std::min (numSrcGids, numTgtGids); 00447 00448 // Compute numSameIDs_: the number of initial GIDs that are the 00449 // same (and occur in the same order) in both Maps. The point of 00450 // numSameIDs_ is for the common case of an Import where all the 00451 // overlapping GIDs are at the end of the target Map, but 00452 // otherwise the source and target Maps are the same. This allows 00453 // a fast contiguous copy for the initial "same IDs." 00454 size_type numSameGids = 0; 00455 for ( ; numSameGids < numGids && rawSrcGids[numSameGids] == rawTgtGids[numSameGids]; ++numSameGids) 00456 {} // third clause of 'for' does everything 00457 ImportData_->numSameIDs_ = numSameGids; 00458 00459 // Compute permuteToLIDs_, permuteFromLIDs_, remoteGIDs, and 00460 // remoteLIDs_. The first two arrays are IDs to be permuted, and 00461 // the latter two arrays are IDs to be received ("imported"), 00462 // called "remote" IDs. 00463 // 00464 // IDs to permute are in both the source and target Maps, which 00465 // means we don't have to send or receive them, but we do have to 00466 // rearrange (permute) them in general. IDs to receive are in the 00467 // target Map, but not the source Map. 00468 00469 Array<LO>& permuteToLIDs = ImportData_->permuteToLIDs_; 00470 Array<LO>& permuteFromLIDs = ImportData_->permuteFromLIDs_; 00471 Array<LO>& remoteLIDs = ImportData_->remoteLIDs_; 00472 const LO LINVALID = Teuchos::OrdinalTraits<LO>::invalid (); 00473 const LO numTgtLids = as<LO> (numTgtGids); 00474 // Iterate over the target Map's LIDs, since we only need to do 00475 // GID -> LID lookups for the source Map. 00476 for (LO tgtLid = numSameGids; tgtLid < numTgtLids; ++tgtLid) { 00477 const GO curTargetGid = rawTgtGids[tgtLid]; 00478 // getLocalElement() returns LINVALID if the GID isn't in the source Map. 00479 // This saves us a lookup (which isNodeGlobalElement() would do). 00480 const LO srcLid = source.getLocalElement (curTargetGid); 00481 if (srcLid != LINVALID) { // if source.isNodeGlobalElement (curTargetGid) 00482 permuteToLIDs.push_back (tgtLid); 00483 permuteFromLIDs.push_back (srcLid); 00484 } else { 00485 remoteGIDs.push_back (curTargetGid); 00486 remoteLIDs.push_back (tgtLid); 00487 } 00488 } 00489 00490 TPETRA_ABUSE_WARNING( 00491 getNumRemoteIDs() > 0 && ! source.isDistributed(), 00492 std::runtime_error, 00493 "::setupSamePermuteRemote(): Target has remote LIDs but Source is not " 00494 "distributed globally." << std::endl 00495 << "Importing to a submap of the target map."); 00496 } 00497 00498 00499 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00500 void Import<LocalOrdinal,GlobalOrdinal,Node>:: 00501 setupExport (Teuchos::Array<GlobalOrdinal>& remoteGIDs, 00502 bool useRemotePIDs, 00503 Teuchos::Array<int>& userRemotePIDs) 00504 { 00505 using Teuchos::arcp; 00506 using Teuchos::Array; 00507 using Teuchos::ArrayRCP; 00508 using Teuchos::ArrayView; 00509 using Teuchos::null; 00510 using std::endl; 00511 typedef LocalOrdinal LO; 00512 typedef GlobalOrdinal GO; 00513 typedef typename Array<int>::difference_type size_type; 00514 00515 TEUCHOS_TEST_FOR_EXCEPTION( 00516 getSourceMap ().is_null (), std::logic_error, "Tpetra::Import::" 00517 "setupExport: Source Map is null. Please report this bug to the Tpetra " 00518 "developers."); 00519 const map_type& source = * (getSourceMap ()); 00520 00521 Teuchos::OSTab tab (out_); 00522 00523 // if (debug_ && ! out_.is_null ()) { 00524 // std::ostringstream os; 00525 // const int myRank = source.getComm ()->getRank (); 00526 // os << myRank << ": Import::setupExport:" << endl; 00527 // } 00528 00529 // Sanity checks 00530 TEUCHOS_TEST_FOR_EXCEPTION( 00531 ! useRemotePIDs && (userRemotePIDs.size() > 0), std::invalid_argument, 00532 "Tpetra::Import::setupExport: remotePIDs are non-empty but their use has " 00533 "not been requested."); 00534 TEUCHOS_TEST_FOR_EXCEPTION( 00535 userRemotePIDs.size () > 0 && remoteGIDs.size () != userRemotePIDs.size (), 00536 std::invalid_argument, "Tpetra::Import::setupExport: remotePIDs must " 00537 "either be of size zero or match the size of remoteGIDs."); 00538 00539 // For each entry remoteGIDs[i], remoteProcIDs[i] will contain 00540 // the process ID of the process that owns that GID. 00541 ArrayView<GO> remoteGIDsView = remoteGIDs (); 00542 ArrayView<int> remoteProcIDsView; 00543 00544 // lookup == IDNotPresent means that the source Map wasn't able to 00545 // figure out to which processes one or more of the GIDs in the 00546 // given list of remote GIDs belong. 00547 // 00548 // The previous abuse warning said "The target Map has GIDs not 00549 // found in the source Map." This statement could be confusing, 00550 // because it doesn't refer to ownership by the current process, 00551 // but rather to ownership by _any_ process participating in the 00552 // Map. (It could not possibly refer to ownership by the current 00553 // process, since remoteGIDs is exactly the list of GIDs owned by 00554 // the target Map but not owned by the source Map. It was 00555 // constructed that way by setupSamePermuteRemote().) 00556 // 00557 // What this statement means is that the source and target Maps 00558 // don't contain the same set of GIDs globally (over all 00559 // processes). That is, there is at least one GID owned by some 00560 // process in the target Map, which is not owned by _any_ process 00561 // in the source Map. 00562 Array<int> newRemotePIDs; 00563 LookupStatus lookup = AllIDsPresent; 00564 00565 if (! useRemotePIDs) { 00566 newRemotePIDs.resize (remoteGIDsView.size ()); 00567 if (debug_ && ! out_.is_null ()) { 00568 std::ostringstream os; 00569 const int myRank = source.getComm ()->getRank (); 00570 os << myRank << ": Import::setupExport: about to call " 00571 "getRemoteIndexList on source Map" << endl; 00572 *out_ << os.str (); 00573 } 00574 lookup = source.getRemoteIndexList (remoteGIDsView, newRemotePIDs ()); 00575 } 00576 Array<int>& remoteProcIDs = useRemotePIDs ? userRemotePIDs : newRemotePIDs; 00577 00578 TPETRA_ABUSE_WARNING( lookup == IDNotPresent, std::runtime_error, 00579 "::setupExport(): the source Map wasn't able to figure out which process " 00580 "owns one or more of the GIDs in the list of remote GIDs. This probably " 00581 "means that there is at least one GID owned by some process in the target" 00582 " Map which is not owned by any process in the source Map. (That is, the" 00583 " source and target Maps do not contain the same set of GIDs globally.)"); 00584 00585 // Ignore remote GIDs that aren't owned by any process in the 00586 // source Map. getRemoteIndexList() gives each of these a process 00587 // ID of -1. 00588 if (lookup == IDNotPresent) { 00589 const size_type numInvalidRemote = 00590 std::count_if (remoteProcIDs.begin (), remoteProcIDs.end (), 00591 std::bind1st (std::equal_to<int> (), -1)); 00592 // If all of them are invalid, we can delete the whole array. 00593 const size_type totalNumRemote = getNumRemoteIDs (); 00594 if (numInvalidRemote == totalNumRemote) { 00595 // all remotes are invalid; we have no remotes; we can delete the remotes 00596 remoteProcIDs.clear (); 00597 remoteGIDs.clear (); // This invalidates the view remoteGIDsView 00598 ImportData_->remoteLIDs_.clear(); 00599 } 00600 else { 00601 // Some remotes are valid; we need to keep the valid ones. 00602 // Pack and resize remoteProcIDs, remoteGIDs, and remoteLIDs_. 00603 size_type numValidRemote = 0; 00604 #ifdef HAVE_TPETRA_DEBUG 00605 ArrayView<GlobalOrdinal> remoteGIDsPtr = remoteGIDsView; 00606 #else 00607 GlobalOrdinal* const remoteGIDsPtr = remoteGIDsView.getRawPtr (); 00608 #endif // HAVE_TPETRA_DEBUG 00609 for (size_type r = 0; r < totalNumRemote; ++r) { 00610 // Pack in all the valid remote PIDs and GIDs. 00611 if (remoteProcIDs[r] != -1) { 00612 remoteProcIDs[numValidRemote] = remoteProcIDs[r]; 00613 remoteGIDsPtr[numValidRemote] = remoteGIDsPtr[r]; 00614 ImportData_->remoteLIDs_[numValidRemote] = ImportData_->remoteLIDs_[r]; 00615 ++numValidRemote; 00616 } 00617 } 00618 TEUCHOS_TEST_FOR_EXCEPTION( 00619 numValidRemote != totalNumRemote - numInvalidRemote, std::logic_error, 00620 "Tpetra::Import::setupExport(): After removing invalid remote GIDs and" 00621 " packing the valid remote GIDs, numValidRemote = " << numValidRemote 00622 << " != totalNumRemote - numInvalidRemote = " 00623 << totalNumRemote - numInvalidRemote 00624 << ". Please report this bug to the Tpetra developers."); 00625 00626 remoteProcIDs.resize (numValidRemote); 00627 remoteGIDs.resize (numValidRemote); 00628 ImportData_->remoteLIDs_.resize (numValidRemote); 00629 } 00630 // Revalidate the view after clear or resize. 00631 remoteGIDsView = remoteGIDs (); 00632 } 00633 00634 // Sort remoteProcIDs in ascending order, and apply the resulting 00635 // permutation to remoteGIDs and remoteLIDs_. This ensures that 00636 // remoteProcIDs[i], remoteGIDs[i], and remoteLIDs_[i] all refer 00637 // to the same thing. 00638 sort3 (remoteProcIDs.begin (), 00639 remoteProcIDs.end (), 00640 remoteGIDsView.begin (), 00641 ImportData_->remoteLIDs_.begin ()); 00642 00643 // Call the Distributor's createFromRecvs() method to turn the 00644 // remote GIDs and their owning processes into a send-and-receive 00645 // communication plan. remoteGIDs and remoteProcIDs_ are input; 00646 // exportGIDs and exportProcIDs_ are output arrays which are 00647 // allocated by createFromRecvs(). 00648 Array<GO> exportGIDs; 00649 ImportData_->distributor_.createFromRecvs (remoteGIDsView ().getConst (), 00650 remoteProcIDs, exportGIDs, 00651 ImportData_->exportPIDs_); 00652 // if (debug_ && ! out_.is_null ()) { 00653 // std::ostringstream os; 00654 // const int myRank = source.getComm ()->getRank (); 00655 // os << myRank << ": Import::setupExport: Getting LIDs" << endl; 00656 // *out_ << os.str (); 00657 // } 00658 00659 // Find the LIDs corresponding to the (outgoing) GIDs in 00660 // exportGIDs. For sparse matrix-vector multiply, this tells the 00661 // calling process how to index into the source vector to get the 00662 // elements which it needs to send. 00663 // 00664 // NOTE (mfh 03 Mar 2014) This is now a candidate for a 00665 // thread-parallel kernel, but only if using the new thread-safe 00666 // Map implementation. 00667 const size_type numExportIDs = exportGIDs.size (); 00668 if (numExportIDs > 0) { 00669 ImportData_->exportLIDs_.resize (numExportIDs); 00670 ArrayView<const GO> expGIDs = exportGIDs (); 00671 ArrayView<LO> expLIDs = ImportData_->exportLIDs_ (); 00672 for (size_type k = 0; k < numExportIDs; ++k) { 00673 expLIDs[k] = source.getLocalElement (expGIDs[k]); 00674 } 00675 } 00676 00677 if (debug_ && ! out_.is_null ()) { 00678 std::ostringstream os; 00679 const int myRank = source.getComm ()->getRank (); 00680 os << myRank << ": Import::setupExport: done" << endl; 00681 *out_ << os.str (); 00682 } 00683 } 00684 00685 00686 template <class LocalOrdinal, class GlobalOrdinal, class Node> 00687 Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node> > 00688 Import<LocalOrdinal,GlobalOrdinal,Node>:: 00689 setUnion (const Import<LocalOrdinal, GlobalOrdinal, Node>& rhs) const 00690 { 00691 typedef Tpetra::global_size_t GST; 00692 using Teuchos::Array; 00693 using Teuchos::ArrayView; 00694 using Teuchos::as; 00695 using Teuchos::Comm; 00696 using Teuchos::RCP; 00697 using Teuchos::rcp; 00698 using Teuchos::outArg; 00699 using Teuchos::REDUCE_MIN; 00700 using Teuchos::reduceAll; 00701 typedef LocalOrdinal LO; 00702 typedef GlobalOrdinal GO; 00703 typedef Import<LO, GO, Node> import_type; 00704 typedef typename Array<GO>::size_type size_type; 00705 00706 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00707 using Teuchos::toString; 00708 using std::cerr; 00709 using std::endl; 00710 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00711 00712 RCP<const map_type> srcMap = this->getSourceMap (); 00713 RCP<const map_type> tgtMap1 = this->getTargetMap (); 00714 RCP<const map_type> tgtMap2 = rhs.getTargetMap (); 00715 RCP<const Comm<int> > comm = srcMap->getComm (); 00716 00717 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00718 const int myRank = comm->getRank (); 00719 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00720 00721 #ifdef HAVE_TPETRA_DEBUG 00722 TEUCHOS_TEST_FOR_EXCEPTION( 00723 ! srcMap->isSameAs (* (rhs.getSourceMap ())), std::invalid_argument, 00724 "Tpetra::Import::setUnion: The source Map of the input Import must be the " 00725 "same as (in the sense of Map::isSameAs) the source Map of this Import."); 00726 TEUCHOS_TEST_FOR_EXCEPTION( 00727 ! Details::congruent (* (tgtMap1->getComm ()), * (tgtMap2->getComm ())), 00728 std::invalid_argument, "Tpetra::Import::setUnion: " 00729 "The target Maps must have congruent communicators."); 00730 #endif // HAVE_TPETRA_DEBUG 00731 00732 // It's probably worth the one all-reduce to check whether the two 00733 // Maps are the same. If so, we can just return a copy of *this. 00734 // isSameAs() bypasses the all-reduce if the pointers are equal. 00735 if (tgtMap1->isSameAs (*tgtMap2)) { 00736 return rcp (new import_type (*this)); 00737 } 00738 // Alas, the two target Maps are not the same. That means we have 00739 // to compute their union, and the union Import object. 00740 00741 ArrayView<const GO> srcGIDs = srcMap->getNodeElementList (); 00742 ArrayView<const GO> tgtGIDs1 = tgtMap1->getNodeElementList (); 00743 ArrayView<const GO> tgtGIDs2 = tgtMap2->getNodeElementList (); 00744 00745 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00746 comm->barrier (); 00747 { 00748 std::ostringstream os; 00749 os << myRank << ": srcGIDs: " << toString (srcGIDs) << endl; 00750 os << myRank << ": tgtGIDs1: " << toString (tgtGIDs1) << endl; 00751 os << myRank << ": tgtGIDs2: " << toString (tgtGIDs2) << endl; 00752 cerr << os.str (); 00753 } 00754 comm->barrier (); 00755 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00756 00757 00758 // Fill this as we go with the union target Map's GIDs, in the 00759 // desired order. We'll need them for the Map constructor. 00760 Array<GO> unionTgtGIDs; 00761 // Upper bound on the number of union target Map GIDs. This 00762 // happens to be strict, but doesn't have to be. Setting some 00763 // reasonable upper bound avoids reallocation in loops that do 00764 // push_back operations. 00765 unionTgtGIDs.reserve (tgtGIDs1.size () + tgtGIDs2.size ()); 00766 00767 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00768 if (myRank == 0) { 00769 cerr << endl; 00770 } 00771 comm->barrier (); 00772 comm->barrier (); 00773 comm->barrier (); 00774 cerr << myRank << ": Computing \"same\" GIDs" << endl; 00775 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00776 00777 // Compute the initial sequence of "same" GIDs in the union 00778 // import. The number of "same" GIDs in the union is the maximum 00779 // of the lengths of this in the two inputs. 00780 00781 const size_type numSameGIDs1 = this->getNumSameIDs (); 00782 const size_type numSameGIDs2 = rhs.getNumSameIDs (); 00783 ArrayView<const GO> sameGIDs1 = tgtGIDs1 (0, numSameGIDs1); 00784 ArrayView<const GO> sameGIDs2 = tgtGIDs2 (0, numSameGIDs2); 00785 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00786 { 00787 std::ostringstream os; 00788 os << myRank << ": same IDs for target Map 1: " << toString (sameGIDs1) << endl; 00789 os << myRank << ": same IDs for target Map 2: " << toString (sameGIDs2) << endl; 00790 cerr << os.str (); 00791 } 00792 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00793 // For the input target Map with fewer "same" GIDs, that Map's 00794 // permute IDs could include some of the other input target Map's 00795 // "same" GIDs. We have to make sure not to include them twice. 00796 // To do so, keep a view of them for now, and remove them (via set 00797 // intersection) from the permute ID list. Keeping track of which 00798 // GID set had the max number of "same" IDs avoids unnecessary set 00799 // intersection operations later. 00800 ArrayView<const GO> doubleCountedSameGIDs; 00801 size_type numSameIDsUnion; 00802 bool tgtMap1HadMaxSameGIDs; 00803 if (numSameGIDs1 >= numSameGIDs2) { 00804 tgtMap1HadMaxSameGIDs = true; 00805 numSameIDsUnion = numSameGIDs1; 00806 std::copy (sameGIDs1.begin (), sameGIDs1.end (), std::back_inserter (unionTgtGIDs)); 00807 // There could be GIDs in target Map 2 that are not included in 00808 // the "same" IDs, but are included in Import 2's permute IDs. 00809 // Keep track of them so we don't double-count them when 00810 // building the list of permute IDs. 00811 doubleCountedSameGIDs = tgtGIDs1 (numSameGIDs2, numSameGIDs1 - numSameGIDs2); 00812 } else { 00813 tgtMap1HadMaxSameGIDs = false; 00814 numSameIDsUnion = numSameGIDs2; 00815 std::copy (sameGIDs2.begin (), sameGIDs2.end (), std::back_inserter (unionTgtGIDs)); 00816 // There could be GIDs in target Map 1 that are not included in 00817 // the "same" IDs, but are included in Import 1's permute IDs. 00818 // Keep track of them so we don't double-count them when 00819 // building the list of permute IDs. 00820 doubleCountedSameGIDs = tgtGIDs2 (numSameGIDs1, numSameGIDs2 - numSameGIDs1); 00821 } 00822 00823 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00824 { 00825 std::ostringstream os; 00826 os << myRank << ": union Map's same GIDs: " << toString (unionTgtGIDs ()) << endl; 00827 os << myRank << ": doubleCountedSameGIDs: " << toString (doubleCountedSameGIDs) << endl; 00828 cerr << os.str (); 00829 } 00830 if (myRank == 0) { 00831 cerr << endl; 00832 } 00833 comm->barrier (); 00834 comm->barrier (); 00835 comm->barrier (); 00836 cerr << myRank << ": Computing permute IDs" << endl; 00837 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00838 00839 // Each input Import knows its permute-from LIDs (in the source 00840 // Map) and permute-to LIDs (in its target Map). We will have to 00841 // reassign LIDs in the union target Map, but we can use these 00842 // permute-to LIDs to construct the union Import's permute-to IDs. 00843 Array<LO> permuteFromLIDsUnion; 00844 Array<LO> permuteToLIDsUnion; 00845 LO curTgtLid = as<LO> (numSameIDsUnion); 00846 { 00847 // Permute-to LIDs in the two input target Maps. 00848 ArrayView<const LO> permuteToLIDs1 = this->getPermuteToLIDs (); 00849 ArrayView<const LO> permuteToLIDs2 = rhs.getPermuteToLIDs (); 00850 const size_type numPermuteIDs1 = this->getNumPermuteIDs (); 00851 const size_type numPermuteIDs2 = rhs.getNumPermuteIDs (); 00852 00853 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00854 cerr << myRank << ": Converting permute-to LIDs to GIDs" << endl; 00855 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00856 00857 // Convert the permute-to LID lists to GIDs, so that we can 00858 // later reassign LIDs for the (output) union target Map. 00859 Array<GO> permuteGIDs1 (numPermuteIDs1); 00860 for (size_type k = 0; k < numPermuteIDs1; ++k) { 00861 permuteGIDs1[k] = tgtMap1->getGlobalElement (permuteToLIDs1[k]); 00862 } 00863 Array<GO> permuteGIDs2 (numPermuteIDs2); 00864 for (size_type k = 0; k < numPermuteIDs2; ++k) { 00865 permuteGIDs2[k] = tgtMap2->getGlobalElement (permuteToLIDs2[k]); 00866 } 00867 00868 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00869 { 00870 std::ostringstream os; 00871 os << myRank << ": permuteGIDs1: " << toString (permuteGIDs1) << endl; 00872 os << myRank << ": permuteGIDs2: " << toString (permuteGIDs2) << endl; 00873 cerr << os.str (); 00874 } 00875 cerr << myRank << ": Sorting and merging permute GID lists" << endl; 00876 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00877 00878 // Sort the two permute GID lists, remove the GIDs that we don't 00879 // want to double-count, and merge the result into the global 00880 // list of GIDs in the target union Map. 00881 std::sort (permuteGIDs1.begin (), permuteGIDs1.end ()); 00882 std::sort (permuteGIDs2.begin (), permuteGIDs2.end ()); 00883 00884 typename Array<GO>::iterator permuteGIDs1_beg = permuteGIDs1.begin (); 00885 typename Array<GO>::iterator permuteGIDs1_end = permuteGIDs1.end (); 00886 typename Array<GO>::iterator permuteGIDs2_beg = permuteGIDs2.begin (); 00887 typename Array<GO>::iterator permuteGIDs2_end = permuteGIDs2.end (); 00888 if (tgtMap1HadMaxSameGIDs) { 00889 // This operation allows the last (output) argument to alias the first. 00890 permuteGIDs2_end = 00891 std::set_difference(permuteGIDs2_beg, 00892 permuteGIDs2_end, 00893 doubleCountedSameGIDs.begin (), 00894 doubleCountedSameGIDs.end (), 00895 permuteGIDs2_beg); 00896 00897 00898 } else { 00899 // This operation allows the last (output) argument to alias the first. 00900 permuteGIDs1_end = 00901 std::set_difference(permuteGIDs1_beg, 00902 permuteGIDs1_end, 00903 doubleCountedSameGIDs.begin (), 00904 doubleCountedSameGIDs.end (), 00905 permuteGIDs1_beg); 00906 00907 } 00908 std::set_union (permuteGIDs1_beg, permuteGIDs1_end, 00909 permuteGIDs2_beg, permuteGIDs2_end, 00910 std::back_inserter (unionTgtGIDs)); 00911 00912 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00913 { 00914 std::ostringstream os; 00915 if(tgtMap1HadMaxSameGIDs) os << myRank << ": tgtMap1HadMaxSameGIDs == true"<<endl; 00916 else os << myRank << ": tgtMap1HadMaxSameGIDs == false"<<endl; 00917 00918 os << myRank << ": reduced permuteGIDs1: {"; 00919 for(typename Array<GO>::iterator k = permuteGIDs1_beg; k != permuteGIDs1_end; k++) 00920 os<<*k<<", "; 00921 os<<"}"<<endl; 00922 os << myRank << ": reduced permuteGIDs2: {"; 00923 for(typename Array<GO>::iterator k = permuteGIDs2_beg; k != permuteGIDs2_end; k++) 00924 os<<*k<<", "; 00925 os<<"}"<<endl; 00926 cerr << os.str (); 00927 } 00928 #endif 00929 const size_type numPermuteIDsUnion = 00930 unionTgtGIDs.size () - numSameIDsUnion; 00931 ArrayView<const GO> permuteGIDsUnion = 00932 unionTgtGIDs (numSameIDsUnion, numPermuteIDsUnion).getConst (); 00933 00934 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00935 { 00936 std::ostringstream os; 00937 os << myRank << ": permuteGIDsUnion: " << toString (permuteGIDsUnion) << endl; 00938 cerr << os.str (); 00939 } 00940 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00941 00942 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00943 comm->barrier (); 00944 cerr << myRank << ": Computing permute-to LIDs" << endl; 00945 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00946 00947 // Compute the permute-to LIDs (in the union target Map). 00948 permuteToLIDsUnion.resize (numPermuteIDsUnion); 00949 for (size_type k = 0; k < numPermuteIDsUnion; ++k) { 00950 permuteToLIDsUnion[k] = curTgtLid++; 00951 } 00952 00953 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00954 { 00955 std::ostringstream os; 00956 os << myRank << ": permuteToLIDsUnion: " << toString (permuteToLIDsUnion) << endl; 00957 cerr << os.str (); 00958 } 00959 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00960 00961 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00962 comm->barrier (); 00963 cerr << myRank << ": Computing permute-from LIDs" << endl; 00964 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00965 00966 // Convert the permute GIDs to permute-from LIDs in the source Map. 00967 permuteFromLIDsUnion.resize (numPermuteIDsUnion); 00968 for (size_type k = 0; k < numPermuteIDsUnion; ++k) { 00969 permuteFromLIDsUnion[k] = srcMap->getLocalElement (permuteGIDsUnion[k]); 00970 } 00971 00972 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00973 { 00974 std::ostringstream os; 00975 os << myRank << ": permuteFromLIDsUnion: " << toString (permuteFromLIDsUnion) << endl; 00976 cerr << os.str (); 00977 } 00978 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00979 }// end permutes 00980 00981 00982 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00983 { 00984 std::ostringstream os; 00985 os << myRank << ": unionTgtGIDs after permutes: " 00986 << toString (unionTgtGIDs ()) << endl; 00987 cerr << os.str (); 00988 } 00989 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 00990 00991 // Thus far, we have computed the following in the union Import: 00992 // - getNumSameIDs() 00993 // - getNumPermuteIDs() 00994 // - getPermuteFromLIDs () 00995 // - getPermuteToLIDs () 00996 // 00997 // Now it's time to compute the remote IDs. By definition, none 00998 // of these IDs are in the source Map (on the calling process), so 00999 // they can't possibly overlap with any of the "same" or permute 01000 // IDs in either target Map. 01001 // 01002 // After the first numSameIDsUnion IDs, we get to control the 01003 // order of GIDs in the union target Map. We'll put the permute 01004 // IDs first (which we already did above) and the remote IDs last 01005 // (which we are about to do). We'll sort the remote IDs by 01006 // process rank, so that Distributor doesn't have to pack buffers. 01007 // (That way, doPosts() will always take the "fast path" on all 01008 // processes.) 01009 01010 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01011 if (myRank == 0) { 01012 cerr << endl; 01013 } 01014 comm->barrier (); 01015 comm->barrier (); 01016 comm->barrier (); 01017 cerr << myRank << ": Computing remote IDs" << endl; 01018 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01019 01020 Array<GO> remoteGIDsUnion; 01021 Array<int> remotePIDsUnion; 01022 Array<LO> remoteLIDsUnion; 01023 size_type numRemoteIDsUnion = 0; 01024 { 01025 // Distributor::createFromRecvs takes remote IDs and PIDs as 01026 // input, and computes exportIDs and exportPIDs. The easiest 01027 // way to get the remote PIDs is to imitate setupExport by using 01028 // getRemoteIndexList(). We could try to get them out of the 01029 // Distributor via getImagesFrom(), but Distributor reorders 01030 // them in some not entirely transparent way. 01031 01032 // Grab the remoteLIDs 01033 ArrayView<const LO> remoteLIDs1 = this->getRemoteLIDs(); 01034 ArrayView<const LO> remoteLIDs2 = rhs.getRemoteLIDs(); 01035 01036 // Grab the remotePIDs 01037 Array<int> remotePIDs1, remotePIDs2; 01038 Tpetra::Import_Util::getRemotePIDs(*this,remotePIDs1); 01039 Tpetra::Import_Util::getRemotePIDs(rhs,remotePIDs2); 01040 01041 // Put the (PID,GID) into std:pairs to make for easier sorting 01042 Array<std::pair<int,GO> > remotePGIDs1, remotePGIDs2,remotePGUnion; 01043 remotePGIDs1.resize(remotePIDs1.size()); 01044 remotePGIDs2.resize(remotePIDs2.size()); 01045 01046 for(size_type k=0; k < remotePIDs1.size(); k++) 01047 remotePGIDs1[k] = std::pair<int,GO>(remotePIDs1[k],this->getTargetMap()->getGlobalElement(remoteLIDs1[k])); 01048 01049 for(size_type k=0; k < remotePIDs2.size(); k++) 01050 remotePGIDs2[k] = std::pair<int,GO>(remotePIDs2[k],rhs.getTargetMap()->getGlobalElement(remoteLIDs2[k])); 01051 01052 01053 // Sort and merge the (PID,GID) pairs (with the LIDs along for the ride at least for the sort) 01054 std::sort(remotePGIDs1.begin(), remotePGIDs1.end()); 01055 std::sort(remotePGIDs2.begin(), remotePGIDs2.end()); 01056 std::merge(remotePGIDs1.begin(), remotePGIDs1.end(), 01057 remotePGIDs2.begin(), remotePGIDs2.end(), 01058 std::back_inserter(remotePGUnion)); 01059 typename Array<std::pair<int,GO> >::iterator it = std::unique(remotePGUnion.begin(),remotePGUnion.end()); 01060 remotePGUnion.resize(std::distance(remotePGUnion.begin(),it)); 01061 01062 // Assign the remote LIDs in order; copy out 01063 numRemoteIDsUnion = remotePGUnion.size(); 01064 remoteLIDsUnion.resize(numRemoteIDsUnion); 01065 remotePIDsUnion.resize(numRemoteIDsUnion); 01066 remoteGIDsUnion.resize(numRemoteIDsUnion); 01067 01068 for (size_type k = 0; k < numRemoteIDsUnion; ++k) { 01069 remoteLIDsUnion[k] = curTgtLid++; 01070 remotePIDsUnion[k] = remotePGUnion[k].first; 01071 remoteGIDsUnion[k] = remotePGUnion[k].second; 01072 } 01073 01074 // Update the unionTgtGIDs 01075 const size_type oldSize = unionTgtGIDs.size(); 01076 unionTgtGIDs.resize(oldSize + numRemoteIDsUnion); 01077 for(size_type k=0; k<numRemoteIDsUnion; k++) 01078 unionTgtGIDs[oldSize+k] = remoteGIDsUnion[k]; 01079 01080 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01081 { 01082 // For debugging purposes only 01083 Array<GO> remoteGIDs1(remotePIDs1.size()); 01084 Array<GO> remoteGIDs2(remotePIDs2.size()); 01085 for(size_type k=0; k < remotePIDs1.size(); k++) 01086 remoteGIDs1[k] = this->getTargetMap()->getGlobalElement(remoteLIDs1[k]); 01087 for(size_type k=0; k < remotePIDs2.size(); k++) 01088 remoteGIDs2[k] = rhs.getTargetMap()->getGlobalElement(remoteLIDs2[k]); 01089 01090 std::ostringstream os; 01091 os << myRank << ": remoteGIDs1 : " << toString (remoteGIDs1 ()) << endl; 01092 os << myRank << ": remotePIDs1 : " << toString (remotePIDs1 ()) << endl; 01093 os << myRank << ": remoteGIDs2 : " << toString (remoteGIDs2 ()) << endl; 01094 os << myRank << ": remotePIDs2 : " << toString (remotePIDs2 ()) << endl; 01095 cerr << os.str (); 01096 } 01097 #endif 01098 }//end remotes 01099 01100 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01101 { 01102 std::ostringstream os; 01103 os << myRank << ": remoteGIDsUnion sorted: " << toString (remoteGIDsUnion ()) << endl; 01104 os << myRank << ": remotePIDsUnion sorted: " << toString (remotePIDsUnion ()) << endl; 01105 os << myRank << ": remoteLIDsUnion sorted: " << toString (remoteLIDsUnion ()) << endl; 01106 cerr << os.str (); 01107 } 01108 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01109 01110 01111 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01112 { 01113 std::ostringstream os; 01114 os << myRank << ": unionTgtGIDs after remotes: " 01115 << toString (unionTgtGIDs ()) << endl; 01116 cerr << os.str (); 01117 } 01118 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01119 01120 // Find the union target Map's index base, which must also be the 01121 // union target Map's global min GID. Thus, by definition, it 01122 // must be the minimum of the two input target Maps' index bases. 01123 // We already know these, so we don't have to do another 01124 // all-reduce to find it. 01125 const GO indexBaseUnion = 01126 std::min (tgtMap1->getIndexBase (), tgtMap2->getIndexBase ()); 01127 01128 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01129 cerr << myRank << "Creating union target Map" << endl; 01130 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01131 01132 // Create the union target Map. 01133 // 01134 // mfh 01 May 2013, 28 Feb 2014: It might be handy to have a Map 01135 // constructor that takes the global min and max GIDs; that would 01136 // obviate the need for Map to compute them. On the other hand, 01137 // for signed GlobalOrdinal, this version of Map's constructor 01138 // already computes as few all-reduces as possible (not including 01139 // optimizations that might be possible if one were to fold in 01140 // Directory construction). The constructor must do two 01141 // all-reduces: 01142 // 01143 // 1. Get the global number of GIDs (since the first argument is 01144 // INVALID, we're asking Map to compute this for us) 01145 // 01146 // 2. Figure out three things: global min and max GID, and 01147 // whether the Map is distributed or locally replicated. 01148 // 01149 // #2 above happens in one all-reduce (of three integers). 01150 // #Figuring out whether the Map is distributed or locally 01151 // #replicated requires knowing the global number of GIDs. 01152 const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid (); 01153 RCP<const map_type> unionTgtMap = 01154 rcp (new map_type (INVALID, unionTgtGIDs (), indexBaseUnion, 01155 comm, srcMap->getNode ())); 01156 01157 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01158 if (myRank == 0) { 01159 cerr << endl; 01160 } 01161 comm->barrier (); 01162 comm->barrier (); 01163 comm->barrier (); 01164 cerr << myRank << ": Computing export IDs and Distributor" << endl; 01165 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01166 01167 // Thus far, we have computed the following in the union Import: 01168 // - numSameIDs 01169 // - numPermuteIDs and permuteFromLIDs 01170 // - numRemoteIDs, remoteGIDs, remoteLIDs, and remotePIDs 01171 // 01172 // Now it's time to compute the export IDs and initialize the 01173 // Distributor. 01174 01175 Array<GO> exportGIDsUnion; 01176 Array<LO> exportLIDsUnion; 01177 Array<int> exportPIDsUnion; 01178 Distributor distributor (comm, this->out_); 01179 01180 #ifdef TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS 01181 // Compute the export IDs without communication, by merging the 01182 // lists of (export LID, export PID) pairs from the two input 01183 // Import objects. The export LIDs in both input Import objects 01184 // are LIDs in the source Map. Then, use the export PIDs to 01185 // initialize the Distributor via createFromSends. 01186 01187 // const size_type numExportIDs1 = this->getNumExportIDs (); 01188 ArrayView<const LO> exportLIDs1 = this->getExportLIDs (); 01189 ArrayView<const LO> exportPIDs1 = this->getExportPIDs (); 01190 01191 // const size_type numExportIDs2 = rhs.getNumExportIDs (); 01192 ArrayView<const LO> exportLIDs2 = rhs.getExportLIDs (); 01193 ArrayView<const LO> exportPIDs2 = rhs.getExportPIDs (); 01194 01195 // We have to keep the export LIDs in PID-sorted order, then merge 01196 // them. So, first key-value merge (LID,PID) pairs, treating PIDs 01197 // as values, merging values by replacement. Then, sort the 01198 // (LID,PID) pairs again by PID. 01199 01200 // Sort (LID,PID) pairs by LID for the later merge, and make 01201 // each sequence unique by LID. 01202 Array<LO> exportLIDs1Copy (exportLIDs1.begin (), exportLIDs1.end ()); 01203 Array<int> exportPIDs1Copy (exportLIDs1.begin (), exportLIDs1.end ()); 01204 sort2 (exportLIDs1Copy.begin (), exportLIDs1Copy.end (), 01205 exportPIDs1Copy.begin ()); 01206 typename ArrayView<LO>::iterator exportLIDs1_end = exportLIDs1Copy.end (); 01207 typename ArrayView<LO>::iterator exportPIDs1_end = exportPIDs1Copy.end (); 01208 merge2 (exportLIDs1_end, exportPIDs1_end, 01209 exportLIDs1Copy.begin (), exportLIDs1_end, 01210 exportPIDs1Copy.begin (), exportPIDs1_end, 01211 project1st<LO, LO> ()); 01212 01213 Array<LO> exportLIDs2Copy (exportLIDs2.begin (), exportLIDs2.end ()); 01214 Array<int> exportPIDs2Copy (exportLIDs2.begin (), exportLIDs2.end ()); 01215 sort2 (exportLIDs2Copy.begin (), exportLIDs2Copy.end (), 01216 exportPIDs2Copy.begin ()); 01217 typename ArrayView<LO>::iterator exportLIDs2_end = exportLIDs2Copy.end (); 01218 typename ArrayView<LO>::iterator exportPIDs2_end = exportPIDs2Copy.end (); 01219 merge2 (exportLIDs2_end, exportPIDs2_end, 01220 exportLIDs2Copy.begin (), exportLIDs2_end, 01221 exportPIDs2Copy.begin (), exportPIDs2_end, 01222 project1st<LO, LO> ()); 01223 01224 // Merge export (LID,PID) pairs. In this merge operation, the 01225 // LIDs are the "keys" and the PIDs their "values." We combine 01226 // the "values" (PIDs) in the pairs by replacement, rather than 01227 // by adding them together. 01228 keyValueMerge (exportLIDs1Copy.begin (), exportLIDs1Copy.end (), 01229 exportPIDs1Copy.begin (), exportPIDs1Copy.end (), 01230 exportLIDs2Copy.begin (), exportLIDs2Copy.end (), 01231 exportPIDs2Copy.begin (), exportPIDs2Copy.end (), 01232 std::back_inserter (exportLIDsUnion), 01233 std::back_inserter (exportPIDsUnion), 01234 project1st<int, int> ()); 01235 01236 // Resort the merged (LID,PID) pairs by PID. 01237 sort2 (exportPIDsUnion.begin (), exportPIDsUnion.end (), 01238 exportLIDsUnion.begin ()); 01239 01240 // Initialize the Distributor. Using createFromSends instead of 01241 // createFromRecvs avoids the initialization and use of a 01242 // temporary Distributor object. 01243 (void) distributor.createFromSends (exportPIDsUnion ().getConst ()); 01244 #else // NOT TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS 01245 01246 // Call the Distributor's createFromRecvs() method to turn the 01247 // remote GIDs and their owning processes into a send-and-receive 01248 // communication plan. remoteGIDsUnion and remotePIDsUnion are 01249 // input; exportGIDsUnion and exportPIDsUnion are output arrays 01250 // which are allocated by createFromRecvs(). 01251 distributor.createFromRecvs (remoteGIDsUnion().getConst (), 01252 remotePIDsUnion ().getConst (), 01253 exportGIDsUnion, exportPIDsUnion); 01254 01255 // Find the (source Map) LIDs corresponding to the export GIDs. 01256 const size_type numExportIDsUnion = exportGIDsUnion.size (); 01257 exportLIDsUnion.resize (numExportIDsUnion); 01258 for (size_type k = 0; k < numExportIDsUnion; ++k) { 01259 exportLIDsUnion[k] = srcMap->getLocalElement (exportGIDsUnion[k]); 01260 } 01261 #endif // TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS 01262 01263 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01264 { 01265 std::ostringstream os; 01266 os << myRank << ": exportGIDsUnion: " << toString (exportGIDsUnion ()) << endl; 01267 os << myRank << ": exportPIDsUnion: " << toString (exportPIDsUnion ()) << endl; 01268 os << myRank << ": exportLIDsUnion: " << toString (exportLIDsUnion ()) << endl; 01269 cerr << os.str (); 01270 } 01271 comm->barrier (); 01272 cerr << "Creating union Import" << endl; 01273 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01274 01275 // Create and return the union Import. 01276 RCP<const import_type> unionImport = 01277 rcp (new import_type (srcMap, unionTgtMap, 01278 as<size_t> (numSameIDsUnion), 01279 permuteToLIDsUnion, permuteFromLIDsUnion, 01280 remoteLIDsUnion, exportLIDsUnion, 01281 exportPIDsUnion, distributor, this->out_)); 01282 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01283 comm->barrier (); 01284 cerr << "Created union Import; done!" << endl; 01285 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01286 01287 return unionImport; 01288 } 01289 01290 01291 01292 template <class LocalOrdinal, class GlobalOrdinal, class Node> 01293 Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node> > 01294 Import<LocalOrdinal,GlobalOrdinal,Node>:: 01295 setUnion () const 01296 { 01297 using Teuchos::Array; 01298 using Teuchos::ArrayView; 01299 using Teuchos::as; 01300 using Teuchos::Comm; 01301 using Teuchos::RCP; 01302 using Teuchos::rcp; 01303 using Teuchos::outArg; 01304 using Teuchos::REDUCE_MIN; 01305 using Teuchos::reduceAll; 01306 typedef LocalOrdinal LO; 01307 typedef GlobalOrdinal GO; 01308 Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node> > unionImport; 01309 RCP<const map_type> srcMap = this->getSourceMap (); 01310 RCP<const map_type> tgtMap = this->getTargetMap (); 01311 RCP<const Comm<int> > comm = srcMap->getComm (); 01312 01313 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01314 const int myRank = comm->getRank (); 01315 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT 01316 01317 ArrayView<const GO> srcGIDs = srcMap->getNodeElementList (); 01318 ArrayView<const GO> tgtGIDs = tgtMap->getNodeElementList (); 01319 01320 // All elements in srcMap will be in the "new" target map, so... 01321 size_t numSameIDsNew = srcMap->getNodeNumElements(); 01322 size_t numRemoteIDsNew = getNumRemoteIDs(); 01323 Array<LO> permuteToLIDsNew, permuteFromLIDsNew; // empty on purpose 01324 01325 // Grab some old data 01326 ArrayView<const LO> remoteLIDsOld = getRemoteLIDs(); 01327 ArrayView<const LO> exportLIDsOld = getExportLIDs(); 01328 01329 // Build up the new map (same part) 01330 Array<GO> GIDs(numSameIDsNew + numRemoteIDsNew); 01331 for(size_t i=0; i<numSameIDsNew; i++) 01332 GIDs[i] = srcGIDs[i]; 01333 01334 // Build up the new map (remote part) and remotes list 01335 Array<LO> remoteLIDsNew(numRemoteIDsNew); 01336 for(size_t i=0; i<numRemoteIDsNew; i++) { 01337 GIDs[numSameIDsNew + i] = tgtGIDs[remoteLIDsOld[i]]; 01338 remoteLIDsNew[i] = numSameIDsNew+i; 01339 } 01340 01341 // Build the new target map 01342 GO GO_INVALID = Teuchos::OrdinalTraits<GO>::invalid(); 01343 RCP<const map_type> targetMapNew = rcp(new map_type(GO_INVALID,GIDs,tgtMap->getIndexBase(),tgtMap->getComm(),tgtMap->getNode())); 01344 01345 // Exports are trivial (since the sourcemap doesn't change) 01346 Array<int> exportPIDsnew(getExportPIDs()); 01347 Array<LO> exportLIDsnew(getExportLIDs()); 01348 01349 // Copy the Distributor (due to how the Import constructor works) 01350 Distributor D(getDistributor()); 01351 01352 // Build the importer 01353 unionImport = rcp(new Import<LocalOrdinal, GlobalOrdinal, Node>(srcMap,targetMapNew,numSameIDsNew,permuteToLIDsNew,permuteFromLIDsNew, 01354 remoteLIDsNew,exportLIDsnew,exportPIDsnew,D)); 01355 01356 return unionImport; 01357 } 01358 01359 01360 01361 01362 template <class LocalOrdinal, class GlobalOrdinal, class Node> 01363 Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node> > 01364 Import<LocalOrdinal,GlobalOrdinal,Node>:: 01365 createRemoteOnlyImport(const Teuchos::RCP<const map_type>& remoteTarget) const 01366 { 01367 using Teuchos::rcp; 01368 typedef Import<LocalOrdinal,GlobalOrdinal,Node> import_type; 01369 01370 const size_t NumRemotes = getNumRemoteIDs (); 01371 TEUCHOS_TEST_FOR_EXCEPTION( 01372 NumRemotes != remoteTarget->getNodeNumElements (), 01373 std::runtime_error, "Tpetra::createRemoteOnlyImport: " 01374 "remoteTarget map ID count doesn't match."); 01375 01376 // Compute the new Remote LIDs 01377 Teuchos::ArrayView<const LocalOrdinal> oldRemoteLIDs = getRemoteLIDs (); 01378 Teuchos::Array<LocalOrdinal> newRemoteLIDs (NumRemotes); 01379 for (size_t i = 0; i < NumRemotes; ++i) { 01380 newRemoteLIDs[i] = remoteTarget->getLocalElement (getTargetMap ()->getGlobalElement (oldRemoteLIDs[i])); 01381 // Now we make sure these guys are in sorted order (AztecOO-ML ordering) 01382 TEUCHOS_TEST_FOR_EXCEPTION( 01383 i > 0 && newRemoteLIDs[i] < newRemoteLIDs[i-1], 01384 std::runtime_error, "Tpetra::createRemoteOnlyImport: " 01385 "this and remoteTarget order don't match."); 01386 } 01387 01388 // Copy ExportPIDs and such 01389 // NOTE: Be careful: The Import constructor we use does a "swap" 01390 // for most of the LID/PID lists and the Distributor, meaning it 01391 // ruins the existing object if we pass things in directly. Hence 01392 // we copy them first. 01393 Teuchos::Array<int> newExportPIDs (getExportPIDs ()); 01394 Teuchos::Array<LocalOrdinal> newExportLIDs (getExportLIDs ()); 01395 Teuchos::Array<LocalOrdinal> dummy; 01396 Distributor newDistor (getDistributor ()); 01397 01398 return rcp (new import_type (getSourceMap (), remoteTarget, 01399 static_cast<size_t> (0), dummy, dummy, 01400 newRemoteLIDs, newExportLIDs, 01401 newExportPIDs, newDistor)); 01402 } 01403 01404 } // namespace Tpetra 01405 01406 #define TPETRA_IMPORT_CLASS_INSTANT(LO, GO, NODE) \ 01407 \ 01408 template class Import< LO , GO , NODE >; 01409 01410 // Explicit instantiation macro. 01411 // Only invoke this when in the Tpetra namespace. 01412 // Most users do not need to use this. 01413 // 01414 // LO: The local ordinal type. 01415 // GO: The global ordinal type. 01416 // NODE: The Kokkos Node type. 01417 #define TPETRA_IMPORT_INSTANT(LO, GO, NODE) \ 01418 TPETRA_IMPORT_CLASS_INSTANT(LO, GO, NODE) 01419 01420 #endif // TPETRA_IMPORT_DEF_HPP
1.7.6.1