Tpetra Matrix/Vector Services Version of the Day
Tpetra_MultiVectorFiller.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 #ifndef __Tpetra_MultiVectorFiller_hpp
00042 #define __Tpetra_MultiVectorFiller_hpp
00043 
00044 #include <Tpetra_MultiVector.hpp>
00045 #include <Teuchos_CommHelpers.hpp>
00046 #include <iterator>
00047 
00048 namespace {
00049 
00050   // \fn sortAndMergeIn
00051   // \brief Sort and merge newEntries into allEntries, and make unique.
00052   //
00053   // \param allEntries [in/out]: Array in which current entries have
00054   //   already been stored, and in which the new entries are to be
00055   //   stored.  Passed by reference in case we need to resize it.
00056   //
00057   // \param currentEntries [in/out]: Current entries, which we assume
00058   //   have already been sorted and made unique.  Aliases the
00059   //   beginning of allEntries.
00060   //
00061   // \param newEntries [in/out] New entries, which have not yet been
00062   //   sorted or made unique.  This does <i>not</i> alias allEntries.
00063   //
00064   // Sort and make entries of newEntries unique.  Resize allEntries if
00065   // necessary to fit the unique entries of newEntries.  Merge
00066   // newEntries into allEntries and make the results unique.  (This is
00067   // cheaper than sorting the whole array.)
00068   //
00069   // \return A view of all the entries (current and new) in allEntries.
00070   template<class T>
00071   Teuchos::ArrayView<T>
00072   sortAndMergeIn (Teuchos::Array<T>& allEntries,
00073                   Teuchos::ArrayView<T> currentEntries,
00074                   Teuchos::ArrayView<T> newEntries)
00075   {
00076     using Teuchos::ArrayView;
00077     using Teuchos::as;
00078     typedef typename ArrayView<T>::iterator iter_type;
00079     typedef typename ArrayView<T>::size_type size_type;
00080 
00081     std::unique (newEntries.begin(), newEntries.end());
00082     iter_type it = std::unique (newEntries.begin(), newEntries.end());
00083     const size_type numNew = as<size_type> (it - newEntries.begin());
00084     // View of the sorted, made-unique new entries to merge in.
00085     ArrayView<T> newEntriesView = newEntries.view (0, numNew);
00086 
00087     const size_type numCur = currentEntries.size();
00088     if (allEntries.size() < numCur + numNew) {
00089       allEntries.resize (numCur + numNew);
00090     }
00091     ArrayView<T> allView = allEntries.view (0, numCur + numNew);
00092     ArrayView<T> newView = allEntries.view (numCur, numNew); // target of copy
00093 
00094     std::copy (newEntries.begin(), newEntries.end(), newView.begin());
00095     std::inplace_merge (allView.begin(), newView.begin(), allView.end());
00096     iter_type it2 = std::unique (allView.begin(), allView.end());
00097     const size_type numTotal = as<size_type> (it2 - allView.begin());
00098 
00099     return allEntries.view (0, numTotal);
00100   }
00101 
00107   template<class MV>
00108   class MultiVectorFillerData {
00109   public:
00110     typedef typename MV::scalar_type scalar_type;
00111     typedef typename MV::local_ordinal_type local_ordinal_type;
00112     typedef typename MV::global_ordinal_type global_ordinal_type;
00113     typedef typename MV::node_type node_type;
00114 
00115     typedef Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
00116 
00128     MultiVectorFillerData (const Teuchos::RCP<const map_type>& map) :
00129       map_ (map),
00130       numCols_ (0)
00131     {}
00132 
00149     MultiVectorFillerData (const Teuchos::RCP<const map_type>& map,
00150                            const size_t numColumns) :
00151       map_ (map),
00152       numCols_ (numColumns),
00153       sourceIndices_ (numColumns),
00154       sourceValues_ (numColumns)
00155     {}
00156 
00158     void
00159     setNumColumns (const size_t newNumColumns)
00160     {
00161       const size_t oldNumColumns = getNumColumns();
00162       if (newNumColumns >= oldNumColumns) {
00163         for (size_t j = oldNumColumns; j < newNumColumns; ++j) {
00164           sourceIndices_.push_back (Teuchos::Array<global_ordinal_type> ());
00165           sourceValues_.push_back (Teuchos::Array<scalar_type> ());
00166         }
00167       }
00168       else {
00169         // This may not necessarily deallocate any data, but that's OK.
00170         sourceIndices_.resize (newNumColumns);
00171         sourceValues_.resize (newNumColumns);
00172       }
00173       numCols_ = oldNumColumns;
00174     }
00175 
00176     void
00177     sumIntoGlobalValues (Teuchos::ArrayView<const global_ordinal_type> rows,
00178                          size_t column,
00179                          Teuchos::ArrayView<const scalar_type> values)
00180     {
00181       if (column >= getNumColumns()) {
00182         for (size_t j = column; j < getNumColumns(); ++j) {
00183           sourceIndices_.push_back (Teuchos::Array<global_ordinal_type> ());
00184           sourceValues_.push_back (Teuchos::Array<scalar_type> ());
00185         }
00186       }
00187       std::copy (rows.begin(), rows.end(), std::back_inserter (sourceIndices_[column]));
00188       std::copy (values.begin(), values.end(), std::back_inserter (sourceValues_[column]));
00189     }
00190 
00198     void
00199     sumIntoGlobalValues (Teuchos::ArrayView<const global_ordinal_type> rows,
00200                          Teuchos::ArrayView<const scalar_type> values)
00201     {
00202       typedef global_ordinal_type GO;
00203       typedef scalar_type ST;
00204       typedef typename Teuchos::ArrayView<const GO>::const_iterator GoIter;
00205       typedef typename Teuchos::ArrayView<const ST>::const_iterator StIter;
00206 
00207       const size_t numColumns = getNumColumns();
00208       GoIter rowIter = rows.begin();
00209       StIter valIter = values.begin();
00210       for (size_t j = 0; j < numColumns; ++j) {
00211         GoIter rowIterNext = rowIter + numColumns;
00212         StIter valIterNext = valIter + numColumns;
00213         std::copy (rowIter, rowIterNext, std::back_inserter (sourceIndices_[j]));
00214         std::copy (valIter, valIterNext, std::back_inserter (sourceValues_[j]));
00215         rowIter = rowIterNext;
00216         valIter = valIterNext;
00217       }
00218     }
00219 
00244     template<class BinaryFunction>
00245     void
00246     locallyAssemble (MV& X, BinaryFunction& f)
00247     {
00248       using Teuchos::Array;
00249       using Teuchos::ArrayRCP;
00250       using Teuchos::ArrayView;
00251       using Teuchos::RCP;
00252       typedef local_ordinal_type LO;
00253       typedef global_ordinal_type GO;
00254       typedef scalar_type ST;
00255       typedef node_type NT;
00256 
00257       RCP<const Tpetra::Map<LO, GO, NT> > map = X.getMap();
00258       Array<LO> localIndices;
00259       const size_t numColumns = getNumColumns();
00260       for (size_t j = 0; j < numColumns; ++j) {
00261         const typename Array<const GO>::size_type numIndices = sourceIndices_[j].size();
00262         // Precompute all the local indices before saving to the
00263         // vector.  Hopefully this gives us a little bit of locality
00264         // in the global->local conversion, at the expense of a little
00265         // more storage.
00266         if (localIndices.size() < numIndices) {
00267           localIndices.resize (numIndices);
00268         }
00269         ArrayView<LO> localIndicesView = localIndices.view (0, numIndices);
00270         ArrayView<const GO> globalIndicesView = sourceIndices_[j].view (0, numIndices);
00271         for (typename ArrayView<const GO>::size_type i = 0; i < numIndices; ++i) {
00272           localIndices[i] = map->getLocalElement (globalIndicesView[i]);
00273         }
00274 
00275         ArrayRCP<ST> X_j = X.getDataNonConst (j);
00276         ArrayView<const ST> localValues = sourceValues_[j].view (0, numIndices);
00277         for (typename ArrayView<const GO>::size_type i = 0; i < numIndices; ++i) {
00278           const LO localInd = localIndices[i];
00279           X_j[localInd] = f (X_j[localInd], localValues[i]);
00280         }
00281       }
00282     }
00283 
00285     void
00286     locallyAssemble (MV& X)
00287     {
00288       std::plus<double> f;
00289       locallyAssemble<std::plus<scalar_type> > (X, f);
00290     }
00291 
00293     void clear() {
00294       Teuchos::Array<Teuchos::Array<global_ordinal_type> > newSourceIndices;
00295       Teuchos::Array<Teuchos::Array<scalar_type> > newSourceValues;
00296       // The standard STL idiom for clearing the contents of a vector completely.
00297       std::swap (sourceIndices_, newSourceIndices);
00298       std::swap (sourceValues_, newSourceValues);
00299     }
00300 
00302     Teuchos::Array<global_ordinal_type>
00303     getSourceIndices () const
00304     {
00305       using Teuchos::Array;
00306       using Teuchos::ArrayView;
00307       using Teuchos::as;
00308       typedef global_ordinal_type GO;
00309       typedef typename Array<GO>::iterator iter_type;
00310       typedef typename Array<GO>::size_type size_type;
00311 
00312       Array<GO> allInds (0); // will resize below
00313       const size_t numCols = getNumColumns();
00314 
00315       if (numCols == 1) {
00316         // Special case for 1 column avoids copying indices twice.
00317         // Pick the size of the array exactly the first time so there
00318         // are at most two allocations (the constructor may choose to
00319         // allocate).
00320         const size_type numNew = sourceIndices_[0].size();
00321         allInds.resize (allInds.size() + numNew);
00322         std::copy (sourceIndices_[0].begin(), sourceIndices_[0].end(),
00323                    allInds.begin());
00324         std::sort (allInds.begin(), allInds.end());
00325         typename Array<GO>::iterator it =
00326           std::unique (allInds.begin(), allInds.end());
00327         const size_type numFinal = as<size_type> (it - allInds.begin());
00328         allInds.resize (numFinal);
00329       }
00330       else {
00331         // Carefully collect all the row indices one column at a time.
00332         // This ensures that the total allocation size in this routine
00333         // is independent of the number of columns.  Also, only sort
00334         // the current column's indices.  Use merges to ensure sorted
00335         // order in the collected final result.
00336         ArrayView<GO> curIndsView = allInds.view (0, 0); // will grow
00337         Array<GO> newInds;
00338         for (size_t j = 0; j < numCols; ++j) {
00339           const size_type numNew = sourceIndices_[j].size();
00340           if (numNew > newInds.size()) {
00341             newInds.resize (numNew);
00342           }
00343           ArrayView<GO> newIndsView = newInds.view (0, numNew);
00344           std::copy (sourceIndices_[j].begin(), sourceIndices_[j].end(),
00345                      newIndsView.begin());
00346           curIndsView = sortAndMergeIn<GO> (allInds, curIndsView, newIndsView);
00347         }
00348       }
00349       return allInds;
00350     }
00351 
00352   private:
00353     Teuchos::RCP<const map_type> map_;
00354     size_t numCols_;
00355     Teuchos::Array<Teuchos::Array<global_ordinal_type> > sourceIndices_;
00356     Teuchos::Array<Teuchos::Array<scalar_type> > sourceValues_;
00357 
00358     size_t getNumColumns() const { return numCols_; }
00359   };
00360 
00366   template<class MV>
00367   class MultiVectorFillerData2 : public Teuchos::Describable {
00368   public:
00369     typedef typename MV::scalar_type scalar_type;
00370     typedef typename MV::local_ordinal_type local_ordinal_type;
00371     typedef typename MV::global_ordinal_type global_ordinal_type;
00372     typedef typename MV::node_type node_type;
00373 
00374     typedef Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
00375 
00386     MultiVectorFillerData2 (const Teuchos::RCP<const map_type>& map,
00387                             const Teuchos::EVerbosityLevel verbLevel=Teuchos::VERB_DEFAULT,
00388                             const Teuchos::RCP<Teuchos::FancyOStream>& out=Teuchos::null) :
00389       map_ (map),
00390       numCols_ (0),
00391       verbLevel_ (verbLevel),
00392       out_ (out)
00393     {}
00394 
00412     MultiVectorFillerData2 (const Teuchos::RCP<const map_type>& map,
00413                             const size_t numColumns,
00414                             const Teuchos::EVerbosityLevel verbLevel=Teuchos::VERB_DEFAULT,
00415                             const Teuchos::RCP<Teuchos::FancyOStream>& out=Teuchos::null) :
00416       map_ (map),
00417       numCols_ (numColumns),
00418       localVec_ (new MV (map, numColumns)),
00419       nonlocalIndices_ (numColumns),
00420       nonlocalValues_ (numColumns),
00421       verbLevel_ (verbLevel),
00422       out_ (out)
00423     {}
00424 
00425     std::string
00426     description() const
00427     {
00428       std::ostringstream oss;
00429       oss << "Tpetra::MultiVectorFillerData2<"
00430           << Teuchos::TypeNameTraits<MV>::name () << ">";
00431       return oss.str();
00432     }
00433 
00434     void
00435     describe (Teuchos::FancyOStream& out,
00436               const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
00437     {
00438       using std::endl;
00439       using Teuchos::Array;
00440       using Teuchos::ArrayRCP;
00441       using Teuchos::ArrayView;
00442       using Teuchos::RCP;
00443       using Teuchos::VERB_DEFAULT;
00444       using Teuchos::VERB_NONE;
00445       using Teuchos::VERB_LOW;
00446       using Teuchos::VERB_MEDIUM;
00447       using Teuchos::VERB_HIGH;
00448       using Teuchos::VERB_EXTREME;
00449 
00450       // Set default verbosity if applicable.
00451       const Teuchos::EVerbosityLevel vl =
00452         (verbLevel == VERB_DEFAULT) ? VERB_LOW : verbLevel;
00453 
00454       RCP<const Teuchos::Comm<int> > comm = map_->getComm();
00455       const int myImageID = comm->getRank();
00456       const int numImages = comm->getSize();
00457 
00458       if (vl != VERB_NONE) {
00459         // Don't set the tab level unless we're printing something.
00460         Teuchos::OSTab tab (out);
00461 
00462         if (myImageID == 0) { // >= VERB_LOW prints description()
00463           out << this->description() << endl;
00464         }
00465         for (int imageCtr = 0; imageCtr < numImages; ++imageCtr) {
00466           if (myImageID == imageCtr) {
00467             if (vl != VERB_LOW) {
00468               // At verbosity > VERB_LOW, each process prints something.
00469               out << "Process " << myImageID << ":" << endl;
00470 
00471               Teuchos::OSTab procTab (out);
00472               // >= VERB_MEDIUM: print the local vector length.
00473               out << "local length=" << localVec_->getLocalLength();
00474               if (vl != VERB_MEDIUM) {
00475                 // >= VERB_HIGH: print isConstantStride() and getStride()
00476                 if (localVec_->isConstantStride()) {
00477                   out << ", constant stride=" << localVec_->getStride() << endl;
00478                 }
00479                 else {
00480                   out << ", not constant stride" << endl;
00481                 }
00482                 if (vl == VERB_EXTREME) {
00483                   // VERB_EXTREME: print all the values in the multivector.
00484                   out << "Local values:" << endl;
00485                   ArrayRCP<ArrayRCP<const scalar_type> > X = localVec_->get2dView();
00486                   for (size_t i = 0; i < localVec_->getLocalLength(); ++i) {
00487                     for (size_t j = 0; j < localVec_->getNumVectors(); ++j) {
00488                       out << X[j][i];
00489                       if (j < localVec_->getNumVectors() - 1) {
00490                         out << " ";
00491                       }
00492                     } // for each column
00493                     out << endl;
00494                   } // for each row
00495 
00496                   out << "Nonlocal indices and values:" << endl;
00497                   for (size_t j = 0; j < (size_t)nonlocalIndices_.size(); ++j) {
00498                     ArrayView<const global_ordinal_type> inds = nonlocalIndices_[j]();
00499                     ArrayView<const scalar_type> vals = nonlocalValues_[j]();
00500 
00501                     for (typename ArrayView<const global_ordinal_type>::size_type k = 0; k < inds.size(); ++k) {
00502                       out << "X(" << inds[k] << "," << j << ") = " << vals[k] << endl;
00503                     }
00504                   }
00505                 } // if vl == VERB_EXTREME
00506               } // if (vl != VERB_MEDIUM)
00507               else { // vl == VERB_LOW
00508                 out << endl;
00509               }
00510             } // if vl != VERB_LOW
00511           } // if it is my process' turn to print
00512         } // for each process in the communicator
00513       } // if vl != VERB_NONE
00514     }
00515 
00517     Teuchos::Array<global_ordinal_type>
00518     getSourceIndices () const
00519     {
00520       using Teuchos::Array;
00521       using Teuchos::ArrayView;
00522       using Teuchos::RCP;
00523       using Teuchos::rcp;
00524       using Tpetra::global_size_t;
00525       typedef global_ordinal_type GO;
00526 
00527       // Get the nonlocal row indices, sorted and made unique.
00528       // It's fair to assume that these are not contiguous.
00529       Array<GO> nonlocalIndices = getSortedUniqueNonlocalIndices();
00530 
00531       // Get the local row indices, not necessarily sorted or unique.
00532       ArrayView<const GO> localIndices = getLocalIndices ();
00533 
00534       // Copy the local indices into the full indices array, and sort
00535       // them there.  We'll merge in the nonlocal indices below.  This
00536       // can be more efficient than just sorting all the indices, if
00537       // there are a lot of nonlocal indices.
00538       Array<GO> indices (localIndices.size() + nonlocalIndices.size());
00539       ArrayView<GO> localIndView = indices.view (0, localIndices.size());
00540       std::copy (localIndices.begin(), localIndices.end(), localIndView.begin());
00541       std::sort (localIndView.begin(), localIndView.end());
00542 
00543       // Merge the local and nonlocal indices.
00544       if (nonlocalIndices.size() > 0) {
00545         typedef typename ArrayView<GO>::iterator iter_type;
00546 
00547         iter_type middle = localIndView.end();
00548         // We need a view, because std::inplace_merge needs all its
00549         // iterator inputs to have the same type.  Debug mode builds
00550         // are pickier than release mode builds, because the iterators
00551         // in a debug mode build are of a different type that does
00552         // run-time checking (they aren't just raw pointers).
00553         ArrayView<GO> indView = indices.view (0, indices.size());
00554 
00555         //iter_type middle = &indices[nonlocalIndices.size()];
00556         std::copy (nonlocalIndices.begin(), nonlocalIndices.end(), middle);
00557         std::inplace_merge (indView.begin(), middle, indView.end());
00558       }
00559       return indices;
00560     }
00561 
00571     void
00572     setNumColumns (const size_t newNumColumns)
00573     {
00574       using Teuchos::Array;
00575       using Teuchos::Range1D;
00576       using Teuchos::RCP;
00577       typedef global_ordinal_type GO;
00578       typedef scalar_type ST;
00579 
00580       const size_t oldNumColumns = numCols_;
00581       if (newNumColumns == oldNumColumns) {
00582         return; // No side effects if no change.
00583       }
00584 
00585       RCP<MV> newLocalVec;
00586       if (newNumColumns > oldNumColumns) {
00587         newLocalVec = rcp (new MV (map_, newNumColumns));
00588         // Assign the contents of the old local multivector to the
00589         // first oldNumColumns columns of the new local multivector,
00590         // then get rid of the old local multivector.
00591         RCP<MV> newLocalVecView =
00592           newLocalVec->subViewNonConst (Range1D (0, oldNumColumns-1));
00593         *newLocalVecView = *localVec_;
00594       }
00595       else {
00596         if (newNumColumns == 0) {
00597           // Tpetra::MultiVector doesn't let you construct a
00598           // multivector with zero columns.
00599           newLocalVec = Teuchos::null;
00600         }
00601         else {
00602           newLocalVec =
00603             localVec_->subViewNonConst (Range1D (0, newNumColumns-1));
00604         }
00605       }
00606 
00607       // Leave most side effects until the end, for exception safety.
00608       nonlocalIndices_.resize (newNumColumns);
00609       nonlocalValues_.resize (newNumColumns);
00610       localVec_ = newLocalVec;
00611       numCols_ = newNumColumns;
00612     }
00613 
00615     void
00616     sumIntoGlobalValues (Teuchos::ArrayView<const global_ordinal_type> rows,
00617                          size_t columnIndex,
00618                          Teuchos::ArrayView<const scalar_type> values)
00619     {
00620       using Teuchos::ArrayRCP;
00621       using Teuchos::ArrayView;
00622       typedef local_ordinal_type LO;
00623       typedef global_ordinal_type GO;
00624       typedef scalar_type ST;
00625 
00626       if (columnIndex >= getNumColumns()) {
00627         // Automatically expand the number of columns.  This
00628         // implicitly ensures that localVec_ is not null.
00629         setNumColumns (columnIndex + 1);
00630       }
00631 
00632       typename ArrayView<const GO>::const_iterator rowIter = rows.begin();
00633       typename ArrayView<const ST>::const_iterator valIter = values.begin();
00634       for ( ; rowIter != rows.end() && valIter != values.end(); ++rowIter, ++valIter) {
00635         const GO globalRowIndex = *rowIter;
00636         // Converting from global to local index could be logarithmic
00637         // in the number of global indices that this process owns,
00638         // depending on the Map implementation.  However, the lookup
00639         // allows us to store data in the local multivector, rather
00640         // than in a separate data structure.
00641         const LO localRowIndex = map_->getLocalElement (globalRowIndex);
00642         if (localRowIndex == Teuchos::OrdinalTraits<LO>::invalid()) {
00643           nonlocalIndices_[columnIndex].push_back (globalRowIndex);
00644           nonlocalValues_[columnIndex].push_back (*valIter);
00645         }
00646         else {
00647           // FIXME (mfh 27 Feb 2012) This will be very slow for GPU
00648           // Node types.  In that case, we should hold on to the view
00649           // of localVec_ as long as the number of columns doesn't
00650           // change, and make modifications to the view until
00651           // localAssemble() is called.
00652           ArrayRCP<ST> X_j = localVec_->getDataNonConst (columnIndex);
00653           // FIXME (mfh 27 Feb 2012) Allow different combine modes.
00654           // The current combine mode just adds to the current value
00655           // at that location.
00656           X_j[localRowIndex] += *valIter;
00657         }
00658       }
00659     }
00660 
00670     void
00671     sumIntoGlobalValues (Teuchos::ArrayView<const global_ordinal_type> rows,
00672                          Teuchos::ArrayView<const scalar_type> values)
00673     {
00674       using Teuchos::ArrayView;
00675       typedef typename ArrayView<const global_ordinal_type>::size_type size_type;
00676 
00677       const size_t numCols = getNumColumns();
00678       for (size_t j = 0; j < numCols; ++j) {
00679         const size_type offset = numCols*j;
00680         const size_type len = numCols;
00681         sumIntoGlobalValues (rows.view (offset, len), j, values.view (offset, len));
00682       }
00683     }
00684 
00709     template<class BinaryFunction>
00710     void
00711     locallyAssemble (MV& X, BinaryFunction& f)
00712     {
00713       using Teuchos::ArrayRCP;
00714       using Teuchos::ArrayView;
00715       using Teuchos::FancyOStream;
00716       using Teuchos::getFancyOStream;
00717       using Teuchos::oblackholestream;
00718       using Teuchos::RCP;
00719       using Teuchos::rcp;
00720       using std::endl;
00721 
00722       typedef local_ordinal_type LO;
00723       typedef global_ordinal_type GO;
00724       typedef scalar_type ST;
00725 
00726       // Default output stream prints nothing.
00727       RCP<FancyOStream> out = out_.is_null() ?
00728         getFancyOStream (rcp (new oblackholestream)) : out_;
00729 
00730       Teuchos::OSTab tab (out);
00731       *out << "locallyAssemble:" << endl;
00732 
00733       RCP<const map_type> srcMap = X.getMap();
00734       ArrayView<const GO> localIndices = map_->getNodeElementList ();
00735 
00736       for (size_t j = 0; j < X.getNumVectors(); ++j) {
00737         ArrayRCP<ST> X_j = X.getDataNonConst (j);
00738 
00739         // First add all the local data into X_j.
00740         ArrayRCP<const ST> local_j = localVec_->getDataNonConst (j);
00741         for (typename ArrayView<const GO>::const_iterator it = localIndices.begin();
00742              it != localIndices.end(); ++it) {
00743           const LO rowIndLocal = map_->getLocalElement (*it);
00744           const LO rowIndX = srcMap->getLocalElement (*it);
00745 
00746           TEUCHOS_TEST_FOR_EXCEPTION(rowIndX == Teuchos::OrdinalTraits<LO>::invalid(),
00747             std::invalid_argument, "locallyAssemble(): Input multivector X does "
00748             "not own the global index " << *it << ".  This probably means that "
00749             "X was not constructed with the right Map.");
00750           X_j[rowIndX] = f (X_j[rowIndX], local_j[rowIndLocal]);
00751         }
00752 
00753         // Now add the nonlocal data into X_j.
00754         ArrayView<const GO> nonlocalIndices = nonlocalIndices_[j]();
00755         typename ArrayView<const GO>::const_iterator indexIter = nonlocalIndices.begin();
00756         ArrayView<const ST> nonlocalValues = nonlocalValues_[j]();
00757         typename ArrayView<const ST>::const_iterator valueIter = nonlocalValues.begin();
00758         for ( ; indexIter != nonlocalIndices.end() && valueIter != nonlocalValues.end();
00759               ++indexIter, ++valueIter) {
00760           const LO rowIndX = srcMap->getLocalElement (*indexIter);
00761           X_j[rowIndX] = f (X_j[rowIndX], *valueIter);
00762         }
00763       }
00764 
00765       *out << "Locally assembled vector:" << endl;
00766       X.describe (*out, Teuchos::VERB_EXTREME);
00767     }
00768 
00770     void
00771     locallyAssemble (MV& X)
00772     {
00773       std::plus<double> f;
00774       locallyAssemble<std::plus<scalar_type> > (X, f);
00775     }
00776 
00782     void clear() {
00783       Teuchos::Array<Teuchos::Array<global_ordinal_type> > newNonlocalIndices;
00784       Teuchos::Array<Teuchos::Array<scalar_type> > newNonlocalValues;
00785       // The standard STL idiom for clearing the contents of a vector
00786       // completely.  Setting the size to zero may not necessarily
00787       // deallocate data.
00788       std::swap (nonlocalIndices_, newNonlocalIndices);
00789       std::swap (nonlocalValues_, newNonlocalValues);
00790 
00791       // Don't actually deallocate the multivector of local entries.
00792       // Just fill it with zero.  This is because the caller hasn't
00793       // reset the number of columns.
00794       if (! localVec_.is_null()) {
00795         localVec_->putScalar (Teuchos::ScalarTraits<scalar_type>::zero());
00796       }
00797     }
00798 
00799   private:
00801     Teuchos::RCP<const map_type> map_;
00802 
00804     size_t numCols_;
00805 
00807     Teuchos::RCP<MV> localVec_;
00808 
00810     Teuchos::Array<Teuchos::Array<global_ordinal_type> > nonlocalIndices_;
00811 
00813     Teuchos::Array<Teuchos::Array<scalar_type> > nonlocalValues_;
00814 
00816     Teuchos::EVerbosityLevel verbLevel_;
00817 
00819     Teuchos::RCP<Teuchos::FancyOStream> out_;
00820 
00822     size_t getNumColumns() const { return numCols_; }
00823 
00825     Teuchos::ArrayView<const global_ordinal_type>
00826     getLocalIndices() const
00827     {
00828       return map_->getNodeElementList ();
00829     }
00830 
00832     Teuchos::Array<global_ordinal_type>
00833     getSortedUniqueNonlocalIndices() const
00834     {
00835       using Teuchos::Array;
00836       using Teuchos::ArrayView;
00837       using Teuchos::as;
00838       typedef global_ordinal_type GO;
00839       typedef typename Array<GO>::size_type size_type;
00840 
00841       Array<GO> allNonlocals (0); // will resize below
00842       const size_t numCols = getNumColumns();
00843 
00844       if (numCols == 1) {
00845         // Special case for 1 column avoids copying indices twice.
00846         // Pick the size of the array exactly the first time so there
00847         // are at most two allocations (the constructor may choose to
00848         // allocate).
00849         const size_type numNew = nonlocalIndices_[0].size();
00850         allNonlocals.resize (allNonlocals.size() + numNew);
00851         std::copy (nonlocalIndices_[0].begin(), nonlocalIndices_[0].end(),
00852                    allNonlocals.begin());
00853         std::sort (allNonlocals.begin(), allNonlocals.end());
00854         typename Array<GO>::iterator it =
00855           std::unique (allNonlocals.begin(), allNonlocals.end());
00856         const size_type numFinal = as<size_type> (it - allNonlocals.begin());
00857         allNonlocals.resize (numFinal);
00858       }
00859       else {
00860         // Carefully collect all the row indices one column at a time.
00861         // This ensures that the total allocation size in this routine
00862         // is independent of the number of columns.  Also, only sort
00863         // the current column's indices.  Use merges to ensure sorted
00864         // order in the collected final result.
00865         ArrayView<GO> curNonlocalsView = allNonlocals.view (0, 0); // will grow
00866         Array<GO> newNonlocals;
00867         for (size_t j = 0; j < numCols; ++j) {
00868           const size_type numNew = nonlocalIndices_[j].size();
00869           if (numNew > newNonlocals.size()) {
00870             newNonlocals.resize (numNew);
00871           }
00872           ArrayView<GO> newNonlocalsView = newNonlocals.view (0, numNew);
00873           std::copy (nonlocalIndices_[j].begin(), nonlocalIndices_[j].end(),
00874                      newNonlocalsView.begin());
00875           curNonlocalsView = sortAndMergeIn<GO> (allNonlocals, curNonlocalsView,
00876                                                  newNonlocalsView);
00877         }
00878       }
00879       return allNonlocals;
00880     }
00881   };
00882 } // namespace (anonymous)
00883 
00884 namespace Tpetra {
00885 
00910   template<class MV>
00911   class MultiVectorFiller {
00912   public:
00913     typedef typename MV::scalar_type scalar_type;
00914     typedef typename MV::local_ordinal_type local_ordinal_type;
00915     typedef typename MV::global_ordinal_type global_ordinal_type;
00916     typedef typename MV::node_type node_type;
00917     typedef Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
00918 
00948     MultiVectorFiller (const Teuchos::RCP<const map_type>& map,
00949                        const size_t numCols);
00950 
00970     void globalAssemble (MV& X_out, const bool forceReuseMap = false);
00971 
00972     void
00973     describe (Teuchos::FancyOStream& out,
00974               const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
00975     {
00976       data_.describe (out, verbLevel);
00977     }
00978 
00989     void
00990     sumIntoGlobalValues (Teuchos::ArrayView<const global_ordinal_type> rows,
00991                          size_t column,
00992                          Teuchos::ArrayView<const scalar_type> values)
00993     {
00994       data_.sumIntoGlobalValues (rows, column, values);
00995     }
00996 
01012     void
01013     sumIntoGlobalValues (Teuchos::ArrayView<const global_ordinal_type> rows,
01014                          Teuchos::ArrayView<const scalar_type> values)
01015     {
01016       data_.sumIntoGlobalValues (rows, values);
01017     }
01018 
01019   private:
01021     Teuchos::RCP<const map_type> ctorMap_;
01022 
01027     Teuchos::RCP<const map_type> sourceMap_;
01028 
01034     Teuchos::RCP<const map_type> targetMap_;
01035 
01048     Teuchos::RCP<MV> sourceVec_;
01049 
01054     MultiVectorFillerData2<MV> data_;
01055 
01056     typedef Tpetra::Export<local_ordinal_type, global_ordinal_type, node_type> export_type;
01057     Teuchos::RCP<export_type> exporter_;
01058 
01064     void locallyAssemble (MV& X_in) {
01065       data_.locallyAssemble (X_in);
01066     }
01067 
01069     Teuchos::Array<global_ordinal_type> getSourceIndices () const {
01070       return data_.getSourceIndices();
01071     }
01072 
01081     Teuchos::RCP<const map_type>
01082     computeSourceMap (const global_ordinal_type indexBase,
01083                       const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
01084                       const Teuchos::RCP<node_type>& node);
01085   };
01086 
01087   template<class MV>
01088   MultiVectorFiller<MV>::MultiVectorFiller (const Teuchos::RCP<const typename MultiVectorFiller<MV>::map_type>& map, const size_t numCols)
01089     : ctorMap_ (map),
01090       sourceMap_ (Teuchos::null),
01091       targetMap_ (Teuchos::null),
01092       data_ (map, numCols),
01093       exporter_ (Teuchos::null)
01094   {}
01095 
01096   template<class MV>
01097   Teuchos::RCP<const typename MultiVectorFiller<MV>::map_type>
01098   MultiVectorFiller<MV>::
01099   computeSourceMap (const global_ordinal_type indexBase,
01100                     const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
01101                     const Teuchos::RCP<node_type>& node)
01102   {
01103     using Teuchos::Array;
01104     using Teuchos::ArrayView;
01105     using Teuchos::rcp;
01106     typedef global_ordinal_type GO;
01107 
01108     Array<GO> indices = getSourceIndices ();
01109 
01110     // Passing "invalid" for the numGlobalElements argument of the Map
01111     // constructor tells the Map to compute the global number of
01112     // elements itself.
01113     const Tpetra::global_size_t invalid =
01114       Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid();
01115     return rcp (new map_type (invalid, indices, indexBase, comm, node));
01116   }
01117 
01118   template<class MV>
01119   void
01120   MultiVectorFiller<MV>::globalAssemble (MV& X_out, const bool forceReuseMap)
01121   {
01122     using Teuchos::ArrayView;
01123     using Teuchos::Array;
01124     using Teuchos::Range1D;
01125     using Teuchos::RCP;
01126     using Teuchos::rcp;
01127     typedef global_ordinal_type GO;
01128 
01129     const size_t numVecs = X_out.getNumVectors();
01130 
01131     if (numVecs == 0) {
01132       // Nothing to do!  Of course, this does not check for whether
01133       // X_out has the right number of rows.  That's OK, though.
01134       // Compare to the definition of the BLAS' _AXPY for an input
01135       // vector containing NaNs, but multiplied by alpha=0.
01136       return;
01137     }
01138     //
01139     // Get the target Map of the Export.  If X_out's Map is the same
01140     // as the target Map from last time, then we may be able to
01141     // recycle the Export from last time, if the source Map is also
01142     // the same.
01143     //
01144     RCP<const map_type> targetMap;
01145     bool assumeSameTargetMap = false;
01146     if (targetMap_.is_null()) {
01147       targetMap_ = X_out.getMap();
01148       targetMap = targetMap_;
01149       assumeSameTargetMap = false;
01150     }
01151     else {
01152       if (forceReuseMap) {
01153         targetMap = targetMap_;
01154         assumeSameTargetMap = true;
01155       }
01156       else  {
01157         // If X_out's Map is the same as targetMap_, we may be able to
01158         // reuse the Export.  Constructing the Export may be more
01159         // expensive than calling isSameAs() (which requires just a
01160         // few reductions and reading through the lists of owned
01161         // global indices), so it's worth checking.
01162         if (targetMap_->isSameAs (*(X_out.getMap()))) {
01163           assumeSameTargetMap = true;
01164           targetMap = targetMap_;
01165         }
01166       }
01167     }
01168     //
01169     // Get the source Map of the Export.  If the source Map of the
01170     // Export is the same as last time, then we may be able to recycle
01171     // the Export from last time, if the target Map is also the same.
01172     //
01173     RCP<const map_type> sourceMap;
01174     bool computedSourceMap = false;
01175     {
01176       if (forceReuseMap && ! sourceMap_.is_null()) {
01177         sourceMap = sourceMap_;
01178       }
01179       else {
01180         sourceMap = computeSourceMap (ctorMap_->getIndexBase(),
01181                                       ctorMap_->getComm(),
01182                                       ctorMap_->getNode());
01183         computedSourceMap = true;
01184       }
01185     }
01186     if (computedSourceMap) {
01187       sourceMap_ = sourceMap;
01188     }
01189     //
01190     // Now that we have the source and target Maps of the Export, we
01191     // can check whether we can recycle the Export from last time.
01192     //
01193     const bool mustComputeExport =
01194       (exporter_.is_null() || (assumeSameTargetMap && ! computedSourceMap));
01195     if (mustComputeExport) {
01196       exporter_ = rcp (new export_type (sourceMap_, targetMap_));
01197     }
01198 
01199     // Source multivector for the Export.
01200     RCP<MV> X_in;
01201     const bool mustReallocateVec = sourceVec_.is_null() ||
01202       sourceVec_->getNumVectors() < numVecs || ! assumeSameTargetMap;
01203 
01204     if (mustReallocateVec) {
01205       // Reallocating nonlocalVec_ ensures that it has the right Map.
01206       sourceVec_ = rcp (new MV (sourceMap_, numVecs));
01207       X_in = sourceVec_;
01208     } else {
01209       if (sourceVec_->getNumVectors() == numVecs) {
01210         X_in = sourceVec_;
01211       } else { // sourceVec_ has more vectors than needed.
01212         X_in = sourceVec_->subViewNonConst (Range1D (0, numVecs-1));
01213       }
01214     }
01215 
01216     // "Locally assemble" the data into X_in by summing together
01217     // entries with the same indices.
01218     locallyAssemble (*X_in);
01219 
01220     // Do the Export.
01221     const Tpetra::CombineMode combineMode = Tpetra::ADD;
01222     X_out.doExport (*X_in, *exporter_, combineMode);
01223   }
01224 
01225   namespace Test {
01226 
01232     template<class MV>
01233     class MultiVectorFillerTester {
01234     public:
01235       typedef typename MV::scalar_type scalar_type;
01236       typedef typename MV::local_ordinal_type local_ordinal_type;
01237       typedef typename MV::global_ordinal_type global_ordinal_type;
01238       typedef typename MV::node_type node_type;
01239       typedef Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
01240 
01249       static void
01250       testSameMap (const Teuchos::RCP<const map_type>& targetMap,
01251                    const global_ordinal_type eltSize, // Must be odd
01252                    const size_t numCols,
01253                    const Teuchos::RCP<Teuchos::FancyOStream>& outStream=Teuchos::null,
01254                    const Teuchos::EVerbosityLevel verbosityLevel=Teuchos::VERB_DEFAULT)
01255       {
01256         using Teuchos::Array;
01257         using Teuchos::ArrayRCP;
01258         using Teuchos::ArrayView;
01259         using Teuchos::as;
01260         using Teuchos::Comm;
01261         using Teuchos::FancyOStream;
01262         using Teuchos::getFancyOStream;
01263         using Teuchos::oblackholestream;
01264         using Teuchos::ptr;
01265         using Teuchos::RCP;
01266         using Teuchos::rcp;
01267         using Teuchos::rcpFromRef;
01268         using Teuchos::REDUCE_SUM;
01269         using Teuchos::reduceAll;
01270         using std::cerr;
01271         using std::endl;
01272 
01273         typedef local_ordinal_type LO;
01274         typedef global_ordinal_type GO;
01275         typedef scalar_type ST;
01276         typedef Teuchos::ScalarTraits<ST> STS;
01277 
01278         TEUCHOS_TEST_FOR_EXCEPTION(eltSize % 2 == 0, std::invalid_argument,
01279           "Element size (eltSize) argument must be odd.");
01280         TEUCHOS_TEST_FOR_EXCEPTION(numCols == 0, std::invalid_argument,
01281           "Number of columns (numCols) argument must be nonzero.");
01282         // Default behavior is to print nothing out.
01283         RCP<FancyOStream> out = outStream.is_null() ?
01284           getFancyOStream (rcp (new oblackholestream)) : outStream;
01285         const Teuchos::EVerbosityLevel verbLevel =
01286           (verbosityLevel == Teuchos::VERB_DEFAULT) ?
01287           Teuchos::VERB_NONE : verbosityLevel;
01288 
01289         //RCP<MV> X = rcp (new MV (targetMap, numCols));
01290 
01291         const GO indexBase = targetMap->getIndexBase();
01292         Array<GO> rows (eltSize);
01293         Array<ST> values (eltSize);
01294         std::fill (values.begin(), values.end(), STS::one());
01295 
01296         // Make this a pointer so we can free its contents, in case
01297         // those contents depend on the input to globalAssemble().
01298         RCP<MultiVectorFiller<MV> > filler =
01299           rcp (new MultiVectorFiller<MV> (targetMap, numCols));
01300 
01301         TEUCHOS_TEST_FOR_EXCEPTION(! targetMap->isContiguous(),
01302           std::invalid_argument, "MultiVectorFiller test currently only works "
01303           "for contiguous Maps.");
01304 
01305         const GO minGlobalIndex = targetMap->getMinGlobalIndex();
01306         const GO maxGlobalIndex = targetMap->getMaxGlobalIndex();
01307         const GO minAllGlobalIndex = targetMap->getMinAllGlobalIndex();
01308         const GO maxAllGlobalIndex = targetMap->getMaxAllGlobalIndex();
01309         for (size_t j = 0; j < numCols; ++j) {
01310           for (GO i = minGlobalIndex; i <= maxGlobalIndex; ++i) {
01311             // Overlap over processes, without running out of bounds.
01312             const GO start = std::max (i - eltSize/2, minAllGlobalIndex);
01313             const GO end = std::min (i + eltSize/2, maxAllGlobalIndex);
01314             const GO len = end - start + 1;
01315 
01316             TEUCHOS_TEST_FOR_EXCEPTION(len > eltSize, std::logic_error,
01317               "At start,end = " << start << "," << end << ", len = " << len
01318               << " > eltSize = " << eltSize << ".");
01319 
01320             for (GO k = 0; k < len; ++k) {
01321               rows[k] = start + k;
01322             }
01323             if (verbLevel == Teuchos::VERB_EXTREME) {
01324               *out << "Inserting: "
01325                    << Teuchos::toString (rows.view(0,len)) << ", "
01326                    << Teuchos::toString (values.view(0, len)) << std::endl;
01327             }
01328             filler->sumIntoGlobalValues (rows.view(0, len), j, values.view(0, len));
01329           }
01330         }
01331 
01332         if (verbLevel == Teuchos::VERB_EXTREME) {
01333           *out << "Filler:" << std::endl;
01334           filler->describe (*out, verbLevel);
01335           *out << std::endl;
01336         }
01337 
01338         MV X_out (targetMap, numCols);
01339         filler->globalAssemble (X_out);
01340         filler = Teuchos::null;
01341 
01342         if (verbLevel == Teuchos::VERB_EXTREME) {
01343           *out << "X_out:" << std::endl;
01344           X_out.describe (*out, verbLevel);
01345           *out << std::endl;
01346         }
01347 
01348         // Create multivector for comparison.
01349         MV X_expected (targetMap, numCols);
01350         const scalar_type two = STS::one() + STS::one();
01351         for (size_t j = 0; j < numCols; ++j) {
01352           ArrayRCP<ST> X_j = X_expected.getDataNonConst (j);
01353 
01354           // Each entry of the column should have the value eltSize,
01355           // except for the first and last few entries in the whole
01356           // column (globally, not locally).
01357           for (GO i = minGlobalIndex; i <= maxGlobalIndex; ++i) {
01358             const LO localIndex = targetMap->getLocalElement (i);
01359             TEUCHOS_TEST_FOR_EXCEPTION(i == Teuchos::OrdinalTraits<LO>::invalid(),
01360               std::logic_error, "Global index " << i << " is not in the "
01361               "multivector's Map.");
01362 
01363             if (i <= minAllGlobalIndex + eltSize/2) {
01364               X_j[localIndex] = two + as<ST>(i) - as<ST>(indexBase);
01365             }
01366             else if (i >= maxAllGlobalIndex - eltSize/2) {
01367               X_j[localIndex] = two + as<ST>(maxAllGlobalIndex) - as<ST>(i);
01368             }
01369             else {
01370               X_j[localIndex] = as<ST>(eltSize);
01371             }
01372           } // for each global index which my process owns
01373         } // for each column of the multivector
01374 
01375         if (verbLevel == Teuchos::VERB_EXTREME) {
01376           *out << "X_expected:" << std::endl;
01377           X_expected.describe (*out, verbLevel);
01378           *out << std::endl;
01379         }
01380 
01381         Array<GO> errorLocations;
01382         for (size_t j = 0; j < numCols; ++j) {
01383           ArrayRCP<const ST> X_out_j = X_out.getData (j);
01384           ArrayRCP<const ST> X_expected_j = X_expected.getData (j);
01385 
01386           // Each entry of the column should have the value eltSize,
01387           // except for the first and last few entries in the whole
01388           // column (globally, not locally).
01389           for (GO i = minGlobalIndex; i <= maxGlobalIndex; ++i) {
01390             const LO localIndex = targetMap->getLocalElement (i);
01391             TEUCHOS_TEST_FOR_EXCEPTION(i == Teuchos::OrdinalTraits<LO>::invalid(),
01392               std::logic_error, "Global index " << i << " is not in the "
01393               "multivector's Map.");
01394 
01395             // The floating-point additions should be exact in this
01396             // case, except for very large values of eltSize.
01397             if (X_out_j[localIndex] != X_expected_j[localIndex]) {
01398               errorLocations.push_back (i);
01399             }
01400           } // for each global index which my process owns
01401 
01402           const typename Array<GO>::size_type localNumErrors = errorLocations.size();
01403           typename Array<GO>::size_type globalNumErrors = 0;
01404           RCP<const Comm<int> > comm = targetMap->getComm();
01405           reduceAll (*comm, REDUCE_SUM, localNumErrors, ptr (&globalNumErrors));
01406 
01407           if (globalNumErrors != 0) {
01408             std::ostringstream os;
01409             os << "Proc " << comm->getRank() << ": " << localNumErrors
01410                << " incorrect value" << (localNumErrors != 1 ? "s" : "")
01411                << ".  Error locations: [ ";
01412             std::copy (errorLocations.begin(), errorLocations.end(),
01413                        std::ostream_iterator<GO> (os, " "));
01414             os << "].";
01415             // Iterate through all processes in the communicator,
01416             // printing out each process' local errors.
01417             for (int p = 0; p < comm->getSize(); ++p) {
01418               if (p == comm->getRank()) {
01419                 cerr << os.str() << endl;
01420               }
01421               // Barriers to let output finish.
01422               comm->barrier();
01423               comm->barrier();
01424               comm->barrier();
01425             }
01426             TEUCHOS_TEST_FOR_EXCEPTION(globalNumErrors != 0, std::logic_error,
01427               "Over all procs: " << globalNumErrors << " total error"
01428               << (globalNumErrors != 1 ? "s" : "") << ".");
01429           } // if there were any errors in column j
01430         } // for each column j
01431       }
01432     };
01433 
01435     template<class ScalarType,
01436              class LocalOrdinalType,
01437              class GlobalOrdinalType,
01438              class NodeType>
01439     void
01440     testMultiVectorFiller (const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
01441                            const Teuchos::RCP<NodeType>& node,
01442                            const size_t unknownsPerNode,
01443                            const GlobalOrdinalType unknownsPerElt,
01444                            const size_t numCols,
01445                            const Teuchos::RCP<Teuchos::FancyOStream>& outStream,
01446                            const Teuchos::EVerbosityLevel verbLevel)
01447     {
01448       using Tpetra::createContigMapWithNode;
01449       using Teuchos::FancyOStream;
01450       using Teuchos::getFancyOStream;
01451       using Teuchos::oblackholestream;
01452       using Teuchos::ParameterList;
01453       using Teuchos::RCP;
01454       using Teuchos::rcp;
01455       using std::cerr;
01456       using std::endl;
01457 
01458       typedef ScalarType ST;
01459       typedef LocalOrdinalType LO;
01460       typedef GlobalOrdinalType GO;
01461       typedef NodeType NT;
01462       typedef Tpetra::Map<LO, GO, NT> MT;
01463       typedef Tpetra::MultiVector<ST, LO, GO, NT> MV;
01464 
01465       RCP<FancyOStream> out = outStream.is_null() ?
01466         getFancyOStream (rcp (new oblackholestream)) : outStream;
01467       const Tpetra::global_size_t invalid =
01468         Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid();
01469       RCP<const MT> targetMap =
01470         createContigMapWithNode<LO, GO, NT> (invalid, unknownsPerNode, comm, node);
01471 
01472       std::ostringstream os;
01473       try {
01474         MultiVectorFillerTester<MV>::testSameMap (targetMap, unknownsPerElt, numCols, out, verbLevel);
01475       } catch (std::exception& e) {
01476         os << e.what();
01477       }
01478 
01479       for (int p = 0; p < comm->getSize(); ++p) {
01480         if (p == comm->getRank()) {
01481           *out << "On process " << comm->getRank() << ": " << os.str() << endl;
01482         }
01483         comm->barrier();
01484         comm->barrier();
01485         comm->barrier();
01486       }
01487     }
01488 
01494     void
01495     testSortAndMergeIn ();
01496 
01497   } // namespace Test
01498 } // namespace Tpetra
01499 
01500 
01501 #endif // __Tpetra_MultiVectorFiller_hpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines