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 (const Map<LO, GO, NT>& map) :
00060     impl_ (NULL)
00061   {
00062     // Create an implementation object of the appropriate type,
00063     // depending on whether the Map is distributed or replicated, and
00064     // contiguous or noncontiguous.
00065     const Details::Directory<LO, GO, NT>* dir = NULL;
00066     if (map.isDistributed ()) {
00067       if (map.isUniform ()) {
00068         dir = new Details::ContiguousUniformDirectory<LO, GO, NT> (map);
00069       }
00070       else if (map.isContiguous ()) {
00071         dir = new Details::DistributedContiguousDirectory<LO, GO, NT> (map);
00072       }
00073       else {
00074         dir = new Details::DistributedNoncontiguousDirectory<LO, GO, NT> (map);
00075       }
00076     }
00077     else {
00078       dir = new Details::ReplicatedDirectory<LO, GO, NT> (map);
00079     }
00080     TEUCHOS_TEST_FOR_EXCEPTION(dir == NULL, std::logic_error, "Tpetra::"
00081       "Directory constructor failed to create Directory implementation.  "
00082       "Please report this bug to the Tpetra developers.");
00083     impl_ = dir;
00084   }
00085 
00086   template<class LO, class GO, class NT>
00087   Directory<LO, GO, NT>::
00088   Directory (const Map<LO, GO, NT>& map,
00089              const Tpetra::Details::TieBreak<LO,GO>& tieBreak) :
00090     impl_ (NULL)
00091   {
00092     // Create an implementation object of the appropriate type,
00093     // depending on whether the Map is distributed or replicated, and
00094     // contiguous or noncontiguous.
00095     //
00096     // mfh 06 Apr 2014: When a distributed noncontiguous Directory
00097     // takes a TieBreak, all the entries (local indices and process
00098     // ranks) owned by the Directory on the calling process pass
00099     // through the TieBreak object.  This may have side effects, such
00100     // as the TieBreak object remembering whether there were any
00101     // duplicates on the calling process.  We want to extend use of a
00102     // TieBreak object to other kinds of Directories.  For a
00103     // distributed contiguous Directory, the calling process owns all
00104     // of the (PID,LID) pairs in the input Map.  For a locally
00105     // replicated contiguous Directory, Process 0 owns all of the
00106     // (PID,LID) pairs in the input Map.
00107     //
00108     // It may seem silly to pass in a TieBreak when there are no ties
00109     // to break.  However, the TieBreak object gets to see all
00110     // (PID,LID) pairs that the Directory owns on the calling process,
00111     // and interface of TieBreak allows side effects.  Users may wish
00112     // to exploit them regardless of the kind of Map they pass in.
00113     const Details::Directory<LO, GO, NT>* dir = NULL;
00114     bool usedTieBreak = false;
00115     if (map.isDistributed ()) {
00116       if (map.isUniform ()) {
00117         dir = new Details::ContiguousUniformDirectory<LO, GO, NT> (map);
00118       }
00119       else if (map.isContiguous ()) {
00120         dir = new Details::DistributedContiguousDirectory<LO, GO, NT> (map);
00121       }
00122       else {
00123         dir = new Details::DistributedNoncontiguousDirectory<LO, GO, NT> (map, tieBreak);
00124         usedTieBreak = true;
00125       }
00126     }
00127     else {
00128       dir = new Details::ReplicatedDirectory<LO, GO, NT> (map);
00129 
00130       if (tieBreak.mayHaveSideEffects () && map.getNodeNumElements () != 0) {
00131         // We need the second clause in the above test because Map's
00132         // interface provides an inclusive range of local indices.
00133         const int myRank = map.getComm ()->getRank ();
00134         // In a replicated Directory, Process 0 owns all the
00135         // Directory's entries.  This is an arbitrary assignment; any
00136         // one process would do.
00137         if (myRank == 0) {
00138           std::vector<std::pair<int, LO> > pidLidList (1);
00139           const LO minLocInd = map.getMinLocalIndex ();
00140           const LO maxLocInd = map.getMaxLocalIndex ();
00141           for (LO locInd = minLocInd; locInd <= maxLocInd; ++locInd) {
00142             pidLidList[0] = std::make_pair (myRank, locInd);
00143             const GO globInd = map.getGlobalElement (locInd);
00144             // We don't care about the return value; we just want to
00145             // invoke the side effects.
00146             (void) tieBreak.selectedIndex (globInd, pidLidList);
00147           }
00148         }
00149       }
00150       usedTieBreak = true;
00151     }
00152     TEUCHOS_TEST_FOR_EXCEPTION(dir == NULL, std::logic_error, "Tpetra::"
00153       "Directory constructor failed to create Directory implementation.  "
00154       "Please report this bug to the Tpetra developers.");
00155 
00156     if (! usedTieBreak && tieBreak.mayHaveSideEffects () &&
00157         map.getNodeNumElements () != 0) {
00158       // We need the third clause in the above test because Map's
00159       // interface provides an inclusive range of local indices.
00160       std::vector<std::pair<int, LO> > pidLidList (1);
00161       const LO minLocInd = map.getMinLocalIndex ();
00162       const LO maxLocInd = map.getMaxLocalIndex ();
00163       const int myRank = map.getComm ()->getRank ();
00164       for (LO locInd = minLocInd; locInd <= maxLocInd; ++locInd) {
00165         pidLidList[0] = std::make_pair (myRank, locInd);
00166         const GO globInd = map.getGlobalElement (locInd);
00167         // We don't care about the return value; we just want to
00168         // invoke the side effects.
00169         (void) tieBreak.selectedIndex (globInd, pidLidList);
00170       }
00171     }
00172 
00173     impl_ = dir;
00174   }
00175 
00176   template<class LO, class GO, class NT>
00177   Directory<LO, GO, NT>::Directory () : impl_ (NULL) {}
00178 
00179   template<class LO, class GO, class NT>
00180   Directory<LO, GO, NT>::~Directory () {
00181     if (impl_ != NULL) {
00182       delete impl_;
00183       impl_ = NULL;
00184     }
00185   }
00186 
00187   template<class LO, class GO, class NT>
00188   LookupStatus
00189   Directory<LO, GO, NT>::
00190   getDirectoryEntries (const Map<LO, GO, NT>& map,
00191                        const Teuchos::ArrayView<const GO>& globalIDs,
00192                        const Teuchos::ArrayView<int>& nodeIDs) const
00193   {
00194     const bool computeLIDs = false;
00195     return impl_->getEntries (map, globalIDs, nodeIDs, Teuchos::null, computeLIDs);
00196   }
00197 
00198   template<class LO, class GO, class NT>
00199   LookupStatus
00200   Directory<LO, GO, NT>::
00201   getDirectoryEntries (const Map<LO, GO, NT>& map,
00202                        const Teuchos::ArrayView<const GO>& globalIDs,
00203                        const Teuchos::ArrayView<int>& nodeIDs,
00204                        const Teuchos::ArrayView<LO>& localIDs) const
00205   {
00206     const bool computeLIDs = true;
00207     return impl_->getEntries (map, globalIDs, nodeIDs, localIDs, computeLIDs);
00208   }
00209 
00210   template<class LO, class GO, class NT>
00211   bool Directory<LO, GO, NT>::isOneToOne (const Teuchos::Comm<int>& comm) const {
00212     return impl_->isOneToOne (comm);
00213   }
00214 
00215   template<class LO, class GO, class NT>
00216   std::string
00217   Directory<LO, GO, NT>::description () const
00218   {
00219     using Teuchos::TypeNameTraits;
00220 
00221     std::ostringstream os;
00222     os << "Directory"
00223        << "<" << TypeNameTraits<LO>::name ()
00224        << ", " << TypeNameTraits<GO>::name ()
00225        << ", " << TypeNameTraits<NT>::name () << ">";
00226     return os.str ();
00227   }
00228 
00229 } // namespace Tpetra
00230 
00231 //
00232 // Explicit instantiation macro
00233 //
00234 // Must be expanded from within the Tpetra namespace!
00235 //
00236 
00237 #define TPETRA_DIRECTORY_INSTANT(LO,GO,NODE) \
00238   \
00239   template class Directory< LO , GO , NODE >; \
00240 
00241 #endif // TPETRA_DIRECTORY_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines