Belos Version of the Day
Loading...
Searching...
No Matches
BelosPseudoBlockCGIter.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_PSEUDO_BLOCK_CG_ITER_HPP
11#define BELOS_PSEUDO_BLOCK_CG_ITER_HPP
12
17#include "BelosConfigDefs.hpp"
18#include "BelosTypes.hpp"
19#include "BelosCGIteration.hpp"
20
24#include "BelosStatusTest.hpp"
28
29#include "Teuchos_ScalarTraits.hpp"
30#include "Teuchos_ParameterList.hpp"
31#include "Teuchos_TimeMonitor.hpp"
32
44namespace Belos {
45
47
48
53 template <class ScalarType, class MV, class DM>
54 class PseudoBlockCGIterationState : public CGIterationStateBase<ScalarType, MV, DM> {
55
56 public:
58
59 PseudoBlockCGIterationState(Teuchos::RCP<const MV> tmp) {
61 }
62
63 virtual ~PseudoBlockCGIterationState() = default;
64
65 void initialize(Teuchos::RCP<const MV> tmp, int _numVectors) {
67 this->R = MVT::Clone( *tmp, _numVectors );
68 this->Z = MVT::Clone( *tmp, _numVectors );
69 this->P = MVT::Clone( *tmp, _numVectors );
70 this->AP = MVT::Clone(*tmp, _numVectors );
71
73 }
74
75 bool matches(Teuchos::RCP<const MV> tmp, int _numVectors=1) const {
77 }
78 };
79
80 template<class ScalarType, class MV, class OP, class DM>
81 class PseudoBlockCGIter : virtual public CGIteration<ScalarType,MV,OP,DM> {
82
83 public:
84
85 //
86 // Convenience typedefs
87 //
91 using SCT = Teuchos::ScalarTraits<ScalarType>;
92 using MagnitudeType = typename SCT::magnitudeType;
93
95
96
103 const Teuchos::RCP<OutputManager<ScalarType> > &printer,
104 const Teuchos::RCP<StatusTest<ScalarType,MV,OP,DM> > &tester,
105 Teuchos::ParameterList &params );
106
108 virtual ~PseudoBlockCGIter() = default;
110
111
113
114
128 void iterate();
129
150 void initializeCG(Teuchos::RCP<CGIterationStateBase<ScalarType,MV, DM> > newstate, Teuchos::RCP<MV> R_0);
151
156 {
157 initializeCG(Teuchos::null, Teuchos::null);
158 }
159
167 Teuchos::RCP<CGIterationStateBase<ScalarType,MV, DM> > getState() const {
168 auto state = Teuchos::rcp(new PseudoBlockCGIterationState<ScalarType,MV, DM>());
169 state->R = R_;
170 state->P = P_;
171 state->AP = AP_;
172 state->Z = Z_;
173 return state;
174 }
175
177 auto s = Teuchos::rcp_dynamic_cast<PseudoBlockCGIterationState<ScalarType,MV, DM> >(state, true);
178 R_ = s->R;
179 Z_ = s->Z;
180 P_ = s->P;
181 AP_ = s->AP;
182 }
183
185
186
188
189
191 int getNumIters() const { return iter_; }
192
194 void resetNumIters( int iter = 0 ) { iter_ = iter; }
195
198 Teuchos::RCP<const MV> getNativeResiduals( std::vector<MagnitudeType> * /* norms */ ) const { return R_; }
199
201
203 Teuchos::RCP<MV> getCurrentUpdate() const { return Teuchos::null; }
204
206
208
209
211 const LinearProblem<ScalarType,MV,OP,DM>& getProblem() const { return *lp_; }
212
214 int getBlockSize() const { return 1; }
215
218 TEUCHOS_TEST_FOR_EXCEPTION(blockSize!=1,std::invalid_argument,
219 "Belos::PseudoBlockCGIter::setBlockSize(): Cannot use a block size that is not one.");
220 }
221
223 bool isInitialized() { return initialized_; }
224
226
228 void setDoCondEst(bool val) {
229 if (numEntriesForCondEst_ != 0) doCondEst_=val;
230 }
231
233 Teuchos::ArrayView<MagnitudeType> getDiag() {
234 // NOTE (mfh 30 Jul 2015) See note on getOffDiag() below.
235 // getDiag() didn't actually throw for me in that case, but why
236 // not be cautious?
237 using size_type = typename Teuchos::ArrayView<MagnitudeType>::size_type;
238 if (static_cast<size_type> (iter_) >= diag_.size ()) {
239 return diag_ ();
240 } else {
241 return diag_ (0, iter_);
242 }
243 }
244
246 Teuchos::ArrayView<MagnitudeType> getOffDiag() {
247 // NOTE (mfh 30 Jul 2015) The implementation as I found it
248 // returned "offdiag(0,iter_)". This breaks (Teuchos throws in
249 // debug mode) when the maximum number of iterations has been
250 // reached, because iter_ == offdiag_.size() in that case. The
251 // new logic fixes this.
252 using size_type = typename Teuchos::ArrayView<MagnitudeType>::size_type;
253 if (static_cast<size_type> (iter_) >= offdiag_.size ()) {
254 return offdiag_ ();
255 } else {
256 return offdiag_ (0, iter_);
257 }
258 }
259
260 private:
261
262 //
263 // Classes inputed through constructor that define the linear problem to be solved.
264 //
265 const Teuchos::RCP<LinearProblem<ScalarType,MV,OP,DM> > lp_;
266 const Teuchos::RCP<OutputManager<ScalarType> > om_;
267 const Teuchos::RCP<StatusTest<ScalarType,MV,OP,DM> > stest_;
268
269 //
270 // Algorithmic parameters
271 //
272 // numRHS_ is the current number of linear systems being solved.
273 int numRHS_;
274
275 //
276 // Current solver state
277 //
278 // initialized_ specifies that the basis vectors have been initialized and the iterate() routine
279 // is capable of running; _initialize is controlled by the initialize() member method
280 // For the implications of the state of initialized_, please see documentation for initialize()
281 bool initialized_;
282
283 // Current number of iterations performed.
284 int iter_;
285
286 // Assert that the matrix is positive definite
287 bool assertPositiveDefiniteness_;
288
289 // Tridiagonal system for condition estimation (if needed)
290 Teuchos::ArrayRCP<MagnitudeType> diag_, offdiag_;
291 ScalarType pAp_old_, beta_old_, rHz_old2_; // Put scalars here so that estimate is correct for multiple RHS, when deflation occurs.
292 int numEntriesForCondEst_;
293 bool doCondEst_;
294
295 //
296 // State Storage
297 //
298 // Residual
299 Teuchos::RCP<MV> R_;
300 //
301 // Preconditioned residual
302 Teuchos::RCP<MV> Z_;
303 //
304 // Direction vector
305 Teuchos::RCP<MV> P_;
306 //
307 // Operator applied to direction vector
308 Teuchos::RCP<MV> AP_;
309
310 };
311
313 // Constructor.
314 template<class ScalarType, class MV, class OP, class DM>
316 const Teuchos::RCP<OutputManager<ScalarType> > &printer,
317 const Teuchos::RCP<StatusTest<ScalarType,MV,OP,DM> > &tester,
318 Teuchos::ParameterList &params ):
319 lp_(problem),
320 om_(printer),
321 stest_(tester),
322 numRHS_(0),
323 initialized_(false),
324 iter_(0),
325 assertPositiveDefiniteness_( params.get("Assert Positive Definiteness", true) ),
326 numEntriesForCondEst_(params.get("Max Size For Condest",0) ),
327 doCondEst_(false)
328 {
329 }
330
331
333 // Initialize this iteration object
334 template<class ScalarType, class MV, class OP, class DM>
336 {
337 // Check if there is any mltivector to clone from.
338 Teuchos::RCP<const MV> lhsMV = lp_->getCurrLHSVec();
339 Teuchos::RCP<const MV> rhsMV = lp_->getCurrRHSVec();
340 TEUCHOS_TEST_FOR_EXCEPTION((lhsMV==Teuchos::null && rhsMV==Teuchos::null),std::invalid_argument,
341 "Belos::PseudoBlockCGIter::initialize(): Cannot initialize state storage!");
342
343 // Get the multivector that is not null.
344 Teuchos::RCP<const MV> tmp = ( (rhsMV!=Teuchos::null)? rhsMV: lhsMV );
345
346 // Get the number of right-hand sides we're solving for now.
347 int numRHS = MVT::GetNumberVecs(*tmp);
348 numRHS_ = numRHS;
349
350 // Initialize the state storage if it isn't already.
351 TEUCHOS_ASSERT(!newstate.is_null());
352 if (!Teuchos::rcp_dynamic_cast<PseudoBlockCGIterationState<ScalarType,MV, DM> >(newstate, true)->matches(tmp, numRHS_))
353 newstate->initialize(tmp, numRHS_);
354 setState(newstate);
355
356 // Tracking information for condition number estimation
357 if(numEntriesForCondEst_ > 0) {
358 diag_.resize(numEntriesForCondEst_);
359 offdiag_.resize(numEntriesForCondEst_-1);
360 }
361
362 std::string errstr("Belos::BlockPseudoCGIter::initialize(): Specified multivectors must have a consistent length and width.");
363 {
364
365 TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetGlobalLength(*R_0) != MVT::GetGlobalLength(*R_),
366 std::invalid_argument, errstr );
367 TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetNumberVecs(*R_0) != numRHS_,
368 std::invalid_argument, errstr );
369
370 // Copy basis vectors from newstate into V
371 if (R_0 != R_) {
372 // copy over the initial residual (unpreconditioned).
373 MVT::Assign( *R_0, *R_ );
374 }
375
376 // Compute initial direction vectors
377 // Initially, they are set to the preconditioned residuals
378 //
379 if ( lp_->getLeftPrec() != Teuchos::null ) {
380 lp_->applyLeftPrec( *R_, *Z_ );
381 if ( lp_->getRightPrec() != Teuchos::null ) {
382 Teuchos::RCP<MV> tmp1 = MVT::Clone( *Z_, numRHS_ );
383 lp_->applyRightPrec( *Z_, *tmp1 );
384 Z_ = tmp1;
385 }
386 }
387 else if ( lp_->getRightPrec() != Teuchos::null ) {
388 lp_->applyRightPrec( *R_, *Z_ );
389 }
390 else {
391 MVT::Assign( *R_, *Z_ );
392 }
393 MVT::Assign( *Z_, *P_ );
394 }
395
396 // The solver is initialized
397 initialized_ = true;
398 }
399
400
402 // Iterate until the status test informs us we should stop.
403 template<class ScalarType, class MV, class OP, class DM>
405 {
406 //
407 // Allocate/initialize data structures
408 //
409 if (!initialized_) {
410 initialize();
411 }
412
413 // Allocate memory for scalars.
414 int i=0;
415 std::vector<int> index(1);
416 std::vector<ScalarType> rHz( numRHS_ );
417 std::vector<ScalarType> rHz_old( numRHS_ );
418 std::vector<ScalarType> pAp( numRHS_ );
419 std::vector<ScalarType> beta( numRHS_ );
420 Teuchos::RCP<DM> alpha = DMT::Create( numRHS_,numRHS_ );
421
422 // Create convenience variables for zero and one.
423 const ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
424 const MagnitudeType zero = Teuchos::ScalarTraits<MagnitudeType>::zero();
425
426 // Get the current solution std::vector.
427 Teuchos::RCP<MV> cur_soln_vec = lp_->getCurrLHSVec();
428
429 // Compute first <r,z> a.k.a. rHz
430 MVT::MvDot( *R_, *Z_, rHz );
431
432 if ( assertPositiveDefiniteness_ )
433 for (i=0; i<numRHS_; ++i)
434 TEUCHOS_TEST_FOR_EXCEPTION( SCT::real(rHz[i]) < zero,
436 "Belos::PseudoBlockCGIter::iterate(): negative value for r^H*M*r encountered!" );
437
439 // Iterate until the status test tells us to stop.
440 //
441 while (stest_->checkStatus(this) != Passed) {
442
443 // Increment the iteration
444 iter_++;
445
446 // Multiply the current direction std::vector by A and store in AP_
447 lp_->applyOp( *P_, *AP_ );
448
449 // Compute alpha := <R_,Z_> / <P_,AP_>
450 MVT::MvDot( *P_, *AP_, pAp );
451
452 for (i=0; i<numRHS_; ++i) {
453 if ( assertPositiveDefiniteness_ )
454 // Check that pAp[i] is a positive number!
455 TEUCHOS_TEST_FOR_EXCEPTION( SCT::real(pAp[i]) <= zero,
457 "Belos::PseudoBlockCGIter::iterate(): non-positive value for p^H*A*p encountered!" );
458
459 DMT::Value(*alpha,i,i) = rHz[i] / pAp[i];
460 }
461 DMT::SyncHostToDevice( *alpha );
462
463 //
464 // Update the solution std::vector x := x + alpha * P_
465 //
466 MVT::MvTimesMatAddMv( one, *P_, *alpha, one, *cur_soln_vec );
467 lp_->updateSolution();// what does this do?
468 //
469 // Save the denominator of beta before residual is updated [ old <R_, Z_> ]
470 //
471 for (i=0; i<numRHS_; ++i) {
472 rHz_old[i] = rHz[i];
473 }
474 //
475 // Compute the new residual R_ := R_ - alpha * AP_
476 //
477 MVT::MvTimesMatAddMv( -one, *AP_, *alpha, one, *R_ );
478 //
479 // Compute beta := [ new <R_, Z_> ] / [ old <R_, Z_> ],
480 // and the new direction std::vector p.
481 //
482 if ( lp_->getLeftPrec() != Teuchos::null ) {
483 lp_->applyLeftPrec( *R_, *Z_ );
484 if ( lp_->getRightPrec() != Teuchos::null ) {
485 Teuchos::RCP<MV> tmp = MVT::Clone( *Z_, numRHS_ );
486 lp_->applyRightPrec( *Z_, *tmp );
487 Z_ = tmp;
488 }
489 }
490 else if ( lp_->getRightPrec() != Teuchos::null ) {
491 lp_->applyRightPrec( *R_, *Z_ );
492 }
493 else {
494 Z_ = R_;
495 }
496 //
497 MVT::MvDot( *R_, *Z_, rHz );
498 if ( assertPositiveDefiniteness_ )
499 for (i=0; i<numRHS_; ++i)
500 TEUCHOS_TEST_FOR_EXCEPTION( SCT::real(rHz[i]) < zero,
502 "Belos::PseudoBlockCGIter::iterate(): negative value for r^H*M*r encountered!" );
503 //
504 // Update the search directions.
505 for (i=0; i<numRHS_; ++i) {
506 beta[i] = rHz[i] / rHz_old[i];
507 index[0] = i;
508 Teuchos::RCP<const MV> Z_i = MVT::CloneView( *Z_, index );
509 Teuchos::RCP<MV> P_i = MVT::CloneViewNonConst( *P_, index );
510 MVT::MvAddMv( one, *Z_i, beta[i], *P_i, *P_i );
511 }
512
513 // Condition estimate (if needed)
514 if (doCondEst_ && (iter_ - 1) < diag_.size()) {
515 if (iter_ > 1) {
516 diag_[iter_-1] = Teuchos::ScalarTraits<ScalarType>::real((beta_old_ * beta_old_ * pAp_old_ + pAp[0]) / rHz_old[0]);
517 offdiag_[iter_-2] = -Teuchos::ScalarTraits<ScalarType>::real(beta_old_ * pAp_old_ / (sqrt( rHz_old[0] * rHz_old2_)));
518 }
519 else {
520 diag_[iter_-1] = Teuchos::ScalarTraits<ScalarType>::real(pAp[0] / rHz_old[0]);
521 }
522 rHz_old2_ = rHz_old[0];
523 beta_old_ = beta[0];
524 pAp_old_ = pAp[0];
525 }
526
527
528 //
529 } // end while (sTest_->checkStatus(this) != Passed)
530 }
531
532} // end Belos namespace
533
534#endif /* BELOS_PSEUDO_BLOCK_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.
Templated virtual class for providing orthogonalization/orthonormalization methods with matrix-based ...
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.
Structure to contain pointers to CGIteration state variables.
Teuchos::RCP< MV > AP
The matrix A applied to current decent direction vector.
virtual bool matches(Teuchos::RCP< const MV > tmp, int _numVectors=1) const
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.
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).
This class implements the pseudo-block CG iteration, where the basic CG algorithm is performed on all...
PseudoBlockCGIter(const Teuchos::RCP< LinearProblem< ScalarType, MV, OP, DM > > &problem, const Teuchos::RCP< OutputManager< ScalarType > > &printer, const Teuchos::RCP< StatusTest< ScalarType, MV, OP, DM > > &tester, Teuchos::ParameterList &params)
PseudoBlockCGIter constructor with linear problem, solver utilities, and parameter list of solver opt...
Teuchos::RCP< MV > getCurrentUpdate() const
Get the current update to the linear system.
void setState(Teuchos::RCP< CGIterationStateBase< ScalarType, MV, DM > > state)
void iterate()
This method performs CG iterations on each linear system until the status test indicates the need to ...
void resetNumIters(int iter=0)
Reset the iteration count.
Teuchos::ScalarTraits< ScalarType > SCT
Teuchos::ArrayView< MagnitudeType > getDiag()
Gets the diagonal for condition estimation.
int getNumIters() const
Get the current iteration count.
void initializeCG(Teuchos::RCP< CGIterationStateBase< ScalarType, MV, DM > > newstate, Teuchos::RCP< MV > R_0)
Initialize the solver to an iterate, providing a complete state.
int getBlockSize() const
Get the blocksize to be used by the iterative solver in solving this linear problem.
const LinearProblem< ScalarType, MV, OP, DM > & getProblem() const
Get a constant reference to the linear problem.
Teuchos::RCP< CGIterationStateBase< ScalarType, MV, DM > > getState() const
Get the current state of the linear solver.
Teuchos::RCP< const MV > getNativeResiduals(std::vector< MagnitudeType > *) const
Get the norms of the residuals native to the solver.
void setDoCondEst(bool val)
Sets whether or not to store the diagonal for condition estimation.
Teuchos::ArrayView< MagnitudeType > getOffDiag()
Gets the off-diagonal for condition estimation.
typename SCT::magnitudeType MagnitudeType
virtual ~PseudoBlockCGIter()=default
Destructor.
void setBlockSize(int blockSize)
Set the blocksize.
void initialize()
Initialize the solver with the initial vectors from the linear problem or random data.
bool isInitialized()
States whether the solver has been initialized or not.
Structure to contain pointers to PseudoBlockCGIteration state variables.
bool matches(Teuchos::RCP< const MV > tmp, int _numVectors=1) const
void initialize(Teuchos::RCP< const MV > tmp, int _numVectors)
PseudoBlockCGIterationState(Teuchos::RCP< const MV > tmp)
virtual ~PseudoBlockCGIterationState()=default

Generated for Belos by doxygen 1.9.8