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 Tpetra {
00049 namespace Details {
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::sort (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>::size_type size_type;
00310 
00311       Array<GO> allInds (0); // will resize below
00312       const size_t numCols = getNumColumns();
00313 
00314       if (numCols == 1) {
00315         // Special case for 1 column avoids copying indices twice.
00316         // Pick the size of the array exactly the first time so there
00317         // are at most two allocations (the constructor may choose to
00318         // allocate).
00319         const size_type numNew = sourceIndices_[0].size();
00320         allInds.resize (allInds.size() + numNew);
00321         std::copy (sourceIndices_[0].begin(), sourceIndices_[0].end(),
00322                    allInds.begin());
00323         std::sort (allInds.begin(), allInds.end());
00324         typename Array<GO>::iterator it =
00325           std::unique (allInds.begin(), allInds.end());
00326         const size_type numFinal = as<size_type> (it - allInds.begin());
00327         allInds.resize (numFinal);
00328       }
00329       else {
00330         // Carefully collect all the row indices one column at a time.
00331         // This ensures that the total allocation size in this routine
00332         // is independent of the number of columns.  Also, only sort
00333         // the current column's indices.  Use merges to ensure sorted
00334         // order in the collected final result.
00335         ArrayView<GO> curIndsView = allInds.view (0, 0); // will grow
00336         Array<GO> newInds;
00337         for (size_t j = 0; j < numCols; ++j) {
00338           const size_type numNew = sourceIndices_[j].size();
00339           if (numNew > newInds.size()) {
00340             newInds.resize (numNew);
00341           }
00342           ArrayView<GO> newIndsView = newInds.view (0, numNew);
00343           std::copy (sourceIndices_[j].begin(), sourceIndices_[j].end(),
00344                      newIndsView.begin());
00345           curIndsView = sortAndMergeIn<GO> (allInds, curIndsView, newIndsView);
00346         }
00347       }
00348       return allInds;
00349     }
00350 
00351   private:
00352     Teuchos::RCP<const map_type> map_;
00353     size_t numCols_;
00354     Teuchos::Array<Teuchos::Array<global_ordinal_type> > sourceIndices_;
00355     Teuchos::Array<Teuchos::Array<scalar_type> > sourceValues_;
00356 
00357     size_t getNumColumns() const { return numCols_; }
00358   };
00359 
00365   template<class MV>
00366   class MultiVectorFillerData2 : public Teuchos::Describable {
00367   public:
00368     typedef typename MV::scalar_type scalar_type;
00369     typedef typename MV::local_ordinal_type local_ordinal_type;
00370     typedef typename MV::global_ordinal_type global_ordinal_type;
00371     typedef typename MV::node_type node_type;
00372 
00373     typedef Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
00374 
00385     MultiVectorFillerData2 (const Teuchos::RCP<const map_type>& map,
00386                             const Teuchos::EVerbosityLevel verbLevel=Teuchos::VERB_DEFAULT,
00387                             const Teuchos::RCP<Teuchos::FancyOStream>& out=Teuchos::null) :
00388       map_ (map),
00389       numCols_ (0),
00390       verbLevel_ (verbLevel),
00391       out_ (out)
00392     {}
00393 
00411     MultiVectorFillerData2 (const Teuchos::RCP<const map_type>& map,
00412                             const size_t numColumns,
00413                             const Teuchos::EVerbosityLevel verbLevel=Teuchos::VERB_DEFAULT,
00414                             const Teuchos::RCP<Teuchos::FancyOStream>& out=Teuchos::null) :
00415       map_ (map),
00416       numCols_ (numColumns),
00417       localVec_ (new MV (map, numColumns)),
00418       nonlocalIndices_ (numColumns),
00419       nonlocalValues_ (numColumns),
00420       verbLevel_ (verbLevel),
00421       out_ (out)
00422     {}
00423 
00424     std::string
00425     description() const
00426     {
00427       std::ostringstream oss;
00428       oss << "Tpetra::MultiVectorFillerData2<"
00429           << Teuchos::TypeNameTraits<MV>::name () << ">";
00430       return oss.str();
00431     }
00432 
00433     void
00434     describe (Teuchos::FancyOStream& out,
00435               const Teuchos::EVerbosityLevel verbLevel =
00436               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 
00578       const size_t oldNumColumns = numCols_;
00579       if (newNumColumns == oldNumColumns) {
00580         return; // No side effects if no change.
00581       }
00582 
00583       RCP<MV> newLocalVec;
00584       if (newNumColumns > oldNumColumns) {
00585         newLocalVec = rcp (new MV (map_, newNumColumns));
00586         // Assign the contents of the old local multivector to the
00587         // first oldNumColumns columns of the new local multivector,
00588         // then get rid of the old local multivector.
00589         RCP<MV> newLocalVecView =
00590           newLocalVec->subViewNonConst (Range1D (0, oldNumColumns-1));
00591         *newLocalVecView = *localVec_;
00592       }
00593       else {
00594         if (newNumColumns == 0) {
00595           // Tpetra::MultiVector doesn't let you construct a
00596           // multivector with zero columns.
00597           newLocalVec = Teuchos::null;
00598         }
00599         else {
00600           newLocalVec =
00601             localVec_->subViewNonConst (Range1D (0, newNumColumns-1));
00602         }
00603       }
00604 
00605       // Leave most side effects until the end, for exception safety.
00606       nonlocalIndices_.resize (newNumColumns);
00607       nonlocalValues_.resize (newNumColumns);
00608       localVec_ = newLocalVec;
00609       numCols_ = newNumColumns;
00610     }
00611 
00613     void
00614     sumIntoGlobalValues (Teuchos::ArrayView<const global_ordinal_type> rows,
00615                          size_t columnIndex,
00616                          Teuchos::ArrayView<const scalar_type> values)
00617     {
00618       using Teuchos::ArrayRCP;
00619       using Teuchos::ArrayView;
00620       typedef local_ordinal_type LO;
00621       typedef global_ordinal_type GO;
00622       typedef scalar_type ST;
00623 
00624       if (columnIndex >= getNumColumns()) {
00625         // Automatically expand the number of columns.  This
00626         // implicitly ensures that localVec_ is not null.
00627         setNumColumns (columnIndex + 1);
00628       }
00629 
00630       typename ArrayView<const GO>::const_iterator rowIter = rows.begin();
00631       typename ArrayView<const ST>::const_iterator valIter = values.begin();
00632       for ( ; rowIter != rows.end() && valIter != values.end(); ++rowIter, ++valIter) {
00633         const GO globalRowIndex = *rowIter;
00634         // Converting from global to local index could be logarithmic
00635         // in the number of global indices that this process owns,
00636         // depending on the Map implementation.  However, the lookup
00637         // allows us to store data in the local multivector, rather
00638         // than in a separate data structure.
00639         const LO localRowIndex = map_->getLocalElement (globalRowIndex);
00640         if (localRowIndex == Teuchos::OrdinalTraits<LO>::invalid()) {
00641           nonlocalIndices_[columnIndex].push_back (globalRowIndex);
00642           nonlocalValues_[columnIndex].push_back (*valIter);
00643         }
00644         else {
00645           // FIXME (mfh 27 Feb 2012) This will be very slow for GPU
00646           // Node types.  In that case, we should hold on to the view
00647           // of localVec_ as long as the number of columns doesn't
00648           // change, and make modifications to the view until
00649           // localAssemble() is called.
00650           ArrayRCP<ST> X_j = localVec_->getDataNonConst (columnIndex);
00651           // FIXME (mfh 27 Feb 2012) Allow different combine modes.
00652           // The current combine mode just adds to the current value
00653           // at that location.
00654           X_j[localRowIndex] += *valIter;
00655         }
00656       }
00657     }
00658 
00668     void
00669     sumIntoGlobalValues (Teuchos::ArrayView<const global_ordinal_type> rows,
00670                          Teuchos::ArrayView<const scalar_type> values)
00671     {
00672       using Teuchos::ArrayView;
00673       typedef typename ArrayView<const global_ordinal_type>::size_type size_type;
00674 
00675       const size_t numCols = getNumColumns();
00676       for (size_t j = 0; j < numCols; ++j) {
00677         const size_type offset = numCols*j;
00678         const size_type len = numCols;
00679         sumIntoGlobalValues (rows.view (offset, len), j, values.view (offset, len));
00680       }
00681     }
00682 
00707     template<class BinaryFunction>
00708     void
00709     locallyAssemble (MV& X, BinaryFunction& f)
00710     {
00711       using Teuchos::ArrayRCP;
00712       using Teuchos::ArrayView;
00713       using Teuchos::FancyOStream;
00714       using Teuchos::getFancyOStream;
00715       using Teuchos::oblackholestream;
00716       using Teuchos::RCP;
00717       using Teuchos::rcp;
00718       using std::endl;
00719 
00720       typedef local_ordinal_type LO;
00721       typedef global_ordinal_type GO;
00722       typedef scalar_type ST;
00723 
00724       // Default output stream prints nothing.
00725       RCP<FancyOStream> out = out_.is_null() ?
00726         getFancyOStream (rcp (new oblackholestream)) : out_;
00727 
00728       Teuchos::OSTab tab (out);
00729       *out << "locallyAssemble:" << endl;
00730 
00731       RCP<const map_type> srcMap = X.getMap();
00732       ArrayView<const GO> localIndices = map_->getNodeElementList ();
00733 
00734       for (size_t j = 0; j < X.getNumVectors(); ++j) {
00735         ArrayRCP<ST> X_j = X.getDataNonConst (j);
00736 
00737         // First add all the local data into X_j.
00738         ArrayRCP<const ST> local_j = localVec_->getDataNonConst (j);
00739         for (typename ArrayView<const GO>::const_iterator it = localIndices.begin();
00740              it != localIndices.end(); ++it) {
00741           const LO rowIndLocal = map_->getLocalElement (*it);
00742           const LO rowIndX = srcMap->getLocalElement (*it);
00743 
00744           TEUCHOS_TEST_FOR_EXCEPTION(rowIndX == Teuchos::OrdinalTraits<LO>::invalid(),
00745             std::invalid_argument, "locallyAssemble(): Input multivector X does "
00746             "not own the global index " << *it << ".  This probably means that "
00747             "X was not constructed with the right Map.");
00748           X_j[rowIndX] = f (X_j[rowIndX], local_j[rowIndLocal]);
00749         }
00750 
00751         // Now add the nonlocal data into X_j.
00752         ArrayView<const GO> nonlocalIndices = nonlocalIndices_[j]();
00753         typename ArrayView<const GO>::const_iterator indexIter = nonlocalIndices.begin();
00754         ArrayView<const ST> nonlocalValues = nonlocalValues_[j]();
00755         typename ArrayView<const ST>::const_iterator valueIter = nonlocalValues.begin();
00756         for ( ; indexIter != nonlocalIndices.end() && valueIter != nonlocalValues.end();
00757               ++indexIter, ++valueIter) {
00758           const LO rowIndX = srcMap->getLocalElement (*indexIter);
00759           X_j[rowIndX] = f (X_j[rowIndX], *valueIter);
00760         }
00761       }
00762 
00763       *out << "Locally assembled vector:" << endl;
00764       X.describe (*out, Teuchos::VERB_EXTREME);
00765     }
00766 
00768     void
00769     locallyAssemble (MV& X)
00770     {
00771       std::plus<double> f;
00772       locallyAssemble<std::plus<scalar_type> > (X, f);
00773     }
00774 
00780     void clear() {
00781       Teuchos::Array<Teuchos::Array<global_ordinal_type> > newNonlocalIndices;
00782       Teuchos::Array<Teuchos::Array<scalar_type> > newNonlocalValues;
00783       // The standard STL idiom for clearing the contents of a vector
00784       // completely.  Setting the size to zero may not necessarily
00785       // deallocate data.
00786       std::swap (nonlocalIndices_, newNonlocalIndices);
00787       std::swap (nonlocalValues_, newNonlocalValues);
00788 
00789       // Don't actually deallocate the multivector of local entries.
00790       // Just fill it with zero.  This is because the caller hasn't
00791       // reset the number of columns.
00792       if (! localVec_.is_null()) {
00793         localVec_->putScalar (Teuchos::ScalarTraits<scalar_type>::zero());
00794       }
00795     }
00796 
00797   private:
00799     Teuchos::RCP<const map_type> map_;
00800 
00802     size_t numCols_;
00803 
00805     Teuchos::RCP<MV> localVec_;
00806 
00808     Teuchos::Array<Teuchos::Array<global_ordinal_type> > nonlocalIndices_;
00809 
00811     Teuchos::Array<Teuchos::Array<scalar_type> > nonlocalValues_;
00812 
00814     Teuchos::EVerbosityLevel verbLevel_;
00815 
00817     Teuchos::RCP<Teuchos::FancyOStream> out_;
00818 
00820     size_t getNumColumns() const { return numCols_; }
00821 
00823     Teuchos::ArrayView<const global_ordinal_type>
00824     getLocalIndices() const
00825     {
00826       return map_->getNodeElementList ();
00827     }
00828 
00830     Teuchos::Array<global_ordinal_type>
00831     getSortedUniqueNonlocalIndices() const
00832     {
00833       using Teuchos::Array;
00834       using Teuchos::ArrayView;
00835       using Teuchos::as;
00836       typedef global_ordinal_type GO;
00837       typedef typename Array<GO>::size_type size_type;
00838 
00839       Array<GO> allNonlocals (0); // will resize below
00840       const size_t numCols = getNumColumns();
00841 
00842       if (numCols == 1) {
00843         // Special case for 1 column avoids copying indices twice.
00844         // Pick the size of the array exactly the first time so there
00845         // are at most two allocations (the constructor may choose to
00846         // allocate).
00847         const size_type numNew = nonlocalIndices_[0].size();
00848         allNonlocals.resize (allNonlocals.size() + numNew);
00849         std::copy (nonlocalIndices_[0].begin(), nonlocalIndices_[0].end(),
00850                    allNonlocals.begin());
00851         std::sort (allNonlocals.begin(), allNonlocals.end());
00852         typename Array<GO>::iterator it =
00853           std::unique (allNonlocals.begin(), allNonlocals.end());
00854         const size_type numFinal = as<size_type> (it - allNonlocals.begin());
00855         allNonlocals.resize (numFinal);
00856       }
00857       else {
00858         // Carefully collect all the row indices one column at a time.
00859         // This ensures that the total allocation size in this routine
00860         // is independent of the number of columns.  Also, only sort
00861         // the current column's indices.  Use merges to ensure sorted
00862         // order in the collected final result.
00863         ArrayView<GO> curNonlocalsView = allNonlocals.view (0, 0); // will grow
00864         Array<GO> newNonlocals;
00865         for (size_t j = 0; j < numCols; ++j) {
00866           const size_type numNew = nonlocalIndices_[j].size();
00867           if (numNew > newNonlocals.size()) {
00868             newNonlocals.resize (numNew);
00869           }
00870           ArrayView<GO> newNonlocalsView = newNonlocals.view (0, numNew);
00871           std::copy (nonlocalIndices_[j].begin(), nonlocalIndices_[j].end(),
00872                      newNonlocalsView.begin());
00873           curNonlocalsView = sortAndMergeIn<GO> (allNonlocals, curNonlocalsView,
00874                                                  newNonlocalsView);
00875         }
00876       }
00877       return allNonlocals;
00878     }
00879   };
00880 } // namespace Details
00881 } // namespace Tpetra
00882 
00883 namespace Tpetra {
00884 
00909   template<class MV>
00910   class MultiVectorFiller {
00911   public:
00912     typedef typename MV::scalar_type scalar_type;
00913     typedef typename MV::local_ordinal_type local_ordinal_type;
00914     typedef typename MV::global_ordinal_type global_ordinal_type;
00915     typedef typename MV::node_type node_type;
00916     typedef Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
00917 
00947     MultiVectorFiller (const Teuchos::RCP<const map_type>& map,
00948                        const size_t numCols);
00949 
00969     void globalAssemble (MV& X_out, const bool forceReuseMap = false);
00970 
00971     void
00972     describe (Teuchos::FancyOStream& out,
00973               const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
00974     {
00975       data_.describe (out, verbLevel);
00976     }
00977 
00988     void
00989     sumIntoGlobalValues (Teuchos::ArrayView<const global_ordinal_type> rows,
00990                          size_t column,
00991                          Teuchos::ArrayView<const scalar_type> values)
00992     {
00993       data_.sumIntoGlobalValues (rows, column, values);
00994     }
00995 
01011     void
01012     sumIntoGlobalValues (Teuchos::ArrayView<const global_ordinal_type> rows,
01013                          Teuchos::ArrayView<const scalar_type> values)
01014     {
01015       data_.sumIntoGlobalValues (rows, values);
01016     }
01017 
01018   private:
01020     Teuchos::RCP<const map_type> ctorMap_;
01021 
01026     Teuchos::RCP<const map_type> sourceMap_;
01027 
01033     Teuchos::RCP<const map_type> targetMap_;
01034 
01047     Teuchos::RCP<MV> sourceVec_;
01048 
01053     Tpetra::Details::MultiVectorFillerData2<MV> data_;
01054 
01055     typedef Tpetra::Export<local_ordinal_type, global_ordinal_type, node_type> export_type;
01056     Teuchos::RCP<export_type> exporter_;
01057 
01063     void locallyAssemble (MV& X_in) {
01064       data_.locallyAssemble (X_in);
01065     }
01066 
01068     Teuchos::Array<global_ordinal_type> getSourceIndices () const {
01069       return data_.getSourceIndices();
01070     }
01071 
01080     Teuchos::RCP<const map_type>
01081     computeSourceMap (const global_ordinal_type indexBase,
01082                       const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
01083                       const Teuchos::RCP<node_type>& node);
01084   };
01085 
01086   template<class MV>
01087   MultiVectorFiller<MV>::MultiVectorFiller (const Teuchos::RCP<const typename MultiVectorFiller<MV>::map_type>& map, const size_t numCols)
01088     : ctorMap_ (map),
01089       sourceMap_ (Teuchos::null),
01090       targetMap_ (Teuchos::null),
01091       data_ (map, numCols),
01092       exporter_ (Teuchos::null)
01093   {}
01094 
01095   template<class MV>
01096   Teuchos::RCP<const typename MultiVectorFiller<MV>::map_type>
01097   MultiVectorFiller<MV>::
01098   computeSourceMap (const global_ordinal_type indexBase,
01099                     const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
01100                     const Teuchos::RCP<node_type>& node)
01101   {
01102     using Teuchos::Array;
01103     using Teuchos::ArrayView;
01104     using Teuchos::rcp;
01105     typedef global_ordinal_type GO;
01106 
01107     Array<GO> indices = getSourceIndices ();
01108 
01109     // Passing "invalid" for the numGlobalElements argument of the Map
01110     // constructor tells the Map to compute the global number of
01111     // elements itself.
01112     const Tpetra::global_size_t invalid =
01113       Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid();
01114     return rcp (new map_type (invalid, indices, indexBase, comm, node));
01115   }
01116 
01117   template<class MV>
01118   void
01119   MultiVectorFiller<MV>::globalAssemble (MV& X_out, const bool forceReuseMap)
01120   {
01121     using Teuchos::ArrayView;
01122     using Teuchos::Array;
01123     using Teuchos::Range1D;
01124     using Teuchos::RCP;
01125     using Teuchos::rcp;
01126 
01127     const size_t numVecs = X_out.getNumVectors();
01128 
01129     if (numVecs == 0) {
01130       // Nothing to do!  Of course, this does not check for whether
01131       // X_out has the right number of rows.  That's OK, though.
01132       // Compare to the definition of the BLAS' _AXPY for an input
01133       // vector containing NaNs, but multiplied by alpha=0.
01134       return;
01135     }
01136     //
01137     // Get the target Map of the Export.  If X_out's Map is the same
01138     // as the target Map from last time, then we may be able to
01139     // recycle the Export from last time, if the source Map is also
01140     // the same.
01141     //
01142     RCP<const map_type> targetMap;
01143     bool assumeSameTargetMap = false;
01144     if (targetMap_.is_null()) {
01145       targetMap_ = X_out.getMap();
01146       targetMap = targetMap_;
01147       assumeSameTargetMap = false;
01148     }
01149     else {
01150       if (forceReuseMap) {
01151         targetMap = targetMap_;
01152         assumeSameTargetMap = true;
01153       }
01154       else  {
01155         // If X_out's Map is the same as targetMap_, we may be able to
01156         // reuse the Export.  Constructing the Export may be more
01157         // expensive than calling isSameAs() (which requires just a
01158         // few reductions and reading through the lists of owned
01159         // global indices), so it's worth checking.
01160         if (targetMap_->isSameAs (*(X_out.getMap()))) {
01161           assumeSameTargetMap = true;
01162           targetMap = targetMap_;
01163         }
01164       }
01165     }
01166     //
01167     // Get the source Map of the Export.  If the source Map of the
01168     // Export is the same as last time, then we may be able to recycle
01169     // the Export from last time, if the target Map is also the same.
01170     //
01171     RCP<const map_type> sourceMap;
01172     bool computedSourceMap = false;
01173     {
01174       if (forceReuseMap && ! sourceMap_.is_null()) {
01175         sourceMap = sourceMap_;
01176       }
01177       else {
01178         sourceMap = computeSourceMap (ctorMap_->getIndexBase(),
01179                                       ctorMap_->getComm(),
01180                                       ctorMap_->getNode());
01181         computedSourceMap = true;
01182       }
01183     }
01184     if (computedSourceMap) {
01185       sourceMap_ = sourceMap;
01186     }
01187     //
01188     // Now that we have the source and target Maps of the Export, we
01189     // can check whether we can recycle the Export from last time.
01190     //
01191     const bool mustComputeExport =
01192       (exporter_.is_null() || (assumeSameTargetMap && ! computedSourceMap));
01193     if (mustComputeExport) {
01194       exporter_ = rcp (new export_type (sourceMap_, targetMap_));
01195     }
01196 
01197     // Source multivector for the Export.
01198     RCP<MV> X_in;
01199     const bool mustReallocateVec = sourceVec_.is_null() ||
01200       sourceVec_->getNumVectors() < numVecs || ! assumeSameTargetMap;
01201 
01202     if (mustReallocateVec) {
01203       // Reallocating nonlocalVec_ ensures that it has the right Map.
01204       sourceVec_ = rcp (new MV (sourceMap_, numVecs));
01205       X_in = sourceVec_;
01206     } else {
01207       if (sourceVec_->getNumVectors() == numVecs) {
01208         X_in = sourceVec_;
01209       } else { // sourceVec_ has more vectors than needed.
01210         X_in = sourceVec_->subViewNonConst (Range1D (0, numVecs-1));
01211       }
01212     }
01213 
01214     // "Locally assemble" the data into X_in by summing together
01215     // entries with the same indices.
01216     locallyAssemble (*X_in);
01217 
01218     // Do the Export.
01219     const Tpetra::CombineMode combineMode = Tpetra::ADD;
01220     X_out.doExport (*X_in, *exporter_, combineMode);
01221   }
01222 
01223   namespace Test {
01224 
01230     template<class MV>
01231     class MultiVectorFillerTester {
01232     public:
01233       typedef typename MV::scalar_type scalar_type;
01234       typedef typename MV::local_ordinal_type local_ordinal_type;
01235       typedef typename MV::global_ordinal_type global_ordinal_type;
01236       typedef typename MV::node_type node_type;
01237       typedef Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
01238 
01247       static void
01248       testSameMap (const Teuchos::RCP<const map_type>& targetMap,
01249                    const global_ordinal_type eltSize, // Must be odd
01250                    const size_t numCols,
01251                    const Teuchos::RCP<Teuchos::FancyOStream>& outStream=Teuchos::null,
01252                    const Teuchos::EVerbosityLevel verbosityLevel=Teuchos::VERB_DEFAULT)
01253       {
01254         using Teuchos::Array;
01255         using Teuchos::ArrayRCP;
01256         using Teuchos::ArrayView;
01257         using Teuchos::as;
01258         using Teuchos::Comm;
01259         using Teuchos::FancyOStream;
01260         using Teuchos::getFancyOStream;
01261         using Teuchos::oblackholestream;
01262         using Teuchos::ptr;
01263         using Teuchos::RCP;
01264         using Teuchos::rcp;
01265         using Teuchos::rcpFromRef;
01266         using Teuchos::REDUCE_SUM;
01267         using Teuchos::reduceAll;
01268         using std::cerr;
01269         using std::endl;
01270 
01271         typedef local_ordinal_type LO;
01272         typedef global_ordinal_type GO;
01273         typedef scalar_type ST;
01274         typedef Teuchos::ScalarTraits<ST> STS;
01275 
01276         TEUCHOS_TEST_FOR_EXCEPTION(eltSize % 2 == 0, std::invalid_argument,
01277           "Element size (eltSize) argument must be odd.");
01278         TEUCHOS_TEST_FOR_EXCEPTION(numCols == 0, std::invalid_argument,
01279           "Number of columns (numCols) argument must be nonzero.");
01280         // Default behavior is to print nothing out.
01281         RCP<FancyOStream> out = outStream.is_null() ?
01282           getFancyOStream (rcp (new oblackholestream)) : outStream;
01283         const Teuchos::EVerbosityLevel verbLevel =
01284           (verbosityLevel == Teuchos::VERB_DEFAULT) ?
01285           Teuchos::VERB_NONE : verbosityLevel;
01286 
01287         //RCP<MV> X = rcp (new MV (targetMap, numCols));
01288 
01289         const GO indexBase = targetMap->getIndexBase();
01290         Array<GO> rows (eltSize);
01291         Array<ST> values (eltSize);
01292         std::fill (values.begin(), values.end(), STS::one());
01293 
01294         // Make this a pointer so we can free its contents, in case
01295         // those contents depend on the input to globalAssemble().
01296         RCP<MultiVectorFiller<MV> > filler =
01297           rcp (new MultiVectorFiller<MV> (targetMap, numCols));
01298 
01299         TEUCHOS_TEST_FOR_EXCEPTION(! targetMap->isContiguous(),
01300           std::invalid_argument, "MultiVectorFiller test currently only works "
01301           "for contiguous Maps.");
01302 
01303         const GO minGlobalIndex = targetMap->getMinGlobalIndex();
01304         const GO maxGlobalIndex = targetMap->getMaxGlobalIndex();
01305         const GO minAllGlobalIndex = targetMap->getMinAllGlobalIndex();
01306         const GO maxAllGlobalIndex = targetMap->getMaxAllGlobalIndex();
01307         for (size_t j = 0; j < numCols; ++j) {
01308           for (GO i = minGlobalIndex; i <= maxGlobalIndex; ++i) {
01309             // Overlap over processes, without running out of bounds.
01310             const GO start = std::max (i - eltSize/2, minAllGlobalIndex);
01311             const GO end = std::min (i + eltSize/2, maxAllGlobalIndex);
01312             const GO len = end - start + 1;
01313 
01314             TEUCHOS_TEST_FOR_EXCEPTION(len > eltSize, std::logic_error,
01315               "At start,end = " << start << "," << end << ", len = " << len
01316               << " > eltSize = " << eltSize << ".");
01317 
01318             for (GO k = 0; k < len; ++k) {
01319               rows[k] = start + k;
01320             }
01321             if (verbLevel == Teuchos::VERB_EXTREME) {
01322               *out << "Inserting: "
01323                    << Teuchos::toString (rows.view(0,len)) << ", "
01324                    << Teuchos::toString (values.view(0, len)) << std::endl;
01325             }
01326             filler->sumIntoGlobalValues (rows.view(0, len), j, values.view(0, len));
01327           }
01328         }
01329 
01330         if (verbLevel == Teuchos::VERB_EXTREME) {
01331           *out << "Filler:" << std::endl;
01332           filler->describe (*out, verbLevel);
01333           *out << std::endl;
01334         }
01335 
01336         MV X_out (targetMap, numCols);
01337         filler->globalAssemble (X_out);
01338         filler = Teuchos::null;
01339 
01340         if (verbLevel == Teuchos::VERB_EXTREME) {
01341           *out << "X_out:" << std::endl;
01342           X_out.describe (*out, verbLevel);
01343           *out << std::endl;
01344         }
01345 
01346         // Create multivector for comparison.
01347         MV X_expected (targetMap, numCols);
01348         const scalar_type two = STS::one() + STS::one();
01349         for (size_t j = 0; j < numCols; ++j) {
01350           ArrayRCP<ST> X_j = X_expected.getDataNonConst (j);
01351 
01352           // Each entry of the column should have the value eltSize,
01353           // except for the first and last few entries in the whole
01354           // column (globally, not locally).
01355           for (GO i = minGlobalIndex; i <= maxGlobalIndex; ++i) {
01356             const LO localIndex = targetMap->getLocalElement (i);
01357             TEUCHOS_TEST_FOR_EXCEPTION(i == Teuchos::OrdinalTraits<LO>::invalid(),
01358               std::logic_error, "Global index " << i << " is not in the "
01359               "multivector's Map.");
01360 
01361             if (i <= minAllGlobalIndex + eltSize/2) {
01362               X_j[localIndex] = two + as<ST>(i) - as<ST>(indexBase);
01363             }
01364             else if (i >= maxAllGlobalIndex - eltSize/2) {
01365               X_j[localIndex] = two + as<ST>(maxAllGlobalIndex) - as<ST>(i);
01366             }
01367             else {
01368               X_j[localIndex] = as<ST>(eltSize);
01369             }
01370           } // for each global index which my process owns
01371         } // for each column of the multivector
01372 
01373         if (verbLevel == Teuchos::VERB_EXTREME) {
01374           *out << "X_expected:" << std::endl;
01375           X_expected.describe (*out, verbLevel);
01376           *out << std::endl;
01377         }
01378 
01379         Array<GO> errorLocations;
01380         for (size_t j = 0; j < numCols; ++j) {
01381           ArrayRCP<const ST> X_out_j = X_out.getData (j);
01382           ArrayRCP<const ST> X_expected_j = X_expected.getData (j);
01383 
01384           // Each entry of the column should have the value eltSize,
01385           // except for the first and last few entries in the whole
01386           // column (globally, not locally).
01387           for (GO i = minGlobalIndex; i <= maxGlobalIndex; ++i) {
01388             const LO localIndex = targetMap->getLocalElement (i);
01389             TEUCHOS_TEST_FOR_EXCEPTION(i == Teuchos::OrdinalTraits<LO>::invalid(),
01390               std::logic_error, "Global index " << i << " is not in the "
01391               "multivector's Map.");
01392 
01393             // The floating-point additions should be exact in this
01394             // case, except for very large values of eltSize.
01395             if (X_out_j[localIndex] != X_expected_j[localIndex]) {
01396               errorLocations.push_back (i);
01397             }
01398           } // for each global index which my process owns
01399 
01400           const typename Array<GO>::size_type localNumErrors = errorLocations.size();
01401           typename Array<GO>::size_type globalNumErrors = 0;
01402           RCP<const Comm<int> > comm = targetMap->getComm();
01403           reduceAll (*comm, REDUCE_SUM, localNumErrors, ptr (&globalNumErrors));
01404 
01405           if (globalNumErrors != 0) {
01406             std::ostringstream os;
01407             os << "Proc " << comm->getRank() << ": " << localNumErrors
01408                << " incorrect value" << (localNumErrors != 1 ? "s" : "")
01409                << ".  Error locations: [ ";
01410             std::copy (errorLocations.begin(), errorLocations.end(),
01411                        std::ostream_iterator<GO> (os, " "));
01412             os << "].";
01413             // Iterate through all processes in the communicator,
01414             // printing out each process' local errors.
01415             for (int p = 0; p < comm->getSize(); ++p) {
01416               if (p == comm->getRank()) {
01417                 cerr << os.str() << endl;
01418               }
01419               // Barriers to let output finish.
01420               comm->barrier();
01421               comm->barrier();
01422               comm->barrier();
01423             }
01424             TEUCHOS_TEST_FOR_EXCEPTION(globalNumErrors != 0, std::logic_error,
01425               "Over all procs: " << globalNumErrors << " total error"
01426               << (globalNumErrors != 1 ? "s" : "") << ".");
01427           } // if there were any errors in column j
01428         } // for each column j
01429       }
01430     };
01431 
01433     template<class ScalarType,
01434              class LocalOrdinalType,
01435              class GlobalOrdinalType,
01436              class NodeType>
01437     void
01438     testMultiVectorFiller (const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
01439                            const Teuchos::RCP<NodeType>& node,
01440                            const size_t unknownsPerNode,
01441                            const GlobalOrdinalType unknownsPerElt,
01442                            const size_t numCols,
01443                            const Teuchos::RCP<Teuchos::FancyOStream>& outStream,
01444                            const Teuchos::EVerbosityLevel verbLevel)
01445     {
01446       using Tpetra::createContigMapWithNode;
01447       using Teuchos::FancyOStream;
01448       using Teuchos::getFancyOStream;
01449       using Teuchos::oblackholestream;
01450       using Teuchos::ParameterList;
01451       using Teuchos::RCP;
01452       using Teuchos::rcp;
01453       using std::cerr;
01454       using std::endl;
01455 
01456       typedef ScalarType ST;
01457       typedef LocalOrdinalType LO;
01458       typedef GlobalOrdinalType GO;
01459       typedef NodeType NT;
01460       typedef Tpetra::Map<LO, GO, NT> MT;
01461       typedef Tpetra::MultiVector<ST, LO, GO, NT> MV;
01462 
01463       RCP<FancyOStream> out = outStream.is_null() ?
01464         getFancyOStream (rcp (new oblackholestream)) : outStream;
01465       const Tpetra::global_size_t invalid =
01466         Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid();
01467       RCP<const MT> targetMap =
01468         createContigMapWithNode<LO, GO, NT> (invalid, unknownsPerNode, comm, node);
01469 
01470       std::ostringstream os;
01471       try {
01472         MultiVectorFillerTester<MV>::testSameMap (targetMap, unknownsPerElt, numCols, out, verbLevel);
01473       } catch (std::exception& e) {
01474         os << e.what();
01475       }
01476 
01477       for (int p = 0; p < comm->getSize(); ++p) {
01478         if (p == comm->getRank()) {
01479           *out << "On process " << comm->getRank() << ": " << os.str() << endl;
01480         }
01481         comm->barrier();
01482         comm->barrier();
01483         comm->barrier();
01484       }
01485     }
01486 
01492     void
01493     testSortAndMergeIn ();
01494 
01495   } // namespace Test
01496 } // namespace Tpetra
01497 
01498 
01499 #endif // __Tpetra_MultiVectorFiller_hpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines