|
Tpetra Matrix/Vector Services
Version of the Day
|
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
1.7.6.1