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