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.
void Input(Level &level, const std::string &varName) const
T Get(Level &level, const std::string &varName) const
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)
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
Namespace for MueLu classes and methods.
@ Runtime0
One-liner description of what is happening.