Zoltan 2 Version 0.5
IdentifierMap.cpp
Go to the documentation of this file.
00001 // @HEADER
00002 //
00003 // ***********************************************************************
00004 //
00005 //   Zoltan2: A package of combinatorial algorithms for scientific computing
00006 //                  Copyright 2012 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 Karen Devine      (kddevin@sandia.gov)
00039 //                    Erik Boman        (egboman@sandia.gov)
00040 //                    Siva Rajamanickam (srajama@sandia.gov)
00041 //
00042 // ***********************************************************************
00043 //
00044 // @HEADER
00045 //
00046 // Test the IdentifierMap class.
00047 //
00048 //   Test local IDs are implied, not supplied by app.
00049 
00050 #include <Zoltan2_IdentifierMap.hpp>
00051 #include <Zoltan2_TestHelpers.hpp>
00052 
00053 #if 0
00054 #include <string>
00055 #include <ostream>
00056 #include <iostream>
00057 #include <exception>
00058 #include <utility>
00059 #endif
00060 
00061 #include <Teuchos_Comm.hpp>
00062 #include <Teuchos_DefaultComm.hpp>
00063 #include <Teuchos_RCP.hpp>
00064 #include <Teuchos_ArrayRCP.hpp>
00065 #include <Teuchos_Array.hpp>
00066 #include <Teuchos_ArrayView.hpp>
00067 
00068 
00069 using namespace std;
00070 using Teuchos::RCP;
00071 using Teuchos::rcp;
00072 using Teuchos::ArrayRCP;
00073 using Teuchos::Array;
00074 using Teuchos::ArrayView;
00075 using Teuchos::Comm;
00076 
00077 template <typename T>
00078 struct UserIdTraits{
00079   static std::string stringify(T val) {return std::string("INVALID");}
00080 };
00081 
00082 template<>
00083 struct UserIdTraits<std::pair<int, int> >{
00084   static std::string stringify(std::pair<int, int> p) {
00085     ostringstream oss;
00086     oss << "pair(" << p.first << ", " << p.second << ")";
00087     return oss.str();
00088   }
00089 };
00090 
00091 template<>
00092 struct UserIdTraits<long>{
00093   static std::string stringify(long val) {
00094     ostringstream oss;
00095     oss << val;
00096     return oss.str();
00097   }
00098 };
00099 
00100 template<>
00101 struct UserIdTraits<int>{
00102   static std::string stringify(int val) {
00103     ostringstream oss;
00104     oss << val;
00105     return oss.str();
00106   }
00107 };
00108 
00109 template <typename IDMAP>
00110   void testIdMap( RCP<const Comm<int> > &comm,
00111     IDMAP *map, bool gnosAreGids, bool gnosAreConsecutive,
00112     ArrayRCP<typename IDMAP::gid_t> &gids, 
00113     ArrayRCP<typename IDMAP::gid_t> &remoteGids,
00114     bool verbose)
00115 {
00116   typedef typename IDMAP::lno_t LNO;
00117   typedef typename IDMAP::gno_t GNO;
00118   typedef typename IDMAP::gid_t GID;
00119 
00120   int rank = comm->getRank();
00121   int nprocs = comm->getSize();
00122 
00123   int fail = 0;
00124 
00125   if (map->gnosAreGids() != gnosAreGids)
00126     fail = 1;
00127 
00128   TEST_FAIL_AND_THROW(*comm, fail==0, "gnosAreGids")
00129 
00130   if (map->gnosAreConsecutive() != gnosAreConsecutive)
00131     fail = 1;
00132 
00133   TEST_FAIL_AND_THROW(*comm, fail==0, "consecutiveGids")
00134 
00135   // Get Zoltan2's global numbers given user global Ids
00136 
00137   size_t nLocalIds = gids.size();
00138   Array<GNO> z2Ids(nLocalIds);
00139 
00140   try {
00141     map->gidTranslate(gids(), z2Ids(), Zoltan2::TRANSLATE_APP_TO_LIB);
00142   }
00143   catch (std::exception &e){
00144     fail = 2;
00145   }
00146 
00147   TEST_FAIL_AND_THROW(*comm, fail==0, "gidTranslate")
00148 
00149   if (verbose){
00150     comm->barrier();
00151     if (rank == 0)
00152       std::cout << "Zoltan2 GNOs = User GIDs: " << gnosAreGids << std::endl;
00153     for (int p=0; p < nprocs; p++){
00154       if (p == rank){
00155         std::cout << "Rank " << p << " gnos: ";
00156         for (size_t i=0; i < nLocalIds; i++){
00157           std::cout << z2Ids[i] << " ";
00158         }
00159         std::cout << std::endl;
00160         std::cout.flush();
00161       }
00162       comm->barrier();
00163     }
00164     comm->barrier();
00165     if (rank == 0){
00166       std::cout << "MIN GNO " << map->getMinimumGlobalId();
00167       std::cout << ", MAX GNO " << map->getMaximumGlobalId() << std::endl;
00168       std::cout.flush();
00169     }
00170     comm->barrier();
00171   }
00172 
00173   // Get Zoltan2's global numbers given user local indices 
00174 
00175   Array<GNO> z2Ids2(nLocalIds);
00176   Array<LNO> indices(nLocalIds);
00177 
00178   for (LNO i=nLocalIds-1,j=0; i >= 0; i--,j++){
00179     indices[j] = i;
00180   }
00181    
00182 
00183   try {
00184     map->lnoTranslate(indices(), z2Ids2(), Zoltan2::TRANSLATE_APP_TO_LIB);
00185   }
00186   catch (std::exception &e){
00187     fail = 3;
00188   }
00189 
00190   TEST_FAIL_AND_THROW(*comm, fail==0, "lidTranslate")
00191 
00192   for (LNO i=nLocalIds-1, j=0; i >= 0; i--, j++){
00193     if (z2Ids2[j] != z2Ids[i]){
00194        fail = 4;
00195        break;
00196     }
00197   }
00198 
00199   TEST_FAIL_AND_THROW(*comm, fail==0, "lnoTranslate results")
00200 
00201   // Get User's global Ids give Zoltan2's global numbers
00202 
00203   Array<GID> userGids(nLocalIds);
00204 
00205   try {
00206     map->gidTranslate(userGids(), z2Ids(), Zoltan2::TRANSLATE_LIB_TO_APP);
00207   }
00208   catch (std::exception &e){
00209     fail = 5;
00210   }
00211 
00212   TEST_FAIL_AND_THROW(*comm, fail==0, "gidTranslate 2")
00213 
00214   for (size_t i=0; i < nLocalIds; i++){
00215     if (userGids[i] != gids[i]){
00216        fail = 6;
00217        break;
00218     }
00219   }
00220 
00221   TEST_FAIL_AND_THROW(*comm, fail==0, "gidTranslate 2 results")
00222 
00223   if (nprocs > 1){
00224     // Get Zoltan2 global number and owner of some remote User global Ids
00225     size_t nRemoteIds = remoteGids.size();
00226     Array<GNO> remoteGno(nRemoteIds);
00227     Array<int> remoteProc(nRemoteIds);
00228   
00229     try {
00230       map->gidGlobalTranslate(remoteGids(), remoteGno(), remoteProc());
00231     }
00232     catch (std::exception &e){
00233       fail = 7;
00234     }
00235 
00236     TEST_FAIL_AND_THROW(*comm, fail==0, "gidGLobalTranslate")
00237   
00238     if (verbose){
00239       comm->barrier();
00240       for (int p=0; p < nprocs; p++){
00241         if (rank == 0)
00242           std::cout << "Global info obtained from map:" << std::endl;
00243         if (p == rank){
00244           std::cout << "Rank " << p << std::endl;
00245           for (size_t i=0; i < nRemoteIds; i++){
00246             std::cout << "  GID: ";
00247             std::cout << UserIdTraits<GID>::stringify(remoteGids[i]);
00248             std::cout << ", GNO " << remoteGno[i];
00249             std::cout << ", Owner " << remoteProc[i] << std::endl;
00250           }
00251           std::cout << std::endl;
00252           std::cout.flush();
00253         }
00254         comm->barrier();
00255       }
00256       comm->barrier();
00257     }
00258   }
00259 }
00260 
00261 int main(int argc, char *argv[])
00262 {
00263   Teuchos::GlobalMPISession session(&argc, &argv);
00264   RCP<const Comm<int> > comm = Teuchos::DefaultComm<int>::getComm();
00265   int nprocs = comm->getSize();
00266   int rank = comm->getRank();
00267   RCP<const Zoltan2::Environment> env = rcp(new Zoltan2::Environment);
00268 
00269   lno_t numLocalObjects = 10;
00270   long numRemoteObjects = 3;   // numRemoteObjects < numLocalObjects
00271   bool verbose = true;
00272   bool consecutiveGids=true;
00273   bool gnosAreGids=true;
00274 
00275   // Test these cases:
00276   // 1. GIDs are non-consecutive ordinals
00277   // 2. GIDs are non-consecutive ordinals, but we ask IdentifierMap to
00278   //    map them to consecutive IDs
00279   // 3. GIDs are consecutive ordinals
00280   // 4. GIDs are not Teuchos Ordinals
00281 
00282   ArrayRCP<gno_t> gids(new gno_t [numLocalObjects], 0, numLocalObjects, true);
00283   ArrayRCP<gno_t> remoteGids(new gno_t [numRemoteObjects], 0, 
00284     numRemoteObjects, true);
00285 
00286   using Zoltan2::IdentifierMap;
00287 
00288   typedef Zoltan2::BasicUserTypes<scalar_t, gno_t, lno_t, gno_t> UserTypes;
00289 
00291   //  Ids are non-consecutive ordinals.
00292 
00293   gno_t base1 = 10000 * rank;
00294   gno_t base2 = base1 + 5000;
00295   int fail = 0;
00296   gno_t base = base1;
00297 
00298   for (lno_t i=0; i < numLocalObjects; i++){
00299     gids[i] = base + i;   
00300     if (i == numLocalObjects/2) base = base2;
00301   }
00302 
00303   typedef IdentifierMap<UserTypes> idmap_t;
00304 
00305   idmap_t *idMap = NULL;
00306 
00307   try{
00308     idMap = new idmap_t(env, comm, gids, false);
00309   }
00310   catch (std::exception &e){
00311     std::cerr << rank << ") " << e.what() << std::endl;
00312     fail = 1; 
00313   }
00314   TEST_FAIL_AND_EXIT(*comm, fail==0, "constructor first case", 1);
00315 
00316   if (nprocs > 1){
00317     int remoteProc = (rank ? rank-1 : nprocs-1);
00318     base = remoteProc * 10000;
00319     for (int i=0; i < numRemoteObjects; i++)
00320       remoteGids[i] = base + i;
00321   }
00322 
00323   // We're not asking IdentifierMap to create consecutive
00324   // IDs, so Zoltan2 GNOs will be the User's GIDs, and
00325   // we will not have consecutive GNOs.
00326 
00327   testIdMap(comm, idMap, gnosAreGids, !consecutiveGids, 
00328     gids, remoteGids, verbose);
00329 
00330   delete idMap;
00331 
00333   //  Ids are non-consecutive ordinals.  
00334   //  IdentifierMap is asked to map them to consecutive.
00335 
00336   try{
00337     idMap = new idmap_t(env, comm, gids, true); 
00338   }
00339   catch (std::exception &e){
00340     std::cerr << rank << ") " << e.what() << std::endl;
00341     fail = 1; 
00342   }
00343   TEST_FAIL_AND_EXIT(*comm, fail==0, "constructor second case", 1);
00344 
00345   // Because we're asking IdentifierMap to make the Zoltan2 GNOs
00346   // consecutive, the GNOs will not be the same as the user GIDs.
00347   // And because we specifically asked for consecutive GNOs, we
00348   // will have consecutive global Ids.
00349 
00350   testIdMap(comm, idMap, !gnosAreGids, consecutiveGids, 
00351     gids, remoteGids, verbose);
00352 
00353   delete idMap;
00354 
00356   //  Ids are consecutive ordinals.  
00357 
00358   base = rank * numLocalObjects;
00359   for (lno_t i=0; i < numLocalObjects; i++){
00360     gids[i] = base + i;   
00361   }
00362 
00363   try{
00364     idMap = new idmap_t(env, comm, gids, false); 
00365   }
00366   catch (std::exception &e){
00367     std::cerr << rank << ") " << e.what() << std::endl;
00368     fail = 1; 
00369   }
00370   TEST_FAIL_AND_EXIT(*comm, fail==0, "constructor third case", 1);
00371 
00372   if (nprocs > 1){
00373     int remoteProc = (rank ? rank-1 : nprocs-1);
00374     base = remoteProc * numLocalObjects;
00375     for (int i=0; i < numRemoteObjects; i++)
00376       remoteGids[i] = base + i;
00377   }
00378 
00379   // Because the User GIDs are ordinals, the Zoltan2 GNOs will be
00380   // the User GIDs. And since the User GIDs are already consecutive,
00381   // the Zoltan2 GNOs are consecutive.
00382 
00383   testIdMap(comm, idMap, gnosAreGids, consecutiveGids, 
00384     gids, remoteGids, verbose);
00385 
00386   delete idMap;
00387 
00388 #if 0
00389 
00390   ArrayRCP<std::pair<int,int> > remoteGidPairs(
00391     new std::pair<int,int> [numRemoteObjects], 0, numRemoteObjects, true);
00392 
00393   // TODO - there is a bug in the IdentifierMap constructor
00394   //   when GIDs are std::pair<int,int>
00396   //  Ids are not ordinals.  
00397   Zoltan2::BasicUserTypes<float, std::pair<int,int>, int, long> UserPairGids;
00398 
00399   ArrayRCP<std::pair<int,int> > nonOrdinalGids(
00400      new std::pair<int,int> [numLocalObjects],
00401      0, numLocalObjects, true);
00402 
00403   for (int i=0; i < numLocalObjects; i++){
00404     nonOrdinalGids[i] = std::pair<int, int>(rank, i);
00405   }
00406 
00407   typedef IdentifierMap<UserPairGids> mapPairGids_t;
00408 
00409   mapPairGids_t *idMap2 = NULL;
00410 
00411   try{
00412     idMap2 = new mapPairGids_t(env, comm, nonOrdinalGids, false); 
00413   }
00414   catch (std::exception &e){
00415     std::cerr << rank << ") " << e.what() << std::endl;
00416     fail = 1; 
00417   }
00418   TEST_FAIL_AND_EXIT(*comm, fail==0, "constructor fourth case", 1);
00419 
00420   if (nprocs > 1){
00421     int remoteProc = (rank ? rank-1 : nprocs-1);
00422     base = remoteProc * numLocalObjects;
00423     for (int i=0; i < numRemoteObjects; i++)
00424       remoteGidPairs[i] = std::pair<int,int>(remoteProc,i);
00425   }
00426 
00427   // Because the User's GIDs are not Teuchos Ordinals, they
00428   // will not be used as Zoltan2 GNOs.  When Zoltan2 creates
00429   // the global Ids for the problem, it creates consecutive
00430   // Ids that begin at 0.
00431 
00432   testIdMap(comm, idMap2, !gnosAreGids, consecutiveGids, 
00433     nonOrdinalGids, remoteGidPairs, verbose);
00434 
00435   delete idMap2;
00436 #endif
00437 
00438   if (rank == 0)
00439     std::cout << "PASS" << std::endl;
00440 }
00441