Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Thyra_BelosLinearOpWithSolve_def.hpp
Go to the documentation of this file.
1 /*
2 // @HEADER
3 // ***********************************************************************
4 //
5 // Stratimikos: Thyra-based strategies for linear solvers
6 // Copyright (2006) Sandia Corporation
7 //
8 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
9 // license for use of this work by or on behalf of the U.S. Government.
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 Roscoe A. Bartlett (rabartl@sandia.gov)
39 //
40 // ***********************************************************************
41 // @HEADER
42 */
43 
44 
45 #ifndef THYRA_BELOS_LINEAR_OP_WITH_SOLVE_HPP
46 #define THYRA_BELOS_LINEAR_OP_WITH_SOLVE_HPP
47 
49 #include "Thyra_GeneralSolveCriteriaBelosStatusTest.hpp"
50 #include "Thyra_LinearOpWithSolveHelpers.hpp"
52 #include "Teuchos_Assert.hpp"
53 #include "Teuchos_TimeMonitor.hpp"
54 #include "Stratimikos_Config.h"
55 #ifdef HAVE_STRATIMIKOS_THYRATPETRAADAPTERS
57 # include <MatrixMarket_Tpetra.hpp>
58 # include <TpetraExt_MatrixMatrix.hpp>
59 #endif
60 
61 namespace {
62  // Set the Belos solver's parameter list to scale its residual norms
63  // in the specified way.
64  //
65  // We break this out in a separate function because the parameters
66  // to set depend on which parameters the Belos solver supports. Not
67  // all Belos solvers support both the "Implicit Residual Scaling"
68  // and "Explicit Residual Scaling" parameters, so we have to check
69  // the solver's list of valid parameters for the existence of these.
70  //
71  // Scaling options: Belos lets you decide whether the solver will
72  // scale residual norms by the (left-)preconditioned initial
73  // residual norms (residualScalingType = "Norm of Initial
74  // Residual"), or by the unpreconditioned initial residual norms
75  // (residualScalingType = "Norm of RHS"). Usually you want to scale
76  // by the unpreconditioned initial residual norms. This is because
77  // preconditioning is just an optimization, and you really want to
78  // make ||B - AX|| small, rather than ||M B - M (A X)||. If you're
79  // measuring ||B - AX|| and scaling by the initial residual, you
80  // should use the unpreconditioned initial residual to match it.
81  //
82  // Note, however, that the implicit residual test computes
83  // left-preconditioned residuals, if a left preconditioner was
84  // provided. That's OK because when Belos solvers (at least the
85  // GMRES variants) are given a left preconditioner, they first check
86  // the implicit residuals. If those converge, they then check the
87  // explicit residuals. The explicit residual test does _not_ apply
88  // the left preconditioner when computing the residual. The
89  // implicit residual test is just an optimization so that Belos
90  // doesn't have to compute explicit residuals B - A*X at every
91  // iteration. This is why we use the same scaling factor for both
92  // the implicit and explicit residuals.
93  //
94  // Arguments:
95  //
96  // solverParams [in/out] Parameters for the current solve.
97  //
98  // solverValidParams [in] Valid parameter list for the Belos solver.
99  // Result of calling the solver's getValidParameters() method.
100  //
101  // residualScalingType [in] String describing how the solver should
102  // scale residuals. Valid values include "Norm of RHS" and "Norm
103  // of Initial Residual" (these are the only two options this file
104  // currently uses, though Belos offers other options).
105  void
106  setResidualScalingType (const Teuchos::RCP<Teuchos::ParameterList>& solverParams,
107  const Teuchos::RCP<const Teuchos::ParameterList>& solverValidParams,
108  const std::string& residualScalingType)
109  {
110  // Many Belos solvers (especially the GMRES variants) define both
111  // "Implicit Residual Scaling" and "Explicit Residual Scaling"
112  // options.
113  //
114  // "Implicit" means "the left-preconditioned approximate
115  // a.k.a. 'recursive' residual as computed by the Krylov method."
116  //
117  // "Explicit" means ||B - A*X||, the unpreconditioned, "exact"
118  // residual.
119  //
120  // Belos' GMRES implementations chain these two tests in sequence.
121  // Implicit comes first, and explicit is not evaluated unless
122  // implicit passes. In some cases (e.g., no left preconditioner),
123  // GMRES _only_ uses the implicit tests. This means that only
124  // setting "Explicit Residual Scaling" won't change the solver's
125  // behavior. Stratimikos tends to prefer using a right
126  // preconditioner, in which case setting only the "Explicit
127  // Residual Scaling" argument has no effect. Furthermore, if
128  // "Explicit Residual Scaling" is set to something other than the
129  // default (initial residual norm), without "Implicit Residual
130  // Scaling" getting the same setting, then the implicit residual
131  // test will be using a radically different scaling factor than
132  // the user wanted.
133  //
134  // Not all Belos solvers support both options. We check the
135  // solver's valid parameter list first before attempting to set
136  // the option.
137  if (solverValidParams->isParameter ("Implicit Residual Scaling")) {
138  solverParams->set ("Implicit Residual Scaling", residualScalingType);
139  }
140  if (solverValidParams->isParameter ("Explicit Residual Scaling")) {
141  solverParams->set ("Explicit Residual Scaling", residualScalingType);
142  }
143  }
144 
145 } // namespace (anonymous)
146 
147 
148 namespace Thyra {
149 
150 
151 // Constructors/initializers/accessors
152 
153 
154 template<class Scalar>
156  :convergenceTestFrequency_(-1),
157  isExternalPrec_(false),
158  supportSolveUse_(SUPPORT_SOLVE_UNSPECIFIED),
159  defaultTol_ (-1.0),
160  label_(""),
161  filenameLHS_(""),
162  filenameRHS_(""),
163  counter_(0)
164 {}
165 
166 
167 template<class Scalar>
169  const RCP<Belos::LinearProblem<Scalar,MV_t,LO_t> > &lp,
170  const RCP<Teuchos::ParameterList> &solverPL,
171  const RCP<Belos::SolverManager<Scalar,MV_t,LO_t> > &iterativeSolver,
172  const RCP<const LinearOpSourceBase<Scalar> > &fwdOpSrc,
173  const RCP<const PreconditionerBase<Scalar> > &prec,
174  const bool isExternalPrec_in,
175  const RCP<const LinearOpSourceBase<Scalar> > &approxFwdOpSrc,
176  const ESupportSolveUse &supportSolveUse_in,
177  const int convergenceTestFrequency
178  )
179 {
180  using Teuchos::as;
183  typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType magnitude_type;
184 
185  this->setLinePrefix("BELOS/T");
186  // ToDo: Validate input
187  lp_ = lp;
188  solverPL_ = solverPL;
189  iterativeSolver_ = iterativeSolver;
190  fwdOpSrc_ = fwdOpSrc;
191  prec_ = prec;
192  isExternalPrec_ = isExternalPrec_in;
193  approxFwdOpSrc_ = approxFwdOpSrc;
194  supportSolveUse_ = supportSolveUse_in;
195  convergenceTestFrequency_ = convergenceTestFrequency;
196  // Check if "Convergence Tolerance" is in the solver parameter list. If
197  // not, use the default from the solver.
198  if ( !is_null(solverPL_) ) {
199  if (solverPL_->isParameter("Convergence Tolerance")) {
200 
201  // Stratimikos prefers tolerances as double, no matter the
202  // Scalar type. However, we also want it to accept the
203  // tolerance as magnitude_type, for example float if the Scalar
204  // type is float or std::complex<float>.
205  if (solverPL_->isType<double> ("Convergence Tolerance")) {
206  defaultTol_ =
207  as<magnitude_type> (solverPL_->get<double> ("Convergence Tolerance"));
208  }
209  else if (std::is_same_v<double, magnitude_type>) {
210  // magnitude_type == double in this case, and we've already
211  // checked double above.
213  true, std::invalid_argument, "BelosLinearOpWithSolve::initialize: "
214  "The \"Convergence Tolerance\" parameter, which you provided, must "
215  "have type double (the type of the magnitude of Scalar = double).");
216  }
217  else if (solverPL_->isType<magnitude_type> ("Convergence Tolerance")) {
218  defaultTol_ = solverPL_->get<magnitude_type> ("Convergence Tolerance");
219  }
220  else {
221  // Throwing InvalidParameterType ensures that the exception's
222  // type is consistent both with what this method would have
223  // thrown before for an unrecognized type, and with what the
224  // user expects in general when the parameter doesn't have the
225  // right type.
227  true, InvalidParameterType, "BelosLinearOpWithSolve::initialize: "
228  "The \"Convergence Tolerance\" parameter, which you provided, must "
229  "have type double (preferred) or the type of the magnitude of Scalar "
230  "= " << TypeNameTraits<Scalar>::name () << ", which is " <<
231  TypeNameTraits<magnitude_type>::name () << " in this case. You can "
232  "find that type using Teuchos::ScalarTraits<Scalar>::magnitudeType.");
233  }
234  }
235 
236  if (solverPL_->isParameter("Timer Label") && solverPL_->isType<std::string>("Timer Label")) {
237  label_ = solverPL_->get<std::string>("Timer Label");
238  lp_->setLabel(label_);
239  }
240  if (solverPL_->isParameter("Filename LHS") && solverPL_->isType<std::string>("Filename LHS")) {
241  filenameLHS_ = solverPL_->get<std::string>("Filename LHS");
242  }
243  if (solverPL_->isParameter("Filename RHS") && solverPL_->isType<std::string>("Filename RHS")) {
244  filenameRHS_ = solverPL_->get<std::string>("Filename RHS");
245  }
246  }
247  else {
249  iterativeSolver->getValidParameters();
250 
251  // Stratimikos prefers tolerances as double, no matter the
252  // Scalar type. However, we also want it to accept the
253  // tolerance as magnitude_type, for example float if the Scalar
254  // type is float or std::complex<float>.
255  if (defaultPL->isType<double> ("Convergence Tolerance")) {
256  defaultTol_ =
257  as<magnitude_type> (defaultPL->get<double> ("Convergence Tolerance"));
258  }
259  else if (std::is_same_v<double, magnitude_type>) {
260  // magnitude_type == double in this case, and we've already
261  // checked double above.
263  true, std::invalid_argument, "BelosLinearOpWithSolve::initialize: "
264  "The \"Convergence Tolerance\" parameter, which you provided, must "
265  "have type double (the type of the magnitude of Scalar = double).");
266  }
267  else if (defaultPL->isType<magnitude_type> ("Convergence Tolerance")) {
268  defaultTol_ = defaultPL->get<magnitude_type> ("Convergence Tolerance");
269  }
270  else {
271  // Throwing InvalidParameterType ensures that the exception's
272  // type is consistent both with what this method would have
273  // thrown before for an unrecognized type, and with what the
274  // user expects in general when the parameter doesn't have the
275  // right type.
277  true, InvalidParameterType, "BelosLinearOpWithSolve::initialize: "
278  "The \"Convergence Tolerance\" parameter, which you provided, must "
279  "have type double (preferred) or the type of the magnitude of Scalar "
280  "= " << TypeNameTraits<Scalar>::name () << ", which is " <<
281  TypeNameTraits<magnitude_type>::name () << " in this case. You can "
282  "find that type using Teuchos::ScalarTraits<Scalar>::magnitudeType.");
283  }
284  }
285 }
286 
287 
288 template<class Scalar>
291 {
293  _fwdOpSrc = fwdOpSrc_;
294  fwdOpSrc_ = Teuchos::null;
295  return _fwdOpSrc;
296 }
297 
298 
299 template<class Scalar>
302 {
304  _prec = prec_;
305  prec_ = Teuchos::null;
306  return _prec;
307 }
308 
309 
310 template<class Scalar>
312 {
313  return isExternalPrec_;
314 }
315 
316 
317 template<class Scalar>
320 {
322  _approxFwdOpSrc = approxFwdOpSrc_;
323  approxFwdOpSrc_ = Teuchos::null;
324  return _approxFwdOpSrc;
325 }
326 
327 
328 template<class Scalar>
330 {
331  return supportSolveUse_;
332 }
333 
334 
335 template<class Scalar>
337  RCP<Belos::LinearProblem<Scalar,MV_t,LO_t> > *lp,
338  RCP<Teuchos::ParameterList> *solverPL,
339  RCP<Belos::SolverManager<Scalar,MV_t,LO_t> > *iterativeSolver,
340  RCP<const LinearOpSourceBase<Scalar> > *fwdOpSrc,
341  RCP<const PreconditionerBase<Scalar> > *prec,
342  bool *isExternalPrec_in,
343  RCP<const LinearOpSourceBase<Scalar> > *approxFwdOpSrc,
344  ESupportSolveUse *supportSolveUse_in
345  )
346 {
347  if (lp) *lp = lp_;
348  if (solverPL) *solverPL = solverPL_;
349  if (iterativeSolver) *iterativeSolver = iterativeSolver_;
350  if (fwdOpSrc) *fwdOpSrc = fwdOpSrc_;
351  if (prec) *prec = prec_;
352  if (isExternalPrec_in) *isExternalPrec_in = isExternalPrec_;
353  if (approxFwdOpSrc) *approxFwdOpSrc = approxFwdOpSrc_;
354  if (supportSolveUse_in) *supportSolveUse_in = supportSolveUse_;
355 
356  lp_ = Teuchos::null;
357  solverPL_ = Teuchos::null;
358  iterativeSolver_ = Teuchos::null;
359  fwdOpSrc_ = Teuchos::null;
360  prec_ = Teuchos::null;
361  isExternalPrec_ = false;
362  approxFwdOpSrc_ = Teuchos::null;
363  supportSolveUse_ = SUPPORT_SOLVE_UNSPECIFIED;
364 }
365 
366 
367 // Overridden from LinearOpBase
368 
369 
370 template<class Scalar>
373 {
374  if (!is_null(lp_))
375  return lp_->getOperator()->range();
376  return Teuchos::null;
377 }
378 
379 
380 template<class Scalar>
383 {
384  if (!is_null(lp_))
385  return lp_->getOperator()->domain();
386  return Teuchos::null;
387 }
388 
389 
390 template<class Scalar>
393 {
394  return Teuchos::null; // Not supported yet but could be
395 }
396 
397 
398 // Overridden from Teuchos::Describable
399 
400 
401 template<class Scalar>
403 {
404  std::ostringstream oss;
406  if ( !is_null(lp_) && !is_null(lp_->getOperator()) ) {
407  oss << "{";
408  oss << "iterativeSolver=\'"<<iterativeSolver_->description()<<"\'";
409  oss << ",fwdOp=\'"<<lp_->getOperator()->description()<<"\'";
410  if (lp_->getLeftPrec().get())
411  oss << ",leftPrecOp=\'"<<lp_->getLeftPrec()->description()<<"\'";
412  if (lp_->getRightPrec().get())
413  oss << ",rightPrecOp=\'"<<lp_->getRightPrec()->description()<<"\'";
414  oss << "}";
415  }
416  // ToDo: Make Belos::SolverManager derive from Teuchos::Describable so
417  // that we can get better information.
418  return oss.str();
419 }
420 
421 
422 template<class Scalar>
424  Teuchos::FancyOStream &out_arg,
425  const Teuchos::EVerbosityLevel verbLevel
426  ) const
427 {
428  using Teuchos::FancyOStream;
429  using Teuchos::OSTab;
430  using Teuchos::describe;
431  RCP<FancyOStream> out = rcp(&out_arg,false);
432  OSTab tab(out);
433  switch (verbLevel) {
434  case Teuchos::VERB_DEFAULT: // fall-through
435  case Teuchos::VERB_LOW:
436  case Teuchos::VERB_MEDIUM: // fall-through
437  *out << this->description() << std::endl;
438  break;
439  case Teuchos::VERB_HIGH: // fall-through
441  {
442  *out
444  << "rangeDim=" << this->range()->dim()
445  << ",domainDim=" << this->domain()->dim() << "}\n";
446  if (lp_->getOperator().get()) {
447  OSTab tab1(out);
448  *out
449  << "iterativeSolver = "<<describe(*iterativeSolver_,verbLevel)
450  << "fwdOp = " << describe(*lp_->getOperator(),verbLevel);
451  if (lp_->getLeftPrec().get())
452  *out << "leftPrecOp = "<<describe(*lp_->getLeftPrec(),verbLevel);
453  if (lp_->getRightPrec().get())
454  *out << "rightPrecOp = "<<describe(*lp_->getRightPrec(),verbLevel);
455  }
456  break;
457  }
458  default:
459  TEUCHOS_TEST_FOR_EXCEPT(true); // Should never get here!
460  }
461 }
462 
463 
464 // protected
465 
466 
467 // Overridden from LinearOpBase
468 
469 
470 template<class Scalar>
472 {
473  return ::Thyra::opSupported(*lp_->getOperator(),M_trans);
474 }
475 
476 
477 template<class Scalar>
479  const EOpTransp M_trans,
480  const MultiVectorBase<Scalar> &X,
481  const Ptr<MultiVectorBase<Scalar> > &Y,
482  const Scalar alpha,
483  const Scalar beta
484  ) const
485 {
486  ::Thyra::apply<Scalar>(*lp_->getOperator(), M_trans, X, Y, alpha, beta);
487 }
488 
489 
490 // Overridden from LinearOpWithSolveBase
491 
492 
493 template<class Scalar>
494 bool
496 {
497  return solveSupportsNewImpl(M_trans, Teuchos::null);
498 }
499 
500 
501 template<class Scalar>
502 bool
504  const Ptr<const SolveCriteria<Scalar> > /* solveCriteria */) const
505 {
506  // Only support forward solve right now!
507  if (real_trans(transp)==NOTRANS) return true;
508  return false; // ToDo: Support adjoint solves!
509  // Otherwise, Thyra/Belos now supports every solve criteria type that exists
510  // because of the class Thyra::GeneralSolveCriteriaBelosStatusTest!
511 /*
512  if (real_trans(M_trans)==NOTRANS) {
513  return (
514  solveMeasureType.useDefault()
515  ||
516  solveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL,SOLVE_MEASURE_NORM_RHS)
517  ||
518  solveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL,SOLVE_MEASURE_NORM_INIT_RESIDUAL)
519  );
520  }
521 */
522 }
523 
524 
525 template<class Scalar>
526 bool
528  EOpTransp M_trans, const SolveMeasureType& solveMeasureType) const
529 {
530  SolveCriteria<Scalar> solveCriteria(solveMeasureType, SolveCriteria<Scalar>::unspecifiedTolerance());
531  return solveSupportsNewImpl(M_trans, Teuchos::constOptInArg(solveCriteria));
532 }
533 
534 
535 template<class Scalar>
536 SolveStatus<Scalar>
538  const EOpTransp M_trans,
539  const MultiVectorBase<Scalar> &B,
540  const Ptr<MultiVectorBase<Scalar> > &X,
541  const Ptr<const SolveCriteria<Scalar> > solveCriteria
542  ) const
543 {
544 
545  THYRA_FUNC_TIME_MONITOR("Stratimikos: BelosLOWS");
546 
547  using Teuchos::rcp;
548  using Teuchos::rcpFromRef;
549  using Teuchos::rcpFromPtr;
550  using Teuchos::FancyOStream;
551  using Teuchos::OSTab;
553  using Teuchos::parameterList;
554  using Teuchos::describe;
556  typedef typename ST::magnitudeType ScalarMag;
557  Teuchos::Time totalTimer(""), timer("");
558  totalTimer.start(true);
559 
560  assertSolveSupports(*this, M_trans, solveCriteria);
561  // 2010/08/22: rabartl: Bug 4915 ToDo: Move the above into the NIV function
562  // solve(...).
563 
564  const RCP<FancyOStream> out = this->getOStream();
565  const Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
566  OSTab tab = this->getOSTab();
567  if (out.get() && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_LOW)) {
568  *out << "\nStarting iterations with Belos:\n";
569  OSTab tab2(out);
570  *out << "Using forward operator = " << describe(*fwdOpSrc_->getOp(),verbLevel);
571  *out << "Using iterative solver = " << describe(*iterativeSolver_,verbLevel);
572  *out << "With #Eqns="<<B.range()->dim()<<", #RHSs="<<B.domain()->dim()<<" ...\n";
573  }
574 
575 #ifdef HAVE_STRATIMIKOS_THYRATPETRAADAPTERS
576  //
577  // Write RHS and LHS to file if desired
578  //
579  if (filenameLHS_ != "") {
580  try {
582  Tpetra::MatrixMarket::Writer<::Tpetra::CrsMatrix<Scalar> >::writeDenseFile(filenameLHS_+ "." + label_ + "." + std::to_string(counter_), *tmv, "", "");
583  } catch (const std::logic_error&) {
584  *out << "Warning: Cannot write LHS multivector to file.\n";
585  }
586  }
587  if (filenameRHS_ != "") {
588  try {
590  Tpetra::MatrixMarket::Writer<::Tpetra::CrsMatrix<Scalar> >::writeDenseFile(filenameRHS_+ "." + label_ + "." + std::to_string(counter_), *tmv, "", "");
591  } catch (const std::logic_error&) {
592  *out << "Warning: Cannot write RHS multivector to file.\n";
593  }
594  }
595  ++counter_;
596 #endif
597 
598  //
599  // Set RHS and LHS
600  //
601 
602  bool ret = lp_->setProblem( rcpFromPtr(X), rcpFromRef(B) );
604  ret == false, CatastrophicSolveFailure
605  ,"Error, the Belos::LinearProblem could not be set for the current solve!"
606  );
607 
608  //
609  // Set the solution criteria
610  //
611 
612  // Parameter list for the current solve.
613  const RCP<ParameterList> tmpPL = Teuchos::parameterList();
614 
615  // The solver's valid parameter list.
616  RCP<const ParameterList> validPL = iterativeSolver_->getValidParameters();
617 
618  SolveMeasureType solveMeasureType;
619  RCP<GeneralSolveCriteriaBelosStatusTest<Scalar> > generalSolveCriteriaBelosStatusTest;
620  if (nonnull(solveCriteria)) {
621  solveMeasureType = solveCriteria->solveMeasureType;
622  const ScalarMag requestedTol = solveCriteria->requestedTol;
623  if (solveMeasureType.useDefault()) {
624  tmpPL->set("Convergence Tolerance", defaultTol_);
625  }
626  else if (solveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL, SOLVE_MEASURE_NORM_RHS)) {
627  if (requestedTol != SolveCriteria<Scalar>::unspecifiedTolerance()) {
628  tmpPL->set("Convergence Tolerance", requestedTol);
629  }
630  else {
631  tmpPL->set("Convergence Tolerance", defaultTol_);
632  }
633  setResidualScalingType (tmpPL, validPL, "Norm of RHS");
634  }
635  else if (solveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL, SOLVE_MEASURE_NORM_INIT_RESIDUAL)) {
636  if (requestedTol != SolveCriteria<Scalar>::unspecifiedTolerance()) {
637  tmpPL->set("Convergence Tolerance", requestedTol);
638  }
639  else {
640  tmpPL->set("Convergence Tolerance", defaultTol_);
641  }
642  setResidualScalingType (tmpPL, validPL, "Norm of Initial Residual");
643  }
644  else {
645  // Set the most generic (and inefficient) solve criteria
646  generalSolveCriteriaBelosStatusTest = createGeneralSolveCriteriaBelosStatusTest(
647  *solveCriteria, convergenceTestFrequency_);
648  // Set the verbosity level (one level down)
649  generalSolveCriteriaBelosStatusTest->setOStream(out);
650  generalSolveCriteriaBelosStatusTest->setVerbLevel(incrVerbLevel(verbLevel, -1));
651  // Set the default convergence tolerance to always converged to allow
652  // the above status test to control things.
653  tmpPL->set("Convergence Tolerance", 1.0);
654  }
655  // maximum iterations
656  if (nonnull(solveCriteria->extraParameters)) {
657  if (Teuchos::isParameterType<int>(*solveCriteria->extraParameters,"Maximum Iterations")) {
658  tmpPL->set("Maximum Iterations", Teuchos::get<int>(*solveCriteria->extraParameters,"Maximum Iterations"));
659  }
660  }
661  // If a preconditioner is on the left, then the implicit residual test
662  // scaling should be the preconditioned initial residual.
663  if (Teuchos::nonnull(lp_->getLeftPrec()) &&
664  validPL->isParameter ("Implicit Residual Scaling"))
665  tmpPL->set("Implicit Residual Scaling",
666  "Norm of Preconditioned Initial Residual");
667  }
668  else {
669  // No solveCriteria was even passed in!
670  tmpPL->set("Convergence Tolerance", defaultTol_);
671  }
672 
673  //
674  // Solve the linear system
675  //
676 
677  Belos::ReturnType belosSolveStatus;
678  {
679  // Write detailed convergence information if requested for levels >= VERB_LOW
681  outUsed =
682  ( static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_LOW)
683  ? out
685  );
686  Teuchos::OSTab tab1(outUsed,1,"BELOS");
687  tmpPL->set("Output Stream", outUsed);
688  iterativeSolver_->setParameters(tmpPL);
689  if (nonnull(generalSolveCriteriaBelosStatusTest)) {
690  iterativeSolver_->setUserConvStatusTest(generalSolveCriteriaBelosStatusTest);
691  }
692  try {
693  belosSolveStatus = iterativeSolver_->solve();
694  }
695  catch (Belos::BelosError& ex) {
697  CatastrophicSolveFailure,
698  ex.what() );
699  }
700  }
701 
702  //
703  // Report the solve status
704  //
705 
706  totalTimer.stop();
707 
708  SolveStatus<Scalar> solveStatus;
709 
710  switch (belosSolveStatus) {
711  case Belos::Unconverged: {
712  solveStatus.solveStatus = SOLVE_STATUS_UNCONVERGED;
713  // Set achievedTol even if the solver did not converge. This is
714  // helpful for things like nonlinear solvers, which might be
715  // able to use a partially converged result, and which would
716  // like to know the achieved convergence tolerance for use in
717  // computing bounds. It's also helpful for estimating whether a
718  // small increase in the maximum iteration count might be
719  // helpful next time.
720  try {
721  // Some solvers might not have implemented achievedTol().
722  // The default implementation throws std::runtime_error.
723  solveStatus.achievedTol = iterativeSolver_->achievedTol();
724  } catch (std::runtime_error&) {
725  // Do nothing; use the default value of achievedTol.
726  }
727  break;
728  }
729  case Belos::Converged: {
730  solveStatus.solveStatus = SOLVE_STATUS_CONVERGED;
731  if (nonnull(generalSolveCriteriaBelosStatusTest)) {
732  // The user set a custom status test. This means that we
733  // should ask the custom status test itself, rather than the
734  // Belos solver, what the final achieved convergence tolerance
735  // was.
736  const ArrayView<const ScalarMag> achievedTol =
737  generalSolveCriteriaBelosStatusTest->achievedTol();
738  solveStatus.achievedTol = Teuchos::ScalarTraits<ScalarMag>::zero();
739  for (Ordinal i = 0; i < achievedTol.size(); ++i) {
740  solveStatus.achievedTol = std::max(solveStatus.achievedTol, achievedTol[i]);
741  }
742  }
743  else {
744  try {
745  // Some solvers might not have implemented achievedTol().
746  // The default implementation throws std::runtime_error.
747  solveStatus.achievedTol = iterativeSolver_->achievedTol();
748  } catch (std::runtime_error&) {
749  // Use the default convergence tolerance. This is a correct
750  // upper bound, since we did actually converge.
751  solveStatus.achievedTol = tmpPL->get("Convergence Tolerance", defaultTol_);
752  }
753  }
754  break;
755  }
757  }
758 
759  std::ostringstream ossmessage;
760  ossmessage
761  << "The Belos solver " << (label_ != "" ? ("\"" + label_ + "\" ") : "")
762  << "of type \""<<iterativeSolver_->description()
763  <<"\" returned a solve status of \""<< toString(solveStatus.solveStatus) << "\""
764  << " in " << iterativeSolver_->getNumIters() << " iterations"
765  << " with total CPU time of " << totalTimer.totalElapsedTime() << " sec" ;
766  if (out.get() && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_LOW))
767  *out << "\n" << ossmessage.str() << "\n";
768 
769  solveStatus.message = ossmessage.str();
770 
771  // Dump the getNumIters() and the achieved convergence tolerance
772  // into solveStatus.extraParameters, as the "Belos/Iteration Count"
773  // resp. "Belos/Achieved Tolerance" parameters.
774  if (solveStatus.extraParameters.is_null()) {
775  solveStatus.extraParameters = parameterList ();
776  }
777  solveStatus.extraParameters->set ("Belos/Iteration Count",
778  iterativeSolver_->getNumIters());\
779  // package independent version of the same
780  solveStatus.extraParameters->set ("Iteration Count",
781  iterativeSolver_->getNumIters());\
782  // NOTE (mfh 13 Dec 2011) Though the most commonly used Belos
783  // solvers do implement achievedTol(), some Belos solvers currently
784  // do not. In the latter case, if the solver did not converge, the
785  // reported achievedTol() value may just be the default "invalid"
786  // value -1, and if the solver did converge, the reported value will
787  // just be the convergence tolerance (a correct upper bound).
788  solveStatus.extraParameters->set ("Belos/Achieved Tolerance",
789  solveStatus.achievedTol);
790 
791 // This information is in the previous line, which is printed anytime the verbosity
792 // is not set to Teuchos::VERB_NONE, so I'm commenting this out for now.
793 // if (out.get() && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_NONE))
794 // *out << "\nTotal solve time in Belos = "<<totalTimer.totalElapsedTime()<<" sec\n";
795 
796  return solveStatus;
797 
798 }
799 
800 
801 } // end namespace Thyra
802 
803 
804 #endif // THYRA_BELOS_LINEAR_OP_WITH_SOLVE_HPP
virtual bool solveSupportsImpl(EOpTransp M_trans) const
RCP< const VectorSpaceBase< Scalar > > domain() const
const std::string toString(const EAdjointEpetraOp adjointEpetraOp)
bool is_null(const boost::shared_ptr< T > &p)
virtual SolveStatus< Scalar > solveImpl(const EOpTransp transp, const MultiVectorBase< Scalar > &B, const Ptr< MultiVectorBase< Scalar > > &X, const Ptr< const SolveCriteria< Scalar > > solveCriteria) const
RCP< const LinearOpSourceBase< Scalar > > extract_approxFwdOpSrc()
T & get(ParameterList &l, const std::string &name)
void initialize(const RCP< Belos::LinearProblem< Scalar, MV_t, LO_t > > &lp, const RCP< Teuchos::ParameterList > &solverPL, const RCP< Belos::SolverManager< Scalar, MV_t, LO_t > > &iterativeSolver, const RCP< const LinearOpSourceBase< Scalar > > &fwdOpSrc, const RCP< const PreconditionerBase< Scalar > > &prec, const bool isExternalPrec, const RCP< const LinearOpSourceBase< Scalar > > &approxFwdOpSrc, const ESupportSolveUse &supportSolveUse, const int convergenceTestFrequency)
Initializes given precreated solver objects.
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)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
RCP< const PreconditionerBase< Scalar > > extract_prec()
virtual bool solveSupportsNewImpl(EOpTransp transp, const Ptr< const SolveCriteria< Scalar > > solveCriteria) const
T * get() const
RCP< const VectorSpaceBase< Scalar > > range() const
virtual void applyImpl(const EOpTransp M_trans, const MultiVectorBase< Scalar > &X, const Ptr< MultiVectorBase< Scalar > > &Y, const Scalar alpha, const Scalar beta) const
basic_OSTab< char > OSTab
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
bool isParameter(const std::string &name) const
static RCP< Tpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > getTpetraMultiVector(const RCP< MultiVectorBase< Scalar > > &mv)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
#define TEUCHOS_SWITCH_DEFAULT_DEBUG_ASSERT()
virtual std::string description() const
TypeTo as(const TypeFrom &t)
ParameterList & setParameters(const ParameterList &source)
RCP< const LinearOpSourceBase< Scalar > > extract_fwdOpSrc()
TEUCHOSCORE_LIB_DLL_EXPORT EVerbosityLevel incrVerbLevel(const EVerbosityLevel inputVerbLevel, const int numLevels)
bool nonnull(const boost::shared_ptr< T > &p)
basic_FancyOStream< char > FancyOStream
bool isType(const std::string &name) const
static RCP< const Tpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > getConstTpetraMultiVector(const RCP< const MultiVectorBase< Scalar > > &mv)
BelosLinearOpWithSolve()
Construct to unintialize.
void uninitialize(RCP< Belos::LinearProblem< Scalar, MV_t, LO_t > > *lp=NULL, RCP< Teuchos::ParameterList > *solverPL=NULL, RCP< Belos::SolverManager< Scalar, MV_t, LO_t > > *iterativeSolver=NULL, RCP< const LinearOpSourceBase< Scalar > > *fwdOpSrc=NULL, RCP< const PreconditionerBase< Scalar > > *prec=NULL, bool *isExternalPrec=NULL, RCP< const LinearOpSourceBase< Scalar > > *approxFwdOpSrc=NULL, ESupportSolveUse *supportSolveUse=NULL)
Uninitializes and returns stored quantities.
RCP< const LinearOpBase< Scalar > > clone() const
virtual bool opSupportedImpl(EOpTransp M_trans) const
Teuchos_Ordinal Ordinal
virtual bool solveSupportsSolveMeasureTypeImpl(EOpTransp M_trans, const SolveMeasureType &solveMeasureType) const
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)