Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Belos_PseudoBlockCGIter_MP_Vector.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Belos: Block Linear Solvers Package
4 //
5 // Copyright 2004 NTESS and the Belos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef BELOS_PSEUDO_BLOCK_CG_ITER_MP_VECTOR_HPP
11 #define BELOS_PSEUDO_BLOCK_CG_ITER_MP_VECTOR_HPP
12 
22 #include "BelosPseudoBlockCGIter.hpp"
23 
39 namespace Belos {
40 
41  template<class Storage, class MV, class OP>
42  class PseudoBlockCGIter<Sacado::MP::Vector<Storage>, MV, OP> :
43  virtual public CGIteration<Sacado::MP::Vector<Storage>, MV, OP> {
44 
45  public:
46 
47  //
48  // Convenience typedefs
49  //
51  typedef MultiVecTraits<ScalarType,MV> MVT;
52  typedef OperatorTraits<ScalarType,MV,OP> OPT;
56 
58 
59 
65  PseudoBlockCGIter( const Teuchos::RCP<LinearProblem<ScalarType,MV,OP> > &problem,
66  const Teuchos::RCP<OutputManager<ScalarType> > &printer,
67  const Teuchos::RCP<StatusTest<ScalarType,MV,OP> > &tester,
68  Teuchos::ParameterList &params );
69 
71  virtual ~PseudoBlockCGIter() {};
73 
74 
76 
77 
91  void iterate();
92 
113  void initializeCG(CGIterationState<ScalarType,MV>& newstate);
114 
118  void initialize()
119  {
120  CGIterationState<ScalarType,MV> empty;
121  initializeCG(empty);
122  }
123 
131  CGIterationState<ScalarType,MV> getState() const {
132  CGIterationState<ScalarType,MV> state;
133  state.R = R_;
134  state.P = P_;
135  state.AP = AP_;
136  state.Z = Z_;
137  return state;
138  }
139 
141 
142 
144 
145 
147  int getNumIters() const { return iter_; }
148 
150  void resetNumIters( int iter = 0 ) { iter_ = iter; }
151 
154  Teuchos::RCP<const MV> getNativeResiduals( std::vector<MagnitudeType> *norms ) const { return R_; }
155 
157 
160 
162 
164 
165 
167  const LinearProblem<ScalarType,MV,OP>& getProblem() const { return *lp_; }
168 
170  int getBlockSize() const { return 1; }
171 
173  void setBlockSize(int blockSize) {
174  TEUCHOS_TEST_FOR_EXCEPTION(blockSize!=1,std::invalid_argument,
175  "Belos::PseudoBlockCGIter::setBlockSize(): Cannot use a block size that is not one.");
176  }
177 
179  bool isInitialized() { return initialized_; }
180 
182 
184  void setDoCondEst(bool val){doCondEst_=val;}
185 
188  // NOTE (mfh 30 Jul 2015) See note on getOffDiag() below.
189  // getDiag() didn't actually throw for me in that case, but why
190  // not be cautious?
191  typedef typename Teuchos::ArrayView<MagnitudeType>::size_type size_type;
192  if (static_cast<size_type> (iter_) >= diag_.size ()) {
193  return diag_ ();
194  } else {
195  return diag_ (0, iter_);
196  }
197  }
198 
201  // NOTE (mfh 30 Jul 2015) The implementation as I found it
202  // returned "offdiag(0,iter_)". This breaks (Teuchos throws in
203  // debug mode) when the maximum number of iterations has been
204  // reached, because iter_ == offdiag_.size() in that case. The
205  // new logic fixes this.
206  typedef typename Teuchos::ArrayView<MagnitudeType>::size_type size_type;
207  if (static_cast<size_type> (iter_) >= offdiag_.size ()) {
208  return offdiag_ ();
209  } else {
210  return offdiag_ (0, iter_);
211  }
212  }
213 
214  private:
215 
216  //
217  // Classes inputed through constructor that define the linear problem to be solved.
218  //
222 
223  //
224  // Algorithmic parameters
225  //
226  // numRHS_ is the current number of linear systems being solved.
227  int numRHS_;
228 
229  //
230  // Current solver state
231  //
232  // initialized_ specifies that the basis vectors have been initialized and the iterate() routine
233  // is capable of running; _initialize is controlled by the initialize() member method
234  // For the implications of the state of initialized_, please see documentation for initialize()
236 
237  // Current number of iterations performed.
238  int iter_;
239 
240  // Assert that the matrix is positive definite
242 
243  // Tridiagonal system for condition estimation (if needed)
247 
248  //
249  // State Storage
250  //
251  // Residual
253  //
254  // Preconditioned residual
256  //
257  // Direction vector
259  //
260  // Operator applied to direction vector
262 
263  // Tolerance for ensemble breakdown
265 
266  };
267 
269  // Constructor.
270  template<class StorageType, class MV, class OP>
272  PseudoBlockCGIter(const Teuchos::RCP<LinearProblem<ScalarType,MV,OP> > &problem,
273  const Teuchos::RCP<OutputManager<ScalarType> > &printer,
274  const Teuchos::RCP<StatusTest<ScalarType,MV,OP> > &tester,
275  Teuchos::ParameterList &params ):
276  lp_(problem),
277  om_(printer),
278  stest_(tester),
279  numRHS_(0),
280  initialized_(false),
281  iter_(0),
282  assertPositiveDefiniteness_( params.get("Assert Positive Definiteness", true) ),
283  numEntriesForCondEst_(params.get("Max Size For Condest",0) ),
284  breakDownTol_(params.get("Ensemble Breakdown Tolerance", 0.0))
285  {
286  }
287 
288 
290  // Initialize this iteration object
291  template <class StorageType, class MV, class OP>
292  void PseudoBlockCGIter<Sacado::MP::Vector<StorageType>,MV,OP>::
293  initializeCG(CGIterationState<ScalarType,MV>& newstate)
294  {
295  // Check if there is any mltivector to clone from.
296  Teuchos::RCP<const MV> lhsMV = lp_->getCurrLHSVec();
297  Teuchos::RCP<const MV> rhsMV = lp_->getCurrRHSVec();
298  TEUCHOS_TEST_FOR_EXCEPTION((lhsMV==Teuchos::null && rhsMV==Teuchos::null),std::invalid_argument,
299  "Belos::PseudoBlockCGIter::initialize(): Cannot initialize state storage!");
300 
301  // Get the multivector that is not null.
302  Teuchos::RCP<const MV> tmp = ( (rhsMV!=Teuchos::null)? rhsMV: lhsMV );
303 
304  // Get the number of right-hand sides we're solving for now.
305  int numRHS = MVT::GetNumberVecs(*tmp);
306  numRHS_ = numRHS;
307 
308  // Initialize the state storage
309  // If the subspace has not be initialized before or has changed sizes, generate it using the LHS or RHS from lp_.
310  if (Teuchos::is_null(R_) || MVT::GetNumberVecs(*R_)!=numRHS_) {
311  R_ = MVT::Clone( *tmp, numRHS_ );
312  Z_ = MVT::Clone( *tmp, numRHS_ );
313  P_ = MVT::Clone( *tmp, numRHS_ );
314  AP_ = MVT::Clone( *tmp, numRHS_ );
315  }
316 
317  // Tracking information for condition number estimation
318  if(numEntriesForCondEst_ > 0) {
319  diag_.resize(numEntriesForCondEst_);
320  offdiag_.resize(numEntriesForCondEst_-1);
321  }
322 
323  // NOTE: In CGIter R_, the initial residual, is required!!!
324  //
325  std::string errstr("Belos::BlockPseudoCGIter::initialize(): Specified multivectors must have a consistent length and width.");
326 
327  // Create convenience variables for zero and one.
328  const ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
329  const MagnitudeType zero = Teuchos::ScalarTraits<MagnitudeType>::zero();
330 
331  if (!Teuchos::is_null(newstate.R)) {
332 
333  TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetGlobalLength(*newstate.R) != MVT::GetGlobalLength(*R_),
334  std::invalid_argument, errstr );
335  TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetNumberVecs(*newstate.R) != numRHS_,
336  std::invalid_argument, errstr );
337 
338  // Copy basis vectors from newstate into V
339  if (newstate.R != R_) {
340  // copy over the initial residual (unpreconditioned).
341  MVT::MvAddMv( one, *newstate.R, zero, *newstate.R, *R_ );
342  }
343 
344  // Compute initial direction vectors
345  // Initially, they are set to the preconditioned residuals
346  //
347  if ( lp_->getLeftPrec() != Teuchos::null ) {
348  lp_->applyLeftPrec( *R_, *Z_ );
349  if ( lp_->getRightPrec() != Teuchos::null ) {
350  Teuchos::RCP<MV> tmp1 = MVT::Clone( *Z_, numRHS_ );
351  lp_->applyRightPrec( *Z_, *tmp1 );
352  Z_ = tmp1;
353  }
354  }
355  else if ( lp_->getRightPrec() != Teuchos::null ) {
356  lp_->applyRightPrec( *R_, *Z_ );
357  }
358  else {
359  Z_ = R_;
360  }
361  MVT::MvAddMv( one, *Z_, zero, *Z_, *P_ );
362  }
363  else {
364 
365  TEUCHOS_TEST_FOR_EXCEPTION(Teuchos::is_null(newstate.R),std::invalid_argument,
366  "Belos::CGIter::initialize(): CGStateIterState does not have initial residual.");
367  }
368 
369  // The solver is initialized
370  initialized_ = true;
371  }
372 
373 
375  // Iterate until the status test informs us we should stop.
376  template <class StorageType, class MV, class OP>
377  void PseudoBlockCGIter<Sacado::MP::Vector<StorageType>,MV,OP>::
378  iterate()
379  {
380  //
381  // Allocate/initialize data structures
382  //
383  if (initialized_ == false) {
384  initialize();
385  }
386 
387  // Allocate memory for scalars.
388  int i=0;
389  std::vector<int> index(1);
390  std::vector<ScalarType> rHz( numRHS_ ), rHz_old( numRHS_ ), pAp( numRHS_ );
391  Teuchos::SerialDenseMatrix<int, ScalarType> alpha( numRHS_,numRHS_ ), beta( numRHS_,numRHS_ );
392 
393  // Create convenience variables for zero and one.
394  const ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
395  const MagnitudeType zero = Teuchos::ScalarTraits<MagnitudeType>::zero();
396 
397  // Scalars for condition estimation (if needed) - These will always use entry zero, for convenience
398  ScalarType pAp_old=one, beta_old=one ,rHz_old2=one;
399 
400  // Get the current solution std::vector.
401  Teuchos::RCP<MV> cur_soln_vec = lp_->getCurrLHSVec();
402 
403  // Compute first <r,z> a.k.a. rHz
404  MVT::MvDot( *R_, *Z_, rHz );
405 
406  if ( assertPositiveDefiniteness_ )
407  for (i=0; i<numRHS_; ++i)
408  TEUCHOS_TEST_FOR_EXCEPTION( SCT::real(rHz[i]) < zero,
409  CGIterateFailure,
410  "Belos::PseudoBlockCGIter::iterate(): negative value for r^H*M*r encountered!" );
411 
413  // Iterate until the status test tells us to stop.
414  //
415  while (stest_->checkStatus(this) != Passed) {
416 
417  // Increment the iteration
418  iter_++;
419 
420  // Multiply the current direction std::vector by A and store in AP_
421  lp_->applyOp( *P_, *AP_ );
422 
423  // Compute alpha := <R_,Z_> / <P_,AP_>
424  MVT::MvDot( *P_, *AP_, pAp );
425 
426  for (i=0; i<numRHS_; ++i) {
427  if ( assertPositiveDefiniteness_ )
428  // Check that pAp[i] is a positive number!
429  TEUCHOS_TEST_FOR_EXCEPTION( SCT::real(pAp[i]) <= zero,
430  CGIterateFailure,
431  "Belos::PseudoBlockCGIter::iterate(): non-positive value for p^H*A*p encountered!" );
432 
433  const int ensemble_size = pAp[i].size();
434  for (int k=0; k<ensemble_size; ++k) {
435  if (SVT::magnitude(pAp[i].coeff(k)) <= breakDownTol_)
436  alpha(i,i).fastAccessCoeff(k) = 0.0;
437  else
438  alpha(i,i).fastAccessCoeff(k) = rHz[i].coeff(k) / pAp[i].coeff(k);
439  }
440  }
441 
442  //
443  // Update the solution std::vector x := x + alpha * P_
444  //
445  MVT::MvTimesMatAddMv( one, *P_, alpha, one, *cur_soln_vec );
446  lp_->updateSolution();
447  //
448  // Save the denominator of beta before residual is updated [ old <R_, Z_> ]
449  //
450  for (i=0; i<numRHS_; ++i) {
451  rHz_old[i] = rHz[i];
452  }
453  //
454  // Compute the new residual R_ := R_ - alpha * AP_
455  //
456  MVT::MvTimesMatAddMv( -one, *AP_, alpha, one, *R_ );
457  //
458  // Compute beta := [ new <R_, Z_> ] / [ old <R_, Z_> ],
459  // and the new direction std::vector p.
460  //
461  if ( lp_->getLeftPrec() != Teuchos::null ) {
462  lp_->applyLeftPrec( *R_, *Z_ );
463  if ( lp_->getRightPrec() != Teuchos::null ) {
464  Teuchos::RCP<MV> tmp = MVT::Clone( *Z_, numRHS_ );
465  lp_->applyRightPrec( *Z_, *tmp );
466  Z_ = tmp;
467  }
468  }
469  else if ( lp_->getRightPrec() != Teuchos::null ) {
470  lp_->applyRightPrec( *R_, *Z_ );
471  }
472  else {
473  Z_ = R_;
474  }
475  //
476  MVT::MvDot( *R_, *Z_, rHz );
477  if ( assertPositiveDefiniteness_ )
478  for (i=0; i<numRHS_; ++i)
479  TEUCHOS_TEST_FOR_EXCEPTION( SCT::real(rHz[i]) < zero,
480  CGIterateFailure,
481  "Belos::PseudoBlockCGIter::iterate(): negative value for r^H*M*r encountered!" );
482  //
483  // Update the search directions.
484  for (i=0; i<numRHS_; ++i) {
485  const int ensemble_size = rHz[i].size();
486  for (int k=0; k<ensemble_size; ++k) {
487  if (SVT::magnitude(rHz[i].coeff(k)) <= breakDownTol_)
488  beta(i,i).fastAccessCoeff(k) = 0.0;
489  else
490  beta(i,i).fastAccessCoeff(k) = rHz[i].coeff(k) / rHz_old[i].coeff(k);
491  }
492  index[0] = i;
493  Teuchos::RCP<const MV> Z_i = MVT::CloneView( *Z_, index );
494  Teuchos::RCP<MV> P_i = MVT::CloneViewNonConst( *P_, index );
495  MVT::MvAddMv( one, *Z_i, beta(i,i), *P_i, *P_i );
496  }
497 
498  // Condition estimate (if needed)
499  if(doCondEst_ > 0) {
500  if(iter_ > 1 ) {
501  diag_[iter_-1] = Teuchos::ScalarTraits<ScalarType>::real((beta_old * beta_old * pAp_old + pAp[0]) / rHz_old[0]);
502  offdiag_[iter_-2] = -Teuchos::ScalarTraits<ScalarType>::real(beta_old * pAp_old / (sqrt( rHz_old[0] * rHz_old2)));
503  }
504  else {
505  diag_[iter_-1] = Teuchos::ScalarTraits<ScalarType>::real(pAp[0] / rHz_old[0]);
506  }
507  rHz_old2 = rHz_old[0];
508  beta_old = beta(0,0);
509  pAp_old = pAp[0];
510  }
511 
512 
513  //
514  } // end while (sTest_->checkStatus(this) != Passed)
515  }
516 
517 } // end Belos namespace
518 
519 #endif /* BELOS_PSEUDO_BLOCK_CG_ITER_HPP */
KOKKOS_INLINE_FUNCTION PCE< Storage > sqrt(const PCE< Storage > &a)
bool is_null(const std::shared_ptr< T > &p)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
static magnitudeType real(T a)
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
Teuchos::RCP< MV > getCurrentUpdate() const
Get the current update to the linear system.
This class implements the pseudo-block CG iteration, where the basic CG algorithm is performed on all...
expr val()
Teuchos::ArrayView< MagnitudeType > getDiag()
Gets the diagonal for condition estimation.
int getBlockSize() const
Get the blocksize to be used by the iterative solver in solving this linear problem.
Teuchos::ArrayView< MagnitudeType > getOffDiag()
Gets the off-diagonal for condition estimation.
void setDoCondEst(bool val)
Sets whether or not to store the diagonal for condition estimation.
CGIterationState< ScalarType, MV > getState() const
Get the current state of the linear solver.
bool isInitialized()
States whether the solver has been initialized or not.
const LinearProblem< ScalarType, MV, OP > & getProblem() const
Get a constant reference to the linear problem.