MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_BlockedGaussSeidelSmoother_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_BLOCKEDGAUSSSEIDELSMOOTHER_DEF_HPP_
11#define MUELU_BLOCKEDGAUSSSEIDELSMOOTHER_DEF_HPP_
12
13#include "Teuchos_ArrayViewDecl.hpp"
14#include "Teuchos_ScalarTraits.hpp"
15
16#include "MueLu_ConfigDefs.hpp"
17
18#include <Xpetra_BlockReorderManager.hpp>
19#include <Xpetra_Matrix.hpp>
20#include <Xpetra_BlockedCrsMatrix.hpp>
21#include <Xpetra_ReorderedBlockedCrsMatrix.hpp>
22#include <Xpetra_ReorderedBlockedMultiVector.hpp>
23#include <Xpetra_MultiVectorFactory.hpp>
24
26#include "MueLu_Level.hpp"
27#include "MueLu_Monitor.hpp"
28#include "MueLu_HierarchyUtils.hpp"
30
31namespace MueLu {
32
33template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
35 : type_("blocked GaussSeidel")
36 , A_(Teuchos::null) {
37 FactManager_.reserve(10); // TODO fix me!
38}
39
40template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
42
43template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
45 RCP<ParameterList> validParamList = rcp(new ParameterList());
46
47 validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A");
48 validParamList->set<Scalar>("Damping factor", 1.0, "Damping/Scaling factor in BGS");
49 validParamList->set<LocalOrdinal>("Sweeps", 1, "Number of BGS sweeps (default = 1)");
50
51 return validParamList;
52}
53
54template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
56 TEUCHOS_TEST_FOR_EXCEPTION(pos < 0, Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::AddFactoryManager: parameter \'pos\' must not be negative! error.");
57
58 size_t myPos = Teuchos::as<size_t>(pos);
59
60 if (myPos < FactManager_.size()) {
61 // replace existing entries in FactManager_ vector
62 FactManager_.at(myPos) = FactManager;
63 } else if (myPos == FactManager_.size()) {
64 // append new Factory manager at the end of the vector
65 FactManager_.push_back(FactManager);
66 } else { // if(myPos > FactManager_.size())
67 RCP<Teuchos::FancyOStream> out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
68 *out << "Warning: cannot add new FactoryManager at proper position " << pos << ". The FactoryManager is just appended to the end. Check this!" << std::endl;
69
70 // add new Factory manager in the end of the vector
71 FactManager_.push_back(FactManager);
72 }
73}
74
75template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
77 // this->Input(currentLevel, "A");
78 // TODO: check me: why is this->Input not freeing properly A in release mode?
79 currentLevel.DeclareInput("A", this->GetFactory("A").get());
80
81 // loop over all factory managers for the subblocks of blocked operator A
82 std::vector<Teuchos::RCP<const FactoryManagerBase> >::const_iterator it;
83 for (it = FactManager_.begin(); it != FactManager_.end(); ++it) {
84 SetFactoryManager currentSFM(rcpFromRef(currentLevel), *it);
85
86 // request "Smoother" for current subblock row.
87 currentLevel.DeclareInput("PreSmoother", (*it)->GetFactory("Smoother").get());
88
89 // request "A" for current subblock row (only needed for Thyra mode)
90 currentLevel.DeclareInput("A", (*it)->GetFactory("A").get());
91 }
92}
93
94template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
96 RCP<Teuchos::FancyOStream> out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
97
98 FactoryMonitor m(*this, "Setup blocked Gauss-Seidel Smoother", currentLevel);
99 if (SmootherPrototype::IsSetup() == true) this->GetOStream(Warnings0) << "MueLu::BlockedGaussSeidelSmoother::Setup(): Setup() has already been called";
100
101 // extract blocked operator A from current level
102 A_ = Factory::Get<RCP<Matrix> >(currentLevel, "A"); // A needed for extracting map extractors
103 RCP<BlockedCrsMatrix> bA = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A_);
104 TEUCHOS_TEST_FOR_EXCEPTION(bA == Teuchos::null, Exceptions::BadCast, "MueLu::BlockedPFactory::Build: input matrix A is not of type BlockedCrsMatrix! error.");
105
106 // plausibility check
107 TEUCHOS_TEST_FOR_EXCEPTION(bA->Rows() != FactManager_.size(), Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::Setup: number of block rows of A is " << bA->Rows() << " and does not match number of SubFactoryManagers " << FactManager_.size() << ". error.");
108 TEUCHOS_TEST_FOR_EXCEPTION(bA->Cols() != FactManager_.size(), Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::Setup: number of block cols of A is " << bA->Cols() << " and does not match number of SubFactoryManagers " << FactManager_.size() << ". error.");
109
110 // store map extractors
111 rangeMapExtractor_ = bA->getRangeMapExtractor();
112 domainMapExtractor_ = bA->getDomainMapExtractor();
113
114 // loop over all factory managers for the subblocks of blocked operator A
115 std::vector<Teuchos::RCP<const FactoryManagerBase> >::const_iterator it;
116 for (it = FactManager_.begin(); it != FactManager_.end(); ++it) {
117 SetFactoryManager currentSFM(rcpFromRef(currentLevel), *it);
118
119 // extract Smoother for current block row (BGS ordering)
120 RCP<const SmootherBase> Smoo = currentLevel.Get<RCP<SmootherBase> >("PreSmoother", (*it)->GetFactory("Smoother").get());
121 Inverse_.push_back(Smoo);
122
123 // store whether subblock matrix is blocked or not!
124 RCP<Matrix> Aii = currentLevel.Get<RCP<Matrix> >("A", (*it)->GetFactory("A").get());
125 bIsBlockedOperator_.push_back(Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(Aii) != Teuchos::null);
126 }
127
129}
130
131template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
132void BlockedGaussSeidelSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Apply(MultiVector &X, const MultiVector &B, bool InitialGuessIsZero) const {
133 TEUCHOS_TEST_FOR_EXCEPTION(SmootherPrototype::IsSetup() == false, Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::Apply(): Setup() has not been called");
134
135#if 0 // def HAVE_MUELU_DEBUG
136 // TODO simplify this debug check
137 RCP<MultiVector> rcpDebugX = Teuchos::rcpFromRef(X);
138 RCP<const MultiVector> rcpDebugB = Teuchos::rcpFromRef(B);
139 RCP<BlockedMultiVector> rcpBDebugX = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(rcpDebugX);
140 RCP<const BlockedMultiVector> rcpBDebugB = Teuchos::rcp_dynamic_cast<const BlockedMultiVector>(rcpDebugB);
141 //RCP<BlockedCrsMatrix> bA = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A_);
142 if(rcpBDebugB.is_null() == false) {
143 //this->GetOStream(Runtime1) << "BlockedGaussSeidel: B is a BlockedMultiVector of size " << B.getMap()->getGlobalNumElements() << " with " << rcpBDebugB->getBlockedMap()->getNumMaps() << " blocks." << std::endl;
144 //TEUCHOS_TEST_FOR_EXCEPTION(A_->getRangeMap()->isSameAs(*(B.getMap())) == false, Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::Apply(): The map of RHS vector B is not the same as range map of the blocked operator A. Please check the map of B and A.");
145 } else {
146 //this->GetOStream(Runtime1) << "BlockedGaussSeidel: B is a MultiVector of size " << B.getMap()->getGlobalNumElements() << std::endl;
147 //TEUCHOS_TEST_FOR_EXCEPTION(bA->getFullRangeMap()->isSameAs(*(B.getMap())) == false, Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::Apply(): The map of RHS vector B is not the same as range map of the blocked operator A. Please check the map of B and A.");
148 }
149 if(rcpBDebugX.is_null() == false) {
150 //this->GetOStream(Runtime1) << "BlockedGaussSeidel: X is a BlockedMultiVector of size " << X.getMap()->getGlobalNumElements() << " with " << rcpBDebugX->getBlockedMap()->getNumMaps() << " blocks." << std::endl;
151 //TEUCHOS_TEST_FOR_EXCEPTION(A_->getDomainMap()->isSameAs(*(X.getMap())) == false, Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::Apply(): The map of the solution vector X is not the same as domain map of the blocked operator A. Please check the map of X and A.");
152 } else {
153 //this->GetOStream(Runtime1) << "BlockedGaussSeidel: X is a MultiVector of size " << X.getMap()->getGlobalNumElements() << std::endl;
154 //TEUCHOS_TEST_FOR_EXCEPTION(bA->getFullDomainMap()->isSameAs(*(X.getMap())) == false, Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::Apply(): The map of the solution vector X is not the same as domain map of the blocked operator A. Please check the map of X and A.");
155 }
156#endif
157 SC zero = Teuchos::ScalarTraits<SC>::zero(), one = Teuchos::ScalarTraits<SC>::one();
158
159 // Input variables used for the rest of the algorithm
160 RCP<MultiVector> rcpX = Teuchos::rcpFromRef(X);
161 RCP<const MultiVector> rcpB = Teuchos::rcpFromRef(B);
162
163 // make sure that both rcpX and rcpB are BlockedMultiVector objects
164 bool bCopyResultX = false;
165 bool bReorderX = false;
166 bool bReorderB = false;
167 RCP<BlockedCrsMatrix> bA = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A_);
168 MUELU_TEST_FOR_EXCEPTION(bA.is_null() == true, Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::Apply(): A_ must be a BlockedCrsMatrix");
169 RCP<BlockedMultiVector> bX = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(rcpX);
170 RCP<const BlockedMultiVector> bB = Teuchos::rcp_dynamic_cast<const BlockedMultiVector>(rcpB);
171
172 // check the type of operator
173 RCP<Xpetra::ReorderedBlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> > rbA =
174 Teuchos::rcp_dynamic_cast<Xpetra::ReorderedBlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> >(bA);
175
176 if (rbA.is_null() == false) {
177 // A is a ReorderedBlockedCrsMatrix and thus uses nested maps, retrieve BlockedCrsMatrix and use plain blocked
178 // map for the construction of the blocked multivectors
179
180 // check type of X vector
181 if (bX.is_null() == true) {
182 RCP<MultiVector> vectorWithBlockedMap = Teuchos::rcp(new BlockedMultiVector(rbA->getBlockedCrsMatrix()->getBlockedDomainMap(), rcpX));
183 rcpX.swap(vectorWithBlockedMap);
184 bCopyResultX = true;
185 bReorderX = true;
186 }
187
188 // check type of B vector
189 if (bB.is_null() == true) {
190 RCP<const MultiVector> vectorWithBlockedMap = Teuchos::rcp(new BlockedMultiVector(rbA->getBlockedCrsMatrix()->getBlockedRangeMap(), rcpB));
191 rcpB.swap(vectorWithBlockedMap);
192 bReorderB = true;
193 }
194 } else {
195 // A is a BlockedCrsMatrix and uses a plain blocked map
196 if (bX.is_null() == true) {
197 RCP<MultiVector> vectorWithBlockedMap = Teuchos::rcp(new BlockedMultiVector(bA->getBlockedDomainMap(), rcpX));
198 rcpX.swap(vectorWithBlockedMap);
199 bCopyResultX = true;
200 }
201
202 if (bB.is_null() == true) {
203 RCP<const MultiVector> vectorWithBlockedMap = Teuchos::rcp(new BlockedMultiVector(bA->getBlockedRangeMap(), rcpB));
204 rcpB.swap(vectorWithBlockedMap);
205 }
206 }
207
208 // we now can guarantee that X and B are blocked multi vectors
209 bX = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(rcpX);
210 bB = Teuchos::rcp_dynamic_cast<const BlockedMultiVector>(rcpB);
211
212 // Finally we can do a reordering of the blocked multivectors if A is a ReorderedBlockedCrsMatrix
213 if (rbA.is_null() == false) {
214 Teuchos::RCP<const Xpetra::BlockReorderManager> brm = rbA->getBlockReorderManager();
215
216 // check type of X vector
217 if (bX->getBlockedMap()->getNumMaps() != bA->getDomainMapExtractor()->NumMaps() || bReorderX) {
218 // X is a blocked multi vector but incompatible to the reordered blocked operator A
219 Teuchos::RCP<MultiVector> reorderedBlockedVector = buildReorderedBlockedMultiVector(brm, bX);
220 rcpX.swap(reorderedBlockedVector);
221 }
222
223 if (bB->getBlockedMap()->getNumMaps() != bA->getRangeMapExtractor()->NumMaps() || bReorderB) {
224 // B is a blocked multi vector but incompatible to the reordered blocked operator A
225 Teuchos::RCP<const MultiVector> reorderedBlockedVector = buildReorderedBlockedMultiVector(brm, bB);
226 rcpB.swap(reorderedBlockedVector);
227 }
228 }
229
230 // Throughout the rest of the algorithm rcpX and rcpB are used for solution vector and RHS
231
232 RCP<MultiVector> residual = MultiVectorFactory::Build(rcpB->getMap(), rcpB->getNumVectors());
233 RCP<MultiVector> tempres = MultiVectorFactory::Build(rcpB->getMap(), rcpB->getNumVectors());
234
235 // extract parameters from internal parameter list
236 const ParameterList &pL = Factory::GetParameterList();
237 LocalOrdinal nSweeps = pL.get<LocalOrdinal>("Sweeps");
238 Scalar omega = pL.get<Scalar>("Damping factor");
239
240 // Clear solution from previos V cycles in case it is still stored
241 if (InitialGuessIsZero == true)
242 rcpX->putScalar(Teuchos::ScalarTraits<Scalar>::zero());
243
244 // outer Richardson loop
245 for (LocalOrdinal run = 0; run < nSweeps; ++run) {
246 // one BGS sweep
247 // loop over all block rows
248 for (size_t i = 0; i < Inverse_.size(); i++) {
249 // calculate block residual r = B-A*X
250 // note: A_ is the full blocked operator
251 residual->update(1.0, *rcpB, 0.0); // r = B
252 if (InitialGuessIsZero == false || i > 0 || run > 0)
253 bA->bgs_apply(*rcpX, *residual, i, Teuchos::NO_TRANS, -1.0, 1.0);
254
255 // extract corresponding subvectors from X and residual
256 bool bRangeThyraMode = rangeMapExtractor_->getThyraMode();
257 bool bDomainThyraMode = domainMapExtractor_->getThyraMode();
258 Teuchos::RCP<MultiVector> Xi = domainMapExtractor_->ExtractVector(rcpX, i, bDomainThyraMode);
259 Teuchos::RCP<MultiVector> ri = rangeMapExtractor_->ExtractVector(residual, i, bRangeThyraMode);
260 Teuchos::RCP<MultiVector> tXi = domainMapExtractor_->getVector(i, X.getNumVectors(), bDomainThyraMode);
261
262 // apply solver/smoother
263 Inverse_.at(i)->Apply(*tXi, *ri, false);
264
265 // update vector
266 Xi->update(omega, *tXi, 1.0); // X_{i+1} = X_i + omega \Delta X_i
267 }
268 }
269
270 if (bCopyResultX == true) {
271 RCP<MultiVector> Xmerged = bX->Merge();
272 X.update(one, *Xmerged, zero);
273 }
274}
275
276template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
277RCP<MueLu::SmootherPrototype<Scalar, LocalOrdinal, GlobalOrdinal, Node> > BlockedGaussSeidelSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Copy() const {
278 return rcp(new BlockedGaussSeidelSmoother(*this));
279}
280
281template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
283 std::ostringstream out;
285 out << "{type = " << type_ << "}";
286 return out.str();
287}
288
289template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
292
293 // extract parameters from internal parameter list
294 const ParameterList &pL = Factory::GetParameterList();
295 LocalOrdinal nSweeps = pL.get<LocalOrdinal>("Sweeps");
296 Scalar omega = pL.get<Scalar>("Damping factor");
297
298 if (verbLevel & Parameters0) {
299 out0 << "Prec. type: " << type_ << " Sweeps: " << nSweeps << " damping: " << omega << std::endl;
300 }
301
302 if (verbLevel & Debug) {
303 out0 << "IsSetup: " << Teuchos::toString(SmootherPrototype::IsSetup()) << std::endl;
304 }
305}
306template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
308 // FIXME: This is a placeholder
309 return Teuchos::OrdinalTraits<size_t>::invalid();
310}
311
312} // namespace MueLu
313
314#endif /* MUELU_BLOCKEDGAUSSSEIDELSMOOTHER_DEF_HPP_ */
#define MUELU_DESCRIBE
Helper macro for implementing Describable::describe() for BaseClass objects.
#define MUELU_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
MueLu::DefaultLocalOrdinal LocalOrdinal
MueLu::DefaultScalar Scalar
block Gauss-Seidel method for blocked matrices
void DeclareInput(Level &currentLevel) const
Input.
std::vector< Teuchos::RCP< const FactoryManagerBase > > FactManager_
vector of factory managers
std::string description() const
Return a simple one-line description of this object.
size_t getNodeSmootherComplexity() const
Get a rough estimate of cost per iteration.
void AddFactoryManager(RCP< const FactoryManagerBase > FactManager, int pos)
Add a factory manager.
RCP< const ParameterList > GetValidParameterList() const
Input.
void Apply(MultiVector &X, const MultiVector &B, bool InitialGuessIsZero=false) const
Apply the direct solver. Solves the linear system AX=B using the constructed solver.
void print(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
Print the object with some verbosity level verbLevel to an FancyOStream object out.
void Setup(Level &currentLevel)
Setup routine In the Setup method the Inverse_ vector is filled with the corresponding SmootherBase o...
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.
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.
Namespace for MueLu classes and methods.
@ Warnings0
Important warning messages (one line)
@ Debug
Print additional debugging information.
@ Parameters0
Print class parameters.