Belos Version of the Day
Loading...
Searching...
No Matches
BelosGCRODRSolMgr.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_GCRODR_SOLMGR_HPP
11#define BELOS_GCRODR_SOLMGR_HPP
12
16
17#include "BelosConfigDefs.hpp"
21#include "BelosTypes.hpp"
22
23#include "BelosGCRODRIter.hpp"
30#include "Teuchos_BLAS.hpp" // includes Teuchos_ConfigDefs.hpp
31#include "Teuchos_LAPACK.hpp"
32#include "Teuchos_as.hpp"
33
34#ifdef BELOS_TEUCHOS_TIME_MONITOR
35# include "Teuchos_TimeMonitor.hpp"
36#endif // BELOS_TEUCHOS_TIME_MONITOR
37
38#if defined(HAVE_TEUCHOSCORE_CXX11)
39# include <type_traits>
40# if defined(HAVE_TEUCHOS_COMPLEX)
41#include "Kokkos_Complex.hpp"
42# endif
43#endif // defined(HAVE_TEUCHOSCORE_CXX11)
44
55namespace Belos {
56
58
59
70
78 public:
80 };
81
89 public:
91 };
92
100 public:
102 };
103
105
130 template<class ScalarType, class MV, class OP,
131 const bool lapackSupportsScalarType =
134 public Details::SolverManagerRequiresLapack<ScalarType,MV,OP>
135 {
136 static const bool requiresLapack =
139 requiresLapack> base_type;
140
141 public:
143 base_type ()
144 {}
146 const Teuchos::RCP<Teuchos::ParameterList>& pl) :
147 base_type ()
148 {}
149 virtual ~GCRODRSolMgr () {}
150 };
151
155 template<class ScalarType, class MV, class OP>
157 public Details::SolverManagerRequiresLapack<ScalarType, MV, OP, true>
158 {
159
160#if defined(HAVE_TEUCHOSCORE_CXX11)
161# if defined(HAVE_TEUCHOS_COMPLEX)
162 #if defined(HAVE_TEUCHOS_LONG_DOUBLE)
163 static_assert (std::is_same<ScalarType, std::complex<float> >::value ||
164 std::is_same<ScalarType, std::complex<double> >::value ||
165 std::is_same<ScalarType, Kokkos::complex<double> >::value ||
166 std::is_same<ScalarType, float>::value ||
167 std::is_same<ScalarType, double>::value ||
168 std::is_same<ScalarType, long double>::value,
169 "Belos::GCRODRSolMgr: ScalarType must be one of the four "
170 "types (S,D,C,Z) supported by LAPACK or long double (largely not impl'd).");
171 #else
172 static_assert (std::is_same<ScalarType, std::complex<float> >::value ||
173 std::is_same<ScalarType, std::complex<double> >::value ||
174 std::is_same<ScalarType, Kokkos::complex<double> >::value ||
175 std::is_same<ScalarType, float>::value ||
176 std::is_same<ScalarType, double>::value,
177 "Belos::GCRODRSolMgr: ScalarType must be one of the four "
178 "types (S,D,C,Z) supported by LAPACK.");
179 #endif
180# else
181 #if defined(HAVE_TEUCHOS_LONG_DOUBLE)
182 static_assert (std::is_same<ScalarType, float>::value ||
183 std::is_same<ScalarType, double>::value ||
184 std::is_same<ScalarType, long double>::value,
185 "Belos::GCRODRSolMgr: ScalarType must be float, double or long double. "
186 "Complex arithmetic support is currently disabled. To "
187 "enable it, set Teuchos_ENABLE_COMPLEX=ON.");
188 #else
189 static_assert (std::is_same<ScalarType, float>::value ||
190 std::is_same<ScalarType, double>::value,
191 "Belos::GCRODRSolMgr: ScalarType must be float or double. "
192 "Complex arithmetic support is currently disabled. To "
193 "enable it, set Teuchos_ENABLE_COMPLEX=ON.");
194 #endif
195# endif // defined(HAVE_TEUCHOS_COMPLEX)
196#endif // defined(HAVE_TEUCHOSCORE_CXX11)
197
198 private:
201 typedef Teuchos::ScalarTraits<ScalarType> SCT;
202 typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MagnitudeType;
203 typedef Teuchos::ScalarTraits<MagnitudeType> MT;
205
206 public:
208
209
215 GCRODRSolMgr();
216
270 const Teuchos::RCP<Teuchos::ParameterList> &pl);
271
273 virtual ~GCRODRSolMgr() {};
274
276 Teuchos::RCP<SolverManager<ScalarType, MV, OP> > clone () const override {
277 return Teuchos::rcp(new GCRODRSolMgr<ScalarType,MV,OP,true>);
278 }
280
282
283
287 return *problem_;
288 }
289
292 Teuchos::RCP<const Teuchos::ParameterList> getValidParameters() const override;
293
296 Teuchos::RCP<const Teuchos::ParameterList> getCurrentParameters() const override {
297 return params_;
298 }
299
305 Teuchos::Array<Teuchos::RCP<Teuchos::Time> > getTimers() const {
306 return Teuchos::tuple(timerSolve_);
307 }
308
314 MagnitudeType achievedTol() const override {
315 return achievedTol_;
316 }
317
319 int getNumIters() const override {
320 return numIters_;
321 }
322
325 bool isLOADetected() const override { return false; }
326
328
330
331
333 void setProblem( const Teuchos::RCP<LinearProblem<ScalarType,MV,OP> > &problem ) override {
334 problem_ = problem;
335 }
336
338 void setParameters( const Teuchos::RCP<Teuchos::ParameterList> &params ) override;
339
341
343
344
348 void reset( const ResetType type ) override {
349 if ((type & Belos::Problem) && !Teuchos::is_null(problem_)) {
350 bool set = problem_->setProblem();
351 if (!set)
352 throw "Could not set problem.";
353 }
354 else if (type & Belos::RecycleSubspace) {
355 keff = 0;
356 }
357 }
359
361
362
389 ReturnType solve() override;
390
392
394
396 std::string description() const override;
397
399
400 private:
401
402 // Called by all constructors; Contains init instructions common to all constructors
403 void init();
404
405 // Initialize solver state storage
406 void initializeStateStorage();
407
408 // Compute updated recycle space given existing recycle space and newly generated Krylov space
409 void buildRecycleSpace2(Teuchos::RCP<GCRODRIter<ScalarType,MV,OP> > gcrodr_iter);
410
411 // Computes harmonic eigenpairs of projected matrix created during the priming solve.
412 // HH is the projected problem from the initial cycle of Gmres, it is (at least) of dimension m+1 x m.
413 // PP contains the harmonic eigenvectors corresponding to the recycledBlocks eigenvalues of smallest magnitude.
414 // The return value is the number of vectors needed to be stored, recycledBlocks or recycledBlocks+1.
415 int getHarmonicVecs1(int m,
416 const Teuchos::SerialDenseMatrix<int,ScalarType>& HH,
417 Teuchos::SerialDenseMatrix<int,ScalarType>& PP);
418
419 // Computes harmonic eigenpairs of projected matrix created during one cycle.
420 // HH is the total block projected problem from the GCRO-DR algorithm, it is (at least) of dimension keff+m+1 x keff+m.
421 // VV is the Krylov vectors from the projected GMRES algorithm, which has (at least) m+1 vectors.
422 // PP contains the harmonic eigenvectors corresponding to the recycledBlocks eigenvalues of smallest magnitude.
423 // The return value is the number of vectors needed to be stored, recycledBlocks or recycledBlocks+1.
424 int getHarmonicVecs2(int keff, int m,
425 const Teuchos::SerialDenseMatrix<int,ScalarType>& HH,
426 const Teuchos::RCP<const MV>& VV,
427 Teuchos::SerialDenseMatrix<int,ScalarType>& PP);
428
429 // Sort list of n floating-point numbers and return permutation vector
430 void sort(std::vector<MagnitudeType>& dlist, int n, std::vector<int>& iperm);
431
432 // Lapack interface
433 Teuchos::LAPACK<int,ScalarType> lapack;
434
435 // Linear problem.
436 Teuchos::RCP<LinearProblem<ScalarType,MV,OP> > problem_;
437
438 // Output manager.
439 Teuchos::RCP<OutputManager<ScalarType> > printer_;
440 Teuchos::RCP<std::ostream> outputStream_;
441
442 // Status test.
443 Teuchos::RCP<StatusTest<ScalarType,MV,OP> > sTest_;
444 Teuchos::RCP<StatusTestMaxIters<ScalarType,MV,OP> > maxIterTest_;
445 Teuchos::RCP<StatusTest<ScalarType,MV,OP> > convTest_;
446 Teuchos::RCP<StatusTestGenResNorm<ScalarType,MV,OP> > expConvTest_, impConvTest_;
447 Teuchos::RCP<StatusTestOutput<ScalarType,MV,OP> > outputTest_;
448
452 Teuchos::RCP<MatOrthoManager<ScalarType,MV,OP> > ortho_;
453
454 // Current parameter list.
455 Teuchos::RCP<Teuchos::ParameterList> params_;
456
457 // Default solver values.
458 static constexpr double orthoKappa_default_ = 0.0;
459 static constexpr int maxRestarts_default_ = 100;
460 static constexpr int maxIters_default_ = 1000;
461 static constexpr int numBlocks_default_ = 50;
462 static constexpr int blockSize_default_ = 1;
463 static constexpr int recycledBlocks_default_ = 5;
464 static constexpr int verbosity_default_ = Belos::Errors;
465 static constexpr int outputStyle_default_ = Belos::General;
466 static constexpr int outputFreq_default_ = -1;
467 static constexpr const char * impResScale_default_ = "Norm of Preconditioned Initial Residual";
468 static constexpr const char * expResScale_default_ = "Norm of Initial Residual";
469 static constexpr const char * label_default_ = "Belos";
470 static constexpr const char * orthoType_default_ = "ICGS";
471
472 // Current solver values.
473 MagnitudeType convTol_, orthoKappa_, achievedTol_;
474 int maxRestarts_, maxIters_, numIters_;
475 int verbosity_, outputStyle_, outputFreq_;
476 std::string orthoType_;
477 std::string impResScale_, expResScale_;
478
480 // Solver State Storage
482 //
483 // The number of blocks and recycle blocks (m and k, respectively)
484 int numBlocks_, recycledBlocks_;
485 // Current size of recycled subspace
486 int keff;
487 //
488 // Residual vector
489 Teuchos::RCP<MV> r_;
490 //
491 // Search space
492 Teuchos::RCP<MV> V_;
493 //
494 // Recycled subspace and its image
495 Teuchos::RCP<MV> U_, C_;
496 //
497 // Updated recycle space and its image
498 Teuchos::RCP<MV> U1_, C1_;
499 //
500 // Storage used in constructing harmonic Ritz values/vectors
501 Teuchos::RCP<Teuchos::SerialDenseMatrix<int,ScalarType> > H2_;
502 Teuchos::RCP<Teuchos::SerialDenseMatrix<int,ScalarType> > H_;
503 Teuchos::RCP<Teuchos::SerialDenseMatrix<int,ScalarType> > B_;
504 Teuchos::RCP<Teuchos::SerialDenseMatrix<int,ScalarType> > PP_;
505 Teuchos::RCP<Teuchos::SerialDenseMatrix<int,ScalarType> > HP_;
506 std::vector<ScalarType> tau_;
507 std::vector<ScalarType> work_;
508 Teuchos::RCP<Teuchos::SerialDenseMatrix<int,ScalarType> > R_;
509 std::vector<int> ipiv_;
511
512 // Timers.
513 std::string label_;
514 Teuchos::RCP<Teuchos::Time> timerSolve_;
515
516 // Internal state variables.
517 bool isSet_;
518
519 // Have we generated or regenerated a recycle space yet this solve?
520 bool builtRecycleSpace_;
521 };
522
523
524// Empty Constructor
525template<class ScalarType, class MV, class OP>
527 achievedTol_(0.0),
528 numIters_(0)
529{
530 init ();
531}
532
533
534// Basic Constructor
535template<class ScalarType, class MV, class OP>
538 const Teuchos::RCP<Teuchos::ParameterList>& pl):
539 achievedTol_(0.0),
540 numIters_(0)
541{
542 // Initialize local pointers to null, and initialize local variables
543 // to default values.
544 init ();
545
547 problem == Teuchos::null, std::invalid_argument,
548 "Belos::GCRODRSolMgr constructor: The solver manager's "
549 "constructor needs the linear problem argument 'problem' "
550 "to be non-null.");
551 problem_ = problem;
552
553 // Set the parameters using the list that was passed in. If null,
554 // we defer initialization until a non-null list is set (by the
555 // client calling setParameters(), or by calling solve() -- in
556 // either case, a null parameter list indicates that default
557 // parameters should be used).
558 if (! pl.is_null ()) {
559 setParameters (pl);
560 }
561}
562
563// Common instructions executed in all constructors
564template<class ScalarType, class MV, class OP>
566 outputStream_ = Teuchos::rcpFromRef(std::cout);
568 orthoKappa_ = orthoKappa_default_;
569 maxRestarts_ = maxRestarts_default_;
570 maxIters_ = maxIters_default_;
571 numBlocks_ = numBlocks_default_;
572 recycledBlocks_ = recycledBlocks_default_;
573 verbosity_ = verbosity_default_;
574 outputStyle_ = outputStyle_default_;
575 outputFreq_ = outputFreq_default_;
576 orthoType_ = orthoType_default_;
577 impResScale_ = impResScale_default_;
578 expResScale_ = expResScale_default_;
579 label_ = label_default_;
580 isSet_ = false;
581 builtRecycleSpace_ = false;
582 keff = 0;
583 r_ = Teuchos::null;
584 V_ = Teuchos::null;
585 U_ = Teuchos::null;
586 C_ = Teuchos::null;
587 U1_ = Teuchos::null;
588 C1_ = Teuchos::null;
589 PP_ = Teuchos::null;
590 HP_ = Teuchos::null;
591 H2_ = Teuchos::null;
592 R_ = Teuchos::null;
593 H_ = Teuchos::null;
594 B_ = Teuchos::null;
595}
596
597template<class ScalarType, class MV, class OP>
598void
600setParameters (const Teuchos::RCP<Teuchos::ParameterList> &params)
601{
602 using Teuchos::isParameterType;
603 using Teuchos::getParameter;
604 using Teuchos::null;
605 using Teuchos::ParameterList;
606 using Teuchos::parameterList;
607 using Teuchos::RCP;
608 using Teuchos::rcp;
609 using Teuchos::rcp_dynamic_cast;
610 using Teuchos::rcpFromRef;
611 using Teuchos::Exceptions::InvalidParameter;
612 using Teuchos::Exceptions::InvalidParameterName;
613 using Teuchos::Exceptions::InvalidParameterType;
614
615 // The default parameter list contains all parameters that
616 // GCRODRSolMgr understands, and none that it doesn't understand.
617 RCP<const ParameterList> defaultParams = getValidParameters();
618
619 // Create the internal parameter list if one doesn't already exist.
620 //
621 // (mfh 28 Feb 2011, 10 Mar 2011) At the time this code was written,
622 // ParameterList did not have validators or validateParameters().
623 // This is why the code below carefully validates the parameters one
624 // by one and fills in defaults. This code could be made a lot
625 // shorter by using validators. To do so, we would have to define
626 // appropriate validators for all the parameters. (This would more
627 // or less just move all that validation code out of this routine
628 // into to getValidParameters().)
629 //
630 // For an analogous reason, GCRODRSolMgr defines default parameter
631 // values as class data, as well as in the default ParameterList.
632 // This redundancy could be removed by defining the default
633 // parameter values only in the default ParameterList (which
634 // documents each parameter as well -- handy!).
635 if (params_.is_null()) {
636 params_ = parameterList (*defaultParams);
637 } else {
638 // A common case for setParameters() is for it to be called at the
639 // beginning of the solve() routine. This follows the Belos
640 // pattern of delaying initialization until the last possible
641 // moment (when the user asks Belos to perform the solve). In
642 // this common case, we save ourselves a deep copy of the input
643 // parameter list.
644 if (params_ != params) {
645 // Make a deep copy of the input parameter list. This allows
646 // the caller to modify or change params later, without
647 // affecting the behavior of this solver. This solver will then
648 // only change its internal parameters if setParameters() is
649 // called again.
650 params_ = parameterList (*params);
651 }
652
653 // Fill in any missing parameters and their default values. Also,
654 // throw an exception if the parameter list has any misspelled or
655 // "extra" parameters. If you don't like this behavior, you'll
656 // want to replace the line of code below with your desired
657 // validation scheme. Note that Teuchos currently only implements
658 // two options:
659 //
660 // 1. validateParameters() requires that params_ has all the
661 // parameters that the default list has, and none that it
662 // doesn't have.
663 //
664 // 2. validateParametersAndSetDefaults() fills in missing
665 // parameters in params_ using the default list, but requires
666 // that any parameter provided in params_ is also in the
667 // default list.
668 //
669 // Here is an easy way to ignore any "extra" or misspelled
670 // parameters: Make a deep copy of the default list, fill in any
671 // "missing" parameters from the _input_ list, and then validate
672 // the input list using the deep copy of the default list. We
673 // show this in code:
674 //
675 // RCP<ParameterList> defaultCopy = parameterList (*getValidParameters ());
676 // defaultCopy->validateParametersAndSetDefaults (params);
677 // params->validateParametersAndSetDefaults (defaultCopy);
678 //
679 // This method is not entirely robust, because the input list may
680 // have incorrect validators set for existing parameters in the
681 // default list. This would then cause "validation" of the
682 // default list to throw an exception. As a result, we've chosen
683 // for now to be intolerant of misspellings and "extra" parameters
684 // in the input list.
685 params_->validateParametersAndSetDefaults (*defaultParams);
686 }
687
688 // Check for maximum number of restarts.
689 if (params->isParameter ("Maximum Restarts")) {
690 maxRestarts_ = params->get("Maximum Restarts", maxRestarts_default_);
691
692 // Update parameter in our list.
693 params_->set ("Maximum Restarts", maxRestarts_);
694 }
695
696 // Check for maximum number of iterations
697 if (params->isParameter ("Maximum Iterations")) {
698 maxIters_ = params->get ("Maximum Iterations", maxIters_default_);
699
700 // Update parameter in our list and in status test.
701 params_->set ("Maximum Iterations", maxIters_);
702 if (! maxIterTest_.is_null())
703 maxIterTest_->setMaxIters (maxIters_);
704 }
705
706 // Check for the maximum number of blocks.
707 if (params->isParameter ("Num Blocks")) {
708 numBlocks_ = params->get ("Num Blocks", numBlocks_default_);
709 TEUCHOS_TEST_FOR_EXCEPTION(numBlocks_ <= 0, std::invalid_argument,
710 "Belos::GCRODRSolMgr: The \"Num Blocks\" parameter must "
711 "be strictly positive, but you specified a value of "
712 << numBlocks_ << ".");
713 // Update parameter in our list.
714 params_->set ("Num Blocks", numBlocks_);
715 }
716
717 // Check for the maximum number of blocks.
718 if (params->isParameter ("Num Recycled Blocks")) {
719 recycledBlocks_ = params->get ("Num Recycled Blocks",
720 recycledBlocks_default_);
721 TEUCHOS_TEST_FOR_EXCEPTION(recycledBlocks_ <= 0, std::invalid_argument,
722 "Belos::GCRODRSolMgr: The \"Num Recycled Blocks\" "
723 "parameter must be strictly positive, but you specified "
724 "a value of " << recycledBlocks_ << ".");
725 TEUCHOS_TEST_FOR_EXCEPTION(recycledBlocks_ >= numBlocks_, std::invalid_argument,
726 "Belos::GCRODRSolMgr: The \"Num Recycled Blocks\" "
727 "parameter must be less than the \"Num Blocks\" "
728 "parameter, but you specified \"Num Recycled Blocks\" "
729 "= " << recycledBlocks_ << " and \"Num Blocks\" = "
730 << numBlocks_ << ".");
731 // Update parameter in our list.
732 params_->set("Num Recycled Blocks", recycledBlocks_);
733 }
734
735 // Check to see if the timer label changed. If it did, update it in
736 // the parameter list, and create a new timer with that label (if
737 // Belos was compiled with timers enabled).
738 if (params->isParameter ("Timer Label")) {
739 std::string tempLabel = params->get ("Timer Label", label_default_);
740
741 // Update parameter in our list and solver timer
742 if (tempLabel != label_) {
743 label_ = tempLabel;
744 params_->set ("Timer Label", label_);
745 std::string solveLabel = label_ + ": GCRODRSolMgr total solve time";
746#ifdef BELOS_TEUCHOS_TIME_MONITOR
747 timerSolve_ = Teuchos::TimeMonitor::getNewCounter (solveLabel);
748#endif
749 if (ortho_ != Teuchos::null) {
750 ortho_->setLabel( label_ );
751 }
752 }
753 }
754
755 // Check for a change in verbosity level
756 if (params->isParameter ("Verbosity")) {
757 if (isParameterType<int> (*params, "Verbosity")) {
758 verbosity_ = params->get ("Verbosity", verbosity_default_);
759 } else {
760 verbosity_ = (int) getParameter<Belos::MsgType> (*params, "Verbosity");
761 }
762 // Update parameter in our list.
763 params_->set ("Verbosity", verbosity_);
764 // If the output manager (printer_) is null, then we will
765 // instantiate it later with the correct verbosity.
766 if (! printer_.is_null())
767 printer_->setVerbosity (verbosity_);
768 }
769
770 // Check for a change in output style
771 if (params->isParameter ("Output Style")) {
772 if (isParameterType<int> (*params, "Output Style")) {
773 outputStyle_ = params->get ("Output Style", outputStyle_default_);
774 } else {
775 outputStyle_ = (int) getParameter<OutputType> (*params, "Output Style");
776 }
777
778 // Update parameter in our list.
779 params_->set ("Output Style", outputStyle_);
780 // We will (re)instantiate the output status test afresh below.
781 outputTest_ = null;
782 }
783
784 // Get the output stream for the output manager.
785 //
786 // While storing the output stream in the parameter list (either as
787 // an RCP or as a nonconst reference) is convenient and safe for
788 // programming, it makes it impossible to serialize the parameter
789 // list, read it back in from the serialized representation, and get
790 // the same output stream as before. This is because output streams
791 // may be arbitrary constructed objects.
792 //
793 // In case the user tried reading in the parameter list from a
794 // serialized representation and the output stream can't be read
795 // back in, we set the output stream to point to std::cout. This
796 // ensures reasonable behavior.
797 if (params->isParameter ("Output Stream")) {
798 try {
799 outputStream_ = getParameter<RCP<std::ostream> > (*params, "Output Stream");
800 } catch (InvalidParameter&) {
801 outputStream_ = rcpFromRef (std::cout);
802 }
803 // We assume that a null output stream indicates that the user
804 // doesn't want to print anything, so we replace it with a "black
805 // hole" stream that prints nothing sent to it. (We can't use a
806 // null output stream, since the output manager always sends
807 // things it wants to print to the output stream.)
808 if (outputStream_.is_null()) {
809 outputStream_ = rcp (new Teuchos::oblackholestream);
810 }
811 // Update parameter in our list.
812 params_->set ("Output Stream", outputStream_);
813 // If the output manager (printer_) is null, then we will
814 // instantiate it later with the correct output stream.
815 if (! printer_.is_null()) {
816 printer_->setOStream (outputStream_);
817 }
818 }
819
820 // frequency level
821 if (verbosity_ & Belos::StatusTestDetails) {
822 if (params->isParameter ("Output Frequency")) {
823 outputFreq_ = params->get ("Output Frequency", outputFreq_default_);
824 }
825
826 // Update parameter in out list and output status test.
827 params_->set("Output Frequency", outputFreq_);
828 if (! outputTest_.is_null())
829 outputTest_->setOutputFrequency (outputFreq_);
830 }
831
832 // Create output manager if we need to, using the verbosity level
833 // and output stream that we fetched above. We do this here because
834 // instantiating an OrthoManager using OrthoManagerFactory requires
835 // a valid OutputManager.
836 if (printer_.is_null()) {
837 printer_ = rcp (new OutputManager<ScalarType> (verbosity_, outputStream_));
838 }
839
840 // Get the orthogonalization manager name ("Orthogonalization").
841 //
842 // Getting default values for the orthogonalization manager
843 // parameters ("Orthogonalization Parameters") requires knowing the
844 // orthogonalization manager name. Save it for later, and also
845 // record whether it's different than before.
847 bool changedOrthoType = false;
848 if (params->isParameter ("Orthogonalization")) {
849 const std::string& tempOrthoType =
850 params->get ("Orthogonalization", orthoType_default_);
851 // Ensure that the specified orthogonalization type is valid.
852 if (! factory.isValidName (tempOrthoType)) {
853 std::ostringstream os;
854 os << "Belos::GCRODRSolMgr: Invalid orthogonalization name \""
855 << tempOrthoType << "\". The following are valid options "
856 << "for the \"Orthogonalization\" name parameter: ";
857 factory.printValidNames (os);
858 throw std::invalid_argument (os.str());
859 }
860 if (tempOrthoType != orthoType_) {
861 changedOrthoType = true;
862 orthoType_ = tempOrthoType;
863 // Update parameter in our list.
864 params_->set ("Orthogonalization", orthoType_);
865 }
866 }
867
868 // Get any parameters for the orthogonalization ("Orthogonalization
869 // Parameters"). If not supplied, the orthogonalization manager
870 // factory will supply default values.
871 //
872 // NOTE (mfh 12 Jan 2011) For the sake of backwards compatibility,
873 // if params has an "Orthogonalization Constant" parameter and the
874 // DGKS orthogonalization manager is to be used, the value of this
875 // parameter will override DGKS's "depTol" parameter.
876 //
877 // Users must supply the orthogonalization manager parameters as a
878 // sublist (supplying it as an RCP<ParameterList> would make the
879 // resulting parameter list not serializable).
881 { // The nonmember function sublist() returns an RCP<ParameterList>,
882 // which is what we want here.
883 using Teuchos::sublist;
884 // Abbreviation to avoid typos.
885 const std::string paramName ("Orthogonalization Parameters");
886
887 try {
888 orthoParams = sublist (params_, paramName, true);
889 } catch (InvalidParameter&) {
890 // We didn't get the parameter list from params, so get a
891 // default parameter list from the OrthoManagerFactory. Modify
892 // params_ so that it has the default parameter list, and set
893 // orthoParams to ensure it's a sublist of params_ (and not just
894 // a copy of one).
895 params_->set (paramName, factory.getDefaultParameters (orthoType_));
896 orthoParams = sublist (params_, paramName, true);
897 }
898 }
899 TEUCHOS_TEST_FOR_EXCEPTION(orthoParams.is_null(), std::logic_error,
900 "Failed to get orthogonalization parameters. "
901 "Please report this bug to the Belos developers.");
902
903 // Instantiate a new MatOrthoManager subclass instance if necessary.
904 // If not necessary, then tell the existing instance about the new
905 // parameters.
906 if (ortho_.is_null() || changedOrthoType) {
907 // We definitely need to make a new MatOrthoManager, since either
908 // we haven't made one yet, or we've changed orthogonalization
909 // methods. Creating the orthogonalization manager requires that
910 // the OutputManager (printer_) already be initialized.
911 ortho_ = factory.makeMatOrthoManager (orthoType_, null, printer_,
912 label_, orthoParams);
913 } else {
914 // If the MatOrthoManager implements the ParameterListAcceptor
915 // mix-in interface, we can propagate changes to its parameters
916 // without reinstantiating the MatOrthoManager.
917 //
918 // We recommend that all MatOrthoManager subclasses implement
919 // Teuchos::ParameterListAcceptor, but do not (yet) require this.
920 typedef Teuchos::ParameterListAcceptor PLA;
922 if (pla.is_null()) {
923 // Oops, it's not a ParameterListAcceptor. We have to
924 // reinstantiate the MatOrthoManager in order to pass in the
925 // possibly new parameters.
926 ortho_ = factory.makeMatOrthoManager (orthoType_, null, printer_,
927 label_, orthoParams);
928 } else {
929 pla->setParameterList (orthoParams);
930 }
931 }
932
933 // The DGKS orthogonalization accepts a "Orthogonalization Constant"
934 // parameter (also called kappa in the code, but not in the
935 // parameter list). If its value is provided in the given parameter
936 // list, and its value is positive, use it. Ignore negative values.
937 //
938 // NOTE (mfh 12 Jan 2011) This overrides the "depTol" parameter that
939 // may have been specified in "Orthogonalization Parameters". We
940 // retain this behavior for backwards compatibility.
941 if (params->isParameter ("Orthogonalization Constant")) {
942 MagnitudeType orthoKappa = orthoKappa_default_;
943 if (params->isType<MagnitudeType> ("Orthogonalization Constant")) {
944 orthoKappa = params->get ("Orthogonalization Constant", orthoKappa);
945 }
946 else {
947 orthoKappa = params->get ("Orthogonalization Constant", orthoKappa_default_);
948 }
949
950 if (orthoKappa > 0) {
951 orthoKappa_ = orthoKappa;
952 // Update parameter in our list.
953 params_->set("Orthogonalization Constant", orthoKappa_);
954 // Only DGKS currently accepts this parameter.
955 if (orthoType_ == "DGKS" && ! ortho_.is_null()) {
957 // This cast should always succeed; it's a bug
958 // otherwise. (If the cast fails, then orthoType_
959 // doesn't correspond to the OrthoManager subclass
960 // instance that we think we have, so we initialized the
961 // wrong subclass somehow.)
962 rcp_dynamic_cast<ortho_man_type>(ortho_)->setDepTol (orthoKappa_);
963 }
964 }
965 }
966
967 // Convergence
968 typedef Belos::StatusTestCombo<ScalarType,MV,OP> StatusTestCombo_t;
969 typedef Belos::StatusTestGenResNorm<ScalarType,MV,OP> StatusTestResNorm_t;
970
971 // Check for convergence tolerance
972 if (params->isParameter("Convergence Tolerance")) {
973 if (params->isType<MagnitudeType> ("Convergence Tolerance")) {
974 convTol_ = params->get ("Convergence Tolerance",
975 static_cast<MagnitudeType> (DefaultSolverParameters::convTol));
976 }
977 else {
978 convTol_ = params->get ("Convergence Tolerance", DefaultSolverParameters::convTol);
979 }
980
981 // Update parameter in our list and residual tests.
982 params_->set ("Convergence Tolerance", convTol_);
983 if (! impConvTest_.is_null())
984 impConvTest_->setTolerance (convTol_);
985 if (! expConvTest_.is_null())
986 expConvTest_->setTolerance (convTol_);
987 }
988
989 // Check for a change in scaling, if so we need to build new residual tests.
990 if (params->isParameter ("Implicit Residual Scaling")) {
991 std::string tempImpResScale =
992 getParameter<std::string> (*params, "Implicit Residual Scaling");
993
994 // Only update the scaling if it's different.
995 if (impResScale_ != tempImpResScale) {
997 impResScale_ = tempImpResScale;
998
999 // Update parameter in our list and residual tests
1000 params_->set("Implicit Residual Scaling", impResScale_);
1001 // NOTE (mfh 28 Feb 2011) StatusTestImpResNorm only lets you
1002 // call defineScaleForm() once. The code below attempts to call
1003 // defineScaleForm(); if the scale form has already been
1004 // defined, it constructs a new StatusTestImpResNorm instance.
1005 // StatusTestImpResNorm really should not expose the
1006 // defineScaleForm() method, since it's serving an
1007 // initialization purpose; all initialization should happen in
1008 // the constructor whenever possible. In that case, the code
1009 // below could be simplified into a single (re)instantiation.
1010 if (! impConvTest_.is_null()) {
1011 try {
1012 impConvTest_->defineScaleForm (impResScaleType, Belos::TwoNorm);
1013 }
1014 catch (StatusTestError&) {
1015 // Delete the convergence test so it gets constructed again.
1016 impConvTest_ = null;
1017 convTest_ = null;
1018 }
1019 }
1020 }
1021 }
1022
1023 if (params->isParameter("Explicit Residual Scaling")) {
1024 std::string tempExpResScale =
1025 getParameter<std::string> (*params, "Explicit Residual Scaling");
1026
1027 // Only update the scaling if it's different.
1028 if (expResScale_ != tempExpResScale) {
1030 expResScale_ = tempExpResScale;
1031
1032 // Update parameter in our list and residual tests
1033 params_->set("Explicit Residual Scaling", expResScale_);
1034 // NOTE (mfh 28 Feb 2011) See note above on the (re)construction
1035 // of StatusTestImpResNorm.
1036 if (! expConvTest_.is_null()) {
1037 try {
1038 expConvTest_->defineScaleForm (expResScaleType, Belos::TwoNorm);
1039 }
1040 catch (StatusTestError&) {
1041 // Delete the convergence test so it gets constructed again.
1042 expConvTest_ = null;
1043 convTest_ = null;
1044 }
1045 }
1046 }
1047 }
1048 //
1049 // Create iteration stopping criteria ("status tests") if we need
1050 // to, by combining three different stopping criteria.
1051 //
1052 // First, construct maximum-number-of-iterations stopping criterion.
1053 if (maxIterTest_.is_null())
1054 maxIterTest_ = rcp (new StatusTestMaxIters<ScalarType,MV,OP> (maxIters_));
1055
1056 // Implicit residual test, using the native residual to determine if
1057 // convergence was achieved.
1058 if (impConvTest_.is_null()) {
1059 impConvTest_ = rcp (new StatusTestResNorm_t (convTol_));
1060 impConvTest_->defineScaleForm (convertStringToScaleType (impResScale_),
1062 }
1063
1064 // Explicit residual test once the native residual is below the tolerance
1065 if (expConvTest_.is_null()) {
1066 expConvTest_ = rcp (new StatusTestResNorm_t (convTol_));
1067 expConvTest_->defineResForm (StatusTestResNorm_t::Explicit, Belos::TwoNorm);
1068 expConvTest_->defineScaleForm (convertStringToScaleType (expResScale_),
1070 }
1071 // Convergence test first tests the implicit residual, then the
1072 // explicit residual if the implicit residual test passes.
1073 if (convTest_.is_null()) {
1074 convTest_ = rcp (new StatusTestCombo_t (StatusTestCombo_t::SEQ,
1075 impConvTest_,
1076 expConvTest_));
1077 }
1078 // Construct the complete iteration stopping criterion:
1079 //
1080 // "Stop iterating if the maximum number of iterations has been
1081 // reached, or if the convergence test passes."
1082 sTest_ = rcp (new StatusTestCombo_t (StatusTestCombo_t::OR,
1083 maxIterTest_,
1084 convTest_));
1085 // Create the status test output class.
1086 // This class manages and formats the output from the status test.
1088 outputTest_ = stoFactory.create (printer_, sTest_, outputFreq_,
1090
1091 // Set the solver string for the output test
1092 std::string solverDesc = " GCRODR ";
1093 outputTest_->setSolverDesc( solverDesc );
1094
1095 // Create the timer if we need to.
1096 if (timerSolve_.is_null()) {
1097 std::string solveLabel = label_ + ": GCRODRSolMgr total solve time";
1098#ifdef BELOS_TEUCHOS_TIME_MONITOR
1099 timerSolve_ = Teuchos::TimeMonitor::getNewCounter(solveLabel);
1100#endif
1101 }
1102
1103 // Inform the solver manager that the current parameters were set.
1104 isSet_ = true;
1105}
1106
1107
1108template<class ScalarType, class MV, class OP>
1109Teuchos::RCP<const Teuchos::ParameterList>
1111{
1112 using Teuchos::ParameterList;
1113 using Teuchos::parameterList;
1114 using Teuchos::RCP;
1115
1117 if (is_null(validPL)) {
1119
1120 // Set all the valid parameters and their default values.
1121 pl->set("Convergence Tolerance", static_cast<MagnitudeType>(DefaultSolverParameters::convTol),
1122 "The relative residual tolerance that needs to be achieved by the\n"
1123 "iterative solver in order for the linear system to be declared converged.");
1124 pl->set("Maximum Restarts", static_cast<int>(maxRestarts_default_),
1125 "The maximum number of cycles allowed for each\n"
1126 "set of RHS solved.");
1127 pl->set("Maximum Iterations", static_cast<int>(maxIters_default_),
1128 "The maximum number of iterations allowed for each\n"
1129 "set of RHS solved.");
1130 // mfh 25 Oct 2010: "Block Size" must be 1 because GCRODR is
1131 // currently not a block method: i.e., it does not work on
1132 // multiple right-hand sides at once.
1133 pl->set("Block Size", static_cast<int>(blockSize_default_),
1134 "Block Size Parameter -- currently must be 1 for GCRODR");
1135 pl->set("Num Blocks", static_cast<int>(numBlocks_default_),
1136 "The maximum number of vectors allowed in the Krylov subspace\n"
1137 "for each set of RHS solved.");
1138 pl->set("Num Recycled Blocks", static_cast<int>(recycledBlocks_default_),
1139 "The maximum number of vectors in the recycled subspace." );
1140 pl->set("Verbosity", static_cast<int>(verbosity_default_),
1141 "What type(s) of solver information should be outputted\n"
1142 "to the output stream.");
1143 pl->set("Output Style", static_cast<int>(outputStyle_default_),
1144 "What style is used for the solver information outputted\n"
1145 "to the output stream.");
1146 pl->set("Output Frequency", static_cast<int>(outputFreq_default_),
1147 "How often convergence information should be outputted\n"
1148 "to the output stream.");
1149 pl->set("Output Stream", Teuchos::rcpFromRef(std::cout),
1150 "A reference-counted pointer to the output stream where all\n"
1151 "solver output is sent.");
1152 pl->set("Implicit Residual Scaling", static_cast<const char *>(impResScale_default_),
1153 "The type of scaling used in the implicit residual convergence test.");
1154 pl->set("Explicit Residual Scaling", static_cast<const char *>(expResScale_default_),
1155 "The type of scaling used in the explicit residual convergence test.");
1156 pl->set("Timer Label", static_cast<const char *>(label_default_),
1157 "The string to use as a prefix for the timer labels.");
1158 {
1160 pl->set("Orthogonalization", static_cast<const char *>(orthoType_default_),
1161 "The type of orthogonalization to use. Valid options: " +
1162 factory.validNamesString());
1164 factory.getDefaultParameters (orthoType_default_);
1165 pl->set ("Orthogonalization Parameters", *orthoParams,
1166 "Parameters specific to the type of orthogonalization used.");
1167 }
1168 pl->set("Orthogonalization Constant",static_cast<MagnitudeType>(orthoKappa_default_),
1169 "When using DGKS orthogonalization: the \"depTol\" constant, used "
1170 "to determine whether another step of classical Gram-Schmidt is "
1171 "necessary. Otherwise ignored.");
1172 validPL = pl;
1173 }
1174 return validPL;
1175}
1176
1177// initializeStateStorage
1178template<class ScalarType, class MV, class OP>
1180
1181 ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
1182
1183 // Check if there is any multivector to clone from.
1184 Teuchos::RCP<const MV> rhsMV = problem_->getRHS();
1185 if (rhsMV == Teuchos::null) {
1186 // Nothing to do
1187 return;
1188 }
1189 else {
1190
1191 // Initialize the state storage
1192 TEUCHOS_TEST_FOR_EXCEPTION(static_cast<ptrdiff_t>(numBlocks_) > MVT::GetGlobalLength(*rhsMV),std::invalid_argument,
1193 "Belos::GCRODRSolMgr::initializeStateStorage(): Cannot generate a Krylov basis with dimension larger the operator!");
1194
1195 // If the subspace has not been initialized before, generate it using the RHS from lp_.
1196 if (U_ == Teuchos::null) {
1197 U_ = MVT::Clone( *rhsMV, recycledBlocks_+1 );
1198 }
1199 else {
1200 // Generate U_ by cloning itself ONLY if more space is needed.
1201 if (MVT::GetNumberVecs(*U_) < recycledBlocks_+1) {
1202 Teuchos::RCP<const MV> tmp = U_;
1203 U_ = MVT::Clone( *tmp, recycledBlocks_+1 );
1204 }
1205 }
1206
1207 // If the subspace has not been initialized before, generate it using the RHS from lp_.
1208 if (C_ == Teuchos::null) {
1209 C_ = MVT::Clone( *rhsMV, recycledBlocks_+1 );
1210 }
1211 else {
1212 // Generate C_ by cloning itself ONLY if more space is needed.
1213 if (MVT::GetNumberVecs(*C_) < recycledBlocks_+1) {
1214 Teuchos::RCP<const MV> tmp = C_;
1215 C_ = MVT::Clone( *tmp, recycledBlocks_+1 );
1216 }
1217 }
1218
1219 // If the subspace has not been initialized before, generate it using the RHS from lp_.
1220 if (V_ == Teuchos::null) {
1221 V_ = MVT::Clone( *rhsMV, numBlocks_+1 );
1222 }
1223 else {
1224 // Generate V_ by cloning itself ONLY if more space is needed.
1225 if (MVT::GetNumberVecs(*V_) < numBlocks_+1) {
1226 Teuchos::RCP<const MV> tmp = V_;
1227 V_ = MVT::Clone( *tmp, numBlocks_+1 );
1228 }
1229 }
1230
1231 // If the subspace has not been initialized before, generate it using the RHS from lp_.
1232 if (U1_ == Teuchos::null) {
1233 U1_ = MVT::Clone( *rhsMV, recycledBlocks_+1 );
1234 }
1235 else {
1236 // Generate U1_ by cloning itself ONLY if more space is needed.
1237 if (MVT::GetNumberVecs(*U1_) < recycledBlocks_+1) {
1238 Teuchos::RCP<const MV> tmp = U1_;
1239 U1_ = MVT::Clone( *tmp, recycledBlocks_+1 );
1240 }
1241 }
1242
1243 // If the subspace has not been initialized before, generate it using the RHS from lp_.
1244 if (C1_ == Teuchos::null) {
1245 C1_ = MVT::Clone( *rhsMV, recycledBlocks_+1 );
1246 }
1247 else {
1248 // Generate C1_ by cloning itself ONLY if more space is needed.
1249 if (MVT::GetNumberVecs(*C1_) < recycledBlocks_+1) {
1250 Teuchos::RCP<const MV> tmp = C1_;
1251 C1_ = MVT::Clone( *tmp, recycledBlocks_+1 );
1252 }
1253 }
1254
1255 // Generate r_ only if it doesn't exist
1256 if (r_ == Teuchos::null)
1257 r_ = MVT::Clone( *rhsMV, 1 );
1258
1259 // Size of tau_ will change during computation, so just be sure it starts with appropriate size
1260 tau_.resize(recycledBlocks_+1);
1261
1262 // Size of work_ will change during computation, so just be sure it starts with appropriate size
1263 work_.resize(recycledBlocks_+1);
1264
1265 // Size of ipiv_ will change during computation, so just be sure it starts with appropriate size
1266 ipiv_.resize(recycledBlocks_+1);
1267
1268 // Generate H2_ only if it doesn't exist, otherwise resize it.
1269 if (H2_ == Teuchos::null)
1270 H2_ = Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>( numBlocks_+recycledBlocks_+2, numBlocks_+recycledBlocks_+1 ) );
1271 else {
1272 if ( (H2_->numRows() != numBlocks_+recycledBlocks_+2) || (H2_->numCols() != numBlocks_+recycledBlocks_+1) )
1273 H2_->reshape( numBlocks_+recycledBlocks_+2, numBlocks_+recycledBlocks_+1 );
1274 }
1275 H2_->putScalar(zero);
1276
1277 // Generate R_ only if it doesn't exist, otherwise resize it.
1278 if (R_ == Teuchos::null)
1279 R_ = Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>( recycledBlocks_+1, recycledBlocks_+1 ) );
1280 else {
1281 if ( (R_->numRows() != recycledBlocks_+1) || (R_->numCols() != recycledBlocks_+1) )
1282 R_->reshape( recycledBlocks_+1, recycledBlocks_+1 );
1283 }
1284 R_->putScalar(zero);
1285
1286 // Generate PP_ only if it doesn't exist, otherwise resize it.
1287 if (PP_ == Teuchos::null)
1288 PP_ = Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>( numBlocks_+recycledBlocks_+2, recycledBlocks_+1 ) );
1289 else {
1290 if ( (PP_->numRows() != numBlocks_+recycledBlocks_+2) || (PP_->numCols() != recycledBlocks_+1) )
1291 PP_->reshape( numBlocks_+recycledBlocks_+2, recycledBlocks_+1 );
1292 }
1293
1294 // Generate HP_ only if it doesn't exist, otherwise resize it.
1295 if (HP_ == Teuchos::null)
1296 HP_ = Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>( numBlocks_+recycledBlocks_+2, numBlocks_+recycledBlocks_+1 ) );
1297 else {
1298 if ( (HP_->numRows() != numBlocks_+recycledBlocks_+2) || (HP_->numCols() != numBlocks_+recycledBlocks_+1) )
1299 HP_->reshape( numBlocks_+recycledBlocks_+2, numBlocks_+recycledBlocks_+1 );
1300 }
1301
1302 } // end else
1303}
1304
1305
1306// solve()
1307template<class ScalarType, class MV, class OP>
1309 using Teuchos::RCP;
1310 using Teuchos::rcp;
1311
1313
1314 // Set the current parameters if they were not set before.
1315 // NOTE: This may occur if the user generated the solver manager with the default constructor and
1316 // then didn't set any parameters using setParameters().
1317 if (!isSet_) { setParameters( params_ ); }
1318
1319 ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
1320 ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
1321 std::vector<int> index(numBlocks_+1);
1322
1323 TEUCHOS_TEST_FOR_EXCEPTION(problem_ == Teuchos::null,GCRODRSolMgrLinearProblemFailure, "Belos::GCRODRSolMgr::solve(): Linear problem is not a valid object.");
1324
1325 TEUCHOS_TEST_FOR_EXCEPTION(!problem_->isProblemSet(),GCRODRSolMgrLinearProblemFailure,"Belos::GCRODRSolMgr::solve(): Linear problem is not ready, setProblem() has not been called.");
1326
1327 // Create indices for the linear systems to be solved.
1328 int numRHS2Solve = MVT::GetNumberVecs( *(problem_->getRHS()) );
1329 std::vector<int> currIdx(1);
1330 currIdx[0] = 0;
1331
1332 // Inform the linear problem of the current linear system to solve.
1333 problem_->setLSIndex( currIdx );
1334
1335 // Check the number of blocks and change them is necessary.
1336 ptrdiff_t dim = MVT::GetGlobalLength( *(problem_->getRHS()) );
1337 if (static_cast<ptrdiff_t>(numBlocks_) > dim) {
1338 numBlocks_ = Teuchos::as<int>(dim);
1339 printer_->stream(Warnings) <<
1340 "Warning! Requested Krylov subspace dimension is larger than operator dimension!" << std::endl <<
1341 " The maximum number of blocks allowed for the Krylov subspace will be adjusted to " << numBlocks_ << std::endl;
1342 params_->set("Num Blocks", numBlocks_);
1343 }
1344
1345 // Assume convergence is achieved, then let any failed convergence set this to false.
1346 bool isConverged = true;
1347
1348 // Initialize storage for all state variables
1349 initializeStateStorage();
1350
1352 // Parameter list
1353 Teuchos::ParameterList plist;
1354
1355 plist.set("Num Blocks",numBlocks_);
1356 plist.set("Recycled Blocks",recycledBlocks_);
1357
1359 // GCRODR solver
1360
1362 gcrodr_iter = rcp( new GCRODRIter<ScalarType,MV,OP>(problem_,printer_,outputTest_,ortho_,plist) );
1363 // Number of iterations required to generate initial recycle space (if needed)
1364 int prime_iterations = 0;
1365
1366 // Enter solve() iterations
1367 {
1368#ifdef BELOS_TEUCHOS_TIME_MONITOR
1369 Teuchos::TimeMonitor slvtimer(*timerSolve_);
1370#endif
1371
1372 while ( numRHS2Solve > 0 ) {
1373
1374 // Set flag indicating recycle space has not been generated this solve
1375 builtRecycleSpace_ = false;
1376
1377 // Reset the status test.
1378 outputTest_->reset();
1379
1381 // Initialize recycled subspace for GCRODR
1382
1383 // If there is a subspace to recycle, recycle it, otherwise generate the initial recycled subspace.
1384 if (keff > 0) {
1386 "Belos::GCRODRSolMgr::solve(): Requested size of recycled subspace is not consistent with the current recycle subspace.");
1387
1388 printer_->stream(Debug) << " Now solving RHS index " << currIdx[0] << " using recycled subspace of dimension " << keff << std::endl << std::endl;
1389 // Compute image of U_ under the new operator
1390 index.resize(keff);
1391 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1392 RCP<const MV> Utmp = MVT::CloneView( *U_, index );
1393 RCP<MV> Ctmp = MVT::CloneViewNonConst( *C_, index );
1394 problem_->apply( *Utmp, *Ctmp );
1395
1396 RCP<MV> U1tmp = MVT::CloneViewNonConst( *U1_, index );
1397
1398 // Orthogonalize this block
1399 // Get a matrix to hold the orthonormalization coefficients.
1400 Teuchos::SerialDenseMatrix<int,ScalarType> Rtmp( Teuchos::View, *R_, keff, keff );
1401 int rank = ortho_->normalize(*Ctmp, rcp(&Rtmp,false));
1402 // Throw an error if we could not orthogonalize this block
1403 TEUCHOS_TEST_FOR_EXCEPTION(rank != keff,GCRODRSolMgrOrthoFailure,"Belos::GCRODRSolMgr::solve(): Failed to compute orthonormal basis for initial recycled subspace.");
1404
1405 // U_ = U_*R^{-1}
1406 // First, compute LU factorization of R
1407 int info = 0;
1408 ipiv_.resize(Rtmp.numRows());
1409 lapack.GETRF(Rtmp.numRows(),Rtmp.numCols(),Rtmp.values(),Rtmp.stride(),&ipiv_[0],&info);
1410 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, GCRODRSolMgrLAPACKFailure,"Belos::GCRODRSolMgr::solve(): LAPACK _GETRF failed to compute an LU factorization.");
1411
1412 // Now, form inv(R)
1413 int lwork = Rtmp.numRows();
1414 work_.resize(lwork);
1415 lapack.GETRI(Rtmp.numRows(),Rtmp.values(),Rtmp.stride(),&ipiv_[0],&work_[0],lwork,&info);
1416 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, GCRODRSolMgrLAPACKFailure,"Belos::GCRODRSolMgr::solve(): LAPACK _GETRI failed to invert triangular matrix.");
1417
1418 // U_ = U1_; (via a swap)
1419 MVT::MvTimesMatAddMv( one, *Utmp, Rtmp, zero, *U1tmp );
1420 std::swap(U_, U1_);
1421
1422 // Must reinitialize after swap
1423 index.resize(keff);
1424 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1425 Ctmp = MVT::CloneViewNonConst( *C_, index );
1426 Utmp = MVT::CloneView( *U_, index );
1427
1428 // Compute C_'*r_
1429 Teuchos::SerialDenseMatrix<int,ScalarType> Ctr(keff,1);
1430 problem_->computeCurrPrecResVec( &*r_ );
1431 MVT::MvTransMv( one, *Ctmp, *r_, Ctr );
1432
1433 // Update solution ( x += U_*C_'*r_ )
1434 RCP<MV> update = MVT::Clone( *problem_->getCurrLHSVec(), 1 );
1435 MVT::MvInit( *update, 0.0 );
1436 MVT::MvTimesMatAddMv( one, *Utmp, Ctr, one, *update );
1437 problem_->updateSolution( update, true );
1438
1439 // Update residual norm ( r -= C_*C_'*r_ )
1440 MVT::MvTimesMatAddMv( -one, *Ctmp, Ctr, one, *r_ );
1441
1442 // We recycled space from previous call
1443 prime_iterations = 0;
1444
1445 }
1446 else {
1447
1448 // Do one cycle of Gmres to "prime the pump" if there is no subspace to recycle
1449 printer_->stream(Debug) << " No recycled subspace available for RHS index " << currIdx[0] << std::endl << std::endl;
1450
1451 Teuchos::ParameterList primeList;
1452
1453 // Tell the block solver that the block size is one.
1454 primeList.set("Num Blocks",numBlocks_);
1455 primeList.set("Recycled Blocks",0);
1456
1457 // Create GCRODR iterator object to perform one cycle of GMRES.
1459 gcrodr_prime_iter = rcp( new GCRODRIter<ScalarType,MV,OP>(problem_,printer_,outputTest_,ortho_,primeList) );
1460
1461 // Create the first block in the current Krylov basis (residual).
1462 problem_->computeCurrPrecResVec( &*r_ );
1463 index.resize( 1 ); index[0] = 0;
1464 RCP<MV> v0 = MVT::CloneViewNonConst( *V_, index );
1465 MVT::SetBlock(*r_,index,*v0); // V(:,0) = r
1466
1467 // Set the new state and initialize the solver.
1469 index.resize( numBlocks_+1 );
1470 for (int ii=0; ii<(numBlocks_+1); ++ii) { index[ii] = ii; }
1471 newstate.V = MVT::CloneViewNonConst( *V_, index );
1472 newstate.U = Teuchos::null;
1473 newstate.C = Teuchos::null;
1474 newstate.H = rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>( Teuchos::View, *H2_, numBlocks_+1, numBlocks_, recycledBlocks_+1, recycledBlocks_+1 ) );
1475 newstate.B = Teuchos::null;
1476 newstate.curDim = 0;
1477 gcrodr_prime_iter->initialize(newstate);
1478
1479 // Perform one cycle of GMRES
1480 bool primeConverged = false;
1481 try {
1482 gcrodr_prime_iter->iterate();
1483
1484 // Check convergence first
1485 if ( convTest_->getStatus() == Passed ) {
1486 // we have convergence
1487 primeConverged = true;
1488 }
1489 }
1490 catch (const GCRODRIterOrthoFailure &e) {
1491 // Try to recover the most recent least-squares solution
1492 gcrodr_prime_iter->updateLSQR( gcrodr_prime_iter->getCurSubspaceDim() );
1493
1494 // Check to see if the most recent least-squares solution yielded convergence.
1495 sTest_->checkStatus( &*gcrodr_prime_iter );
1496 if (convTest_->getStatus() == Passed)
1497 primeConverged = true;
1498 }
1499 catch (const StatusTestNaNError& e) {
1500 // A NaN was detected in the solver. Set the solution to zero and return unconverged.
1502 achievedTol_ = MT::one();
1503 Teuchos::RCP<MV> X = problem_->getLHS();
1504 MVT::MvInit( *X, SCT::zero() );
1505 printer_->stream(Warnings) << "Belos::GCRODRSolMgr::solve(): Warning! NaN has been detected!"
1506 << std::endl;
1507 return retType;
1508 }
1509 catch (const std::exception &e) {
1511 printer_->stream(Errors) << "Error! Caught exception in GCRODRIter::iterate() at iteration "
1512 << gcrodr_prime_iter->getNumIters() << std::endl
1513 << e.what() << std::endl;
1514 throw;
1515 }
1516 // Record number of iterations in generating initial recycle spacec
1517 prime_iterations = gcrodr_prime_iter->getNumIters();
1518
1519 // Update the linear problem.
1520 RCP<MV> update = gcrodr_prime_iter->getCurrentUpdate();
1521 problem_->updateSolution( update, true );
1522
1523 // Get the state.
1524 newstate = gcrodr_prime_iter->getState();
1525 int p = newstate.curDim;
1526
1527 // Compute harmonic Ritz vectors
1528 // NOTE: The storage for the harmonic Ritz vectors (PP) is made one column larger
1529 // just in case we split a complex conjugate pair.
1530 // NOTE: Generate a recycled subspace only if we have enough vectors. If we converged
1531 // too early, move on to the next linear system and try to generate a subspace again.
1532 if (recycledBlocks_ < p+1) {
1533 int info = 0;
1534 RCP<Teuchos::SerialDenseMatrix<int,ScalarType> > PPtmp = rcp (new Teuchos::SerialDenseMatrix<int,ScalarType> ( Teuchos::View, *PP_, p, recycledBlocks_+1 ) );
1535 // getHarmonicVecs1 assumes PP has recycledBlocks_+1 columns available
1536 keff = getHarmonicVecs1( p, *newstate.H, *PPtmp );
1537 // Hereafter, only keff columns of PP are needed
1538 PPtmp = rcp (new Teuchos::SerialDenseMatrix<int,ScalarType> ( Teuchos::View, *PP_, p, keff ) );
1539 // Now get views into C, U, V
1540 index.resize(keff);
1541 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1542 RCP<MV> Ctmp = MVT::CloneViewNonConst( *C_, index );
1543 RCP<MV> Utmp = MVT::CloneViewNonConst( *U_, index );
1544 RCP<MV> U1tmp = MVT::CloneViewNonConst( *U1_, index );
1545 index.resize(p);
1546 for (int ii=0; ii < p; ++ii) { index[ii] = ii; }
1547 RCP<const MV> Vtmp = MVT::CloneView( *V_, index );
1548
1549 // Form U (the subspace to recycle)
1550 // U = newstate.V(:,1:p) * PP;
1551 MVT::MvTimesMatAddMv( one, *Vtmp, *PPtmp, zero, *U1tmp );
1552
1553 // Form orthonormalized C and adjust U so that C = A*U
1554
1555 // First, compute [Q, R] = qr(H*P);
1556
1557 // Step #1: Form HP = H*P
1558 Teuchos::SerialDenseMatrix<int,ScalarType> Htmp( Teuchos::View, *H2_, p+1, p, recycledBlocks_+1,recycledBlocks_+1);
1559 Teuchos::SerialDenseMatrix<int,ScalarType> HPtmp( Teuchos::View, *HP_, p+1, keff );
1560 HPtmp.multiply( Teuchos::NO_TRANS, Teuchos::NO_TRANS, one, Htmp, *PPtmp, zero );
1561
1562 // Step #1.5: Perform workspace size query for QR
1563 // factorization of HP. On input, lwork must be -1.
1564 // _GEQRF will put the workspace size in work_[0].
1565 int lwork = -1;
1566 tau_.resize (keff);
1567 lapack.GEQRF (HPtmp.numRows (), HPtmp.numCols (), HPtmp.values (),
1568 HPtmp.stride (), &tau_[0], &work_[0], lwork, &info);
1570 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve:"
1571 " LAPACK's _GEQRF failed to compute a workspace size.");
1572
1573 // Step #2: Compute QR factorization of HP
1574 //
1575 // NOTE (mfh 17 Apr 2014) LAPACK promises that the value of
1576 // work_[0] after the workspace query will fit in int. This
1577 // justifies the cast. We call real() first because
1578 // static_cast from std::complex to int doesn't work.
1579 lwork = std::abs (static_cast<int> (Teuchos::ScalarTraits<ScalarType>::real (work_[0])));
1580 work_.resize (lwork); // Allocate workspace for the QR factorization
1581 lapack.GEQRF (HPtmp.numRows (), HPtmp.numCols (), HPtmp.values (),
1582 HPtmp.stride (), &tau_[0], &work_[0], lwork, &info);
1584 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve:"
1585 " LAPACK's _GEQRF failed to compute a QR factorization.");
1586
1587 // Step #3: Explicitly construct Q and R factors
1588 // NOTE: The upper triangular part of HP is copied into R and HP becomes Q.
1589 Teuchos::SerialDenseMatrix<int,ScalarType> Rtmp( Teuchos::View, *R_, keff, keff );
1590 for (int ii = 0; ii < keff; ++ii) {
1591 for (int jj = ii; jj < keff; ++jj) {
1592 Rtmp(ii,jj) = HPtmp(ii,jj);
1593 }
1594 }
1595 // NOTE (mfh 17 Apr 2014): Teuchos::LAPACK's wrapper for
1596 // UNGQR dispatches to the correct Scalar-specific routine.
1597 // It calls {S,D}ORGQR if Scalar is real, and {C,Z}UNGQR if
1598 // Scalar is complex.
1599 lapack.UNGQR (HPtmp.numRows (), HPtmp.numCols (), HPtmp.numCols (),
1600 HPtmp.values (), HPtmp.stride (), &tau_[0], &work_[0],
1601 lwork, &info);
1603 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve: "
1604 "LAPACK's _UNGQR failed to construct the Q factor.");
1605
1606 // Now we have [Q,R] = qr(H*P)
1607
1608 // Now compute C = V(:,1:p+1) * Q
1609 index.resize (p + 1);
1610 for (int ii = 0; ii < (p+1); ++ii) {
1611 index[ii] = ii;
1612 }
1613 Vtmp = MVT::CloneView( *V_, index ); // need new view into V (p+1 vectors now; needed p above)
1614 MVT::MvTimesMatAddMv( one, *Vtmp, HPtmp, zero, *Ctmp );
1615
1616 // Finally, compute U = U*R^{-1}.
1617 // This unfortuntely requires me to form R^{-1} explicitly and execute U = U * R^{-1}, as
1618 // backsolve capabilities don't exist in the Belos::MultiVec class
1619
1620 // Step #1: First, compute LU factorization of R
1621 ipiv_.resize(Rtmp.numRows());
1622 lapack.GETRF(Rtmp.numRows(),Rtmp.numCols(),Rtmp.values(),Rtmp.stride(),&ipiv_[0],&info);
1624 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve: "
1625 "LAPACK's _GETRF failed to compute an LU factorization.");
1626
1627 // FIXME (mfh 17 Apr 2014) We have to compute the explicit
1628 // inverse of R here because Belos::MultiVecTraits doesn't
1629 // have a triangular solve (where the triangular matrix is
1630 // globally replicated and the "right-hand side" is the
1631 // distributed MultiVector).
1632
1633 // Step #2: Form inv(R)
1634 lwork = Rtmp.numRows();
1635 work_.resize(lwork);
1636 lapack.GETRI(Rtmp.numRows(),Rtmp.values(),Rtmp.stride(),&ipiv_[0],&work_[0],lwork,&info);
1638 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve: "
1639 "LAPACK's _GETRI failed to invert triangular matrix.");
1640
1641 // Step #3: Let U = U * R^{-1}
1642 MVT::MvTimesMatAddMv( one, *U1tmp, Rtmp, zero, *Utmp );
1643
1644 printer_->stream(Debug)
1645 << " Generated recycled subspace using RHS index " << currIdx[0]
1646 << " of dimension " << keff << std::endl << std::endl;
1647
1648 } // if (recycledBlocks_ < p+1)
1649
1650 // Return to outer loop if the priming solve converged, set the next linear system.
1651 if (primeConverged) {
1652 // Inform the linear problem that we are finished with this block linear system.
1653 problem_->setCurrLS();
1654
1655 // Update indices for the linear systems to be solved.
1656 numRHS2Solve -= 1;
1657 if (numRHS2Solve > 0) {
1658 currIdx[0]++;
1659 problem_->setLSIndex (currIdx); // Set the next indices
1660 }
1661 else {
1662 currIdx.resize (numRHS2Solve);
1663 }
1664
1665 continue;
1666 }
1667 } // if (keff > 0) ...
1668
1669 // Prepare for the Gmres iterations with the recycled subspace.
1670
1671 // Set the current number of recycled blocks and subspace dimension with the GCRO-DR iteration.
1672 gcrodr_iter->setSize( keff, numBlocks_ );
1673
1674 // Reset the number of iterations.
1675 gcrodr_iter->resetNumIters(prime_iterations);
1676
1677 // Reset the number of calls that the status test output knows about.
1678 outputTest_->resetNumCalls();
1679
1680 // Compute the residual after the priming solve, it will be the first block in the current Krylov basis.
1681 problem_->computeCurrPrecResVec( &*r_ );
1682 index.resize( 1 ); index[0] = 0;
1683 RCP<MV> v0 = MVT::CloneViewNonConst( *V_, index );
1684 MVT::SetBlock(*r_,index,*v0); // V(:,0) = r
1685
1686 // Set the new state and initialize the solver.
1688 index.resize( numBlocks_+1 );
1689 for (int ii=0; ii<(numBlocks_+1); ++ii) { index[ii] = ii; }
1690 newstate.V = MVT::CloneViewNonConst( *V_, index );
1691 index.resize( keff );
1692 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1693 newstate.C = MVT::CloneViewNonConst( *C_, index );
1694 newstate.U = MVT::CloneViewNonConst( *U_, index );
1695 newstate.B = rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>( Teuchos::View, *H2_, keff, numBlocks_, 0, keff ) );
1696 newstate.H = rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>( Teuchos::View, *H2_, numBlocks_+1, numBlocks_, keff, keff ) );
1697 newstate.curDim = 0;
1698 gcrodr_iter->initialize(newstate);
1699
1700 // variables needed for inner loop
1701 int numRestarts = 0;
1702 while(1) {
1703
1704 // tell gcrodr_iter to iterate
1705 try {
1706 gcrodr_iter->iterate();
1707
1709 //
1710 // check convergence first
1711 //
1713 if ( convTest_->getStatus() == Passed ) {
1714 // we have convergence
1715 break; // break from while(1){gcrodr_iter->iterate()}
1716 }
1718 //
1719 // check for maximum iterations
1720 //
1722 else if ( maxIterTest_->getStatus() == Passed ) {
1723 // we don't have convergence
1725 isConverged = false;
1726 break; // break from while(1){gcrodr_iter->iterate()}
1727 }
1729 //
1730 // check for restarting, i.e. the subspace is full
1731 //
1733 else if ( gcrodr_iter->getCurSubspaceDim() == gcrodr_iter->getMaxSubspaceDim() ) {
1734
1735 // Update the recycled subspace even if we have hit the maximum number of restarts.
1736
1737 // Update the linear problem.
1738 RCP<MV> update = gcrodr_iter->getCurrentUpdate();
1739 problem_->updateSolution( update, true );
1740
1741 buildRecycleSpace2(gcrodr_iter);
1742
1743 printer_->stream(Debug)
1744 << " Generated new recycled subspace using RHS index "
1745 << currIdx[0] << " of dimension " << keff << std::endl
1746 << std::endl;
1747
1748 // NOTE: If we have hit the maximum number of restarts then quit
1749 if (numRestarts >= maxRestarts_) {
1751 isConverged = false;
1752 break; // break from while(1){gcrodr_iter->iterate()}
1753 }
1754 numRestarts++;
1755
1756 printer_->stream(Debug)
1757 << " Performing restart number " << numRestarts << " of "
1758 << maxRestarts_ << std::endl << std::endl;
1759
1760 // Create the restart vector (first block in the current Krylov basis)
1761 problem_->computeCurrPrecResVec( &*r_ );
1762 index.resize( 1 ); index[0] = 0;
1763 RCP<MV> v00 = MVT::CloneViewNonConst( *V_, index );
1764 MVT::SetBlock(*r_,index,*v00); // V(:,0) = r
1765
1766 // Set the new state and initialize the solver.
1768 index.resize( numBlocks_+1 );
1769 for (int ii=0; ii<(numBlocks_+1); ++ii) { index[ii] = ii; }
1770 restartState.V = MVT::CloneViewNonConst( *V_, index );
1771 index.resize( keff );
1772 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1773 restartState.U = MVT::CloneViewNonConst( *U_, index );
1774 restartState.C = MVT::CloneViewNonConst( *C_, index );
1775 restartState.B = rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>( Teuchos::View, *H2_, keff, numBlocks_, 0, keff ) );
1776 restartState.H = rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>( Teuchos::View, *H2_, numBlocks_+1, numBlocks_, keff, keff ) );
1777 restartState.curDim = 0;
1778 gcrodr_iter->initialize(restartState);
1779
1780
1781 } // end of restarting
1782
1784 //
1785 // we returned from iterate(), but none of our status tests Passed.
1786 // something is wrong, and it is probably our fault.
1787 //
1789
1790 else {
1793 std::logic_error, "Belos::GCRODRSolMgr::solve: "
1794 "Invalid return from GCRODRIter::iterate().");
1795 }
1796 }
1797 catch (const GCRODRIterOrthoFailure &e) {
1798 // Try to recover the most recent least-squares solution
1799 gcrodr_iter->updateLSQR( gcrodr_iter->getCurSubspaceDim() );
1800
1801 // Check to see if the most recent least-squares solution yielded convergence.
1802 sTest_->checkStatus( &*gcrodr_iter );
1803 if (convTest_->getStatus() != Passed) {
1805 isConverged = false;
1806 }
1807 break;
1808 }
1809 catch (const std::exception& e) {
1811 printer_->stream(Errors)
1812 << "Error! Caught exception in GCRODRIter::iterate() at iteration "
1813 << gcrodr_iter->getNumIters() << std::endl << e.what() << std::endl;
1814 throw;
1815 }
1816 }
1817
1818 // Compute the current solution.
1819 // Update the linear problem.
1820 RCP<MV> update = gcrodr_iter->getCurrentUpdate();
1821 problem_->updateSolution( update, true );
1822
1823 // Inform the linear problem that we are finished with this block linear system.
1824 problem_->setCurrLS();
1825
1826 // If we didn't build a recycle space this solve but ran at least k iterations,
1827 // force build of new recycle space
1828
1829 if (!builtRecycleSpace_) {
1830 buildRecycleSpace2(gcrodr_iter);
1831 printer_->stream(Debug)
1832 << " Generated new recycled subspace using RHS index " << currIdx[0]
1833 << " of dimension " << keff << std::endl << std::endl;
1834 }
1835
1836 // Update indices for the linear systems to be solved.
1837 numRHS2Solve -= 1;
1838 if (numRHS2Solve > 0) {
1839 currIdx[0]++;
1840 problem_->setLSIndex (currIdx); // Set the next indices
1841 }
1842 else {
1843 currIdx.resize (numRHS2Solve);
1844 }
1845 } // while (numRHS2Solve > 0)
1846 }
1847
1848 sTest_->print (printer_->stream (FinalSummary)); // print final summary
1849
1850 // print timing information
1851#ifdef BELOS_TEUCHOS_TIME_MONITOR
1852 // Calling summarize() can be expensive, so don't call unless the
1853 // user wants to print out timing details. summarize() will do all
1854 // the work even if it's passed a "black hole" output stream.
1855 if (verbosity_ & TimingDetails)
1856 Teuchos::TimeMonitor::summarize( printer_->stream(TimingDetails) );
1857#endif // BELOS_TEUCHOS_TIME_MONITOR
1858
1859 // get iteration information for this solve
1860 numIters_ = maxIterTest_->getNumIters ();
1861
1862 // Save the convergence test value ("achieved tolerance") for this
1863 // solve. This solver (unlike BlockGmresSolMgr) always has two
1864 // residual norm status tests: an explicit and an implicit test.
1865 // The master convergence test convTest_ is a SEQ combo of the
1866 // implicit resp. explicit tests. If the implicit test never
1867 // passes, then the explicit test won't ever be executed. This
1868 // manifests as expConvTest_->getTestValue()->size() < 1. We deal
1869 // with this case by using the values returned by
1870 // impConvTest_->getTestValue().
1871 {
1872 const std::vector<MagnitudeType>* pTestValues = expConvTest_->getTestValue();
1873 if (pTestValues == NULL || pTestValues->size() < 1) {
1874 pTestValues = impConvTest_->getTestValue();
1875 }
1876 TEUCHOS_TEST_FOR_EXCEPTION(pTestValues == NULL, std::logic_error,
1877 "Belos::GCRODRSolMgr::solve(): The implicit convergence test's getTestValue() "
1878 "method returned NULL. Please report this bug to the Belos developers.");
1879 TEUCHOS_TEST_FOR_EXCEPTION(pTestValues->size() < 1, std::logic_error,
1880 "Belos::GCRODRSolMgr::solve(): The implicit convergence test's getTestValue() "
1881 "method returned a vector of length zero. Please report this bug to the "
1882 "Belos developers.");
1883
1884 // FIXME (mfh 12 Dec 2011) Does pTestValues really contain the
1885 // achieved tolerances for all vectors in the current solve(), or
1886 // just for the vectors from the last deflation?
1887 achievedTol_ = *std::max_element (pTestValues->begin(), pTestValues->end());
1888 }
1889
1890 if (!isConverged) {
1891 return retType; // return from solve()
1892 }
1893 return Converged; // return from solve()
1894}
1895
1896// Given existing recycle space and Krylov space, build new recycle space
1897template<class ScalarType, class MV, class OP>
1899
1900 MagnitudeType one = Teuchos::ScalarTraits<MagnitudeType>::one();
1901 ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
1902
1903 std::vector<MagnitudeType> d(keff);
1904 std::vector<ScalarType> dscalar(keff);
1905 std::vector<int> index(numBlocks_+1);
1906
1907 // Get the state
1909 int p = oldState.curDim;
1910
1911 // insufficient new information to update recycle space
1912 if (p<1) return;
1913
1914 // Take the norm of the recycled vectors
1915 {
1916 index.resize(keff);
1917 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1918 Teuchos::RCP<MV> Utmp = MVT::CloneViewNonConst( *U_, index );
1919 d.resize(keff);
1920 dscalar.resize(keff);
1921 MVT::MvNorm( *Utmp, d );
1922 for (int i=0; i<keff; ++i) {
1923 d[i] = one / d[i];
1924 dscalar[i] = (ScalarType)d[i];
1925 }
1926 MVT::MvScale( *Utmp, dscalar );
1927 }
1928
1929 // Get view into current "full" upper Hessnburg matrix
1930 Teuchos::RCP<Teuchos::SerialDenseMatrix<int,ScalarType> > H2tmp = Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>( Teuchos::View, *H2_, p+keff+1, p+keff ) );
1931
1932 // Insert D into the leading keff x keff block of H2
1933 for (int i=0; i<keff; ++i) {
1934 (*H2tmp)(i,i) = d[i];
1935 }
1936
1937 // Compute the harmoic Ritz pairs for the generalized eigenproblem
1938 // getHarmonicVecs2 assumes PP has recycledBlocks_+1 columns available
1939 int keff_new;
1940 {
1941 Teuchos::SerialDenseMatrix<int,ScalarType> PPtmp( Teuchos::View, *PP_, p+keff, recycledBlocks_+1 );
1942 keff_new = getHarmonicVecs2( keff, p, *H2tmp, oldState.V, PPtmp );
1943 }
1944
1945 // Code to form new U, C
1946 // U = [U V(:,1:p)] * P; (in two steps)
1947
1948 // U(:,1:keff) = matmul(U(:,1:keff_old),PP(1:keff_old,1:keff)) (step 1)
1949 Teuchos::RCP<MV> U1tmp;
1950 {
1951 index.resize( keff );
1952 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1953 Teuchos::RCP<const MV> Utmp = MVT::CloneView( *U_, index );
1954 index.resize( keff_new );
1955 for (int ii=0; ii<keff_new; ++ii) { index[ii] = ii; }
1956 U1tmp = MVT::CloneViewNonConst( *U1_, index );
1957 Teuchos::SerialDenseMatrix<int,ScalarType> PPtmp( Teuchos::View, *PP_, keff, keff_new );
1958 MVT::MvTimesMatAddMv( one, *Utmp, PPtmp, zero, *U1tmp );
1959 }
1960
1961 // U(:,1:keff) = U(:,1:keff) + matmul(V(:,1:m-k),PP(keff_old+1:m-k+keff_old,1:keff)) (step 2)
1962 {
1963 index.resize(p);
1964 for (int ii=0; ii < p; ii++) { index[ii] = ii; }
1965 Teuchos::RCP<const MV> Vtmp = MVT::CloneView( *V_, index );
1966 Teuchos::SerialDenseMatrix<int,ScalarType> PPtmp( Teuchos::View, *PP_, p, keff_new, keff );
1967 MVT::MvTimesMatAddMv( one, *Vtmp, PPtmp, one, *U1tmp );
1968 }
1969
1970 // Form HP = H*P
1971 Teuchos::SerialDenseMatrix<int,ScalarType> HPtmp( Teuchos::View, *HP_, p+keff+1, keff_new );
1972 {
1973 Teuchos::SerialDenseMatrix<int,ScalarType> PPtmp( Teuchos::View, *PP_, p+keff, keff_new );
1974 HPtmp.multiply(Teuchos::NO_TRANS,Teuchos::NO_TRANS,one,*H2tmp,PPtmp,zero);
1975 }
1976
1977 // Workspace size query for QR factorization of HP (the worksize will be placed in work_[0])
1978 int info = 0, lwork = -1;
1979 tau_.resize (keff_new);
1980 lapack.GEQRF (HPtmp.numRows (), HPtmp.numCols (), HPtmp.values (),
1981 HPtmp.stride (), &tau_[0], &work_[0], lwork, &info);
1983 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve: "
1984 "LAPACK's _GEQRF failed to compute a workspace size.");
1985
1986 // NOTE (mfh 18 Apr 2014) LAPACK promises that the value of work_[0]
1987 // after the workspace query will fit in int. This justifies the
1988 // cast. We call real() first because static_cast from std::complex
1989 // to int doesn't work.
1990 lwork = std::abs (static_cast<int> (Teuchos::ScalarTraits<ScalarType>::real (work_[0])));
1991 work_.resize (lwork); // Allocate workspace for the QR factorization
1992 lapack.GEQRF (HPtmp.numRows (), HPtmp.numCols (), HPtmp.values (),
1993 HPtmp.stride (), &tau_[0], &work_[0], lwork, &info);
1995 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve: "
1996 "LAPACK's _GEQRF failed to compute a QR factorization.");
1997
1998 // Explicitly construct Q and R factors
1999 // NOTE: The upper triangular part of HP is copied into R and HP becomes Q.
2000 Teuchos::SerialDenseMatrix<int,ScalarType> Rtmp( Teuchos::View, *R_, keff_new, keff_new );
2001 for(int i=0;i<keff_new;i++) { for(int j=i;j<keff_new;j++) Rtmp(i,j) = HPtmp(i,j); }
2002
2003 // NOTE (mfh 18 Apr 2014): Teuchos::LAPACK's wrapper for UNGQR
2004 // dispatches to the correct Scalar-specific routine. It calls
2005 // {S,D}ORGQR if Scalar is real, and {C,Z}UNGQR if Scalar is
2006 // complex.
2007 lapack.UNGQR (HPtmp.numRows (), HPtmp.numCols (), HPtmp.numCols (),
2008 HPtmp.values (), HPtmp.stride (), &tau_[0], &work_[0],
2009 lwork, &info);
2011 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve: "
2012 "LAPACK's _UNGQR failed to construct the Q factor.");
2013
2014 // Form orthonormalized C and adjust U accordingly so that C = A*U
2015 // C = [C V] * Q;
2016
2017 // C(:,1:keff) = matmul(C(:,1:keff_old),QQ(1:keff_old,1:keff))
2018 {
2019 Teuchos::RCP<MV> C1tmp;
2020 {
2021 index.resize(keff);
2022 for (int i=0; i < keff; i++) { index[i] = i; }
2023 Teuchos::RCP<const MV> Ctmp = MVT::CloneView( *C_, index );
2024 index.resize(keff_new);
2025 for (int i=0; i < keff_new; i++) { index[i] = i; }
2026 C1tmp = MVT::CloneViewNonConst( *C1_, index );
2027 Teuchos::SerialDenseMatrix<int,ScalarType> PPtmp( Teuchos::View, *HP_, keff, keff_new );
2028 MVT::MvTimesMatAddMv( one, *Ctmp, PPtmp, zero, *C1tmp );
2029 }
2030 // Now compute C += V(:,1:p+1) * Q
2031 {
2032 index.resize( p+1 );
2033 for (int i=0; i < p+1; ++i) { index[i] = i; }
2034 Teuchos::RCP<const MV> Vtmp = MVT::CloneView( *V_, index );
2035 Teuchos::SerialDenseMatrix<int,ScalarType> PPtmp( Teuchos::View, *HP_, p+1, keff_new, keff, 0 );
2036 MVT::MvTimesMatAddMv( one, *Vtmp, PPtmp, one, *C1tmp );
2037 }
2038 }
2039
2040 // C_ = C1_; (via a swap)
2041 std::swap(C_, C1_);
2042
2043 // Finally, compute U_ = U_*R^{-1}
2044 // First, compute LU factorization of R
2045 ipiv_.resize(Rtmp.numRows());
2046 lapack.GETRF(Rtmp.numRows(),Rtmp.numCols(),Rtmp.values(),Rtmp.stride(),&ipiv_[0],&info);
2047 TEUCHOS_TEST_FOR_EXCEPTION(info != 0,GCRODRSolMgrLAPACKFailure,"Belos::GCRODRSolMgr::solve(): LAPACK _GETRF failed to compute an LU factorization.");
2048
2049 // Now, form inv(R)
2050 lwork = Rtmp.numRows();
2051 work_.resize(lwork);
2052 lapack.GETRI(Rtmp.numRows(),Rtmp.values(),Rtmp.stride(),&ipiv_[0],&work_[0],lwork,&info);
2053 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, GCRODRSolMgrLAPACKFailure,"Belos::GCRODRSolMgr::solve(): LAPACK _GETRI failed to compute an LU factorization.");
2054
2055 {
2056 index.resize(keff_new);
2057 for (int i=0; i < keff_new; i++) { index[i] = i; }
2058 Teuchos::RCP<MV> Utmp = MVT::CloneViewNonConst( *U_, index );
2059 MVT::MvTimesMatAddMv( one, *U1tmp, Rtmp, zero, *Utmp );
2060 }
2061
2062 // Set the current number of recycled blocks and subspace dimension with the GCRO-DR iteration.
2063 if (keff != keff_new) {
2064 keff = keff_new;
2065 gcrodr_iter->setSize( keff, numBlocks_ );
2066 // Important to zero this out before next cyle
2067 Teuchos::SerialDenseMatrix<int,ScalarType> b1( Teuchos::View, *H2_, recycledBlocks_+2, 1, 0, recycledBlocks_ );
2068 b1.putScalar(zero);
2069 }
2070
2071}
2072
2073
2074// Compute the harmonic eigenpairs of the projected, dense system.
2075template<class ScalarType, class MV, class OP>
2076int GCRODRSolMgr<ScalarType,MV,OP,true>::getHarmonicVecs1(int m,
2077 const Teuchos::SerialDenseMatrix<int,ScalarType>& HH,
2078 Teuchos::SerialDenseMatrix<int,ScalarType>& PP) {
2079 int i, j;
2080 bool xtraVec = false;
2081 ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
2082
2083 // Real and imaginary eigenvalue components
2084 std::vector<MagnitudeType> wr(m), wi(m);
2085
2086 // Real and imaginary (right) eigenvectors; Don't zero out matrix when constructing
2087 Teuchos::SerialDenseMatrix<int,ScalarType> vr(m,m,false);
2088
2089 // Magnitude of harmonic Ritz values
2090 std::vector<MagnitudeType> w(m);
2091
2092 // Sorted order of harmonic Ritz values, also used for GEEV
2093 std::vector<int> iperm(m);
2094
2095 // Output info
2096 int info = 0;
2097
2098 // Set flag indicating recycle space has been generated this solve
2099 builtRecycleSpace_ = true;
2100
2101 // Solve linear system: H_m^{-H}*e_m
2102 Teuchos::SerialDenseMatrix<int, ScalarType> HHt( HH, Teuchos::TRANS );
2103 Teuchos::SerialDenseVector<int, ScalarType> e_m( m );
2104 e_m[m-1] = one;
2105 lapack.GESV(m, 1, HHt.values(), HHt.stride(), &iperm[0], e_m.values(), e_m.stride(), &info);
2106 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve(): LAPACK GESV failed to compute a solution.");
2107
2108 // Compute H_m + d*H_m^{-H}*e_m*e_m^H
2109 ScalarType d = HH(m, m-1) * HH(m, m-1);
2110 Teuchos::SerialDenseMatrix<int, ScalarType> harmHH( Teuchos::Copy, HH, m, m );
2111 for( i=0; i<m; ++i )
2112 harmHH(i, m-1) += d * e_m[i];
2113
2114 // Revise to do query for optimal workspace first
2115 // Create simple storage for the left eigenvectors, which we don't care about.
2116 const int ldvl = 1;
2117 ScalarType* vl = 0;
2118
2119 // Size of workspace and workspace for GEEV
2120 int lwork = -1;
2121 std::vector<ScalarType> work(1);
2122 std::vector<MagnitudeType> rwork(2*m);
2123
2124 // First query GEEV for the optimal workspace size
2125 lapack.GEEV('N', 'V', m, harmHH.values(), harmHH.stride(), &wr[0], &wi[0],
2126 vl, ldvl, vr.values(), vr.stride(), &work[0], lwork, &rwork[0], &info);
2127
2128 lwork = std::abs (static_cast<int> (Teuchos::ScalarTraits<ScalarType>::real (work[0])));
2129 work.resize( lwork );
2130
2131 lapack.GEEV('N', 'V', m, harmHH.values(), harmHH.stride(), &wr[0], &wi[0],
2132 vl, ldvl, vr.values(), vr.stride(), &work[0], lwork, &rwork[0], &info);
2133 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, GCRODRSolMgrLAPACKFailure,"Belos::GCRODRSolMgr::solve(): LAPACK GEEV failed to compute eigensolutions.");
2134
2135 // Construct magnitude of each harmonic Ritz value
2136 for( i=0; i<m; ++i )
2137 w[i] = Teuchos::ScalarTraits<MagnitudeType>::squareroot( wr[i]*wr[i] + wi[i]*wi[i] );
2138
2139 // Construct magnitude of each harmonic Ritz value
2140 this->sort(w, m, iperm);
2141
2142 const bool scalarTypeIsComplex = Teuchos::ScalarTraits<ScalarType>::isComplex;
2143
2144 // Select recycledBlocks_ smallest eigenvectors
2145 for( i=0; i<recycledBlocks_; ++i ) {
2146 for( j=0; j<m; j++ ) {
2147 PP(j,i) = vr(j,iperm[i]);
2148 }
2149 }
2150
2151 if(!scalarTypeIsComplex) {
2152
2153 // Determine exact size for PP (i.e., determine if we need to store an additional vector)
2154 if (wi[iperm[recycledBlocks_-1]] != 0.0) {
2155 int countImag = 0;
2156 for ( i=0; i<recycledBlocks_; ++i ) {
2157 if (wi[iperm[i]] != 0.0)
2158 countImag++;
2159 }
2160 // Check to see if this count is even or odd:
2161 if (countImag % 2)
2162 xtraVec = true;
2163 }
2164
2165 if (xtraVec) { // we need to store one more vector
2166 if (wi[iperm[recycledBlocks_-1]] > 0.0) { // I picked the "real" component
2167 for( j=0; j<m; ++j ) { // so get the "imag" component
2168 PP(j,recycledBlocks_) = vr(j,iperm[recycledBlocks_-1]+1);
2169 }
2170 }
2171 else { // I picked the "imag" component
2172 for( j=0; j<m; ++j ) { // so get the "real" component
2173 PP(j,recycledBlocks_) = vr(j,iperm[recycledBlocks_-1]-1);
2174 }
2175 }
2176 }
2177
2178 }
2179
2180 // Return whether we needed to store an additional vector
2181 if (xtraVec) {
2182 return recycledBlocks_+1;
2183 }
2184 else {
2185 return recycledBlocks_;
2186 }
2187
2188}
2189
2190// Compute the harmonic eigenpairs of the projected, dense system.
2191template<class ScalarType, class MV, class OP>
2192int GCRODRSolMgr<ScalarType,MV,OP,true>::getHarmonicVecs2(int keffloc, int m,
2193 const Teuchos::SerialDenseMatrix<int,ScalarType>& HH,
2194 const Teuchos::RCP<const MV>& VV,
2195 Teuchos::SerialDenseMatrix<int,ScalarType>& PP) {
2196 int i, j;
2197 int m2 = HH.numCols();
2198 bool xtraVec = false;
2199 ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
2200 ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
2201 std::vector<int> index;
2202
2203 // Real and imaginary eigenvalue components
2204 std::vector<MagnitudeType> wr(m2), wi(m2);
2205
2206 // Magnitude of harmonic Ritz values
2207 std::vector<MagnitudeType> w(m2);
2208
2209 // Real and imaginary (right) eigenvectors; Don't zero out matrix when constructing
2210 Teuchos::SerialDenseMatrix<int,ScalarType> vr(m2,m2,false);
2211
2212 // Sorted order of harmonic Ritz values
2213 std::vector<int> iperm(m2);
2214
2215 // Set flag indicating recycle space has been generated this solve
2216 builtRecycleSpace_ = true;
2217
2218 // Form matrices for generalized eigenproblem
2219
2220 // B = H2' * H2; Don't zero out matrix when constructing
2221 Teuchos::SerialDenseMatrix<int,ScalarType> B(m2,m2,false);
2222 B.multiply(Teuchos::TRANS,Teuchos::NO_TRANS,one,HH,HH,zero);
2223
2224 // A_tmp = | C'*U 0 |
2225 // | V_{m+1}'*U I |
2226 Teuchos::SerialDenseMatrix<int,ScalarType> A_tmp( keffloc+m+1, keffloc+m );
2227
2228 // A_tmp(1:keffloc,1:keffloc) = C' * U;
2229 index.resize(keffloc);
2230 for (i=0; i<keffloc; ++i) { index[i] = i; }
2231 Teuchos::RCP<const MV> Ctmp = MVT::CloneView( *C_, index );
2232 Teuchos::RCP<const MV> Utmp = MVT::CloneView( *U_, index );
2233 Teuchos::SerialDenseMatrix<int,ScalarType> A11( Teuchos::View, A_tmp, keffloc, keffloc );
2234 MVT::MvTransMv( one, *Ctmp, *Utmp, A11 );
2235
2236 // A_tmp(keffloc+1:m-k+keffloc+1,1:keffloc) = V' * U;
2237 Teuchos::SerialDenseMatrix<int,ScalarType> A21( Teuchos::View, A_tmp, m+1, keffloc, keffloc );
2238 index.resize(m+1);
2239 for (i=0; i < m+1; i++) { index[i] = i; }
2240 Teuchos::RCP<const MV> Vp = MVT::CloneView( *VV, index );
2241 MVT::MvTransMv( one, *Vp, *Utmp, A21 );
2242
2243 // A_tmp(keffloc+1:m-k+keffloc,keffloc+1:m-k+keffloc) = eye(m-k);
2244 for( i=keffloc; i<keffloc+m; i++ ) {
2245 A_tmp(i,i) = one;
2246 }
2247
2248 // A = H2' * A_tmp;
2249 Teuchos::SerialDenseMatrix<int,ScalarType> A( m2, A_tmp.numCols() );
2250 A.multiply( Teuchos::TRANS, Teuchos::NO_TRANS, one, HH, A_tmp, zero );
2251
2252 // Compute k smallest harmonic Ritz pairs
2253 // SUBROUTINE DGGEVX( BALANC, JOBVL, JOBVR, SENSE, N, A, LDA, B, LDB,
2254 // ALPHAR, ALPHAI, BETA, VL, LDVL, VR, LDVR, ILO,
2255 // IHI, LSCALE, RSCALE, ABNRM, BBNRM, RCONDE,
2256 // RCONDV, WORK, LWORK, IWORK, BWORK, INFO )
2257 // MLP: 'SCALING' in DGGEVX generates incorrect eigenvalues. Therefore, only permuting
2258 char balanc='P', jobvl='N', jobvr='V', sense='N';
2259 int ld = A.numRows();
2260 int lwork = 6*ld;
2261 int ldvl = ld, ldvr = ld;
2262 int info = 0,ilo = 0,ihi = 0;
2263 MagnitudeType abnrm = 0.0, bbnrm = 0.0;
2264 ScalarType *vl = 0; // This is never referenced by dggevx if jobvl == 'N'
2265 std::vector<ScalarType> beta(ld);
2266 std::vector<ScalarType> work(lwork);
2267 std::vector<MagnitudeType> rwork(lwork);
2268 std::vector<MagnitudeType> lscale(ld), rscale(ld);
2269 std::vector<MagnitudeType> rconde(ld), rcondv(ld);
2270 std::vector<int> iwork(ld+6);
2271 int *bwork = 0; // If sense == 'N', bwork is never referenced
2272 //lapack.GGEVX(balanc, jobvl, jobvr, sense, ld, A.values(), ld, B.values(), ld, &wr[0], &wi[0],
2273 // &beta[0], vl, ldvl, vr.values(), ldvr, &ilo, &ihi, &lscale[0], &rscale[0],
2274 // &abnrm, &bbnrm, &rconde[0], &rcondv[0], &work[0], lwork, &iwork[0], bwork, &info);
2275 lapack.GGEVX(balanc, jobvl, jobvr, sense, ld, A.values(), ld, B.values(), ld, &wr[0], &wi[0],
2276 &beta[0], vl, ldvl, vr.values(), ldvr, &ilo, &ihi, &lscale[0], &rscale[0],
2277 &abnrm, &bbnrm, &rconde[0], &rcondv[0], &work[0], lwork, &rwork[0],
2278 &iwork[0], bwork, &info);
2279 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve(): LAPACK GGEVX failed to compute eigensolutions.");
2280
2281 // Construct magnitude of each harmonic Ritz value
2282 // NOTE : Forming alpha/beta *should* be okay here, given assumptions on construction of matrix pencil above
2283 for( i=0; i<ld; i++ ) {
2284 w[i] = Teuchos::ScalarTraits<MagnitudeType>::squareroot (wr[i]*wr[i] + wi[i]*wi[i]) /
2285 Teuchos::ScalarTraits<ScalarType>::magnitude (beta[i]);
2286 }
2287
2288 // Construct magnitude of each harmonic Ritz value
2289 this->sort(w,ld,iperm);
2290
2291 const bool scalarTypeIsComplex = Teuchos::ScalarTraits<ScalarType>::isComplex;
2292
2293 // Select recycledBlocks_ smallest eigenvectors
2294 for( i=0; i<recycledBlocks_; i++ ) {
2295 for( j=0; j<ld; j++ ) {
2296 PP(j,i) = vr(j,iperm[ld-recycledBlocks_+i]);
2297 }
2298 }
2299
2300 if(!scalarTypeIsComplex) {
2301
2302 // Determine exact size for PP (i.e., determine if we need to store an additional vector)
2303 if (wi[iperm[ld-recycledBlocks_]] != 0.0) {
2304 int countImag = 0;
2305 for ( i=ld-recycledBlocks_; i<ld; i++ ) {
2306 if (wi[iperm[i]] != 0.0)
2307 countImag++;
2308 }
2309 // Check to see if this count is even or odd:
2310 if (countImag % 2)
2311 xtraVec = true;
2312 }
2313
2314 if (xtraVec) { // we need to store one more vector
2315 if (wi[iperm[ld-recycledBlocks_]] > 0.0) { // I picked the "real" component
2316 for( j=0; j<ld; j++ ) { // so get the "imag" component
2317 PP(j,recycledBlocks_) = vr(j,iperm[ld-recycledBlocks_]+1);
2318 }
2319 }
2320 else { // I picked the "imag" component
2321 for( j=0; j<ld; j++ ) { // so get the "real" component
2322 PP(j,recycledBlocks_) = vr(j,iperm[ld-recycledBlocks_]-1);
2323 }
2324 }
2325 }
2326
2327 }
2328
2329 // Return whether we needed to store an additional vector
2330 if (xtraVec) {
2331 return recycledBlocks_+1;
2332 }
2333 else {
2334 return recycledBlocks_;
2335 }
2336
2337}
2338
2339
2340// This method sorts list of n floating-point numbers and return permutation vector
2341template<class ScalarType, class MV, class OP>
2342void GCRODRSolMgr<ScalarType,MV,OP,true>::sort(std::vector<MagnitudeType>& dlist, int n, std::vector<int>& iperm) {
2343 int l, r, j, i, flag;
2344 int RR2;
2345 MagnitudeType dRR, dK;
2346
2347 // Initialize the permutation vector.
2348 for(j=0;j<n;j++)
2349 iperm[j] = j;
2350
2351 if (n <= 1) return;
2352
2353 l = n / 2 + 1;
2354 r = n - 1;
2355 l = l - 1;
2356 dRR = dlist[l - 1];
2357 dK = dlist[l - 1];
2358
2359 RR2 = iperm[l - 1];
2360 while (r != 0) {
2361 j = l;
2362 flag = 1;
2363
2364 while (flag == 1) {
2365 i = j;
2366 j = j + j;
2367
2368 if (j > r + 1)
2369 flag = 0;
2370 else {
2371 if (j < r + 1)
2372 if (dlist[j] > dlist[j - 1]) j = j + 1;
2373
2374 if (dlist[j - 1] > dK) {
2375 dlist[i - 1] = dlist[j - 1];
2376 iperm[i - 1] = iperm[j - 1];
2377 }
2378 else {
2379 flag = 0;
2380 }
2381 }
2382 }
2383 dlist[i - 1] = dRR;
2384 iperm[i - 1] = RR2;
2385
2386 if (l == 1) {
2387 dRR = dlist [r];
2388 RR2 = iperm[r];
2389 dK = dlist[r];
2390 dlist[r] = dlist[0];
2391 iperm[r] = iperm[0];
2392 r = r - 1;
2393 }
2394 else {
2395 l = l - 1;
2396 dRR = dlist[l - 1];
2397 RR2 = iperm[l - 1];
2398 dK = dlist[l - 1];
2399 }
2400 }
2401 dlist[0] = dRR;
2402 iperm[0] = RR2;
2403}
2404
2405
2406template<class ScalarType, class MV, class OP>
2408 std::ostringstream out;
2409 out << "Belos::GCRODRSolMgr<...,"<<Teuchos::ScalarTraits<ScalarType>::name()<<">";
2410 out << "{";
2411 out << "Ortho Type: \"" << orthoType_ << "\"";
2412 out << ", Num Blocks: " <<numBlocks_;
2413 out << ", Num Recycle Blocks: " << recycledBlocks_;
2414 out << ", Max Restarts: " << maxRestarts_;
2415 out << "}";
2416 return out.str ();
2417}
2418
2419} // namespace Belos
2420
2421#endif /* BELOS_GCRODR_SOLMGR_HPP */
Belos concrete class for performing the block, flexible GMRES iteration.
Belos header file which uses auto-configuration information to include necessary C++ headers.
Belos concrete class for performing the GCRO-DR iteration.
Class which describes the linear problem to be solved by the iterative solver.
Class which manages the output and verbosity of the Belos solvers.
Pure virtual base class which describes the basic interface for a solver manager.
Belos::StatusTest for logically combining several status tests.
Belos::StatusTestResNorm for specifying general residual norm stopping criteria.
Belos::StatusTest class for specifying a maximum number of iterations.
A factory class for generating StatusTestOutput objects.
Collection of types and exceptions used within the Belos solvers.
Parent class to all Belos exceptions.
Type traits class that says whether Teuchos::LAPACK has a valid implementation for the given ScalarTy...
Base class for Belos::SolverManager subclasses which normally can only compile with ScalarType types ...
GCRODRIterOrthoFailure is thrown when the GCRODRIter object is unable to compute independent directio...
const LinearProblem< ScalarType, MV, OP > & getProblem() const override
Get current linear problem being solved for in this object.
void reset(const ResetType type) override
Performs a reset of the solver manager specified by the ResetType. This informs the solver manager th...
Teuchos::RCP< SolverManager< ScalarType, MV, OP > > clone() const override
clone for Inverted Injection (DII)
Teuchos::Array< Teuchos::RCP< Teuchos::Time > > getTimers() const
Return the timers for this object.
int getNumIters() const override
Get the iteration count for the most recent call to solve().
void setProblem(const Teuchos::RCP< LinearProblem< ScalarType, MV, OP > > &problem) override
Set the linear problem that needs to be solved.
Teuchos::RCP< const Teuchos::ParameterList > getCurrentParameters() const override
Get a parameter list containing the current parameters for this object.
MagnitudeType achievedTol() const override
Tolerance achieved by the last solve() invocation.
bool isLOADetected() const override
Return whether a loss of accuracy was detected by this solver during the most current solve.
Implementation of the GCRODR (Recycling GMRES) iterative linear solver.
GCRODRSolMgr(const Teuchos::RCP< LinearProblem< ScalarType, MV, OP > > &problem, const Teuchos::RCP< Teuchos::ParameterList > &pl)
GCRODRSolMgrLAPACKFailure is thrown when a nonzero value is retuned from an LAPACK call.
GCRODRSolMgrLAPACKFailure(const std::string &what_arg)
GCRODRSolMgrLinearProblemFailure is thrown when the linear problem is not setup (i....
GCRODRSolMgrLinearProblemFailure(const std::string &what_arg)
GCRODRSolMgrOrthoFailure is thrown when the orthogonalization manager is unable to generate orthonorm...
GCRODRSolMgrOrthoFailure(const std::string &what_arg)
GCRODRSolMgrRecyclingFailure is thrown when any problem occurs in using/creating the recycling subspa...
GCRODRSolMgrRecyclingFailure(const std::string &what_arg)
Alternative run-time polymorphic interface for operators.
Operator()
Default constructor (does nothing).
Exception thrown to signal error in a status test during Belos::StatusTest::checkStatus().
ScaleType convertStringToScaleType(const std::string &scaleType)
Convert the given string to its ScaleType enum value.
@ StatusTestDetails
@ FinalSummary
@ TimingDetails
ReturnType
Whether the Belos solve converged for all linear systems.
@ NaNDetected
@ MaxItersReached
@ NonspecificException
@ MaxRestartsReached
@ InconsistentState
@ OrthonormFailure
@ Undetermined
ScaleType
The type of scaling to use on the residual norm value.
ResetType
How to reset the solver.
@ RecycleSubspace
static const double convTol
Default convergence tolerance.

Generated for Belos by doxygen 1.9.8