MueLu  Version of the Day
MueLu_IfpackSmoother.cpp
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 #include "MueLu_ConfigDefs.hpp"
47 
48 #if defined(HAVE_MUELU_EPETRA) && defined(HAVE_MUELU_IFPACK)
49 #include <Ifpack.h>
50 #include <Ifpack_Chebyshev.h>
51 #include "Xpetra_MultiVectorFactory.hpp"
52 
53 #include "MueLu_IfpackSmoother.hpp"
54 
55 #include "MueLu_Level.hpp"
56 #include "MueLu_Utilities.hpp"
57 #include "MueLu_Monitor.hpp"
58 #include "MueLu_Aggregates.hpp"
59 
60 
61 namespace MueLu {
62 
63  template <class Node>
64  IfpackSmoother<Node>::IfpackSmoother(std::string const & type, Teuchos::ParameterList const & paramList, LO const &overlap)
65  : type_(type), overlap_(overlap)
66  {
67  this->declareConstructionOutcome(false, "");
68  SetParameterList(paramList);
69  }
70 
71  template <class Node>
72  void IfpackSmoother<Node>::SetParameterList(const Teuchos::ParameterList& paramList) {
73  Factory::SetParameterList(paramList);
74 
76  // It might be invalid to change parameters after the setup, but it depends entirely on Ifpack implementation.
77  // TODO: I don't know if Ifpack returns an error code or exception or ignore parameters modification in this case...
78  prec_->SetParameters(const_cast<ParameterList&>(this->GetParameterList()));
79  }
80  }
81 
82  template <class Node>
83  void IfpackSmoother<Node>::SetPrecParameters(const Teuchos::ParameterList& list) const {
84  ParameterList& paramList = const_cast<ParameterList&>(this->GetParameterList());
85  paramList.setParameters(list);
86 
87  RCP<ParameterList> precList = this->RemoveFactoriesFromList(this->GetParameterList());
88 
89  prec_->SetParameters(*precList);
90 
91  // We would like to have the following line here:
92  // paramList.setParameters(*precList);
93  // For instance, if Ifpack sets somem parameters internally, we would like to have
94  // them listed when we call this->GetParameterList()
95  // But because of the way Ifpack handles the list, we cannot do that.
96  // The bad scenario goes like this:
97  // * SmootherFactory calls Setup
98  // * Setup calls SetPrecParameters
99  // * We call prec_->SetParameters(*precList)
100  // This actually updates the internal parameter list with default prec_ parameters
101  // This means that we get a parameter ("chebyshev: max eigenvalue", -1) in the list
102  // * Setup calls prec_->Compute()
103  // Here we may compute the max eigenvalue, but we get no indication of this. If we
104  // do compute it, our parameter list becomes outdated
105  // * SmootherFactory calls Apply
106  // * Apply constructs a list with a list with an entry "chebyshev: zero starting solution"
107  // * We call prec_->SetParameters(*precList)
108  // The last call is the problem. At this point, we have a list with an outdated entry
109  // "chebyshev: max eigenvalue", but prec_ uses this entry and replaces the computed max
110  // eigenvalue with the one from the list, resulting in -1.0 eigenvalue.
111  //
112  // Ifpack2 does not have this problem, as it does not populate the list with new entries
113  }
114 
115  template <class Node>
116  void IfpackSmoother<Node>::DeclareInput(Level &currentLevel) const {
117  this->Input(currentLevel, "A");
118 
119  if (type_ == "LINESMOOTHING_BANDED_RELAXATION" ||
120  type_ == "LINESMOOTHING_BANDED RELAXATION" ||
121  type_ == "LINESMOOTHING_BANDEDRELAXATION" ||
122  type_ == "LINESMOOTHING_BLOCK_RELAXATION" ||
123  type_ == "LINESMOOTHING_BLOCK RELAXATION" ||
124  type_ == "LINESMOOTHING_BLOCKRELAXATION") {
125  this->Input(currentLevel, "CoarseNumZLayers"); // necessary for fallback criterion
126  this->Input(currentLevel, "LineDetection_VertLineIds"); // necessary to feed block smoother
127  } // if (type_ == "LINESMOOTHING_BANDEDRELAXATION")
128  else if (type_ == "AGGREGATE")
129  {
130  // Aggregate smoothing needs aggregates
131  this->Input(currentLevel,"Aggregates");
132  }
133 
134  }
135 
136  template <class Node>
137  void IfpackSmoother<Node>::Setup(Level &currentLevel) {
138  FactoryMonitor m(*this, "Setup Smoother", currentLevel);
139  if (SmootherPrototype::IsSetup() == true)
140  this->GetOStream(Warnings0) << "MueLu::IfpackSmoother::Setup(): Setup() has already been called" << std::endl;
141 
142  A_ = Factory::Get< RCP<Matrix> >(currentLevel, "A");
143 
144  double lambdaMax = -1.0;
145  if (type_ == "Chebyshev") {
146  std::string maxEigString = "chebyshev: max eigenvalue";
147  std::string eigRatioString = "chebyshev: ratio eigenvalue";
148 
149  try {
150  lambdaMax = Teuchos::getValue<Scalar>(this->GetParameter(maxEigString));
151  this->GetOStream(Statistics1) << maxEigString << " (cached with smoother parameter list) = " << lambdaMax << std::endl;
152 
153  } catch (Teuchos::Exceptions::InvalidParameterName&) {
154  lambdaMax = A_->GetMaxEigenvalueEstimate();
155 
156  if (lambdaMax != -1.0) {
157  this->GetOStream(Statistics1) << maxEigString << " (cached with matrix) = " << lambdaMax << std::endl;
158  this->SetParameter(maxEigString, ParameterEntry(lambdaMax));
159  }
160  }
161 
162  // Calculate the eigenvalue ratio
163  const Scalar defaultEigRatio = 20;
164 
165  Scalar ratio = defaultEigRatio;
166  try {
167  ratio = Teuchos::getValue<Scalar>(this->GetParameter(eigRatioString));
168 
169  } catch (Teuchos::Exceptions::InvalidParameterName&) {
170  this->SetParameter(eigRatioString, ParameterEntry(ratio));
171  }
172 
173  if (currentLevel.GetLevelID()) {
174  // Update ratio to be
175  // ratio = max(number of fine DOFs / number of coarse DOFs, defaultValue)
176  //
177  // NOTE: We don't need to request previous level matrix as we know for sure it was constructed
178  RCP<const Matrix> fineA = currentLevel.GetPreviousLevel()->Get<RCP<Matrix> >("A");
179  size_t nRowsFine = fineA->getGlobalNumRows();
180  size_t nRowsCoarse = A_->getGlobalNumRows();
181 
182  ratio = std::max(ratio, as<Scalar>(nRowsFine)/nRowsCoarse);
183 
184  this->GetOStream(Statistics1) << eigRatioString << " (computed) = " << ratio << std::endl;
185  this->SetParameter(eigRatioString, ParameterEntry(ratio));
186  }
187  } // if (type_ == "Chebyshev")
188 
189  if (type_ == "LINESMOOTHING_BANDED_RELAXATION" ||
190  type_ == "LINESMOOTHING_BANDED RELAXATION" ||
191  type_ == "LINESMOOTHING_BANDEDRELAXATION" ||
192  type_ == "LINESMOOTHING_BLOCK_RELAXATION" ||
193  type_ == "LINESMOOTHING_BLOCK RELAXATION" ||
194  type_ == "LINESMOOTHING_BLOCKRELAXATION" ) {
195  ParameterList& myparamList = const_cast<ParameterList&>(this->GetParameterList());
196 
197  LO CoarseNumZLayers = currentLevel.Get<LO>("CoarseNumZLayers",Factory::GetFactory("CoarseNumZLayers").get());
198  if (CoarseNumZLayers > 0) {
199  Teuchos::ArrayRCP<LO> TVertLineIdSmoo = currentLevel.Get< Teuchos::ArrayRCP<LO> >("LineDetection_VertLineIds", Factory::GetFactory("LineDetection_VertLineIds").get());
200 
201  // determine number of local parts
202  LO maxPart = 0;
203  for(size_t k = 0; k < Teuchos::as<size_t>(TVertLineIdSmoo.size()); k++) {
204  if(maxPart < TVertLineIdSmoo[k]) maxPart = TVertLineIdSmoo[k];
205  }
206 
207  size_t numLocalRows = A_->getNodeNumRows();
208  TEUCHOS_TEST_FOR_EXCEPTION(numLocalRows % TVertLineIdSmoo.size() != 0, Exceptions::RuntimeError, "MueLu::Ifpack2Smoother::Setup(): the number of local nodes is incompatible with the TVertLineIdsSmoo.");
209 
210  if (numLocalRows == Teuchos::as<size_t>(TVertLineIdSmoo.size())) {
211  myparamList.set("partitioner: type","user");
212  myparamList.set("partitioner: map",&(TVertLineIdSmoo[0]));
213  myparamList.set("partitioner: local parts",maxPart+1);
214  } else {
215  // we assume a constant number of DOFs per node
216  size_t numDofsPerNode = numLocalRows / TVertLineIdSmoo.size();
217 
218  // Create a new Teuchos::ArrayRCP<LO> of size numLocalRows and fill it with the corresponding information
219  Teuchos::ArrayRCP<LO> partitionerMap(numLocalRows, Teuchos::OrdinalTraits<LocalOrdinal>::invalid());
220  for (size_t blockRow = 0; blockRow < Teuchos::as<size_t>(TVertLineIdSmoo.size()); ++blockRow)
221  for (size_t dof = 0; dof < numDofsPerNode; dof++)
222  partitionerMap[blockRow * numDofsPerNode + dof] = TVertLineIdSmoo[blockRow];
223  myparamList.set("partitioner: type","user");
224  myparamList.set("partitioner: map",&(partitionerMap[0]));
225  myparamList.set("partitioner: local parts",maxPart + 1);
226  }
227 
228  if (type_ == "LINESMOOTHING_BANDED_RELAXATION" ||
229  type_ == "LINESMOOTHING_BANDED RELAXATION" ||
230  type_ == "LINESMOOTHING_BANDEDRELAXATION")
231  type_ = "block relaxation";
232  else
233  type_ = "block relaxation";
234  } else {
235  // line detection failed -> fallback to point-wise relaxation
236  this->GetOStream(Runtime0) << "Line detection failed: fall back to point-wise relaxation" << std::endl;
237  myparamList.remove("partitioner: type",false);
238  myparamList.remove("partitioner: map", false);
239  myparamList.remove("partitioner: local parts",false);
240  type_ = "point relaxation stand-alone";
241  }
242 
243  } // if (type_ == "LINESMOOTHING_BANDEDRELAXATION")
244 
245  if(type_ == "AGGREGATE") {
246  SetupAggregate(currentLevel);
247  }
248 
249  else {
250  // If we're using a linear partitioner and haven't set the # local parts, set it to match the operator's block size
251  ParameterList precList = this->GetParameterList();
252  if(precList.isParameter("partitioner: type") && precList.get<std::string>("partitioner: type") == "linear" &&
253  !precList.isParameter("partitioner: local parts")) {
254  precList.set("partitioner: local parts", (int)A_->getNodeNumRows() / A_->GetFixedBlockSize());
255  }
256 
257 
258  RCP<Epetra_CrsMatrix> epA = Utilities::Op2NonConstEpetraCrs(A_);
259 
260  Ifpack factory;
261  prec_ = rcp(factory.Create(type_, &(*epA), overlap_));
262  TEUCHOS_TEST_FOR_EXCEPTION(prec_.is_null(), Exceptions::RuntimeError, "Could not create an Ifpack preconditioner with type = \"" << type_ << "\"");
263  SetPrecParameters();
264  prec_->Compute();
265  }
266 
268 
269  if (type_ == "Chebyshev" && lambdaMax == -1.0) {
270  Teuchos::RCP<Ifpack_Chebyshev> chebyPrec = rcp_dynamic_cast<Ifpack_Chebyshev>(prec_);
271  if (chebyPrec != Teuchos::null) {
272  lambdaMax = chebyPrec->GetLambdaMax();
273  A_->SetMaxEigenvalueEstimate(lambdaMax);
274  this->GetOStream(Statistics1) << "chebyshev: max eigenvalue (calculated by Ifpack)" << " = " << lambdaMax << std::endl;
275  }
276  TEUCHOS_TEST_FOR_EXCEPTION(lambdaMax == -1.0, Exceptions::RuntimeError, "MueLu::IfpackSmoother::Setup(): no maximum eigenvalue estimate");
277  }
278 
279  this->GetOStream(Statistics1) << description() << std::endl;
280  }
281 
282 
283  template <class Node>
285 
286  ParameterList& paramList = const_cast<ParameterList&>(this->GetParameterList());
287 
288  if (this->IsSetup() == true) {
289  this->GetOStream(Warnings0) << "MueLu::Ifpack2moother::SetupAggregate(): Setup() has already been called" << std::endl;
290  this->GetOStream(Warnings0) << "MueLu::IfpackSmoother::SetupAggregate(): reuse of this type is not available, reverting to full construction" << std::endl;
291  }
292 
293  this->GetOStream(Statistics0) << "IfpackSmoother: Using Aggregate Smoothing"<<std::endl;
294 
295  RCP<Aggregates> aggregates = Factory::Get<RCP<Aggregates> >(currentLevel,"Aggregates");
296  RCP<const LOMultiVector> vertex2AggId = aggregates->GetVertex2AggId();
297  ArrayRCP<LO> aggregate_ids = rcp_const_cast<LOMultiVector>(vertex2AggId)->getDataNonConst(0);
298  ArrayRCP<LO> dof_ids;
299 
300  // We need to unamalgamate, if the FixedBlockSize > 1
301  if(A_->GetFixedBlockSize() > 1) {
302  // NOTE: We're basically going to have to leave a deallocated pointer hanging out
303  // in the paramList object (and inside the partitioner). This never gets
304  // use again after Compute() gets called, so this is OK, but I'm still leaving
305  // this note here in case it bites us again later.
306  LO blocksize = (LO) A_->GetFixedBlockSize();
307  dof_ids.resize(aggregate_ids.size() * blocksize);
308  for(LO i=0; i<(LO)aggregate_ids.size(); i++) {
309  for(LO j=0; j<(LO)blocksize; j++)
310  dof_ids[i*blocksize+j] = aggregate_ids[i];
311  }
312  }
313  else {
314  dof_ids = aggregate_ids;
315  }
316 
317  paramList.set("partitioner: map", dof_ids.getRawPtr());
318  paramList.set("partitioner: type", "user");
319  paramList.set("partitioner: overlap", 0);
320  paramList.set("partitioner: local parts", (int)aggregates->GetNumAggregates());
321  // In case of Dirichlet nodes
322  paramList.set("partitioner: keep singletons",true);
323 
324  RCP<Epetra_CrsMatrix> A = Utilities::Op2NonConstEpetraCrs(A_);
325  type_ = "block relaxation stand-alone";
326 
327  Ifpack factory;
328  prec_ = rcp(factory.Create(type_, &(*A), overlap_));
329  TEUCHOS_TEST_FOR_EXCEPTION(prec_.is_null(), Exceptions::RuntimeError, "Could not create an Ifpack preconditioner with type = \"" << type_ << "\"");
330  SetPrecParameters();
331 
332  int rv = prec_->Compute();
333  TEUCHOS_TEST_FOR_EXCEPTION(rv, Exceptions::RuntimeError, "Ifpack preconditioner with type = \"" << type_ << "\" Compute() call failed.");
334 
335  }
336 
337 
338  template <class Node>
339  void IfpackSmoother<Node>::Apply(MultiVector& X, const MultiVector& B, bool InitialGuessIsZero) const {
340  TEUCHOS_TEST_FOR_EXCEPTION(SmootherPrototype::IsSetup() == false, Exceptions::RuntimeError, "MueLu::IfpackSmoother::Apply(): Setup() has not been called");
341 
342 
343  // Forward the InitialGuessIsZero option to Ifpack
344  Teuchos::ParameterList paramList;
345  bool supportInitialGuess = false;
346  if (type_ == "Chebyshev") {
347  paramList.set("chebyshev: zero starting solution", InitialGuessIsZero);
348  supportInitialGuess = true;
349 
350  } else if (type_ == "point relaxation stand-alone") {
351  paramList.set("relaxation: zero starting solution", InitialGuessIsZero);
352  supportInitialGuess = true;
353  }
354 
355  SetPrecParameters(paramList);
356 
357  // Apply
358  if (InitialGuessIsZero || supportInitialGuess) {
361 
362  prec_->ApplyInverse(epB, epX);
363 
364  } else {
365  RCP<MultiVector> Residual = Utilities::Residual(*A_, X, B);
366  RCP<MultiVector> Correction = MultiVectorFactory::Build(A_->getDomainMap(), X.getNumVectors());
367 
369  const Epetra_MultiVector& epB = Utilities::MV2EpetraMV(*Residual);
370 
371  prec_->ApplyInverse(epB, epX);
372 
373  X.update(1.0, *Correction, 1.0);
374  }
375  }
376 
377  template <class Node>
378  RCP<MueLu::SmootherPrototype<double, int, int, Node> > IfpackSmoother<Node>::Copy() const {
379  RCP<IfpackSmoother<Node> > smoother = rcp(new IfpackSmoother<Node>(*this) );
380  smoother->SetParameterList(this->GetParameterList());
381  return Teuchos::rcp_dynamic_cast<MueLu::SmootherPrototype<double, int, int, Node> >(smoother);
382  }
383 
384  template <class Node>
385  std::string IfpackSmoother<Node>::description() const {
386  std::ostringstream out;
387  // The check "GetVerbLevel() == Test" is to avoid
388  // failures in the EasyInterface test.
389  if (prec_ == Teuchos::null || this->GetVerbLevel() == InterfaceTest) {
391  out << "{type = " << type_ << "}";
392  } else {
393  out << prec_->Label();
394  }
395  return out.str();
396  }
397 
398  template <class Node>
399  void IfpackSmoother<Node>::print(Teuchos::FancyOStream &out, const VerbLevel verbLevel) const {
401 
402  if (verbLevel & Parameters0)
403  out0 << "Prec. type: " << type_ << std::endl;
404 
405  if (verbLevel & Parameters1) {
406  out0 << "Parameter list: " << std::endl;
407  Teuchos::OSTab tab2(out);
408  out << this->GetParameterList();
409  out0 << "Overlap: " << overlap_ << std::endl;
410  }
411 
412  if (verbLevel & External)
413  if (prec_ != Teuchos::null) {
414  Teuchos::OSTab tab2(out);
415  out << *prec_ << std::endl;
416  }
417 
418  if (verbLevel & Debug) {
419  out0 << "IsSetup: " << Teuchos::toString(SmootherPrototype::IsSetup()) << std::endl
420  << "-" << std::endl
421  << "RCP<A_>: " << A_ << std::endl
422  << "RCP<prec_>: " << prec_ << std::endl;
423  }
424  }
425 
426  template <class Node>
428  // FIXME: This is a placeholder
429  return Teuchos::OrdinalTraits<size_t>::invalid();
430  }
431 
432 
433 } // namespace MueLu
434 
435 // The IfpackSmoother is only templated on the Node, since it is an Epetra only object
436 // Therefore we do not need the full ETI instantiations as we do for the other MueLu
437 // objects which are instantiated on all template parameters.
438 #if defined(HAVE_MUELU_EPETRA)
440 #endif
441 
442 #endif
void Setup(Level &currentLevel)
Set up the smoother.
Important warning messages (one line)
std::string toString(const T &what)
Little helper function to convert non-string types to strings.
static RCP< Epetra_CrsMatrix > Op2NonConstEpetraCrs(RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Op)
Print external lib objects.
bool IsSetup() const
Get the state of a smoother prototype.
static RCP< const Epetra_MultiVector > MV2EpetraMV(RCP< Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > const vec)
Helper utility to pull out the underlying Epetra objects from an Xpetra object.
Timer to be used in factories. Similar to Monitor but with additional timers.
void SetPrecParameters(const Teuchos::ParameterList &list=Teuchos::ParameterList()) const
Print more statistics.
RCP< SmootherPrototype > Copy() const
Print additional debugging information.
One-liner description of what is happening.
Namespace for MueLu classes and methods.
Ifpack_Preconditioner * Create(const std::string PrecType, Epetra_RowMatrix *Matrix, const int overlap=0, bool overrideSerialDefault=false)
IfpackSmoother(std::string const &type, Teuchos::ParameterList const &paramList=Teuchos::ParameterList(), LO const &overlap=0)
Constructor.
void print(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
Print the object with some verbosity level to an FancyOStream object.
Print statistics that do not involve significant additional computation.
static RCP< Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Residual(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &X, const Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &RHS)
virtual void SetParameterList(const Teuchos::ParameterList &paramList)
Set parameters from a parameter list and return with default values.
static RCP< Epetra_MultiVector > MV2NonConstEpetraMV(RCP< Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > vec)
void declareConstructionOutcome(bool fail, std::string msg)
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
virtual double GetLambdaMax()
#define MUELU_DESCRIBE
Helper macro for implementing Describable::describe() for BaseClass objects.
void DeclareInput(Level &currentLevel) const
Input.
void SetParameterList(const Teuchos::ParameterList &paramList)
Set parameters from a parameter list and return with default values.
Print class parameters.
size_t getNodeSmootherComplexity() const
Get a rough estimate of cost per iteration.
void SetupAggregate(Level &currentLevel)
std::string description() const
Return a simple one-line description of this object.
const RCP< const FactoryBase > GetFactory(const std::string &varName) const
Default implementation of FactoryAcceptor::GetFactory()
Print class parameters (more parameters, more verbose)
Exception throws to report errors in the internal logical of the program.
void Apply(MultiVector &X, const MultiVector &B, bool InitialGuessIsZero=false) const
Apply the preconditioner.
virtual std::string description() const
Return a simple one-line description of this object.
Class that encapsulates Ifpack smoothers.