Belos Version of the Day
Loading...
Searching...
No Matches
BelosGmresPolyOp.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Belos: Block Linear Solvers Package
4//
5// Copyright 2004-2016 NTESS and the Belos contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef BELOS_GMRESPOLYOP_HPP
11#define BELOS_GMRESPOLYOP_HPP
12
17#include "BelosConfigDefs.hpp"
19#include "BelosTypes.hpp"
20
21#include "BelosOperator.hpp"
22#include "BelosMultiVec.hpp"
26
30
35
37
38#include "Teuchos_BLAS.hpp"
39#include "Teuchos_LAPACK.hpp"
40#include "Teuchos_as.hpp"
41#include "Teuchos_RCP.hpp"
42#include "Teuchos_SerialDenseMatrix.hpp"
43#include "Teuchos_SerialDenseVector.hpp"
44#include "Teuchos_SerialDenseSolver.hpp"
45#include "Teuchos_ParameterList.hpp"
46
47#ifdef BELOS_TEUCHOS_TIME_MONITOR
48 #include "Teuchos_TimeMonitor.hpp"
49#endif // BELOS_TEUCHOS_TIME_MONITOR
50
51namespace Belos {
52
59 class GmresPolyOpOrthoFailure : public BelosError {public:
61 {}};
62
63 // Create a shell class for the MV, inherited off MultiVec<> that will operate with the GmresPolyOp.
64 template <class ScalarType, class MV, class DM = DefaultDenseMatrix<int, ScalarType>>
65 class GmresPolyMv : public MultiVec< ScalarType, DM >
66 {
67 public:
68
69 GmresPolyMv ( const Teuchos::RCP<MV>& mv_in )
70 : mv_(mv_in)
71 {}
72 GmresPolyMv ( const Teuchos::RCP<const MV>& mv_in )
73 {
74 mv_ = Teuchos::rcp_const_cast<MV>( mv_in );
75 }
76 Teuchos::RCP<MV> getMV() { return mv_; }
77 Teuchos::RCP<const MV> getConstMV() const { return mv_; }
78
79 GmresPolyMv * Clone ( const int numvecs ) const
80 {
81 GmresPolyMv * newMV = new GmresPolyMv( MVT::Clone( *mv_, numvecs ) );
82 return newMV;
83 }
85 {
86 GmresPolyMv * newMV = new GmresPolyMv( MVT::CloneCopy( *mv_ ) );
87 return newMV;
88 }
89 GmresPolyMv * CloneCopy ( const std::vector<int>& index ) const
90 {
91 GmresPolyMv * newMV = new GmresPolyMv( MVT::CloneCopy( *mv_, index ) );
92 return newMV;
93 }
94 GmresPolyMv * CloneViewNonConst ( const std::vector<int>& index )
95 {
96 GmresPolyMv * newMV = new GmresPolyMv( MVT::CloneViewNonConst( *mv_, index ) );
97 return newMV;
98 }
99 const GmresPolyMv * CloneView ( const std::vector<int>& index ) const
100 {
101 const GmresPolyMv * newMV = new GmresPolyMv( MVT::CloneView( *mv_, index ) );
102 return newMV;
103 }
104 ptrdiff_t GetGlobalLength () const { return MVT::GetGlobalLength( *mv_ ); }
105 int GetNumberVecs () const { return MVT::GetNumberVecs( *mv_ ); }
106 void MvTimesMatAddMv (const ScalarType alpha,
108 const DM& B, const ScalarType beta)
109 {
111 MVT::MvTimesMatAddMv( alpha, *(A_in.getConstMV()), B, beta, *mv_ );
112 }
113 void MvAddMv ( const ScalarType alpha, const MultiVec<ScalarType, DM>& A, const ScalarType beta, const MultiVec<ScalarType, DM>& B )
114 {
117 MVT::MvAddMv( alpha, *(A_in.getConstMV()), beta, *(B_in.getConstMV()), *mv_ );
118 }
119 void MvScale ( const ScalarType alpha ) { MVT::MvScale( *mv_, alpha ); }
120 void MvScale ( const std::vector<ScalarType>& alpha ) { MVT::MvScale( *mv_, alpha ); }
121 void MvTransMv ( const ScalarType alpha, const MultiVec<ScalarType, DM>& A, DM& B) const
122 {
124 MVT::MvTransMv( alpha, *(A_in.getConstMV()), *mv_, B );
125 }
126 void MvDot ( const MultiVec<ScalarType, DM>& A, std::vector<ScalarType>& b ) const
127 {
129 MVT::MvDot( *(A_in.getConstMV()), *mv_, b );
130 }
131 void MvNorm ( std::vector<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType>& normvec, NormType type = TwoNorm ) const
132 {
133 MVT::MvNorm( *mv_, normvec, type );
134 }
135 void SetBlock ( const MultiVec<ScalarType, DM>& A, const std::vector<int>& index )
136 {
138 MVT::SetBlock( *(A_in.getConstMV()), index, *mv_ );
139 }
140 void MvRandom () { MVT::MvRandom( *mv_ ); }
141 void MvInit ( const ScalarType alpha ) { MVT::MvInit( *mv_, alpha ); }
142 void MvPrint ( std::ostream& os ) const { MVT::MvPrint( *mv_, os ); }
143
144 private:
145
147
148 Teuchos::RCP<MV> mv_;
149
150 };
151
162 template <class ScalarType, class MV, class OP, class DM>
163 class GmresPolyOp : public Operator<ScalarType, DM> {
164
166
167 public:
168
170
171
174 const Teuchos::RCP<Teuchos::ParameterList>& params_in
175 )
176 : problem_(problem_in),
177 params_(params_in),
178 LP_(problem_in->getLeftPrec()),
179 RP_(problem_in->getRightPrec())
180 {
181 setParameters( params_ );
182
183 polyUpdateLabel_ = label_ + ": Hybrid Gmres: Vector Update";
184#ifdef BELOS_TEUCHOS_TIME_MONITOR
185 timerPolyUpdate_ = Teuchos::TimeMonitor::getNewCounter(polyUpdateLabel_);
186#endif // BELOS_TEUCHOS_TIME_MONITOR
187
188 if (polyType_ == "Arnoldi" || polyType_=="Roots")
190 else if (polyType_ == "Gmres")
192 else
193 TEUCHOS_TEST_FOR_EXCEPTION(polyType_!="Arnoldi"&&polyType_!="Gmres"&&polyType_!="Roots",std::invalid_argument,
194 "Belos::GmresPolyOp: \"Polynomial Type\" must be either \"Arnoldi\", \"Gmres\", or \"Roots\".");
195 }
196
199 : problem_(problem_in)
200 {
201 // If dimension is zero, it will just apply the operator from problem_in in the Apply method.
202 dim_ = 0;
203 }
204
206 virtual ~GmresPolyOp() {};
208
210
211
213 void setParameters( const Teuchos::RCP<Teuchos::ParameterList>& params_in );
215
217
218
222 void generateArnoldiPoly();
223
227 void generateGmresPoly();
228
230
232
233
239 void ApplyPoly ( const MV& x, MV& y ) const;
240 void ApplyArnoldiPoly ( const MV& x, MV& y ) const;
241 void ApplyGmresPoly ( const MV& x, MV& y ) const;
242 void ApplyRootsPoly ( const MV& x, MV& y ) const;
243
248 {
251 ApplyPoly( *(x_in.getConstMV()), *(y_in.getMV()) );
252 }
253
254 int polyDegree() const { return dim_; }
255
256 private:
257
258#ifdef BELOS_TEUCHOS_TIME_MONITOR
259 Teuchos::RCP<Teuchos::Time> timerPolyUpdate_;
260#endif // BELOS_TEUCHOS_TIME_MONITOR
261 std::string polyUpdateLabel_;
262
263 typedef int OT; //Ordinal type
265 typedef Teuchos::ScalarTraits<ScalarType> SCT ;
266 typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MagnitudeType;
267 typedef Teuchos::ScalarTraits<MagnitudeType> MCT ;
268
269 // Default polynomial parameters
270 static constexpr int maxDegree_default_ = 25;
271 static constexpr int verbosity_default_ = Belos::Errors;
272 static constexpr bool randomRHS_default_ = true;
273 static constexpr const char * label_default_ = "Belos";
274 static constexpr const char * polyType_default_ = "Roots";
275 static constexpr const char * orthoType_default_ = "DGKS";
276 static constexpr bool damp_default_ = false;
277 static constexpr bool addRoots_default_ = true;
278
279 // Variables for generating the polynomial
280 Teuchos::RCP<LinearProblem<ScalarType,MV,OP,DM> > problem_;
281 Teuchos::RCP<Teuchos::ParameterList> params_;
282 Teuchos::RCP<const OP> LP_, RP_;
283
284 // Output manager.
285 Teuchos::RCP<OutputManager<ScalarType> > printer_;
286 Teuchos::RCP<std::ostream> outputStream_ = Teuchos::rcpFromRef(std::cout);
287
288 // Orthogonalization manager.
289 Teuchos::RCP<MatOrthoManager<ScalarType,MV,OP,DM> > ortho_;
290
291 // Current polynomial parameters
292 MagnitudeType polyTol_ = DefaultSolverParameters::polyTol;
293 int maxDegree_ = maxDegree_default_;
294 int verbosity_ = verbosity_default_;
295 bool randomRHS_ = randomRHS_default_;
296 std::string label_ = label_default_;
297 std::string polyType_ = polyType_default_;
298 std::string orthoType_ = orthoType_default_;
299 int dim_ = 0;
300 bool damp_ = damp_default_;
301 bool addRoots_ = addRoots_default_;
302
303 // Variables for Arnoldi polynomial
304 mutable Teuchos::RCP<MV> V_, wL_, wR_;
305 DM H_, y_;
306 DM r0_;
307
308 // Variables for Gmres polynomial;
309 bool autoDeg = false;
310 DM pCoeff_;
311
312 // Variables for Roots polynomial:
313 Teuchos::SerialDenseMatrix< OT, MagnitudeType > theta_;
314
315 // Modified Leja sorting function. Takes a serial dense matrix of M harmonic Ritz values and an index
316 // of values from 0 to M. Returns the sorted values and sorted index, similar to Matlab.
317 void SortModLeja(Teuchos::SerialDenseMatrix< OT, MagnitudeType > &thetaN, std::vector<int> &index) const ;
318
319 //Function determines whether added roots are needed and adds them if option is turned on.
320 void ComputeAddedRoots();
321 };
322
323 template <class ScalarType, class MV, class OP, class DM>
324 void GmresPolyOp<ScalarType, MV, OP, DM>::setParameters( const Teuchos::RCP<Teuchos::ParameterList>& params_in )
325 {
326 // Check which Gmres polynomial to use
327 if (params_in->isParameter("Polynomial Type")) {
328 polyType_ = params_in->get("Polynomial Type", polyType_default_);
329 }
330
331 // Check for polynomial convergence tolerance
332 if (params_in->isParameter("Polynomial Tolerance")) {
333 if (params_in->isType<MagnitudeType> ("Polynomial Tolerance")) {
334 polyTol_ = params_in->get ("Polynomial Tolerance",
335 static_cast<MagnitudeType> (DefaultSolverParameters::polyTol));
336 }
337 else {
338 polyTol_ = params_in->get ("Polynomial Tolerance", DefaultSolverParameters::polyTol);
339 }
340 }
341
342 // Check for maximum polynomial degree
343 if (params_in->isParameter("Maximum Degree")) {
344 maxDegree_ = params_in->get("Maximum Degree", maxDegree_default_);
345 }
346
347 // Check for maximum polynomial degree
348 if (params_in->isParameter("Random RHS")) {
349 randomRHS_ = params_in->get("Random RHS", randomRHS_default_);
350 }
351
352 // Check for a change in verbosity level
353 if (params_in->isParameter("Verbosity")) {
354 if (Teuchos::isParameterType<int>(*params_in,"Verbosity")) {
355 verbosity_ = params_in->get("Verbosity", verbosity_default_);
356 }
357 else {
358 verbosity_ = (int)Teuchos::getParameter<Belos::MsgType>(*params_in,"Verbosity");
359 }
360 }
361
362 if (params_in->isParameter("Orthogonalization")) {
363 orthoType_ = params_in->get("Orthogonalization",orthoType_default_);
364 }
365
366 // Check for timer label
367 if (params_in->isParameter("Timer Label")) {
368 label_ = params_in->get("Timer Label", label_default_);
369 }
370
371 // Output stream
372 if (params_in->isParameter("Output Stream")) {
373 outputStream_ = Teuchos::getParameter<Teuchos::RCP<std::ostream> >(*params_in,"Output Stream");
374 }
375
376 // Check for damped polynomial
377 if (params_in->isParameter("Damped Poly")) {
378 damp_ = params_in->get("Damped Poly", damp_default_);
379 }
380
381 // Check for root-adding
382 if (params_in->isParameter("Add Roots")) {
383 addRoots_ = params_in->get("Add Roots", addRoots_default_);
384 }
385 }
386
387 template <class ScalarType, class MV, class OP, class DM>
389 {
390 Teuchos::RCP< MV > V = MVT::Clone( *problem_->getRHS(), maxDegree_+1 );
391
392 //Make power basis:
393 std::vector<int> index(1,0);
394 Teuchos::RCP< MV > V0 = MVT::CloneViewNonConst(*V, index);
395 if (randomRHS_)
396 MVT::MvRandom( *V0 );
397 else
398 MVT::Assign( *problem_->getRHS(), *V0 );
399
400 if ( !LP_.is_null() ) {
401 Teuchos::RCP< MV > Vtemp = MVT::CloneCopy(*V0);
402 problem_->applyLeftPrec( *Vtemp, *V0);
403 }
404 if ( damp_ ) {
405 Teuchos::RCP< MV > Vtemp = MVT::CloneCopy(*V0);
406 problem_->apply( *Vtemp, *V0);
407 }
408
409 for(int i=0; i< maxDegree_; i++)
410 {
411 index[0] = i;
412 Teuchos::RCP< const MV > Vi = MVT::CloneView(*V, index);
413 index[0] = i+1;
414 Teuchos::RCP< MV > Vip1 = MVT::CloneViewNonConst(*V, index);
415 problem_->apply( *Vi, *Vip1);
416 }
417
418 //Consider AV:
419 Teuchos::Range1D range( 1, maxDegree_);
420 Teuchos::RCP< const MV > AV = MVT::CloneView( *V, range);
421
422 //Make lhs (AV)^T(AV)
423 DM AVtransAV = *DMT::Create( maxDegree_, maxDegree_);
424 MVT::MvTransMv( SCT::one(), *AV, *AV, AVtransAV);
425 //This process adds pDeg*pDeg + pDeg inner products that aren't in the final count.
426
427 Teuchos::LAPACK< OT, ScalarType > lapack;
428 int infoInt;
429 bool status = true; //Keep adjusting poly deg when true.
430
431 dim_ = maxDegree_;
432 DM lhs;
433 while( status && dim_ >= 1)
434 {
435 DM lhstemp = *DMT::SubviewCopy(AVtransAV, dim_, dim_);
436 lapack.POTRF( 'U', dim_, DMT::GetRawHostPtr(lhstemp), DMT::GetStride(lhstemp), &infoInt);
437
438 DMT::SyncHostToDevice(lhstemp);
439 if(autoDeg == false)
440 {
441 status = false;
442 if(infoInt != 0)
443 {
444 std::cout << "BelosGmresPolyOp.hpp: LAPACK POTRF was not successful!!" << std::endl;
445 std::cout << "Error code: " << infoInt << std::endl;
446 }
447 }
448 else
449 {
450 if(infoInt != 0)
451 {//Had bad factor. Reduce poly degree.
452 dim_--;
453 }
454 else
455 {
456 status = false;
457 }
458 }
459 if(status == false)
460 {
461 lhs = lhstemp;
462 }
463 }
464 if(dim_ == 0)
465 {
466 DMT::Reshape(pCoeff_, 1, 1);
467 DMT::Value(pCoeff_, 0,0) = SCT::one();
468 std::cout << "Poly Degree is zero. No preconditioner created." << std::endl;
469 }
470 else
471 {
472 DMT::Reshape(pCoeff_, dim_, 1);
473 //Get correct submatrix of AV:
474 Teuchos::Range1D rangeSub( 1, dim_);
475 Teuchos::RCP< const MV > AVsub = MVT::CloneView( *V, rangeSub);
476
477 //Compute rhs (AV)^T V0
478 MVT::MvTransMv( SCT::one(), *AVsub, *V0, pCoeff_);
479 lapack.POTRS( 'U', dim_, 1, DMT::GetRawHostPtr(lhs), DMT::GetStride(lhs), DMT::GetRawHostPtr(pCoeff_), DMT::GetStride(pCoeff_), &infoInt);
480 DMT::SyncHostToDevice(pCoeff_);
481 if(infoInt != 0)
482 {
483 std::cout << "BelosGmresPolyOp.hpp: LAPACK POTRS was not successful!!" << std::endl;
484 std::cout << "Error code: " << infoInt << std::endl;
485 }
486 }
487 }
488
489 template <class ScalarType, class MV, class OP, class DM>
491 {
492 std::string polyLabel = label_ + ": GmresPolyOp creation";
493
494 // Create a copy of the linear problem that has a zero initial guess and random RHS.
495 std::vector<int> idx(1,0);
496 Teuchos::RCP<MV> newX = MVT::Clone( *(problem_->getLHS()), 1 );
497 Teuchos::RCP<MV> newB = MVT::Clone( *(problem_->getRHS()), 1 );
498 MVT::MvInit( *newX, SCT::zero() );
499 if (randomRHS_) {
500 MVT::MvRandom( *newB );
501 }
502 else {
503 MVT::Assign( *(MVT::CloneView(*(problem_->getRHS()), idx)), *newB );
504 }
505 Teuchos::RCP<LinearProblem<ScalarType,MV,OP,DM> > newProblem =
506 Teuchos::rcp( new LinearProblem<ScalarType,MV,OP,DM>( problem_->getOperator(), newX, newB ) );
507 newProblem->setInitResVec( newB );
508 newProblem->setLeftPrec( problem_->getLeftPrec() );
509 newProblem->setRightPrec( problem_->getRightPrec() );
510 newProblem->setLabel(polyLabel);
511 newProblem->setProblem();
512 newProblem->setLSIndex( idx );
513
514 // Create a parameter list for the GMRES iteration.
515 Teuchos::ParameterList polyList;
516
517 // Tell the block solver that the block size is one.
518 polyList.set("Num Blocks",maxDegree_);
519 polyList.set("Block Size",1);
520 polyList.set("Keep Hessenberg", true);
521
522 // Create output manager.
523 printer_ = Teuchos::rcp( new OutputManager<ScalarType>(verbosity_, outputStream_) );
524
525 // Create orthogonalization manager if we need to.
526 if (ortho_.is_null()) {
527 params_->set("Orthogonalization", orthoType_);
529 Teuchos::RCP<Teuchos::ParameterList> paramsOrtho; // can be null
530
531 ortho_ = factory.makeMatOrthoManager (orthoType_, Teuchos::null, printer_, polyLabel, paramsOrtho);
532 }
533
534 // Create a simple status test that either reaches the relative residual tolerance or maximum polynomial size.
535 Teuchos::RCP<StatusTestMaxIters<ScalarType,MV,OP,DM> > maxItrTst =
536 Teuchos::rcp( new StatusTestMaxIters<ScalarType,MV,OP,DM>( maxDegree_ ) );
537
538 // Implicit residual test, using the native residual to determine if convergence was achieved.
539 Teuchos::RCP<StatusTestGenResNorm<ScalarType,MV,OP,DM> > convTst =
540 Teuchos::rcp( new StatusTestGenResNorm<ScalarType,MV,OP,DM>( polyTol_ ) );
541 convTst->defineScaleForm( convertStringToScaleType("Norm of RHS"), Belos::TwoNorm );
542
543 // Convergence test that stops the iteration when either are satisfied.
544 Teuchos::RCP<StatusTestCombo<ScalarType,MV,OP,DM> > polyTest =
546
547 // Create Gmres iteration object to perform one cycle of Gmres.
548 Teuchos::RCP<BlockGmresIter<ScalarType,MV,OP,DM> > gmres_iter;
549 gmres_iter = Teuchos::rcp( new BlockGmresIter<ScalarType,MV,OP,DM>(newProblem,printer_,polyTest,ortho_,polyList) );
550
551 // Create the first block in the current Krylov basis (residual).
552 Teuchos::RCP<MV> V_0 = MVT::CloneCopy( *newB );
553 if ( !LP_.is_null() )
554 newProblem->applyLeftPrec( *newB, *V_0 );
555 if ( damp_ )
556 {
557 Teuchos::RCP< MV > Vtemp = MVT::CloneCopy(*V_0);
558 newProblem->apply( *Vtemp, *V_0 );
559 }
560
561 // Get a matrix to hold the orthonormalization coefficients.
562 DMT::Reshape(r0_, 1, 1);
563
564 // Orthonormalize the new V_0
565 int rank = ortho_->normalize( *V_0, Teuchos::rcpFromRef(r0_) );
567 "Belos::GmresPolyOp::generateArnoldiPoly(): Failed to compute initial block of orthonormal vectors for polynomial generation.");
568
569 DMT::SyncDeviceToHost(r0_);
570 // Set the new state and initialize the solver.
572 newstate.V = V_0;
573 newstate.z = Teuchos::rcpFromRef( r0_);
574 newstate.curDim = 0;
575 gmres_iter->initializeGmres(newstate);
576
577 // Perform Gmres iteration
578 try {
579 gmres_iter->iterate();
580 }
582 // Try to recover the most recent least-squares solution
583 gmres_iter->updateLSQR( gmres_iter->getCurSubspaceDim() );
584 }
585 catch (std::exception& e) {
586 using std::endl;
587 printer_->stream(Errors) << "Error! Caught exception in BlockGmresIter::iterate() at iteration "
588 << gmres_iter->getNumIters() << endl << e.what () << endl;
589 throw;
590 }
591
592 // Get the solution for this polynomial, use in comparison below
593 Teuchos::RCP<MV> currX = gmres_iter->getCurrentUpdate();
594
595 // Record polynomial info, get current GMRES state
597
598 // If the polynomial has no dimension, the tolerance is too low, return false
599 dim_ = gmresState.curDim;
600 if (dim_ == 0) {
601 return;
602 }
603 if(polyType_ == "Arnoldi"){
604 // Make a view and then copy the RHS of the least squares problem.
605 //
606 y_ = *DMT::SubviewCopy(*gmresState.z, dim_, 1);
607 H_ = *gmresState.H;
608
609 //
610 // Solve the least squares problem.
611 //
612 Teuchos::BLAS<OT,ScalarType> blas;
613 blas.TRSM( Teuchos::LEFT_SIDE, Teuchos::UPPER_TRI, Teuchos::NO_TRANS,
614 Teuchos::NON_UNIT_DIAG, dim_, 1, SCT::one(),
615 DMT::GetConstRawHostPtr(*gmresState.R), DMT::GetStride(*gmresState.R),
616 DMT::GetRawHostPtr(y_), DMT::GetStride(y_) );
617 // DMT::SyncHostToDevice(*gmresState.R); // Why sync this when the result is in y? Shouldn't y be sync'ed before update is computed?
618 DMT::SyncHostToDevice(y_);
619 }
620 else{ //Generate Roots Poly
621 //Find Harmonic Ritz Values to use as polynomial roots:
622
623 //Copy of square H used to find poly roots:
624 H_ = *DMT::SubviewCopy(*gmresState.H, dim_, dim_);
625 //Zero out below subdiagonal of H:
626 for(int i=0; i <= dim_-3; i++) {
627 for(int k=i+2; k <= dim_-1; k++) {
628 DMT::Value(H_,k,i) = SCT::zero();
629 }
630 }
631 //Extra copy of H because equilibrate changes the matrix:
632 DMT::SyncHostToDevice(H_);
633 DM Htemp = *DMT::CreateCopy(H_);
634
635 //View the m+1,m element and last col of H:
636 ScalarType Hlast = DMT::ValueConst(*gmresState.H,dim_,dim_-1);
637 DM HlastCol = *DMT::Subview(H_, dim_, 1, 0, dim_-1);
638
639 //Set up linear system for H^{-*}e_m:
640 DM F = *DMT::Create(dim_,1);
641 DM E = *DMT::Create(dim_,1);
642 DMT::PutScalar(E, SCT::zero());
643 DMT::Value(E, dim_-1,0) = SCT::one();
644
645 auto HSolver = DMT::createDenseSolver();
646 HSolver->setMatrix( Teuchos::rcpFromRef(Htemp));
647 HSolver->solveWithTransposeFlag( Teuchos::CONJ_TRANS );
648 HSolver->setVectors( Teuchos::rcpFromRef(F), Teuchos::rcpFromRef(E));
649 HSolver->factorWithEquilibration( true );
650
651 //Factor matrix and solve for F = H^{-*}e_m:
652 int info = 0;
653 info = HSolver->factor();
654 if(info != 0){
655 std::cout << "Hsolver factor: info = " << info << std::endl;
656 }
657 info = HSolver->solve();
658 if(info != 0){
659 std::cout << "Hsolver solve : info = " << info << std::endl;
660 }
661
662 //Scale F and adjust H for Harmonic Ritz value eigenproblem:
663 DMT::Scale(F, Hlast*Hlast);
664 DMT::Add(HlastCol, F);
665
666 //Set up for eigenvalue problem to get Harmonic Ritz Values:
667 Teuchos::LAPACK< OT, ScalarType > lapack;
668 theta_.shape(dim_,2);//1st col for real part, 2nd col for imaginary
669
670 const int ldv = 1;
671 ScalarType* vlr = 0;
672
673 // Size of workspace and workspace for DGEEV
674 int lwork = -1;
675 std::vector<ScalarType> work(1);
676 std::vector<MagnitudeType> rwork(2*dim_);
677
678 //Find workspace size for DGEEV:
679 lapack.GEEV('N','N',dim_,DMT::GetRawHostPtr(H_),DMT::GetStride(H_),theta_[0],theta_[1],vlr, ldv, vlr, ldv, &work[0], lwork, &rwork[0], &info);
680 lwork = std::abs (static_cast<int> (Teuchos::ScalarTraits<ScalarType>::real (work[0])));
681 work.resize( lwork );
682 // Solve for Harmonic Ritz Values:
683 lapack.GEEV('N','N',dim_,DMT::GetRawHostPtr(H_),DMT::GetStride(H_),theta_[0],theta_[1],vlr, ldv, vlr, ldv, &work[0], lwork, &rwork[0], &info);
684
685 if(info != 0){
686 std::cout << "GEEV solve : info = " << info << std::endl;
687 }
688
689 // Set index for sort function, verify roots are non-zero,
690 // and sort Harmonic Ritz Values:
691 const MagnitudeType tol = 10.0 * Teuchos::ScalarTraits<MagnitudeType>::eps();
692 std::vector<int> index(dim_);
693 for(int i=0; i<dim_; ++i){
694 index[i] = i;
695 // Check if real + imag parts of roots < tol.
696 TEUCHOS_TEST_FOR_EXCEPTION(hypot(theta_(i,0),theta_(i,1)) < tol, std::runtime_error, "BelosGmresPolyOp Error: One of the computed polynomial roots is approximately zero. This will cause a divide by zero error! Your matrix may be close to singular. Please select a lower polynomial degree or give a shifted matrix.");
697 }
698 SortModLeja(theta_,index);
699
700 //Add roots if neded.
701 ComputeAddedRoots();
702
703 }
704 }
705
706 //Function determines whether added roots are needed and adds them if option is turned on.
707 template <class ScalarType, class MV, class OP, class DM>
709 {
710 // Store theta (with cols for real and imag parts of Harmonic Ritz Vals)
711 // as one vector of complex numbers to perform arithmetic:
712 std::vector<std::complex<MagnitudeType>> cmplxHRitz (dim_);
713 for(unsigned int i=0; i<cmplxHRitz.size(); ++i){
714 cmplxHRitz[i] = std::complex<MagnitudeType>( theta_(i,0), theta_(i,1) );
715 }
716
717 // Compute product of factors (pof) to determine added roots:
718 const MagnitudeType one(1.0);
719 std::vector<MagnitudeType> pof (dim_,one);
720 for(int j=0; j<dim_; ++j) {
721 for(int i=0; i<dim_; ++i) {
722 if(i!=j) {
723 pof[j] = std::abs(pof[j]*(one-(cmplxHRitz[j]/cmplxHRitz[i])));
724 }
725 }
726 }
727
728 // Compute number of extra roots needed:
729 std::vector<int> extra (dim_);
730 int totalExtra = 0;
731 for(int i=0; i<dim_; ++i){
732 if (pof[i] > MCT::zero())
733 extra[i] = ceil((log10(pof[i])-MagnitudeType(4.0))/MagnitudeType(14.0));
734 else
735 extra[i] = 0;
736 if(extra[i] > 0){
737 totalExtra += extra[i];
738 }
739 }
740 if (totalExtra){
741 printer_->stream(Warnings) << "Warning: Need to add " << totalExtra << " extra roots." << std::endl;}
742
743 // If requested to add roots, append them to the theta matrix:
744 if(addRoots_ && totalExtra>0)
745 {
746 theta_.reshape(dim_+totalExtra,2);
747 // Make a matrix copy for perturbed roots:
748 Teuchos::SerialDenseMatrix<OT,MagnitudeType> thetaPert (Teuchos::Copy, theta_, dim_+totalExtra, 2);
749
750 //Add extra eigenvalues to matrix and perturb for sort:
751 int count = dim_;
752 for(int i=0; i<dim_; ++i){
753 for(int j=0; j< extra[i]; ++j){
754 theta_(count,0) = theta_(i,0);
755 theta_(count,1) = theta_(i,1);
756 thetaPert(count,0) = theta_(i,0)+(j+MCT::one())*MagnitudeType(5e-8);
757 thetaPert(count,1) = theta_(i,1);
758 ++count;
759 }
760 }
761
762 // Update polynomial degree:
763 dim_ += totalExtra;
764 if (totalExtra){
765 printer_->stream(Warnings) << "New poly degree is: " << dim_ << std::endl;}
766
767 // Create a new index and sort perturbed roots:
768 std::vector<int> index2(dim_);
769 for(int i=0; i<dim_; ++i){
770 index2[i] = i;
771 }
772 SortModLeja(thetaPert,index2);
773 //Apply sorting to non-perturbed roots:
774 for(int i=0; i<dim_; ++i)
775 {
776 thetaPert(i,0) = theta_(index2[i],0);
777 thetaPert(i,1) = theta_(index2[i],1);
778 }
779 theta_ = thetaPert;
780
781 }
782 }
783
784 // Modified Leja sorting function. Takes a serial dense matrix of M harmonic Ritz values and an index
785 // of values from 0 to M. Returns the sorted values and sorted index, similar to Matlab.
786 template <class ScalarType, class MV, class OP, class DM>
787 void GmresPolyOp<ScalarType, MV, OP, DM>::SortModLeja(Teuchos::SerialDenseMatrix< OT, MagnitudeType > &thetaN, std::vector<int> &index) const
788 {
789 //Sort theta values via Modified Leja Ordering:
790
791 // Set up blank matrices to track sorting:
792 int dimN = index.size();
793 std::vector<int> newIndex(dimN);
794 Teuchos::SerialDenseMatrix< OT, MagnitudeType > sorted (thetaN.numRows(), thetaN.numCols());
795 Teuchos::SerialDenseVector< OT, MagnitudeType > absVal (thetaN.numRows());
796 Teuchos::SerialDenseVector< OT, MagnitudeType > prod (thetaN.numRows());
797
798 //Compute all absolute values and find maximum:
799 for(int i = 0; i < dimN; i++){
800 absVal(i) = hypot(thetaN(i,0), thetaN(i,1));
801 }
802 MagnitudeType * maxPointer = std::max_element(absVal.values(), (absVal.values()+dimN));
803 int maxIndex = int (maxPointer- absVal.values());
804
805 //Put largest abs value first in the list:
806 sorted(0,0) = thetaN(maxIndex,0);
807 sorted(0,1) = thetaN(maxIndex,1);
808 newIndex[0] = index[maxIndex];
809
810 int j;
811 // If largest value was complex (for real scalar type) put its conjugate in the next slot.
812 if(sorted(0,1)!= SCT::zero() && !SCT::isComplex)
813 {
814 sorted(1,0) = thetaN(maxIndex,0);
815 sorted(1,1) = -thetaN(maxIndex,1);
816 newIndex[1] = index[maxIndex+1];
817 j = 2;
818 }
819 else
820 {
821 j = 1;
822 }
823
824 //Sort remaining values:
825 MagnitudeType a, b;
826 while( j < dimN )
827 {
828 //For each value, compute (a log of) a product of differences:
829 for(int i = 0; i < dimN; i++)
830 {
831 prod(i) = MCT::one();
832 for(int k = 0; k < j; k++)
833 {
834 a = thetaN(i,0) - sorted(k,0);
835 b = thetaN(i,1) - sorted(k,1);
836 if (a*a + b*b > MCT::zero())
837 prod(i) = prod(i) + log10(hypot(a,b));
838 else {
839 prod(i) = -std::numeric_limits<MagnitudeType>::infinity();
840 break;
841 }
842 }
843 }
844
845 //Value with largest product goes in the next slot:
846 maxPointer = std::max_element(prod.values(), (prod.values()+dimN));
847 maxIndex = int (maxPointer- prod.values());
848 sorted(j,0) = thetaN(maxIndex,0);
849 sorted(j,1) = thetaN(maxIndex,1);
850 newIndex[j] = index[maxIndex];
851
852 //If it was complex (and scalar type real) put its conjugate in next slot:
853 if(sorted(j,1)!= SCT::zero() && !SCT::isComplex)
854 {
855 j++;
856 sorted(j,0) = thetaN(maxIndex,0);
857 sorted(j,1) = -thetaN(maxIndex,1);
858 newIndex[j] = index[maxIndex+1];
859 }
860 j++;
861 }
862
863 //Return sorted values and sorted indices:
864 thetaN = sorted;
865 index = newIndex;
866 } //End Modified Leja ordering
867
868 template <class ScalarType, class MV, class OP, class DM>
870 {
871 if (dim_) {
872 if (polyType_ == "Arnoldi")
873 ApplyArnoldiPoly(x, y);
874 else if (polyType_ == "Gmres")
875 ApplyGmresPoly(x, y);
876 else if (polyType_ == "Roots")
877 ApplyRootsPoly(x, y);
878 }
879 else {
880 // Just apply the operator in problem_ to x and return y.
881 problem_->applyOp( x, y );
882 }
883 }
884
885 template <class ScalarType, class MV, class OP, class DM>
887 {
888 Teuchos::RCP<MV> AX = MVT::CloneCopy(x);
889 Teuchos::RCP<MV> AX2 = MVT::Clone( x, MVT::GetNumberVecs(x) );
890
891 // Apply left preconditioner.
892 if (!LP_.is_null()) {
893 Teuchos::RCP<MV> Xtmp = MVT::Clone( x, MVT::GetNumberVecs(x) );
894 problem_->applyLeftPrec( *AX, *Xtmp ); // Left precondition x into the first vector
895 AX = Xtmp;
896 }
897
898 {
899#ifdef BELOS_TEUCHOS_TIME_MONITOR
900 Teuchos::TimeMonitor updateTimer( *timerPolyUpdate_ );
901#endif
902 MVT::MvAddMv(DMT::ValueConst(pCoeff_,0,0), *AX, SCT::zero(), y, y); //y= coeff_i(A^ix)
903 }
904 for( int i=1; i < dim_; i++)
905 {
906 Teuchos::RCP<MV> X, Y;
907 if ( i%2 )
908 {
909 X = AX;
910 Y = AX2;
911 }
912 else
913 {
914 X = AX2;
915 Y = AX;
916 }
917 problem_->apply(*X, *Y);
918 {
919#ifdef BELOS_TEUCHOS_TIME_MONITOR
920 Teuchos::TimeMonitor updateTimer( *timerPolyUpdate_ );
921#endif
922 MVT::MvAddMv(DMT::ValueConst(pCoeff_,i,0), *Y, SCT::one(), y, y); //y= coeff_i(A^ix) +y
923 }
924 }
925
926 // Apply right preconditioner.
927 if (!RP_.is_null()) {
928 Teuchos::RCP<MV> Ytmp = MVT::CloneCopy(y);
929 problem_->applyRightPrec( *Ytmp, y );
930 }
931 }
932
933 template <class ScalarType, class MV, class OP, class DM>
935 {
936 MVT::MvInit( y, SCT::zero() ); //Zero out y to take the vector with poly applied.
937 Teuchos::RCP<MV> prod = MVT::CloneCopy(x);
938 Teuchos::RCP<MV> Xtmp = MVT::Clone( x, MVT::GetNumberVecs(x) );
939 Teuchos::RCP<MV> Xtmp2 = MVT::Clone( x, MVT::GetNumberVecs(x) );
940
941 // Apply left preconditioner.
942 if (!LP_.is_null()) {
943 problem_->applyLeftPrec( *prod, *Xtmp ); // Left precondition x into the first vector
944 prod = Xtmp;
945 }
946
947 int i=0;
948 while(i < dim_-1)
949 {
950 if(theta_(i,1)== SCT::zero() || SCT::isComplex) //Real Harmonic Ritz value or complex scalars
951 {
952 {
953#ifdef BELOS_TEUCHOS_TIME_MONITOR
954 Teuchos::TimeMonitor updateTimer( *timerPolyUpdate_ );
955#endif
956 MVT::MvAddMv(SCT::one(), y, SCT::one()/theta_(i,0), *prod, y); //poly = poly + 1/theta_i * prod
957 }
958 problem_->apply(*prod, *Xtmp); // temp = A*prod
959 {
960#ifdef BELOS_TEUCHOS_TIME_MONITOR
961 Teuchos::TimeMonitor updateTimer( *timerPolyUpdate_ );
962#endif
963 MVT::MvAddMv(SCT::one(), *prod, -SCT::one()/theta_(i,0), *Xtmp, *prod); //prod = prod - 1/theta_i * temp
964 }
965 i++;
966 }
967 else //Current theta is complex and has a conjugate; combine to preserve real arithmetic
968 {
969 MagnitudeType mod = theta_(i,0)*theta_(i,0) + theta_(i,1)*theta_(i,1); //mod = a^2 + b^2
970 problem_->apply(*prod, *Xtmp); // temp = A*prod
971 {
972#ifdef BELOS_TEUCHOS_TIME_MONITOR
973 Teuchos::TimeMonitor updateTimer( *timerPolyUpdate_ );
974#endif
975 MVT::MvAddMv(2*theta_(i,0), *prod, -SCT::one(), *Xtmp, *Xtmp); //temp = 2a*prod-temp
976 MVT::MvAddMv(SCT::one(), y, SCT::one()/mod, *Xtmp, y); //poly = poly + 1/mod*temp
977 }
978 if( i < dim_-2 )
979 {
980 problem_->apply(*Xtmp, *Xtmp2); // temp2 = A*temp
981 {
982#ifdef BELOS_TEUCHOS_TIME_MONITOR
983 Teuchos::TimeMonitor updateTimer( *timerPolyUpdate_ );
984#endif
985 MVT::MvAddMv(SCT::one(), *prod, -SCT::one()/mod, *Xtmp2, *prod); //prod = prod - 1/mod * temp2
986 }
987 }
988 i = i + 2;
989 }
990 }
991 if(theta_(dim_-1,1)== SCT::zero() || SCT::isComplex)
992 {
993#ifdef BELOS_TEUCHOS_TIME_MONITOR
994 Teuchos::TimeMonitor updateTimer( *timerPolyUpdate_ );
995#endif
996 MVT::MvAddMv(SCT::one(), y, SCT::one()/theta_(dim_-1,0), *prod, y); //poly = poly + 1/theta_i * prod
997 }
998
999 // Apply right preconditioner.
1000 if (!RP_.is_null()) {
1001 Teuchos::RCP<MV> Ytmp = MVT::CloneCopy(y);
1002 problem_->applyRightPrec( *Ytmp, y );
1003 }
1004 }
1005
1006 template <class ScalarType, class MV, class OP, class DM>
1008 {
1009 // Initialize vector storage.
1010 if (V_.is_null()) {
1011 V_ = MVT::Clone( x, dim_ );
1012 if (!LP_.is_null()) {
1013 wL_ = MVT::Clone( y, 1 );
1014 }
1015 if (!RP_.is_null()) {
1016 wR_ = MVT::Clone( y, 1 );
1017 }
1018 }
1019 //
1020 // Apply polynomial to x.
1021 //
1022 int n = MVT::GetNumberVecs( x );
1023 std::vector<int> idxi(1), idxi2, idxj(1);
1024
1025 // Select vector x[j].
1026 for (int j=0; j<n; ++j) {
1027
1028 idxi[0] = 0;
1029 idxj[0] = j;
1030 Teuchos::RCP<const MV> x_view = MVT::CloneView( x, idxj );
1031 Teuchos::RCP<MV> y_view = MVT::CloneViewNonConst( y, idxj );
1032 if (!LP_.is_null()) {
1033 Teuchos::RCP<MV> v_curr = MVT::CloneViewNonConst( *V_, idxi );
1034 problem_->applyLeftPrec( *x_view, *v_curr ); // Left precondition x into the first vector of V
1035 } else {
1036 MVT::SetBlock( *x_view, idxi, *V_ ); // Set x as the first vector of V
1037 }
1038
1039 for (int i=0; i<dim_-1; ++i) {
1040
1041 // Get views into the current and next vectors
1042 idxi2.resize(i+1);
1043 for (int ii=0; ii<i+1; ++ii) { idxi2[ii] = ii; }
1044 Teuchos::RCP<const MV> v_prev = MVT::CloneView( *V_, idxi2 );
1045 // the tricks below with wR_ and wL_ (potentially set to v_curr and v_next) unfortunately imply that
1046 // v_curr and v_next must be non-const views.
1047 Teuchos::RCP<MV> v_curr = MVT::CloneViewNonConst( *V_, idxi );
1048 idxi[0] = i+1;
1049 Teuchos::RCP<MV> v_next = MVT::CloneViewNonConst( *V_, idxi );
1050
1051 //---------------------------------------------
1052 // Apply operator to next vector
1053 //---------------------------------------------
1054 // 1) Apply right preconditioner, if we have one.
1055 if (!RP_.is_null()) {
1056 problem_->applyRightPrec( *v_curr, *wR_ );
1057 } else {
1058 wR_ = v_curr;
1059 }
1060 // 2) Check for left preconditioner, if none exists, point at the next vector.
1061 if (LP_.is_null()) {
1062 wL_ = v_next;
1063 }
1064 // 3) Apply operator A.
1065 problem_->applyOp( *wR_, *wL_ );
1066 // 4) Apply left preconditioner, if we have one.
1067 if (!LP_.is_null()) {
1068 problem_->applyLeftPrec( *wL_, *v_next );
1069 }
1070
1071 // Compute A*v_curr - v_prev*H(1:i,i)
1072 // Teuchos::SerialDenseMatrix<OT,ScalarType> h(Teuchos::View,H_,i+1,1,0,i);
1073 auto h = DMT::SubviewConst(H_,i+1,1,0,i);
1074 {
1075#ifdef BELOS_TEUCHOS_TIME_MONITOR
1076 Teuchos::TimeMonitor updateTimer( *timerPolyUpdate_ );
1077#endif
1078 MVT::MvTimesMatAddMv( -SCT::one(), *v_prev, *h, SCT::one(), *v_next );
1079 }
1080
1081 // Scale by H(i+1,i)
1082 MVT::MvScale( *v_next, SCT::one()/DMT::ValueConst(H_, i+1,i) );
1083 }
1084
1085 // Compute output y = V*y_./r0_
1086 if (!RP_.is_null()) {
1087 {
1088#ifdef BELOS_TEUCHOS_TIME_MONITOR
1089 Teuchos::TimeMonitor updateTimer( *timerPolyUpdate_ );
1090#endif
1091 MVT::MvTimesMatAddMv( SCT::one()/DMT::ValueConst(r0_, 0, 0), *V_, y_, SCT::zero(), *wR_ );
1092 }
1093 problem_->applyRightPrec( *wR_, *y_view );
1094 }
1095 else {
1096#ifdef BELOS_TEUCHOS_TIME_MONITOR
1097 Teuchos::TimeMonitor updateTimer( *timerPolyUpdate_ );
1098#endif
1099 MVT::MvTimesMatAddMv( SCT::one()/DMT::ValueConst(r0_, 0, 0), *V_, y_, SCT::zero(), *y_view );
1100 }
1101 } // (int j=0; j<n; ++j)
1102 } // end Apply()
1103} // end Belos namespace
1104
1105#endif
1106
1107// end of file BelosGmresPolyOp.hpp
Belos concrete class for performing the block GMRES iteration.
Belos header file which uses auto-configuration information to include necessary C++ headers.
Pure virtual base class which augments the basic interface for a Gmres linear solver iteration.
Class which describes the linear problem to be solved by the iterative solver.
Interface for multivectors used by Belos' linear solvers.
Declaration of basic traits for the multivector type.
Alternative run-time polymorphic interface for operators.
Class which defines basic traits for the operator type.
Class which manages the output and verbosity of the Belos solvers.
Belos::StatusTest for logically combining several status tests.
Belos::StatusTestResNorm for specifying general residual norm stopping criteria.
Belos::StatusTest class for specifying a maximum number of iterations.
A factory class for generating StatusTestOutput objects.
Collection of types and exceptions used within the Belos solvers.
Parent class to all Belos exceptions.
GmresIterationOrthoFailure is thrown when the GmresIteration object is unable to compute independent ...
void MvNorm(std::vector< typename Teuchos::ScalarTraits< ScalarType >::magnitudeType > &normvec, NormType type=TwoNorm) const
Compute the norm of each vector in *this.
GmresPolyMv(const Teuchos::RCP< const MV > &mv_in)
void MvInit(const ScalarType alpha)
Replace each element of the vectors in *this with alpha.
GmresPolyMv * CloneCopy(const std::vector< int > &index) const
Creates a new Belos::MultiVec and copies the selected contents of *this into the new multivector (dee...
GmresPolyMv * CloneViewNonConst(const std::vector< int > &index)
Creates a new Belos::MultiVec that shares the selected contents of *this. The index of the numvecs ve...
int GetNumberVecs() const
The number of vectors (i.e., columns) in the multivector.
void SetBlock(const MultiVec< ScalarType, DM > &A, const std::vector< int > &index)
Copy the vectors in A to a set of vectors in *this.
Teuchos::RCP< const MV > getConstMV() const
GmresPolyMv(const Teuchos::RCP< MV > &mv_in)
GmresPolyMv * Clone(const int numvecs) const
Create a new MultiVec with numvecs columns.
void MvScale(const std::vector< ScalarType > &alpha)
Scale each element of the i-th vector in *this with alpha[i].
const GmresPolyMv * CloneView(const std::vector< int > &index) const
Creates a new Belos::MultiVec that shares the selected contents of *this. The index of the numvecs ve...
Teuchos::RCP< MV > getMV()
void MvRandom()
Fill all the vectors in *this with random numbers.
void MvAddMv(const ScalarType alpha, const MultiVec< ScalarType, DM > &A, const ScalarType beta, const MultiVec< ScalarType, DM > &B)
Replace *this with alpha * A + beta * B.
ptrdiff_t GetGlobalLength() const
The number of rows in the multivector.
void MvTransMv(const ScalarType alpha, const MultiVec< ScalarType, DM > &A, DM &B) const
Compute a dense matrix B through the matrix-matrix multiply alpha * A^T * (*this).
void MvScale(const ScalarType alpha)
Scale each element of the vectors in *this with alpha.
GmresPolyMv * CloneCopy() const
Create a new MultiVec and copy contents of *this into it (deep copy).
void MvDot(const MultiVec< ScalarType, DM > &A, std::vector< ScalarType > &b) const
Compute the dot product of each column of *this with the corresponding column of A.
void MvPrint(std::ostream &os) const
Print *this multivector to the os output stream.
void MvTimesMatAddMv(const ScalarType alpha, const MultiVec< ScalarType, DM > &A, const DM &B, const ScalarType beta)
Update *this with alpha * A * B + beta * (*this).
Belos's class for applying the GMRES polynomial operator that is used by the hybrid-GMRES linear solv...
void Apply(const MultiVec< ScalarType, DM > &x, MultiVec< ScalarType, DM > &y, ETrans=NOTRANS) const
This routine casts the MultiVec to GmresPolyMv to retrieve the MV. Then the above apply method is cal...
void setParameters(const Teuchos::RCP< Teuchos::ParameterList > &params_in)
Process the passed in parameters.
void generateArnoldiPoly()
This routine takes the matrix, preconditioner, and vectors from the linear problem as well as the par...
void ApplyPoly(const MV &x, MV &y) const
This routine takes the MV x and applies the polynomial operator phi(OP) to it resulting in the MV y,...
GmresPolyOp(const Teuchos::RCP< LinearProblem< ScalarType, MV, OP, DM > > &problem_in, const Teuchos::RCP< Teuchos::ParameterList > &params_in)
Basic contstructor.
void ApplyRootsPoly(const MV &x, MV &y) const
virtual ~GmresPolyOp()
Destructor.
GmresPolyOp(const Teuchos::RCP< LinearProblem< ScalarType, MV, OP, DM > > &problem_in)
Given no ParameterList, constructor creates no polynomial and only applies the given operator.
void ApplyGmresPoly(const MV &x, MV &y) const
void ApplyArnoldiPoly(const MV &x, MV &y) const
void generateGmresPoly()
This routine takes the matrix, preconditioner, and vectors from the linear problem as well as the par...
GmresPolyOpOrthoFailure is thrown when the orthogonalization manager is unable to generate orthonorma...
GmresPolyOpOrthoFailure(const std::string &what_arg)
Interface for multivectors used by Belos' linear solvers.
Alternative run-time polymorphic interface for operators.
Operator()
Default constructor (does nothing).
A class for extending the status testing capabilities of Belos via logical combinations.
ScaleType convertStringToScaleType(const std::string &scaleType)
Convert the given string to its ScaleType enum value.
NormType
The type of vector norm to compute.
ETrans
Whether to apply the (conjugate) transpose of an operator.
static const double polyTol
Relative residual tolerance for matrix polynomial construction.

Generated for Belos by doxygen 1.9.8