Zoltan2
Zoltan2_GraphModel.hpp
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 
00050 #ifndef _ZOLTAN2_GRAPHMODEL_HPP_
00051 #define _ZOLTAN2_GRAPHMODEL_HPP_
00052 
00053 #include <Zoltan2_Model.hpp>
00054 #include <Zoltan2_InputTraits.hpp>
00055 #include <Zoltan2_MatrixAdapter.hpp>
00056 #include <Zoltan2_GraphAdapter.hpp>
00057 #include <Zoltan2_IdentifierAdapter.hpp>
00058 #include <Zoltan2_VectorAdapter.hpp>
00059 #include <Zoltan2_StridedData.hpp>
00060 #include <Zoltan2_MeshAdapter.hpp>
00061 
00062 #include <vector>
00063 #include <Teuchos_Hashtable.hpp>
00064 
00065 namespace Zoltan2 {
00066 
00067 
00069 
00105 template <typename User>
00106 size_t removeUndesiredEdges(
00107   const RCP<const Environment> &env,
00108   int myRank,
00109   bool removeSelfEdges,
00110   bool removeOffProcessEdges,
00111   bool removeOffGroupEdges,
00112   ArrayView<const typename InputTraits<User>::zgid_t> &gids,
00113   ArrayView<const typename InputTraits<User>::zgid_t> &gidNbors,
00114   ArrayView<const int> &procIds,
00115   ArrayView<StridedData<typename InputTraits<User>::lno_t,
00116                         typename InputTraits<User>::scalar_t> > &edgeWeights,
00117   ArrayView<const typename InputTraits<User>::lno_t> &offsets,
00118   ArrayRCP<const typename InputTraits<User>::zgid_t> &newGidNbors, // out
00119   typename InputTraits<User>::scalar_t **&newWeights,             // out
00120   ArrayRCP<const typename InputTraits<User>::lno_t> &newOffsets)  // out
00121 {
00122   typedef typename InputTraits<User>::zgid_t zgid_t;
00123   typedef typename InputTraits<User>::scalar_t scalar_t;
00124   typedef typename InputTraits<User>::lno_t lno_t;
00125   size_t numKeep = 0;
00126 
00127   size_t numVtx = offsets.size() - 1;
00128   size_t numNbors = gidNbors.size();
00129 
00130   env->localInputAssertion(__FILE__, __LINE__, "need more input",
00131     (!removeSelfEdges ||
00132       gids.size() >=
00133        static_cast<typename ArrayView<const zgid_t>::size_type>(numVtx))
00134       &&
00135     (!removeOffProcessEdges ||
00136       procIds.size() >=
00137        static_cast<typename ArrayView<const int>::size_type>(numNbors)) &&
00138     (!removeOffGroupEdges ||
00139       procIds.size() >=
00140        static_cast<typename ArrayView<const int>::size_type>(numNbors)),
00141     BASIC_ASSERTION);
00142 
00143   // initialize edge weight array
00144 
00145   newWeights = NULL;
00146   int eDim = edgeWeights.size();
00147 
00148   // count desired edges
00149 
00150   lno_t *offs = new lno_t [numVtx + 1];
00151   env->localMemoryAssertion(__FILE__, __LINE__, numVtx+1, offs);
00152   for (size_t i = 0; i < numVtx+1; i++) offs[i] = 0;
00153   ArrayRCP<const lno_t> offArray = arcp(offs, 0, numVtx+1, true);
00154 
00155   const lno_t *allOffs = offsets.getRawPtr();
00156   const zgid_t *allIds = gidNbors.getRawPtr();
00157 
00158   const zgid_t *vtx = NULL;
00159   const int *proc = NULL;
00160 
00161   if (gids.size() > 0)
00162     vtx = gids.getRawPtr();
00163 
00164   if (procIds.size() > 0)
00165     proc = procIds.getRawPtr();
00166 
00167   offs[0] = 0;
00168   for (size_t i=0; i < numVtx; i++){
00169     offs[i+1] = 0;
00170     zgid_t vid = vtx ? vtx[i] : zgid_t(0);
00171     for (lno_t j=allOffs[i]; j < allOffs[i+1]; j++){
00172       int owner = proc ? proc[j] : 0;
00173       bool keep = (!removeSelfEdges || vid != allIds[j]) &&
00174                (!removeOffProcessEdges || owner == myRank) &&
00175                (!removeOffGroupEdges || owner >= 0);
00176 
00177       if (keep)
00178         offs[i+1]++;
00179     }
00180   }
00181 
00182   // from counters to offsets
00183 
00184   for (size_t i=1; i < numVtx; i++)
00185     offs[i+1] += offs[i];
00186 
00187   numKeep = offs[numVtx];
00188 
00189   // do we need a new neighbor list?
00190 
00191   if (numNbors == numKeep){
00192     newGidNbors = Teuchos::arcpFromArrayView(gidNbors);
00193     newOffsets = Teuchos::arcpFromArrayView(offsets);
00194     return numNbors;
00195   }
00196   else if (numKeep == 0){
00197     newGidNbors = ArrayRCP<const zgid_t>(Teuchos::null);
00198     newOffsets = offArray;
00199     return 0;
00200   }
00201 
00202   // Build the subset neighbor lists (id, weight, and offset).
00203 
00204   zgid_t *newGids = new zgid_t [numKeep];
00205   env->localMemoryAssertion(__FILE__, __LINE__, numKeep, newGids);
00206 
00207   newGidNbors = arcp(newGids, 0, numKeep, true);
00208   newOffsets = offArray;
00209 
00210   if (eDim > 0){
00211     newWeights = new scalar_t * [eDim];
00212     env->localMemoryAssertion(__FILE__, __LINE__, eDim, newWeights);
00213 
00214     if (numKeep) {
00215       for (int w=0; w < eDim; w++){
00216         newWeights[w] = new scalar_t [numKeep];
00217         env->localMemoryAssertion(__FILE__, __LINE__, numKeep, newWeights[w]);
00218       }
00219     }
00220     else {
00221       for (int w=0; w < eDim; w++)
00222         newWeights[w] = NULL;
00223     }
00224   }
00225 
00226   size_t next = 0;
00227   for (size_t i=0; i < numVtx && next < numKeep; i++){
00228     zgid_t vid = vtx ? vtx[i] : zgid_t(0);
00229     for (lno_t j=allOffs[i]; j < allOffs[i+1]; j++){
00230       int owner = proc ? proc[j] : 0;
00231       bool keep = (!removeSelfEdges || vid != allIds[j]) &&
00232                (!removeOffProcessEdges || owner == myRank) &&
00233                (!removeOffGroupEdges || owner >= 0);
00234 
00235       if (keep){
00236         newGids[next] = allIds[j];
00237         for (int w=0; w < eDim; w++){
00238           newWeights[w][next] = edgeWeights[w][j];
00239         }
00240         next++;
00241         if (next == numKeep)
00242           break;
00243 
00244       }  // if (keep)
00245     }
00246   }
00247 
00248   return numKeep;
00249 }
00250 
00252 
00256 template <typename User>
00257 size_t computeLocalEdgeList(
00258   const RCP<const Environment> &env, const RCP<const Comm<int> > &comm,
00259   size_t numLocalEdges,           // local edges
00260   size_t numLocalGraphEdges,      // edges in "local" graph
00261   RCP<const IdentifierMap<User> > &idMap,
00262   ArrayRCP<const typename InputTraits<User>::zgid_t> &allEdgeIds, // in
00263   ArrayRCP<const typename InputTraits<User>::gno_t> &allEdgeGnos, // in
00264   ArrayRCP<int> &allProcs,                                 // in
00265   ArrayRCP<const typename InputTraits<User>::lno_t> &allOffs,    // in
00266   ArrayRCP<StridedData<typename InputTraits<User>::lno_t,
00267                        typename InputTraits<User>::scalar_t> > &allWeights,// in
00268   ArrayRCP<const typename InputTraits<User>::lno_t> &edgeLocalIds, //
00269   ArrayRCP<const typename InputTraits<User>::lno_t> &offsets,      // out
00270   ArrayRCP<StridedData<typename InputTraits<User>::lno_t,
00271     typename InputTraits<User>::scalar_t> > &eWeights)             // out
00272 {
00273   typedef typename InputTraits<User>::zgid_t zgid_t;
00274   typedef typename InputTraits<User>::gno_t gno_t;
00275   typedef typename InputTraits<User>::scalar_t scalar_t;
00276   typedef typename InputTraits<User>::lno_t lno_t;
00277   typedef StridedData<lno_t, scalar_t> input_t;
00278   int rank = comm->getRank();
00279 
00280   bool gnosAreGids = idMap->gnosAreGids();
00281 
00282   edgeLocalIds = ArrayRCP<const lno_t>(Teuchos::null);
00283   eWeights = ArrayRCP<input_t>(Teuchos::null);
00284   offsets = ArrayRCP<const lno_t>(Teuchos::null);
00285 
00286   if (numLocalGraphEdges == 0) {
00287     // Set the offsets array and return
00288     size_t allOffsSize = allOffs.size();
00289     lno_t *offs = new lno_t [allOffsSize];
00290     env->localMemoryAssertion(__FILE__, __LINE__, allOffsSize, offs);
00291     for (size_t i = 0; i < allOffsSize; i++) offs[i] = 0;
00292     offsets = arcp(offs, 0, allOffsSize, true);
00293     return 0;
00294   }
00295 
00296   if (numLocalGraphEdges == numLocalEdges){
00297 
00298     // Entire graph is local.
00299 
00300     lno_t *lnos = new lno_t [numLocalGraphEdges];
00301     env->localMemoryAssertion(__FILE__, __LINE__, numLocalGraphEdges, lnos);
00302     if (comm->getSize() == 1) {
00303       // With one rank, Can use gnos as local index.
00304       if (gnosAreGids)
00305         for (size_t i=0; i < numLocalEdges; i++) lnos[i] = allEdgeIds[i];
00306       else
00307         for (size_t i=0; i < numLocalEdges; i++) lnos[i] = allEdgeGnos[i];
00308     }
00309     else {
00310       ArrayRCP<gno_t> gnoArray;
00311 
00312       if (gnosAreGids){
00313         ArrayRCP<const gno_t> gnosConst =
00314                  arcp_reinterpret_cast<const gno_t>(allEdgeIds);
00315         gnoArray = arcp_const_cast<gno_t>(gnosConst);
00316       }
00317       else {
00318         gnoArray = arcp_const_cast<gno_t>(allEdgeGnos);
00319       }
00320 
00321       // Need to translate to gnos to local indexing
00322       ArrayView<lno_t> lnoView(lnos, numLocalGraphEdges);
00323       try {
00324         idMap->lnoTranslate(lnoView,
00325                             gnoArray.view(0,numLocalGraphEdges),
00326                             TRANSLATE_LIB_TO_APP);
00327       }
00328       Z2_FORWARD_EXCEPTIONS;
00329     }
00330     edgeLocalIds = arcp(lnos, 0, numLocalGraphEdges, true);
00331     offsets = allOffs;
00332     eWeights = allWeights;
00333 
00334   }
00335   else{
00336 
00337     // Create subset list of local graph edges, offsets and weights.
00338 
00339     int nWeightsPerEdge = allWeights.size();
00340 
00341     ArrayRCP<const zgid_t> newEgids;
00342     scalar_t **newWeights = NULL;
00343 
00344     ArrayView<const zgid_t> dummyVtx;
00345     ArrayView<const zgid_t> nborView= allEdgeIds.view(0, numLocalEdges);
00346     ArrayView<const int> nborOwner = allProcs.view(0, numLocalEdges);
00347     ArrayView<input_t> eWgts = allWeights.view(0, nWeightsPerEdge);
00348     ArrayView<const lno_t> offView = allOffs.view(0, allOffs.size());
00349 
00350     try{
00351       numLocalEdges = removeUndesiredEdges<User>(env, rank, false, true, false,
00352                                                  dummyVtx, nborView, nborOwner,
00353                                                  eWgts, offView, newEgids,
00354                                                  newWeights, offsets);
00355     }
00356     Z2_FORWARD_EXCEPTIONS;
00357 
00358     env->localBugAssertion(__FILE__, __LINE__, "local graph miscalculation",
00359       numLocalEdges == numLocalGraphEdges, BASIC_ASSERTION);
00360 
00361     // offsets array was set by removeUndesiredEdges.  Create weight array.
00362 
00363     if (nWeightsPerEdge > 0){
00364       input_t *wgts = new input_t [nWeightsPerEdge];
00365       for (int w=0; w < nWeightsPerEdge; w++){
00366         ArrayRCP<const scalar_t> wgtArray(newWeights[w], 0, numLocalGraphEdges,true);
00367         wgts[w] = input_t(wgtArray, 1);
00368       }
00369       eWeights = arcp(wgts, 0, nWeightsPerEdge);
00370       delete [] newWeights;
00371     }
00372 
00373     // Create local ID array.  First translate gid to gno.
00374     ArrayRCP<gno_t> gnoArray;
00375 
00376     if (gnosAreGids){
00377       ArrayRCP<const gno_t> gnosConst =
00378         arcp_reinterpret_cast<const gno_t>(newEgids);
00379       gnoArray = arcp_const_cast<gno_t>(gnosConst);
00380     }
00381     else{
00382 
00383       ArrayRCP<zgid_t> gidArray = arcp_const_cast<zgid_t>(newEgids);
00384       gno_t *gnoList= new gno_t [numLocalGraphEdges];
00385       env->localMemoryAssertion(__FILE__, __LINE__, numLocalGraphEdges,
00386         gnoList);
00387       gnoArray = arcp(gnoList, 0, numLocalGraphEdges, true);
00388 
00389       try {
00390         idMap->gidTranslate(
00391           gidArray.view(0,numLocalGraphEdges),
00392           gnoArray.view(0,numLocalGraphEdges),
00393           TRANSLATE_APP_TO_LIB);
00394       }
00395       Z2_FORWARD_EXCEPTIONS;
00396     }
00397 
00398     // translate gno to lno
00399 
00400     lno_t *lnoList = new lno_t [numLocalGraphEdges];
00401     env->localMemoryAssertion(__FILE__, __LINE__, numLocalGraphEdges,
00402       lnoList);
00403     ArrayView<lno_t> lnoView(lnoList, numLocalGraphEdges);
00404 
00405     try {
00406       idMap->lnoTranslate(
00407         lnoView,
00408         gnoArray.view(0,numLocalGraphEdges),
00409         TRANSLATE_LIB_TO_APP);
00410     }
00411     Z2_FORWARD_EXCEPTIONS;
00412     edgeLocalIds = arcp<const lno_t>(lnoList, 0, numLocalGraphEdges, true);
00413   }
00414 
00415   return numLocalGraphEdges;
00416 }
00417 
00419 
00428 template <typename Adapter>
00429 class GraphModel : public Model<Adapter>
00430 {
00431 public:
00432 
00433 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00434   typedef typename Adapter::scalar_t    scalar_t;
00435   typedef typename Adapter::gno_t       gno_t;
00436   typedef typename Adapter::lno_t       lno_t;
00437   typedef typename Adapter::zgid_t       zgid_t;
00438   typedef typename Adapter::node_t      node_t;
00439   typedef typename Adapter::user_t      user_t;
00440   typedef typename Adapter::userCoord_t userCoord_t;
00441   typedef IdentifierMap<user_t>         idmap_t;
00442   typedef StridedData<lno_t, scalar_t>  input_t;
00443 #endif
00444 
00446   ~GraphModel() { }
00447 
00459   GraphModel(const MatrixAdapter<user_t,userCoord_t> *ia,
00460     const RCP<const Environment> &env, const RCP<const Comm<int> > &comm,
00461     modelFlag_t &modelFlags);
00462 
00463   GraphModel(const GraphAdapter<user_t,userCoord_t> *ia,
00464     const RCP<const Environment> &env, const RCP<const Comm<int> > &comm,
00465     modelFlag_t &modelFlags);
00466 
00467   GraphModel(const MeshAdapter<user_t> *ia,
00468     const RCP<const Environment> &env, const RCP<const Comm<int> > &comm,
00469     modelFlag_t &modelflags);
00470 
00471   GraphModel(const VectorAdapter<userCoord_t> *ia,
00472     const RCP<const Environment> &env, const RCP<const Comm<int> > &comm,
00473     modelFlag_t &flags)
00474   {
00475     throw std::runtime_error("cannot build GraphModel from VectorAdapter");
00476   }
00477 
00478   GraphModel(const IdentifierAdapter<user_t> *ia,
00479     const RCP<const Environment> &env, const RCP<const Comm<int> > &comm,
00480     modelFlag_t &flags)
00481   {
00482     throw std::runtime_error("cannot build GraphModel from IdentifierAdapter");
00483   }
00484 
00487   size_t getLocalNumVertices() const { return numLocalVertices_; }
00488 
00491   size_t getGlobalNumVertices() const { return numGlobalVertices_; }
00492 
00496   size_t getLocalNumGlobalEdges() const { return numLocalEdges_; }
00497 
00501   size_t getLocalNumLocalEdges() const { return numLocalGraphEdges_; }
00502 
00505   size_t getGlobalNumEdges() const { return numGlobalEdges_; }
00506 
00509   int getNumWeightsPerVertex() const { return numWeightsPerVertex_; }
00510 
00513   int getNumWeightsPerEdge() const { return nWeightsPerEdge_; }
00514 
00517   int getCoordinateDim() const { return vCoordDim_; }
00518 
00529   size_t getVertexList(
00530     ArrayView<const gno_t> &Ids,
00531     ArrayView<input_t> &xyz,
00532     ArrayView<input_t> &wgts) const
00533   {
00534     Ids = ArrayView<const gno_t>();
00535     size_t nv = gids_.size();
00536     if (nv){
00537       if (gnosAreGids_)
00538         Ids = ArrayView<const gno_t>(
00539                         reinterpret_cast<const gno_t*>(gids_.getRawPtr()), nv);
00540       else
00541         Ids = gnosConst_(0, nv);
00542     }
00543 
00544     xyz = vCoords_.view(0, vCoordDim_);
00545     wgts = vWeights_.view(0, numWeightsPerVertex_);
00546     return nv;
00547   }
00548 
00562   // Implied Vertex LNOs from getVertexList are used as indices to offsets
00563   // array.
00564   // Vertex GNOs are returned as neighbors in edgeIds.
00565 
00566   size_t getEdgeList( ArrayView<const gno_t> &edgeIds,
00567     ArrayView<const int> &procIds, ArrayView<const lno_t> &offsets,
00568     ArrayView<input_t> &wgts) const
00569   {
00570     edgeIds = ArrayView<const gno_t>();
00571     if (numLocalEdges_) {
00572       if (gnosAreGids_)
00573         edgeIds = ArrayView<const gno_t>(
00574                         reinterpret_cast<const gno_t*>(edgeGids_.getRawPtr()),
00575                                                        numLocalEdges_);
00576       else
00577         edgeIds = edgeGnosConst_(0, numLocalEdges_);
00578     }
00579 
00580     procIds = procIdsConst_.view(0, numLocalEdges_);
00581     offsets = offsets_.view(0, numLocalVertices_+1);
00582     wgts = eWeights_.view(0, nWeightsPerEdge_);
00583     return numLocalEdges_;
00584   }
00585 
00609   size_t getLocalEdgeList(
00610     ArrayView<const lno_t> &edgeIds,
00611     ArrayView<const lno_t> &offsets,
00612     ArrayView<input_t> &wgts)
00613   {
00614     env_->timerStart(MACRO_TIMERS, "GraphModel::getLocalEdgeList");
00615 
00616     if (localGraphEdgeOffsets_.size() == 0) {
00617       // Local graph not created yet
00618       RCP<const IdentifierMap<user_t> > idmap = this->getIdentifierMap();
00619       computeLocalEdgeList(env_, comm_,
00620         numLocalEdges_, numLocalGraphEdges_,
00621         idmap, edgeGids_, edgeGnosConst_, procIds_, offsets_, eWeights_,
00622         localGraphEdgeLnos_, localGraphEdgeOffsets_, localGraphEdgeWeights_);
00623     }
00624     edgeIds = localGraphEdgeLnos_();
00625     offsets = localGraphEdgeOffsets_();
00626     wgts = localGraphEdgeWeights_();
00627 
00628     env_->timerStop(MACRO_TIMERS, "GraphModel::getLocalEdgeList");
00629 
00630     return numLocalGraphEdges_;
00631   }
00632 
00634   // The Model interface.
00636 
00637   size_t getLocalNumObjects() const { return numLocalVertices_; }
00638 
00639   size_t getGlobalNumObjects() const { return numGlobalVertices_; }
00640 
00641 private:
00642   void shared_constructor(const Adapter *ia, modelFlag_t &modelFlags);
00643 
00644   template <typename AdapterWithCoords>
00645   void shared_GetVertexCoords(const AdapterWithCoords *ia);
00646 
00647   const RCP<const Environment > env_;
00648   const RCP<const Comm<int> > comm_;
00649 
00650   ArrayRCP<const zgid_t> gids_;        // vertices of input graph
00651   ArrayRCP<gno_t> gnos_;
00652 
00653   int numWeightsPerVertex_;
00654   ArrayRCP<input_t> vWeights_;
00655 
00656   int vCoordDim_;
00657   ArrayRCP<input_t> vCoords_;
00658 
00659   // Note: in case of graph subsetting, size of these arrays
00660   // may be larger than numLocalEdges_.  So do not use .size().
00661 
00662   ArrayRCP<const zgid_t> edgeGids_;
00663   ArrayRCP<gno_t> edgeGnos_;
00664   ArrayRCP<int> procIds_;
00665   ArrayRCP<const lno_t> offsets_;
00666 
00667   int nWeightsPerEdge_;
00668   ArrayRCP<input_t> eWeights_;
00669 
00670   ArrayRCP<const gno_t> gnosConst_;
00671   ArrayRCP<const gno_t> edgeGnosConst_;
00672   ArrayRCP<const int> procIdsConst_;
00673 
00674   bool gnosAreGids_;
00675 
00676   // For local graphs (graph restricted to local process).  We
00677   // create these arrays only if required by the algorithm.
00678 
00679   ArrayRCP<const lno_t> localGraphEdgeLnos_;
00680   ArrayRCP<const lno_t> localGraphEdgeOffsets_;
00681   ArrayRCP<input_t> localGraphEdgeWeights_;
00682 
00683   // For convenience
00684 
00685   size_t numLocalVertices_;
00686   size_t numGlobalVertices_;
00687   size_t numLocalEdges_;
00688   size_t numGlobalEdges_;
00689   size_t numLocalGraphEdges_;
00690 
00691   // For debugging
00692   void print();
00693 };
00694 
00695 
00697 template <typename Adapter>
00698 GraphModel<Adapter>::GraphModel(
00699   const MatrixAdapter<user_t,userCoord_t> *ia,
00700   const RCP<const Environment> &env,
00701   const RCP<const Comm<int> > &comm,
00702   modelFlag_t &modelFlags):
00703        env_(env),
00704        comm_(comm),
00705        gids_(),
00706        gnos_(),
00707        numWeightsPerVertex_(0),
00708        vWeights_(),
00709        vCoordDim_(0),
00710        vCoords_(),
00711        edgeGids_(),
00712        edgeGnos_(),
00713        procIds_(),
00714        offsets_(),
00715        nWeightsPerEdge_(0),
00716        eWeights_(),
00717        gnosConst_(),
00718        edgeGnosConst_(),
00719        procIdsConst_(),
00720        gnosAreGids_(false),
00721        localGraphEdgeLnos_(),
00722        localGraphEdgeOffsets_(),
00723        localGraphEdgeWeights_(),
00724        numLocalVertices_(0),
00725        numGlobalVertices_(0),
00726        numLocalEdges_(0),
00727        numGlobalEdges_(0),
00728        numLocalGraphEdges_(0)
00729 {
00730   // Model creation flags
00731   bool symTranspose = modelFlags.test(SYMMETRIZE_INPUT_TRANSPOSE);
00732   bool symBipartite = modelFlags.test(SYMMETRIZE_INPUT_BIPARTITE);
00733   bool vertexCols = modelFlags.test(VERTICES_ARE_MATRIX_COLUMNS);
00734   bool vertexNz = modelFlags.test(VERTICES_ARE_MATRIX_NONZEROS);
00735 
00736   if (symTranspose || symBipartite || vertexCols || vertexNz){
00737     throw std::runtime_error("graph build option not yet implemented");
00738   }
00739 
00740   // Get the matrix from the input adapter
00741   zgid_t const *vtxIds=NULL, *nborIds=NULL;
00742   lno_t const *offsets=NULL;
00743   try{
00744     numLocalVertices_ = ia->getLocalNumIDs();
00745     ia->getIDsView(vtxIds);
00746   }
00747   Z2_FORWARD_EXCEPTIONS;
00748   try{
00749     if (ia->CRSViewAvailable()) {
00750       ia->getCRSView(offsets, nborIds);
00751     }
00752     else {
00753       // TODO:  Add support for CCS matrix layout
00754       throw std::runtime_error("Only MatrixAdapter::getCRSView is supported "
00755                                "in graph model");
00756     }
00757   }
00758   Z2_FORWARD_EXCEPTIONS;
00759 
00760   numLocalEdges_ = offsets[numLocalVertices_];
00761 
00762   gids_ = arcp<const zgid_t>(vtxIds, 0, numLocalVertices_, false);
00763   edgeGids_ = arcp<const zgid_t>(nborIds, 0, numLocalEdges_, false);
00764   offsets_ = arcp<const lno_t>(offsets, 0, numLocalVertices_ + 1, false);
00765 
00766   nWeightsPerEdge_ = 0;   // no edge weights from a matrix yet.
00767                      // TODO:  use matrix values as edge weights
00768 
00769   shared_constructor(ia, modelFlags);
00770 
00771   // Get vertex coordinates, if available
00772   if (ia->coordinatesAvailable()) {
00773     typedef VectorAdapter<userCoord_t> adapterWithCoords_t;
00774     shared_GetVertexCoords<adapterWithCoords_t>(ia->getCoordinateInput());
00775   }
00776   //print();
00777 }
00778 
00779 
00781 template <typename Adapter>
00782 GraphModel<Adapter>::GraphModel(
00783   const GraphAdapter<user_t,userCoord_t> *ia,
00784   const RCP<const Environment> &env,
00785   const RCP<const Comm<int> > &comm,
00786   modelFlag_t &modelFlags):
00787        env_(env),
00788        comm_(comm),
00789        gids_(),
00790        gnos_(),
00791        numWeightsPerVertex_(0),
00792        vWeights_(),
00793        vCoordDim_(0),
00794        vCoords_(),
00795        edgeGids_(),
00796        edgeGnos_(),
00797        procIds_(),
00798        offsets_(),
00799        nWeightsPerEdge_(0),
00800        eWeights_(),
00801        gnosConst_(),
00802        edgeGnosConst_(),
00803        procIdsConst_(),
00804        gnosAreGids_(false),
00805        localGraphEdgeLnos_(),
00806        localGraphEdgeOffsets_(),
00807        localGraphEdgeWeights_(),
00808        numLocalVertices_(0),
00809        numGlobalVertices_(0),
00810        numLocalEdges_(0),
00811        numGlobalEdges_(0),
00812        numLocalGraphEdges_(0)
00813 {
00814 
00815   // This GraphModel is built with vertices == GRAPH_VERTEX from GraphAdapter.
00816   // It is not ready to use vertices == GRAPH_EDGE from GraphAdapter.
00817   env_->localInputAssertion(__FILE__, __LINE__,
00818     "GraphModel from GraphAdapter is implemented only for "
00819     "Graph Vertices as primary object, not for Graph Edges",
00820     ia->getPrimaryEntityType() == Zoltan2::GRAPH_VERTEX, BASIC_ASSERTION);
00821 
00822   // Get the graph from the input adapter
00823 
00824   zgid_t const *vtxIds=NULL, *nborIds=NULL;
00825   lno_t const *offsets=NULL;
00826   try{
00827     numLocalVertices_ = ia->getLocalNumVertices();
00828     ia->getVertexIDsView(vtxIds);
00829     ia->getEdgesView(offsets, nborIds);
00830   }
00831   Z2_FORWARD_EXCEPTIONS;
00832 
00833   numLocalEdges_ = offsets[numLocalVertices_];
00834 
00835   gids_ = arcp<const zgid_t>(vtxIds, 0, numLocalVertices_, false);
00836   edgeGids_ = arcp<const zgid_t>(nborIds, 0, numLocalEdges_, false);
00837   offsets_ = arcp<const lno_t>(offsets, 0, numLocalVertices_ + 1, false);
00838 
00839   nWeightsPerEdge_ = ia->getNumWeightsPerEdge();
00840 
00841   if (nWeightsPerEdge_ > 0){
00842     input_t *wgts = new input_t [nWeightsPerEdge_];
00843     eWeights_ = arcp(wgts, 0, nWeightsPerEdge_, true);
00844   }
00845 
00846   for (int w=0; w < nWeightsPerEdge_; w++){
00847     const scalar_t *ewgts=NULL;
00848     int stride=0;
00849 
00850     ia->getEdgeWeightsView(ewgts, stride, w);
00851 
00852     ArrayRCP<const scalar_t> wgtArray(ewgts, 0, numLocalEdges_, false);
00853     eWeights_[w] = input_t(wgtArray, stride);
00854   }
00855 
00856   shared_constructor(ia, modelFlags);
00857 
00858   // Get vertex coordinates, if available
00859   if (ia->coordinatesAvailable()) {
00860     typedef VectorAdapter<userCoord_t> adapterWithCoords_t;
00861     shared_GetVertexCoords<adapterWithCoords_t>(ia->getCoordinateInput());
00862   }
00863   //print();
00864 }
00865 
00867 template <typename Adapter>
00868 GraphModel<Adapter>::GraphModel(
00869   const MeshAdapter<user_t> *ia,
00870   const RCP<const Environment> &env,
00871   const RCP<const Comm<int> > &comm,
00872   modelFlag_t &modelFlags):
00873        env_(env),
00874        comm_(comm),
00875        gids_(),
00876        gnos_(),
00877        numWeightsPerVertex_(0),
00878        vWeights_(),
00879        vCoordDim_(0),
00880        vCoords_(),
00881        edgeGids_(),
00882        edgeGnos_(),
00883        procIds_(),
00884        offsets_(),
00885        nWeightsPerEdge_(0),
00886        eWeights_(),
00887        gnosConst_(),
00888        edgeGnosConst_(),
00889        procIdsConst_(),
00890        gnosAreGids_(false),
00891        localGraphEdgeLnos_(),
00892        localGraphEdgeOffsets_(),
00893        localGraphEdgeWeights_(),
00894        numLocalVertices_(0),
00895        numGlobalVertices_(0),
00896        numLocalEdges_(0),
00897        numGlobalEdges_(0),
00898        numLocalGraphEdges_(0)
00899 {
00900   env_->timerStart(MACRO_TIMERS, "GraphModel constructed from MeshAdapter");
00901 
00902   // This GraphModel is built with vertices == ia->getPrimaryEntityType()
00903   // from MeshAdapter.
00904 
00905   // Get the graph from the input adapter
00906 
00907   Zoltan2::MeshEntityType primaryEType = ia->getPrimaryEntityType();
00908   Zoltan2::MeshEntityType secondAdjEType = ia->getSecondAdjacencyEntityType();
00909 
00910   // Get the IDs of the primary entity type; these are graph vertices
00911 
00912   zgid_t const *vtxIds=NULL;
00913   try {
00914     numLocalVertices_ = ia->getLocalNumOf(primaryEType);
00915     ia->getIDsViewOf(primaryEType, vtxIds);
00916   }
00917   Z2_FORWARD_EXCEPTIONS;
00918 
00919   gids_ = arcp<const zgid_t>(vtxIds, 0, numLocalVertices_, false);
00920 
00921   // Get the second adjacencies to construct edges of the dual graph.
00922   // TODO:  Enable building the graph from 1st adjacencies
00923 
00924   zgid_t const *nborIds=NULL;
00925   lno_t const *offsets=NULL;
00926 
00927   if (!ia->avail2ndAdjs(primaryEType, secondAdjEType)) {
00928 
00929     throw std::logic_error("MeshAdapter must provide 2nd adjacencies for "
00930                            "graph construction");
00931 
00932   }
00933   else {  // avail2ndAdjs
00934 
00935     // Get the edges
00936     try {
00937       ia->get2ndAdjsView(primaryEType, secondAdjEType, offsets, nborIds);
00938     }
00939     Z2_FORWARD_EXCEPTIONS;
00940 
00941     numLocalEdges_ = offsets[numLocalVertices_];
00942 
00943     edgeGids_ = arcp<const zgid_t>(nborIds, 0, numLocalEdges_, false);
00944     offsets_ = arcp<const lno_t>(offsets, 0, numLocalVertices_ + 1, false);
00945 
00946     // Get edge weights
00947     nWeightsPerEdge_ = ia->getNumWeightsPer2ndAdj(primaryEType, secondAdjEType);
00948 
00949     if (nWeightsPerEdge_ > 0){
00950       input_t *wgts = new input_t [nWeightsPerEdge_];
00951       eWeights_ = arcp(wgts, 0, nWeightsPerEdge_, true);
00952     }
00953 
00954     for (int w=0; w < nWeightsPerEdge_; w++){
00955       const scalar_t *ewgts=NULL;
00956       int stride=0;
00957 
00958       ia->get2ndAdjWeightsView(primaryEType, secondAdjEType,
00959                                ewgts, stride, w);
00960 
00961       ArrayRCP<const scalar_t> wgtArray(ewgts, 0, numLocalEdges_, false);
00962       eWeights_[w] = input_t(wgtArray, stride);
00963     }
00964   }
00965 
00966   shared_constructor(ia, modelFlags);
00967 
00968   typedef MeshAdapter<user_t> adapterWithCoords_t;
00969   shared_GetVertexCoords<adapterWithCoords_t>(ia);
00970 
00971   env_->timerStop(MACRO_TIMERS, "GraphModel constructed from MeshAdapter");
00972   print();
00973 }
00974 
00976 template <typename Adapter>
00977 void GraphModel<Adapter>::shared_constructor(
00978   const Adapter *ia,
00979   modelFlag_t &modelFlags)
00980 {
00981   // Model creation flags
00982   bool consecutiveIdsRequired =
00983     modelFlags.test(IDS_MUST_BE_GLOBALLY_CONSECUTIVE);
00984   bool removeSelfEdges = modelFlags.test(SELF_EDGES_MUST_BE_REMOVED);
00985   bool subsetGraph = modelFlags.test(GRAPH_IS_A_SUBSET_GRAPH);
00986 
00987   // A subset graph is special in that it may contain neighbor
00988   // vertices that are not owned by processes in this communicator.
00989   // We remove these.
00990 
00991   ArrayRCP<const int> nborProcs;
00992 
00993   if (subsetGraph){
00994     RCP<const idmap_t> idMap;
00995     try{
00996       idMap = rcp(new idmap_t(env_, comm_, gids_, false));
00997     }
00998     Z2_FORWARD_EXCEPTIONS;
00999 
01000     ArrayRCP<int> procArray;
01001 
01002     if (numLocalEdges_ > 0){
01003       int *pids = new int [numLocalEdges_];
01004       env_->localMemoryAssertion(__FILE__, __LINE__, numLocalEdges_, pids);
01005       procArray = arcp(pids, 0, numLocalEdges_, true);
01006     }
01007 
01008     ArrayView<gno_t> dummyGno;
01009 
01010     try{
01011       // All processes must make this call.
01012       // procOwner will be -1 if edge Id is not in our communicator.
01013 
01014       idMap->gidGlobalTranslate( edgeGids_.view(0, numLocalEdges_),
01015         dummyGno, procArray.view(0, numLocalEdges_));
01016     }
01017     Z2_FORWARD_EXCEPTIONS;
01018 
01019     int outOfSubset = 0;
01020     for (size_t i=0; i < numLocalEdges_; i++){
01021       if (procArray[i] < 0){
01022         outOfSubset++;
01023         break;
01024       }
01025     }
01026 
01027     if (outOfSubset == 0){
01028       procArray.clear();
01029       subsetGraph = false;
01030     }
01031     else{
01032       nborProcs = arcp_const_cast<const int>(procArray);
01033     }
01034   }
01035 
01036   // Now remove undesired edges.
01037 
01038   if (subsetGraph || removeSelfEdges){
01039 
01040     ArrayRCP<const zgid_t> newEdges;
01041     ArrayRCP<const lno_t> newOffs;
01042     scalar_t **newWeights = NULL;
01043     size_t numNewEdges = 0;
01044 
01045     ArrayView<const zgid_t> vtxView = gids_.view(0, numLocalVertices_);
01046     ArrayView<const zgid_t> nborView= edgeGids_.view(0, numLocalEdges_);
01047     ArrayView<const int> nborOwner = nborProcs.view(0, nborProcs.size());
01048     ArrayView<input_t> eWgts = eWeights_.view(0, nWeightsPerEdge_);
01049     ArrayView<const lno_t> offView = offsets_.view(0, numLocalVertices_ + 1);
01050 
01051     try{
01052       numNewEdges = removeUndesiredEdges<user_t>(env_, comm_->getRank(),
01053         removeSelfEdges,
01054         false,
01055         subsetGraph,
01056         vtxView,
01057         nborView,
01058         nborOwner,
01059         eWgts,
01060         offView,
01061         newEdges,
01062         newWeights,
01063         newOffs);
01064     }
01065     Z2_FORWARD_EXCEPTIONS;
01066 
01067     nborProcs.clear();
01068 
01069     if (numNewEdges < numLocalEdges_){
01070       edgeGids_ = newEdges;
01071       offsets_ = newOffs;
01072       numLocalEdges_ = numNewEdges;
01073 
01074       for (int w=0; w < nWeightsPerEdge_; w++){
01075         ArrayRCP<const scalar_t> wgtArray(newWeights[w], 0, numNewEdges, true);
01076         eWeights_[w] = input_t(wgtArray, 1);
01077       }
01078     }
01079     delete [] newWeights;
01080   }
01081 
01082   // Create an IdentifierMap, which maps the user's global IDs to
01083   //   Zoltan2 internal global numbers if necessary.
01084   //   The map can also give us owners of our vertex neighbors.
01085 
01086   RCP<const idmap_t> idMap;
01087 
01088   try{
01089     idMap = rcp(new idmap_t(env_, comm_, gids_, consecutiveIdsRequired));
01090   }
01091   Z2_FORWARD_EXCEPTIONS;
01092 
01093   // Model base class needs to have IdentifierMap.
01094 
01095   this->setIdentifierMap(idMap);
01096 
01097   numGlobalVertices_ = idMap->getGlobalNumberOfIds();
01098   gnosAreGids_ = idMap->gnosAreGids();
01099 
01100   // Compute internal global numbers if we can not use the
01101   // user's global Ids.  Also find the process owning each
01102   // neighboring vertex.
01103 
01104   ArrayView<const zgid_t> gidArray(Teuchos::null);  // edge gid
01105   ArrayView<gno_t> gnoArray(Teuchos::null);        // edge gno
01106   ArrayView<int> procArray(Teuchos::null);         // edge owner
01107 
01108   if (numLocalVertices_){
01109 
01110     if (!gnosAreGids_){   // need vertex global numbers, edge global numbers
01111       gno_t *tmp = new gno_t [numLocalVertices_];
01112       env_->localMemoryAssertion(__FILE__, __LINE__, numLocalVertices_, tmp);
01113       gnos_ = arcp(tmp, 0, numLocalVertices_);
01114 
01115       try{
01116         ArrayRCP<zgid_t> tmpGids = arcp_const_cast<zgid_t>(gids_);
01117 
01118         idMap->gidTranslate(tmpGids(0,numLocalVertices_),
01119           gnos_(0,numLocalVertices_), TRANSLATE_APP_TO_LIB);
01120       }
01121       Z2_FORWARD_EXCEPTIONS;
01122 
01123       if (numLocalEdges_){
01124         tmp = new gno_t [numLocalEdges_];
01125         env_->localMemoryAssertion(__FILE__, __LINE__, numLocalEdges_, tmp);
01126         edgeGnos_ = arcp(tmp, 0, numLocalEdges_);
01127         gnoArray = edgeGnos_.view(0, numLocalEdges_);
01128       }
01129     }
01130 
01131     if (numLocalEdges_){
01132       gidArray = edgeGids_.view(0, numLocalEdges_);
01133 
01134       int *p = new int [numLocalEdges_];
01135       env_->localMemoryAssertion(__FILE__, __LINE__, numLocalEdges_, p);
01136       procIds_ = arcp(p, 0, numLocalEdges_);
01137       procArray = procIds_.view(0, numLocalEdges_);
01138     }
01139   }
01140 
01141   try{
01142     // All processes must make this call.
01143     idMap->gidGlobalTranslate(gidArray, gnoArray, procArray);
01144   }
01145   Z2_FORWARD_EXCEPTIONS;
01146 
01147   gnosConst_ = arcp_const_cast<const gno_t>(gnos_);
01148   edgeGnosConst_ = arcp_const_cast<const gno_t>(edgeGnos_);
01149   procIdsConst_ = arcp_const_cast<const int>(procIds_);
01150 
01151   // Number of edges such that neighbor is on the local process.
01152   // We only create the list of local graph edges if the user
01153   // calls getLocalEdgeList().
01154 
01155   numLocalGraphEdges_ = 0;
01156   int *pids = procArray.getRawPtr();
01157   int me = comm_->getRank();
01158   for (size_t i=0; i < numLocalEdges_; i++)
01159     if (pids[i] == me) numLocalGraphEdges_++;
01160 
01161   // Vertex weights
01162 
01163   numWeightsPerVertex_ = ia->getNumWeightsPerID();
01164 
01165   if (numWeightsPerVertex_ > 0){
01166     input_t *weightInfo = new input_t [numWeightsPerVertex_];
01167     env_->localMemoryAssertion(__FILE__, __LINE__, numWeightsPerVertex_,
01168                                weightInfo);
01169 
01170     for (int idx=0; idx < numWeightsPerVertex_; idx++){
01171       bool useNumNZ = ia->useDegreeAsWeight(idx);
01172       if (useNumNZ){
01173         scalar_t *wgts = new scalar_t [numLocalVertices_];
01174         env_->localMemoryAssertion(__FILE__, __LINE__, numLocalVertices_, wgts);
01175         ArrayRCP<const scalar_t> wgtArray =
01176           arcp(wgts, 0, numLocalVertices_, true);
01177         for (size_t i=0; i < numLocalVertices_; i++){
01178           wgts[i] = offsets_[i+1] - offsets_[i];
01179         }
01180         weightInfo[idx] = input_t(wgtArray, 1);
01181       }
01182       else{
01183         const scalar_t *weights=NULL;
01184         int stride=0;
01185         ia->getWeightsView(weights, stride, idx);
01186         ArrayRCP<const scalar_t> wgtArray = arcp(weights, 0,
01187                                                  stride*numLocalVertices_,
01188                                                  false);
01189         weightInfo[idx] = input_t(wgtArray, stride);
01190       }
01191     }
01192 
01193     vWeights_ = arcp<input_t>(weightInfo, 0, numWeightsPerVertex_, true);
01194   }
01195 
01196 
01197   reduceAll<int, size_t>(*comm_, Teuchos::REDUCE_SUM, 1,
01198     &numLocalEdges_, &numGlobalEdges_);
01199 
01200   env_->memory("After construction of graph model");
01201 }
01202 
01204 
01205 template <typename Adapter>
01206 template <typename AdapterWithCoords>
01207 void GraphModel<Adapter>::shared_GetVertexCoords(const AdapterWithCoords *ia)
01208 {
01209   // get Vertex coordinates from input adapter
01210 
01211   vCoordDim_ = ia->getDimension();
01212 
01213   if (vCoordDim_ > 0){
01214     input_t *coordInfo = new input_t [vCoordDim_];
01215     env_->localMemoryAssertion(__FILE__, __LINE__, vCoordDim_, coordInfo);
01216 
01217     for (int dim=0; dim < vCoordDim_; dim++){
01218       const scalar_t *coords=NULL;
01219       int stride=0;
01220       ia->getCoordinatesView(coords, stride, dim);
01221       ArrayRCP<const scalar_t> coordArray = arcp(coords, 0,
01222                                                  stride*numLocalVertices_,
01223                                                  false);
01224       coordInfo[dim] = input_t(coordArray, stride);
01225     }
01226 
01227     vCoords_ = arcp<input_t>(coordInfo, 0, vCoordDim_, true);
01228   }
01229 }
01230 
01232   template <typename Adapter>
01233 void GraphModel<Adapter>::print()
01234 {
01235   if (env_->getDebugLevel() < VERBOSE_DETAILED_STATUS)
01236     return;
01237 
01238   std::ostream *os = env_->getDebugOStream();
01239   
01240   int me = comm_->getRank();
01241   std::string fn(" ");
01242 
01243   *os << me << fn
01244       << " Nvtx  " << gids_.size()
01245       << " Nedge " << edgeGids_.size()
01246       << " NLocalEdge " << numLocalGraphEdges_
01247       << " NVWgt " << numWeightsPerVertex_
01248       << " NEWgt " << nWeightsPerEdge_
01249       << " CDim  " << vCoordDim_
01250       << " GnosAreGids " << gnosAreGids_ << std::endl;
01251 
01252   for (lno_t i = 0; i < gids_.size(); i++) {
01253     *os << me << fn << i << " GID " << gids_[i] << ": ";
01254     for (lno_t j = offsets_[i]; j < offsets_[i+1]; j++)
01255       *os << edgeGids_[j] << " " << "(" << procIds_[j] << ") ";
01256     *os << std::endl;
01257   }
01258 
01259   if (gnos_.size())
01260     for (lno_t i = 0; i < gnos_.size(); i++) {
01261       *os << me << fn << i << " GNO " << gnos_[i] << ": ";
01262       for (lno_t j = offsets_[i]; j < offsets_[i+1]; j++)
01263         *os << edgeGnos_[j] << " ";//<< "(" << procIds_[j] << ") ";
01264       *os << std::endl;
01265     }
01266   else
01267     *os << me << fn << " GNOS NOT AVAILABLE " << std::endl;
01268 
01269   if (comm_->getSize() > 1) {
01270     // Print local graph, with no off-process edges.
01271     ArrayView<const lno_t> localEdgeIds;
01272     ArrayView<const lno_t> localOffsets;
01273     ArrayView<input_t> localWgts;
01274     this->getLocalEdgeList(localEdgeIds, localOffsets, localWgts);
01275 
01276     for (lno_t i = 0; i < gids_.size(); i++) {
01277       *os << me << fn << i << " LGNO " << gids_[i] << ": ";
01278       for (lno_t j = localOffsets[i]; j < localOffsets[i+1]; j++) 
01279         *os << localEdgeIds[j] << " ";
01280       *os << std::endl;
01281     }
01282   }
01283   else
01284     *os << me << fn 
01285        << " LOCAL GRAPH IS SAME AS GLOBAL GRAPH ON ONE RANK " << std::endl;
01286 
01287   if (vCoordDim_) {
01288     for (lno_t i = 0; i < gids_.size(); i++) {
01289       *os << me << fn << i << " COORDS " << gids_[i] << ": ";
01290       for (int j = 0; j < vCoordDim_; j++)
01291          *os << vCoords_[j][i] << " ";
01292       *os << std::endl;
01293     }
01294   }
01295   else
01296     *os << me << fn << "NO COORDINATES AVAIL " << std::endl;
01297 }
01298 
01299 }   // namespace Zoltan2
01300 
01301 
01302 #endif
01303