Belos Version of the Day
Loading...
Searching...
No Matches
BelosBlockGmresIter.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_BLOCK_GMRES_ITER_HPP
11#define BELOS_BLOCK_GMRES_ITER_HPP
12
17#include "BelosConfigDefs.hpp"
18#include "BelosTypes.hpp"
20
24#include "BelosStatusTest.hpp"
28
29#include "Teuchos_BLAS.hpp"
30#include "Teuchos_LAPACK.hpp"
31#include "Teuchos_ScalarTraits.hpp"
32#include "Teuchos_ParameterList.hpp"
33#include "Teuchos_TimeMonitor.hpp"
34
35#include <vector>
36
50namespace Belos {
51
52template<class ScalarType, class MV, class OP, class DM>
53class BlockGmresIter : virtual public GmresIteration<ScalarType,MV,OP,DM> {
54
55 public:
56
57 //
58 // Convenience typedefs
59 //
63 typedef Teuchos::ScalarTraits<ScalarType> SCT;
64 typedef typename SCT::magnitudeType MagnitudeType;
65
67
68
79 const Teuchos::RCP<OutputManager<ScalarType> > &printer,
80 const Teuchos::RCP<StatusTest<ScalarType,MV,OP,DM> > &tester,
81 const Teuchos::RCP<MatOrthoManager<ScalarType,MV,OP,DM> > &ortho,
82 Teuchos::ParameterList &params );
83
85 virtual ~BlockGmresIter() {};
87
88
90
91
113 void iterate();
114
137
146
156 state.curDim = curDim_;
157 state.V = V_;
158 state.H = H_;
159 state.R = R_;
160 state.z = z_;
161 return state;
162 }
163
165
166
168
169
171 int getNumIters() const { return iter_; }
172
174 void resetNumIters( int iter = 0 ) { iter_ = iter; }
175
178 Teuchos::RCP<const MV> getNativeResiduals( std::vector<MagnitudeType> *norms ) const;
179
181
186 Teuchos::RCP<MV> getCurrentUpdate() const;
187
189
192 void updateLSQR( int dim = -1 );
193
195 int getCurSubspaceDim() const {
196 if (!initialized_) return 0;
197 return curDim_;
198 };
199
201 int getMaxSubspaceDim() const { return blockSize_*numBlocks_; }
202
204
205
207
208
210 const LinearProblem<ScalarType,MV,OP,DM>& getProblem() const { return *lp_; }
211
213 int getBlockSize() const { return blockSize_; }
214
216 void setBlockSize(int blockSize) { setSize( blockSize, numBlocks_ ); }
217
219 int getNumBlocks() const { return numBlocks_; }
220
222 void setNumBlocks(int numBlocks) { setSize( blockSize_, numBlocks ); }
223
230 void setSize(int blockSize, int numBlocks);
231
233 bool isInitialized() { return initialized_; }
234
236
237 private:
238
239 //
240 // Internal structs
241 //
242 struct CheckList {
243 bool checkV;
244 bool checkArn;
245 CheckList() : checkV(false), checkArn(false) {};
246 };
247 //
248 // Internal methods
249 //
251 std::string accuracyCheck(const CheckList &chk, const std::string &where) const;
252
254 void setStateSize();
255
256 //
257 // Classes inputed through constructor that define the linear problem to be solved.
258 //
259 const Teuchos::RCP<LinearProblem<ScalarType,MV,OP,DM> > lp_;
260 const Teuchos::RCP<OutputManager<ScalarType> > om_;
261 const Teuchos::RCP<StatusTest<ScalarType,MV,OP,DM> > stest_;
262 const Teuchos::RCP<OrthoManager<ScalarType,MV,DM> > ortho_;
263
264 //
265 // Algorithmic parameters
266 //
267 // blockSize_ is the solver block size.
268 // It controls the number of vectors added to the basis on each iteration.
269 int blockSize_;
270 // numBlocks_ is the size of the allocated space for the Krylov basis, in blocks.
271 int numBlocks_;
272
273 // Storage for QR factorization of the least squares system.
274 std::vector<ScalarType> beta, sn;
275 std::vector<MagnitudeType> cs;
276
277 //
278 // Current solver state
279 //
280 // initialized_ specifies that the basis vectors have been initialized and the iterate() routine
281 // is capable of running; _initialize is controlled by the initialize() member method
282 // For the implications of the state of initialized_, please see documentation for initialize()
283 bool initialized_;
284
285 // stateStorageInitialized_ specifies that the state storage has be initialized to the current
286 // blockSize_ and numBlocks_. This initialization may be postponed if the linear problem was
287 // generated without the right-hand side or solution vectors.
288 bool stateStorageInitialized_;
289
290 // keepHessenberg_ specifies that the iteration must keep the Hessenberg matrix formed via the
291 // Arnoldi factorization and the upper triangular matrix that is the Hessenberg matrix reduced via
292 // QR factorization separate.
293 bool keepHessenberg_;
294
295 // initHessenberg_ specifies that the iteration should reinitialize the Hessenberg matrix by zeroing
296 // out all entries before an iteration is started.
297 bool initHessenberg_;
298
299 // Current subspace dimension, and number of iterations performed.
300 int curDim_, iter_;
301
302 //
303 // State Storage
304 //
305 Teuchos::RCP<MV> V_;
306 //
307 // Projected matrices
308 // H_ : Projected matrix from the Krylov factorization AV = VH + FE^T
309 //
310 Teuchos::RCP<DM> H_;
311 //
312 // QR decomposition of Projected matrices for solving the least squares system HY = B.
313 // R_: Upper triangular reduction of H
314 // z_: Q applied to right-hand side of the least squares system
315 Teuchos::RCP<DM> R_;
316 Teuchos::RCP<DM> z_;
317};
318
320 // Constructor.
321 template<class ScalarType, class MV, class OP, class DM>
323 const Teuchos::RCP<OutputManager<ScalarType> > &printer,
324 const Teuchos::RCP<StatusTest<ScalarType,MV,OP,DM> > &tester,
325 const Teuchos::RCP<MatOrthoManager<ScalarType,MV,OP,DM> > &ortho,
326 Teuchos::ParameterList &params ):
327 lp_(problem),
328 om_(printer),
329 stest_(tester),
330 ortho_(ortho),
331 blockSize_(0),
332 numBlocks_(0),
333 initialized_(false),
334 stateStorageInitialized_(false),
335 keepHessenberg_(false),
336 initHessenberg_(false),
337 curDim_(0),
338 iter_(0)
339 {
340 // Find out whether we are saving the Hessenberg matrix.
341 if ( om_->isVerbosity( Debug ) )
342 keepHessenberg_ = true;
343 else
344 keepHessenberg_ = params.get("Keep Hessenberg", false);
345
346 // Find out whether we are initializing the Hessenberg matrix.
347 initHessenberg_ = params.get("Initialize Hessenberg", false);
348
349 // Get the maximum number of blocks allowed for this Krylov subspace
350 TEUCHOS_TEST_FOR_EXCEPTION(!params.isParameter("Num Blocks"), std::invalid_argument,
351 "Belos::BlockGmresIter::constructor: mandatory parameter 'Num Blocks' is not specified.");
352 int nb = Teuchos::getParameter<int>(params, "Num Blocks");
353
354 // Set the block size and allocate data
355 int bs = params.get("Block Size", 1);
356 setSize( bs, nb );
357 }
358
360 // Set the block size and make necessary adjustments.
361 template <class ScalarType, class MV, class OP, class DM>
363 {
364 // This routine only allocates space; it doesn't not perform any computation
365 // any change in size will invalidate the state of the solver.
366
367 TEUCHOS_TEST_FOR_EXCEPTION(numBlocks <= 0 || blockSize <= 0, std::invalid_argument, "Belos::BlockGmresIter::setSize was passed a non-positive argument.");
368 if (blockSize == blockSize_ && numBlocks == numBlocks_) {
369 // do nothing
370 return;
371 }
372
373 if (blockSize!=blockSize_ || numBlocks!=numBlocks_)
374 stateStorageInitialized_ = false;
375
376 blockSize_ = blockSize;
377 numBlocks_ = numBlocks;
378
379 initialized_ = false;
380 curDim_ = 0;
381
382 // Use the current blockSize_ and numBlocks_ to initialize the state storage.
383 setStateSize();
384
385 }
386
388 // Setup the state storage.
389 template <class ScalarType, class MV, class OP, class DM>
391 {
392 if (!stateStorageInitialized_) {
393
394 // Check if there is any multivector to clone from.
395 Teuchos::RCP<const MV> lhsMV = lp_->getLHS();
396 Teuchos::RCP<const MV> rhsMV = lp_->getRHS();
397 if (lhsMV == Teuchos::null && rhsMV == Teuchos::null) {
398 stateStorageInitialized_ = false;
399 return;
400 }
401 else {
402
404 // blockSize*numBlocks dependent
405 //
406 int newsd = blockSize_*(numBlocks_+1);
407
408 if (blockSize_==1) {
409 cs.resize( newsd );
410 sn.resize( newsd );
411 }
412 else {
413 beta.resize( newsd );
414 }
415
416 // Initialize the state storage
417 TEUCHOS_TEST_FOR_EXCEPTION(blockSize_*static_cast<ptrdiff_t>(numBlocks_) > MVT::GetGlobalLength(*rhsMV),std::invalid_argument,
418 "Belos::BlockGmresIter::setStateSize(): Cannot generate a Krylov basis with dimension larger the operator!");
419
420 // If the subspace has not be initialized before, generate it using the LHS or RHS from lp_.
421 if (V_ == Teuchos::null) {
422 // Get the multivector that is not null.
423 Teuchos::RCP<const MV> tmp = ( (rhsMV!=Teuchos::null)? rhsMV: lhsMV );
424 TEUCHOS_TEST_FOR_EXCEPTION(tmp == Teuchos::null,std::invalid_argument,
425 "Belos::BlockGmresIter::setStateSize(): linear problem does not specify multivectors to clone from.");
426 V_ = MVT::Clone( *tmp, newsd );
427 }
428 else {
429 // Generate V_ by cloning itself ONLY if more space is needed.
430 if (MVT::GetNumberVecs(*V_) < newsd) {
431 Teuchos::RCP<const MV> tmp = V_;
432 V_ = MVT::Clone( *tmp, newsd );
433 }
434 }
435
436 // Generate R_ only if it doesn't exist, otherwise resize it.
437 if (R_ == Teuchos::null) {
438 R_ = DMT::Create();
439 }
440 if (initHessenberg_) {
441 DMT::Reshape(*R_, newsd, newsd-blockSize_, true);
442 }
443 else {
444 if (DMT::GetNumRows(*R_) < newsd || DMT::GetNumCols(*R_) < newsd-blockSize_) {
445 DMT::Reshape(*R_, newsd, newsd-blockSize_, false);
446 }
447 }
448
449 // Generate H_ only if it doesn't exist, and we are keeping the upper Hessenberg matrix.
450 if (keepHessenberg_) {
451 if (H_ == Teuchos::null) {
452 H_ = DMT::Create();
453 }
454 if (initHessenberg_) {
455 DMT::Reshape(*H_, newsd, newsd-blockSize_, true);
456 }
457 else {
458 if (DMT::GetNumRows(*H_)< newsd || DMT::GetNumCols(*H_)< newsd-blockSize_) {
459 DMT::Reshape(*H_, newsd, newsd-blockSize_, false);
460 }
461 }
462 }
463 else {
464 // Point H_ and R_ at the same object.
465 H_ = R_;
466 }
467
468 // Generate z_ only if it doesn't exist, otherwise resize it.
469 if (z_ == Teuchos::null) {
470 z_ = DMT::Create();
471 }
472 if (DMT::GetNumRows(*z_) < newsd || DMT::GetNumCols(*z_) < blockSize_) {
473 DMT::Reshape(*z_, newsd, blockSize_);
474 }
475
476 // State storage has now been initialized.
477 stateStorageInitialized_ = true;
478 }
479 }
480 }
481
483 // Get the current update from this subspace.
484 template <class ScalarType, class MV, class OP, class DM>
486 {
487 //
488 // If this is the first iteration of the Arnoldi factorization,
489 // there is no update, so return Teuchos::null.
490 //
491 Teuchos::RCP<MV> currentUpdate = Teuchos::null;
492 if (curDim_==0) {
493 return currentUpdate;
494 } else {
495 const ScalarType one = SCT::one();
496 const ScalarType zero = SCT::zero();
497 Teuchos::BLAS<int,ScalarType> blas;
498 currentUpdate = MVT::Clone( *V_, blockSize_ );
499 //
500 // Make a view and then copy the RHS of the least squares problem. DON'T OVERWRITE IT!
501 //
502 Teuchos::RCP<DM> y = DMT::SubviewCopy(*z_, curDim_, blockSize_);
503 //
504 // Solve the least squares problem.
505 //
506 blas.TRSM( Teuchos::LEFT_SIDE, Teuchos::UPPER_TRI, Teuchos::NO_TRANS,
507 Teuchos::NON_UNIT_DIAG, curDim_, blockSize_, one,
508 DMT::GetRawHostPtr(*R_), DMT::GetStride(*R_), DMT::GetRawHostPtr(*y), DMT::GetStride(*y) );
509 DMT::SyncHostToDevice(*y);
510 //
511 // Compute the current update.
512 //
513 std::vector<int> index(curDim_);
514 for ( int i=0; i<curDim_; i++ ) {
515 index[i] = i;
516 }
517 Teuchos::RCP<const MV> Vjp1 = MVT::CloneView( *V_, index );
518 MVT::MvTimesMatAddMv( one, *Vjp1, *y, zero, *currentUpdate );
519 }
520 return currentUpdate;
521 }
522
523
525 // Get the native residuals stored in this iteration.
526 // Note: No residual std::vector will be returned by Gmres.
527 template <class ScalarType, class MV, class OP, class DM>
528 Teuchos::RCP<const MV> BlockGmresIter<ScalarType,MV,OP,DM>::getNativeResiduals( std::vector<MagnitudeType> *norms ) const
529 {
530 //
531 // NOTE: Make sure the incoming std::vector is the correct size!
532 //
533 if ( norms && (int)norms->size() < blockSize_ )
534 norms->resize( blockSize_ );
535
536 if (norms) {
537 Teuchos::BLAS<int,ScalarType> blas;
538 DMT::SyncDeviceToHost(*z_);
539 for (int j=0; j<blockSize_; j++) {
540 Teuchos::RCP<DM> z_j = DMT::Subview(*z_, blockSize_, 1, curDim_, j);
541 (*norms)[j] = blas.NRM2( blockSize_, DMT::GetRawHostPtr(*z_j), 1);
542 }
543 }
544 return Teuchos::null;
545 }
546
547
548
550 // Initialize this iteration object
551 template <class ScalarType, class MV, class OP, class DM>
553 {
554 // Initialize the state storage if it isn't already.
555 if (!stateStorageInitialized_)
556 setStateSize();
557
558 TEUCHOS_TEST_FOR_EXCEPTION(!stateStorageInitialized_,std::invalid_argument,
559 "Belos::BlockGmresIter::initialize(): Cannot initialize state storage!");
560
561 // NOTE: In BlockGmresIter, V and Z are required!!!
562 // inconsitent multivectors widths and lengths will not be tolerated, and
563 // will be treated with exceptions.
564 //
565 std::string errstr("Belos::BlockGmresIter::initialize(): Specified multivectors must have a consistent length and width.");
566
567 if (newstate.V != Teuchos::null && newstate.z != Teuchos::null) {
568
569 // initialize V_,z_, and curDim_
570
571 TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetGlobalLength(*newstate.V) != MVT::GetGlobalLength(*V_),
572 std::invalid_argument, errstr );
573 TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetNumberVecs(*newstate.V) < blockSize_,
574 std::invalid_argument, errstr );
575 TEUCHOS_TEST_FOR_EXCEPTION( newstate.curDim > blockSize_*(numBlocks_+1),
576 std::invalid_argument, errstr );
577
578 curDim_ = newstate.curDim;
579 int lclDim = MVT::GetNumberVecs(*newstate.V);
580
581 // check size of Z
582 TEUCHOS_TEST_FOR_EXCEPTION(DMT::GetNumRows(*newstate.z) < curDim_ || DMT::GetNumCols(*newstate.z) < blockSize_, std::invalid_argument, errstr);
583
584
585 // copy basis vectors from newstate into V
586 if (newstate.V != V_) {
587 // only copy over the first block and print a warning.
588 if (curDim_ == 0 && lclDim > blockSize_) {
589 om_->stream(Warnings) << "Belos::BlockGmresIter::initialize(): the solver was initialized with a kernel of " << lclDim << std::endl
590 << "The block size however is only " << blockSize_ << std::endl
591 << "The last " << lclDim - blockSize_ << " vectors will be discarded." << std::endl;
592 }
593 std::vector<int> nevind(curDim_+blockSize_);
594 for (int i=0; i<curDim_+blockSize_; i++) nevind[i] = i;
595 Teuchos::RCP<const MV> newV = MVT::CloneView( *newstate.V, nevind );
596 Teuchos::RCP<MV> lclV = MVT::CloneViewNonConst( *V_, nevind );
597 MVT::Assign( *newV, *lclV );
598
599 // done with local pointers
600 lclV = Teuchos::null;
601 }
602
603 // put data into z_, make sure old information is not still hanging around.
604 if (newstate.z != z_) {
605 DMT::PutScalar(*z_);
606 //Note: Need a SubviewConst here because the z in GMRES Iteration State is defined as const.
607 Teuchos::RCP<const DM> newZ = DMT::SubviewConst(*newstate.z,curDim_+blockSize_,blockSize_);
608 Teuchos::RCP<DM> lclZ = DMT::Subview(*z_,curDim_+blockSize_,blockSize_);
609 DMT::Assign(*lclZ,*newZ);
610
611 // done with local pointers
612 lclZ = Teuchos::null;
613 }
614
615 }
616 else {
617
618 TEUCHOS_TEST_FOR_EXCEPTION(newstate.V == Teuchos::null,std::invalid_argument,
619 "Belos::BlockGmresIter::initialize(): BlockGmresStateIterState does not have initial kernel V_0.");
620
621 TEUCHOS_TEST_FOR_EXCEPTION(newstate.z == Teuchos::null,std::invalid_argument,
622 "Belos::BlockGmresIter::initialize(): BlockGmresStateIterState does not have initial norms z_0.");
623 }
624
625 // the solver is initialized
626 initialized_ = true;
627
628 if (om_->isVerbosity( Debug ) ) {
629 // Check almost everything here
630 CheckList chk;
631 chk.checkV = true;
632 chk.checkArn = true;
633 om_->print( Debug, accuracyCheck(chk, ": after initialize()") );
634 }
635
636 }
637
638
640 // Iterate until the status test informs us we should stop.
641 template <class ScalarType, class MV, class OP, class DM>
643 {
644 //
645 // Allocate/initialize data structures
646 //
647 if (initialized_ == false) {
648 initialize();
649 }
650
651 // Compute the current search dimension.
652 int searchDim = blockSize_*numBlocks_;
653
655 // iterate until the status test tells us to stop.
656 //
657 // also break if our basis is full
658 //
659 while (stest_->checkStatus(this) != Passed && curDim_+blockSize_ <= searchDim) {
660
661 iter_++;
662
663 // F can be found at the curDim_ block, but the next block is at curDim_ + blockSize_.
664 int lclDim = curDim_ + blockSize_;
665
666 // Get the current part of the basis.
667 std::vector<int> curind(blockSize_);
668 for (int i=0; i<blockSize_; i++) { curind[i] = lclDim + i; }
669 Teuchos::RCP<MV> Vnext = MVT::CloneViewNonConst(*V_,curind);
670
671 // Get a view of the previous vectors.
672 // This is used for orthogonalization and for computing V^H K H
673 for (int i=0; i<blockSize_; i++) { curind[i] = curDim_ + i; }
674 Teuchos::RCP<const MV> Vprev = MVT::CloneView(*V_,curind);
675
676 // Compute the next std::vector in the Krylov basis: Vnext = Op*Vprev
677 lp_->apply(*Vprev,*Vnext);
678 Vprev = Teuchos::null;
679
680 // Remove all previous Krylov basis vectors from Vnext
681 // Get a view of all the previous vectors
682 std::vector<int> prevind(lclDim);
683 for (int i=0; i<lclDim; i++) { prevind[i] = i; }
684 Vprev = MVT::CloneView(*V_,prevind);
685 Teuchos::Array<Teuchos::RCP<const MV> > AVprev(1, Vprev);
686
687 // Get a view of the part of the Hessenberg matrix needed to hold the ortho coeffs.
688 Teuchos::RCP<DM> subH = DMT::Subview(*H_,lclDim,blockSize_,0,curDim_ );
689 Teuchos::Array<Teuchos::RCP<DM> > AsubH;
690 AsubH.append( subH );
691
692 // Get a view of the part of the Hessenberg matrix needed to hold the norm coeffs.
693 Teuchos::RCP<DM> subH2 = DMT::Subview(*H_,blockSize_,blockSize_,lclDim,curDim_);
694 DMT::PutScalar(*subH2); // Initialize subdiagonal to zero
695
696 // TODO
697 // Make an abstract dense matrix that holds the data of subH2 (an RCP of serialDense.)
698 // Do the same for AsubH. ????
699 // subH needs to be a new rcp to an abstract dense. No, keep subH how it is.
700 // Then make a subHAbstract that grabs the pointer from subH, making it an abstract dense guy.
701 // Then AsubH can be a Teuchos::Array
702 // of the abstract dense guys.
703 int rank = ortho_->projectAndNormalize(*Vnext,AsubH,subH2,AVprev);
704
705 // Copy over the coefficients if we are saving the upper Hessenberg matrix,
706 // just in case we run into an error.
707 if (keepHessenberg_) {
708 // Copy over the orthogonalization coefficients.
709 Teuchos::RCP<DM> subR = DMT::Subview(*R_,lclDim,blockSize_,0,curDim_ );
710 DMT::Assign(*subR,*subH);
711
712 // Copy over the lower diagonal block of the Hessenberg matrix.
713 Teuchos::RCP<DM> subR2 = DMT::Subview(*R_,blockSize_,blockSize_,lclDim,curDim_ );
714 DMT::Assign(*subR2,*subH2);
715 }
716
718 "Belos::BlockGmresIter::iterate(): couldn't generate basis of full rank.");
719 //
720 // V has been extended, and H has been extended.
721 //
722 // Update the QR factorization of the upper Hessenberg matrix
723 //
724 updateLSQR();
725 //
726 // Update basis dim and release all pointers.
727 //
728 Vnext = Teuchos::null;
729 curDim_ += blockSize_;
730 //
731 // When required, monitor some orthogonalities
732 if (om_->isVerbosity( Debug ) ) {
733 // Check almost everything here
734 CheckList chk;
735 chk.checkV = true;
736 chk.checkArn = true;
737 om_->print( Debug, accuracyCheck(chk, ": after local update") );
738 }
739 else if (om_->isVerbosity( OrthoDetails ) ) {
740 CheckList chk;
741 chk.checkV = true;
742 om_->print( OrthoDetails, accuracyCheck(chk, ": after local update") );
743 }
744
745 } // end while (statusTest == false)
746
747 }
748
749
750 template<class ScalarType, class MV, class OP, class DM>
752 {
753 int i, j, maxidx;
755 const ScalarType zero = SCT::zero();
756
757 // Get correct dimension based on input "dim"
758 // Remember that ortho failures result in an exit before updateLSQR() is called.
759 // Therefore, it is possible that dim == curDim_.
760 int curDim = curDim_;
761 if (dim >= curDim_ && dim < getMaxSubspaceDim()) {
762 curDim = dim;
763 }
764
765 Teuchos::BLAS<int, ScalarType> blas;
766 //
767 // Apply previous transformations and compute new transformation to reduce upper-Hessenberg
768 // system to upper-triangular form.
769 //
770 DMT::SyncDeviceToHost(*R_);
771 DMT::SyncDeviceToHost(*z_);
772
773 if (blockSize_ == 1) {
774 //
775 // QR factorization of Least-Squares system with Givens rotations
776 //
777 for (i=0; i<curDim; i++) {
778 //
779 // Apply previous Givens rotations to new column of Hessenberg matrix
780 //
781 blas.ROT( 1, &DMT::Value(*R_,i,curDim), 1, &DMT::Value(*R_,i+1, curDim), 1, &cs[i], &sn[i] );
782 }
783 //
784 // Calculate new Givens rotation
785 //
786 blas.ROTG( &DMT::Value(*R_,curDim,curDim), &DMT::Value(*R_,curDim+1,curDim), &cs[curDim], &sn[curDim] );
787 DMT::Value(*R_,curDim+1,curDim) = zero;
788 //
789 // Update RHS w/ new transformation
790 //
791 blas.ROT( 1, &DMT::Value(*z_,curDim,0), 1, &DMT::Value(*z_,curDim+1,0), 1, &cs[curDim], &sn[curDim] );
792 }
793 else {
794 //
795 // QR factorization of Least-Squares system with Householder reflectors
796 //
797 for (j=0; j<blockSize_; j++) {
798 //
799 // Apply previous Householder reflectors to new block of Hessenberg matrix
800 //
801 for (i=0; i<curDim+j; i++) {
802 sigma = blas.DOT( blockSize_, &DMT::Value(*R_,i+1,i), 1, &DMT::Value(*R_,i+1,curDim+j), 1);
803 sigma += DMT::ValueConst(*R_,i,curDim+j);
804 sigma *= SCT::conjugate(beta[i]);
805 blas.AXPY(blockSize_, ScalarType(-sigma), &DMT::Value(*R_,i+1,i), 1, &DMT::Value(*R_,i+1,curDim+j), 1);
806 DMT::Value(*R_,i,curDim+j) -= sigma;
807 }
808 //
809 // Compute new Householder reflector
810 //
811 maxidx = blas.IAMAX( blockSize_+1, &DMT::Value(*R_,curDim+j,curDim+j), 1 );
812 maxelem = SCT::magnitude(DMT::Value(*R_,curDim+j+maxidx-1,curDim+j));
813 for (i=0; i<blockSize_+1; i++)
814 DMT::Value(*R_,curDim+j+i,curDim+j) /= maxelem;
815 sigma = blas.DOT( blockSize_, &DMT::Value(*R_,curDim+j+1,curDim+j), 1,
816 &DMT::Value(*R_,curDim+j+1,curDim+j), 1 );
817 MagnitudeType sign_Rjj = -SCT::real(DMT::Value(*R_,curDim+j,curDim+j)) /
818 SCT::magnitude(SCT::real((DMT::Value(*R_,curDim+j,curDim+j))));
819 if (sigma == zero) {
820 beta[curDim + j] = zero;
821 } else {
822 mu = SCT::squareroot(SCT::conjugate(DMT::Value(*R_,curDim+j,curDim+j))*DMT::Value(*R_,curDim+j,curDim+j)+sigma);
823 vscale = DMT::ValueConst(*R_,curDim+j,curDim+j) - Teuchos::as<ScalarType>(sign_Rjj)*mu;
824 beta[curDim+j] = -Teuchos::as<ScalarType>(sign_Rjj) * vscale / mu;
825 DMT::Value(*R_,curDim+j,curDim+j) = Teuchos::as<ScalarType>(sign_Rjj)*maxelem*mu;
826 for (i=0; i<blockSize_; i++)
827 DMT::Value(*R_,curDim+j+1+i,curDim+j) /= vscale;
828 }
829 //
830 // Apply new Householder reflector to rhs
831 //
832 for (i=0; i<blockSize_; i++) {
833 sigma = blas.DOT( blockSize_, &DMT::Value(*R_,curDim+j+1,curDim+j),
834 1, &DMT::Value(*z_,curDim+j+1,i), 1);
835 sigma += DMT::ValueConst(*z_,curDim+j,i);
836 sigma *= SCT::conjugate(beta[curDim+j]);
837 blas.AXPY(blockSize_, ScalarType(-sigma), &DMT::Value(*R_,curDim+j+1,curDim+j),
838 1, &DMT::Value(*z_,curDim+j+1,i), 1);
839 DMT::Value(*z_,curDim+j,i) -= sigma;
840 }
841 }
842 } // end if (blockSize_ == 1)
843
844 DMT::SyncHostToDevice(*z_);
845 DMT::SyncHostToDevice(*R_);
846
847 // If the least-squares problem is updated wrt "dim" then update the curDim_.
848 if (dim >= curDim_ && dim < getMaxSubspaceDim()) {
849 curDim_ = dim + blockSize_;
850 }
851 } // end updateLSQR()
852
854 // Check accuracy, orthogonality, and other debugging stuff
855 //
856 // bools specify which tests we want to run (instead of running more than we actually care about)
857 //
858 // checkV : V orthonormal
859 //
860 // checkArn: check the Arnoldi factorization
861 //
862 // NOTE: This method needs to check the current dimension of the subspace, since it is possible to
863 // call this method when curDim_ = 0 (after initialization).
864 template <class ScalarType, class MV, class OP, class DM>
865 std::string BlockGmresIter<ScalarType,MV,OP,DM>::accuracyCheck( const CheckList &chk, const std::string &where ) const
866 {
867 std::stringstream os;
868 os.precision(2);
869 os.setf(std::ios::scientific, std::ios::floatfield);
870 MagnitudeType tmp;
871
872 os << " Debugging checks: iteration " << iter_ << where << std::endl;
873
874 // index vectors for V and F
875 std::vector<int> lclind(curDim_);
876 for (int i=0; i<curDim_; i++) lclind[i] = i;
877 std::vector<int> bsind(blockSize_);
878 for (int i=0; i<blockSize_; i++) { bsind[i] = curDim_ + i; }
879
880 Teuchos::RCP<const MV> lclV,lclF;
881 Teuchos::RCP<MV> lclAV;
882 if (curDim_)
883 lclV = MVT::CloneView(*V_,lclind);
884 lclF = MVT::CloneView(*V_,bsind);
885
886 if (chk.checkV) {
887 if (curDim_) {
888 tmp = ortho_->orthonormError(*lclV);
889 os << " >> Error in V^H M V == I : " << tmp << std::endl;
890 }
891 tmp = ortho_->orthonormError(*lclF);
892 os << " >> Error in F^H M F == I : " << tmp << std::endl;
893 if (curDim_) {
894 tmp = ortho_->orthogError(*lclV,*lclF);
895 os << " >> Error in V^H M F == 0 : " << tmp << std::endl;
896 }
897 }
898
899 if (chk.checkArn) {
900
901 if (curDim_) {
902 // Compute AV
903 lclAV = MVT::Clone(*V_,curDim_);
904 lp_->apply(*lclV,*lclAV);
905
906 // Compute AV - VH
907 const ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
908 Teuchos::RCP<DM> subH = DMT::Subview(*H_,curDim_,curDim_);
909 MVT::MvTimesMatAddMv( -one, *lclV, *subH, one, *lclAV );
910
911 // Compute FB_k^T - (AV-VH)
912 Teuchos::RCP<DM> curB = DMT::Subview(*H_,blockSize_,curDim_,curDim_);
913 MVT::MvTimesMatAddMv( -one, *lclF, *curB, one, *lclAV );
914
915 // Compute || FE_k^T - (AV-VH) ||
916 std::vector<MagnitudeType> arnNorms( curDim_ );
917 ortho_->norm( *lclAV, arnNorms );
918
919 for (int i=0; i<curDim_; i++) {
920 os << " >> Error in Krylov factorization (R = AV-VH-FB^H), ||R[" << i << "]|| : " << arnNorms[i] << std::endl;
921 }
922 }
923 }
924
925 os << std::endl;
926
927 return os.str();
928 }
929
930} // end Belos namespace
931
932#endif /* BELOS_BLOCK_GMRES_ITER_HPP */
Belos header file which uses auto-configuration information to include necessary C++ headers.
Pure virtual base class which augments the basic interface for a Gmres linear solver iteration.
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.
This class implements the block GMRES iteration, where a block Krylov subspace is constructed....
MultiVecTraits< ScalarType, MV, DM > MVT
void setNumBlocks(int numBlocks)
Set the maximum number of blocks used by the iterative solver.
GmresIterationState< ScalarType, MV, DM > getState() const
Get the current state of the linear solver.
int getNumIters() const
Get the current iteration count.
void updateLSQR(int dim=-1)
Method for updating QR factorization of upper Hessenberg matrix.
void resetNumIters(int iter=0)
Reset the iteration count.
void iterate()
This method performs block Gmres iterations until the status test indicates the need to stop or an er...
OperatorTraits< ScalarType, MV, OP > OPT
int getBlockSize() const
Get the blocksize to be used by the iterative solver in solving this linear problem.
Teuchos::RCP< const MV > getNativeResiduals(std::vector< MagnitudeType > *norms) const
Get the norms of the residuals native to the solver.
bool isInitialized()
States whether the solver has been initialized or not.
Teuchos::ScalarTraits< ScalarType > SCT
int getMaxSubspaceDim() const
Get the maximum dimension allocated for the search subspace.
virtual ~BlockGmresIter()
Destructor.
DenseMatTraits< ScalarType, DM > DMT
const LinearProblem< ScalarType, MV, OP, DM > & getProblem() const
Get a constant reference to the linear problem.
int getCurSubspaceDim() const
Get the dimension of the search subspace used to generate the current solution to the linear problem.
Teuchos::RCP< MV > getCurrentUpdate() const
Get the current update to the linear system.
void initializeGmres(GmresIterationState< ScalarType, MV, DM > &newstate)
Initialize the solver to an iterate, providing a complete state.
void setSize(int blockSize, int numBlocks)
Set the blocksize and number of blocks to be used by the iterative solver in solving this linear prob...
int getNumBlocks() const
Get the maximum number of blocks used by the iterative solver in solving this linear problem.
SCT::magnitudeType MagnitudeType
void setBlockSize(int blockSize)
Set the blocksize.
void initialize()
Initialize the solver with the initial vectors from the linear problem or random data.
BlockGmresIter(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< MatOrthoManager< ScalarType, MV, OP, DM > > &ortho, Teuchos::ParameterList &params)
BlockGmresIter constructor with linear problem, solver utilities, and parameter list of solver option...
GmresIterationOrthoFailure is thrown when the GmresIteration object is unable to compute independent ...
Alternative run-time polymorphic interface for operators.
Operator()
Default constructor (does nothing).
@ OrthoDetails

Generated for Belos by doxygen 1.9.8