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"
28
29#include "Teuchos_ScalarTraits.hpp"
30#include "Teuchos_ParameterList.hpp"
31#include "Teuchos_TimeMonitor.hpp"
32
43namespace Belos {
44
46
47
52 template <class ScalarType, class MV, class DM>
53 class CGIterationState : public CGIterationStateBase<ScalarType, MV, DM> {
54
55 public:
56 CGIterationState() = default;
57
58 CGIterationState(Teuchos::RCP<const MV> tmp) {
60 }
61
62 virtual ~CGIterationState() = default;
63
64 void initialize(Teuchos::RCP<const MV> tmp, int _numVectors) {
67
68 // S = (R, Z)
69 // This allows to compute the inner products (R, S) = ((R, R), (R, Z)) using a single reduction.
70 S = MVT::Clone( *tmp, 2 );
71 std::vector<int> index(1,0);
72 index[0] = 0;
73 this->R = MVT::CloneViewNonConst( *S, index );
74 index[0] = 1;
75 this->Z = MVT::CloneViewNonConst( *S, index );
76
77 this->P = MVT::Clone( *tmp, 1 );
78 this->AP = MVT::Clone(*tmp, 1);
79
81 }
82
83 bool matches(Teuchos::RCP<const MV> tmp, int _numVectors=1) const {
85 !S.is_null());
86 }
87
88 Teuchos::RCP<MV> S;
89
90};
91
92template<class ScalarType, class MV, class OP, class DM>
93class CGIter : virtual public CGIteration<ScalarType,MV,OP,DM> {
94
95 public:
96
97 //
98 // Convenience typedefs
99 //
103 using SCT = Teuchos::ScalarTraits<ScalarType>;
104 using MagnitudeType = typename SCT::magnitudeType;
105
107
108
115 const Teuchos::RCP<OutputManager<ScalarType> > &printer,
116 const Teuchos::RCP<StatusTest<ScalarType,MV,OP,DM> > &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, DM> > newstate, Teuchos::RCP<MV> R_0);
157
162 {
163 initializeCG(Teuchos::null, Teuchos::null);
164 }
165
172 Teuchos::RCP<CGIterationStateBase<ScalarType,MV, DM> > getState() const {
173 auto state = Teuchos::rcp(new CGIterationState<ScalarType,MV,DM>());
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,DM> >(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,DM>& 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,DM> > lp_;
282 const Teuchos::RCP<OutputManager<ScalarType> > om_;
283 const Teuchos::RCP<StatusTest<ScalarType,MV,OP,DM> > stest_;
284 const Teuchos::RCP<StatusTestGenResNorm<ScalarType,MV,OP,DM> > 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, class DM>
336 const Teuchos::RCP<OutputManager<ScalarType> > &printer,
337 const Teuchos::RCP<StatusTest<ScalarType,MV,OP,DM> > &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, class DM>
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,DM> >(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, class DM>
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::RCP<DM> rHs = DMT::Create( 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 DMT::SyncDeviceToHost( *rHs );
452 rHr_ = DMT::ValueConst(*rHs,0,0);
453 rHz[0] = DMT::ValueConst(*rHs,0,1);
454 } else
455 MVT::MvDot( *R_, *Z_, rHz );
456
458 // Iterate until the status test tells us to stop.
459 //
460 while (stest_->checkStatus(this) != Passed) {
461
462 // Increment the iteration
463 iter_++;
464
465 // Multiply the current direction vector by A and store in AP_
466 lp_->applyOp( *P_, *AP_ );
467
468 // Compute alpha := <R_,Z_> / <P_,AP_>
469 MVT::MvDot( *P_, *AP_, pAp );
470 alpha[0] = rHz[0] / pAp[0];
471
472 // Check that alpha is a positive number!
473 if(assertPositiveDefiniteness_) {
475 "Belos::CGIter::iterate(): non-positive value for p^H*A*p encountered!" );
476 }
477
478 //
479 // Update the solution vector x := x + alpha * P_
480 //
481 MVT::MvAddMv( one, *cur_soln_vec, alpha[0], *P_, *cur_soln_vec );
482 lp_->updateSolution();
483 //
484 // Save the denominator of beta before residual is updated [ old <R_, Z_> ]
485 //
486 rHz_old[0] = rHz[0];
487 //
488 // Compute the new residual R_ := R_ - alpha * AP_
489 //
490 MVT::MvAddMv( one, *R_, -alpha[0], *AP_, *R_ );
491 //
492 // Compute beta := [ new <R_, Z_> ] / [ old <R_, Z_> ],
493 // and the new direction vector p.
494 //
495 if ( lp_->getLeftPrec() != Teuchos::null ) {
496 lp_->applyLeftPrec( *R_, *Z_ );
497 if ( lp_->getRightPrec() != Teuchos::null ) {
498 Teuchos::RCP<MV> tmp = MVT::CloneCopy( *Z_);
499 lp_->applyRightPrec( *tmp, *Z_ );
500 }
501 }
502 else if ( lp_->getRightPrec() != Teuchos::null ) {
503 lp_->applyRightPrec( *R_, *Z_ );
504 }
505 else {
506 MVT::Assign( *R_, *Z_ );
507 }
508 //
509 if (foldConvergenceDetectionIntoAllreduce_ && convTest_->getResNormType() == Belos::TwoNorm) {
510 MVT::MvTransMv( one, *R_, *S_, *rHs );
511 DMT::SyncDeviceToHost( *rHs );
512 rHr_ = DMT::ValueConst(*rHs,0,0);
513 rHz[0] = DMT::ValueConst(*rHs,0,1);
514 } else
515 MVT::MvDot( *R_, *Z_, rHz );
516 //
517 beta[0] = rHz[0] / rHz_old[0];
518 //
519 MVT::MvAddMv( one, *Z_, beta[0], *P_, *P_ );
520
521 // Condition estimate (if needed)
522 if (doCondEst_) {
523 if (iter_ > 1) {
524 diag_[iter_-1] = Teuchos::ScalarTraits<ScalarType>::real((beta_old * beta_old * pAp_old + pAp[0]) / rHz_old[0]);
525 offdiag_[iter_-2] = -Teuchos::ScalarTraits<ScalarType>::real(beta_old * pAp_old / (sqrt( rHz_old[0] * rHz_old2)));
526 }
527 else {
528 diag_[iter_-1] = Teuchos::ScalarTraits<ScalarType>::real(pAp[0] / rHz_old[0]);
529 }
530 rHz_old2 = rHz_old[0];
531 beta_old = beta[0];
532 pAp_old = pAp[0];
533 }
534
535 } // end while (sTest_->checkStatus(this) != Passed)
536 }
537
538} // end Belos namespace
539
540#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.
Pure virtual base class for defining the status testing capabilities of Belos.
Belos::StatusTestResNorm for specifying general residual norm stopping criteria.
Collection of types and exceptions used within the Belos solvers.
This class implements the preconditioned Conjugate Gradient (CG) iteration.
bool isInitialized()
States whether the solver has been initialized or not.
Teuchos::ArrayView< MagnitudeType > getOffDiag()
Gets the off-diagonal for condition estimation.
void iterate()
This method performs CG iterations until the status test indicates the need to stop or an error occur...
int getNumIters() const
Get the current iteration count.
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 with the initial vectors from the linear problem or random data.
void setDoCondEst(bool val)
Sets whether or not to store the diagonal for condition estimation.
void resetNumIters(int iter=0)
Reset the iteration count.
void setState(Teuchos::RCP< CGIterationStateBase< ScalarType, MV, DM > > state)
void setBlockSize(int blockSize)
Set the blocksize to be used by the iterative solver in solving this linear problem.
int getBlockSize() const
Get the blocksize to be used by the iterative solver in solving this linear problem.
CGIter(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::RCP< StatusTestGenResNorm< ScalarType, MV, OP, DM > > &convTester, Teuchos::ParameterList &params)
CGIter constructor with linear problem, solver utilities, and parameter list of solver options.
virtual ~CGIter()=default
Destructor.
Teuchos::ScalarTraits< ScalarType > SCT
void initializeCG(Teuchos::RCP< CGIterationStateBase< ScalarType, MV, DM > > newstate, Teuchos::RCP< MV > R_0)
Initialize the solver to an iterate, providing a complete state.
Teuchos::ArrayView< MagnitudeType > getDiag()
Gets the diagonal for condition estimation.
Teuchos::RCP< MV > getCurrentUpdate() const
Get the current update to the linear system.
const LinearProblem< ScalarType, MV, OP, DM > & getProblem() const
Get a constant reference to the linear problem.
typename SCT::magnitudeType MagnitudeType
Teuchos::RCP< CGIterationStateBase< ScalarType, MV, DM > > getState() const
Get the current state of the linear solver.
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 > AP
The matrix A applied to current decent direction vector.
Teuchos::RCP< MV > P
The current decent direction vector.
Teuchos::RCP< MV > R
The current residual.
virtual void initialize(Teuchos::RCP< const MV > tmp, int _numVectors)
Teuchos::RCP< MV > Z
The current preconditioned residual.
Structure to contain pointers to CGIteration state variables.
Teuchos::RCP< MV > S
virtual ~CGIterationState()=default
void initialize(Teuchos::RCP< const MV > tmp, int _numVectors)
CGIterationState(Teuchos::RCP< const MV > tmp)
bool matches(Teuchos::RCP< const MV > tmp, int _numVectors=1) const
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