Tpetra_MultiVector.hpp

00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //          Tpetra: Templated Linear Algebra Services Package
00005 //                 Copyright (2004) Sandia Corporation
00006 // 
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 // 
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 
00025 // 
00026 // ***********************************************************************
00027 // @HEADER
00028 
00029 // TODO: with contiguous MVs, some of the level one blas routines below can be turned from multiple calls to one call for best efficiency (eliminate loop over numVecs)
00030 
00031 #ifndef TPETRA_MULTIVECTOR_HPP
00032 #define TPETRA_MULTIVECTOR_HPP
00033 
00034 #include <Teuchos_TestForException.hpp>
00035 #include <Teuchos_as.hpp>
00036 #include <Teuchos_CommHelpers.hpp>
00037 #include <Teuchos_OrdinalTraits.hpp>
00038 #include <Teuchos_Array.hpp>
00039 #include <Teuchos_Ptr.hpp>
00040 #include <Teuchos_BLAS.hpp>
00041 
00042 #include "Tpetra_MultiVectorDecl.hpp"
00043 #include "Tpetra_MultiVectorData.hpp"
00044 
00045 namespace Tpetra {
00046 
00047   template <typename Ordinal, typename Scalar> 
00048   MultiVector<Ordinal,Scalar>::MultiVector(const Map<Ordinal> &map, Ordinal NumVectors, bool zeroOut) 
00049     : DistObject<Ordinal,Scalar>(map, map.getComm(), "Tpetra::MultiVector")
00050   {
00051     using Teuchos::as;
00052     TEST_FOR_EXCEPTION(NumVectors < 1, std::invalid_argument,
00053         "Tpetra::MultiVector::MultiVector(): NumVectors must be strictly positive.");
00054     const Ordinal myLen = myLength();
00055     MVData_ = Teuchos::rcp( new MultiVectorData<Ordinal,Scalar>() );
00056     MVData_->constantStride_ = true;
00057     MVData_->stride_ = myLen;
00058     MVData_->ptrs_.resize(NumVectors,Teuchos::null);
00059     if (myLen > as<Ordinal>(0)) {
00060       MVData_->values_ = Teuchos::arcp<Scalar>(NumVectors*myLen);
00061       if (zeroOut) {
00062         std::fill(MVData_->values_.begin(),MVData_->values_.end(),Teuchos::ScalarTraits<Scalar>::zero());
00063       }
00064       for (Ordinal i = as<Ordinal>(0); i < NumVectors; ++i) {
00065         MVData_->ptrs_[i] = MVData_->values_(i*myLen,myLen);
00066       }
00067     }
00068     MVData_->updateConstPointers();
00069   }
00070 
00071 
00072   template <typename Ordinal, typename Scalar> 
00073   MultiVector<Ordinal,Scalar>::MultiVector(const MultiVector<Ordinal,Scalar> &source) 
00074     : DistObject<Ordinal,Scalar>(source)
00075   {
00076     // copy data from the source MultiVector into this multivector
00077     // this multivector will be allocated with constant stride, even if the source multivector does not have constant stride
00078     using Teuchos::as;
00079     const Ordinal myLen   = myLength();
00080     const Ordinal numVecs = source.numVectors();
00081     MVData_ = Teuchos::rcp( new MultiVectorData<Ordinal,Scalar>() );
00082     MVData_->constantStride_ = true;
00083     MVData_->stride_ = myLen;
00084     MVData_->ptrs_.resize(numVecs,Teuchos::null);
00085     if (myLen > as<Ordinal>(0)) {
00086       MVData_->values_ = Teuchos::arcp<Scalar>(numVecs*myLen);
00087       for (Ordinal i = as<Ordinal>(0); i < numVecs; ++i) {
00088         MVData_->ptrs_[i] = MVData_->values_(i*myLen,myLen);
00089         std::copy( source.MVData_->ptrs_[i].begin(), source.MVData_->ptrs_[i].end(), MVData_->ptrs_[i].begin() );
00090       }
00091     }
00092     MVData_->updateConstPointers();
00093   }
00094 
00095 
00096   template <typename Ordinal, typename Scalar> 
00097   MultiVector<Ordinal,Scalar>::MultiVector(const Map<Ordinal> &map, const Teuchos::ArrayView<const Scalar> &A, Ordinal LDA, Ordinal NumVectors)
00098     : DistObject<Ordinal,Scalar>(map, map.getComm(), "Tpetra::MultiVector")
00099   {
00100     using Teuchos::ArrayView;
00101     using Teuchos::as;
00102     TEST_FOR_EXCEPTION(NumVectors < 1, std::invalid_argument,
00103         "Tpetra::MultiVector::MultiVector(): NumVectors must be strictly positive.");
00104     const Ordinal myLen = myLength();
00105 #ifdef TEUCHOS_DEBUG
00106     // need LDA*(NumVectors-1)+myLen elements in A
00107     TEST_FOR_EXCEPTION(A.size() < LDA*(NumVectors-1)+myLen, std::runtime_error,
00108         "Tpetra::MultiVector::MultiVector(): A,LDA must be large enough to accomodate the local entries.");
00109 #endif
00110     TEST_FOR_EXCEPTION(LDA < myLen, std::invalid_argument,
00111         "Tpetra::MultiVector::MultiVector(): LDA must be large enough to accomodate the local entries.");
00112     MVData_ = Teuchos::rcp( new MultiVectorData<Ordinal,Scalar>() );
00113     MVData_->constantStride_ = true;
00114     MVData_->stride_ = myLen;
00115     MVData_->ptrs_.resize(NumVectors,Teuchos::null);
00116     if (myLen > as<Ordinal>(0)) {
00117       MVData_->values_ = Teuchos::arcp<Scalar>(NumVectors*myLen);
00118       for (Ordinal i = as<Ordinal>(0); i < NumVectors; ++i) {
00119         MVData_->ptrs_[i] = MVData_->values_(i*myLen,myLen);
00120         // copy data from A to my internal data structure
00121         ArrayView<const Scalar> Aptr = A(i*LDA,myLen);
00122         std::copy(Aptr.begin(),Aptr.end(),MVData_->ptrs_[i].begin());
00123       }
00124     }
00125     MVData_->updateConstPointers();
00126   }
00127 
00128 
00129   template <typename Ordinal, typename Scalar> 
00130   MultiVector<Ordinal,Scalar>::MultiVector(const Map<Ordinal> &map, const Teuchos::RCP<MultiVectorData<Ordinal,Scalar> > &mvdata) 
00131     : DistObject<Ordinal,Scalar>(map, map.getComm(), "Tpetra::MultiVector"), MVData_(mvdata)
00132   {}
00133 
00134 
00135   template <typename Ordinal, typename Scalar> 
00136   MultiVector<Ordinal,Scalar>::MultiVector(const Map<Ordinal> &map, const Teuchos::ArrayView<const Teuchos::ArrayView<const Scalar> > &arrayOfArrays)
00137     : DistObject<Ordinal,Scalar>(map, map.getComm(), "Tpetra::MultiVector")
00138   {
00139     using Teuchos::as;
00140     const Ordinal myLen = myLength();
00141     Ordinal NumVectors = arrayOfArrays.size();
00142     TEST_FOR_EXCEPTION(NumVectors < 1, std::runtime_error,
00143         "Tpetra::MultiVector::MultiVector(map,arrayOfArrays): arrayOfArrays.size() must be strictly positive.");
00144     MVData_ = Teuchos::rcp( new MultiVectorData<Ordinal,Scalar>() );
00145     MVData_->constantStride_ = true;
00146     MVData_->stride_ = myLen;
00147     MVData_->ptrs_.resize(NumVectors,Teuchos::null);
00148     if (myLen > as<Ordinal>(0)) {
00149       MVData_->values_ = Teuchos::arcp<Scalar>(NumVectors*myLen);
00150       for (Ordinal i = as<Ordinal>(0); i < NumVectors; ++i) {
00151         MVData_->ptrs_[i] = MVData_->values_(i*myLen,myLen);
00152 #ifdef TEUCHOS_DEBUG
00153         TEST_FOR_EXCEPTION(arrayOfArrays[i].size() != myLength(), std::runtime_error,
00154             "Tpetra::MultiVector::MultiVector(map,arrayOfArrays): arrayOfArrays[" << i << "].size() (==" << arrayOfArrays[i].size() 
00155             << ") != myLength() (==" << myLength() << ")");
00156 #endif
00157         std::copy(arrayOfArrays[i].begin(),arrayOfArrays[i].end(),MVData_->ptrs_[i].begin());
00158       }
00159     }
00160     MVData_->updateConstPointers();
00161   }
00162 
00163 
00164   template <typename Ordinal, typename Scalar> 
00165   MultiVector<Ordinal,Scalar>::~MultiVector()
00166   {}
00167 
00168 
00169   template <typename Ordinal, typename Scalar> 
00170   bool MultiVector<Ordinal,Scalar>::constantStride() const
00171   {
00172     return MVData_->constantStride_;
00173   }
00174 
00175 
00176   template <typename Ordinal, typename Scalar> 
00177   Ordinal MultiVector<Ordinal,Scalar>::myLength() const
00178   {
00179     return this->getMap().getNumMyEntries();
00180   }
00181 
00182 
00183   template <typename Ordinal, typename Scalar> 
00184   Ordinal MultiVector<Ordinal,Scalar>::globalLength() const
00185   {
00186     return this->getMap().getNumGlobalEntries();
00187   }
00188 
00189 
00190   template <typename Ordinal, typename Scalar> 
00191   Ordinal MultiVector<Ordinal,Scalar>::stride() const
00192   {
00193     return MVData_->stride_;
00194   }
00195 
00196 
00197   template <typename Ordinal, typename Scalar> 
00198   void MultiVector<Ordinal,Scalar>::print(std::ostream &os) const
00199   {
00200     using std::endl;
00201     Teuchos::RCP<const Teuchos::Comm<Ordinal> > comm = this->getMap().getComm();
00202     const int myImageID = comm->getRank();
00203     const int numImages = comm->getSize();
00204     for (int imageCtr = 0; imageCtr < numImages; ++imageCtr) {
00205       if (myImageID == imageCtr) {
00206         if (myImageID == 0) {
00207           os << "Number of vectors: " << numVectors() << endl;
00208           os << "Global length: " << globalLength() << endl;
00209         }
00210         os << "Local length: " << myLength() << endl;
00211         os << "Local stride: " << stride() << endl;
00212         os << "Constant stride: " << (constantStride() ? "true" : "false") << endl;
00213       }
00214       // Do a few global ops to give I/O a chance to complete
00215       comm->barrier();
00216       comm->barrier();
00217       comm->barrier();
00218     }
00219   }
00220 
00221 
00222   template <typename Ordinal, typename Scalar> 
00223   void MultiVector<Ordinal,Scalar>::printValues(std::ostream &os) const
00224   {
00225     using std::endl;
00226     using std::setw;
00227     Teuchos::RCP<const Teuchos::Comm<Ordinal> > comm = this->getMap().getComm();
00228     const Map<Ordinal> &map = this->getMap();
00229     const int myImageID = comm->getRank();
00230     const int numImages = comm->getSize();
00231     for (int imageCtr = 0; imageCtr < numImages; ++imageCtr) {
00232       if (myImageID == imageCtr) {
00233         for (int i=0; i<myLength(); ++i) {
00234           os << setw(4) << map.getGlobalIndex(i) << "\t";
00235           for (int j=0; j<numVectors(); ++j) {
00236             os << setw(20) << MVData_->ptrs_[j][i] << " ";
00237           }
00238           os << endl;
00239         }
00240       }
00241       // Do a few global ops to give I/O a chance to complete
00242       comm->barrier();
00243       comm->barrier();
00244       comm->barrier();
00245     }
00246   }
00247 
00248 
00249   template<typename Ordinal, typename Scalar>
00250   bool MultiVector<Ordinal,Scalar>::checkSizes(const DistObject<Ordinal,Scalar> &sourceObj, Ordinal &packetSize) 
00251   {
00252     const MultiVector<Ordinal,Scalar> &A = dynamic_cast<const MultiVector<Ordinal,Scalar>&>(sourceObj);
00253     // objects maps have already been checked. simply check the number of vectors.
00254     packetSize = this->numVectors();
00255     return (A.numVectors() == packetSize);
00256   }
00257 
00258   template<typename Ordinal, typename Scalar>
00259   void MultiVector<Ordinal,Scalar>::copyAndPermute(
00260       const DistObject<Ordinal,Scalar> & sourceObj,
00261       Ordinal numSameIDs,
00262       const Teuchos::ArrayView<const Ordinal> &permuteToLIDs,
00263       const Teuchos::ArrayView<const Ordinal> &permuteFromLIDs)
00264   {
00265     typedef Teuchos::OrdinalTraits<Ordinal> OT;
00266     using Teuchos::ArrayView;
00267     const MultiVector<Ordinal,Scalar> &sourceMV = dynamic_cast<const MultiVector<Ordinal,Scalar> &>(sourceObj);
00268     ArrayView<Scalar>          dstView(Teuchos::null);
00269     ArrayView<const Scalar>    srcView(Teuchos::null);
00270     typename ArrayView<const Ordinal>::iterator pTo, pFrom;
00271 #ifdef TEUCHOS_DEBUG
00272     // any other error will be caught by Teuchos
00273     TEST_FOR_EXCEPTION(permuteToLIDs.size() != permuteFromLIDs.size(), std::runtime_error,
00274         "Tpetra::MultiVector::copyAndPermute(): permuteToLIDs and permuteFromLIDs must have the same size.");
00275 #endif
00276     // one vector at a time
00277     for (Ordinal j = OT::zero(); j < numVectors(); ++j) {
00278       // the first numImportIDs GIDs are the same between source and target,
00279       // we can just copy them
00280       dstView = (*this)[j];
00281       srcView = sourceMV[j];
00282       std::copy(srcView.begin(),srcView.begin()+numSameIDs,dstView.begin());
00283       // next, do permutations
00284       for (pTo = permuteToLIDs.begin(), pFrom = permuteFromLIDs.begin();
00285            pTo != permuteToLIDs.end(); ++pTo, ++pFrom)
00286       {
00287         dstView[*pTo] = srcView[*pFrom];
00288       }
00289     }
00290   }
00291 
00292 
00293   template<typename Ordinal, typename Scalar>
00294   void MultiVector<Ordinal,Scalar>::packAndPrepare(
00295       const DistObject<Ordinal,Scalar> & sourceObj,
00296       const Teuchos::ArrayView<const Ordinal> &exportLIDs,
00297       const Teuchos::ArrayView<Scalar> &exports,
00298       Distributor<Ordinal> &distor)
00299   {
00300     const MultiVector<Ordinal,Scalar> &sourceMV = dynamic_cast<const MultiVector<Ordinal,Scalar> &>(sourceObj);
00301     typedef Teuchos::OrdinalTraits<Ordinal> OT;
00302     using Teuchos::ArrayView;
00303     (void)distor;    // we don't use these, but we don't want unused parameter warnings
00304     /* The layout in the export for MultiVectors is as follows:
00305        exports = { all of the data from row exportLIDs.front() ; 
00306                    ....
00307                    all of the data from row exportLIDs.back() }
00308       this doesn't have the best locality, but is necessary because the data for a Packet
00309       (all data associated with an LID) is required to be contiguous */
00310 #ifdef TEUCHOS_DEBUG
00311     TEST_FOR_EXCEPTION(exports.size() != numVectors()*exportLIDs.size(), std::runtime_error,
00312         "Tpetra::MultiVector::packAndPrepare(): sizing of exports buffer should be appropriate for the amount of data to be exported.");
00313 #endif
00314     typename ArrayView<       Scalar>::iterator  expptr;
00315     typename ArrayView<const Ordinal>::iterator  idptr;
00316     expptr = exports.begin();
00317     for (idptr = exportLIDs.begin(); idptr != exportLIDs.end(); ++idptr) {
00318       for (Ordinal j = OT::zero(); j < numVectors(); ++j) {
00319         *expptr++ = sourceMV[j][*idptr];
00320       }
00321     }
00322   }
00323 
00324 
00325   template<typename Ordinal, typename Scalar>
00326   void MultiVector<Ordinal,Scalar>::unpackAndCombine(
00327       const Teuchos::ArrayView<const Ordinal> &importLIDs,
00328       const Teuchos::ArrayView<const Scalar> &imports,
00329       Distributor<Ordinal> &distor,
00330       CombineMode CM)
00331   {
00332     (void)distor; // we don't use this, but we don't want unused parameter warnings
00333     typedef Teuchos::OrdinalTraits<Ordinal> OT;
00334     using Teuchos::ArrayView;
00335     /* The layout in the export for MultiVectors is as follows:
00336        imports = { all of the data from row exportLIDs.front() ; 
00337                    ....
00338                    all of the data from row exportLIDs.back() }
00339       this doesn't have the best locality, but is necessary because the data for a Packet
00340       (all data associated with an LID) is required to be contiguous */
00341 #ifdef TEUCHOS_DEBUG
00342     TEST_FOR_EXCEPTION(imports.size() != numVectors()*importLIDs.size(), std::runtime_error,
00343         "Tpetra::MultiVector::unpackAndCombine(): sizing of imports buffer should be appropriate for the amount of data to be exported.");
00344 #endif
00345     typename ArrayView<const  Scalar>::iterator  impptr;
00346     typename ArrayView<const Ordinal>::iterator  idptr;
00347     impptr = imports.begin();
00348     if (CM == INSERT || CM == REPLACE) 
00349     {
00350       for (idptr = importLIDs.begin(); idptr != importLIDs.end(); ++idptr) {
00351         for (Ordinal j = OT::zero(); j < numVectors(); ++j) {
00352           (*this)[j][*idptr] = *impptr++;
00353         }
00354       }
00355     }
00356     else if (CM == ADD) {
00357       for (idptr = importLIDs.begin(); idptr != importLIDs.end(); ++idptr) {
00358         for (Ordinal j = OT::zero(); j < numVectors(); ++j) {
00359           (*this)[j][*idptr] += *impptr++;
00360         }
00361       }
00362     }
00363     else {
00364       TEST_FOR_EXCEPTION(CM != ADD && CM != REPLACE && CM != INSERT, std::invalid_argument,
00365           "Tpetra::MultiVector::unpackAndCombine(): Invalid CombineMode: " << CM);
00366     }
00367   }
00368 
00369 
00370   template<typename Ordinal, typename Scalar>
00371   Ordinal MultiVector<Ordinal,Scalar>::numVectors() const 
00372   {
00373     return Teuchos::as<Ordinal>(MVData_->ptrs_.size());
00374   }
00375 
00376 
00377   template<typename Ordinal, typename Scalar>
00378   void MultiVector<Ordinal,Scalar>::dot(
00379       const MultiVector<Ordinal,Scalar> &A, 
00380       const Teuchos::ArrayView<Scalar> &dots) const 
00381   {
00382     Teuchos::BLAS<int,Scalar> blas;
00383     const Ordinal ZERO = Teuchos::OrdinalTraits<Ordinal>::zero();
00384     const Ordinal ONE = Teuchos::OrdinalTraits<Ordinal>::one();
00385     // compute local dot products of *this and A
00386     // sum these across all nodes
00387     const Ordinal numVecs = this->numVectors();
00388     TEST_FOR_EXCEPTION( !this->getMap().isCompatible(A.getMap()), std::runtime_error,
00389         "Tpetra::MultiVector::dots(): MultiVectors must have compatible Maps.");
00390     TEST_FOR_EXCEPTION(A.numVectors() != numVecs, std::runtime_error,
00391         "Tpetra::MultiVector::dots(): MultiVectors must have the same number of vectors.");
00392 #ifdef TEUCHOS_DEBUG
00393     TEST_FOR_EXCEPTION(dots.size() != numVecs, std::runtime_error,
00394         "Tpetra::MultiVector::dots(A,dots): dots.size() must be as large as the number of vectors in *this and A.");
00395 #endif
00396     Teuchos::Array<Scalar> ldots(numVecs);
00397     for (Ordinal i=ZERO; i<numVecs; ++i) {
00398       ldots[i] = blas.DOT(MVData_->cPtrs_[i].size(),MVData_->cPtrs_[i].getRawPtr(),ONE,A[i].getRawPtr(),ONE);
00399     }
00400     if (this->isDistributed()) {
00401       // only combine if we are a distributed MV
00402       Teuchos::reduceAll(*this->getMap().getComm(),Teuchos::REDUCE_SUM,numVecs,ldots.getRawPtr(),dots.getRawPtr());
00403     }
00404     else {
00405       std::copy(ldots.begin(),ldots.end(),dots.begin());
00406     }
00407   }
00408 
00409 
00410   template<typename Ordinal, typename Scalar>
00411   void MultiVector<Ordinal,Scalar>::norm1(
00412       const Teuchos::ArrayView<typename Teuchos::ScalarTraits<Scalar>::magnitudeType> &norms) const
00413   {
00414     Teuchos::BLAS<int,Scalar> blas;
00415     typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType Mag;
00416     const Ordinal ZERO = Teuchos::OrdinalTraits<Ordinal>::zero();
00417     const Ordinal ONE = Teuchos::OrdinalTraits<Ordinal>::one();
00418     // compute local components of the norms
00419     // sum these across all nodes
00420     const Ordinal numVecs = this->numVectors();
00421 #ifdef TEUCHOS_DEBUG
00422     TEST_FOR_EXCEPTION(norms.size() != numVecs, std::runtime_error,
00423         "Tpetra::MultiVector::norm1(norms): norms.size() must be as large as the number of vectors in *this.");
00424 #endif
00425     Teuchos::Array<Mag> lnorms(numVecs);
00426     for (Ordinal i=ZERO; i<numVecs; ++i) {
00427       lnorms[i] = blas.ASUM(MVData_->cPtrs_[i].size(),MVData_->cPtrs_[i].getRawPtr(),ONE);
00428     }
00429     if (this->isDistributed()) {
00430       // only combine if we are a distributed MV
00431       Teuchos::reduceAll(*this->getMap().getComm(),Teuchos::REDUCE_SUM,numVecs,lnorms.getRawPtr(),norms.getRawPtr());
00432     }
00433     else {
00434       std::copy(lnorms.begin(),lnorms.end(),norms.begin());
00435     }
00436   }
00437 
00438 
00439   template<typename Ordinal, typename Scalar>
00440   void MultiVector<Ordinal,Scalar>::norm2(
00441       const Teuchos::ArrayView<typename Teuchos::ScalarTraits<Scalar>::magnitudeType> &norms) const
00442   {
00443     using Teuchos::ScalarTraits;
00444     using Teuchos::ArrayView;
00445     typedef typename ScalarTraits<Scalar>::magnitudeType Mag;
00446     const Ordinal ZERO = Teuchos::OrdinalTraits<Ordinal>::zero();
00447     // compute local components of the norms
00448     // sum these across all nodes
00449     const Ordinal numVecs = this->numVectors();
00450 #ifdef TEUCHOS_DEBUG
00451     TEST_FOR_EXCEPTION(norms.size() != numVecs, std::runtime_error,
00452         "Tpetra::MultiVector::norm2(norms): norms.size() must be as large as the number of vectors in *this.");
00453 #endif
00454     Teuchos::Array<Mag> lnorms(numVecs,ScalarTraits<Mag>::zero());
00455     for (Ordinal j=ZERO; j<numVecs; ++j) {
00456       typename Teuchos::ArrayView<const Scalar>::iterator cpos = MVData_->cPtrs_[j].begin(),
00457                                                           cend = MVData_->cPtrs_[j].end();
00458       for (; cpos != cend; ++cpos) {
00459         lnorms[j] += ScalarTraits<Scalar>::magnitude( 
00460                        (*cpos) * ScalarTraits<Scalar>::conjugate(*cpos)
00461                      );
00462       }
00463     }
00464     if (this->isDistributed()) {
00465       // only combine if we are a distributed MV
00466       Teuchos::reduceAll(*this->getMap().getComm(),Teuchos::REDUCE_SUM,numVecs,lnorms.getRawPtr(),norms.getRawPtr());
00467     }
00468     else {
00469       std::copy(lnorms.begin(),lnorms.end(),norms.begin());
00470     }
00471     for (typename ArrayView<Mag>::iterator n = norms.begin(); n != norms.begin()+numVecs; ++n) {
00472       *n = ScalarTraits<Mag>::squareroot(*n);
00473     }
00474   }
00475 
00476 
00477   template<typename Ordinal, typename Scalar>
00478   void MultiVector<Ordinal,Scalar>::normWeighted(
00479       const MultiVector<Ordinal,Scalar> &weights,
00480       const Teuchos::ArrayView<typename Teuchos::ScalarTraits<Scalar>::magnitudeType> &norms) const
00481   {
00482     using Teuchos::ScalarTraits;
00483     using Teuchos::ArrayView;
00484     using Teuchos::ArrayRCP;
00485     using Teuchos::Array;
00486     using Teuchos::as;
00487     typedef ScalarTraits<Scalar> SCT;
00488     typedef typename SCT::magnitudeType Mag;
00489     const Ordinal ZERO = Teuchos::OrdinalTraits<Ordinal>::zero();
00490     const Ordinal ONE  = Teuchos::OrdinalTraits<Ordinal>::one();
00491     const Ordinal numImages = this->getMap().getComm()->getSize();
00492     bool OneW = false;
00493     const Ordinal numVecs = this->numVectors();
00494     if (weights.numVectors() == ONE) {
00495       OneW = true;
00496     }
00497     else {
00498       TEST_FOR_EXCEPTION(weights.numVectors() != numVecs, std::runtime_error,
00499           "Tpetra::MultiVector::normWeighted(): MultiVector of weights must contain either one vector or the same number of vectors as this.");
00500     }
00501     TEST_FOR_EXCEPTION( !this->getMap().isCompatible(weights.getMap()), std::runtime_error,
00502         "Tpetra::MultiVector::normWeighted(): MultiVectors must have compatible Maps.");
00503 #ifdef TEUCHOS_DEBUG
00504     TEST_FOR_EXCEPTION(norms.size() != numVecs, std::runtime_error,
00505         "Tpetra::MultiVector::normWeighted(): norms.size() must be as large as the number of vectors in *this.");
00506 #endif
00507     // compute local components of the norms
00508     // sum these across all nodes
00509     Array<Mag> lnorms(numVecs,ScalarTraits<Mag>::zero());
00510     for (Ordinal j=ZERO; j<numVecs; ++j) {
00511       typename ArrayView<const Scalar>::iterator wpos = (OneW ? weights[0] : weights[j]).begin(),
00512                                                  cpos = MVData_->cPtrs_[j].begin(),
00513                                                  cend = MVData_->cPtrs_[j].end();
00514       for (; cpos != cend; ++cpos, ++wpos) {
00515         Scalar tmp = *cpos / *wpos;
00516         lnorms[j] += SCT::magnitude( tmp * SCT::conjugate(tmp) );
00517       }
00518     }
00519     if (this->isDistributed()) {
00520       // only combine if we are a distributed MV
00521       Teuchos::reduceAll(*this->getMap().getComm(),Teuchos::REDUCE_SUM,numVecs,lnorms.getRawPtr(),norms.getRawPtr());
00522     }
00523     else {
00524       std::copy(lnorms.begin(),lnorms.end(),norms.begin());
00525     }
00526     for (typename ArrayView<Mag>::iterator n = norms.begin(); n != norms.begin()+numVecs; ++n) {
00527       *n = ScalarTraits<Mag>::squareroot(*n/as<Mag>(numImages));
00528     }
00529   }
00530 
00531 
00532   template<typename Ordinal, typename Scalar>
00533   void MultiVector<Ordinal,Scalar>::normInf(
00534       const Teuchos::ArrayView<typename Teuchos::ScalarTraits<Scalar>::magnitudeType> &norms) const
00535   {
00536     Teuchos::BLAS<int,Scalar> blas;
00537     typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType Mag;
00538     const Ordinal ZERO = Teuchos::OrdinalTraits<Ordinal>::zero();
00539     const Ordinal ONE = Teuchos::OrdinalTraits<Ordinal>::one();
00540     // compute local components of the norms
00541     // sum these across all nodes
00542     const Ordinal numVecs = this->numVectors();
00543 #ifdef TEUCHOS_DEBUG
00544     TEST_FOR_EXCEPTION(norms.size() != numVecs, std::runtime_error,
00545         "Tpetra::MultiVector::normInf(norms): norms.size() must be as large as the number of vectors in *this.");
00546 #endif
00547     Teuchos::Array<Mag> lnorms(numVecs);
00548     for (Ordinal i=ZERO; i<numVecs; ++i) {
00549       // careful!!! IAMAX returns FORTRAN-style (i.e., one-based) index. subtract ind by one
00550       Ordinal ind = blas.IAMAX(MVData_->cPtrs_[i].size(),MVData_->cPtrs_[i].getRawPtr(),ONE) - ONE;
00551       lnorms[i] = Teuchos::ScalarTraits<Scalar>::magnitude( MVData_->cPtrs_[i][ind] );
00552     }
00553     if (this->isDistributed()) {
00554       // only combine if we are a distributed MV
00555       Teuchos::reduceAll(*this->getMap().getComm(),Teuchos::REDUCE_MAX,numVecs,lnorms.getRawPtr(),norms.getRawPtr());
00556     }
00557     else {
00558       std::copy(lnorms.begin(),lnorms.end(),norms.begin());
00559     }
00560   }
00561 
00562 
00563   template<typename Ordinal, typename Scalar>
00564   void MultiVector<Ordinal,Scalar>::random() 
00565   {
00566     const Ordinal ZERO = Teuchos::OrdinalTraits<Ordinal>::zero();
00567     const Ordinal numVecs = this->numVectors();
00568     for (Ordinal j=ZERO; j<numVecs; ++j) {
00569       typename Teuchos::ArrayView<Scalar>::iterator cpos = MVData_->ptrs_[j].begin(),
00570                                                     cend = MVData_->ptrs_[j].end();
00571       for (; cpos != cend; ++cpos) {
00572         *cpos = Teuchos::ScalarTraits<Scalar>::random();
00573       }
00574     }
00575   }
00576 
00577 
00578   template<typename Ordinal, typename Scalar>
00579   void MultiVector<Ordinal,Scalar>::putScalar(const Scalar &alpha) 
00580   {
00581     using Teuchos::OrdinalTraits;
00582     using Teuchos::ArrayView;
00583     const Ordinal numVecs = this->numVectors();
00584     for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00585       ArrayView<Scalar> &curpos = MVData_->ptrs_[i];
00586       std::fill(curpos.begin(),curpos.end(),alpha);
00587     }
00588   }
00589 
00590 
00591   template<typename Ordinal, typename Scalar>
00592   void MultiVector<Ordinal,Scalar>::scale(const Scalar &alpha) 
00593   {
00594     Teuchos::BLAS<int,Scalar> blas;
00595     using Teuchos::OrdinalTraits;
00596     const Ordinal ONE = Teuchos::OrdinalTraits<Ordinal>::one();
00597     using Teuchos::ArrayView;
00598     const Ordinal numVecs = this->numVectors();
00599     if (alpha == Teuchos::ScalarTraits<Scalar>::one()) {
00600       // do nothing
00601     }
00602     else if (alpha == Teuchos::ScalarTraits<Scalar>::zero()) {
00603       putScalar(alpha);
00604     }
00605     else {
00606       for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00607         ArrayView<Scalar> &curpos = MVData_->ptrs_[i];
00608         blas.SCAL(curpos.size(),alpha,curpos.getRawPtr(),ONE);
00609       }
00610     }
00611   }
00612 
00613   template<typename Ordinal, typename Scalar>
00614   void MultiVector<Ordinal,Scalar>::scale(Teuchos::ArrayView<const Scalar> alphas)
00615   {
00616     Teuchos::BLAS<int,Scalar> blas;
00617     using Teuchos::OrdinalTraits;
00618     const Ordinal ONE = Teuchos::OrdinalTraits<Ordinal>::one();
00619     using Teuchos::ArrayView;
00620     const Ordinal numVecs = this->numVectors();
00621 #ifdef TEUCHOS_DEBUG
00622     TEST_FOR_EXCEPTION(alphas.size() != numVecs, std::runtime_error,
00623         "Tpetra::MultiVector::scale(alphas): alphas.size() must be as large as the number of vectors in *this.");
00624 #endif
00625     for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00626       if (alphas[i] == Teuchos::ScalarTraits<Scalar>::one()) {
00627         // do nothing
00628       }
00629       else if (alphas[i] == Teuchos::ScalarTraits<Scalar>::zero()) {
00630         ArrayView<Scalar> &curpos = MVData_->ptrs_[i];
00631         std::fill(curpos.begin(),curpos.end(),Teuchos::ScalarTraits<Scalar>::zero());
00632       }
00633       else {
00634         ArrayView<Scalar> &curpos = MVData_->ptrs_[i];
00635         blas.SCAL(curpos.size(),alphas[i],curpos.getRawPtr(),ONE);
00636       }
00637     }
00638   }
00639 
00640   template<typename Ordinal, typename Scalar>
00641   void MultiVector<Ordinal,Scalar>::scale(const Scalar &alpha, const MultiVector<Ordinal,Scalar> &A) 
00642   {
00643     Teuchos::BLAS<int,Scalar> blas;
00644     using Teuchos::OrdinalTraits;
00645     using Teuchos::ArrayView;
00646     const Ordinal numVecs = this->numVectors();
00647     TEST_FOR_EXCEPTION( !this->getMap().isCompatible(A.getMap()), std::runtime_error,
00648         "Tpetra::MultiVector::scale(): MultiVectors must have compatible Maps.");
00649     TEST_FOR_EXCEPTION(A.numVectors() != numVecs, std::runtime_error,
00650         "Tpetra::MultiVector::scale(): MultiVectors must have the same number of vectors.");
00651     const Ordinal ONE = Teuchos::OrdinalTraits<Ordinal>::one();
00652     if (alpha == Teuchos::ScalarTraits<Scalar>::zero()) {
00653       putScalar(alpha); // set me = 0.0
00654     }
00655     else if (alpha == Teuchos::ScalarTraits<Scalar>::one()) {
00656       *this = A;        // set me = A
00657     }
00658     else {
00659       // set me == alpha*A
00660       for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00661         ArrayView<Scalar> &curpos =   MVData_->ptrs_[i],
00662                           &Apos   = A.MVData_->ptrs_[i];
00663         // copy A to *this
00664         blas.COPY(curpos.size(),Apos.getRawPtr(),ONE,curpos.getRawPtr(),ONE);
00665         // then scale *this in-situ
00666         blas.SCAL(curpos.size(),alpha,curpos.getRawPtr(),ONE);
00667       }
00668     }
00669   }
00670 
00671 
00672   template<typename Ordinal, typename Scalar>
00673   void MultiVector<Ordinal,Scalar>::reciprocal(const MultiVector<Ordinal,Scalar> &A) 
00674   {
00675     Teuchos::BLAS<int,Scalar> blas;
00676     using Teuchos::OrdinalTraits;
00677     using Teuchos::ScalarTraits;
00678     using Teuchos::ArrayView;
00679     const Ordinal numVecs = this->numVectors();
00680     TEST_FOR_EXCEPTION( !this->getMap().isCompatible(A.getMap()), std::runtime_error,
00681         "Tpetra::MultiVector::reciprocal(): MultiVectors must have compatible Maps.");
00682     TEST_FOR_EXCEPTION(A.numVectors() != numVecs, std::runtime_error,
00683         "Tpetra::MultiVector::reciprocal(): MultiVectors must have the same number of vectors.");
00684     for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00685       typename Teuchos::ArrayView<Scalar>::iterator curpos =   MVData_->ptrs_[i].begin(),
00686                                                       Apos = A.MVData_->ptrs_[i].begin();
00687       for (; curpos != MVData_->ptrs_[i].end(); ++curpos, ++Apos) {
00688 #ifdef TEUCHOS_DEBUG
00689         TEST_FOR_EXCEPTION( ScalarTraits<Scalar>::magnitude(*Apos) <= ScalarTraits<Scalar>::sfmin() ||
00690             *Apos == ScalarTraits<Scalar>::sfmin(), std::runtime_error,
00691             "Tpetra::MultiVector::reciprocal(): element of A was zero or too small to invert: " << *Apos );
00692 #endif
00693         *curpos = ScalarTraits<Scalar>::one()/(*Apos);
00694       }
00695     }
00696   }
00697 
00698 
00699   template<typename Ordinal, typename Scalar>
00700   void MultiVector<Ordinal,Scalar>::abs(const MultiVector<Ordinal,Scalar> &A) 
00701   {
00702     Teuchos::BLAS<int,Scalar> blas;
00703     using Teuchos::OrdinalTraits;
00704     using Teuchos::ArrayView;
00705     const Ordinal numVecs = this->numVectors();
00706     TEST_FOR_EXCEPTION(A.numVectors() != numVecs, std::runtime_error,
00707         "Tpetra::MultiVector::abs(): MultiVectors must have the same number of vectors.");
00708     TEST_FOR_EXCEPTION( !this->getMap().isCompatible(A.getMap()), std::runtime_error,
00709         "Tpetra::MultiVector::abs(): MultiVectors must have compatible Maps.");
00710     for (Ordinal j = OrdinalTraits<Ordinal>::zero(); j < numVecs; ++j) {
00711       typename ArrayView<Scalar>::iterator curpos =   MVData_->ptrs_[j].begin(),
00712                                              Apos = A.MVData_->ptrs_[j].begin();
00713       for (; curpos != MVData_->ptrs_[j].end(); ++curpos, ++Apos) {
00714         *curpos = Teuchos::ScalarTraits<Scalar>::magnitude(*Apos);
00715       }
00716     }
00717   }
00718 
00719 
00720   template<typename Ordinal, typename Scalar>
00721   void MultiVector<Ordinal,Scalar>::update(const Scalar &alpha, const MultiVector<Ordinal,Scalar> &A, const Scalar &beta) 
00722   {
00723     typedef Teuchos::ScalarTraits<Scalar> ST;
00724     typedef typename Teuchos::ArrayView<Scalar>::iterator avi;
00725     typedef typename Teuchos::ArrayView<const Scalar>::iterator avci;
00726     using Teuchos::OrdinalTraits;
00727     using Teuchos::ArrayView;
00728     if (alpha == ST::zero()) {
00729       scale(beta);
00730       return;
00731     }
00732     const Ordinal numVecs = this->numVectors();
00733     TEST_FOR_EXCEPTION( !this->getMap().isCompatible(A.getMap()), std::runtime_error,
00734         "Tpetra::MultiVector::update(): MultiVectors must have compatible Maps.");
00735     TEST_FOR_EXCEPTION(A.numVectors() != numVecs, std::runtime_error,
00736         "Tpetra::MultiVector::update(): MultiVectors must have the same number of vectors.");
00737 
00738     if (beta == ST::zero()) { // this = alpha*A
00739       scale(alpha,A);
00740       return;
00741     }
00742     else if (beta == ST::one()) { // this = this + alpha*A
00743       if (alpha == ST::one()) { // this = this + A
00744         for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00745           avi curpos = MVData_->ptrs_[i].begin(), cend = MVData_->ptrs_[i].end(); avci Apos = A.MVData_->cPtrs_[i].begin();
00746           for (; curpos != cend; ++curpos, ++Apos) { *curpos = (*curpos) + (*Apos); }
00747         }
00748       }
00749       else { // this = this + alpha*A
00750         for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00751           avi curpos = MVData_->ptrs_[i].begin(), cend = MVData_->ptrs_[i].end(); avci Apos = A.MVData_->cPtrs_[i].begin();
00752           for (; curpos != cend; ++curpos, ++Apos) { *curpos = (*curpos) + alpha*(*Apos); }
00753         }
00754       }
00755     }
00756     else { // this = beta*this + alpha*A
00757       if (alpha == ST::one()) { // this = beta*this + A
00758         for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00759           avi curpos = MVData_->ptrs_[i].begin(), cend = MVData_->ptrs_[i].end(); avci Apos = A.MVData_->cPtrs_[i].begin();
00760           for (; curpos != cend; ++curpos, ++Apos) { *curpos = beta*(*curpos) + (*Apos); }
00761         }
00762       }
00763       else { // this = beta*this + alpha*A
00764         for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00765           avi curpos = MVData_->ptrs_[i].begin(), cend = MVData_->ptrs_[i].end(); avci Apos = A.MVData_->cPtrs_[i].begin();
00766           for (; curpos != cend; ++curpos, ++Apos) { *curpos = beta*(*curpos) + alpha*(*Apos); }
00767         }
00768       }
00769     }
00770   }
00771 
00772 
00773   template<typename Ordinal, typename Scalar>
00774   void MultiVector<Ordinal,Scalar>::update(const Scalar &alpha, const MultiVector<Ordinal,Scalar> &A, const Scalar &beta, const MultiVector<Ordinal,Scalar> &B, const Scalar &gamma)
00775   {
00776     typedef typename Teuchos::ArrayView<Scalar>::iterator avi;
00777     typedef typename Teuchos::ArrayView<const Scalar>::iterator avci;
00778     typedef Teuchos::ScalarTraits<Scalar> ST;
00779     using Teuchos::OrdinalTraits;
00780     using Teuchos::ArrayRCP;
00781     if (alpha == ST::zero()) {
00782       update(beta,B,gamma);
00783       return;
00784     }
00785     else if (beta == ST::zero()) {
00786       update(alpha,A,gamma);
00787       return;
00788     }
00789     const Ordinal numVecs = this->numVectors();
00790     TEST_FOR_EXCEPTION( !this->getMap().isCompatible(A.getMap()) || !this->getMap().isCompatible(B.getMap()),
00791         std::runtime_error,
00792         "Tpetra::MultiVector::update(): MultiVectors must have compatible Maps.");
00793     TEST_FOR_EXCEPTION(A.numVectors() != numVecs || B.numVectors() != numVecs, std::runtime_error,
00794         "Tpetra::MultiVector::update(): MultiVectors must have the same number of vectors.");
00795     // determine if alpha==1 xor beta==1
00796     // if only one of these is 1.0, make it alpha
00797     Teuchos::Ptr<const MultiVector<Ordinal,Scalar> > Aptr = Teuchos::ptr(&A), Bptr = Teuchos::ptr(&B);
00798     Teuchos::Ptr<const Scalar> lalpha = Teuchos::ptr(&alpha),
00799                                lbeta  = Teuchos::ptr(&beta);
00800     if (alpha!=ST::one() && beta==ST::one()) {
00801       // switch them
00802       Aptr = Teuchos::ptr(&B);
00803       Bptr = Teuchos::ptr(&A);
00804       lalpha = Teuchos::ptr(&beta);
00805       lbeta  = Teuchos::ptr(&alpha);
00806     }
00807 
00808     if (gamma == ST::zero()) { // this = lalpha*A + lbeta*B
00809       if (*lalpha == ST::one()) {
00810         if (*lbeta == ST::one()) { // this = gamma*this + A + B
00811           for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00812             avi curpos = MVData_->ptrs_[i].begin(), cend = MVData_->ptrs_[i].end(); avci Apos = Aptr->MVData_->cPtrs_[i].begin(), Bpos = Bptr->MVData_->cPtrs_[i].begin();
00813             for (; curpos != cend; ++curpos, ++Apos, ++Bpos) { *curpos = (*Apos) + (*Bpos); }
00814           }
00815         }
00816         else { // this = A + lbeta*B
00817           for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00818             avi curpos = MVData_->ptrs_[i].begin(), cend = MVData_->ptrs_[i].end(); avci Apos = Aptr->MVData_->cPtrs_[i].begin(), Bpos = Bptr->MVData_->cPtrs_[i].begin();
00819             for (; curpos != cend; ++curpos, ++Apos, ++Bpos) { *curpos = (*Apos) + (*lbeta)*(*Bpos); }
00820           }
00821         }
00822       }
00823       else { // this = lalpha*A + lbeta*B
00824         for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00825           avi curpos = MVData_->ptrs_[i].begin(), cend = MVData_->ptrs_[i].end(); avci Apos = Aptr->MVData_->cPtrs_[i].begin(), Bpos = Bptr->MVData_->cPtrs_[i].begin();
00826           for (; curpos != cend; ++curpos, ++Apos, ++Bpos) { *curpos = (*lalpha)*(*Apos) + (*lbeta)*(*Bpos); }
00827         }
00828       }
00829     }
00830     else if (gamma == ST::one()) { // this = this + lalpha*A + lbeta*B
00831       if ((*lalpha) == ST::one()) {
00832         if ((*lbeta) == ST::one()) { // this = this + A + B
00833           for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00834             avi curpos = MVData_->ptrs_[i].begin(), cend = MVData_->ptrs_[i].end(); avci Apos = Aptr->MVData_->cPtrs_[i].begin(), Bpos = Bptr->MVData_->cPtrs_[i].begin();
00835             for (; curpos != cend; ++curpos, ++Apos, ++Bpos) { *curpos = (*curpos) + (*Apos) + (*Bpos); }
00836           }
00837         }
00838         else { // this = this + A + lbeta*B
00839           for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00840             avi curpos = MVData_->ptrs_[i].begin(), cend = MVData_->ptrs_[i].end(); avci Apos = Aptr->MVData_->cPtrs_[i].begin(), Bpos = Bptr->MVData_->cPtrs_[i].begin();
00841             for (; curpos != cend; ++curpos, ++Apos, ++Bpos) { *curpos = (*curpos) + (*Apos) + (*lbeta)*(*Bpos); }
00842           }
00843         }
00844       }
00845       else { // this = this + lalpha*A + lbeta*B
00846         for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00847           avi curpos = MVData_->ptrs_[i].begin(), cend = MVData_->ptrs_[i].end(); avci Apos = Aptr->MVData_->cPtrs_[i].begin(), Bpos = Bptr->MVData_->cPtrs_[i].begin();
00848           for (; curpos != cend; ++curpos, ++Apos, ++Bpos) { *curpos = (*curpos) + (*lalpha)*(*Apos) + (*lbeta)*(*Bpos); }
00849         }
00850       }
00851     }
00852     else { // this = gamma*this + lalpha*A + lbeta*B
00853       if ((*lalpha) == ST::one()) {
00854         if ((*lbeta) == ST::one()) { // this = gamma*this + A + B
00855           for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00856             avi curpos = MVData_->ptrs_[i].begin(), cend = MVData_->ptrs_[i].end(); avci Apos = Aptr->MVData_->cPtrs_[i].begin(), Bpos = Bptr->MVData_->cPtrs_[i].begin();
00857             for (; curpos != cend; ++curpos, ++Apos, ++Bpos) { *curpos = gamma*(*curpos) + (*Apos) + (*Bpos); }
00858           }
00859         }
00860         else { // this = gamma*this + A + lbeta*B
00861           for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00862             avi curpos = MVData_->ptrs_[i].begin(), cend = MVData_->ptrs_[i].end(); avci Apos = Aptr->MVData_->cPtrs_[i].begin(), Bpos = Bptr->MVData_->cPtrs_[i].begin();
00863             for (; curpos != cend; ++curpos, ++Apos, ++Bpos) { *curpos = gamma*(*curpos) + (*Apos) + (*lbeta)*(*Bpos); }
00864           }
00865         }
00866       }
00867       else { // this = gamma*this + lalpha*A + lbeta*B
00868         for (Ordinal i = OrdinalTraits<Ordinal>::zero(); i < numVecs; ++i) {
00869           avi curpos = MVData_->ptrs_[i].begin(), cend = MVData_->ptrs_[i].end(); avci Apos = Aptr->MVData_->cPtrs_[i].begin(), Bpos = Bptr->MVData_->cPtrs_[i].begin();
00870           for (; curpos != cend; ++curpos, ++Apos, ++Bpos) { *curpos = gamma*(*curpos) + (*lalpha)*(*Apos) + (*lbeta)*(*Bpos); }
00871         }
00872       }
00873     }
00874   }
00875 
00876 
00877   template<typename Ordinal, typename Scalar>
00878   Teuchos::ArrayView<const Scalar> MultiVector<Ordinal,Scalar>::operator[](Ordinal i) const
00879   {
00880     // teuchos does the bounds checking here, if TEUCHOS_DEBUG
00881     return MVData_->cPtrs_[i];
00882   }
00883 
00884   template<typename Ordinal, typename Scalar>
00885   Teuchos::ArrayView<Scalar> MultiVector<Ordinal,Scalar>::operator[](Ordinal i)
00886   {
00887     // teuchos does the bounds checking here, if TEUCHOS_DEBUG
00888     return MVData_->ptrs_[i];
00889   }
00890 
00891   template<typename Ordinal, typename Scalar>
00892   MultiVector<Ordinal,Scalar>& MultiVector<Ordinal,Scalar>::operator=(const MultiVector<Ordinal,Scalar> &source) {
00893     // Check for special case of this=Source
00894     if (this != &source) {
00895       TEST_FOR_EXCEPTION( !this->getMap().isCompatible(source.getMap()), std::runtime_error,
00896           "Tpetra::MultiVector::operator=(): MultiVectors must have compatible Maps.");
00897       if (constantStride() && source.constantStride() && myLength()==stride() && source.myLength()==source.stride()) {
00898         // can copy in one call
00899         std::copy( source.MVData_->values_.begin(), source.MVData_->values_.begin() + source.numVectors()*source.stride(),
00900                    MVData_->values_.begin() );
00901       }
00902       else {
00903         for (Ordinal j=0; j<numVectors(); ++j) {
00904           std::copy( source.MVData_->ptrs_[j].begin(), source.MVData_->ptrs_[j].end(), 
00905                      MVData_->ptrs_[j].begin() );
00906         }
00907       }
00908     }
00909     return(*this);
00910   }
00911 
00912   /*
00913   template<typename Ordinal, typename Scalar>
00914   Teuchos::RCP<MultiVector<Ordinal,Scalar> > MultiVector<Ordinal,Scalar>::subCopy(const Teuchos::Range1D &colRng) const
00915   {
00916     // FINISH
00917     TEST_FOR_EXCEPT(true);
00918     return Teuchos::null;
00919   }
00920   */
00921 
00922   template<typename Ordinal, typename Scalar>
00923   Teuchos::RCP<MultiVector<Ordinal,Scalar> > MultiVector<Ordinal,Scalar>::subCopy(const Teuchos::ArrayView<const Teuchos_Index> &cols) const
00924   {
00925     // TODO: in debug mode, do testing that cols[j] are distinct
00926     Ordinal numCols = cols.size();
00927     // allocate new MV
00928     const bool zeroData = false;
00929     Teuchos::RCP<MultiVector<Ordinal,Scalar> > mv = rcp( new MultiVector<Ordinal,Scalar>(this->getMap(),numCols,zeroData) );
00930     // copy data from *this into mv
00931     for (Ordinal j=0; j<numCols; ++j)
00932     {
00933       std::copy( MVData_->ptrs_[cols[j]].begin(), MVData_->ptrs_[cols[j]].end(), mv->MVData_->ptrs_[j].begin() );
00934     }
00935     return mv;
00936   }
00937 
00938   /*
00939   template<typename Ordinal, typename Scalar>
00940   Teuchos::RCP<MultiVector<Ordinal,Scalar> > MultiVector<Ordinal,Scalar>::subView(const Teuchos::Range1D &colRng) 
00941   {
00942     // the range is contiguous, so if this multivector is contiguous, so will be the resulting view
00943     // make sure that its ArrayRCP contains only the data pertaining to that multivector
00944     // FINISH
00945     TEST_FOR_EXCEPT(true);
00946     return Teuchos::null;
00947   }
00948   */
00949 
00950   template<typename Ordinal, typename Scalar>
00951   Teuchos::RCP<MultiVector<Ordinal,Scalar> > MultiVector<Ordinal,Scalar>::subView(const Teuchos::ArrayView<const Teuchos_Index> &cols) 
00952   {
00953     using Teuchos::as;
00954     const Ordinal numVecs = cols.size();
00955     Teuchos::RCP<MultiVectorData<Ordinal,Scalar> > mvdata = Teuchos::rcp( new MultiVectorData<Ordinal,Scalar>() );
00956     // FINISH: if cols are contiguous, we keep constantStride. in that case, values_ needs to point at the beginning.
00957     mvdata->constantStride_ = false;
00958     mvdata->values_ = MVData_->values_;
00959     mvdata->stride_ = stride();
00960     mvdata->ptrs_.resize(numVecs,Teuchos::null);
00961     for (Ordinal j = as<Ordinal>(0); j < numVecs; ++j) {
00962       mvdata->ptrs_[j] = MVData_->ptrs_[cols[j]];
00963     }
00964     mvdata->updateConstPointers();
00965     Teuchos::RCP<MultiVector<Ordinal,Scalar> > mv = Teuchos::rcp( new MultiVector<Ordinal,Scalar>(this->getMap(),mvdata) );
00966     return mv;
00967   }
00968 
00969   /*
00970   template<typename Ordinal, typename Scalar>
00971   Teuchos::RCP<const MultiVector<Ordinal,Scalar> > MultiVector<Ordinal,Scalar>::subViewConst(const Teuchos::Range1D &colRng) const 
00972   {
00973     // the range is contiguous, so if this multivector is contiguous, so will be the resulting view
00974     // make sure that its ArrayRCP contains only the data pertaining to that multivector
00975     // FINISH
00976     TEST_FOR_EXCEPT(true);
00977     return Teuchos::null;
00978   }
00979   */
00980 
00981   template<typename Ordinal, typename Scalar>
00982   Teuchos::RCP<const MultiVector<Ordinal,Scalar> > MultiVector<Ordinal,Scalar>::subViewConst(const Teuchos::ArrayView<const Teuchos_Index> &cols) const
00983   {
00984     using Teuchos::as;
00985     const Ordinal numVecs = cols.size();
00986     Teuchos::RCP<MultiVectorData<Ordinal,Scalar> > mvdata = Teuchos::rcp( new MultiVectorData<Ordinal,Scalar>() );
00987     mvdata->constantStride_ = false;
00988     mvdata->stride_ = stride();
00989     mvdata->values_ = MVData_->values_;
00990     mvdata->ptrs_.resize(numVecs,Teuchos::null);
00991     for (Ordinal j = as<Ordinal>(0); j < numVecs; ++j) {
00992       mvdata->ptrs_[j] = MVData_->ptrs_[cols[j]];
00993     }
00994     mvdata->updateConstPointers();
00995     Teuchos::RCP<MultiVector<Ordinal,Scalar> > mv = Teuchos::rcp( new MultiVector<Ordinal,Scalar>(this->getMap(),mvdata) );
00996     return mv;
00997   }
00998 
00999   template<typename Ordinal, typename Scalar>
01000   void MultiVector<Ordinal,Scalar>::extractCopy(Teuchos::ArrayView<Scalar> A, Ordinal &MyLDA) const 
01001   {
01002     TEST_FOR_EXCEPTION(constantStride() == false, std::runtime_error,
01003       "MultiVector::extractCopy(A,LDA): only supported for constant stride multivectors.");
01004 #ifdef TEUCHOS_DEBUG
01005     TEST_FOR_EXCEPTION(A.size() != stride()*numVectors(), std::runtime_error,
01006       "MultiVector::extractCopy(A,LDA): A must be large enough to hold contents of MultiVector.");
01007 #endif
01008     MyLDA = stride();
01009     std::copy(MVData_->values_.begin(), MVData_->values_.begin()+stride()*numVectors(),
01010               A.begin());
01011   }
01012 
01013   template<typename Ordinal, typename Scalar>
01014   void MultiVector<Ordinal,Scalar>::extractCopy(Teuchos::ArrayView<const Teuchos::ArrayView<Scalar> > arrayOfArrays) const
01015   {
01016 #ifdef TEUCHOS_DEBUG 
01017     TEST_FOR_EXCEPTION(arrayOfArrays.size() != numVectors(), std::runtime_error,
01018         "Tpetra::MultiVector::extractCopy(arrayOfArrays): arrayOfArrays.size() (==" << arrayOfArrays.size() << ") must match"
01019         "numVectors() (==" << numVectors() << ")");
01020     for (typename Teuchos::ArrayView<const Teuchos::ArrayView<Scalar> >::iterator it=arrayOfArrays.begin(); 
01021          it != arrayOfArrays.end(); ++it) {
01022       TEST_FOR_EXCEPTION(it->size() != myLength(), std::runtime_error, 
01023           "Tpetra::MultiVector::extractCopy(arrayOfArrays): ArrayView's size (==" 
01024           << it->size() << ") must match local MultiVector length (==" << myLength() << ")");
01025     }
01026 #endif
01027     // copy each multivector into the user provided 2-D array
01028     for (Ordinal i=0; i<numVectors(); ++i) {
01029       std::copy(MVData_->ptrs_[i].begin(), MVData_->ptrs_[i].end(), arrayOfArrays[i].begin());
01030     }
01031   }
01032 
01033   template<typename Ordinal, typename Scalar>
01034   void MultiVector<Ordinal,Scalar>::extractView(Teuchos::ArrayView<Scalar> &A, Ordinal &MyLDA)
01035   {
01036     TEST_FOR_EXCEPTION(constantStride() == false, std::runtime_error,
01037       "MultiVector::extractView(A,LDA): only supported for constant stride multivectors.");
01038     A = MVData_->values_;
01039     MyLDA = MVData_->stride_;
01040   }
01041 
01042   template<typename Ordinal, typename Scalar>
01043   void MultiVector<Ordinal,Scalar>::extractConstView(Teuchos::ArrayView<const Scalar> &A, Ordinal &MyLDA) const
01044   {
01045     TEST_FOR_EXCEPTION(constantStride() == false, std::runtime_error,
01046       "MultiVector::extractConstView(A,LDA): only supported for constant stride multivectors.");
01047     A = MVData_->values_.getConst();
01048     MyLDA = MVData_->stride_;
01049   }
01050 
01051   template<typename Ordinal, typename Scalar>
01052   Teuchos::ArrayView<const Teuchos::ArrayView<Scalar> > MultiVector<Ordinal,Scalar>::extractView()
01053   {
01054     return MVData_->ptrs_().getConst();
01055   }
01056 
01057   template<typename Ordinal, typename Scalar>
01058   Teuchos::ArrayView<const Teuchos::ArrayView<const Scalar> > MultiVector<Ordinal,Scalar>::extractConstView() const
01059   {
01060     return MVData_->cPtrs_().getConst();
01061   }
01062 
01063   template<typename Ordinal, typename Scalar>
01064   void MultiVector<Ordinal,Scalar>::multiply(Teuchos::ETransp transA, Teuchos::ETransp transB, const Scalar &alpha, const MultiVector<Ordinal,Scalar> &A, const MultiVector<Ordinal,Scalar> &B, const Scalar &beta) 
01065   {
01066     // This routine performs a variety of matrix-matrix multiply operations, interpreting
01067     // the MultiVector (this-aka C , A and B) as 2D matrices.  Variations are due to
01068     // the fact that A, B and C can be local replicated or global distributed
01069     // MultiVectors and that we may or may not operate with the transpose of 
01070     // A and B.  Possible cases are:
01071     using Teuchos::NO_TRANS;      // enums
01072     using Teuchos::TRANS;
01073     using Teuchos::CONJ_TRANS;
01074     using Teuchos::null;
01075     using Teuchos::ScalarTraits;  // traits
01076     using Teuchos::OrdinalTraits;
01077     using Teuchos::as;
01078     using Teuchos::RCP;           // data structures
01079     using Teuchos::ArrayRCP;
01080     using Teuchos::Array;
01081     using Teuchos::ArrayView;
01082     using Teuchos::rcp;           // initializers for data structures
01083     using Teuchos::arcp;
01084 
01085     //                                       Num
01086     //      OPERATIONS                        cases  Notes
01087     //  1) C(local) = A^X(local) * B^X(local)  4    (X=Trans or Not, No comm needed) 
01088     //  2) C(local) = A^T(distr) * B  (distr)  1    (2D dot product, replicate C)
01089     //  3) C(distr) = A  (distr) * B^X(local)  2    (2D vector update, no comm needed)
01090     //
01091     // The following operations are not meaningful for 1D distributions:
01092     //
01093     // u1) C(local) = A^T(distr) * B^T(distr)  1
01094     // u2) C(local) = A  (distr) * B^X(distr)  2
01095     // u3) C(distr) = A^X(local) * B^X(local)  4
01096     // u4) C(distr) = A^X(local) * B^X(distr)  4
01097     // u5) C(distr) = A^T(distr) * B^X(local)  2
01098     // u6) C(local) = A^X(distr) * B^X(local)  4
01099     // u7) C(distr) = A^X(distr) * B^X(local)  4
01100     // u8) C(local) = A^X(local) * B^X(distr)  4
01101     //
01102     // Total of 32 case (2^5).
01103 
01104     std::string errPrefix("Tpetra::MultiVector::multiply(transOpA,transOpB,A,B): ");
01105 
01106     TEST_FOR_EXCEPTION( ScalarTraits<Scalar>::isComplex && (transA == TRANS || transB == TRANS), std::invalid_argument,
01107         errPrefix << "non-conjugate transpose not supported for complex types.");
01108     transA = (transA == NO_TRANS ? NO_TRANS : CONJ_TRANS);
01109     transB = (transB == NO_TRANS ? NO_TRANS : CONJ_TRANS);
01110 
01111     // Compute effective dimensions, w.r.t. transpose operations on 
01112     Ordinal A_nrows = (transA==CONJ_TRANS) ? A.numVectors() : A.myLength();
01113     Ordinal A_ncols = (transA==CONJ_TRANS) ? A.myLength() : A.numVectors();
01114     Ordinal B_nrows = (transB==CONJ_TRANS) ? B.numVectors() : B.myLength();
01115     Ordinal B_ncols = (transB==CONJ_TRANS) ? B.myLength() : B.numVectors();
01116 
01117     Scalar beta_local = beta; // local copy of beta; might be reassigned below
01118 
01119     TEST_FOR_EXCEPTION( myLength() != A_nrows || numVectors() != B_ncols || A_ncols != B_nrows, std::runtime_error,
01120         errPrefix << "dimension of *this, op(A) and op(B) must be consistent.");
01121 
01122     bool A_is_local = !A.isDistributed();
01123     bool B_is_local = !B.isDistributed();
01124     bool C_is_local = !this->isDistributed();
01125     bool Case1 = ( C_is_local &&  A_is_local &&  B_is_local);                                           // Case 1: C(local) = A^X(local) * B^X(local)
01126     bool Case2 = ( C_is_local && !A_is_local && !B_is_local && transA==CONJ_TRANS && transB==NO_TRANS); // Case 2: C(local) = A^T(distr) * B  (distr)
01127     bool Case3 = (!C_is_local && !A_is_local &&  B_is_local && transA==NO_TRANS  );                     // Case 3: C(distr) = A  (distr) * B^X(local)
01128 
01129     // Test that we are considering a meaningful cases
01130     TEST_FOR_EXCEPTION( !Case1 && !Case2 && !Case3, std::runtime_error,
01131         errPrefix << "multiplication of op(A) and op(B) into *this is not a supported use case.");
01132 
01133     if (beta != ScalarTraits<Scalar>::zero() && Case2) // 
01134     {
01135       // if Case2, then C is local and contributions must be summed across all nodes
01136       // however, if beta != 0, then accumulate beta*C into the sum
01137       // when summing across all nodes, we only want to accumulate this once, so 
01138       // set beta == 0 on all nodes except node 0
01139       int MyPID = this->getMap().getComm()->getRank();
01140       if (MyPID!=0) beta_local = ScalarTraits<Scalar>::zero();
01141     }
01142 
01143     // Check if A, B, C have constant stride, if not then make temp copy (strided)
01144     RCP<const MultiVector<Ordinal,Scalar> > Atmp, Btmp; 
01145     RCP<MultiVector<Ordinal,Scalar> > Ctmp;
01146     if (constantStride() == false) Ctmp = rcp(new MultiVector<Ordinal,Scalar>(*this));
01147     else Ctmp = rcp(this,false);
01148 
01149     if (A.constantStride() == false) Atmp = rcp(new MultiVector<Ordinal,Scalar>(A));
01150     else Atmp = rcp(&A,false);
01151 
01152     if (B.constantStride() == false) Btmp = rcp(new MultiVector<Ordinal,Scalar>(B));
01153     else Btmp = rcp(&B,false);
01154 
01155 #ifdef TEUCHOS_DEBUG
01156     TEST_FOR_EXCEPTION(!Ctmp->constantStride() || !Btmp->constantStride() || !Atmp->constantStride(), std::logic_error,
01157         errPrefix << "failed making temporary strided copies of input multivectors.");
01158 #endif
01159 
01160     Ordinal m = this->myLength();
01161     Ordinal n = this->numVectors();
01162     Ordinal k = A_ncols;
01163     Ordinal lda, ldb, ldc;
01164     ArrayView<const Scalar> Ap(Teuchos::null), Bp(Teuchos::null);
01165     ArrayView<Scalar> Cp(Teuchos::null);
01166     Atmp->extractConstView(Ap,lda);
01167     Btmp->extractConstView(Bp,ldb);
01168     Ctmp->extractView(Cp,ldc);
01169 
01170     Teuchos::BLAS<int,Scalar> blas;
01171     // do the arithmetic now
01172     blas.GEMM(transA,transB,m,n,k,alpha,Ap.getRawPtr(),lda,Bp.getRawPtr(),ldb,beta_local,Cp.getRawPtr(),ldc);
01173 
01174     // Dispose of (possibly) extra copies of A, B
01175     Atmp = null;
01176     Btmp = null;
01177 
01178     // If *this was not strided, copy the data from the strided version and then delete it
01179     if (constantStride() == false) {
01180       Array<ArrayView<Scalar> > aoa(MVData_->ptrs_.size(),null);
01181       for (Ordinal i=0; i<as<Ordinal>(aoa.size()); ++i) {
01182         aoa[i] = MVData_->ptrs_[i]();
01183       }
01184       Ctmp->extractCopy(aoa());
01185     }
01186     Ctmp = null;
01187 
01188     // If Case 2 then sum up C and distribute it to all processors.
01189     if (Case2) 
01190     {
01191       RCP<const Teuchos::Comm<Ordinal> > comm = this->getMap().getComm();
01192       // Global reduction on each entry of a Replicated Local MultiVector
01193       // Comm requires that local and global buffers be congruous and distinct
01194       // Therefore, we must allocate storage for the local values
01195       // Furthermore, if the storage in C (our destination for the global results)
01196       //   is not packed, we must allocate storage for the result as well.
01197       ArrayRCP<Scalar> source = arcp<Scalar>(m*n), target;
01198       bool packed = constantStride() && (stride() == m);
01199       if (packed) {
01200         // copy local info into source buffer
01201         // target buffer will be multivector storage
01202         std::copy(MVData_->values_.begin(),MVData_->values_.begin()+m*n,
01203                   source.begin());
01204         // local storage is packed. can use it for target buffer.
01205         target = MVData_->values_;
01206       }
01207       else {
01208         // copy local info into source buffer
01209         ArrayRCP<Scalar> sptr = source;
01210         for (Ordinal j=OrdinalTraits<Ordinal>::zero(); j<n; ++j) 
01211         {
01212           // copy j-th local MV data into source buffer
01213           std::copy(MVData_->ptrs_[j].begin(),MVData_->ptrs_[j].begin()+m,
01214                     sptr.begin());
01215           // advance ptr into source buffer
01216           sptr += m;
01217         }
01218         // must allocate packed storage for target buffer
01219         target = arcp<Scalar>(m*n);
01220       }
01221       // reduce 
01222       Teuchos::reduceAll<Ordinal,Scalar>(*comm,Teuchos::REDUCE_SUM,m*n,source.getRawPtr(),target.getRawPtr());
01223       if (!packed) {
01224         // copy target buffer into multivector storage buffer
01225         ArrayRCP<Scalar> tptr = target;
01226         for (Ordinal j=OrdinalTraits<Ordinal>::zero(); j<n; ++j) 
01227         {
01228           std::copy(tptr.begin(),tptr.begin()+m,
01229                     MVData_->ptrs_[j].begin()
01230                    );
01231           tptr += m;
01232         }
01233       }
01234       // clear allocated buffers
01235       source = null;
01236       target = null;
01237     } // Case2 reduction
01238   }
01239 
01240 
01241   template<typename Ordinal, typename Scalar>
01242   void MultiVector<Ordinal,Scalar>::reduce() 
01243   {
01244     using Teuchos::as;
01245     typedef Teuchos::OrdinalTraits<Ordinal> OT;
01246     // this should be called only for "local" MultiVectors (!isDistributed())
01247     TEST_FOR_EXCEPTION(this->isDistributed() == true, std::runtime_error,
01248         "Tpetra::MultiVector::reduce() should only be called for non-distributed MultiVectors.");
01249     // sum the data across all multivectors
01250     // need to have separate (contiguous) buffers for send and receive
01251     // if we're contiguous, we'll just set the receive buffer as our data, the send as a copy
01252     // if we're non-contig, we'll use separate buffers for both. 
01253     Ordinal bufsize = myLength() * numVectors();
01254     Teuchos::ArrayRCP<Scalar> sndbuf, rcvbuf;
01255     if (constantStride() == true) {
01256       sndbuf = Teuchos::arcpClone<Scalar>(MVData_->values_());
01257 #ifdef TEUCHOS_DEBUG
01258       TEST_FOR_EXCEPTION(sndbuf.size() != MVData_->values_.size(), std::logic_error,
01259           "Tpetra::MultiVector::reduce(): Error in Tpetra. Please contact Tpetra developers.");
01260 #endif
01261       rcvbuf = MVData_->values_;
01262     }
01263     else {
01264       sndbuf = Teuchos::arcp<Scalar>(bufsize);
01265       rcvbuf = Teuchos::arcp<Scalar>(bufsize);
01266       Teuchos::ArrayRCP<Scalar> sndptr = sndbuf;
01267       for (Ordinal j=OT::zero(); j<numVectors(); ++j) {
01268         Teuchos::ArrayView<const Scalar> jvec = (*this)[j];
01269         std::copy(jvec.begin(),jvec.end(),sndptr);
01270         sndptr += myLength();
01271       }
01272     }
01273     Teuchos::reduceAll(*(this->getMap().getComm()), Teuchos::REDUCE_SUM, bufsize, sndbuf().getConst().getRawPtr(), rcvbuf.getRawPtr() );
01274     if (constantStride() == false) {
01275       Teuchos::ArrayRCP<const Scalar> rcvptr = rcvbuf;
01276       for (Ordinal j=OT::zero(); j<numVectors(); ++j) {
01277         Teuchos::ArrayView<Scalar> jvec = (*this)[j];
01278         std::copy(rcvptr.begin(),rcvptr.begin()+myLength(),jvec.begin());
01279         rcvptr += myLength();
01280       }
01281     }
01282   }
01283 
01284   template<typename Ordinal, typename Scalar>
01285   void MultiVector<Ordinal,Scalar>::replaceMap(const Map<Ordinal> &map)
01286   {
01287     TEST_FOR_EXCEPT(true);
01288   }
01289 
01290   template<typename Ordinal, typename Scalar>
01291   void MultiVector<Ordinal,Scalar>::replaceMyValue(Ordinal MyRow, Ordinal VectorIndex, const Scalar &ScalarValue)
01292   {
01293 #ifdef TEUCHOS_DEBUG
01294     TEST_FOR_EXCEPTION(MyRow < this->getMap().getMinLocalIndex() || MyRow > this->getMap().getMaxLocalIndex(), std::runtime_error,
01295         "Tpetra::MultiVector::replaceMyValue(): row index is invalid.");
01296     TEST_FOR_EXCEPTION(VectorIndex < 0 || VectorIndex >= numVectors(), std::runtime_error,
01297         "Tpetra::MultiVector::replaceMyValue(): vector index is invalid.");
01298 #endif
01299     MVData_->ptrs_[VectorIndex][MyRow] = ScalarValue;
01300   }
01301 
01302   template<typename Ordinal, typename Scalar>
01303   void MultiVector<Ordinal,Scalar>::sumIntoMyValue(Ordinal MyRow, Ordinal VectorIndex, const Scalar &ScalarValue)
01304   {
01305 #ifdef TEUCHOS_DEBUG
01306     TEST_FOR_EXCEPTION(MyRow < this->getMap().getMinLocalIndex() || MyRow > this->getMap().getMaxLocalIndex(), std::runtime_error,
01307         "Tpetra::MultiVector::sumIntoMyValue(): row index is invalid.");
01308     TEST_FOR_EXCEPTION(VectorIndex < 0 || VectorIndex >= numVectors(), std::runtime_error,
01309         "Tpetra::MultiVector::sumIntoMyValue(): vector index is invalid.");
01310 #endif
01311     MVData_->ptrs_[VectorIndex][MyRow] += ScalarValue;
01312   }
01313 
01314   template<typename Ordinal, typename Scalar>
01315   void MultiVector<Ordinal,Scalar>::replaceGlobalValue(Ordinal GlobalRow, Ordinal VectorIndex, const Scalar &ScalarValue)
01316   {
01317 #ifdef TEUCHOS_DEBUG
01318     TEST_FOR_EXCEPTION(!this->getMap().isMyGlobalIndex(GlobalRow), std::runtime_error,
01319         "Tpetra::MultiVector::replaceGlobalValue(): row index is not present on this processor.");
01320     TEST_FOR_EXCEPTION(VectorIndex < 0 || VectorIndex >= numVectors(), std::runtime_error,
01321         "Tpetra::MultiVector::replaceGlobalValue(): vector index is invalid.");
01322 #endif
01323     Ordinal MyRow = this->getMap().getLocalIndex(GlobalRow);
01324     MVData_->ptrs_[VectorIndex][MyRow] = ScalarValue;
01325   }
01326 
01327   template<typename Ordinal, typename Scalar>
01328   void MultiVector<Ordinal,Scalar>::sumIntoGlobalValue(Ordinal GlobalRow, Ordinal VectorIndex, const Scalar &ScalarValue)
01329   {
01330 #ifdef TEUCHOS_DEBUG
01331     TEST_FOR_EXCEPTION(!this->getMap().isMyGlobalIndex(GlobalRow), std::runtime_error,
01332         "Tpetra::MultiVector::sumIntoGlobalValue(): row index is not present on this processor.");
01333     TEST_FOR_EXCEPTION(VectorIndex < 0 || VectorIndex >= numVectors(), std::runtime_error,
01334         "Tpetra::MultiVector::sumIntoGlobalValue(): vector index is invalid.");
01335 #endif
01336     Ordinal MyRow = this->getMap().getLocalIndex(GlobalRow);
01337     MVData_->ptrs_[VectorIndex][MyRow] += ScalarValue;
01338   }
01339 
01340 } // namespace Tpetra
01341 
01342 #endif // TPETRA_MULTIVECTOR_HPP

Generated on Wed May 12 21:59:41 2010 for Tpetra Matrix/Vector Services by  doxygen 1.4.7