MueLu  Version of the Day
MueLu_SimpleSmoother_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  * MueLu_SimpleSmoother_def.hpp
48  *
49  * Created on: 19.03.2013
50  * Author: wiesner
51  */
52 
53 #ifndef MUELU_SIMPLESMOOTHER_DEF_HPP_
54 #define MUELU_SIMPLESMOOTHER_DEF_HPP_
55 
56 #include "Teuchos_ArrayViewDecl.hpp"
57 #include "Teuchos_ScalarTraits.hpp"
58 
59 #include "MueLu_ConfigDefs.hpp"
60 
61 #include <Xpetra_Matrix.hpp>
62 #include <Xpetra_CrsMatrixWrap.hpp>
65 #include <Xpetra_VectorFactory.hpp>
66 
68 #include "MueLu_Level.hpp"
69 #include "MueLu_Utilities.hpp"
70 #include "MueLu_Monitor.hpp"
71 #include "MueLu_HierarchyUtils.hpp"
72 #include "MueLu_SmootherBase.hpp"
73 #include "MueLu_SubBlockAFactory.hpp"
74 
75 // include files for default FactoryManager
76 #include "MueLu_SchurComplementFactory.hpp"
77 #include "MueLu_DirectSolver.hpp"
78 #include "MueLu_SmootherFactory.hpp"
79 #include "MueLu_FactoryManager.hpp"
80 
81 namespace MueLu {
82 
83  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
85  : type_("SIMPLE"), A_(Teuchos::null)
86  {
87  //Factory::SetParameter("Sweeps", Teuchos::ParameterEntry(sweeps));
88  //Factory::SetParameter("Damping factor",Teuchos::ParameterEntry(omega));
89  //Factory::SetParameter("UseSIMPLEC", Teuchos::ParameterEntry(SIMPLEC));
90 
91 #if 0
92  // when declaring default factories without overwriting them leads to a multipleCallCheck exception
93  // TODO: debug into this
94  // workaround: always define your factory managers outside either using the C++ API or the XML files
95  RCP<SchurComplementFactory> SchurFact = Teuchos::rcp(new SchurComplementFactory());
96  SchurFact->SetParameter("omega",Teuchos::ParameterEntry(omega));
97  SchurFact->SetParameter("lumping",Teuchos::ParameterEntry(SIMPLEC));
98  SchurFact->SetFactory("A", this->GetFactory("A"));
99 
100  // define smoother/solver for SchurComplement equation
101  Teuchos::ParameterList SCparams;
102  std::string SCtype;
103  RCP<SmootherPrototype> smoProtoSC = rcp( new DirectSolver(SCtype,SCparams) );
104  smoProtoSC->SetFactory("A", SchurFact);
105 
106  RCP<SmootherFactory> SmooSCFact = rcp( new SmootherFactory(smoProtoSC) );
107 
108  RCP<FactoryManager> schurFactManager = rcp(new FactoryManager());
109  schurFactManager->SetFactory("A", SchurFact);
110  schurFactManager->SetFactory("Smoother", SmooSCFact);
111  schurFactManager->SetIgnoreUserData(true);
112 
113  // define smoother/solver for velocity prediction
114  RCP<SubBlockAFactory> A00Fact = Teuchos::rcp(new SubBlockAFactory(/*this->GetFactory("A"), 0, 0*/));
115  A00Fact->SetFactory("A",this->GetFactory("A"));
116  A00Fact->SetParameter("block row",ParameterEntry(0));
117  A00Fact->SetParameter("block col",ParameterEntry(0));
118  Teuchos::ParameterList velpredictParams;
119  std::string velpredictType;
120  RCP<SmootherPrototype> smoProtoPredict = rcp( new DirectSolver(velpredictType,velpredictParams) );
121  smoProtoPredict->SetFactory("A", A00Fact);
122  RCP<SmootherFactory> SmooPredictFact = rcp( new SmootherFactory(smoProtoPredict) );
123 
124  RCP<FactoryManager> velpredictFactManager = rcp(new FactoryManager());
125  velpredictFactManager->SetFactory("A", A00Fact);
126  velpredictFactManager->SetFactory("Smoother", SmooPredictFact);
127  velpredictFactManager->SetIgnoreUserData(true);
128 
129  AddFactoryManager(velpredictFactManager, 0);
130  AddFactoryManager(schurFactManager, 1);
131 #endif
132  }
133 
134  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
136 
137  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
139  RCP<ParameterList> validParamList = rcp(new ParameterList());
140 
141  validParamList->set< RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A");
142  validParamList->set< Scalar > ("Damping factor", 1.0, "Damping/Scaling factor in SIMPLE");
143  validParamList->set< LocalOrdinal > ("Sweeps", 1, "Number of SIMPLE sweeps (default = 1)");
144  validParamList->set< bool > ("UseSIMPLEC", false, "Use SIMPLEC instead of SIMPLE (default = false)");
145 
146  return validParamList;
147  }
148 
150  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
151  void SimpleSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::AddFactoryManager(RCP<const FactoryManagerBase> FactManager, int pos) {
152  TEUCHOS_TEST_FOR_EXCEPTION(pos < 0, Exceptions::RuntimeError, "MueLu::SimpleSmoother::AddFactoryManager: parameter \'pos\' must not be negative! error.");
153 
154  size_t myPos = Teuchos::as<size_t>(pos);
155 
156  if (myPos < FactManager_.size()) {
157  // replace existing entris in FactManager_ vector
158  FactManager_.at(myPos) = FactManager;
159  } else if( myPos == FactManager_.size()) {
160  // add new Factory manager in the end of the vector
161  FactManager_.push_back(FactManager);
162  } else { // if(myPos > FactManager_.size())
163  RCP<Teuchos::FancyOStream> out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
164  *out << "Warning: cannot add new FactoryManager at proper position " << pos << ". The FactoryManager is just appended to the end. Check this!" << std::endl;
165 
166  // add new Factory manager in the end of the vector
167  FactManager_.push_back(FactManager);
168  }
169 
170  }
171 
172 
173  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
175  AddFactoryManager(FactManager, 0); // overwrite factory manager for predicting the primary variable
176  }
177 
178  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
180  AddFactoryManager(FactManager, 1); // overwrite factory manager for SchurComplement
181  }
182 
183  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
185  currentLevel.DeclareInput("A",this->GetFactory("A").get());
186 
187  TEUCHOS_TEST_FOR_EXCEPTION(FactManager_.size() != 2, Exceptions::RuntimeError,"MueLu::SimpleSmoother::DeclareInput: You have to declare two FactoryManagers with a \"Smoother\" object: One for predicting the primary variable and one for the SchurComplement system. The smoother for the SchurComplement system needs a SchurComplementFactory as input for variable \"A\". make sure that you use the same proper damping factors for omega both in the SchurComplementFactory and in the SIMPLE smoother!");
188 
189  // loop over all factory managers for the subblocks of blocked operator A
190  std::vector<Teuchos::RCP<const FactoryManagerBase> >::const_iterator it;
191  for(it = FactManager_.begin(); it!=FactManager_.end(); ++it) {
192  SetFactoryManager currentSFM (rcpFromRef(currentLevel), *it);
193 
194  // request "Smoother" for current subblock row.
195  currentLevel.DeclareInput("PreSmoother",(*it)->GetFactory("Smoother").get());
196  }
197  }
198 
199  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
201  //*********************************************
202  // Setup routine can be summarized in 4 steps:
203  // - Set the map extractors
204  // - Set the blocks
205  // - Create and set the inverse of the diagonal of F
206  // - Set the smoother for the Schur Complement
207 
208  FactoryMonitor m(*this, "Setup blocked SIMPLE Smoother", currentLevel);
209 
210  if (SmootherPrototype::IsSetup() == true)
211  this->GetOStream(Warnings0) << "MueLu::SimpleSmoother::Setup(): Setup() has already been called";
212 
213  // extract blocked operator A from current level
214  A_ = Factory::Get<RCP<Matrix> > (currentLevel, "A");
215 
216  RCP<BlockedCrsMatrix> bA = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A_);
217  TEUCHOS_TEST_FOR_EXCEPTION(bA == Teuchos::null, Exceptions::BadCast, "MueLu::SimpleSmoother::Setup: input matrix A is not of type BlockedCrsMatrix! error.");
218 
219  // store map extractors
220  rangeMapExtractor_ = bA->getRangeMapExtractor();
221  domainMapExtractor_ = bA->getDomainMapExtractor();
222 
223  // Store the blocks in local member variables
224  F_ = bA->getMatrix(0, 0);
225  G_ = bA->getMatrix(0, 1);
226  D_ = bA->getMatrix(1, 0);
227  Z_ = bA->getMatrix(1, 1);
228 
229  const ParameterList & pL = Factory::GetParameterList();
230  bool bSIMPLEC = pL.get<bool>("UseSIMPLEC");
231 
232  // Create the inverse of the diagonal of F
233  // TODO add safety check for zeros on diagonal of F!
234  RCP<Vector> diagFVector = VectorFactory::Build(F_->getRowMap());
235  if(!bSIMPLEC) {
236  F_->getLocalDiagCopy(*diagFVector); // extract diagonal of F
237  } else {
238  /*const RCP<const Map> rowmap = F_->getRowMap();
239  size_t locSize = rowmap->getNodeNumElements();
240  Teuchos::ArrayRCP<SC> diag = diagFVector->getDataNonConst(0);
241  Teuchos::ArrayView<const LO> cols;
242  Teuchos::ArrayView<const SC> vals;
243  for (size_t i=0; i<locSize; ++i) { // loop over rows
244  F_->getLocalRowView(i,cols,vals);
245  Scalar absRowSum = Teuchos::ScalarTraits<Scalar>::zero();
246  for (LO j=0; j<cols.size(); ++j) { // loop over cols
247  absRowSum += Teuchos::ScalarTraits<Scalar>::magnitude(vals[j]);
248  }
249  diag[i] = absRowSum;
250  }*/
251  diagFVector = Utilities::GetLumpedMatrixDiagonal(F_);
252  }
253  diagFinv_ = Utilities::GetInverse(diagFVector);
254 
255  // Set the Smoother
256  // carefully switch to the SubFactoryManagers (defined by the users)
257  {
258  RCP<const FactoryManagerBase> velpredictFactManager = FactManager_.at(0);
259  SetFactoryManager currentSFM (rcpFromRef(currentLevel), velpredictFactManager);
260  velPredictSmoo_ = currentLevel.Get< RCP<SmootherBase> >("PreSmoother",velpredictFactManager->GetFactory("Smoother").get());
261  }
262  {
263  RCP<const FactoryManagerBase> schurFactManager = FactManager_.at(1);
264  SetFactoryManager currentSFM (rcpFromRef(currentLevel), schurFactManager);
265  schurCompSmoo_ = currentLevel.Get< RCP<SmootherBase> >("PreSmoother", schurFactManager->GetFactory("Smoother").get());
266  }
267 
269  }
270 
271  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
272  void SimpleSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Apply(MultiVector& X, const MultiVector& B, bool InitialGuessIsZero) const
273  {
274  TEUCHOS_TEST_FOR_EXCEPTION(SmootherPrototype::IsSetup() == false, Exceptions::RuntimeError, "MueLu::SimpleSmoother::Apply(): Setup() has not been called");
275 #ifdef HAVE_MUELU_DEBUG
276  TEUCHOS_TEST_FOR_EXCEPTION(A_->getRangeMap()->isSameAs(*(B.getMap())) == false, Exceptions::RuntimeError, "MueLu::SimpleSmoother::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.");
277  TEUCHOS_TEST_FOR_EXCEPTION(A_->getDomainMap()->isSameAs(*(X.getMap())) == false, Exceptions::RuntimeError, "MueLu::SimpleSmoother::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.");
278 #endif
279 
280  Teuchos::RCP<Teuchos::FancyOStream> fos = Teuchos::getFancyOStream(Teuchos::rcpFromRef(std::cout));
281 
282  SC zero = Teuchos::ScalarTraits<SC>::zero(), one = Teuchos::ScalarTraits<SC>::one();
283 
284  // extract parameters from internal parameter list
285  const ParameterList & pL = Factory::GetParameterList();
286  LocalOrdinal nSweeps = pL.get<LocalOrdinal>("Sweeps");
287  Scalar omega = pL.get<Scalar>("Damping factor");
288 
289  // The boolean flags check whether we use Thyra or Xpetra style GIDs
290  // However, assuming that SIMPLE always only works for 2x2 blocked operators, we
291  // most often have to use the ReorderedBlockedCrsOperator as input. If either the
292  // F or Z (or SchurComplement block S) are 1x1 blocked operators with Thyra style
293  // GIDs we need an extra transformation of vectors
294  // In this case, we use the Xpetra (offset) GIDs for all operations and only transform
295  // the input/output vectors before and after the subsolver calls!
296  bool bRangeThyraModePredict = rangeMapExtractor_->getThyraMode() && (Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(F_) == Teuchos::null);
297  bool bDomainThyraModePredict = domainMapExtractor_->getThyraMode() && (Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(F_) == Teuchos::null);
298  bool bRangeThyraModeSchur = rangeMapExtractor_->getThyraMode() && (Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(Z_) == Teuchos::null);
299  bool bDomainThyraModeSchur = domainMapExtractor_->getThyraMode() && (Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(Z_) == Teuchos::null);
300 
301  // The following boolean flags catch the case where we need special transformation
302  // for the GIDs when calling the subsmoothers.
303  RCP<BlockedCrsMatrix> bF = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(F_);
304  RCP<BlockedCrsMatrix> bZ = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(Z_);
305  bool bFThyraSpecialTreatment = false;
306  bool bZThyraSpecialTreatment = false;
307  if (bF != Teuchos::null) {
308  if(bF->Rows() == 1 && bF->Cols() == 1 && rangeMapExtractor_->getThyraMode() == true) bFThyraSpecialTreatment = true;
309  }
310  if (bZ != Teuchos::null) {
311  if(bZ->Rows() == 1 && bZ->Cols() == 1 && rangeMapExtractor_->getThyraMode() == true) bZThyraSpecialTreatment = true;
312  }
313 
314 #if 1// new implementation
315 
316  // create a new vector for storing the current residual in a blocked multi vector
317  RCP<MultiVector> res = MultiVectorFactory::Build(B.getMap(), B.getNumVectors(), true);
318  RCP<BlockedMultiVector> residual = Teuchos::rcp(new BlockedMultiVector(rangeMapExtractor_,res));
319 
320  // create a new solution vector as a blocked multi vector
321  RCP<MultiVector> rcpX = Teuchos::rcpFromRef(X);
322  RCP<BlockedMultiVector> bX = Teuchos::rcp(new BlockedMultiVector(domainMapExtractor_,rcpX));
323 
324  // create a blocked rhs vector
325  RCP<const MultiVector> rcpB = Teuchos::rcpFromRef(B);
326  RCP<const BlockedMultiVector> bB = Teuchos::rcp(new const BlockedMultiVector(rangeMapExtractor_,rcpB));
327 
328 
329  // incrementally improve solution vector X
330  for (LocalOrdinal run = 0; run < nSweeps; ++run) {
331  // 1) calculate current residual
332  residual->update(one,*bB,zero); // r = B
333  A_->apply(*bX, *residual, Teuchos::NO_TRANS, -one, one);
334 
335  // split residual vector
336  Teuchos::RCP<MultiVector> r1 = rangeMapExtractor_->ExtractVector(residual, 0, bRangeThyraModePredict);
337  Teuchos::RCP<MultiVector> r2 = rangeMapExtractor_->ExtractVector(residual, 1, bRangeThyraModeSchur);
338 
339  // 2) solve F * \Delta \tilde{x}_1 = r_1
340  // start with zero guess \Delta \tilde{x}_1
341  RCP<MultiVector> xtilde1 = domainMapExtractor_->getVector(0, X.getNumVectors(), bDomainThyraModePredict, true);
342  //xtilde1->putScalar(zero);
343 
344  if(bFThyraSpecialTreatment == true) {
345  xtilde1->replaceMap(domainMapExtractor_->getMap(0,true));
346  r1->replaceMap(rangeMapExtractor_->getMap(0,true));
347  velPredictSmoo_->Apply(*xtilde1,*r1);
348  xtilde1->replaceMap(domainMapExtractor_->getMap(0,false));
349  } else {
350  velPredictSmoo_->Apply(*xtilde1,*r1);
351  }
352 
353  // 3) calculate rhs for SchurComp equation
354  // r_2 - D \Delta \tilde{x}_1
355  RCP<MultiVector> schurCompRHS = rangeMapExtractor_->getVector(1, B.getNumVectors(), bRangeThyraModeSchur, false);
356  if(D_.is_null() == false)
357  D_->apply(*xtilde1,*schurCompRHS);
358  else
359  schurCompRHS->putScalar(zero);
360  schurCompRHS->update(one,*r2,-one);
361 
362  // 4) solve SchurComp equation
363  // start with zero guess \Delta \tilde{x}_2
364  RCP<MultiVector> xtilde2 = domainMapExtractor_->getVector(1, X.getNumVectors(), bDomainThyraModeSchur, true);
365  //xtilde2->putScalar(zero);
366 
367  // Special handling if SchurComplement operator was a 1x1 blocked operator in Thyra mode
368  // Then, we have to translate the Xpetra offset GIDs to plain Thyra GIDs and vice versa
369  if(bZThyraSpecialTreatment == true) {
370  xtilde2->replaceMap(domainMapExtractor_->getMap(1,true));
371  schurCompRHS->replaceMap(rangeMapExtractor_->getMap(1,true));
372  schurCompSmoo_->Apply(*xtilde2,*schurCompRHS);
373  xtilde2->replaceMap(domainMapExtractor_->getMap(1,false));
374  } else {
375  schurCompSmoo_->Apply(*xtilde2,*schurCompRHS);
376  }
377 
378  // 5) scale xtilde2 with omega
379  // store this in xhat2
380  RCP<MultiVector> xhat2 = domainMapExtractor_->getVector(1, X.getNumVectors(), bDomainThyraModeSchur, false);
381  xhat2->update(omega,*xtilde2,zero);
382 
383  // 6) calculate xhat1
384  RCP<MultiVector> xhat1 = domainMapExtractor_->getVector(0, X.getNumVectors(), bDomainThyraModePredict, false);
385  RCP<MultiVector> xhat1_temp = domainMapExtractor_->getVector(0, X.getNumVectors(), bDomainThyraModePredict, false);
386  if(G_.is_null() == false)
387  G_->apply(*xhat2,*xhat1_temp); // store result temporarely in xtilde1_temp
388  else
389  xhat1_temp->putScalar(zero);
390  xhat1->elementWiseMultiply(one/*/omega*/,*diagFinv_,*xhat1_temp,zero);
391  xhat1->update(one,*xtilde1,-one);
392 
393  // 7) extract parts of solution vector X
394  Teuchos::RCP<MultiVector> x1 = domainMapExtractor_->ExtractVector(bX, 0, bDomainThyraModePredict);
395  Teuchos::RCP<MultiVector> x2 = domainMapExtractor_->ExtractVector(bX, 1, bDomainThyraModeSchur);
396 
397  // 8) update solution vector with increments xhat1 and xhat2
398  // rescale increment for x2 with omega_
399  x1->update(one,*xhat1,one); // x1 = x1_old + xhat1
400  x2->update(/*omega*/ one,*xhat2,one); // x2 = x2_old + omega xhat2
401  // write back solution in global vector X
402  domainMapExtractor_->InsertVector(x1, 0, bX, bDomainThyraModePredict);
403  domainMapExtractor_->InsertVector(x2, 1, bX, bDomainThyraModeSchur);
404  }
405 
406  // write back solution
407  domainMapExtractor_->InsertVector(bX->getMultiVector(0,bDomainThyraModePredict), 0, rcpX, bDomainThyraModePredict);
408  domainMapExtractor_->InsertVector(bX->getMultiVector(1,bDomainThyraModeSchur), 1, rcpX, bDomainThyraModeSchur);
409 #else
410 
411  // wrap current solution vector in RCP
412  RCP<MultiVector> rcpX = Teuchos::rcpFromRef(X);
413 
414  // create residual vector
415  // contains current residual of current solution X with rhs B
416  RCP<MultiVector> residual = MultiVectorFactory::Build(B.getMap(), B.getNumVectors());
417 
418  // incrementally improve solution vector X
419  for (LocalOrdinal run = 0; run < nSweeps; ++run) {
420  // 1) calculate current residual
421  residual->update(one,B,zero); // residual = B
422  A_->apply(*rcpX, *residual, Teuchos::NO_TRANS, -one, one);
423  // split residual vector
424  Teuchos::RCP<MultiVector> r1 = rangeMapExtractor_->ExtractVector(residual, 0, bRangeThyraModePredict);
425  Teuchos::RCP<MultiVector> r2 = rangeMapExtractor_->ExtractVector(residual, 1, bRangeThyraModeSchur);
426 
427  // 2) solve F * \Delta \tilde{x}_1 = r_1
428  // start with zero guess \Delta \tilde{x}_1
429  RCP<MultiVector> xtilde1 = domainMapExtractor_->getVector(0, X.getNumVectors(), bDomainThyraModePredict);
430  xtilde1->putScalar(zero);
431 
432  // Special handling in case that F block is a 1x1 blocked operator in Thyra mode
433  // Then we have to feed the smoother with real Thyra-based vectors
434  if(bFThyraSpecialTreatment == true) {
435  // create empty solution vector based on Thyra GIDs
436  RCP<MultiVector> xtilde1_thyra = domainMapExtractor_->getVector(0, X.getNumVectors(), true);
437  // create new RHS vector based on Thyra GIDs
438  Teuchos::RCP<MultiVector> r1_thyra = rangeMapExtractor_->ExtractVector(residual, 0, true);
439  velPredictSmoo_->Apply(*xtilde1_thyra,*r1_thyra);
440  for(size_t k=0; k < xtilde1_thyra->getNumVectors(); k++) {
441  Teuchos::ArrayRCP<Scalar> xpetraVecData = xtilde1->getDataNonConst(k);
442  Teuchos::ArrayRCP<const Scalar> thyraVecData = xtilde1_thyra->getData(k);
443  for(size_t i=0; i < xtilde1_thyra->getLocalLength(); i++) {
444  xpetraVecData[i] = thyraVecData[i];
445  }
446  }
447  } else {
448  velPredictSmoo_->Apply(*xtilde1,*r1);
449  }
450 
451  // 3) calculate rhs for SchurComp equation
452  // r_2 - D \Delta \tilde{x}_1
453  RCP<MultiVector> schurCompRHS = rangeMapExtractor_->getVector(1, B.getNumVectors(), bRangeThyraModeSchur);
454  D_->apply(*xtilde1,*schurCompRHS);
455  schurCompRHS->update(one,*r2,-one);
456 
457  // 4) solve SchurComp equation
458  // start with zero guess \Delta \tilde{x}_2
459  RCP<MultiVector> xtilde2 = domainMapExtractor_->getVector(1, X.getNumVectors(), bDomainThyraModeSchur);
460  xtilde2->putScalar(zero);
461 
462  // Special handling if SchurComplement operator was a 1x1 blocked operator in Thyra mode
463  // Then, we have to translate the Xpetra offset GIDs to plain Thyra GIDs and vice versa
464  if(bZThyraSpecialTreatment == true) {
465  // create empty solution vector based on Thyra GIDs
466  RCP<MultiVector> xtilde2_thyra = domainMapExtractor_->getVector(1, X.getNumVectors(), true);
467  // create new RHS vector based on Thyra GIDs
468  RCP<MultiVector> schurCompRHS_thyra = rangeMapExtractor_->getVector(1, B.getNumVectors(), true);
469  // transform vector
470  for(size_t k=0; k < schurCompRHS->getNumVectors(); k++) {
471  Teuchos::ArrayRCP<const Scalar> xpetraVecData = schurCompRHS->getData(k);
472  Teuchos::ArrayRCP<Scalar> thyraVecData = schurCompRHS_thyra->getDataNonConst(k);
473  for(size_t i=0; i < schurCompRHS->getLocalLength(); i++) {
474  thyraVecData[i] = xpetraVecData[i];
475  }
476  }
477 
478  schurCompSmoo_->Apply(*xtilde2_thyra,*schurCompRHS_thyra);
479 
480  for(size_t k=0; k < xtilde2_thyra->getNumVectors(); k++) {
481  Teuchos::ArrayRCP<Scalar> xpetraVecData = xtilde2->getDataNonConst(k);
482  Teuchos::ArrayRCP<const Scalar> thyraVecData = xtilde2_thyra->getData(k);
483  for(size_t i=0; i < xtilde2_thyra->getLocalLength(); i++) {
484  xpetraVecData[i] = thyraVecData[i];
485  }
486  }
487  } else {
488  schurCompSmoo_->Apply(*xtilde2,*schurCompRHS);
489  }
490 
491  // 5) scale xtilde2 with omega
492  // store this in xhat2
493  RCP<MultiVector> xhat2 = domainMapExtractor_->getVector(1, X.getNumVectors(), bDomainThyraModeSchur);
494  xhat2->update(omega,*xtilde2,zero);
495 
496  // 6) calculate xhat1
497  RCP<MultiVector> xhat1 = domainMapExtractor_->getVector(0, X.getNumVectors(), bDomainThyraModePredict);
498  RCP<MultiVector> xhat1_temp = domainMapExtractor_->getVector(0, X.getNumVectors(), bDomainThyraModePredict);
499  G_->apply(*xhat2,*xhat1_temp); // store result temporarely in xtilde1_temp
500  xhat1->elementWiseMultiply(one/*/omega*/,*diagFinv_,*xhat1_temp,zero);
501  xhat1->update(one,*xtilde1,-one);
502 
503  // 7) extract parts of solution vector X
504  Teuchos::RCP<MultiVector> x1 = domainMapExtractor_->ExtractVector(rcpX, 0, bDomainThyraModePredict);
505  Teuchos::RCP<MultiVector> x2 = domainMapExtractor_->ExtractVector(rcpX, 1, bDomainThyraModeSchur);
506 
507  // 8) update solution vector with increments xhat1 and xhat2
508  // rescale increment for x2 with omega_
509  x1->update(one,*xhat1,one); // x1 = x1_old + xhat1
510  x2->update(/*omega*/ one,*xhat2,one); // x2 = x2_old + omega xhat2
511  // write back solution in global vector X
512  domainMapExtractor_->InsertVector(x1, 0, rcpX, bDomainThyraModePredict);
513  domainMapExtractor_->InsertVector(x2, 1, rcpX, bDomainThyraModeSchur);
514  }
515 #endif
516  }
517 
518  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
519  RCP<MueLu::SmootherPrototype<Scalar, LocalOrdinal, GlobalOrdinal, Node> >
521  return rcp( new SimpleSmoother(*this) );
522  }
523 
524  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
526  std::ostringstream out;
528  out << "{type = " << type_ << "}";
529  return out.str();
530  }
531 
532  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
533  void SimpleSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::print(Teuchos::FancyOStream &out, const VerbLevel verbLevel) const {
535 
536  if (verbLevel & Parameters0) {
537  out0 << "Prec. type: " << type_ << /*" Sweeps: " << nSweeps_ << " damping: " << omega_ <<*/ std::endl;
538  }
539 
540  if (verbLevel & Debug) {
541  out0 << "IsSetup: " << Teuchos::toString(SmootherPrototype::IsSetup()) << std::endl;
542  }
543  }
544 
545 } // namespace MueLu
546 
547 
548 #endif /* MUELU_SIMPLESMOOTHER_DEF_HPP_ */
Important warning messages (one line)
Generic Smoother Factory for generating the smoothers of the MG hierarchy.
void SetSchurCompFactoryManager(RCP< FactoryManager > FactManager)
Exception indicating invalid cast attempted.
void AddFactoryManager(RCP< const FactoryManagerBase > FactManager, int pos)
Add a factory manager at a specific position.
This class specifies the default factory that should generate some data on a Level if the data does n...
std::string toString(const T &what)
Little helper function to convert non-string types to strings.
bool IsSetup() const
Get the state of a smoother prototype.
Timer to be used in factories. Similar to Monitor but with additional timers.
void Setup(Level &currentLevel)
Setup routine.
Print additional debugging information.
static Teuchos::ArrayRCP< Scalar > GetLumpedMatrixDiagonal(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A)
Namespace for MueLu classes and methods.
void SetVelocityPredictionFactoryManager(RCP< FactoryManager > FactManager)
virtual ~SimpleSmoother()
Destructor.
RCP< SmootherPrototype > Copy() const
Class that encapsulates direct solvers. Autoselection of AmesosSmoother or Amesos2Smoother according ...
void DeclareInput(Level &currentLevel) const
Input.
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
Factory for building a thresholded operator.
#define MUELU_DESCRIBE
Helper macro for implementing Describable::describe() for BaseClass objects.
virtual const Teuchos::ParameterList & GetParameterList() const
Print class parameters.
Factory for building the Schur Complement for a 2x2 block matrix.
static Teuchos::RCP< Xpetra::Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > GetInverse(Teuchos::RCP< const Xpetra::Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > v, Magnitude tol=Teuchos::ScalarTraits< Scalar >::eps() *100, Scalar tolReplacement=Teuchos::ScalarTraits< Scalar >::zero())
Scalar SC
void print(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
Print the object with some verbosity level to an FancyOStream object.
RCP< const ParameterList > GetValidParameterList() const
Input.
const RCP< const FactoryBase > GetFactory(const std::string &varName) const
Default implementation of FactoryAcceptor::GetFactory()
Exception throws to report errors in the internal logical of the program.
An exception safe way to call the method &#39;Level::SetFactoryManager()&#39;.
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput()
std::string description() const
Return a simple one-line description of this object.
virtual std::string description() const
Return a simple one-line description of this object.
SIMPLE smoother for 2x2 block matrices.
void Apply(MultiVector &X, MultiVector const &B, bool InitialGuessIsZero=false) const
Apply the Braess Sarazin smoother.