MueLu Version of the Day
Loading...
Searching...
No Matches
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
25namespace MueLu {
26template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
28
29template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
31
32template <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
41template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
43 Input(coarseLevel, "A");
44}
45
46template <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> >(coarseLevel, "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
149 Teuchos::ArrayView<const LocalOrdinal> indices;
150 Teuchos::ArrayView<const Scalar> vals;
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
187 SC one = Teuchos::ScalarTraits<Scalar>::one(), zero = Teuchos::ScalarTraits<Scalar>::zero();
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
220 Teuchos::RCP<Vector> invDiag = Utilities::GetMatrixDiagonalInverse(*A);
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
241 Teuchos::RCP<Vector> invDiag = Utilities::GetMatrixDiagonalInverse(*A);
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
255template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
256void MatrixAnalysisFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::checkVectorEntries(const Teuchos::RCP<Vector> &vec, std::string info) const {
257 SC zero = Teuchos::ScalarTraits<Scalar>::zero();
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)
MueLu::DefaultLocalOrdinal LocalOrdinal
MueLu::DefaultGlobalOrdinal GlobalOrdinal
Exception throws to report errors in the internal logical of the program.
Timer to be used in factories. Similar to Monitor but with additional timers.
Class that holds all level-specific information.
int GetLevelID() const
Return level number.
void checkVectorEntries(const Teuchos::RCP< Vector > &vec, std::string info) const
void DeclareInput(Level &fineLevel, Level &coarseLevel) const
Specifies the data that this class needs, and the factories that generate that data.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void Build(Level &fineLevel, Level &coarseLevel) const
Build an object with this factory.
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.
Namespace for MueLu classes and methods.
@ Runtime0
One-liner description of what is happening.