MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_UtilitiesBase_decl.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 #ifndef MUELU_UTILITIESBASE_DECL_HPP
47 #define MUELU_UTILITIESBASE_DECL_HPP
48 
49 #ifndef _WIN32
50 #include <unistd.h> //necessary for "sleep" function in debugging methods (PauseForDebugging)
51 #endif
52 
53 #include <string>
54 
55 #include "MueLu_ConfigDefs.hpp"
56 
57 #include <Teuchos_DefaultComm.hpp>
58 #include <Teuchos_ScalarTraits.hpp>
60 
62 #include <Xpetra_CrsMatrix_fwd.hpp>
64 #include <Xpetra_Map_fwd.hpp>
67 #include <Xpetra_Matrix_fwd.hpp>
71 #include <Xpetra_Operator_fwd.hpp>
72 #include <Xpetra_Vector_fwd.hpp>
74 #include <Xpetra_BlockedVector.hpp>
76 #include <Xpetra_ExportFactory.hpp>
77 
78 #include <Xpetra_Import.hpp>
79 #include <Xpetra_ImportFactory.hpp>
80 #include <Xpetra_MatrixMatrix.hpp>
81 #include <Xpetra_CrsMatrixWrap.hpp>
82 #include <Xpetra_StridedMap.hpp>
83 
84 #include "MueLu_Exceptions.hpp"
85 
86 
87 namespace MueLu {
88 
89 // MPI helpers
90 #define MueLu_sumAll(rcpComm, in, out) \
91  Teuchos::reduceAll(*rcpComm, Teuchos::REDUCE_SUM, in, Teuchos::outArg(out))
92 #define MueLu_minAll(rcpComm, in, out) \
93  Teuchos::reduceAll(*rcpComm, Teuchos::REDUCE_MIN, in, Teuchos::outArg(out))
94 #define MueLu_maxAll(rcpComm, in, out) \
95  Teuchos::reduceAll(*rcpComm, Teuchos::REDUCE_MAX, in, Teuchos::outArg(out))
96 
104  template <class Scalar,
105  class LocalOrdinal = int,
106  class GlobalOrdinal = LocalOrdinal,
108  class UtilitiesBase {
109  public:
110 #undef MUELU_UTILITIESBASE_SHORT
111 //#include "MueLu_UseShortNames.hpp"
112  private:
122  public:
124 
125 
127  if (Op.is_null())
128  return Teuchos::null;
129  return rcp(new CrsMatrixWrap(Op));
130  }
131 
139  size_t numRows = A.getRowMap()->getNodeNumElements();
140  Teuchos::ArrayRCP<Scalar> diag(numRows);
143  for (size_t i = 0; i < numRows; ++i) {
144  A.getLocalRowView(i, cols, vals);
145  LocalOrdinal j = 0;
146  for (; j < cols.size(); ++j) {
147  if (Teuchos::as<size_t>(cols[j]) == i) {
148  diag[i] = vals[j];
149  break;
150  }
151  }
152  if (j == cols.size()) {
153  // Diagonal entry is absent
155  }
156  }
157  return diag;
158  }
159 
167 
168  RCP<const Matrix> rcpA = Teuchos::rcpFromRef(A);
169 
170  RCP<const Map> rowMap = rcpA->getRowMap();
172 
173  rcpA->getLocalDiagCopy(*diag);
174 
176 
177  return inv;
178  }
179 
180 
181 
189 
190  size_t numRows = A.getRowMap()->getNodeNumElements();
191  Teuchos::ArrayRCP<Scalar> diag(numRows);
194  for (size_t i = 0; i < numRows; ++i) {
195  A.getLocalRowView(i, cols, vals);
197  for (LocalOrdinal j = 0; j < cols.size(); ++j) {
198  diag[i] += Teuchos::ScalarTraits<Scalar>::magnitude(vals[j]);
199  }
200  }
201  return diag;
202  }
203 
211 
212  RCP<Vector> diag = Teuchos::null;
213 
215  Teuchos::rcp_dynamic_cast<const Xpetra::BlockedCrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >(rcpA);
216  if(bA == Teuchos::null) {
217  RCP<const Map> rowMap = rcpA->getRowMap();
219  ArrayRCP<Scalar> diagVals = diag->getDataNonConst(0);
222  for (size_t i = 0; i < rowMap->getNodeNumElements(); ++i) {
223  rcpA->getLocalRowView(i, cols, vals);
224  diagVals[i] = Teuchos::ScalarTraits<Scalar>::zero();
225  for (LocalOrdinal j = 0; j < cols.size(); ++j) {
226  diagVals[i] += Teuchos::ScalarTraits<Scalar>::magnitude(vals[j]);
227  }
228  }
229 
230  } else {
231  //TEUCHOS_TEST_FOR_EXCEPTION(bA->Rows() != bA->Cols(), Xpetra::Exceptions::RuntimeError,
232  // "UtilitiesBase::GetLumpedMatrixDiagonal(): you cannot extract the diagonal of a "<< bA->Rows() << "x"<< bA->Cols() << " blocked matrix." );
233 
234  diag = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(bA->getRangeMapExtractor()->getFullMap(),true);
235 
236  for (size_t row = 0; row < bA->Rows(); ++row) {
237  for (size_t col = 0; col < bA->Cols(); ++col) {
238  if (!bA->getMatrix(row,col).is_null()) {
239  // if we are in Thyra mode, but the block (row,row) is again a blocked operator, we have to use (pseudo) Xpetra-style GIDs with offset!
240  bool bThyraMode = bA->getRangeMapExtractor()->getThyraMode() && (Teuchos::rcp_dynamic_cast<Xpetra::BlockedCrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >(bA->getMatrix(row,col)) == Teuchos::null);
241  RCP<Vector> ddtemp = bA->getRangeMapExtractor()->ExtractVector(diag,row,bThyraMode);
242  RCP<const Vector> dd = GetLumpedMatrixDiagonal(bA->getMatrix(row,col));
243  ddtemp->update(Teuchos::as<Scalar>(1.0),*dd,Teuchos::as<Scalar>(1.0));
244  bA->getRangeMapExtractor()->InsertVector(ddtemp,row,diag,bThyraMode);
245  }
246  }
247  }
248 
249  }
250 
251  // we should never get here...
252  return diag;
253  }
254 
263 
265 
266  // check whether input vector "v" is a BlockedVector
267  RCP<const BlockedVector> bv = Teuchos::rcp_dynamic_cast<const BlockedVector>(v);
268  if(bv.is_null() == false) {
269  RCP<BlockedVector> bret = Teuchos::rcp_dynamic_cast<BlockedVector>(ret);
270  TEUCHOS_TEST_FOR_EXCEPTION(bret.is_null() == true, MueLu::Exceptions::RuntimeError,"MueLu::UtilitiesBase::GetInverse: return vector should be of type BlockedVector");
271  RCP<const BlockedMap> bmap = bv->getBlockedMap();
272  for(size_t r = 0; r < bmap->getNumMaps(); ++r) {
273  RCP<const MultiVector> submvec = bv->getMultiVector(r,bmap->getThyraMode());
274  RCP<const Vector> subvec = submvec->getVector(0);
276  bret->setMultiVector(r, subvecinf, bmap->getThyraMode());
277  }
278  return ret;
279  }
280 
281  // v is an {Epetra,Tpetra}Vector: work with the underlying raw data
282  ArrayRCP<Scalar> retVals = ret->getDataNonConst(0);
283  ArrayRCP<const Scalar> inputVals = v->getData(0);
284  for (size_t i = 0; i < v->getMap()->getNodeNumElements(); ++i) {
285  if(Teuchos::ScalarTraits<Scalar>::magnitude(inputVals[i]) > tol)
286  retVals[i] = Teuchos::ScalarTraits<Scalar>::one() / inputVals[i];
287  else
288  retVals[i] = tolReplacement;
289  }
290  return ret;
291  }
292 
301  RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
302 
303  // Undo block map (if we have one)
304  RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
305  if(!browMap.is_null()) rowMap = browMap->getMap();
306 
308  try {
309  const CrsMatrixWrap* crsOp = dynamic_cast<const CrsMatrixWrap*>(&A);
310  if (crsOp == NULL) {
311  throw Exceptions::RuntimeError("cast to CrsMatrixWrap failed");
312  }
314  crsOp->getLocalDiagOffsets(offsets);
315  crsOp->getLocalDiagCopy(*localDiag,offsets());
316  }
317  catch (...) {
318  ArrayRCP<Scalar> localDiagVals = localDiag->getDataNonConst(0);
320  for (LocalOrdinal i = 0; i < localDiagVals.size(); i++)
321  localDiagVals[i] = diagVals[i];
322  localDiagVals = diagVals = null;
323  }
324 
327  importer = A.getCrsGraph()->getImporter();
328  if (importer == Teuchos::null) {
330  }
331  diagonal->doImport(*localDiag, *(importer), Xpetra::INSERT);
332  return diagonal;
333  }
334 
335 
336  // TODO: should NOT return an Array. Definition must be changed to:
337  // - ArrayRCP<> ResidualNorm(Matrix const &Op, MultiVector const &X, MultiVector const &RHS)
338  // or
339  // - void ResidualNorm(Matrix const &Op, MultiVector const &X, MultiVector const &RHS, Array &)
341  TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(), Exceptions::RuntimeError, "Number of solution vectors != number of right-hand sides")
342  const size_t numVecs = X.getNumVectors();
343  RCP<MultiVector> RES = Residual(Op, X, RHS);
344  Teuchos::Array<Magnitude> norms(numVecs);
345  RES->norm2(norms);
346  return norms;
347  }
348 
350  TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(), Exceptions::RuntimeError, "Number of solution vectors != number of right-hand sides")
351  const size_t numVecs = X.getNumVectors();
352  Residual(Op,X,RHS,Resid);
353  Teuchos::Array<Magnitude> norms(numVecs);
354  Resid.norm2(norms);
355  return norms;
356  }
357 
359  TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(), Exceptions::RuntimeError, "Number of solution vectors != number of right-hand sides")
360  const size_t numVecs = X.getNumVectors();
361  Scalar one = Teuchos::ScalarTraits<Scalar>::one(), negone = -one, zero = Teuchos::ScalarTraits<Scalar>::zero();
362  // TODO Op.getRangeMap should return a BlockedMap if it is a BlockedCrsOperator
363  RCP<MultiVector> RES = Xpetra::MultiVectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(RHS.getMap(), numVecs, false); // no need to initialize to zero
364  Op.apply(X, *RES, Teuchos::NO_TRANS, one, zero);
365  RES->update(one, RHS, negone);
366  return RES;
367  }
368 
369 
371  TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(), Exceptions::RuntimeError, "Number of solution vectors != number of right-hand sides");
372  TEUCHOS_TEST_FOR_EXCEPTION(Resid.getNumVectors() != RHS.getNumVectors(), Exceptions::RuntimeError, "Number of residual vectors != number of right-hand sides");
373  Scalar one = Teuchos::ScalarTraits<Scalar>::one(), negone = -one, zero = Teuchos::ScalarTraits<Scalar>::zero();
374  // TODO Op.getRangeMap should return a BlockedMap if it is a BlockedCrsOperator
375  Op.apply(X, Resid, Teuchos::NO_TRANS, one, zero);
376  Resid.update(one, RHS, negone);
377  }
378 
379 
380 #ifndef _WIN32
381  static void PauseForDebugger() {
383  int myPID = comm->getRank();
384  int pid = getpid();
385  char hostname[80];
386  for (int i = 0; i <comm->getSize(); i++) {
387  if (i == myPID) {
388  gethostname(hostname, sizeof(hostname));
389  std::cout << "Host: " << hostname << "\tMPI rank: " << myPID << ",\tPID: " << pid << "\n\tattach " << pid << std::endl;
390  sleep(1);
391  }
392  }
393  if (myPID == 0) {
394  std::cout << "** Enter a character to continue > " << std::endl;
395  char go = ' ';
396  int r = scanf("%c", &go);
397  (void)r;
398  assert(r > 0);
399  }
400  comm->barrier();
401  }
402 #else
403  static void PauseForDebugger() {
404  throw(Exceptions::RuntimeError("MueLu Utils: PauseForDebugger not implemented on Windows."));
405  }
406 #endif
407 
423  static Scalar PowerMethod(const Matrix& A, bool scaleByDiag = true,
424  LocalOrdinal niters = 10, Magnitude tolerance = 1e-2, bool verbose = false, unsigned int seed = 123) {
426  "Utils::PowerMethod: operator must have domain and range maps that are equivalent.");
427 
428  // Create three vectors, fill z with random numbers
432 
433  z->setSeed(seed); // seed random number generator
434  z->randomize(true);// use Xpetra implementation: -> same results for Epetra and Tpetra
435 
436  Teuchos::Array<Magnitude> norms(1);
437 
438  typedef Teuchos::ScalarTraits<Scalar> STS;
439 
440  const Scalar zero = STS::zero(), one = STS::one();
441 
442  Scalar lambda = zero;
443  Magnitude residual = STS::magnitude(zero);
444 
445  // power iteration
446  RCP<Vector> diagInvVec;
447  if (scaleByDiag) {
449  A.getLocalDiagCopy(*diagVec);
451  diagInvVec->reciprocal(*diagVec);
452  }
453 
454  for (int iter = 0; iter < niters; ++iter) {
455  z->norm2(norms); // Compute 2-norm of z
456  q->update(one/norms[0], *z, zero); // Set q = z / normz
457  A.apply(*q, *z); // Compute z = A*q
458  if (scaleByDiag)
459  z->elementWiseMultiply(one, *diagInvVec, *z, zero);
460  lambda = q->dot(*z); // Approximate maximum eigenvalue: lamba = dot(q,z)
461 
462  if (iter % 100 == 0 || iter + 1 == niters) {
463  r->update(1.0, *z, -lambda, *q, zero); // Compute A*q - lambda*q
464  r->norm2(norms);
465  residual = STS::magnitude(norms[0] / lambda);
466  if (verbose) {
467  std::cout << "Iter = " << iter
468  << " Lambda = " << lambda
469  << " Residual of A*q - lambda*q = " << residual
470  << std::endl;
471  }
472  }
473  if (residual < tolerance)
474  break;
475  }
476  return lambda;
477  }
478 
479 
480 
481  static RCP<Teuchos::FancyOStream> MakeFancy(std::ostream& os) {
482  RCP<Teuchos::FancyOStream> fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(os));
483  return fancy;
484  }
485 
490  static typename Teuchos::ScalarTraits<Scalar>::magnitudeType Distance2(const Teuchos::Array<Teuchos::ArrayRCP<const Scalar>> &v, LocalOrdinal i0, LocalOrdinal i1) {
491  const size_t numVectors = v.size();
492 
494  for (size_t j = 0; j < numVectors; j++) {
495  d += (v[j][i0] - v[j][i1])*(v[j][i0] - v[j][i1]);
496  }
498  }
499 
513  LocalOrdinal numRows = A.getNodeNumRows();
514  typedef Teuchos::ScalarTraits<Scalar> STS;
515  ArrayRCP<bool> boundaryNodes(numRows, true);
516  if (count_twos_as_dirichlet) {
517  for (LocalOrdinal row = 0; row < numRows; row++) {
520  A.getLocalRowView(row, indices, vals);
521  size_t nnz = A.getNumEntriesInLocalRow(row);
522  if (nnz > 2) {
523  size_t col;
524  for (col = 0; col < nnz; col++)
525  if ( (indices[col] != row) && STS::magnitude(vals[col]) > tol) {
526  if (!boundaryNodes[row])
527  break;
528  boundaryNodes[row] = false;
529  }
530  if (col == nnz)
531  boundaryNodes[row] = true;
532  }
533  }
534  } else {
535  for (LocalOrdinal row = 0; row < numRows; row++) {
538  A.getLocalRowView(row, indices, vals);
539  size_t nnz = A.getNumEntriesInLocalRow(row);
540  if (nnz > 1)
541  for (size_t col = 0; col < nnz; col++)
542  if ( (indices[col] != row) && STS::magnitude(vals[col]) > tol) {
543  boundaryNodes[row] = false;
544  break;
545  }
546  }
547  }
548  return boundaryNodes;
549  }
550 
551 
565 
566  // assume that there is no zero diagonal in matrix
567  bHasZeroDiagonal = false;
568 
570  A.getLocalDiagCopy(*diagVec);
571  Teuchos::ArrayRCP< const Scalar > diagVecData = diagVec->getData(0);
572 
573  LocalOrdinal numRows = A.getNodeNumRows();
574  typedef Teuchos::ScalarTraits<Scalar> STS;
575  ArrayRCP<bool> boundaryNodes(numRows, false);
576  for (LocalOrdinal row = 0; row < numRows; row++) {
579  A.getLocalRowView(row, indices, vals);
580  size_t nnz = 0; // collect nonzeros in row (excluding the diagonal)
581  bool bHasDiag = false;
582  for (decltype(indices.size()) col = 0; col < indices.size(); col++) {
583  if ( indices[col] != row) {
584  if (STS::magnitude(vals[col] / STS::magnitude(sqrt(STS::magnitude(diagVecData[row]) * STS::magnitude(diagVecData[col]))) ) > tol) {
585  nnz++;
586  }
587  } else bHasDiag = true; // found a diagonal entry
588  }
589  if (bHasDiag == false) bHasZeroDiagonal = true; // we found at least one row without a diagonal
590  else if(nnz == 0) boundaryNodes[row] = true;
591  }
592  return boundaryNodes;
593  }
594 
595 
607  const Teuchos::ArrayRCP<const bool>& dirichletRows) {
608  Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
609  Scalar one = Teuchos::ScalarTraits<Scalar>::one();
613  myColsToZero->putScalar(zero);
614  // Find all local column indices that are in Dirichlet rows, record in myColsToZero as 1.0
615  for(size_t i=0; i<(size_t) dirichletRows.size(); i++) {
616  if (dirichletRows[i]) {
619  A.getLocalRowView(i,indices,values);
620  for(size_t j=0; j<static_cast<size_t>(indices.size()); j++)
621  myColsToZero->replaceLocalValue(indices[j],0,one);
622  }
623  }
624 
626  globalColsToZero->putScalar(zero);
628  // export to domain map
629  globalColsToZero->doExport(*myColsToZero,*exporter,Xpetra::ADD);
630  // import to column map
631  myColsToZero->doImport(*globalColsToZero,*exporter,Xpetra::INSERT);
632  Teuchos::ArrayRCP<const Scalar> myCols = myColsToZero->getData(0);
633  Teuchos::ArrayRCP<bool> dirichletCols(colMap->getNodeNumElements(), true);
635  for(size_t i=0; i<colMap->getNodeNumElements(); i++) {
636  dirichletCols[i] = Teuchos::ScalarTraits<Scalar>::magnitude(myCols[i])>2.0*eps;
637  }
638  return dirichletCols;
639  }
640 
641 
647  // We check only row maps. Column may be different. One would hope that they are the same, as we typically
648  // calculate frobenius norm of the specified sparsity pattern with an updated matrix from the previous step,
649  // but matrix addition, even when one is submatrix of the other, changes column map (though change may be as
650  // simple as couple of elements swapped)
651  TEUCHOS_TEST_FOR_EXCEPTION(!A.getRowMap()->isSameAs(*B.getRowMap()), Exceptions::Incompatible, "MueLu::CGSolver::Frobenius: row maps are incompatible");
652  TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete() || !B.isFillComplete(), Exceptions::RuntimeError, "Matrices must be fill completed");
653 
654  const Map& AColMap = *A.getColMap();
655  const Map& BColMap = *B.getColMap();
656 
659  size_t nnzA = 0, nnzB = 0;
660 
661  // We use a simple algorithm
662  // for each row we fill valBAll array with the values in the corresponding row of B
663  // as such, it serves as both sorted array and as storage, so we don't need to do a
664  // tricky problem: "find a value in the row of B corresponding to the specific GID"
665  // Once we do that, we translate LID of entries of row of A to LID of B, and multiply
666  // corresponding entries.
667  // The algorithm should be reasonably cheap, as it does not sort anything, provided
668  // that getLocalElement and getGlobalElement functions are reasonably effective. It
669  // *is* possible that the costs are hidden in those functions, but if maps are close
670  // to linear maps, we should be fine
671  Teuchos::Array<Scalar> valBAll(BColMap.getNodeNumElements());
672 
673  LocalOrdinal invalid = Teuchos::OrdinalTraits<LocalOrdinal>::invalid();
674  Scalar zero = Teuchos::ScalarTraits<Scalar> ::zero(), f = zero, gf;
675  size_t numRows = A.getNodeNumRows();
676  for (size_t i = 0; i < numRows; i++) {
677  A.getLocalRowView(i, indA, valA);
678  B.getLocalRowView(i, indB, valB);
679  nnzA = indA.size();
680  nnzB = indB.size();
681 
682  // Set up array values
683  for (size_t j = 0; j < nnzB; j++)
684  valBAll[indB[j]] = valB[j];
685 
686  for (size_t j = 0; j < nnzA; j++) {
687  // The cost of the whole Frobenius dot product function depends on the
688  // cost of the getLocalElement and getGlobalElement functions here.
689  LocalOrdinal ind = BColMap.getLocalElement(AColMap.getGlobalElement(indA[j]));
690  if (ind != invalid)
691  f += valBAll[ind] * valA[j];
692  }
693 
694  // Clean up array values
695  for (size_t j = 0; j < nnzB; j++)
696  valBAll[indB[j]] = zero;
697  }
698 
699  MueLu_sumAll(AColMap.getComm(), f, gf);
700 
701  return gf;
702  }
703 
713  static void SetRandomSeed(const Teuchos::Comm<int> &comm) {
714  // Distribute the seeds evenly in [1,maxint-1]. This guarantees nothing
715  // about where in random number stream we are, but avoids overflow situations
716  // in parallel when multiplying by a PID. It would be better to use
717  // a good parallel random number generator.
718  double one = 1.0;
719  int maxint = INT_MAX; //= 2^31-1 = 2147483647 for 32-bit integers
720  int mySeed = Teuchos::as<int>((maxint-1) * (one -(comm.getRank()+1)/(comm.getSize()+one)) );
721  if (mySeed < 1 || mySeed == maxint) {
722  std::ostringstream errStr;
723  errStr << "Error detected with random seed = " << mySeed << ". It should be in the interval [1,2^31-2].";
724  throw Exceptions::RuntimeError(errStr.str());
725  }
726  std::srand(mySeed);
727  // For Tpetra, we could use Kokkos' random number generator here.
729  // Epetra
730  // MultiVector::Random() -> Epetra_Util::RandomDouble() -> Epetra_Utils::RandomInt()
731  // Its own random number generator, based on Seed_. Seed_ is initialized in Epetra_Util constructor with std::rand()
732  // So our setting std::srand() affects that too
733  }
734 
735 
736 
737  // Finds the OAZ Dirichlet rows for this matrix
738  // so far only used in IntrepidPCoarsenFactory
739  // TODO check whether we can use DetectDirichletRows instead
741  std::vector<LocalOrdinal>& dirichletRows, bool count_twos_as_dirichlet=false) {
743  dirichletRows.resize(0);
744  for(size_t i=0; i<A->getNodeNumRows(); i++) {
747  A->getLocalRowView(i,indices,values);
748  int nnz=0;
749  for (size_t j=0; j<(size_t)indices.size(); j++) {
751  nnz++;
752  }
753  }
754  if (nnz == 1 || (count_twos_as_dirichlet && nnz == 2)) {
755  dirichletRows.push_back(i);
756  }
757  }
758  }
759 
760  // Applies Ones-and-Zeros to matrix rows
761  // Takes a vector of row indices
763  const std::vector<LocalOrdinal>& dirichletRows) {
764  RCP<const Map> Rmap = A->getColMap();
765  RCP<const Map> Cmap = A->getColMap();
768 
769  for(size_t i=0; i<dirichletRows.size(); i++) {
770  GlobalOrdinal row_gid = Rmap->getGlobalElement(dirichletRows[i]);
771 
774  A->getLocalRowView(dirichletRows[i],indices,values);
775  // NOTE: This won't work with fancy node types.
776  Scalar* valuesNC = const_cast<Scalar*>(values.getRawPtr());
777  for(size_t j=0; j<(size_t)indices.size(); j++) {
778  if(Cmap->getGlobalElement(indices[j])==row_gid)
779  valuesNC[j]=one;
780  else
781  valuesNC[j]=zero;
782  }
783  }
784  }
785 
786  // Applies Ones-and-Zeros to matrix rows
787  // Takes a Boolean array.
789  const Teuchos::ArrayRCP<const bool>& dirichletRows) {
790  RCP<const Map> Rmap = A->getColMap();
791  RCP<const Map> Cmap = A->getColMap();
794 
795  for(size_t i=0; i<(size_t) dirichletRows.size(); i++) {
796  if (dirichletRows[i]){
797  GlobalOrdinal row_gid = Rmap->getGlobalElement(i);
798 
801  A->getLocalRowView(i,indices,values);
802  // NOTE: This won't work with fancy node types.
803  Scalar* valuesNC = const_cast<Scalar*>(values.getRawPtr());
804  for(size_t j=0; j<(size_t)indices.size(); j++) {
805  if(Cmap->getGlobalElement(indices[j])==row_gid)
806  valuesNC[j]=one;
807  else
808  valuesNC[j]=zero;
809  }
810  }
811  }
812  }
813 
814  // Zeros out rows
815  // Takes a vector containg Dirichlet row indices
817  const std::vector<LocalOrdinal>& dirichletRows,
818  Scalar replaceWith=Teuchos::ScalarTraits<Scalar>::zero()) {
819  for(size_t i=0; i<dirichletRows.size(); i++) {
822  A->getLocalRowView(dirichletRows[i],indices,values);
823  // NOTE: This won't work with fancy node types.
824  Scalar* valuesNC = const_cast<Scalar*>(values.getRawPtr());
825  for(size_t j=0; j<(size_t)indices.size(); j++)
826  valuesNC[j]=replaceWith;
827  }
828  }
829 
830  // Zeros out rows
831  // Takes a Boolean ArrayRCP
833  const Teuchos::ArrayRCP<const bool>& dirichletRows,
834  Scalar replaceWith=Teuchos::ScalarTraits<Scalar>::zero()) {
835  for(size_t i=0; i<(size_t) dirichletRows.size(); i++) {
836  if (dirichletRows[i]) {
839  A->getLocalRowView(i,indices,values);
840  // NOTE: This won't work with fancy node types.
841  Scalar* valuesNC = const_cast<Scalar*>(values.getRawPtr());
842  for(size_t j=0; j<(size_t)indices.size(); j++)
843  valuesNC[j]=replaceWith;
844  }
845  }
846  }
847 
848  // Zeros out rows
849  // Takes a Boolean ArrayRCP
851  const Teuchos::ArrayRCP<const bool>& dirichletRows,
852  Scalar replaceWith=Teuchos::ScalarTraits<Scalar>::zero()) {
853  for(size_t i=0; i<(size_t) dirichletRows.size(); i++) {
854  if (dirichletRows[i]) {
855  for(size_t j=0; j<X->getNumVectors(); j++)
856  X->replaceLocalValue(i,j,replaceWith);
857  }
858  }
859  }
860 
861  // Zeros out columns
862  // Takes a Boolean vector
864  const Teuchos::ArrayRCP<const bool>& dirichletCols,
865  Scalar replaceWith=Teuchos::ScalarTraits<Scalar>::zero()) {
866  for(size_t i=0; i<A->getNodeNumRows(); i++) {
869  A->getLocalRowView(i,indices,values);
870  // NOTE: This won't work with fancy node types.
871  Scalar* valuesNC = const_cast<Scalar*>(values.getRawPtr());
872  for(size_t j=0; j<static_cast<size_t>(indices.size()); j++)
873  if (dirichletCols[indices[j]])
874  valuesNC[j] = replaceWith;
875  }
876  }
877 
878  // Finds the OAZ Dirichlet rows for this matrix
882 
883  // Make sure A's RowMap == DomainMap
884  if(!A->getRowMap()->isSameAs(*A->getDomainMap())) {
885  throw std::runtime_error("UtilitiesBase::FindDirichletRowsAndPropagateToCols row and domain maps must match.");
886  }
888  bool has_import = !importer.is_null();
889 
890  // Find the Dirichlet rows
891  std::vector<LocalOrdinal> dirichletRows;
892  FindDirichletRows(A,dirichletRows);
893 
894 #if 0
895  printf("[%d] DirichletRow Ids = ",A->getRowMap()->getComm()->getRank());
896  for(size_t i=0; i<(size_t) dirichletRows.size(); i++)
897  printf("%d ",dirichletRows[i]);
898  printf("\n");
899  fflush(stdout);
900 #endif
901  // Allocate all as non-Dirichlet
902  isDirichletRow = Xpetra::VectorFactory<int,LocalOrdinal,GlobalOrdinal,Node>::Build(A->getRowMap(),true);
903  isDirichletCol = Xpetra::VectorFactory<int,LocalOrdinal,GlobalOrdinal,Node>::Build(A->getColMap(),true);
904 
905  Teuchos::ArrayRCP<int> dr_rcp = isDirichletRow->getDataNonConst(0);
906  Teuchos::ArrayView<int> dr = dr_rcp();
907  Teuchos::ArrayRCP<int> dc_rcp = isDirichletCol->getDataNonConst(0);
908  Teuchos::ArrayView<int> dc = dc_rcp();
909  for(size_t i=0; i<(size_t) dirichletRows.size(); i++) {
910  dr[dirichletRows[i]] = 1;
911  if(!has_import) dc[dirichletRows[i]] = 1;
912  }
913 
914  if(has_import)
915  isDirichletCol->doImport(*isDirichletRow,*importer,Xpetra::CombineMode::ADD);
916 
917  }
918 
919  // This routine takes a BlockedMap and an Importer (assuming that the BlockedMap matches the source of the importer) and generates a BlockedMap corresponding
920  // to the Importer's target map. We assume that the targetMap is unique (which, is not a strict requirement of an Importer, but is here and no, we don't check)
921  // This is largely intended to be used in repartitioning of blocked matrices
925  Xpetra::UnderlyingLib lib = sourceBlockedMap.lib();
926 
927  // De-stride the map if we have to (might regret this later)
928  RCP<const Map> fullMap = sourceBlockedMap.getMap();
929  RCP<const Map> stridedMap = Teuchos::rcp_dynamic_cast<const Xpetra::StridedMap<LocalOrdinal,GlobalOrdinal,Node> >(fullMap);
930  if(!stridedMap.is_null()) fullMap = stridedMap->getMap();
931 
932  // Initial sanity checking for map compatibil
933  const size_t numSubMaps = sourceBlockedMap.getNumMaps();
934  if(!Importer.getSourceMap()->isCompatible(*fullMap))
935  throw std::runtime_error("GenerateBlockedTargetMap(): Map compatibility error");
936 
937  // Build an indicator vector
939 
940  for(size_t i=0; i<numSubMaps; i++) {
941  RCP<const Map> map = sourceBlockedMap.getMap(i);
942 
943  for(size_t j=0; j<map->getNodeNumElements(); j++) {
944  LocalOrdinal jj = fullMap->getLocalElement(map->getGlobalElement(j));
945  block_ids->replaceLocalValue(jj,(int)i);
946  }
947  }
948 
949  // Get the block ids for the new map
950  RCP<const Map> targetMap = Importer.getTargetMap();
952  new_block_ids->doImport(*block_ids,Importer,Xpetra::CombineMode::ADD);
953  Teuchos::ArrayRCP<const int> dataRCP = new_block_ids->getData(0);
954  Teuchos::ArrayView<const int> data = dataRCP();
955 
956 
957  // Get the GIDs for each subblock
958  Teuchos::Array<Teuchos::Array<GlobalOrdinal> > elementsInSubMap(numSubMaps);
959  for(size_t i=0; i<targetMap->getNodeNumElements(); i++) {
960  elementsInSubMap[data[i]].push_back(targetMap->getGlobalElement(i));
961  }
962 
963  // Generate the new submaps
964  std::vector<RCP<const Map> > subMaps(numSubMaps);
965  for(size_t i=0; i<numSubMaps; i++) {
967  }
968 
969  // Build the BlockedMap
970  return rcp(new BlockedMap(targetMap,subMaps));
971 
972  }
973 
974  }; // class Utils
975 
976 
978 
979 } //namespace MueLu
980 
981 #define MUELU_UTILITIESBASE_SHORT
982 #endif // MUELU_UTILITIESBASE_DECL_HPP
virtual Teuchos::ArrayRCP< Scalar > getDataNonConst(size_t j)=0
Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > Matrix
virtual void apply(const MultiVector &X, MultiVector &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS, Scalar alpha=Teuchos::ScalarTraits< Scalar >::one(), Scalar beta=Teuchos::ScalarTraits< Scalar >::zero()) const =0
virtual size_t getNodeNumRows() const =0
static RCP< Import< LocalOrdinal, GlobalOrdinal, Node > > Build(const RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &source, const RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &target)
static RCP< Export< LocalOrdinal, GlobalOrdinal, Node > > Build(const RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &source, const RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &target)
virtual void norm2(const Teuchos::ArrayView< typename Teuchos::ScalarTraits< Scalar >::magnitudeType > &norms) const =0
Xpetra::BlockedMultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > BlockedMultiVector
virtual Teuchos::RCP< const Teuchos::Comm< int > > getComm() const =0
virtual int getSize() const =0
static Teuchos::ArrayRCP< const bool > DetectDirichletCols(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Teuchos::ArrayRCP< const bool > &dirichletRows)
Detect Dirichlet columns based on Dirichlet rows.
virtual int getRank() const =0
static magnitudeType eps()
static Scalar PowerMethod(const Matrix &A, bool scaleByDiag=true, LocalOrdinal niters=10, Magnitude tolerance=1e-2, bool verbose=false, unsigned int seed=123)
Simple transpose for Tpetra::CrsMatrix types.
void setMultiVector(size_t r, Teuchos::RCP< const Vector > v, bool bThyraMode)
static void Residual(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const MultiVector &X, const MultiVector &RHS, MultiVector &Resid)
static Teuchos::RCP< Vector > GetInverse(Teuchos::RCP< const Vector > v, Magnitude tol=Teuchos::ScalarTraits< Scalar >::eps()*100, Scalar tolReplacement=Teuchos::ScalarTraits< Scalar >::zero())
Return vector containing inverse of input vector.
Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > MultiVector
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
static RCP< const Xpetra::BlockedMap< LocalOrdinal, GlobalOrdinal, Node > > GeneratedBlockedTargetMap(const Xpetra::BlockedMap< LocalOrdinal, GlobalOrdinal, Node > &sourceBlockedMap, const Xpetra::Import< LocalOrdinal, GlobalOrdinal, Node > &Importer)
static void ApplyOAZToMatrixRows(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, const std::vector< LocalOrdinal > &dirichletRows)
size_type size() const
virtual size_t getNodeNumElements() const =0
static void FindDirichletRows(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, std::vector< LocalOrdinal > &dirichletRows, bool count_twos_as_dirichlet=false)
virtual LocalOrdinal getLocalElement(GlobalOrdinal globalIndex) const =0
virtual GlobalOrdinal getIndexBase() const =0
static Teuchos::RCP< const Comm< OrdinalType > > getComm()
size_type size() const
Exception throws to report incompatible objects (like maps).
static Teuchos::ArrayRCP< const bool > DetectDirichletRowsExt(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, bool &bHasZeroDiagonal, const Magnitude &tol=Teuchos::ScalarTraits< Scalar >::zero())
Detect Dirichlet rows (extended version)
virtual void reciprocal(const MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A)=0
#define MueLu_sumAll(rcpComm, in, out)
virtual void update(const Scalar &alpha, const MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Scalar &beta)=0
virtual void doImport(const DistObject< Scalar, LocalOrdinal, GlobalOrdinal, Node > &source, const Import< LocalOrdinal, GlobalOrdinal, Node > &importer, CombineMode CM)=0
static Teuchos::ScalarTraits< Scalar >::magnitudeType Distance2(const Teuchos::Array< Teuchos::ArrayRCP< const Scalar >> &v, LocalOrdinal i0, LocalOrdinal i1)
Squared distance between two rows in a multivector.
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getTargetMap() const =0
virtual void getLocalDiagCopy(Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &diag) const =0
void getLocalDiagOffsets(Teuchos::ArrayRCP< size_t > &offsets) const
virtual void getLocalRowView(LocalOrdinal LocalRow, ArrayView< const LocalOrdinal > &indices, ArrayView< const Scalar > &values) const =0
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual RCP< const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > getMap() const
static void FindDirichletRowsAndPropagateToCols(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, Teuchos::RCP< Xpetra::Vector< int, LocalOrdinal, GlobalOrdinal, Node > > &isDirichletRow, Teuchos::RCP< Xpetra::Vector< int, LocalOrdinal, GlobalOrdinal, Node > > &isDirichletCol)
void getLocalDiagCopy(Xpetra::Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &diag) const
virtual bool isFillComplete() const =0
size_t getNumMaps() const
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getMap() const =0
Xpetra::BlockedVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > BlockedVector
Xpetra::CrsMatrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > CrsMatrix
static Teuchos::ArrayRCP< Scalar > GetLumpedMatrixDiagonal(const Matrix &A)
Extract Matrix Diagonal of lumped matrix.
virtual GlobalOrdinal getGlobalElement(LocalOrdinal localIndex) const =0
static Scalar Frobenius(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &B)
Frobenius inner product of two matrices.
T * getRawPtr() const
Teuchos::ScalarTraits< Scalar >::magnitudeType Magnitude
virtual size_t getNumEntriesInLocalRow(LocalOrdinal localRow) const =0
static void seedrandom(unsigned int s)
Xpetra::Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > Vector
static RCP< Vector > Build(const Teuchos::RCP< const Map > &map, bool zeroOut=true)
static void ZeroDirichletRows(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, const Teuchos::ArrayRCP< const bool > &dirichletRows, Scalar replaceWith=Teuchos::ScalarTraits< Scalar >::zero())
virtual Scalar dot(const Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &a) const =0
static void ApplyOAZToMatrixRows(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, const Teuchos::ArrayRCP< const bool > &dirichletRows)
static magnitudeType magnitude(T a)
const RCP< const Map > getMap(size_t i, bool bThyraMode=false) const
TransListIter iter
Xpetra::BlockedMap< LocalOrdinal, GlobalOrdinal, Node > BlockedMap
static void ZeroDirichletCols(Teuchos::RCP< Matrix > &A, const Teuchos::ArrayRCP< const bool > &dirichletCols, Scalar replaceWith=Teuchos::ScalarTraits< Scalar >::zero())
static Teuchos::Array< Magnitude > ResidualNorm(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const MultiVector &X, const MultiVector &RHS)
void push_back(const value_type &x)
virtual RCP< const CrsGraph > getCrsGraph() const =0
static RCP< MultiVector > Residual(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const MultiVector &X, const MultiVector &RHS)
virtual bool isSameAs(const Map< LocalOrdinal, GlobalOrdinal, Node > &map) const =0
static Teuchos::ArrayRCP< const bool > DetectDirichletRows(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Magnitude &tol=Teuchos::ScalarTraits< Scalar >::zero(), bool count_twos_as_dirichlet=false)
Detect Dirichlet rows.
static RCP< Matrix > Crs2Op(RCP< CrsMatrix > Op)
Xpetra::CrsMatrixWrap< Scalar, LocalOrdinal, GlobalOrdinal, Node > CrsMatrixWrap
static RCP< Teuchos::FancyOStream > MakeFancy(std::ostream &os)
virtual Teuchos::RCP< const Map > getRangeMap() const =0
static Teuchos::RCP< MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Build(const Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &map, size_t NumVectors, bool zeroOut=true)
Exception throws to report errors in the internal logical of the program.
Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > Map
static Teuchos::RCP< Map< LocalOrdinal, GlobalOrdinal, Node > > Build(UnderlyingLib lib, global_size_t numGlobalElements, GlobalOrdinal indexBase, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, LocalGlobal lg=Xpetra::GloballyDistributed)
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getSourceMap() const =0
virtual UnderlyingLib lib() const
virtual size_t getNumVectors() const =0
static RCP< Vector > GetMatrixOverlappedDiagonal(const Matrix &A)
Extract Overlapped Matrix Diagonal.
static Teuchos::Array< Magnitude > ResidualNorm(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const MultiVector &X, const MultiVector &RHS, MultiVector &Resid)
static Teuchos::RCP< Vector > GetLumpedMatrixDiagonal(Teuchos::RCP< const Matrix > rcpA)
Extract Matrix Diagonal of lumped matrix.
static RCP< Vector > GetMatrixDiagonalInverse(const Matrix &A, Magnitude tol=Teuchos::ScalarTraits< Scalar >::eps()*100)
Extract Matrix Diagonal.
virtual Teuchos::ArrayRCP< const Scalar > getData(size_t j) const =0
static void ZeroDirichletRows(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, const std::vector< LocalOrdinal > &dirichletRows, Scalar replaceWith=Teuchos::ScalarTraits< Scalar >::zero())
static void SetRandomSeed(const Teuchos::Comm< int > &comm)
Set seed for random number generator.
virtual Teuchos::RCP< const Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > getVector(size_t j) const =0
static void ZeroDirichletRows(Teuchos::RCP< Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &X, const Teuchos::ArrayRCP< const bool > &dirichletRows, Scalar replaceWith=Teuchos::ScalarTraits< Scalar >::zero())
virtual Teuchos::RCP< const Map > getDomainMap() const =0
static Teuchos::ArrayRCP< Scalar > GetMatrixDiagonal(const Matrix &A)
Extract Matrix Diagonal.
bool is_null() const