Belos Version of the Day
Loading...
Searching...
No Matches
BelosCGIter.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_CG_ITER_HPP
11#define BELOS_CG_ITER_HPP
12
17#include "BelosConfigDefs.hpp"
18#include "BelosTypes.hpp"
19#include "BelosCGIteration.hpp"
20
23#include "BelosStatusTest.hpp"
27
28#include "Teuchos_SerialDenseMatrix.hpp"
29#include "Teuchos_SerialDenseVector.hpp"
30#include "Teuchos_ScalarTraits.hpp"
31#include "Teuchos_ParameterList.hpp"
32#include "Teuchos_TimeMonitor.hpp"
33
44namespace Belos {
45
47
48
53 template <class ScalarType, class MV>
54 class CGIterationState : public CGIterationStateBase<ScalarType, MV> {
55
56 public:
57 CGIterationState() = default;
58
59 CGIterationState(Teuchos::RCP<const MV> tmp) {
61 }
62
63 virtual ~CGIterationState() = default;
64
65 void initialize(Teuchos::RCP<const MV> tmp, int _numVectors) {
68
69 // S = (R, Z)
70 // This allows to compute the inner products (R, S) = ((R, R), (R, Z)) using a single reduction.
71 S = MVT::Clone( *tmp, 2 );
72 std::vector<int> index(1,0);
73 index[0] = 0;
74 this->R = MVT::CloneViewNonConst( *S, index );
75 index[0] = 1;
76 this->Z = MVT::CloneViewNonConst( *S, index );
77
78 this->P = MVT::Clone( *tmp, 1 );
79 this->AP = MVT::Clone(*tmp, 1);
80
82 }
83
84 bool matches(Teuchos::RCP<const MV> tmp, int _numVectors=1) const {
86 !S.is_null());
87 }
88
89 Teuchos::RCP<MV> S;
90
91};
92
93template<class ScalarType, class MV, class OP>
94class CGIter : virtual public CGIteration<ScalarType,MV,OP> {
95
96 public:
97
98 //
99 // Convenience typedefs
100 //
103 using SCT = Teuchos::ScalarTraits<ScalarType>;
104 using MagnitudeType = typename SCT::magnitudeType;
105
107
108
114 CGIter( const Teuchos::RCP<LinearProblem<ScalarType,MV,OP> > &problem,
115 const Teuchos::RCP<OutputManager<ScalarType> > &printer,
116 const Teuchos::RCP<StatusTest<ScalarType,MV,OP> > &tester,
118 Teuchos::ParameterList &params );
119
121 virtual ~CGIter() = default;
123
124
126
127
140 void iterate();
141
156 void initializeCG(Teuchos::RCP<CGIterationStateBase<ScalarType,MV> > newstate, Teuchos::RCP<MV> R_0);
157
162 {
163 initializeCG(Teuchos::null, Teuchos::null);
164 }
165
172 Teuchos::RCP<CGIterationStateBase<ScalarType,MV> > getState() const {
173 auto state = Teuchos::rcp(new CGIterationState<ScalarType,MV>());
174 state->R = R_;
175 state->P = P_;
176 state->AP = AP_;
177 state->Z = Z_;
178 state->S = S_;
179 return state;
180 }
181
183 auto s = Teuchos::rcp_dynamic_cast<CGIterationState<ScalarType,MV> >(state, true);
184 R_ = s->R;
185 Z_ = s->Z;
186 P_ = s->P;
187 AP_ = s->AP;
188 S_ = s->S;
189 }
190
192
193
195
196
198 int getNumIters() const { return iter_; }
199
201 void resetNumIters( int iter = 0 ) { iter_ = iter; }
202
205 Teuchos::RCP<const MV> getNativeResiduals( std::vector<MagnitudeType> * norms ) const {
206 if (foldConvergenceDetectionIntoAllreduce_ && convTest_->getResNormType() == Belos::TwoNorm) {
207 (*norms)[0] = std::sqrt(Teuchos::ScalarTraits<ScalarType>::magnitude(rHr_));
208 return Teuchos::null;
209 } else
210 return R_;
211 }
212
214
216 Teuchos::RCP<MV> getCurrentUpdate() const { return Teuchos::null; }
217
219
221
222
224 const LinearProblem<ScalarType,MV,OP>& getProblem() const { return *lp_; }
225
227 int getBlockSize() const { return 1; }
228
231 TEUCHOS_TEST_FOR_EXCEPTION(blockSize!=1,std::invalid_argument,
232 "Belos::CGIter::setBlockSize(): Cannot use a block size that is not one.");
233 }
234
236 bool isInitialized() { return initialized_; }
237
238
240 void setDoCondEst(bool val) {
241 if (numEntriesForCondEst_ != 0) doCondEst_=val;
242 }
243
245 Teuchos::ArrayView<MagnitudeType> getDiag() {
246 // NOTE (mfh 30 Jul 2015) See note on getOffDiag() below.
247 // getDiag() didn't actually throw for me in that case, but why
248 // not be cautious?
249 using size_type = typename Teuchos::ArrayView<MagnitudeType>::size_type;
250 if (static_cast<size_type> (iter_) >= diag_.size ()) {
251 return diag_ ();
252 } else {
253 return diag_ (0, iter_);
254 }
255 }
256
258 Teuchos::ArrayView<MagnitudeType> getOffDiag() {
259 // NOTE (mfh 30 Jul 2015) The implementation as I found it
260 // returned "offdiag(0,iter_)". This breaks (Teuchos throws in
261 // debug mode) when the maximum number of iterations has been
262 // reached, because iter_ == offdiag_.size() in that case. The
263 // new logic fixes this.
264 using size_type = typename Teuchos::ArrayView<MagnitudeType>::size_type;
265 if (static_cast<size_type> (iter_) >= offdiag_.size ()) {
266 return offdiag_ ();
267 } else {
268 return offdiag_ (0, iter_);
269 }
270 }
271
273
274 private:
275
276 //
277 // Internal methods
278 //
279 // Classes inputed through constructor that define the linear problem to be solved.
280 //
281 const Teuchos::RCP<LinearProblem<ScalarType,MV,OP> > lp_;
282 const Teuchos::RCP<OutputManager<ScalarType> > om_;
283 const Teuchos::RCP<StatusTest<ScalarType,MV,OP> > stest_;
284 const Teuchos::RCP<StatusTestGenResNorm<ScalarType,MV,OP> > convTest_;
285
286 //
287 // Current solver state
288 //
289 // initialized_ specifies that the basis vectors have been initialized and the iterate() routine
290 // is capable of running; _initialize is controlled by the initialize() member method
291 // For the implications of the state of initialized_, please see documentation for initialize()
292 bool initialized_;
293
294 // Current number of iterations performed.
295 int iter_;
296
297 // Should the allreduce for convergence detection be merged with one of the inner products?
298 bool foldConvergenceDetectionIntoAllreduce_;
299
300 // <r,r>
301 ScalarType rHr_;
302
303 // Assert that the matrix is positive definite
304 bool assertPositiveDefiniteness_;
305
306 // Tridiagonal system for condition estimation (if needed)
307 Teuchos::ArrayRCP<MagnitudeType> diag_, offdiag_;
308 int numEntriesForCondEst_;
309 bool doCondEst_;
310
311
312
313 //
314 // State Storage
315 //
316 // Residual
317 Teuchos::RCP<MV> R_;
318 //
319 // Preconditioned residual
320 Teuchos::RCP<MV> Z_;
321 //
322 // Direction vector
323 Teuchos::RCP<MV> P_;
324 //
325 // Operator applied to direction vector
326 Teuchos::RCP<MV> AP_;
327
328 Teuchos::RCP<MV> S_;
329
330};
331
333 // Constructor.
334 template<class ScalarType, class MV, class OP>
336 const Teuchos::RCP<OutputManager<ScalarType> > &printer,
337 const Teuchos::RCP<StatusTest<ScalarType,MV,OP> > &tester,
339 Teuchos::ParameterList &params ):
340 lp_(problem),
341 om_(printer),
342 stest_(tester),
343 convTest_(convTester),
344 initialized_(false),
345 iter_(0),
346 assertPositiveDefiniteness_( params.get("Assert Positive Definiteness", true) ),
347 numEntriesForCondEst_(params.get("Max Size For Condest",0) ),
348 doCondEst_(false)
349 {
350 foldConvergenceDetectionIntoAllreduce_ = params.get<bool>("Fold Convergence Detection Into Allreduce",false);
351 }
352
353
355 // Initialize this iteration object
356 template <class ScalarType, class MV, class OP>
358 {
359 // Initialize the state storage if it isn't already.
360 Teuchos::RCP<const MV> lhsMV = lp_->getLHS();
361 Teuchos::RCP<const MV> rhsMV = lp_->getRHS();
362 Teuchos::RCP<const MV> tmp = ( (rhsMV!=Teuchos::null)? rhsMV: lhsMV );
363 TEUCHOS_ASSERT(!newstate.is_null());
364 if (!Teuchos::rcp_dynamic_cast<CGIterationState<ScalarType,MV> >(newstate, true)->matches(tmp, 1))
365 newstate->initialize(tmp, 1);
366 setState(newstate);
367
368 // Tracking information for condition number estimation
369 if(numEntriesForCondEst_ > 0) {
370 diag_.resize(numEntriesForCondEst_);
371 offdiag_.resize(numEntriesForCondEst_-1);
372 }
373
374 std::string errstr("Belos::CGIter::initialize(): Specified multivectors must have a consistent length and width.");
375 {
376
377 TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetGlobalLength(*R_0) != MVT::GetGlobalLength(*R_),
378 std::invalid_argument, errstr );
379 TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetNumberVecs(*R_0) != 1,
380 std::invalid_argument, errstr );
381
382 // Copy basis vectors from newstate into V
383 if (R_0 != R_) {
384 // copy over the initial residual (unpreconditioned).
385 MVT::Assign( *R_0, *R_ );
386 }
387
388 // Compute initial direction vectors
389 // Initially, they are set to the preconditioned residuals
390 //
391 if ( lp_->getLeftPrec() != Teuchos::null ) {
392 lp_->applyLeftPrec( *R_, *Z_ );
393 if ( lp_->getRightPrec() != Teuchos::null ) {
394 Teuchos::RCP<MV> tmp2 = MVT::CloneCopy( *Z_ );
395 lp_->applyRightPrec( *tmp2, *Z_ );
396 }
397 }
398 else if ( lp_->getRightPrec() != Teuchos::null ) {
399 lp_->applyRightPrec( *R_, *Z_ );
400 }
401 else {
402 MVT::Assign( *R_, *Z_ );
403 }
404 MVT::Assign( *Z_, *P_ );
405 }
406
407 // The solver is initialized
408 initialized_ = true;
409 }
410
411
413 // Iterate until the status test informs us we should stop.
414 template <class ScalarType, class MV, class OP>
416 {
417 //
418 // Allocate/initialize data structures
419 //
420 if (!initialized_) {
421 initialize();
422 }
423
424 // Allocate memory for scalars.
425 std::vector<ScalarType> alpha(1);
426 std::vector<ScalarType> beta(1);
427 std::vector<ScalarType> rHz(1);
428 std::vector<ScalarType> rHz_old(1);
429 std::vector<ScalarType> pAp(1);
430 Teuchos::SerialDenseMatrix<int,ScalarType> rHs( 1, 2 );
431
432 // Create convenience variables for zero and one.
433 const ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
434 const MagnitudeType zero = Teuchos::ScalarTraits<MagnitudeType>::zero();
435
436 // Scalars for condition estimation (if needed) - These will always use entry zero, for convenience
440
441 // Get the current solution vector.
442 Teuchos::RCP<MV> cur_soln_vec = lp_->getCurrLHSVec();
443
444 // Check that the current solution vector only has one column.
445 TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetNumberVecs(*cur_soln_vec) != 1, CGIterateFailure,
446 "Belos::CGIter::iterate(): current linear system has more than one vector!" );
447
448 // Compute first <r,z> a.k.a. rHz
449 if (foldConvergenceDetectionIntoAllreduce_ && convTest_->getResNormType() == Belos::TwoNorm) {
450 MVT::MvTransMv( one, *R_, *S_, rHs );
451 rHr_ = rHs(0,0);
452 rHz[0] = rHs(0,1);
453 } else
454 MVT::MvDot( *R_, *Z_, rHz );
455
457 // Iterate until the status test tells us to stop.
458 //
459 while (stest_->checkStatus(this) != Passed) {
460
461 // Increment the iteration
462 iter_++;
463
464 // Multiply the current direction vector by A and store in AP_
465 lp_->applyOp( *P_, *AP_ );
466
467 // Compute alpha := <R_,Z_> / <P_,AP_>
468 MVT::MvDot( *P_, *AP_, pAp );
469 alpha[0] = rHz[0] / pAp[0];
470
471 // Check that alpha is a positive number!
472 if(assertPositiveDefiniteness_) {
474 "Belos::CGIter::iterate(): non-positive value for p^H*A*p encountered!" );
475 }
476
477 //
478 // Update the solution vector x := x + alpha * P_
479 //
480 MVT::MvAddMv( one, *cur_soln_vec, alpha[0], *P_, *cur_soln_vec );
481 lp_->updateSolution();
482 //
483 // Save the denominator of beta before residual is updated [ old <R_, Z_> ]
484 //
485 rHz_old[0] = rHz[0];
486 //
487 // Compute the new residual R_ := R_ - alpha * AP_
488 //
489 MVT::MvAddMv( one, *R_, -alpha[0], *AP_, *R_ );
490 //
491 // Compute beta := [ new <R_, Z_> ] / [ old <R_, Z_> ],
492 // and the new direction vector p.
493 //
494 if ( lp_->getLeftPrec() != Teuchos::null ) {
495 lp_->applyLeftPrec( *R_, *Z_ );
496 if ( lp_->getRightPrec() != Teuchos::null ) {
497 Teuchos::RCP<MV> tmp = MVT::CloneCopy( *Z_);
498 lp_->applyRightPrec( *tmp, *Z_ );
499 }
500 }
501 else if ( lp_->getRightPrec() != Teuchos::null ) {
502 lp_->applyRightPrec( *R_, *Z_ );
503 }
504 else {
505 MVT::Assign( *R_, *Z_ );
506 }
507 //
508 if (foldConvergenceDetectionIntoAllreduce_ && convTest_->getResNormType() == Belos::TwoNorm) {
509 MVT::MvTransMv( one, *R_, *S_, rHs );
510 rHr_ = rHs(0,0);
511 rHz[0] = rHs(0,1);
512 } else
513 MVT::MvDot( *R_, *Z_, rHz );
514 //
515 beta[0] = rHz[0] / rHz_old[0];
516 //
517 MVT::MvAddMv( one, *Z_, beta[0], *P_, *P_ );
518
519 // Condition estimate (if needed)
520 if (doCondEst_) {
521 if (iter_ > 1) {
522 diag_[iter_-1] = Teuchos::ScalarTraits<ScalarType>::real((beta_old * beta_old * pAp_old + pAp[0]) / rHz_old[0]);
523 offdiag_[iter_-2] = -Teuchos::ScalarTraits<ScalarType>::real(beta_old * pAp_old / (sqrt( rHz_old[0] * rHz_old2)));
524 }
525 else {
526 diag_[iter_-1] = Teuchos::ScalarTraits<ScalarType>::real(pAp[0] / rHz_old[0]);
527 }
528 rHz_old2 = rHz_old[0];
529 beta_old = beta[0];
530 pAp_old = pAp[0];
531 }
532
533 } // end while (sTest_->checkStatus(this) != Passed)
534 }
535
536} // end Belos namespace
537
538#endif /* BELOS_CG_ITER_HPP */
Pure virtual base class which augments the basic interface for a conjugate gradient linear solver ite...
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.
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.
Belos::StatusTestResNorm for specifying general residual norm stopping criteria.
Pure virtual base class for defining the status testing capabilities of Belos.
Collection of types and exceptions used within the Belos solvers.
This class implements the preconditioned Conjugate Gradient (CG) iteration.
void iterate()
This method performs CG iterations until the status test indicates the need to stop or an error occur...
virtual ~CGIter()=default
Destructor.
void initialize()
Initialize the solver with the initial vectors from the linear problem or random data.
Teuchos::RCP< const MV > getNativeResiduals(std::vector< MagnitudeType > *norms) const
Get the norms of the residuals native to the solver.
const LinearProblem< ScalarType, MV, OP > & getProblem() const
Get a constant reference to the linear problem.
int getBlockSize() const
Get the blocksize to be used by the iterative solver in solving this linear problem.
void setState(Teuchos::RCP< CGIterationStateBase< ScalarType, MV > > state)
void initializeCG(Teuchos::RCP< CGIterationStateBase< ScalarType, MV > > newstate, Teuchos::RCP< MV > R_0)
Initialize the solver to an iterate, providing a complete state.
int getNumIters() const
Get the current iteration count.
bool isInitialized()
States whether the solver has been initialized or not.
void setBlockSize(int blockSize)
Set the blocksize to be used by the iterative solver in solving this linear problem.
void setDoCondEst(bool val)
Sets whether or not to store the diagonal for condition estimation.
Teuchos::RCP< MV > getCurrentUpdate() const
Get the current update to the linear system.
Teuchos::ArrayView< MagnitudeType > getOffDiag()
Gets the off-diagonal for condition estimation.
Teuchos::RCP< CGIterationStateBase< ScalarType, MV > > getState() const
Get the current state of the linear solver.
void resetNumIters(int iter=0)
Reset the iteration count.
typename SCT::magnitudeType MagnitudeType
CGIter(const Teuchos::RCP< LinearProblem< ScalarType, MV, OP > > &problem, const Teuchos::RCP< OutputManager< ScalarType > > &printer, const Teuchos::RCP< StatusTest< ScalarType, MV, OP > > &tester, const Teuchos::RCP< StatusTestGenResNorm< ScalarType, MV, OP > > &convTester, Teuchos::ParameterList &params)
CGIter constructor with linear problem, solver utilities, and parameter list of solver options.
Teuchos::ScalarTraits< ScalarType > SCT
Teuchos::ArrayView< MagnitudeType > getDiag()
Gets the diagonal for condition estimation.
CGIterateFailure is thrown when the CGIteration object is unable to compute the next iterate in the C...
Structure to contain pointers to CGIteration state variables.
Teuchos::RCP< MV > R
The current residual.
Teuchos::RCP< MV > P
The current decent direction vector.
virtual void initialize(Teuchos::RCP< const MV > tmp, int _numVectors)
Teuchos::RCP< MV > Z
The current preconditioned residual.
Teuchos::RCP< MV > AP
The matrix A applied to current decent direction vector.
Structure to contain pointers to CGIteration state variables.
virtual ~CGIterationState()=default
CGIterationState(Teuchos::RCP< const MV > tmp)
Teuchos::RCP< MV > S
bool matches(Teuchos::RCP< const MV > tmp, int _numVectors=1) const
void initialize(Teuchos::RCP< const MV > tmp, int _numVectors)
CGPositiveDefiniteFailure is thrown when the the CG 'alpha = p^H*A*P' value is less than zero,...
Alternative run-time polymorphic interface for operators.
Operator()
Default constructor (does nothing).

Generated for Belos by doxygen 1.9.8