MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_BlockedGaussSeidelSmoother_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_BLOCKEDGAUSSSEIDELSMOOTHER_DEF_HPP_
48#define MUELU_BLOCKEDGAUSSSEIDELSMOOTHER_DEF_HPP_
49
50#include "Teuchos_ArrayViewDecl.hpp"
51#include "Teuchos_ScalarTraits.hpp"
52
53#include "MueLu_ConfigDefs.hpp"
54
55#include <Xpetra_BlockReorderManager.hpp>
56#include <Xpetra_Matrix.hpp>
57#include <Xpetra_BlockedCrsMatrix.hpp>
58#include <Xpetra_ReorderedBlockedCrsMatrix.hpp>
59#include <Xpetra_ReorderedBlockedMultiVector.hpp>
60#include <Xpetra_MultiVectorFactory.hpp>
61
63#include "MueLu_Level.hpp"
64#include "MueLu_Utilities.hpp"
65#include "MueLu_Monitor.hpp"
66#include "MueLu_HierarchyUtils.hpp"
68
69namespace MueLu {
70
71 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
73 : type_("blocked GaussSeidel"), A_(Teuchos::null)
74 {
75 FactManager_.reserve(10); // TODO fix me!
76 }
77
78 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
80
81 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
83 RCP<ParameterList> validParamList = rcp(new ParameterList());
84
85 validParamList->set< RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A");
86 validParamList->set< Scalar > ("Damping factor", 1.0, "Damping/Scaling factor in BGS");
87 validParamList->set< LocalOrdinal > ("Sweeps", 1, "Number of BGS sweeps (default = 1)");
88
89 return validParamList;
90 }
91
92 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
94 TEUCHOS_TEST_FOR_EXCEPTION(pos < 0, Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::AddFactoryManager: parameter \'pos\' must not be negative! error.");
95
96 size_t myPos = Teuchos::as<size_t>(pos);
97
98 if (myPos < FactManager_.size()) {
99 // replace existing entries in FactManager_ vector
100 FactManager_.at(myPos) = FactManager;
101 } else if(myPos == FactManager_.size()) {
102 // append new Factory manager at the end of the vector
103 FactManager_.push_back(FactManager);
104 } else { // if(myPos > FactManager_.size())
105 RCP<Teuchos::FancyOStream> out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
106 *out << "Warning: cannot add new FactoryManager at proper position " << pos << ". The FactoryManager is just appended to the end. Check this!" << std::endl;
107
108 // add new Factory manager in the end of the vector
109 FactManager_.push_back(FactManager);
110 }
111 }
112
113 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
115 //this->Input(currentLevel, "A");
116 // TODO: check me: why is this->Input not freeing properly A in release mode?
117 currentLevel.DeclareInput("A",this->GetFactory("A").get());
118
119 // loop over all factory managers for the subblocks of blocked operator A
120 std::vector<Teuchos::RCP<const FactoryManagerBase> >::const_iterator it;
121 for(it = FactManager_.begin(); it!=FactManager_.end(); ++it) {
122 SetFactoryManager currentSFM (rcpFromRef(currentLevel), *it);
123
124 // request "Smoother" for current subblock row.
125 currentLevel.DeclareInput("PreSmoother",(*it)->GetFactory("Smoother").get());
126
127 // request "A" for current subblock row (only needed for Thyra mode)
128 currentLevel.DeclareInput("A",(*it)->GetFactory("A").get());
129 }
130 }
131
132 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
134
135 RCP<Teuchos::FancyOStream> out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
136
137 FactoryMonitor m(*this, "Setup blocked Gauss-Seidel Smoother", currentLevel);
138 if (SmootherPrototype::IsSetup() == true) this->GetOStream(Warnings0) << "MueLu::BlockedGaussSeidelSmoother::Setup(): Setup() has already been called";
139
140 // extract blocked operator A from current level
141 A_ = Factory::Get< RCP<Matrix> >(currentLevel, "A"); // A needed for extracting map extractors
142 RCP<BlockedCrsMatrix> bA = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A_);
143 TEUCHOS_TEST_FOR_EXCEPTION(bA==Teuchos::null, Exceptions::BadCast, "MueLu::BlockedPFactory::Build: input matrix A is not of type BlockedCrsMatrix! error.");
144
145 // plausibility check
146 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.");
147 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.");
148
149 // store map extractors
150 rangeMapExtractor_ = bA->getRangeMapExtractor();
151 domainMapExtractor_ = bA->getDomainMapExtractor();
152
153 // loop over all factory managers for the subblocks of blocked operator A
154 std::vector<Teuchos::RCP<const FactoryManagerBase> >::const_iterator it;
155 for(it = FactManager_.begin(); it!=FactManager_.end(); ++it) {
156 SetFactoryManager currentSFM (rcpFromRef(currentLevel), *it);
157
158 // extract Smoother for current block row (BGS ordering)
159 RCP<const SmootherBase> Smoo = currentLevel.Get< RCP<SmootherBase> >("PreSmoother",(*it)->GetFactory("Smoother").get());
160 Inverse_.push_back(Smoo);
161
162 // store whether subblock matrix is blocked or not!
163 RCP<Matrix> Aii = currentLevel.Get< RCP<Matrix> >("A",(*it)->GetFactory("A").get());
164 bIsBlockedOperator_.push_back(Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(Aii)!=Teuchos::null);
165 }
166
168 }
169
170 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
171 void BlockedGaussSeidelSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Apply(MultiVector &X, const MultiVector& B, bool InitialGuessIsZero) const
172 {
173 TEUCHOS_TEST_FOR_EXCEPTION(SmootherPrototype::IsSetup() == false, Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::Apply(): Setup() has not been called");
174
175#if 0 // def HAVE_MUELU_DEBUG
176 // TODO simplify this debug check
177 RCP<MultiVector> rcpDebugX = Teuchos::rcpFromRef(X);
178 RCP<const MultiVector> rcpDebugB = Teuchos::rcpFromRef(B);
179 RCP<BlockedMultiVector> rcpBDebugX = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(rcpDebugX);
180 RCP<const BlockedMultiVector> rcpBDebugB = Teuchos::rcp_dynamic_cast<const BlockedMultiVector>(rcpDebugB);
181 //RCP<BlockedCrsMatrix> bA = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A_);
182 if(rcpBDebugB.is_null() == false) {
183 //this->GetOStream(Runtime1) << "BlockedGaussSeidel: B is a BlockedMultiVector of size " << B.getMap()->getGlobalNumElements() << " with " << rcpBDebugB->getBlockedMap()->getNumMaps() << " blocks." << std::endl;
184 //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.");
185 } else {
186 //this->GetOStream(Runtime1) << "BlockedGaussSeidel: B is a MultiVector of size " << B.getMap()->getGlobalNumElements() << std::endl;
187 //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.");
188 }
189 if(rcpBDebugX.is_null() == false) {
190 //this->GetOStream(Runtime1) << "BlockedGaussSeidel: X is a BlockedMultiVector of size " << X.getMap()->getGlobalNumElements() << " with " << rcpBDebugX->getBlockedMap()->getNumMaps() << " blocks." << std::endl;
191 //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.");
192 } else {
193 //this->GetOStream(Runtime1) << "BlockedGaussSeidel: X is a MultiVector of size " << X.getMap()->getGlobalNumElements() << std::endl;
194 //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.");
195 }
196#endif
197 SC zero = Teuchos::ScalarTraits<SC>::zero(), one = Teuchos::ScalarTraits<SC>::one();
198
199 // Input variables used for the rest of the algorithm
200 RCP<MultiVector> rcpX = Teuchos::rcpFromRef(X);
201 RCP<const MultiVector> rcpB = Teuchos::rcpFromRef(B);
202
203 // make sure that both rcpX and rcpB are BlockedMultiVector objects
204 bool bCopyResultX = false;
205 RCP<BlockedCrsMatrix> bA = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A_);
206 MUELU_TEST_FOR_EXCEPTION(bA.is_null() == true, Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::Apply(): A_ must be a BlockedCrsMatrix");
207 RCP<BlockedMultiVector> bX = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(rcpX);
208 RCP<const BlockedMultiVector> bB = Teuchos::rcp_dynamic_cast<const BlockedMultiVector>(rcpB);
209
210 if(bX.is_null() == true) {
211 RCP<MultiVector> test = Teuchos::rcp(new BlockedMultiVector(bA->getBlockedDomainMap(),rcpX));
212 rcpX.swap(test);
213 bCopyResultX = true;
214 }
215
216 if(bB.is_null() == true) {
217 RCP<const MultiVector> test = Teuchos::rcp(new BlockedMultiVector(bA->getBlockedRangeMap(),rcpB));
218 rcpB.swap(test);
219 }
220
221 // we now can guarantee that X and B are blocked multi vectors
222 bX = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(rcpX);
223 bB = Teuchos::rcp_dynamic_cast<const BlockedMultiVector>(rcpB);
224
225 // check the type of operator
226 RCP<Xpetra::ReorderedBlockedCrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> > rbA = Teuchos::rcp_dynamic_cast<Xpetra::ReorderedBlockedCrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >(bA);
227 if(rbA.is_null() == false) {
228 // A is a ReorderedBlockedCrsMatrix
229 Teuchos::RCP<const Xpetra::BlockReorderManager > brm = rbA->getBlockReorderManager();
230
231 // check type of X vector
232 if(bX->getBlockedMap()->getNumMaps() != bA->getDomainMapExtractor()->NumMaps()) {
233 // X is a blocked multi vector but incompatible to the reordered blocked operator A
234 Teuchos::RCP<MultiVector> test =
235 buildReorderedBlockedMultiVector(brm, bX);
236 rcpX.swap(test);
237 }
238 if(bB->getBlockedMap()->getNumMaps() != bA->getRangeMapExtractor()->NumMaps()) {
239 // B is a blocked multi vector but incompatible to the reordered blocked operator A
240 Teuchos::RCP<const MultiVector> test =
241 buildReorderedBlockedMultiVector(brm, bB);
242 rcpB.swap(test);
243 }
244 }
245
246
247 // check the type of operator
248 /*RCP<BlockedCrsMatrix> bA = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A_);
249 MUELU_TEST_FOR_EXCEPTION(bA.is_null() == true, Exceptions::RuntimeError, "MueLu::BlockedGaussSeidelSmoother::Apply(): A_ must be a BlockedCrsMatrix");
250 RCP<Xpetra::ReorderedBlockedCrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> > rbA = Teuchos::rcp_dynamic_cast<Xpetra::ReorderedBlockedCrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >(bA);
251 if(rbA.is_null() == false) {
252 // A is a ReorderedBlockedCrsMatrix
253 Teuchos::RCP<const Xpetra::BlockReorderManager > brm = rbA->getBlockReorderManager();
254
255 // check type of vectors
256 RCP<BlockedMultiVector> bX = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(rcpX);
257 RCP<const BlockedMultiVector> bB = Teuchos::rcp_dynamic_cast<const BlockedMultiVector>(rcpB);
258
259 // check type of X vector
260 if(bX.is_null() == false && bX->getBlockedMap()->getNumMaps() != bA->getDomainMapExtractor()->NumMaps()) {
261 RCP<ReorderedBlockedMultiVector> rbX = Teuchos::rcp_dynamic_cast<ReorderedBlockedMultiVector>(bX);
262 if(rbX.is_null() == true) {
263 // X is a blocked multi vector but not reordered
264 // However, A is a reordered blocked operator
265 // We have to make sure, that A and X use compatible maps
266 Teuchos::RCP<MultiVector> test =
267 buildReorderedBlockedMultiVector(brm, bX);
268 rcpX.swap(test);
269 }
270 }
271 if(bB.is_null() == false && bB->getBlockedMap()->getNumMaps() != bA->getRangeMapExtractor()->NumMaps()) {
272 RCP<const ReorderedBlockedMultiVector> rbB = Teuchos::rcp_dynamic_cast<const ReorderedBlockedMultiVector>(bB);
273 if(rbB.is_null() == true) {
274 // B is a blocked multi vector but not reordered
275 // However, A is a reordered blocked operator
276 // We have to make sure, that A and X use compatible maps
277 Teuchos::RCP<const MultiVector> test =
278 buildReorderedBlockedMultiVector(brm, bB);
279 rcpB.swap(test);
280 }
281 }
282 }*/
283
284 // Throughout the rest of the algorithm rcpX and rcpB are used for solution vector and RHS
285
286 RCP<MultiVector> residual = MultiVectorFactory::Build(rcpB->getMap(), rcpB->getNumVectors());
287 RCP<MultiVector> tempres = MultiVectorFactory::Build(rcpB->getMap(), rcpB->getNumVectors());
288
289 // extract parameters from internal parameter list
290 const ParameterList & pL = Factory::GetParameterList();
291 LocalOrdinal nSweeps = pL.get<LocalOrdinal>("Sweeps");
292 Scalar omega = pL.get<Scalar>("Damping factor");
293
294
295 // Clear solution from previos V cycles in case it is still stored
296 if( InitialGuessIsZero==true )
297 rcpX->putScalar(Teuchos::ScalarTraits<Scalar>::zero());
298
299
300 // outer Richardson loop
301 for (LocalOrdinal run = 0; run < nSweeps; ++run) {
302 // one BGS sweep
303 // loop over all block rows
304 for(size_t i = 0; i<Inverse_.size(); i++) {
305
306 // calculate block residual r = B-A*X
307 // note: A_ is the full blocked operator
308 residual->update(1.0,*rcpB,0.0); // r = B
309 if(InitialGuessIsZero == false || i > 0 || run > 0)
310 bA->bgs_apply(*rcpX, *residual, i, Teuchos::NO_TRANS, -1.0, 1.0);
311
312 // extract corresponding subvectors from X and residual
313 bool bRangeThyraMode = rangeMapExtractor_->getThyraMode();
314 bool bDomainThyraMode = domainMapExtractor_->getThyraMode();
315 Teuchos::RCP<MultiVector> Xi = domainMapExtractor_->ExtractVector(rcpX, i, bDomainThyraMode);
316 Teuchos::RCP<MultiVector> ri = rangeMapExtractor_->ExtractVector(residual, i, bRangeThyraMode);
317 Teuchos::RCP<MultiVector> tXi = domainMapExtractor_->getVector(i, X.getNumVectors(), bDomainThyraMode);
318
319 // apply solver/smoother
320 Inverse_.at(i)->Apply(*tXi, *ri, false);
321
322 // update vector
323 Xi->update(omega,*tXi,1.0); // X_{i+1} = X_i + omega \Delta X_i
324
325 }
326 }
327
328 if (bCopyResultX == true) {
329 RCP<MultiVector> Xmerged = bX->Merge();
330 X.update(one, *Xmerged, zero);
331 }
332 }
333
334 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
335 RCP<MueLu::SmootherPrototype<Scalar, LocalOrdinal, GlobalOrdinal, Node> > BlockedGaussSeidelSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Copy() const {
336 return rcp( new BlockedGaussSeidelSmoother(*this) );
337 }
338
339 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
341 std::ostringstream out;
343 out << "{type = " << type_ << "}";
344 return out.str();
345 }
346
347 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
348 void BlockedGaussSeidelSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::print(Teuchos::FancyOStream &out, const VerbLevel verbLevel) const {
350
351 // extract parameters from internal parameter list
352 const ParameterList & pL = Factory::GetParameterList();
353 LocalOrdinal nSweeps = pL.get<LocalOrdinal>("Sweeps");
354 Scalar omega = pL.get<Scalar>("Damping factor");
355
356 if (verbLevel & Parameters0) {
357 out0 << "Prec. type: " << type_ << " Sweeps: " << nSweeps << " damping: " << omega << std::endl;
358 }
359
360 if (verbLevel & Debug) {
361 out0 << "IsSetup: " << Teuchos::toString(SmootherPrototype::IsSetup()) << std::endl;
362 }
363 }
364 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
366 // FIXME: This is a placeholder
367 return Teuchos::OrdinalTraits<size_t>::invalid();
368 }
369
370} // namespace MueLu
371
372#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.