Tpetra Matrix/Vector Services  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
Tpetra_Details_makeOptimizedColMap.hpp
Go to the documentation of this file.
00001 /*
00002 // @HEADER
00003 // ***********************************************************************
00004 //
00005 //          Tpetra: Templated Linear Algebra Services Package
00006 //                 Copyright (2008) Sandia Corporation
00007 //
00008 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00009 // the U.S. Government retains certain rights in this software.
00010 //
00011 // Redistribution and use in source and binary forms, with or without
00012 // modification, are permitted provided that the following conditions are
00013 // met:
00014 //
00015 // 1. Redistributions of source code must retain the above copyright
00016 // notice, this list of conditions and the following disclaimer.
00017 //
00018 // 2. Redistributions in binary form must reproduce the above copyright
00019 // notice, this list of conditions and the following disclaimer in the
00020 // documentation and/or other materials provided with the distribution.
00021 //
00022 // 3. Neither the name of the Corporation nor the names of the
00023 // contributors may be used to endorse or promote products derived from
00024 // this software without specific prior written permission.
00025 //
00026 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00027 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00028 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00029 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00030 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00031 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00032 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00033 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00034 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00035 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00036 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037 //
00038 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00039 //
00040 // ************************************************************************
00041 // @HEADER
00042 */
00043 
00061 
00062 #include <Tpetra_Map.hpp>
00063 #include <Tpetra_Import.hpp>
00064 #include <Tpetra_Util.hpp>
00065 
00066 namespace Tpetra {
00067 namespace Details {
00068 
00075   template<class MapType>
00076   class OptColMap {
00077   public:
00078     typedef MapType map_type;
00079     typedef typename MapType::local_ordinal_type local_ordinal_type;
00080     typedef typename MapType::global_ordinal_type global_ordinal_type;
00081     typedef typename MapType::node_type node_type;
00082     typedef Import<local_ordinal_type,
00083                    global_ordinal_type,
00084                    node_type> import_type;
00085 
00120     static std::pair<map_type, Teuchos::RCP<import_type> >
00121     make (std::ostream& errStream,
00122           bool& lclErr,
00123           const map_type& domMap,
00124           const map_type& colMap,
00125           const import_type* oldImport,
00126           const bool makeImport)
00127     {
00128       using Teuchos::Array;
00129       using Teuchos::ArrayView;
00130       using Teuchos::RCP;
00131       using Teuchos::rcp;
00132       using std::endl;
00133       typedef local_ordinal_type LO;
00134       typedef global_ordinal_type GO;
00135       const char prefix[] = "Tpetra::makeOptimizedColMapAndImport: ";
00136       std::ostream& err = errStream;
00137 
00138       (void) oldImport; // We don't currently use this argument.
00139 
00140       RCP<const Teuchos::Comm<int> > comm = colMap.getComm ();
00141       const LO colMapMinLid = colMap.getMinLocalIndex ();
00142       const LO colMapMaxLid = colMap.getMaxLocalIndex ();
00143 
00144       // Count the numbers of GIDs in colMap that are in and not in
00145       // domMap on the calling process.  Check for zero indices on the
00146       // calling process first, because if it's true, then we shouldn't
00147       // trust [getMinLocalIndex(), getMaxLocalIndex()] to return a
00148       // correct range.
00149       LO numOwnedGids = 0;
00150       LO numRemoteGids = 0;
00151       if (colMap.getNodeNumElements () != 0) {
00152         for (LO colMapLid = colMapMinLid; colMapLid <= colMapMaxLid; ++colMapLid) {
00153           const GO colMapGid = colMap.getGlobalElement (colMapLid);
00154           if (domMap.isNodeLocalElement (colMapGid)) {
00155             ++numOwnedGids;
00156           } else {
00157             ++numRemoteGids;
00158           }
00159         }
00160       }
00161 
00162       // Put all colMap GIDs on the calling process in a single array.
00163       // Owned GIDs go in front, and remote GIDs at the end.
00164       Array<GO> allGids (numOwnedGids + numRemoteGids);
00165       ArrayView<GO> ownedGids = allGids.view (0, numOwnedGids);
00166       ArrayView<GO> remoteGids = allGids.view (numOwnedGids, numRemoteGids);
00167 
00168       // Fill ownedGids and remoteGids (and therefore allGids).  We use
00169       // two loops, one to count (above) and one to fill (here), in
00170       // order to avoid dynamic memory allocation during the loop (in
00171       // this case, lots of calls to push_back()).  That will simplify
00172       // use of Kokkos to parallelize these loops later.
00173       LO ownedPos = 0;
00174       LO remotePos = 0;
00175       if (colMap.getNodeNumElements () != 0) {
00176         for (LO colMapLid = colMapMinLid; colMapLid <= colMapMaxLid; ++colMapLid) {
00177           const GO colMapGid = colMap.getGlobalElement (colMapLid);
00178           if (domMap.isNodeLocalElement (colMapGid)) {
00179             ownedGids[ownedPos++] = colMapGid;
00180           } else {
00181             remoteGids[remotePos++] = colMapGid;
00182           }
00183         }
00184       }
00185 
00186       // If, for some reason, the running count doesn't match the
00187       // orignal count, fill in any remaining GID spots with an
00188       // obviously invalid value.  We don't want to stop yet, because
00189       // other processes might not have noticed this error; Map
00190       // construction is a collective, so we can't stop now.
00191       if (ownedPos != numOwnedGids) {
00192         lclErr = true;
00193         err << prefix << "On Process " << comm->getRank () << ", ownedPos = "
00194             << ownedPos << " != numOwnedGids = " << numOwnedGids << endl;
00195         for (LO colMapLid = ownedPos; colMapLid < numOwnedGids; ++colMapLid) {
00196           ownedGids[colMapLid] = Teuchos::OrdinalTraits<GO>::invalid ();
00197         }
00198       }
00199       if (remotePos != numRemoteGids) {
00200         lclErr = true;
00201         err << prefix << "On Process " << comm->getRank () << ", remotePos = "
00202             << remotePos << " != numRemoteGids = " << numRemoteGids << endl;
00203         for (LO colMapLid = remotePos; colMapLid < numRemoteGids; ++colMapLid) {
00204           remoteGids[colMapLid] = Teuchos::OrdinalTraits<GO>::invalid ();
00205         }
00206       }
00207 
00208       // Figure out what processes own what GIDs in the domain Map.
00209       // Initialize the output array of remote PIDs with the "invalid
00210       // process rank" -1, to help us test whether getRemoteIndexList
00211       // did its job.
00212       Array<int> remotePids (numRemoteGids, -1);
00213       Array<LO> remoteLids;
00214       if (makeImport) {
00215         remoteLids.resize (numRemoteGids);
00216         std::fill (remoteLids.begin (), remoteLids.end (),
00217                    Teuchos::OrdinalTraits<LO>::invalid ());
00218       }
00219       LookupStatus lookupStatus;
00220       if (makeImport) {
00221         lookupStatus = domMap.getRemoteIndexList (remoteGids, remotePids (),
00222                                                   remoteLids ());
00223       } else {
00224         lookupStatus = domMap.getRemoteIndexList (remoteGids, remotePids ());
00225       }
00226 
00227       // If any process returns IDNotPresent, then at least one of the
00228       // remote indices was not present in the domain Map.  This means
00229       // that the Import object cannot be constructed, because of
00230       // incongruity between the column Map and domain Map.  This means
00231       // that either the column Map or domain Map, or both, is
00232       // incorrect.
00233       const bool getRemoteIndexListFailed = (lookupStatus == IDNotPresent);
00234       if (getRemoteIndexListFailed) {
00235         lclErr = true;
00236         err << prefix << "On Process " << comm->getRank () << ", some indices "
00237           "in the input colMap (the original column Map) are not in domMap (the "
00238           "domain Map).  Either these indices or the domain Map is invalid.  "
00239           "Likely cause: For a nonsquare matrix, you must give the domain and "
00240           "range Maps as input to fillComplete." << endl;
00241       }
00242 
00243       // Check that getRemoteIndexList actually worked, by making sure
00244       // that none of the remote PIDs are -1.
00245       for (LO k = 0; k < numRemoteGids; ++k) {
00246         bool foundInvalidPid = false;
00247         if (remotePids[k] == -1) {
00248           foundInvalidPid = true;
00249           break;
00250         }
00251         if (foundInvalidPid) {
00252           lclErr = true;
00253           err << prefix << "On Process " << comm->getRank () << ", "
00254             "getRemoteIndexList returned -1 for the process ranks of "
00255             "one or more GIDs on this process." << endl;
00256         }
00257       }
00258 
00259       // Sort incoming remote column Map indices so that all columns
00260       // coming from a given remote process are contiguous.  This means
00261       // the Import's Distributor doesn't need to reorder data.
00262       if (makeImport) {
00263         sort2 (remotePids.begin (), remotePids.end (), remoteGids.begin ());
00264       }
00265       else {
00266         sort3 (remotePids.begin (), remotePids.end (),
00267                remoteGids.begin (),
00268                remoteLids.begin ());
00269       }
00270       // Make the new column Map.
00271       MapType newColMap (colMap.getGlobalNumElements (), allGids (),
00272                          colMap.getIndexBase (), comm, colMap.getNode ());
00273       // Optionally, make the new Import object.
00274       RCP<import_type> imp;
00275       if (makeImport) {
00276         imp = rcp (new import_type (rcp (new map_type (domMap)),
00277                                     rcp (new map_type (newColMap))));
00278         // FIXME (mfh 06 Jul 2014) This constructor throws a runtime
00279         // error, so I'm not using it for now.
00280         //
00281         // imp = rcp (new import_type (domMap, newColMap, remoteGids,
00282         //                             remotePids (), remoteLids (),
00283         //                             Teuchos::null, Teuchos::null));
00284       }
00285       return std::make_pair (newColMap, imp);
00286     }
00287   };
00288 
00308   template<class MapType>
00309   MapType
00310   makeOptimizedColMap (std::ostream& errStream,
00311                        bool& lclErr,
00312                        const MapType& domMap,
00313                        const MapType& colMap)
00314   {
00315     typedef typename MapType::local_ordinal_type LO;
00316     typedef typename MapType::global_ordinal_type GO;
00317     typedef typename MapType::node_type NT;
00318     typedef ::Tpetra::Import<LO, GO, NT> import_type;
00319 
00320     const bool makeImport = false;
00321     std::pair<MapType, Teuchos::RCP<import_type> > ret =
00322       OptColMap<MapType>::make (errStream, lclErr, domMap, colMap,
00323                                 NULL, makeImport);
00324     return ret.first;
00325   }
00326 
00381   template<class MapType>
00382   std::pair<MapType, Teuchos::RCP<typename OptColMap<MapType>::import_type> >
00383   makeOptimizedColMapAndImport (std::ostream& errStream,
00384                                 bool& lclErr,
00385                                 const MapType& domMap,
00386                                 const MapType& colMap,
00387                                 const typename OptColMap<MapType>::import_type* oldImport,
00388                                 const bool makeImport)
00389   {
00390     return OptColMap<MapType>::make (errStream, lclErr, domMap, colMap,
00391                                      oldImport, makeImport);
00392   }
00393 
00394 } // namespace Details
00395 } // namespace Tpetra
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines