Belos Version of the Day
Loading...
Searching...
No Matches
BelosMinresIter.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_MINRES_ITER_HPP
11#define BELOS_MINRES_ITER_HPP
12
29
30#include "BelosConfigDefs.hpp"
31#include "BelosTypes.hpp"
33
36#include "BelosStatusTest.hpp"
40
41#include "Teuchos_ScalarTraits.hpp"
42#include "Teuchos_ParameterList.hpp"
43#include "Teuchos_TimeMonitor.hpp"
44
45namespace Belos {
46
60template<class ScalarType, class MV, class OP, class DM>
61class MinresIter : virtual public MinresIteration<ScalarType,MV,OP,DM> {
62
63 public:
64
65 //
66 // Convenience typedefs
67 //
71 typedef Teuchos::ScalarTraits< ScalarType > SCT;
72 typedef typename SCT::magnitudeType MagnitudeType;
73 typedef Teuchos::ScalarTraits< MagnitudeType > SMT;
74
76
77
87 const Teuchos::RCP< OutputManager< ScalarType > > & printer,
88 const Teuchos::RCP< StatusTest< ScalarType, MV, OP, DM> >& tester,
89 const Teuchos::ParameterList& params);
90
92 virtual ~MinresIter() {};
94
95
97
98
113 void iterate();
114
130
141
149 if (! isInitialized())
150 throw std::logic_error("getState() cannot be called unless "
151 "the state has been initialized");
153 state.Y = Y_;
154 state.R1 = R1_;
155 state.R2 = R2_;
156 state.W = W_;
157 state.W1 = W1_;
158 state.W2 = W2_;
159 return state;
160 }
161
163
164
166
167
169 int getNumIters() const { return iter_; }
170
172 void resetNumIters( int iter = 0 ) { iter_ = iter; }
173
176 Teuchos::RCP<const MV>
177 getNativeResiduals( std::vector<MagnitudeType> *norms ) const
178 {
179 if (norms != NULL)
180 {
181 std::vector<MagnitudeType>& theNorms = *norms;
182 if (theNorms.size() < 1)
183 theNorms.resize(1);
184 theNorms[0] = phibar_;
185 }
186 return Teuchos::null;
187 }
188
190
192 Teuchos::RCP<MV> getCurrentUpdate() const { return Teuchos::null; }
193
196
198
200
201
203 const LinearProblem<ScalarType,MV,OP,DM>& getProblem() const { return *lp_; }
204
206 int getBlockSize() const { return 1; }
207
210 TEUCHOS_TEST_FOR_EXCEPTION(blockSize!=1,std::invalid_argument,
211 "Belos::MinresIter::setBlockSize(): Cannot use a block size that is not one.");
212 }
213
215 bool isInitialized() const { return initialized_; }
216 bool isInitialized() { return initialized_; }
217
219
220 private:
221
222 //
223 // Internal methods
224 //
226 void setStateSize();
227
228 //
229 // Classes inputed through constructor that define the linear problem to be solved.
230 //
231 const Teuchos::RCP< LinearProblem< ScalarType, MV, OP, DM> > lp_;
232 const Teuchos::RCP< OutputManager< ScalarType > > om_;
233 const Teuchos::RCP< StatusTest< ScalarType, MV, OP, DM > > stest_;
234
235
243 bool initialized_;
244
251 bool stateStorageInitialized_;
252
254 int iter_;
255
260 MagnitudeType phibar_;
261
262 //
263 // State Storage
264 //
265
267 Teuchos::RCP< MV > Y_;
269 Teuchos::RCP< MV > R1_;
271 Teuchos::RCP< MV > R2_;
273 Teuchos::RCP< MV > W_;
275 Teuchos::RCP< MV > W1_;
277 Teuchos::RCP< MV > W2_;
278
280 ScalarType beta1_;
281 Teuchos::RCP<DM> tmpDM;
282
283};
284
286 // Constructor.
287 template<class ScalarType, class MV, class OP, class DM>
289 const Teuchos::RCP<OutputManager<ScalarType> > &printer,
290 const Teuchos::RCP<StatusTest<ScalarType,MV,OP,DM> > &tester,
291 const Teuchos::ParameterList &/* params */ ):
292 lp_(problem),
293 om_(printer),
294 stest_(tester),
295 initialized_(false),
296 stateStorageInitialized_(false),
297 iter_(0),
298 phibar_(0.0)
299 {
300 }
301
303 // Setup the state storage.
304 template <class ScalarType, class MV, class OP, class DM>
306 {
307 if (!stateStorageInitialized_) {
308
309 // Check if there is any multivector to clone from.
310 Teuchos::RCP< const MV > lhsMV = lp_->getLHS();
311 Teuchos::RCP< const MV > rhsMV = lp_->getRHS();
312 if (lhsMV == Teuchos::null && rhsMV == Teuchos::null) {
313 stateStorageInitialized_ = false;
314 return;
315 }
316 else {
317
318 // Initialize the state storage
319 // If the subspace has not be initialized before, generate it using the LHS or RHS from lp_.
320 if (Y_ == Teuchos::null) {
321 // Get the multivector that is not null.
322 Teuchos::RCP< const MV > tmp = ( (rhsMV!=Teuchos::null)? rhsMV: lhsMV );
323 TEUCHOS_TEST_FOR_EXCEPTION( tmp == Teuchos::null,
324 std::invalid_argument,
325 "Belos::MinresIter::setStateSize(): linear problem does not specify multivectors to clone from.");
326 Y_ = MVT::Clone( *tmp, 1 );
327 R1_ = MVT::Clone( *tmp, 1 );
328 R2_ = MVT::Clone( *tmp, 1 );
329 W_ = MVT::Clone( *tmp, 1 );
330 W1_ = MVT::Clone( *tmp, 1 );
331 W2_ = MVT::Clone( *tmp, 1 );
332 }
333 // State storage has now been initialized.
334 stateStorageInitialized_ = true;
335 }
336 }
337 }
338
339
341 // Initialize this iteration object
342 template <class ScalarType, class MV, class OP, class DM>
344 {
345 // Initialize the state storage if it isn't already.
346 if (!stateStorageInitialized_)
347 setStateSize();
348
349 TEUCHOS_TEST_FOR_EXCEPTION( !stateStorageInitialized_,
350 std::invalid_argument,
351 "Belos::MinresIter::initialize(): Cannot initialize state storage!" );
352
353 TEUCHOS_TEST_FOR_EXCEPTION( newstate.Y == Teuchos::null,
354 std::invalid_argument,
355 "Belos::MinresIter::initialize(): MinresIterationState does not have initial residual.");
356
357 std::string errstr("Belos::MinresIter::initialize(): Specified multivectors must have a consistent length and width.");
358 TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetGlobalLength(*newstate.Y) != MVT::GetGlobalLength(*Y_),
359 std::invalid_argument,
360 errstr );
361 TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetNumberVecs(*newstate.Y) != 1,
362 std::invalid_argument,
363 errstr );
364
365 // Create convenience variables for zero, one.
366 const ScalarType one = SCT::one();
367 const MagnitudeType m_zero = SMT::zero();
368
369 // Set up y and v for the first Lanczos vector v_1.
370 // y = beta1_ P' v1, where P = C**(-1).
371 // v is really P' v1.
372 MVT::Assign( *newstate.Y, *R2_ );
373 MVT::Assign( *newstate.Y, *R1_ );
374
375 // Initialize the W's to 0.
376 MVT::MvInit ( *W_ );
377 MVT::MvInit ( *W2_ );
378
379 if ( lp_->getLeftPrec() != Teuchos::null ) {
380 lp_->applyLeftPrec( *newstate.Y, *Y_ );
381 if ( lp_->getRightPrec() != Teuchos::null ) {
382 Teuchos::RCP<MV> tmp = MVT::CloneCopy( *Y_ );
383 lp_->applyRightPrec( *tmp, *Y_ );
384 }
385 }
386 else if ( lp_->getRightPrec() != Teuchos::null ) {
387 lp_->applyRightPrec( *newstate.Y, *Y_ );
388 }
389 else {
390 if (newstate.Y != Y_) {
391 // copy over the initial residual (unpreconditioned).
392 MVT::Assign( *newstate.Y, *Y_ );
393 }
394 }
395
396 // beta1_ = b'*y;
397
398 tmpDM = DMT::Create(1,1);
399 MVT::MvTransMv( one, *newstate.Y, *Y_, *tmpDM);
400 DMT::SyncDeviceToHost(*tmpDM);
401 beta1_ = DMT::ValueConst(*tmpDM,0,0);
402
403 TEUCHOS_TEST_FOR_EXCEPTION( SCT::real(beta1_) < m_zero,
404 std::invalid_argument,
405 "The preconditioner is not positive definite." );
406
407 if( SCT::magnitude(beta1_) == m_zero )
408 {
409 // X = 0
410 Teuchos::RCP<MV> cur_soln_vec = lp_->getCurrLHSVec();
411 MVT::MvInit( *cur_soln_vec );
412 }
413
414 beta1_ = SCT::squareroot( beta1_ );
415
416 // The solver is initialized
417 initialized_ = true;
418 }
419
420
422 // Iterate until the status test informs us we should stop.
423 template <class ScalarType, class MV, class OP, class DM>
425 {
426 //
427 // Allocate/initialize data structures
428 //
429 if (initialized_ == false) {
430 initialize();
431 }
432
433 // Create convenience variables for zero and one.
434 const ScalarType one = SCT::one();
435 const ScalarType zero = SCT::zero();
436 const MagnitudeType m_zero = SMT::zero();
437
438 // Allocate memory for scalars.
439 ScalarType alpha, beta = beta1_;
440 phibar_ = Teuchos::ScalarTraits<ScalarType>::magnitude( beta1_ );
441
442 // Initialize a few variables.
445 ScalarType cs = -one;
446 ScalarType sn = zero;
448
449 // Declare a few others that will be initialized in the loop.
455
456 // Allocate workspace.
457 Teuchos::RCP<MV> V = MVT::Clone( *Y_, 1 );
458 Teuchos::RCP<MV> tmpY, tmpW; // Not allocated, just used to transfer ownership.
459
460 // Get the current solution vector.
461 Teuchos::RCP<MV> cur_soln_vec = lp_->getCurrLHSVec();
462
463 // Check that the current solution vector only has one column.
464 TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetNumberVecs(*cur_soln_vec) != 1,
466 "Belos::MinresIter::iterate(): current linear system has more than one vector!" );
467
469 // Iterate until the status test tells us to stop.
470 //
471 while (stest_->checkStatus(this) != Passed) {
472
473 // Increment the iteration
474 iter_++;
475
476 // Normalize previous vector.
477 // v = y / beta(0,0);
478 MVT::MvAddMv (one / beta, *Y_, zero, *Y_, *V);
479
480 // Apply operator.
481 lp_->applyOp (*V, *Y_);
482
483 if (iter_ > 1)
484 MVT::MvAddMv (one, *Y_, -beta/oldBeta, *R1_, *Y_);
485
486 // alpha := dot(V, Y_)
487 MVT::MvTransMv (one, *V, *Y_, *tmpDM);
488 DMT::SyncDeviceToHost(*tmpDM);
489 alpha = DMT::ValueConst(*tmpDM,0,0);
490
491 // y := y - alpha/beta r2
492 MVT::MvAddMv (one, *Y_, -alpha/beta, *R2_, *Y_);
493
494 // r1 = r2;
495 // r2 = y;
496 tmpY = R1_;
497 R1_ = R2_;
498 R2_ = Y_;
499 Y_ = tmpY;
500
501 // apply preconditioner
502 if ( lp_->getLeftPrec() != Teuchos::null ) {
503 lp_->applyLeftPrec( *R2_, *Y_ );
504 if ( lp_->getRightPrec() != Teuchos::null ) {
505 Teuchos::RCP<MV> tmp = MVT::CloneCopy( *Y_ );
506 lp_->applyRightPrec( *tmp, *Y_ );
507 }
508 }
509 else if ( lp_->getRightPrec() != Teuchos::null ) {
510 lp_->applyRightPrec( *R2_, *Y_ );
511 } // else "y = r2"
512 else {
513 MVT::Assign( *R2_, *Y_ );
514 }
515
516 // Get new beta.
517 oldBeta = beta;
518 MVT::MvTransMv( one, *R2_, *Y_, *tmpDM);
519 DMT::SyncDeviceToHost(*tmpDM);
520 beta = DMT::ValueConst(*tmpDM,0,0);
521
522 // Intercept beta <= 0.
523 //
524 // Note: we don't try to test for nonzero imaginary component of
525 // beta, because (a) it could be small and nonzero due to
526 // rounding error in computing the inner product, and (b) it's
527 // hard to tell how big "not small" should be, without computing
528 // some error bounds (for example, by modifying the linear
529 // algebra library to compute a posteriori rounding error bounds
530 // for the inner product, and then changing
531 // Belos::MultiVecTraits to make this information available).
532 TEUCHOS_TEST_FOR_EXCEPTION( SCT::real(beta) < m_zero,
534 "Belos::MinresIter::iterate(): Encountered negative "
535 "value " << beta << " for r2^H*M*r2 at itera"
536 "tion " << iter_ << ": MINRES cannot continue." );
537 beta = SCT::squareroot( beta );
538
539 // Apply previous rotation Q_{k-1} to get
540 //
541 // [delta_k epsln_{k+1}] = [cs sn][dbar_k 0 ]
542 // [gbar_k dbar_{k+1} ] [-sn cs][alpha_k beta_{k+1}].
543 //
544 oldeps = epsln;
545 delta = cs*dbar + sn*alpha;
546 gbar = sn*dbar - cs*alpha;
547 epsln = sn*beta;
548 dbar = - cs*beta;
549
550 // Compute the next plane rotation Q_k.
551 this->symOrtho(gbar, beta, &cs, &sn, &gamma);
552
553 phi = cs * phibar_; // phi_k
554 phibar_ = Teuchos::ScalarTraits<ScalarType>::magnitude( sn * phibar_ ); // phibar_{k+1}
555
556 // w1 = w2;
557 // w2 = w;
558 MVT::Assign( *W_, *W1_ );
559 tmpW = W1_;
560 W1_ = W2_;
561 W2_ = W_;
562 W_ = tmpW;
563
564 // w = (v - oldeps*w1 - delta*w2) / gamma;
565 MVT::MvAddMv( one, *V, -oldeps, *W1_, *W_ );
566 MVT::MvAddMv( one, *W_, -delta, *W2_, *W_ );
567 MVT::MvScale( *W_, one / gamma );
568
569 // Update x:
570 // x = x + phi*w;
571 MVT::MvAddMv( one, *cur_soln_vec, phi, *W_, *cur_soln_vec );
572 lp_->updateSolution();
573 } // end while (sTest_->checkStatus(this) != Passed)
574 }
575
576
578 // Compute the next plane rotation Qk.
579 // r = norm([a b]);
580 // c = a / r;
581 // s = b / r;
582 template <class ScalarType, class MV, class OP, class DM>
585 )
586 {
587 const ScalarType one = SCT::one();
588 const ScalarType zero = SCT::zero();
589 const MagnitudeType m_zero = SMT::zero();
590 const MagnitudeType absA = SCT::magnitude( a );
591 const MagnitudeType absB = SCT::magnitude( b );
592 if ( absB == m_zero ) {
593 *s = zero;
594 *r = absA;
595 if ( absA == m_zero )
596 *c = one;
597 else
598 *c = a / absA;
599 } else if ( absA == m_zero ) {
600 *c = zero;
601 *s = b / absB;
602 *r = absB;
603 } else if ( absB >= absA ) { // && a!=0 && b!=0
604 ScalarType tau = a / b;
605 if ( Teuchos::ScalarTraits<ScalarType>::real(b) < m_zero )
606 *s = -one / SCT::squareroot( one+tau*tau );
607 else
608 *s = one / SCT::squareroot( one+tau*tau );
609 *c = *s * tau;
610 *r = b / *s;
611 } else { // (absA > absB) && a!=0 && b!=0
612 ScalarType tau = b / a;
613 if ( Teuchos::ScalarTraits<ScalarType>::real(a) < m_zero )
614 *c = -one / SCT::squareroot( one+tau*tau );
615 else
616 *c = one / SCT::squareroot( one+tau*tau );
617 *s = *c * tau;
618 *r = a / *c;
619 }
620 }
621
622} // end Belos namespace
623
624#endif /* BELOS_MINRES_ITER_HPP */
Belos header file which uses auto-configuration information to include necessary C++ headers.
Class which describes the linear problem to be solved by the iterative solver.
Pure virtual base class which augments the basic interface for a minimal residual linear solver itera...
Declaration of basic traits for the multivector type.
Class which defines basic traits for the operator type.
Class which manages the output and verbosity of the Belos solvers.
Pure virtual base class for defining the status testing capabilities of Belos.
Collection of types and exceptions used within the Belos solvers.
MINRES implementation.
SCT::magnitudeType MagnitudeType
int getBlockSize() const
Get the blocksize to be used by the iterative solver in solving this linear problem.
Teuchos::ScalarTraits< MagnitudeType > SMT
int getNumIters() const
Get the current iteration count.
MultiVecTraits< ScalarType, MV, DM > MVT
void setBlockSize(int blockSize)
Set the blocksize to be used by the iterative solver in solving this linear problem.
DenseMatTraits< ScalarType, DM > DMT
const LinearProblem< ScalarType, MV, OP, DM > & getProblem() const
Get a constant reference to the linear problem.
MinresIter(const Teuchos::RCP< LinearProblem< ScalarType, MV, OP, DM > > &problem, const Teuchos::RCP< OutputManager< ScalarType > > &printer, const Teuchos::RCP< StatusTest< ScalarType, MV, OP, DM > > &tester, const Teuchos::ParameterList &params)
Constructor.
virtual ~MinresIter()
Destructor.
Teuchos::ScalarTraits< ScalarType > SCT
Teuchos::RCP< const MV > getNativeResiduals(std::vector< MagnitudeType > *norms) const
Get the norms of the residuals native to the solver.
void initialize()
Initialize the solver.
bool isInitialized()
States whether the solver has been initialized or not.
void symOrtho(ScalarType a, ScalarType b, ScalarType *c, ScalarType *s, ScalarType *r)
OperatorTraits< ScalarType, MV, OP > OPT
void initializeMinres(const MinresIterationState< ScalarType, MV > &newstate)
Initialize the solver to an iterate, providing a complete state.
void iterate()
Perform MINRES iterations until convergence or error.
MinresIterationState< ScalarType, MV > getState() const
Get the current state of the linear solver.
Teuchos::RCP< MV > getCurrentUpdate() const
Get the current update to the linear system.
bool isInitialized() const
States whether the solver has been initialized or not.
void resetNumIters(int iter=0)
Reset the iteration count.
MinresIterateFailure is thrown when the MinresIteration object is unable to compute the next iterate ...
Alternative run-time polymorphic interface for operators.
Operator()
Default constructor (does nothing).

Generated for Belos by doxygen 1.9.8