MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_BraessSarazinSmoother_def.hpp
Go to the documentation of this file.
1// @HEADER
2//
3// ***********************************************************************
4//
5// MueLu: A package for multigrid based preconditioning
6// Copyright 2012 Sandia Corporation
7//
8// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9// the U.S. Government retains certain rights in this software.
10//
11// Redistribution and use in source and binary forms, with or without
12// modification, are permitted provided that the following conditions are
13// met:
14//
15// 1. Redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer.
17//
18// 2. Redistributions in binary form must reproduce the above copyright
19// notice, this list of conditions and the following disclaimer in the
20// documentation and/or other materials provided with the distribution.
21//
22// 3. Neither the name of the Corporation nor the names of the
23// contributors may be used to endorse or promote products derived from
24// this software without specific prior written permission.
25//
26// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37//
38// Questions? Contact
39// Jonathan Hu (jhu@sandia.gov)
40// Andrey Prokopenko (aprokop@sandia.gov)
41// Ray Tuminaro (rstumin@sandia.gov)
42//
43// ***********************************************************************
44//
45// @HEADER
46
47#ifndef MUELU_BRAESSSARAZINSMOOTHER_DEF_HPP_
48#define MUELU_BRAESSSARAZINSMOOTHER_DEF_HPP_
49
50#include <Teuchos_ArrayViewDecl.hpp>
51#include <Teuchos_ScalarTraits.hpp>
52
53#include "MueLu_ConfigDefs.hpp"
54
55#include <Xpetra_Matrix.hpp>
56#include <Xpetra_BlockedCrsMatrix.hpp>
57#include <Xpetra_MultiVectorFactory.hpp>
58#include <Xpetra_VectorFactory.hpp>
59#include <Xpetra_ReorderedBlockedCrsMatrix.hpp>
60
62#include "MueLu_Level.hpp"
63#include "MueLu_Utilities.hpp"
64#include "MueLu_Monitor.hpp"
65#include "MueLu_HierarchyUtils.hpp"
67
68#include "MueLu_FactoryManager.hpp"
69
70namespace MueLu {
71
72 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
73 void BraessSarazinSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::AddFactoryManager(RCP<const FactoryManagerBase> FactManager, int pos) {
74 TEUCHOS_TEST_FOR_EXCEPTION(pos != 0, Exceptions::RuntimeError, "MueLu::BraessSarazinSmoother::AddFactoryManager: parameter \'pos\' must be zero! error.");
75 FactManager_ = FactManager;
76 }
77
78 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
80 RCP<ParameterList> validParamList = rcp(new ParameterList());
81
82 SC one = Teuchos::ScalarTraits<SC>::one();
83
84 validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A");
85
86 validParamList->set<bool>("lumping", false, "Use lumping to construct diag(A(0,0)), "
87 "i.e. use row sum of the abs values on the diagonal as approximation of A00 (and A00^{-1})");
88 validParamList->set<SC>("Damping factor", one, "Damping/Scaling factor in BraessSarazin (usually has to be chosen > 1, default = 1.0)");
89 validParamList->set<LO>("Sweeps", 1, "Number of BraessSarazin sweeps (default = 1)");
90 validParamList->set<bool>("q2q1 mode", false, "Run in the mode matching Q2Q1 matlab code");
91
92 return validParamList;
93 }
94
95 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
97 this->Input(currentLevel, "A");
98
99 TEUCHOS_TEST_FOR_EXCEPTION(FactManager_.is_null(), Exceptions::RuntimeError,
100 "MueLu::BraessSarazinSmoother::DeclareInput: FactManager_ must not be null! "
101 "Introduce a FactoryManager for the SchurComplement equation.");
102
103 // carefully call DeclareInput after switching to internal FactoryManager
104 {
105 SetFactoryManager currentSFM(rcpFromRef(currentLevel), FactManager_);
106
107 // request "Smoother" for current subblock row.
108 currentLevel.DeclareInput("PreSmoother", FactManager_->GetFactory("Smoother").get());
109
110 // request Schur matrix just in case
111 currentLevel.DeclareInput("A", FactManager_->GetFactory("A").get());
112 }
113 }
114
115 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
117 FactoryMonitor m(*this, "Setup Smoother", currentLevel);
118
119 if (SmootherPrototype::IsSetup() == true)
120 this->GetOStream(Warnings0) << "MueLu::BreaessSarazinSmoother::Setup(): Setup() has already been called";
121
122 // Extract blocked operator A from current level
123 A_ = Factory::Get<RCP<Matrix> > (currentLevel, "A");
124 RCP<BlockedCrsMatrix> bA = rcp_dynamic_cast<BlockedCrsMatrix>(A_);
125 TEUCHOS_TEST_FOR_EXCEPTION(bA.is_null(), Exceptions::BadCast,
126 "MueLu::BraessSarazinSmoother::Setup: input matrix A is not of type BlockedCrsMatrix! error.");
127
128 // Store map extractors
129 rangeMapExtractor_ = bA->getRangeMapExtractor();
130 domainMapExtractor_ = bA->getDomainMapExtractor();
131
132 // Store the blocks in local member variables
133 A00_ = bA->getMatrix(0,0);
134 A01_ = bA->getMatrix(0,1);
135 A10_ = bA->getMatrix(1,0);
136 A11_ = bA->getMatrix(1,1);
137
138 const ParameterList& pL = Factory::GetParameterList();
139 SC omega = pL.get<SC>("Damping factor");
140
141 // Create the inverse of the diagonal of F
142 // TODO add safety check for zeros on diagonal of F!
143 RCP<Vector> diagFVector = VectorFactory::Build(A00_->getRowMap());
144 if (pL.get<bool>("lumping") == false) {
145 A00_->getLocalDiagCopy(*diagFVector); // extract diagonal of F
146 } else {
148 }
149 diagFVector->scale(omega);
150 D_ = Utilities::GetInverse(diagFVector);
151
152 // check whether D_ is a blocked vector with only 1 block
153 RCP<BlockedVector> bD = Teuchos::rcp_dynamic_cast<BlockedVector>(D_);
154 if(bD.is_null() == false && bD->getBlockedMap()->getNumMaps() == 1) {
155 RCP<Vector> nestedVec = bD->getMultiVector(0,bD->getBlockedMap()->getThyraMode())->getVectorNonConst(0);
156 D_.swap(nestedVec);
157 }
158
159 // Set the Smoother
160 // carefully switch to the SubFactoryManagers (defined by the users)
161 {
162 SetFactoryManager currentSFM(rcpFromRef(currentLevel), FactManager_);
163 smoo_ = currentLevel.Get<RCP<SmootherBase> >("PreSmoother", FactManager_->GetFactory("Smoother").get());
164 S_ = currentLevel.Get<RCP<Matrix> > ("A", FactManager_->GetFactory("A").get());
165 }
166
168 }
169
170 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
171 void BraessSarazinSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Apply(MultiVector& X, const MultiVector& B, bool InitialGuessIsZero) const {
172 TEUCHOS_TEST_FOR_EXCEPTION(SmootherPrototype::IsSetup() == false, Exceptions::RuntimeError,
173 "MueLu::BraessSarazinSmoother::Apply(): Setup() has not been called");
174
175 RCP<MultiVector> rcpX = rcpFromRef(X);
176 RCP<const MultiVector> rcpB = rcpFromRef(B);
177
178 // make sure that both rcpX and rcpB are BlockedMultiVector objects
179 bool bCopyResultX = false;
180 bool bReorderX = false;
181 bool bReorderB = false;
182 RCP<BlockedCrsMatrix> bA = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A_);
183 MUELU_TEST_FOR_EXCEPTION(bA.is_null() == true, Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::Apply(): A_ must be a BlockedCrsMatrix");
184 RCP<BlockedMultiVector> bX = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(rcpX);
185 RCP<const BlockedMultiVector> bB = Teuchos::rcp_dynamic_cast<const BlockedMultiVector>(rcpB);
186
187 // check the type of operator
188 RCP<Xpetra::ReorderedBlockedCrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> > rbA =
189 Teuchos::rcp_dynamic_cast<Xpetra::ReorderedBlockedCrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >(bA);
190
191 if(rbA.is_null() == false) {
192 // A is a ReorderedBlockedCrsMatrix and thus uses nested maps, retrieve BlockedCrsMatrix and use plain blocked
193 // map for the construction of the blocked multivectors
194
195 // check type of X vector
196 if (bX.is_null() == true) {
197 RCP<MultiVector> vectorWithBlockedMap = Teuchos::rcp(new BlockedMultiVector(rbA->getBlockedCrsMatrix()->getBlockedDomainMap(), rcpX));
198 rcpX.swap(vectorWithBlockedMap);
199 bCopyResultX = true;
200 bReorderX = true;
201 }
202
203 // check type of B vector
204 if (bB.is_null() == true) {
205 RCP<const MultiVector> vectorWithBlockedMap = Teuchos::rcp(new BlockedMultiVector(rbA->getBlockedCrsMatrix()->getBlockedRangeMap(), rcpB));
206 rcpB.swap(vectorWithBlockedMap);
207 bReorderB = true;
208 }
209 }
210 else {
211 // A is a BlockedCrsMatrix and uses a plain blocked map
212 if (bX.is_null() == true) {
213 RCP<MultiVector> vectorWithBlockedMap = Teuchos::rcp(new BlockedMultiVector(bA->getBlockedDomainMap(), rcpX));
214 rcpX.swap(vectorWithBlockedMap);
215 bCopyResultX = true;
216 }
217
218 if(bB.is_null() == true) {
219 RCP<const MultiVector> vectorWithBlockedMap = Teuchos::rcp(new BlockedMultiVector(bA->getBlockedRangeMap(),rcpB));
220 rcpB.swap(vectorWithBlockedMap);
221 }
222 }
223
224 // we now can guarantee that X and B are blocked multi vectors
225 bX = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(rcpX);
226 bB = Teuchos::rcp_dynamic_cast<const BlockedMultiVector>(rcpB);
227
228 // Finally we can do a reordering of the blocked multivectors if A is a ReorderedBlockedCrsMatrix
229 if(rbA.is_null() == false) {
230
231 Teuchos::RCP<const Xpetra::BlockReorderManager > brm = rbA->getBlockReorderManager();
232
233 // check type of X vector
234 if(bX->getBlockedMap()->getNumMaps() != bA->getDomainMapExtractor()->NumMaps() || bReorderX) {
235 // X is a blocked multi vector but incompatible to the reordered blocked operator A
236 Teuchos::RCP<MultiVector> reorderedBlockedVector = buildReorderedBlockedMultiVector(brm, bX);
237 rcpX.swap(reorderedBlockedVector);
238 }
239
240 if(bB->getBlockedMap()->getNumMaps() != bA->getRangeMapExtractor()->NumMaps() || bReorderB) {
241 // B is a blocked multi vector but incompatible to the reordered blocked operator A
242 Teuchos::RCP<const MultiVector> reorderedBlockedVector = buildReorderedBlockedMultiVector(brm, bB);
243 rcpB.swap(reorderedBlockedVector);
244 }
245 }
246
247 // use the GIDs of the sub blocks
248 // This is valid as the subblocks actually represent the GIDs (either Thyra, Xpetra or pseudo Xpetra)
249
250 bool bRangeThyraMode = rangeMapExtractor_->getThyraMode();
251 bool bDomainThyraMode = domainMapExtractor_->getThyraMode();
252
253 RCP<MultiVector> deltaX = MultiVectorFactory::Build(rcpX->getMap(), rcpX->getNumVectors());
254 RCP<BlockedMultiVector> bdeltaX = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(deltaX);
255 RCP<MultiVector> deltaX0 = bdeltaX->getMultiVector(0,bDomainThyraMode);
256 RCP<MultiVector> deltaX1 = bdeltaX->getMultiVector(1,bDomainThyraMode);
257
258 RCP<MultiVector> Rtmp = rangeMapExtractor_->getVector(1, rcpB->getNumVectors(), bRangeThyraMode);
259
260
261 typedef Teuchos::ScalarTraits<SC> STS;
262 SC one = STS::one(), zero = STS::zero();
263
264 // extract parameters from internal parameter list
265 const ParameterList& pL = Factory::GetParameterList();
266 LO nSweeps = pL.get<LO>("Sweeps");
267
268 RCP<MultiVector> R;// = MultiVectorFactory::Build(rcpB->getMap(), rcpB->getNumVectors());;
269 if (InitialGuessIsZero) {
270 R = MultiVectorFactory::Build(rcpB->getMap(), rcpB->getNumVectors());
271 R->update(one, *rcpB, zero);
272 } else {
273 R = Utilities::Residual(*A_, *rcpX, *rcpB);
274 }
275
276 // extract diagonal of Schur complement operator
277 RCP<Vector> diagSVector = VectorFactory::Build(S_->getRowMap());
278 S_->getLocalDiagCopy(*diagSVector);
279
280 for (LO run = 0; run < nSweeps; ++run) {
281 // Extract corresponding subvectors from X and R
282 // Automatically detect whether we use Thyra or Xpetra GIDs
283 // The GIDs should be always compatible with the GIDs of A00, A01, etc...
284 RCP<MultiVector> R0 = rangeMapExtractor_ ->ExtractVector(R, 0, bRangeThyraMode);
285 RCP<MultiVector> R1 = rangeMapExtractor_ ->ExtractVector(R, 1, bRangeThyraMode);
286
287 // Calculate Rtmp = R1 - D * deltaX0 (equation 8.14)
288 deltaX0->putScalar(zero);
289 deltaX0->elementWiseMultiply(one, *D_, *R0, zero); // deltaX0 = D * R0 (equation 8.13)
290 A10_->apply(*deltaX0, *Rtmp); // Rtmp = A10*D*deltaX0 (intermediate step)
291 Rtmp->update(one, *R1, -one); // Rtmp = R1 - A10*D*deltaX0
292
293 if (!pL.get<bool>("q2q1 mode")) {
294 deltaX1->putScalar(zero);
295 } else {
296 // special code for q2q1
297 if(Teuchos::rcp_dynamic_cast<BlockedVector>(diagSVector) == Teuchos::null) {
298 ArrayRCP<SC> Sdiag = diagSVector->getDataNonConst(0);
299 ArrayRCP<SC> deltaX1data = deltaX1->getDataNonConst(0);
300 ArrayRCP<SC> Rtmpdata = Rtmp->getDataNonConst(0);
301 for (GO row = 0; row < deltaX1data.size(); row++)
302 deltaX1data[row] = Teuchos::as<SC>(1.1)*Rtmpdata[row] / Sdiag[row];
303 } else {
304 TEUCHOS_TEST_FOR_EXCEPTION(true,MueLu::Exceptions::RuntimeError,"MueLu::BraessSarazinSmoother: q2q1 mode only supported for non-blocked operators.")
305 }
306 }
307
308 smoo_->Apply(*deltaX1,*Rtmp);
309
310 // Compute deltaX0
311 deltaX0->putScalar(zero); // just for safety
312 A01_->apply(*deltaX1, *deltaX0); // deltaX0 = A01*deltaX1
313 deltaX0->update(one, *R0, -one); // deltaX0 = R0 - A01*deltaX1
314 R0.swap(deltaX0);
315 deltaX0->elementWiseMultiply(one, *D_, *R0, zero); // deltaX0 = D*(R0 - A01*deltaX1)
316
317 RCP<MultiVector> X0 = domainMapExtractor_->ExtractVector(rcpX, 0, bDomainThyraMode);
318 RCP<MultiVector> X1 = domainMapExtractor_->ExtractVector(rcpX, 1, bDomainThyraMode);
319
320 // Update solution
321 X0->update(one, *deltaX0, one);
322 X1->update(one, *deltaX1, one);
323
324 domainMapExtractor_->InsertVector(X0, 0, rcpX, bDomainThyraMode);
325 domainMapExtractor_->InsertVector(X1, 1, rcpX, bDomainThyraMode);
326
327 if (run < nSweeps-1) {
328 R = Utilities::Residual(*A_, *rcpX, *rcpB);
329 }
330
331 }
332
333 if (bCopyResultX == true) {
334 RCP<MultiVector> Xmerged = bX->Merge();
335 X.update(one, *Xmerged, zero);
336 }
337
338 }
339
340 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
341 RCP<MueLu::SmootherPrototype<Scalar, LocalOrdinal, GlobalOrdinal, Node> >
345
346 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
348 description () const {
349 std::ostringstream out;
351 out << "{type = " << type_ << "}";
352 return out.str();
353 }
354
355 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
356 void BraessSarazinSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::print(Teuchos::FancyOStream &out, const VerbLevel verbLevel) const {
358
359 if (verbLevel & Parameters0) {
360 out0 << "Prec. type: " << type_ << /*" Sweeps: " << nSweeps_ << " damping: " << omega_ <<*/ std::endl;
361 }
362
363 if (verbLevel & Debug) {
364 out0 << "IsSetup: " << Teuchos::toString(SmootherPrototype::IsSetup()) << std::endl;
365 }
366 }
367
368 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
370 // FIXME: This is a placeholder
371 return Teuchos::OrdinalTraits<size_t>::invalid();
372 }
373
374} // namespace MueLu
375
376#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.
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.
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.