MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_MatrixAnalysisFactory_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // MueLu: A package for multigrid based preconditioning
4 //
5 // Copyright 2012 NTESS and the MueLu contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef MUELU_MATRIXANALYSISFACTORY_DEF_HPP_
11 #define MUELU_MATRIXANALYSISFACTORY_DEF_HPP_
12 
14 
15 #include <Xpetra_Map.hpp>
16 #include <Xpetra_StridedMap.hpp> // for nDofsPerNode...
17 #include <Xpetra_Vector.hpp>
18 #include <Xpetra_VectorFactory.hpp>
19 #include <Xpetra_Matrix.hpp>
20 
21 #include "MueLu_Level.hpp"
22 #include "MueLu_Utilities.hpp"
23 #include "MueLu_Monitor.hpp"
24 
25 namespace MueLu {
26 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
28 
29 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
31 
32 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
34  RCP<ParameterList> validParamList = rcp(new ParameterList());
35 
36  validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A to be permuted.");
37 
38  return validParamList;
39 }
40 
41 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
43  Input(fineLevel, "A");
44 }
45 
46 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
48  FactoryMonitor m(*this, "MatrixAnalysis Factory ", fineLevel);
49 
50  Teuchos::RCP<Matrix> A = Get<Teuchos::RCP<Matrix> >(fineLevel, "A");
51  Teuchos::RCP<const Teuchos::Comm<int> > comm = A->getRangeMap()->getComm();
52 
53  // const ParameterList & pL = GetParameterList();
54 
55  // General information
56  {
57  GetOStream(Runtime0) << "~~~~~~~~ GENERAL INFORMATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (Level " << fineLevel.GetLevelID() << ")" << std::endl;
58  GetOStream(Runtime0) << "A is a " << A->getRangeMap()->getGlobalNumElements() << " x " << A->getDomainMap()->getGlobalNumElements() << " matrix." << std::endl;
59 
60  if (A->IsView("stridedMaps") && Teuchos::rcp_dynamic_cast<const StridedMap>(A->getRowMap("stridedMaps")) != Teuchos::null) {
61  Teuchos::RCP<const StridedMap> strRowMap = Teuchos::rcp_dynamic_cast<const StridedMap>(A->getRowMap("stridedMaps"));
62  LocalOrdinal blockid = strRowMap->getStridedBlockId();
63  if (blockid > -1) {
64  std::vector<size_t> stridingInfo = strRowMap->getStridingData();
65  LO dofsPerNode = Teuchos::as<LocalOrdinal>(stridingInfo[blockid]);
66  GetOStream(Runtime0) << "Strided row: " << dofsPerNode << " dofs per node. Strided block id = " << blockid << std::endl;
67  } else {
68  GetOStream(Runtime0) << "Row: " << strRowMap->getFixedBlockSize() << " dofs per node" << std::endl;
69  }
70  }
71 
72  if (A->IsView("stridedMaps") && Teuchos::rcp_dynamic_cast<const StridedMap>(A->getColMap("stridedMaps")) != Teuchos::null) {
73  Teuchos::RCP<const StridedMap> strDomMap = Teuchos::rcp_dynamic_cast<const StridedMap>(A->getColMap("stridedMaps"));
74  LocalOrdinal blockid = strDomMap->getStridedBlockId();
75  if (blockid > -1) {
76  std::vector<size_t> stridingInfo = strDomMap->getStridingData();
77  LO dofsPerNode = Teuchos::as<LocalOrdinal>(stridingInfo[blockid]);
78  GetOStream(Runtime0) << "Strided column: " << dofsPerNode << " dofs per node. Strided block id = " << blockid << std::endl;
79  } else {
80  GetOStream(Runtime0) << "Column: " << strDomMap->getFixedBlockSize() << " dofs per node" << std::endl;
81  }
82  }
83 
84  GetOStream(Runtime0) << "A is distributed over " << comm->getSize() << " processors" << std::endl;
85 
86  // empty processors
87  std::vector<LO> lelePerProc(comm->getSize(), 0);
88  std::vector<LO> gelePerProc(comm->getSize(), 0);
89  lelePerProc[comm->getRank()] = A->getLocalNumEntries();
90  Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, comm->getSize(), &lelePerProc[0], &gelePerProc[0]);
91  if (comm->getRank() == 0) {
92  for (int i = 0; i < comm->getSize(); i++) {
93  if (gelePerProc[i] == 0) {
94  GetOStream(Runtime0) << "Proc " << i << " is empty." << std::endl;
95  }
96  }
97  }
98  }
99 
100  // Matrix diagonal
101  {
102  GetOStream(Runtime0) << "~~~~~~~~ MATRIX DIAGONAL ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (Level " << fineLevel.GetLevelID() << ")" << std::endl;
103  Teuchos::RCP<Vector> diagAVec = VectorFactory::Build(A->getRowMap(), true);
104  A->getLocalDiagCopy(*diagAVec);
105  Teuchos::ArrayRCP<const Scalar> diagAVecData = diagAVec->getData(0);
106  GlobalOrdinal lzerosOnDiagonal = 0;
107  GlobalOrdinal gzerosOnDiagonal = 0;
108  GlobalOrdinal lnearlyzerosOnDiagonal = 0;
109  GlobalOrdinal gnearlyzerosOnDiagonal = 0;
110  GlobalOrdinal lnansOnDiagonal = 0;
111  GlobalOrdinal gnansOnDiagonal = 0;
112 
113  for (size_t i = 0; i < diagAVec->getMap()->getLocalNumElements(); ++i) {
114  if (diagAVecData[i] == Teuchos::ScalarTraits<Scalar>::zero()) {
115  lzerosOnDiagonal++;
116  } else if (Teuchos::ScalarTraits<Scalar>::magnitude(diagAVecData[i]) < 1e-6) {
117  lnearlyzerosOnDiagonal++;
118  } else if (Teuchos::ScalarTraits<Scalar>::isnaninf(diagAVecData[i])) {
119  lnansOnDiagonal++;
120  }
121  }
122 
123  // sum up all entries in multipleColRequests over all processors
124  MueLu_sumAll(comm, lzerosOnDiagonal, gzerosOnDiagonal);
125  MueLu_sumAll(comm, lnearlyzerosOnDiagonal, gnearlyzerosOnDiagonal);
126  MueLu_sumAll(comm, lnansOnDiagonal, gnansOnDiagonal);
127 
128  if (gzerosOnDiagonal > 0) GetOStream(Runtime0) << "Found " << gzerosOnDiagonal << " zeros on diagonal of A" << std::endl;
129  if (gnearlyzerosOnDiagonal > 0) GetOStream(Runtime0) << "Found " << gnearlyzerosOnDiagonal << " entries with absolute value < 1.0e-6 on diagonal of A" << std::endl;
130  if (gnansOnDiagonal > 0) GetOStream(Runtime0) << "Found " << gnansOnDiagonal << " entries with NAN or INF on diagonal of A" << std::endl;
131  }
132 
133  // Diagonal dominance?
134  {
135  GetOStream(Runtime0) << "~~~~~~~~ DIAGONAL DOMINANCE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (Level " << fineLevel.GetLevelID() << ")" << std::endl;
136  // loop over all local rows in matrix A and keep diagonal entries if corresponding
137  // matrix rows are not contained in permRowMap
138  GlobalOrdinal lnumWeakDiagDomRows = 0;
139  GlobalOrdinal gnumWeakDiagDomRows = 0;
140  GlobalOrdinal lnumStrictDiagDomRows = 0;
141  GlobalOrdinal gnumStrictDiagDomRows = 0;
142  double worstRatio = 99999999.9;
143  for (size_t row = 0; row < A->getRowMap()->getLocalNumElements(); row++) {
144  GlobalOrdinal grow = A->getRowMap()->getGlobalElement(row);
145 
146  size_t nnz = A->getNumEntriesInLocalRow(row);
147 
148  // extract local row information from matrix
151  A->getLocalRowView(row, indices, vals);
152 
153  TEUCHOS_TEST_FOR_EXCEPTION(Teuchos::as<size_t>(indices.size()) != nnz, Exceptions::RuntimeError, "MueLu::MatrixAnalysisFactory::Build: number of nonzeros not equal to number of indices? Error.");
154 
155  // find column entry with max absolute value
156  double norm1 = 0.0;
157  double normdiag = 0.0;
158  for (size_t j = 0; j < Teuchos::as<size_t>(indices.size()); j++) {
159  GO gcol = A->getColMap()->getGlobalElement(indices[j]);
160  if (gcol == grow)
161  normdiag = Teuchos::as<double>(Teuchos::ScalarTraits<Scalar>::magnitude(vals[j]));
162  else
163  norm1 += Teuchos::as<double>(Teuchos::ScalarTraits<Scalar>::magnitude(vals[j]));
164  }
165 
166  if (normdiag >= norm1)
167  lnumWeakDiagDomRows++;
168  else if (normdiag > norm1)
169  lnumStrictDiagDomRows++;
170 
171  if (norm1 != 0.0) {
172  if (normdiag / norm1 < worstRatio) worstRatio = normdiag / norm1;
173  }
174  }
175 
176  MueLu_sumAll(comm, lnumWeakDiagDomRows, gnumWeakDiagDomRows);
177  MueLu_sumAll(comm, lnumStrictDiagDomRows, gnumStrictDiagDomRows);
178 
179  GetOStream(Runtime0) << "A has " << gnumWeakDiagDomRows << "/" << A->getRangeMap()->getGlobalNumElements() << " weakly diagonal dominant rows. (" << Teuchos::as<Scalar>(gnumWeakDiagDomRows / A->getRangeMap()->getGlobalNumElements() * 100) << "%)" << std::endl;
180  GetOStream(Runtime0) << "A has " << gnumStrictDiagDomRows << "/" << A->getRangeMap()->getGlobalNumElements() << " strictly diagonal dominant rows. (" << Teuchos::as<Scalar>(gnumStrictDiagDomRows / A->getRangeMap()->getGlobalNumElements() * 100) << "%)" << std::endl;
181 
182  double gworstRatio;
183  Teuchos::reduceAll(*comm, Teuchos::REDUCE_MIN, comm->getSize(), &worstRatio, &gworstRatio);
184  GetOStream(Runtime0) << "The minimum of the ratio of diagonal element/ sum of off-diagonal elements is " << gworstRatio << ". Values about 1.0 are ok." << std::endl;
185  }
186 
188 
189  // multiply with one vector
190  {
191  GetOStream(Runtime0) << "~~~~~~~~ Av with one vector ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (Level " << fineLevel.GetLevelID() << ")" << std::endl;
192  Teuchos::RCP<Vector> ones = VectorFactory::Build(A->getDomainMap(), 1);
193  ones->putScalar(one);
194 
195  Teuchos::RCP<Vector> res1 = VectorFactory::Build(A->getRangeMap(), false);
196  A->apply(*ones, *res1, Teuchos::NO_TRANS, one, zero);
197  checkVectorEntries(res1, std::string("after applying the one vector to A"));
198  }
199 
200  {
201  GetOStream(Runtime0) << "~~~~~~~~ Av with random vector ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (Level " << fineLevel.GetLevelID() << ")" << std::endl;
202  Teuchos::RCP<Vector> randvec = VectorFactory::Build(A->getDomainMap(), 1);
203  randvec->randomize();
204 
205  Teuchos::RCP<Vector> resrand = VectorFactory::Build(A->getRangeMap(), false);
206  A->apply(*randvec, *resrand, Teuchos::NO_TRANS, one, zero);
207  checkVectorEntries(resrand, std::string("after applying random vector to A"));
208  }
209 
210  // apply Jacobi sweep
211  {
212  GetOStream(Runtime0) << "~~~~~~~~ Damped Jacobi sweep (one vector) ~~~~~~~~~~~~~~~~~~~~~~~ (Level " << fineLevel.GetLevelID() << ")" << std::endl;
213  Teuchos::RCP<Vector> ones = VectorFactory::Build(A->getDomainMap(), 1);
214  ones->putScalar(one);
215 
216  Teuchos::RCP<Vector> res1 = VectorFactory::Build(A->getRangeMap(), false);
217  A->apply(*ones, *res1, Teuchos::NO_TRANS, one, zero);
218  checkVectorEntries(res1, std::string("after applying one vector to A"));
219 
221  checkVectorEntries(invDiag, std::string("in invDiag"));
222 
223  Teuchos::RCP<Vector> res2 = VectorFactory::Build(A->getRangeMap(), false);
224  res2->elementWiseMultiply(0.8, *invDiag, *res1, 0.0);
225  checkVectorEntries(res2, std::string("after scaling Av with invDiag (with v the one vector)"));
226  res2->update(1.0, *ones, -1.0);
227 
228  checkVectorEntries(res2, std::string("after applying one damped Jacobi sweep (with one vector)"));
229  }
230 
231  // apply Jacobi sweep
232  {
233  GetOStream(Runtime0) << "~~~~~~~~ Damped Jacobi sweep (random vector) ~~~~~~~~~~~~~~~~~~~~ (Level " << fineLevel.GetLevelID() << ")" << std::endl;
234  Teuchos::RCP<Vector> ones = VectorFactory::Build(A->getDomainMap(), 1);
235  ones->randomize();
236 
237  Teuchos::RCP<Vector> res1 = VectorFactory::Build(A->getRangeMap(), false);
238  A->apply(*ones, *res1, Teuchos::NO_TRANS, one, zero);
239  checkVectorEntries(res1, std::string("after applying a random vector to A"));
240 
242  checkVectorEntries(invDiag, std::string("in invDiag"));
243 
244  Teuchos::RCP<Vector> res2 = VectorFactory::Build(A->getRangeMap(), false);
245  res2->elementWiseMultiply(0.8, *invDiag, *res1, 0.0);
246  checkVectorEntries(res2, std::string("after scaling Av with invDiag (with v a random vector)"));
247  res2->update(1.0, *ones, -1.0);
248 
249  checkVectorEntries(res2, std::string("after applying one damped Jacobi sweep (with v a random vector)"));
250  }
251 
252  GetOStream(Runtime0) << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (Level " << fineLevel.GetLevelID() << ")" << std::endl;
253 }
254 
255 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
258  Teuchos::RCP<const Teuchos::Comm<int> > comm = vec->getMap()->getComm();
259  Teuchos::ArrayRCP<const Scalar> vecData = vec->getData(0);
260  GO lzeros = 0;
261  GO gzeros = 0;
262  GO lnans = 0;
263  GO gnans = 0;
264 
265  for (size_t i = 0; i < vec->getMap()->getLocalNumElements(); ++i) {
266  if (vecData[i] == zero) {
267  lzeros++;
268  } else if (Teuchos::ScalarTraits<Scalar>::isnaninf(vecData[i])) {
269  lnans++;
270  }
271  }
272 
273  // sum up all entries in multipleColRequests over all processors
274  MueLu_sumAll(comm, lzeros, gzeros);
275  MueLu_sumAll(comm, lnans, gnans);
276 
277  if (gzeros > 0) GetOStream(Runtime0) << "Found " << gzeros << " zeros " << info << std::endl;
278  if (gnans > 0) GetOStream(Runtime0) << "Found " << gnans << " entries " << info << std::endl;
279 }
280 
281 } // namespace MueLu
282 
283 #endif /* MUELU_MATRIXANALYSISFACTORY_DEF_HPP_ */
#define MueLu_sumAll(rcpComm, in, out)
void Build(Level &fineLevel, Level &coarseLevel) const
Build an object with this factory.
MueLu::DefaultLocalOrdinal LocalOrdinal
GlobalOrdinal GO
Timer to be used in factories. Similar to Monitor but with additional timers.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
size_type size() const
LocalOrdinal LO
One-liner description of what is happening.
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
void checkVectorEntries(const Teuchos::RCP< Vector > &vec, std::string info) const
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
MueLu::DefaultGlobalOrdinal GlobalOrdinal
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:63
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
static RCP< Vector > GetMatrixDiagonalInverse(const Matrix &A, Magnitude tol=Teuchos::ScalarTraits< Scalar >::eps()*100, Scalar valReplacement=Teuchos::ScalarTraits< Scalar >::zero(), const bool doLumped=false)
Extract Matrix Diagonal.
static magnitudeType magnitude(T a)
Scalar SC
void DeclareInput(Level &fineLevel, Level &coarseLevel) const
Specifies the data that this class needs, and the factories that generate that data.
Exception throws to report errors in the internal logical of the program.