Tpetra Matrix/Vector Services Version of the Day
Tpetra_Directory_def.hpp
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_DIRECTORY_HPP
00043 #define TPETRA_DIRECTORY_HPP
00044 
00045 #include <Teuchos_as.hpp>
00046 #include <Tpetra_ConfigDefs.hpp>
00047 #include <Tpetra_Distributor.hpp>
00048 #include <Tpetra_Map.hpp>
00049 #include <Tpetra_DirectoryImpl.hpp>
00050 #include <Tpetra_DirectoryImpl_def.hpp>
00051 
00052 #ifdef DOXYGEN_USE_ONLY
00053 #  include "Tpetra_Directory_decl.hpp"
00054 #endif
00055 
00056 namespace Tpetra {
00057 
00058   template<class LO, class GO, class NT>
00059   Directory<LO, GO, NT>::Directory () :
00060     impl_ (NULL)
00061   {}
00062 
00063   template<class LO, class GO, class NT>
00064   TEUCHOS_DEPRECATED
00065   Directory<LO, GO, NT>::Directory (const Map<LO, GO, NT>& /* map */) :
00066     impl_ (NULL)
00067   {
00068     TEUCHOS_TEST_FOR_EXCEPTION(
00069       true, std::logic_error, "Tpetra::Directory: All constructors other than "
00070       "the default (zero-argument) constructor have been deprecated.  All "
00071       "initialization takes place in initialize.");
00072   }
00073 
00074   template<class LO, class GO, class NT>
00075   TEUCHOS_DEPRECATED
00076   Directory<LO, GO, NT>::
00077   Directory (const Teuchos::RCP<const Map<LO, GO, NT> >& /* mapPtr */) :
00078     impl_ (NULL)
00079   {
00080     TEUCHOS_TEST_FOR_EXCEPTION(
00081       true, std::logic_error, "Tpetra::Directory: All constructors other than "
00082       "the default (zero-argument) constructor have been deprecated.  All "
00083       "initialization takes place in initialize.");
00084   }
00085 
00086   template<class LO, class GO, class NT>
00087   TEUCHOS_DEPRECATED
00088   Directory<LO, GO, NT>::
00089   Directory (const Map<LO, GO, NT>& /* map */,
00090              const Tpetra::Details::TieBreak<LO,GO>& /* tieBreak */) :
00091     impl_ (NULL)
00092   {
00093     TEUCHOS_TEST_FOR_EXCEPTION(
00094       true, std::logic_error, "Tpetra::Directory: All constructors other than "
00095       "the default (zero-argument) constructor have been deprecated.  All "
00096       "initialization takes place in initialize.  You may provide an optional "
00097       "TieBreak object there if you like.");
00098   }
00099 
00100   template<class LO, class GO, class NT>
00101   Directory<LO, GO, NT>::~Directory () {
00102     if (impl_ != NULL) {
00103       delete impl_;
00104       impl_ = NULL;
00105     }
00106   }
00107 
00108   template<class LO, class GO, class NT>
00109   bool
00110   Directory<LO, GO, NT>::initialized () const {
00111     return impl_ != NULL;
00112   }
00113 
00114 
00115   template<class LO, class GO, class NT>
00116   void
00117   Directory<LO, GO, NT>::
00118   initialize (const Map<LO, GO, NT>& map,
00119               const Tpetra::Details::TieBreak<LO,GO>& tieBreak)
00120   {
00121     if (initialized ()) {
00122       TEUCHOS_TEST_FOR_EXCEPTION(
00123         impl_ == NULL, std::logic_error, "Tpetra::Directory::initialize: "
00124         "The Directory claims that it has been initialized, "
00125         "but its implementation object has not yet been created.  "
00126         "Please report this bug to the Tpetra developers.");
00127     }
00128     else {
00129       TEUCHOS_TEST_FOR_EXCEPTION(
00130         impl_ != NULL, std::logic_error, "Tpetra::Directory::initialize: "
00131         "Directory implementation has already been initialized, "
00132         "but initialized() returns false.  "
00133         "Please report this bug to the Tpetra developers.");
00134 
00135       // Create an implementation object of the appropriate type,
00136       // depending on whether the Map is distributed or replicated,
00137       // and contiguous or noncontiguous.
00138       //
00139       // mfh 06 Apr 2014: When a distributed noncontiguous Directory
00140       // takes a TieBreak, all the entries (local indices and process
00141       // ranks) owned by the Directory on the calling process pass
00142       // through the TieBreak object.  This may have side effects,
00143       // such as the TieBreak object remembering whether there were
00144       // any duplicates on the calling process.  We want to extend use
00145       // of a TieBreak object to other kinds of Directories.  For a
00146       // distributed contiguous Directory, the calling process owns
00147       // all of the (PID,LID) pairs in the input Map.  For a locally
00148       // replicated contiguous Directory, Process 0 owns all of the
00149       // (PID,LID) pairs in the input Map.
00150       //
00151       // It may seem silly to pass in a TieBreak when there are no
00152       // ties to break.  However, the TieBreak object gets to see all
00153       // (PID,LID) pairs that the Directory owns on the calling
00154       // process, and interface of TieBreak allows side effects.
00155       // Users may wish to exploit them regardless of the kind of Map
00156       // they pass in.
00157       const Details::Directory<LO, GO, NT>* dir = NULL;
00158       bool usedTieBreak = false;
00159       if (map.isDistributed ()) {
00160         if (map.isUniform ()) {
00161           dir = new Details::ContiguousUniformDirectory<LO, GO, NT> (map);
00162         }
00163         else if (map.isContiguous ()) {
00164           dir = new Details::DistributedContiguousDirectory<LO, GO, NT> (map);
00165         }
00166         else {
00167           dir = new Details::DistributedNoncontiguousDirectory<LO, GO, NT> (map, tieBreak);
00168           usedTieBreak = true;
00169         }
00170       }
00171       else {
00172         dir = new Details::ReplicatedDirectory<LO, GO, NT> (map);
00173 
00174         if (tieBreak.mayHaveSideEffects () && map.getNodeNumElements () != 0) {
00175           // We need the second clause in the above test because Map's
00176           // interface provides an inclusive range of local indices.
00177           const int myRank = map.getComm ()->getRank ();
00178           // In a replicated Directory, Process 0 owns all the
00179           // Directory's entries.  This is an arbitrary assignment; any
00180           // one process would do.
00181           if (myRank == 0) {
00182             std::vector<std::pair<int, LO> > pidLidList (1);
00183             const LO minLocInd = map.getMinLocalIndex ();
00184             const LO maxLocInd = map.getMaxLocalIndex ();
00185             for (LO locInd = minLocInd; locInd <= maxLocInd; ++locInd) {
00186               pidLidList[0] = std::make_pair (myRank, locInd);
00187               const GO globInd = map.getGlobalElement (locInd);
00188               // We don't care about the return value; we just want to
00189               // invoke the side effects.
00190               (void) tieBreak.selectedIndex (globInd, pidLidList);
00191             }
00192           }
00193         }
00194         usedTieBreak = true;
00195       } // done with all different Map cases
00196 
00197       // If we haven't already used the TieBreak object, use it now.
00198       // This code appears twice because ReplicatedDirectory is a
00199       // special case: we already know what gets replicated.
00200       if (! usedTieBreak && tieBreak.mayHaveSideEffects () &&
00201           map.getNodeNumElements () != 0) {
00202         // We need the third clause in the above test because Map's
00203         // interface provides an inclusive range of local indices.
00204         std::vector<std::pair<int, LO> > pidLidList (1);
00205         const LO minLocInd = map.getMinLocalIndex ();
00206         const LO maxLocInd = map.getMaxLocalIndex ();
00207         const int myRank = map.getComm ()->getRank ();
00208         for (LO locInd = minLocInd; locInd <= maxLocInd; ++locInd) {
00209           pidLidList[0] = std::make_pair (myRank, locInd);
00210           const GO globInd = map.getGlobalElement (locInd);
00211           // We don't care about the return value; we just want to
00212           // invoke the side effects.
00213           (void) tieBreak.selectedIndex (globInd, pidLidList);
00214         }
00215       }
00216 
00217       impl_ = dir;
00218     }
00219   }
00220 
00221   template<class LO, class GO, class NT>
00222   void
00223   Directory<LO, GO, NT>::initialize (const Map<LO, GO, NT>& map)
00224   {
00225     if (initialized ()) {
00226       TEUCHOS_TEST_FOR_EXCEPTION(
00227         impl_ == NULL, std::logic_error, "Tpetra::Directory::initialize: "
00228         "The Directory claims that it has been initialized, "
00229         "but its implementation object has not yet been created.  "
00230         "Please report this bug to the Tpetra developers.");
00231     }
00232     else {
00233       TEUCHOS_TEST_FOR_EXCEPTION(
00234         impl_ != NULL, std::logic_error, "Tpetra::Directory::initialize: "
00235         "Directory implementation has already been initialized, "
00236         "but initialized() returns false.  "
00237         "Please report this bug to the Tpetra developers.");
00238 
00239       // Create an implementation object of the appropriate type,
00240       // depending on whether the Map is distributed or replicated,
00241       // and contiguous or noncontiguous.
00242       const Details::Directory<LO, GO, NT>* dir = NULL;
00243       if (map.isDistributed ()) {
00244         if (map.isUniform ()) {
00245           dir = new Details::ContiguousUniformDirectory<LO, GO, NT> (map);
00246         }
00247         else if (map.isContiguous ()) {
00248           dir = new Details::DistributedContiguousDirectory<LO, GO, NT> (map);
00249         }
00250         else {
00251           dir = new Details::DistributedNoncontiguousDirectory<LO, GO, NT> (map);
00252         }
00253       }
00254       else {
00255         dir = new Details::ReplicatedDirectory<LO, GO, NT> (map);
00256       }
00257       TEUCHOS_TEST_FOR_EXCEPTION(
00258         dir == NULL, std::logic_error, "Tpetra::Directory::initialize: "
00259         "Failed to create Directory implementation.  "
00260         "Please report this bug to the Tpetra developers.");
00261       impl_ = dir;
00262     }
00263   }
00264 
00265   template<class LO, class GO, class NT>
00266   LookupStatus
00267   Directory<LO, GO, NT>::
00268   getDirectoryEntries (const Map<LO, GO, NT>& map,
00269                        const Teuchos::ArrayView<const GO>& globalIDs,
00270                        const Teuchos::ArrayView<int>& nodeIDs) const
00271   {
00272     if (! initialized ()) {
00273       // This const_cast is super wrong, but "mutable" is also a lie,
00274       // and Map's interface needs this method to be marked const for
00275       // some reason.
00276       const_cast<Directory<LO, GO, NT>* > (this)->initialize (map);
00277     }
00278     const bool computeLIDs = false;
00279     return impl_->getEntries (map, globalIDs, nodeIDs, Teuchos::null, computeLIDs);
00280   }
00281 
00282 
00283   template<class LO, class GO, class NT>
00284   LookupStatus TEUCHOS_DEPRECATED
00285   Directory<LO, GO, NT>::
00286   getDirectoryEntries (const Teuchos::ArrayView<const GO>& globalIDs,
00287                        const Teuchos::ArrayView<int>& nodeIDs) const
00288   {
00289     TEUCHOS_TEST_FOR_EXCEPTION(
00290       true, std::logic_error, "This method is DEPRECATED.  Please call the "
00291       "three-argument version of getDirectoryEntries that takes a Map, an "
00292       "ArrayView<const GO>, and an ArrayView<int>.");
00293   }
00294 
00295   template<class LO, class GO, class NT>
00296   LookupStatus
00297   Directory<LO, GO, NT>::
00298   getDirectoryEntries (const Map<LO, GO, NT>& map,
00299                        const Teuchos::ArrayView<const GO>& globalIDs,
00300                        const Teuchos::ArrayView<int>& nodeIDs,
00301                        const Teuchos::ArrayView<LO>& localIDs) const
00302   {
00303     if (! initialized ()) {
00304       // This const_cast is super wrong, but "mutable" is also a lie,
00305       // and Map's interface needs this method to be marked const for
00306       // some reason.
00307       const_cast<Directory<LO, GO, NT>* > (this)->initialize (map);
00308     }
00309     const bool computeLIDs = true;
00310     return impl_->getEntries (map, globalIDs, nodeIDs, localIDs, computeLIDs);
00311   }
00312 
00313   template<class LO, class GO, class NT>
00314   LookupStatus TEUCHOS_DEPRECATED
00315   Directory<LO, GO, NT>::
00316   getDirectoryEntries (const Teuchos::ArrayView<const GO>& globalIDs,
00317                        const Teuchos::ArrayView<int>& nodeIDs,
00318                        const Teuchos::ArrayView<LO>& localIDs) const
00319   {
00320     TEUCHOS_TEST_FOR_EXCEPTION(
00321       true, std::logic_error, "This method is DEPRECATED.  Please call the "
00322       "four-argument version of getDirectoryEntries that takes a Map, an "
00323       "ArrayView<const GO>, an ArrayView<int>, and an ArrayView<LO>.");
00324   }
00325 
00326   template<class LO, class GO, class NT>
00327   bool Directory<LO, GO, NT>::isOneToOne (const Map<LO, GO, NT>& map) const {
00328     if (! initialized ()) {
00329       // This const_cast is super wrong, but "mutable" is also a lie,
00330       // and Map's interface needs this method to be marked const for
00331       // some reason.
00332       const_cast<Directory<LO, GO, NT>* > (this)->initialize (map);
00333     }
00334     return impl_->isOneToOne (* (map.getComm ()));
00335   }
00336 
00337   template<class LO, class GO, class NT>
00338   std::string
00339   Directory<LO, GO, NT>::description () const
00340   {
00341     using Teuchos::TypeNameTraits;
00342 
00343     std::ostringstream os;
00344     os << "Directory"
00345        << "<" << TypeNameTraits<LO>::name ()
00346        << ", " << TypeNameTraits<GO>::name ()
00347        << ", " << TypeNameTraits<NT>::name () << ">";
00348     return os.str ();
00349   }
00350 
00351 } // namespace Tpetra
00352 
00353 //
00354 // Explicit instantiation macro
00355 //
00356 // Must be expanded from within the Tpetra namespace!
00357 //
00358 
00359 #define TPETRA_DIRECTORY_INSTANT(LO,GO,NODE) \
00360   \
00361   template class Directory< LO , GO , NODE >; \
00362 
00363 #endif // TPETRA_DIRECTORY_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines