MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_BraessSarazinSmoother_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_BRAESSSARAZINSMOOTHER_DEF_HPP_
11#define MUELU_BRAESSSARAZINSMOOTHER_DEF_HPP_
12
13#include <Teuchos_ArrayViewDecl.hpp>
14#include <Teuchos_ScalarTraits.hpp>
15
16#include "MueLu_ConfigDefs.hpp"
17
18#include <Xpetra_Matrix.hpp>
19#include <Xpetra_BlockedCrsMatrix.hpp>
20#include <Xpetra_MultiVectorFactory.hpp>
21#include <Xpetra_VectorFactory.hpp>
22#include <Xpetra_ReorderedBlockedCrsMatrix.hpp>
23
25#include "MueLu_Level.hpp"
26#include "MueLu_Utilities.hpp"
27#include "MueLu_Monitor.hpp"
28#include "MueLu_HierarchyUtils.hpp"
30
31#include "MueLu_FactoryManager.hpp"
32
33namespace MueLu {
34
35template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
36void BraessSarazinSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::AddFactoryManager(RCP<const FactoryManagerBase> FactManager, int pos) {
37 TEUCHOS_TEST_FOR_EXCEPTION(pos != 0, Exceptions::RuntimeError, "MueLu::BraessSarazinSmoother::AddFactoryManager: parameter \'pos\' must be zero! error.");
38 FactManager_ = FactManager;
39}
40
41template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
43 RCP<ParameterList> validParamList = rcp(new ParameterList());
44
45 SC one = Teuchos::ScalarTraits<SC>::one();
46
47 validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A");
48
49 validParamList->set<bool>("lumping", false,
50 "Use lumping to construct diag(A(0,0)), "
51 "i.e. use row sum of the abs values on the diagonal as approximation of A00 (and A00^{-1})");
52 validParamList->set<SC>("Damping factor", one, "Damping/Scaling factor in BraessSarazin (usually has to be chosen > 1, default = 1.0)");
53 validParamList->set<LO>("Sweeps", 1, "Number of BraessSarazin sweeps (default = 1)");
54 validParamList->set<bool>("q2q1 mode", false, "Run in the mode matching Q2Q1 matlab code");
55
56 return validParamList;
57}
58
59template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
61 this->Input(currentLevel, "A");
62
63 TEUCHOS_TEST_FOR_EXCEPTION(FactManager_.is_null(), Exceptions::RuntimeError,
64 "MueLu::BraessSarazinSmoother::DeclareInput: FactManager_ must not be null! "
65 "Introduce a FactoryManager for the SchurComplement equation.");
66
67 // carefully call DeclareInput after switching to internal FactoryManager
68 {
69 SetFactoryManager currentSFM(rcpFromRef(currentLevel), FactManager_);
70
71 // request "Smoother" for current subblock row.
72 currentLevel.DeclareInput("PreSmoother", FactManager_->GetFactory("Smoother").get());
73
74 // request Schur matrix just in case
75 currentLevel.DeclareInput("A", FactManager_->GetFactory("A").get());
76 }
77}
78
79template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
81 FactoryMonitor m(*this, "Setup Smoother", currentLevel);
82
83 if (SmootherPrototype::IsSetup() == true)
84 this->GetOStream(Warnings0) << "MueLu::BreaessSarazinSmoother::Setup(): Setup() has already been called";
85
86 // Extract blocked operator A from current level
87 A_ = Factory::Get<RCP<Matrix> >(currentLevel, "A");
88 RCP<BlockedCrsMatrix> bA = rcp_dynamic_cast<BlockedCrsMatrix>(A_);
89 TEUCHOS_TEST_FOR_EXCEPTION(bA.is_null(), Exceptions::BadCast,
90 "MueLu::BraessSarazinSmoother::Setup: input matrix A is not of type BlockedCrsMatrix! error.");
91
92 // Store map extractors
93 rangeMapExtractor_ = bA->getRangeMapExtractor();
94 domainMapExtractor_ = bA->getDomainMapExtractor();
95
96 // Store the blocks in local member variables
97 A00_ = bA->getMatrix(0, 0);
98 A01_ = bA->getMatrix(0, 1);
99 A10_ = bA->getMatrix(1, 0);
100 A11_ = bA->getMatrix(1, 1);
101
102 const ParameterList& pL = Factory::GetParameterList();
103 SC omega = pL.get<SC>("Damping factor");
104
105 // Create the inverse of the diagonal of F
106 // TODO add safety check for zeros on diagonal of F!
107 RCP<Vector> diagFVector = VectorFactory::Build(A00_->getRowMap());
108 if (pL.get<bool>("lumping") == false) {
109 A00_->getLocalDiagCopy(*diagFVector); // extract diagonal of F
110 } else {
112 }
113 diagFVector->scale(omega);
114 D_ = Utilities::GetInverse(diagFVector);
115
116 // check whether D_ is a blocked vector with only 1 block
117 RCP<BlockedVector> bD = Teuchos::rcp_dynamic_cast<BlockedVector>(D_);
118 if (bD.is_null() == false && bD->getBlockedMap()->getNumMaps() == 1) {
119 RCP<Vector> nestedVec = bD->getMultiVector(0, bD->getBlockedMap()->getThyraMode())->getVectorNonConst(0);
120 D_.swap(nestedVec);
121 }
122
123 // Set the Smoother
124 // carefully switch to the SubFactoryManagers (defined by the users)
125 {
126 SetFactoryManager currentSFM(rcpFromRef(currentLevel), FactManager_);
127 smoo_ = currentLevel.Get<RCP<SmootherBase> >("PreSmoother", FactManager_->GetFactory("Smoother").get());
128 S_ = currentLevel.Get<RCP<Matrix> >("A", FactManager_->GetFactory("A").get());
129 }
130
132}
133
134template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
135void BraessSarazinSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Apply(MultiVector& X, const MultiVector& B, bool InitialGuessIsZero) const {
136 TEUCHOS_TEST_FOR_EXCEPTION(SmootherPrototype::IsSetup() == false, Exceptions::RuntimeError,
137 "MueLu::BraessSarazinSmoother::Apply(): Setup() has not been called");
138
139 RCP<MultiVector> rcpX = rcpFromRef(X);
140 RCP<const MultiVector> rcpB = rcpFromRef(B);
141
142 // make sure that both rcpX and rcpB are BlockedMultiVector objects
143 bool bCopyResultX = false;
144 bool bReorderX = false;
145 bool bReorderB = false;
146 RCP<BlockedCrsMatrix> bA = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A_);
147 MUELU_TEST_FOR_EXCEPTION(bA.is_null() == true, Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::Apply(): A_ must be a BlockedCrsMatrix");
148 RCP<BlockedMultiVector> bX = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(rcpX);
149 RCP<const BlockedMultiVector> bB = Teuchos::rcp_dynamic_cast<const BlockedMultiVector>(rcpB);
150
151 // check the type of operator
152 RCP<Xpetra::ReorderedBlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> > rbA =
153 Teuchos::rcp_dynamic_cast<Xpetra::ReorderedBlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> >(bA);
154
155 if (rbA.is_null() == false) {
156 // A is a ReorderedBlockedCrsMatrix and thus uses nested maps, retrieve BlockedCrsMatrix and use plain blocked
157 // map for the construction of the blocked multivectors
158
159 // check type of X vector
160 if (bX.is_null() == true) {
161 RCP<MultiVector> vectorWithBlockedMap = Teuchos::rcp(new BlockedMultiVector(rbA->getBlockedCrsMatrix()->getBlockedDomainMap(), rcpX));
162 rcpX.swap(vectorWithBlockedMap);
163 bCopyResultX = true;
164 bReorderX = true;
165 }
166
167 // check type of B vector
168 if (bB.is_null() == true) {
169 RCP<const MultiVector> vectorWithBlockedMap = Teuchos::rcp(new BlockedMultiVector(rbA->getBlockedCrsMatrix()->getBlockedRangeMap(), rcpB));
170 rcpB.swap(vectorWithBlockedMap);
171 bReorderB = true;
172 }
173 } else {
174 // A is a BlockedCrsMatrix and uses a plain blocked map
175 if (bX.is_null() == true) {
176 RCP<MultiVector> vectorWithBlockedMap = Teuchos::rcp(new BlockedMultiVector(bA->getBlockedDomainMap(), rcpX));
177 rcpX.swap(vectorWithBlockedMap);
178 bCopyResultX = true;
179 }
180
181 if (bB.is_null() == true) {
182 RCP<const MultiVector> vectorWithBlockedMap = Teuchos::rcp(new BlockedMultiVector(bA->getBlockedRangeMap(), rcpB));
183 rcpB.swap(vectorWithBlockedMap);
184 }
185 }
186
187 // we now can guarantee that X and B are blocked multi vectors
188 bX = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(rcpX);
189 bB = Teuchos::rcp_dynamic_cast<const BlockedMultiVector>(rcpB);
190
191 // Finally we can do a reordering of the blocked multivectors if A is a ReorderedBlockedCrsMatrix
192 if (rbA.is_null() == false) {
193 Teuchos::RCP<const Xpetra::BlockReorderManager> brm = rbA->getBlockReorderManager();
194
195 // check type of X vector
196 if (bX->getBlockedMap()->getNumMaps() != bA->getDomainMapExtractor()->NumMaps() || bReorderX) {
197 // X is a blocked multi vector but incompatible to the reordered blocked operator A
198 Teuchos::RCP<MultiVector> reorderedBlockedVector = buildReorderedBlockedMultiVector(brm, bX);
199 rcpX.swap(reorderedBlockedVector);
200 }
201
202 if (bB->getBlockedMap()->getNumMaps() != bA->getRangeMapExtractor()->NumMaps() || bReorderB) {
203 // B is a blocked multi vector but incompatible to the reordered blocked operator A
204 Teuchos::RCP<const MultiVector> reorderedBlockedVector = buildReorderedBlockedMultiVector(brm, bB);
205 rcpB.swap(reorderedBlockedVector);
206 }
207 }
208
209 // use the GIDs of the sub blocks
210 // This is valid as the subblocks actually represent the GIDs (either Thyra, Xpetra or pseudo Xpetra)
211
212 bool bRangeThyraMode = rangeMapExtractor_->getThyraMode();
213 bool bDomainThyraMode = domainMapExtractor_->getThyraMode();
214
215 RCP<MultiVector> deltaX = MultiVectorFactory::Build(rcpX->getMap(), rcpX->getNumVectors());
216 RCP<BlockedMultiVector> bdeltaX = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(deltaX);
217 RCP<MultiVector> deltaX0 = bdeltaX->getMultiVector(0, bDomainThyraMode);
218 RCP<MultiVector> deltaX1 = bdeltaX->getMultiVector(1, bDomainThyraMode);
219
220 RCP<MultiVector> Rtmp = rangeMapExtractor_->getVector(1, rcpB->getNumVectors(), bRangeThyraMode);
221
222 typedef Teuchos::ScalarTraits<SC> STS;
223 SC one = STS::one(), zero = STS::zero();
224
225 // extract parameters from internal parameter list
226 const ParameterList& pL = Factory::GetParameterList();
227 LO nSweeps = pL.get<LO>("Sweeps");
228
229 RCP<MultiVector> R; // = MultiVectorFactory::Build(rcpB->getMap(), rcpB->getNumVectors());;
230 if (InitialGuessIsZero) {
231 R = MultiVectorFactory::Build(rcpB->getMap(), rcpB->getNumVectors());
232 R->update(one, *rcpB, zero);
233 } else {
234 R = Utilities::Residual(*A_, *rcpX, *rcpB);
235 }
236
237 // extract diagonal of Schur complement operator
238 RCP<Vector> diagSVector = VectorFactory::Build(S_->getRowMap());
239 S_->getLocalDiagCopy(*diagSVector);
240
241 for (LO run = 0; run < nSweeps; ++run) {
242 // Extract corresponding subvectors from X and R
243 // Automatically detect whether we use Thyra or Xpetra GIDs
244 // The GIDs should be always compatible with the GIDs of A00, A01, etc...
245 RCP<MultiVector> R0 = rangeMapExtractor_->ExtractVector(R, 0, bRangeThyraMode);
246 RCP<MultiVector> R1 = rangeMapExtractor_->ExtractVector(R, 1, bRangeThyraMode);
247
248 // Calculate Rtmp = R1 - D * deltaX0 (equation 8.14)
249 deltaX0->putScalar(zero);
250 deltaX0->elementWiseMultiply(one, *D_, *R0, zero); // deltaX0 = D * R0 (equation 8.13)
251 A10_->apply(*deltaX0, *Rtmp); // Rtmp = A10*D*deltaX0 (intermediate step)
252 Rtmp->update(one, *R1, -one); // Rtmp = R1 - A10*D*deltaX0
253
254 if (!pL.get<bool>("q2q1 mode")) {
255 deltaX1->putScalar(zero);
256 } else {
257 // special code for q2q1
258 if (Teuchos::rcp_dynamic_cast<BlockedVector>(diagSVector) == Teuchos::null) {
259 ArrayRCP<SC> Sdiag = diagSVector->getDataNonConst(0);
260 ArrayRCP<SC> deltaX1data = deltaX1->getDataNonConst(0);
261 ArrayRCP<SC> Rtmpdata = Rtmp->getDataNonConst(0);
262 for (GO row = 0; row < deltaX1data.size(); row++)
263 deltaX1data[row] = Teuchos::as<SC>(1.1) * Rtmpdata[row] / Sdiag[row];
264 } else {
265 TEUCHOS_TEST_FOR_EXCEPTION(true, MueLu::Exceptions::RuntimeError, "MueLu::BraessSarazinSmoother: q2q1 mode only supported for non-blocked operators.")
266 }
267 }
268
269 smoo_->Apply(*deltaX1, *Rtmp);
270
271 // Compute deltaX0
272 deltaX0->putScalar(zero); // just for safety
273 A01_->apply(*deltaX1, *deltaX0); // deltaX0 = A01*deltaX1
274 deltaX0->update(one, *R0, -one); // deltaX0 = R0 - A01*deltaX1
275 R0.swap(deltaX0);
276 deltaX0->elementWiseMultiply(one, *D_, *R0, zero); // deltaX0 = D*(R0 - A01*deltaX1)
277
278 RCP<MultiVector> X0 = domainMapExtractor_->ExtractVector(rcpX, 0, bDomainThyraMode);
279 RCP<MultiVector> X1 = domainMapExtractor_->ExtractVector(rcpX, 1, bDomainThyraMode);
280
281 // Update solution
282 X0->update(one, *deltaX0, one);
283 X1->update(one, *deltaX1, one);
284
285 domainMapExtractor_->InsertVector(X0, 0, rcpX, bDomainThyraMode);
286 domainMapExtractor_->InsertVector(X1, 1, rcpX, bDomainThyraMode);
287
288 if (run < nSweeps - 1) {
289 R = Utilities::Residual(*A_, *rcpX, *rcpB);
290 }
291 }
292
293 if (bCopyResultX == true) {
294 RCP<MultiVector> Xmerged = bX->Merge();
295 X.update(one, *Xmerged, zero);
296 }
297}
298
299template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
300RCP<MueLu::SmootherPrototype<Scalar, LocalOrdinal, GlobalOrdinal, Node> >
304
305template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
307 description() const {
308 std::ostringstream out;
310 out << "{type = " << type_ << "}";
311 return out.str();
312}
313
314template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
315void BraessSarazinSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::print(Teuchos::FancyOStream& out, const VerbLevel verbLevel) const {
317
318 if (verbLevel & Parameters0) {
319 out0 << "Prec. type: " << type_ << /*" Sweeps: " << nSweeps_ << " damping: " << omega_ <<*/ std::endl;
320 }
321
322 if (verbLevel & Debug) {
323 out0 << "IsSetup: " << Teuchos::toString(SmootherPrototype::IsSetup()) << std::endl;
324 }
325}
326
327template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
329 // FIXME: This is a placeholder
330 return Teuchos::OrdinalTraits<size_t>::invalid();
331}
332
333} // namespace MueLu
334
335#endif /* MUELU_BRAESSSARAZINSMOOTHER_DEF_HPP_ */
#define MUELU_DESCRIBE
Helper macro for implementing Describable::describe() for BaseClass objects.
#define MUELU_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
BraessSarazin smoother for 2x2 block matrices.
RCP< Matrix > A01_
Block (0,1) [typically, pressure gradient operator].
RCP< Matrix > A10_
Block (1,0) [typically, divergence operator].
RCP< const ParameterList > GetValidParameterList() const
Input.
RCP< const MapExtractor > domainMapExtractor_
domain map extractor (from A_ generated by AFact)
RCP< Matrix > A11_
Block (1,1) [typically, pressure stabilization term or null block].
std::string description() const
Return a simple one-line description of this object.
void Apply(MultiVector &X, const MultiVector &B, bool InitialGuessIsZero=false) const
Apply the Braess Sarazin smoother.
RCP< Vector > D_
Inverse to approximation to block (0,0). Here, D_ = omega*inv(diag(A(0,0))).
RCP< const MapExtractor > rangeMapExtractor_
range map extractor (from A_ generated by AFact)
void DeclareInput(Level &currentLevel) const
Input.
size_t getNodeSmootherComplexity() const
Get a rough estimate of cost per iteration.
void Setup(Level &currentLevel)
Setup routine.
Teuchos::RCP< SmootherBase > smoo_
Smoother for SchurComplement equation.
RCP< const FactoryManagerBase > FactManager_
Factory manager for creating the Schur Complement.
void print(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
Print the object with some verbosity level to an FancyOStream object.
void AddFactoryManager(RCP< const FactoryManagerBase > FactManager, int pos=0)
Add a factory manager for BraessSarazin internal SchurComplement handling.
virtual std::string description() const
Return a simple one-line description of this object.
Exception indicating invalid cast attempted.
Exception throws to report errors in the internal logical of the program.
void Input(Level &level, const std::string &varName) const
T Get(Level &level, const std::string &varName) const
Timer to be used in factories. Similar to Monitor but with additional timers.
Class that holds all level-specific information.
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput().
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access)....
virtual const Teuchos::ParameterList & GetParameterList() const =0
An exception safe way to call the method 'Level::SetFactoryManager()'.
bool IsSetup() const
Get the state of a smoother prototype.
static Teuchos::RCP< Vector > GetInverse(Teuchos::RCP< const Vector > v, Magnitude tol=Teuchos::ScalarTraits< Scalar >::eps() *100, Scalar valReplacement=Teuchos::ScalarTraits< Scalar >::zero())
static Teuchos::RCP< Vector > GetLumpedMatrixDiagonal(Matrix const &A, const bool doReciprocal=false, Magnitude tol=Teuchos::ScalarTraits< Scalar >::magnitude(Teuchos::ScalarTraits< Scalar >::zero()), Scalar valReplacement=Teuchos::ScalarTraits< Scalar >::zero(), const bool replaceSingleEntryRowWithZero=false, const bool useAverageAbsDiagVal=false)
static RCP< MultiVector > Residual(const Xpetra::Operator< Scalar, DefaultLocalOrdinal, DefaultGlobalOrdinal, DefaultNode > &Op, const MultiVector &X, const MultiVector &RHS)
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.
@ Warnings0
Important warning messages (one line).
@ Debug
Print additional debugging information.
@ Parameters0
Print class parameters.