MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Thyra_MueLuPreconditionerFactory_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 #ifndef THYRA_MUELU_PRECONDITIONER_FACTORY_DEF_HPP
47 #define THYRA_MUELU_PRECONDITIONER_FACTORY_DEF_HPP
48 
51 
52 #if defined(HAVE_MUELU_STRATIMIKOS) && defined(HAVE_MUELU_THYRA)
53 
54 // This is not as general as possible, but should be good enough for most builds.
55 #if ((defined(HAVE_TPETRA_INST_DOUBLE) && defined(HAVE_TPETRA_INST_FLOAT) && !defined(HAVE_TPETRA_INST_COMPLEX_DOUBLE) && !defined(HAVE_TPETRA_INST_COMPLEX_FLOAT)) || \
56  (!defined(HAVE_TPETRA_INST_DOUBLE) && !defined(HAVE_TPETRA_INST_FLOAT) && defined(HAVE_TPETRA_INST_COMPLEX_DOUBLE) && defined(HAVE_TPETRA_INST_COMPLEX_FLOAT)) || \
57  (defined(HAVE_TPETRA_INST_DOUBLE) && defined(HAVE_TPETRA_INST_FLOAT) && defined(HAVE_TPETRA_INST_COMPLEX_DOUBLE) && defined(HAVE_TPETRA_INST_COMPLEX_FLOAT)))
58 #define MUELU_CAN_USE_MIXED_PRECISION
59 #endif
60 
61 namespace Thyra {
62 
64 using Teuchos::RCP;
65 using Teuchos::rcp;
66 using Teuchos::rcp_const_cast;
67 using Teuchos::rcp_dynamic_cast;
68 
69 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
70 bool Converters<Scalar, LocalOrdinal, GlobalOrdinal, Node>::replaceWithXpetra(ParameterList& paramList, std::string parameterName) {
71  typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType Magnitude;
73  typedef Xpetra::ThyraUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node> XpThyUtils;
74  // typedef Xpetra::CrsMatrixWrap<Scalar,LocalOrdinal,GlobalOrdinal,Node> XpCrsMatWrap;
75  // typedef Xpetra::CrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> XpCrsMat;
80 
81  typedef Thyra::LinearOpBase<Scalar> ThyLinOpBase;
82  typedef Thyra::DiagonalLinearOpBase<Scalar> ThyDiagLinOpBase;
83  // typedef Thyra::XpetraLinearOp<Scalar, LocalOrdinal, GlobalOrdinal, Node> ThyXpOp;
84  // typedef Thyra::SpmdVectorSpaceBase<Scalar> ThyVSBase;
85 
89  typedef Thyra::TpetraVector<Scalar, LocalOrdinal, GlobalOrdinal, Node> thyTpV;
92 #if defined(MUELU_CAN_USE_MIXED_PRECISION)
93  typedef typename Teuchos::ScalarTraits<Magnitude>::halfPrecision HalfMagnitude;
95 #endif
96 
97  if (paramList.isParameter(parameterName)) {
98  if (paramList.isType<RCP<XpMat> >(parameterName))
99  return true;
100  else if (paramList.isType<RCP<const XpMat> >(parameterName)) {
101  RCP<const XpMat> constM = paramList.get<RCP<const XpMat> >(parameterName);
102  paramList.remove(parameterName);
103  RCP<XpMat> M = rcp_const_cast<XpMat>(constM);
104  paramList.set<RCP<XpMat> >(parameterName, M);
105  return true;
106  } else if (paramList.isType<RCP<XpMultVec> >(parameterName))
107  return true;
108  else if (paramList.isType<RCP<const XpMultVec> >(parameterName)) {
109  RCP<const XpMultVec> constX = paramList.get<RCP<const XpMultVec> >(parameterName);
110  paramList.remove(parameterName);
111  RCP<XpMultVec> X = rcp_const_cast<XpMultVec>(constX);
112  paramList.set<RCP<XpMultVec> >(parameterName, X);
113  return true;
114  } else if (paramList.isType<RCP<XpMagMultVec> >(parameterName))
115  return true;
116  else if (paramList.isType<RCP<const XpMagMultVec> >(parameterName)) {
117  RCP<const XpMagMultVec> constX = paramList.get<RCP<const XpMagMultVec> >(parameterName);
118  paramList.remove(parameterName);
119  RCP<XpMagMultVec> X = rcp_const_cast<XpMagMultVec>(constX);
120  paramList.set<RCP<XpMagMultVec> >(parameterName, X);
121  return true;
122  } else if (paramList.isType<RCP<TpCrsMat> >(parameterName)) {
123  RCP<TpCrsMat> tM = paramList.get<RCP<TpCrsMat> >(parameterName);
124  paramList.remove(parameterName);
125  RCP<XpMat> xM = MueLu::TpetraCrs_To_XpetraMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>(tM);
126  paramList.set<RCP<XpMat> >(parameterName, xM);
127  return true;
128  } else if (paramList.isType<RCP<tMV> >(parameterName)) {
129  RCP<tMV> tpetra_X = paramList.get<RCP<tMV> >(parameterName);
130  paramList.remove(parameterName);
131  RCP<XpMultVec> X = MueLu::TpetraMultiVector_To_XpetraMultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>(tpetra_X);
132  paramList.set<RCP<XpMultVec> >(parameterName, X);
134  return true;
135  } else if (paramList.isType<RCP<tMagMV> >(parameterName)) {
136  RCP<tMagMV> tpetra_X = paramList.get<RCP<tMagMV> >(parameterName);
137  paramList.remove(parameterName);
138  RCP<XpMagMultVec> X = MueLu::TpetraMultiVector_To_XpetraMultiVector<Magnitude, LocalOrdinal, GlobalOrdinal, Node>(tpetra_X);
139  paramList.set<RCP<XpMagMultVec> >(parameterName, X);
141  return true;
142  }
143 #if defined(MUELU_CAN_USE_MIXED_PRECISION)
144  else if (paramList.isType<RCP<tHalfMagMV> >(parameterName)) {
145  RCP<tHalfMagMV> tpetra_hX = paramList.get<RCP<tHalfMagMV> >(parameterName);
146  paramList.remove(parameterName);
147  RCP<tMagMV> tpetra_X = rcp(new tMagMV(tpetra_hX->getMap(), tpetra_hX->getNumVectors()));
148  Tpetra::deep_copy(*tpetra_X, *tpetra_hX);
149  RCP<XpMagMultVec> X = MueLu::TpetraMultiVector_To_XpetraMultiVector<Magnitude, LocalOrdinal, GlobalOrdinal, Node>(tpetra_X);
150  paramList.set<RCP<XpMagMultVec> >(parameterName, X);
152  return true;
153  }
154 #endif
155  else if (paramList.isType<RCP<const ThyDiagLinOpBase> >(parameterName) ||
156  (paramList.isType<RCP<const ThyLinOpBase> >(parameterName) && !rcp_dynamic_cast<const ThyDiagLinOpBase>(paramList.get<RCP<const ThyLinOpBase> >(parameterName)).is_null())) {
157  RCP<const ThyDiagLinOpBase> thyM;
158  if (paramList.isType<RCP<const ThyDiagLinOpBase> >(parameterName))
159  thyM = paramList.get<RCP<const ThyDiagLinOpBase> >(parameterName);
160  else
161  thyM = rcp_dynamic_cast<const ThyDiagLinOpBase>(paramList.get<RCP<const ThyLinOpBase> >(parameterName), true);
162  paramList.remove(parameterName);
163  RCP<const Thyra::VectorBase<Scalar> > diag = thyM->getDiag();
164 
165  RCP<const XpVec> xpDiag;
166  if (!rcp_dynamic_cast<const thyTpV>(diag).is_null()) {
167  RCP<const tV> tDiag = Thyra::TpetraOperatorVectorExtraction<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getConstTpetraVector(diag);
168  if (!tDiag.is_null())
169  xpDiag = Xpetra::toXpetra(tDiag);
170  }
171  TEUCHOS_ASSERT(!xpDiag.is_null());
173  paramList.set<RCP<XpMat> >(parameterName, M);
174  return true;
175  } else if (paramList.isType<RCP<const ThyLinOpBase> >(parameterName)) {
176  RCP<const ThyLinOpBase> thyM = paramList.get<RCP<const ThyLinOpBase> >(parameterName);
177  paramList.remove(parameterName);
178  try {
179  RCP<XpMat> M = XpThyUtils::toXpetra(Teuchos::rcp_const_cast<ThyLinOpBase>(thyM));
180  paramList.set<RCP<XpMat> >(parameterName, M);
181  } catch (std::exception& e) {
182  RCP<XpOp> M = XpThyUtils::toXpetraOperator(Teuchos::rcp_const_cast<ThyLinOpBase>(thyM));
183  RCP<Xpetra::TpetraOperator<Scalar, LocalOrdinal, GlobalOrdinal, Node> > tpOp = rcp_dynamic_cast<Xpetra::TpetraOperator<Scalar, LocalOrdinal, GlobalOrdinal, Node> >(M, true);
184  RCP<tOp> tO = tpOp->getOperator();
185  RCP<tV> diag;
186  if (tO->hasDiagonal()) {
187  diag = rcp(new tV(tO->getRangeMap()));
188  tO->getLocalDiagCopy(*diag);
189  }
191  RCP<Xpetra::TpetraOperator<Scalar, LocalOrdinal, GlobalOrdinal, Node> > tpFOp = rcp(new Xpetra::TpetraOperator<Scalar, LocalOrdinal, GlobalOrdinal, Node>(fTpRow));
192  auto op = rcp_dynamic_cast<XpOp>(tpFOp);
193  paramList.set<RCP<XpOp> >(parameterName, op);
194  }
195  return true;
196  } else {
197  TEUCHOS_TEST_FOR_EXCEPTION(true, MueLu::Exceptions::RuntimeError, "Parameter " << parameterName << " has wrong type.");
198  return false;
199  }
200  } else
201  return false;
202 }
203 
204 #ifdef HAVE_MUELU_EPETRA
205 template <class GlobalOrdinal>
206 bool Converters<double, int, GlobalOrdinal, Tpetra::KokkosCompat::KokkosSerialWrapperNode>::replaceWithXpetra(ParameterList& paramList, std::string parameterName) {
207  typedef double Scalar;
208  typedef int LocalOrdinal;
209  typedef Tpetra::KokkosCompat::KokkosSerialWrapperNode Node;
210  typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType Magnitude;
212  typedef Xpetra::ThyraUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node> XpThyUtils;
219 
220  typedef Thyra::LinearOpBase<Scalar> ThyLinOpBase;
221  typedef Thyra::DiagonalLinearOpBase<Scalar> ThyDiagLinOpBase;
222  typedef Thyra::SpmdVectorSpaceBase<Scalar> ThyVSBase;
223 
227  typedef Thyra::TpetraVector<Scalar, LocalOrdinal, GlobalOrdinal, Node> thyTpV;
230 #if defined(MUELU_CAN_USE_MIXED_PRECISION)
231  typedef typename Teuchos::ScalarTraits<Magnitude>::halfPrecision HalfMagnitude;
233 #endif
234 #if defined(HAVE_MUELU_EPETRA)
236 #endif
237 
238  if (paramList.isParameter(parameterName)) {
239  if (paramList.isType<RCP<XpMat> >(parameterName))
240  return true;
241  else if (paramList.isType<RCP<const XpMat> >(parameterName)) {
242  RCP<const XpMat> constM = paramList.get<RCP<const XpMat> >(parameterName);
243  paramList.remove(parameterName);
244  RCP<XpMat> M = rcp_const_cast<XpMat>(constM);
245  paramList.set<RCP<XpMat> >(parameterName, M);
246  return true;
247  } else if (paramList.isType<RCP<XpMultVec> >(parameterName))
248  return true;
249  else if (paramList.isType<RCP<const XpMultVec> >(parameterName)) {
250  RCP<const XpMultVec> constX = paramList.get<RCP<const XpMultVec> >(parameterName);
251  paramList.remove(parameterName);
252  RCP<XpMultVec> X = rcp_const_cast<XpMultVec>(constX);
253  paramList.set<RCP<XpMultVec> >(parameterName, X);
254  return true;
255  } else if (paramList.isType<RCP<XpMagMultVec> >(parameterName))
256  return true;
257  else if (paramList.isType<RCP<const XpMagMultVec> >(parameterName)) {
258  RCP<const XpMagMultVec> constX = paramList.get<RCP<const XpMagMultVec> >(parameterName);
259  paramList.remove(parameterName);
260  RCP<XpMagMultVec> X = rcp_const_cast<XpMagMultVec>(constX);
261  paramList.set<RCP<XpMagMultVec> >(parameterName, X);
262  return true;
263  } else if (paramList.isType<RCP<TpCrsMat> >(parameterName)) {
264  RCP<TpCrsMat> tM = paramList.get<RCP<TpCrsMat> >(parameterName);
265  paramList.remove(parameterName);
266  RCP<XpMat> xM = MueLu::TpetraCrs_To_XpetraMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>(tM);
267  paramList.set<RCP<XpMat> >(parameterName, xM);
268  return true;
269  } else if (paramList.isType<RCP<tMV> >(parameterName)) {
270  RCP<tMV> tpetra_X = paramList.get<RCP<tMV> >(parameterName);
271  paramList.remove(parameterName);
272  RCP<XpMultVec> X = MueLu::TpetraMultiVector_To_XpetraMultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>(tpetra_X);
273  paramList.set<RCP<XpMultVec> >(parameterName, X);
275  return true;
276  } else if (paramList.isType<RCP<tMagMV> >(parameterName)) {
277  RCP<tMagMV> tpetra_X = paramList.get<RCP<tMagMV> >(parameterName);
278  paramList.remove(parameterName);
279  RCP<XpMagMultVec> X = MueLu::TpetraMultiVector_To_XpetraMultiVector<Magnitude, LocalOrdinal, GlobalOrdinal, Node>(tpetra_X);
280  paramList.set<RCP<XpMagMultVec> >(parameterName, X);
282  return true;
283  }
284 #if defined(MUELU_CAN_USE_MIXED_PRECISION)
285  else if (paramList.isType<RCP<tHalfMagMV> >(parameterName)) {
286  RCP<tHalfMagMV> tpetra_hX = paramList.get<RCP<tHalfMagMV> >(parameterName);
287  paramList.remove(parameterName);
288  RCP<tMagMV> tpetra_X = rcp(new tMagMV(tpetra_hX->getMap(), tpetra_hX->getNumVectors()));
289  Tpetra::deep_copy(*tpetra_X, *tpetra_hX);
290  RCP<XpMagMultVec> X = MueLu::TpetraMultiVector_To_XpetraMultiVector<Magnitude, LocalOrdinal, GlobalOrdinal, Node>(tpetra_X);
291  paramList.set<RCP<XpMagMultVec> >(parameterName, X);
293  return true;
294  }
295 #endif
296 #ifdef HAVE_MUELU_EPETRA
297  else if (paramList.isType<RCP<Epetra_CrsMatrix> >(parameterName)) {
298  RCP<Epetra_CrsMatrix> eM = paramList.get<RCP<Epetra_CrsMatrix> >(parameterName);
299  paramList.remove(parameterName);
300  RCP<XpEpCrsMat> xeM = rcp(new XpEpCrsMat(eM));
301  RCP<XpCrsMat> xCrsM = rcp_dynamic_cast<XpCrsMat>(xeM, true);
302  RCP<XpCrsMatWrap> xwM = rcp(new XpCrsMatWrap(xCrsM));
303  RCP<XpMat> xM = rcp_dynamic_cast<XpMat>(xwM);
304  paramList.set<RCP<XpMat> >(parameterName, xM);
305  return true;
306  } else if (paramList.isType<RCP<Epetra_MultiVector> >(parameterName)) {
307  RCP<Epetra_MultiVector> epetra_X = Teuchos::null;
308  epetra_X = paramList.get<RCP<Epetra_MultiVector> >(parameterName);
309  paramList.remove(parameterName);
310  RCP<Xpetra::EpetraMultiVectorT<int, Node> > xpEpX = rcp(new Xpetra::EpetraMultiVectorT<int, Node>(epetra_X));
311  RCP<Xpetra::MultiVector<Scalar, int, int, Node> > xpEpXMult = rcp_dynamic_cast<Xpetra::MultiVector<Scalar, int, int, Node> >(xpEpX, true);
312  RCP<XpMultVec> X = rcp_dynamic_cast<XpMultVec>(xpEpXMult, true);
313  paramList.set<RCP<XpMultVec> >(parameterName, X);
314  return true;
315  }
316 #endif
317  else if (paramList.isType<RCP<const ThyDiagLinOpBase> >(parameterName) ||
318  (paramList.isType<RCP<const ThyLinOpBase> >(parameterName) && !rcp_dynamic_cast<const ThyDiagLinOpBase>(paramList.get<RCP<const ThyLinOpBase> >(parameterName)).is_null())) {
319  RCP<const ThyDiagLinOpBase> thyM;
320  if (paramList.isType<RCP<const ThyDiagLinOpBase> >(parameterName))
321  thyM = paramList.get<RCP<const ThyDiagLinOpBase> >(parameterName);
322  else
323  thyM = rcp_dynamic_cast<const ThyDiagLinOpBase>(paramList.get<RCP<const ThyLinOpBase> >(parameterName), true);
324  paramList.remove(parameterName);
325  RCP<const Thyra::VectorBase<Scalar> > diag = thyM->getDiag();
326 
327  RCP<const XpVec> xpDiag;
328  if (!rcp_dynamic_cast<const thyTpV>(diag).is_null()) {
329  RCP<const tV> tDiag = Thyra::TpetraOperatorVectorExtraction<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getConstTpetraVector(diag);
330  if (!tDiag.is_null())
331  xpDiag = Xpetra::toXpetra(tDiag);
332  }
333 #ifdef HAVE_MUELU_EPETRA
334  if (xpDiag.is_null()) {
335  RCP<const Epetra_Comm> comm = Thyra::get_Epetra_Comm(*rcp_dynamic_cast<const ThyVSBase>(thyM->range())->getComm());
336  RCP<const Epetra_Map> map = Thyra::get_Epetra_Map(*(thyM->range()), comm);
337  if (!map.is_null()) {
338  RCP<const Epetra_Vector> eDiag = Thyra::get_Epetra_Vector(*map, diag);
339  RCP<Epetra_Vector> nceDiag = rcp_const_cast<Epetra_Vector>(eDiag);
340  RCP<Xpetra::EpetraVectorT<int, Node> > xpEpDiag = rcp(new Xpetra::EpetraVectorT<int, Node>(nceDiag));
341  xpDiag = rcp_dynamic_cast<XpVec>(xpEpDiag, true);
342  }
343  }
344 #endif
345  TEUCHOS_ASSERT(!xpDiag.is_null());
347  paramList.set<RCP<XpMat> >(parameterName, M);
348  return true;
349  } else if (paramList.isType<RCP<const ThyLinOpBase> >(parameterName)) {
350  RCP<const ThyLinOpBase> thyM = paramList.get<RCP<const ThyLinOpBase> >(parameterName);
351  paramList.remove(parameterName);
352  try {
353  RCP<XpMat> M = XpThyUtils::toXpetra(Teuchos::rcp_const_cast<ThyLinOpBase>(thyM));
354  paramList.set<RCP<XpMat> >(parameterName, M);
355  } catch (std::exception& e) {
356  RCP<XpOp> M = XpThyUtils::toXpetraOperator(Teuchos::rcp_const_cast<ThyLinOpBase>(thyM));
357  RCP<Xpetra::TpetraOperator<Scalar, LocalOrdinal, GlobalOrdinal, Node> > tpOp = rcp_dynamic_cast<Xpetra::TpetraOperator<Scalar, LocalOrdinal, GlobalOrdinal, Node> >(M, true);
358  RCP<tOp> tO = tpOp->getOperator();
359  RCP<tV> diag;
360  if (tO->hasDiagonal()) {
361  diag = rcp(new tV(tO->getRangeMap()));
362  tO->getLocalDiagCopy(*diag);
363  }
365  RCP<Xpetra::TpetraOperator<Scalar, LocalOrdinal, GlobalOrdinal, Node> > tpFOp = rcp(new Xpetra::TpetraOperator<Scalar, LocalOrdinal, GlobalOrdinal, Node>(fTpRow));
366  auto op = rcp_dynamic_cast<XpOp>(tpFOp);
367  paramList.set<RCP<XpOp> >(parameterName, op);
368  }
369  return true;
370  } else {
371  TEUCHOS_TEST_FOR_EXCEPTION(true, MueLu::Exceptions::RuntimeError, "Parameter " << parameterName << " has wrong type.");
372  return false;
373  }
374  } else
375  return false;
376 }
377 #endif
378 
379 // Constructors/initializers/accessors
380 
381 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
382 MueLuPreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::MueLuPreconditionerFactory()
383  : paramList_(rcp(new ParameterList())) {}
384 
385 // Overridden from PreconditionerFactoryBase
386 
387 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
388 bool MueLuPreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::isCompatible(const LinearOpSourceBase<Scalar>& fwdOpSrc) const {
389  const RCP<const LinearOpBase<Scalar> > fwdOp = fwdOpSrc.getOp();
390 
391  if (Xpetra::ThyraUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::isTpetra(fwdOp)) return true;
392 
393 #ifdef HAVE_MUELU_EPETRA
394  if (Xpetra::ThyraUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::isEpetra(fwdOp)) return true;
395 #endif
396 
397  if (Xpetra::ThyraUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::isBlockedOperator(fwdOp)) return true;
398 
399  return false;
400 }
401 
402 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
403 RCP<PreconditionerBase<Scalar> > MueLuPreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::createPrec() const {
404  return Teuchos::rcp(new DefaultPreconditioner<Scalar>);
405 }
406 
407 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
408 void MueLuPreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
409  initializePrec(const RCP<const LinearOpSourceBase<Scalar> >& fwdOpSrc, PreconditionerBase<Scalar>* prec, const ESupportSolveUse supportSolveUse) const {
410  Teuchos::TimeMonitor tM(*Teuchos::TimeMonitor::getNewTimer(std::string("ThyraMueLu::initializePrec")));
411 
412  using Teuchos::rcp_dynamic_cast;
413 
414  // we are using typedefs here, since we are using objects from different packages (Xpetra, Thyra,...)
418  typedef Xpetra::ThyraUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node> XpThyUtils;
419  // typedef Xpetra::CrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> XpCrsMat;
422  // typedef Xpetra::MultiVector<Scalar,LocalOrdinal,GlobalOrdinal,Node> XpMultVec;
423  // typedef Xpetra::MultiVector<typename Teuchos::ScalarTraits<Scalar>::coordinateType,LocalOrdinal,GlobalOrdinal,Node> XpMultVecDouble;
424  typedef Thyra::LinearOpBase<Scalar> ThyLinOpBase;
427  typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType Magnitude;
429 #if defined(MUELU_CAN_USE_MIXED_PRECISION)
430  typedef Xpetra::TpetraHalfPrecisionOperator<Scalar, LocalOrdinal, GlobalOrdinal, Node> XpHalfPrecOp;
431  typedef typename XpHalfPrecOp::HalfScalar HalfScalar;
434  typedef typename Teuchos::ScalarTraits<Magnitude>::halfPrecision HalfMagnitude;
438 #endif
439 
440  // Check precondition
441  TEUCHOS_ASSERT(Teuchos::nonnull(fwdOpSrc));
442  TEUCHOS_ASSERT(this->isCompatible(*fwdOpSrc));
443  TEUCHOS_ASSERT(prec);
444 
445  // Create a copy, as we may remove some things from the list
446  ParameterList paramList = *paramList_;
447 
448  // Retrieve wrapped concrete Xpetra matrix from FwdOp
449  const RCP<const ThyLinOpBase> fwdOp = fwdOpSrc->getOp();
451 
452  // Check whether it is Epetra/Tpetra
453  bool bIsEpetra = XpThyUtils::isEpetra(fwdOp);
454  bool bIsTpetra = XpThyUtils::isTpetra(fwdOp);
455  bool bIsBlocked = XpThyUtils::isBlockedOperator(fwdOp);
456  TEUCHOS_TEST_FOR_EXCEPT((bIsEpetra == true && bIsTpetra == true));
457  TEUCHOS_TEST_FOR_EXCEPT((bIsEpetra == bIsTpetra) && bIsBlocked == false);
458  TEUCHOS_TEST_FOR_EXCEPT((bIsEpetra != bIsTpetra) && bIsBlocked == true);
459 
460  RCP<XpMat> A = Teuchos::null;
461  if (bIsBlocked) {
463  Teuchos::rcp_dynamic_cast<const Thyra::BlockedLinearOpBase<Scalar> >(fwdOp);
465 
466  TEUCHOS_TEST_FOR_EXCEPT(ThyBlockedOp->blockExists(0, 0) == false);
467 
468  Teuchos::RCP<const LinearOpBase<Scalar> > b00 = ThyBlockedOp->getBlock(0, 0);
470 
471  // wrap the forward operator as an Xpetra::Matrix that MueLu can work with
472  // MueLu needs a non-const object as input
473  RCP<XpMat> A00 = XpThyUtils::toXpetra(Teuchos::rcp_const_cast<LinearOpBase<Scalar> >(b00));
475 
476  RCP<const XpMap> rowmap00 = A00->getRowMap();
477  RCP<const Teuchos::Comm<int> > comm = rowmap00->getComm();
478 
479  // create a Xpetra::BlockedCrsMatrix which derives from Xpetra::Matrix that MueLu can work with
480  RCP<XpBlockedCrsMat> bMat = Teuchos::rcp(new XpBlockedCrsMat(ThyBlockedOp, comm));
482 
483  // save blocked matrix
484  A = bMat;
485  } else {
486  // wrap the forward operator as an Xpetra::Matrix that MueLu can work with
487  // MueLu needs a non-const object as input
488  A = XpThyUtils::toXpetra(Teuchos::rcp_const_cast<ThyLinOpBase>(fwdOp));
489  }
491 
492  // Retrieve concrete preconditioner object
493  const Teuchos::Ptr<DefaultPreconditioner<Scalar> > defaultPrec = Teuchos::ptr(dynamic_cast<DefaultPreconditioner<Scalar>*>(prec));
495 
496  // extract preconditioner operator
497  RCP<ThyLinOpBase> thyra_precOp = Teuchos::null;
498  thyra_precOp = rcp_dynamic_cast<Thyra::LinearOpBase<Scalar> >(defaultPrec->getNonconstUnspecifiedPrecOp(), true);
499 
500  // make a decision whether to (re)build the multigrid preconditioner or reuse the old one
501  // rebuild preconditioner if startingOver == true
502  // reuse preconditioner if startingOver == false
503  const bool startingOver = (thyra_precOp.is_null() || !paramList.isParameter("reuse: type") || paramList.get<std::string>("reuse: type") == "none");
504  bool useHalfPrecision = false;
505  if (paramList.isParameter("half precision"))
506  useHalfPrecision = paramList.get<bool>("half precision");
507  else if (paramList.isSublist("Hierarchy") && paramList.sublist("Hierarchy").isParameter("half precision"))
508  useHalfPrecision = paramList.sublist("Hierarchy").get<bool>("half precision");
509  if (useHalfPrecision)
510  TEUCHOS_TEST_FOR_EXCEPTION(!bIsTpetra, MueLu::Exceptions::RuntimeError, "The only scalar type Epetra knows is double, so a half precision preconditioner cannot be constructed.");
511 
512  RCP<XpOp> xpPrecOp;
513  if (startingOver == true) {
514  // Convert to Xpetra
515  std::list<std::string> convertXpetra = {"Coordinates", "Nullspace"};
516  for (auto it = convertXpetra.begin(); it != convertXpetra.end(); ++it)
517  Converters<Scalar, LocalOrdinal, GlobalOrdinal, Node>::replaceWithXpetra(paramList, *it);
518 
519  for (int lvlNo = 0; lvlNo < 10; ++lvlNo) {
520  if (paramList.isSublist("level " + std::to_string(lvlNo) + " user data")) {
521  ParameterList& lvlList = paramList.sublist("level " + std::to_string(lvlNo) + " user data");
522  std::list<std::string> convertKeys;
523  for (auto it = lvlList.begin(); it != lvlList.end(); ++it)
524  convertKeys.push_back(lvlList.name(it));
525  for (auto it = convertKeys.begin(); it != convertKeys.end(); ++it)
526  Converters<Scalar, LocalOrdinal, GlobalOrdinal, Node>::replaceWithXpetra(lvlList, *it);
527  }
528  }
529 
530  if (useHalfPrecision) {
531 #if defined(MUELU_CAN_USE_MIXED_PRECISION)
532 
533  // CAG: There is nothing special about the combination double-float,
534  // except that I feel somewhat confident that Trilinos builds
535  // with both scalar types.
536 
537  // convert to half precision
538  RCP<XphMat> halfA = Xpetra::convertToHalfPrecision(A);
539  const std::string userName = "user data";
540  Teuchos::ParameterList& userParamList = paramList.sublist(userName);
541  if (userParamList.isType<RCP<XpmMV> >("Coordinates")) {
542  RCP<XpmMV> coords = userParamList.get<RCP<XpmMV> >("Coordinates");
543  userParamList.remove("Coordinates");
544  RCP<XphmMV> halfCoords = Xpetra::convertToHalfPrecision(coords);
545  userParamList.set("Coordinates", halfCoords);
546  }
547  if (userParamList.isType<RCP<XpMV> >("Nullspace")) {
548  RCP<XpMV> nullspace = userParamList.get<RCP<XpMV> >("Nullspace");
549  userParamList.remove("Nullspace");
550  RCP<XphMV> halfNullspace = Xpetra::convertToHalfPrecision(nullspace);
551  userParamList.set("Nullspace", halfNullspace);
552  }
553  if (paramList.isType<RCP<XpmMV> >("Coordinates")) {
554  RCP<XpmMV> coords = paramList.get<RCP<XpmMV> >("Coordinates");
555  paramList.remove("Coordinates");
556  RCP<XphmMV> halfCoords = Xpetra::convertToHalfPrecision(coords);
557  userParamList.set("Coordinates", halfCoords);
558  }
559  if (paramList.isType<RCP<XpMV> >("Nullspace")) {
560  RCP<XpMV> nullspace = paramList.get<RCP<XpMV> >("Nullspace");
561  paramList.remove("Nullspace");
562  RCP<XphMV> halfNullspace = Xpetra::convertToHalfPrecision(nullspace);
563  userParamList.set("Nullspace", halfNullspace);
564  }
565 
566  // build a new half-precision MueLu preconditioner
567 
568  RCP<MueLu::Hierarchy<HalfScalar, LocalOrdinal, GlobalOrdinal, Node> > H = MueLu::CreateXpetraPreconditioner(halfA, paramList);
569  RCP<MueLuHalfXpOp> xpOp = rcp(new MueLuHalfXpOp(H));
570  xpPrecOp = rcp(new XpHalfPrecOp(xpOp));
571 #else
573 #endif
574  } else {
575  const std::string userName = "user data";
576  Teuchos::ParameterList& userParamList = paramList.sublist(userName);
577  if (paramList.isType<RCP<XpmMV> >("Coordinates")) {
578  RCP<XpmMV> coords = paramList.get<RCP<XpmMV> >("Coordinates");
579  paramList.remove("Coordinates");
580  userParamList.set("Coordinates", coords);
581  }
582  if (paramList.isType<RCP<XpMV> >("Nullspace")) {
583  RCP<XpMV> nullspace = paramList.get<RCP<XpMV> >("Nullspace");
584  paramList.remove("Nullspace");
585  userParamList.set("Nullspace", nullspace);
586  }
587 
588  // build a new MueLu RefMaxwell preconditioner
589  RCP<MueLu::Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node> > H = MueLu::CreateXpetraPreconditioner(A, paramList);
590  xpPrecOp = rcp(new MueLuXpOp(H));
591  }
592  } else {
593  // reuse old MueLu hierarchy stored in MueLu Xpetra operator and put in new matrix
594  RCP<ThyXpOp> thyXpOp = rcp_dynamic_cast<ThyXpOp>(thyra_precOp, true);
595  xpPrecOp = rcp_dynamic_cast<XpOp>(thyXpOp->getXpetraOperator(), true);
596 #if defined(MUELU_CAN_USE_MIXED_PRECISION)
597  RCP<XpHalfPrecOp> xpHalfPrecOp = rcp_dynamic_cast<XpHalfPrecOp>(xpPrecOp);
598  if (!xpHalfPrecOp.is_null()) {
599  RCP<MueLu::Hierarchy<HalfScalar, LocalOrdinal, GlobalOrdinal, Node> > H = rcp_dynamic_cast<MueLuHalfXpOp>(xpHalfPrecOp->GetHalfPrecisionOperator(), true)->GetHierarchy();
600  RCP<XphMat> halfA = Xpetra::convertToHalfPrecision(A);
601 
603  "Thyra::MueLuPreconditionerFactory: Hierarchy has no levels in it");
604  TEUCHOS_TEST_FOR_EXCEPTION(!H->GetLevel(0)->IsAvailable("A"), MueLu::Exceptions::RuntimeError,
605  "Thyra::MueLuPreconditionerFactory: Hierarchy has no fine level operator");
606  RCP<MueLu::Level> level0 = H->GetLevel(0);
607  RCP<XpHalfOp> O0 = level0->Get<RCP<XpHalfOp> >("A");
608  RCP<XphMat> A0 = rcp_dynamic_cast<XphMat>(O0, true);
609 
610  if (!A0.is_null()) {
611  // If a user provided a "number of equations" argument in a parameter list
612  // during the initial setup, we must honor that settings and reuse it for
613  // all consequent setups.
614  halfA->SetFixedBlockSize(A0->GetFixedBlockSize());
615  }
616 
617  // set new matrix
618  level0->Set("A", halfA);
619 
620  H->SetupRe();
621  } else
622 #endif
623  {
624  // get old MueLu hierarchy
625  RCP<MueLuXpOp> xpOp = rcp_dynamic_cast<MueLuXpOp>(thyXpOp->getXpetraOperator(), true);
626  RCP<MueLu::Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node> > H = xpOp->GetHierarchy();
627  ;
628 
630  "Thyra::MueLuPreconditionerFactory: Hierarchy has no levels in it");
631  TEUCHOS_TEST_FOR_EXCEPTION(!H->GetLevel(0)->IsAvailable("A"), MueLu::Exceptions::RuntimeError,
632  "Thyra::MueLuPreconditionerFactory: Hierarchy has no fine level operator");
633  RCP<MueLu::Level> level0 = H->GetLevel(0);
634  RCP<XpOp> O0 = level0->Get<RCP<XpOp> >("A");
635  RCP<XpMat> A0 = rcp_dynamic_cast<XpMat>(O0);
636 
637  if (!A0.is_null()) {
638  // If a user provided a "number of equations" argument in a parameter list
639  // during the initial setup, we must honor that settings and reuse it for
640  // all consequent setups.
641  A->SetFixedBlockSize(A0->GetFixedBlockSize());
642  }
643 
644  // set new matrix
645  level0->Set("A", A);
646 
647  H->SetupRe();
648  }
649  }
650 
651  // wrap preconditioner in thyraPrecOp
652  RCP<const VectorSpaceBase<Scalar> > thyraRangeSpace = Xpetra::ThyraUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::toThyra(xpPrecOp->getRangeMap());
653  RCP<const VectorSpaceBase<Scalar> > thyraDomainSpace = Xpetra::ThyraUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::toThyra(xpPrecOp->getDomainMap());
654 
655  RCP<ThyLinOpBase> thyraPrecOp = Thyra::xpetraLinearOp<Scalar, LocalOrdinal, GlobalOrdinal, Node>(thyraRangeSpace, thyraDomainSpace, xpPrecOp);
657 
658  defaultPrec->initializeUnspecified(thyraPrecOp);
659 }
660 
661 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
662 void MueLuPreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
663  uninitializePrec(PreconditionerBase<Scalar>* prec, RCP<const LinearOpSourceBase<Scalar> >* fwdOp, ESupportSolveUse* supportSolveUse) const {
664  TEUCHOS_ASSERT(prec);
665 
666  // Retrieve concrete preconditioner object
667  const Teuchos::Ptr<DefaultPreconditioner<Scalar> > defaultPrec = Teuchos::ptr(dynamic_cast<DefaultPreconditioner<Scalar>*>(prec));
669 
670  if (fwdOp) {
671  // TODO: Implement properly instead of returning default value
672  *fwdOp = Teuchos::null;
673  }
674 
675  if (supportSolveUse) {
676  // TODO: Implement properly instead of returning default value
677  *supportSolveUse = Thyra::SUPPORT_SOLVE_UNSPECIFIED;
678  }
679 
680  defaultPrec->uninitialize();
681 }
682 
683 // Overridden from ParameterListAcceptor
684 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
685 void MueLuPreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::setParameterList(RCP<ParameterList> const& paramList) {
687  paramList_ = paramList;
688 }
689 
690 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
691 RCP<ParameterList> MueLuPreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getNonconstParameterList() {
692  return paramList_;
693 }
694 
695 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
696 RCP<ParameterList> MueLuPreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::unsetParameterList() {
697  RCP<ParameterList> savedParamList = paramList_;
698  paramList_ = Teuchos::null;
699  return savedParamList;
700 }
701 
702 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
703 RCP<const ParameterList> MueLuPreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getParameterList() const {
704  return paramList_;
705 }
706 
707 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
708 RCP<const ParameterList> MueLuPreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getValidParameters() const {
709  static RCP<const ParameterList> validPL;
710 
711  if (Teuchos::is_null(validPL))
712  validPL = rcp(new ParameterList());
713 
714  return validPL;
715 }
716 
717 // Public functions overridden from Teuchos::Describable
718 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
719 std::string MueLuPreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::description() const {
720  return "Thyra::MueLuPreconditionerFactory";
721 }
722 } // namespace Thyra
723 
724 #endif // HAVE_MUELU_STRATIMIKOS
725 
726 #endif // ifdef THYRA_MUELU_PRECONDITIONER_FACTORY_DEF_HPP
MueLu::DefaultLocalOrdinal LocalOrdinal
bool is_null(const boost::shared_ptr< T > &p)
T & get(const std::string &name, T def_value)
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
bool nonnull(const std::shared_ptr< T > &p)
bool is_null(const std::shared_ptr< T > &p)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
MueLu::DefaultNode Node
static RCP< Time > getNewTimer(const std::string &name)
Teuchos::RCP< MueLu::Hierarchy< Scalar, LocalOrdinal, GlobalOrdinal, Node > > CreateXpetraPreconditioner(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node >> op, const Teuchos::ParameterList &inParamList)
Helper function to create a MueLu preconditioner that can be used by Xpetra.Given an Xpetra::Matrix...
void deep_copy(MultiVector< DS, DL, DG, DN > &dst, const MultiVector< SS, SL, SG, SN > &src)
bool remove(std::string const &name, bool throwIfNotExists=true)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
MueLu::DefaultScalar Scalar
Concrete Thyra::LinearOpBase subclass for Xpetra::Operator.
RCP< const CrsGraph< int, GlobalOrdinal, Node > > toXpetra(const Epetra_CrsGraph &g)
bool isType(const std::string &name) const
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
static RCP< Matrix > Build(const RCP< const Map > &rowMap, size_t maxNumEntriesPerRow, Xpetra::ProfileType pftype=Xpetra::DynamicProfile)
Exception throws to report errors in the internal logical of the program.
#define TEUCHOS_ASSERT(assertion_test)
RCP< Tpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > > getOperator()
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
Wraps an existing MueLu::Hierarchy as a Xpetra::Operator.