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"
24#include "BelosFGCRODRIter.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, class DM = DefaultDenseMatrix<int,ScalarType>,
131 const bool lapackSupportsScalarType =
132 Belos::Details::LapackSupportsScalar<ScalarType>::value>
134 public Details::SolverManagerRequiresLapack<ScalarType,MV,OP,DM>
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, class DM>
156 class GCRODRSolMgr<ScalarType, MV, OP, DM, true> :
157 public Details::SolverManagerRequiresLapack<ScalarType, MV, OP, DM, 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:
202 typedef Teuchos::ScalarTraits<ScalarType> SCT;
203 typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MagnitudeType;
204 typedef Teuchos::ScalarTraits<MagnitudeType> MT;
206
207 public:
209
210
216 GCRODRSolMgr();
217
271 const Teuchos::RCP<Teuchos::ParameterList> &pl);
272
274 virtual ~GCRODRSolMgr() {};
275
277 Teuchos::RCP<SolverManager<ScalarType, MV, OP, DM> > clone () const override {
278 return Teuchos::rcp(new GCRODRSolMgr<ScalarType,MV,OP,DM,true>);
279 }
281
283
284
288 return *problem_;
289 }
290
293 Teuchos::RCP<const Teuchos::ParameterList> getValidParameters() const override;
294
297 Teuchos::RCP<const Teuchos::ParameterList> getCurrentParameters() const override {
298 return params_;
299 }
300
306 Teuchos::Array<Teuchos::RCP<Teuchos::Time> > getTimers() const {
307 return Teuchos::tuple(timerSolve_);
308 }
309
315 MagnitudeType achievedTol() const override {
316 return achievedTol_;
317 }
318
320 int getNumIters() const override {
321 return numIters_;
322 }
323
326 bool isLOADetected() const override { return false; }
327
329
331
332
334 void setProblem( const Teuchos::RCP<LinearProblem<ScalarType,MV,OP,DM> > &problem ) override {
335 problem_ = problem;
336 }
337
339 void setParameters( const Teuchos::RCP<Teuchos::ParameterList> &params ) override;
340
342
344
345
349 void reset( const ResetType type ) override {
350 if ((type & Belos::Problem) && !Teuchos::is_null(problem_)) {
351 bool set = problem_->setProblem();
352 if (!set)
353 throw "Could not set problem.";
354 }
355 else if (type & Belos::RecycleSubspace) {
356 keff = 0;
357 }
358 }
360
362
363
390 ReturnType solve() override;
391
393
395
397 std::string description() const override;
398
400
401 private:
402
403 // Called by all constructors; Contains init instructions common to all constructors
404 void init();
405
406 // Initialize solver state storage
407 void initializeStateStorage();
408
409 // Compute updated recycle space given existing recycle space and newly generated Krylov space
410 void buildRecycleSpace2(Teuchos::RCP<GCRODRIteration<ScalarType,MV,OP,DM> > gcrodr_iter);
411
412 void buildFlexibleRecycleSpace2(Teuchos::RCP<GCRODRIteration<ScalarType,MV,OP,DM> > gcrodr_iter);
413
414 void computeGCRODRResidual();
415
416 void updateSolutionWithUpdate(const Teuchos::RCP<MV>& update);
417
418 // Computes harmonic eigenpairs of projected matrix created during the priming solve.
419 // HH is the projected problem from the initial cycle of Gmres, it is (at least) of dimension m+1 x m.
420 // PP contains the harmonic eigenvectors corresponding to the recycledBlocks eigenvalues of smallest magnitude.
421 // The return value is the number of vectors needed to be stored, recycledBlocks or recycledBlocks+1.
422 int getHarmonicVecs1(int m, const DM& HH, DM& PP);
423
424 // Computes harmonic eigenpairs of projected matrix created during one cycle.
425 // HH is the total block projected problem from the GCRO-DR algorithm, it is (at least) of dimension keff+m+1 x keff+m.
426 // VV is the Krylov vectors from the projected GMRES algorithm, which has (at least) m+1 vectors.
427 // PP contains the harmonic eigenvectors corresponding to the recycledBlocks eigenvalues of smallest magnitude.
428 // The return value is the number of vectors needed to be stored, recycledBlocks or recycledBlocks+1.
429 int getHarmonicVecs2(int keff, int m, const DM& HH,
430 const Teuchos::RCP<const MV>& VV, DM& PP);
431
432 int getFlexibleHarmonicVecs2(int keff, int m, const DM& HH,
433 const Teuchos::RCP<const MV>& VV, DM& PP);
434
435 // Sort list of n floating-point numbers and return permutation vector
436 void sort(std::vector<MagnitudeType>& dlist, int n, std::vector<int>& iperm);
437
438 // Lapack interface
439 Teuchos::LAPACK<int,ScalarType> lapack;
440
441 // Linear problem.
442 Teuchos::RCP<LinearProblem<ScalarType,MV,OP,DM> > problem_;
443
444 // Output manager.
445 Teuchos::RCP<OutputManager<ScalarType> > printer_;
446 Teuchos::RCP<std::ostream> outputStream_;
447
448 // Status test.
449 Teuchos::RCP<StatusTest<ScalarType,MV,OP,DM> > sTest_;
450 Teuchos::RCP<StatusTestMaxIters<ScalarType,MV,OP,DM> > maxIterTest_;
451 Teuchos::RCP<StatusTest<ScalarType,MV,OP,DM> > convTest_;
452 Teuchos::RCP<StatusTestGenResNorm<ScalarType,MV,OP,DM> > expConvTest_, impConvTest_;
453 Teuchos::RCP<StatusTestOutput<ScalarType,MV,OP,DM> > outputTest_;
454
458 Teuchos::RCP<MatOrthoManager<ScalarType,MV,OP,DM> > ortho_;
459
460 // Current parameter list.
461 Teuchos::RCP<Teuchos::ParameterList> params_;
462
463 // Default solver values.
464 static constexpr double orthoKappa_default_ = 0.0;
465 static constexpr int maxRestarts_default_ = 100;
466 static constexpr int maxIters_default_ = 1000;
467 static constexpr int numBlocks_default_ = 50;
468 static constexpr int blockSize_default_ = 1;
469 static constexpr int recycledBlocks_default_ = 5;
470 static constexpr bool flexibleGCRODR_default_ = false;
471 static constexpr int verbosity_default_ = Belos::Errors;
472 static constexpr int outputStyle_default_ = Belos::General;
473 static constexpr int outputFreq_default_ = -1;
474 static constexpr const char * impResScale_default_ = "Norm of Preconditioned Initial Residual";
475 static constexpr const char * expResScale_default_ = "Norm of Initial Residual";
476 static constexpr const char * label_default_ = "Belos";
477 static constexpr const char * orthoType_default_ = "ICGS";
478
479 // Current solver values.
480 MagnitudeType convTol_, orthoKappa_, achievedTol_;
481 int maxRestarts_, maxIters_, numIters_;
482 int verbosity_, outputStyle_, outputFreq_;
483 bool isFlexible_;
484 std::string orthoType_;
485 std::string impResScale_, expResScale_;
486
488 // Solver State Storage
490 //
491 // The number of blocks and recycle blocks (m and k, respectively)
492 int numBlocks_, recycledBlocks_;
493 // Current size of recycled subspace
494 int keff;
495 //
496 // Residual vector
497 Teuchos::RCP<MV> r_;
498 //
499 // Search space
500 Teuchos::RCP<MV> V_;
501 // Flexible correction basis for current cycle.
502 Teuchos::RCP<MV> Z_;
503 //
504 // Recycled subspace and its image
505 Teuchos::RCP<MV> U_, C_;
506 // Auxiliary W recycle basis used by the FGCRODR harmonic projection.
507 Teuchos::RCP<MV> W_, W1_;
508 //
509 // Updated recycle space and its image
510 Teuchos::RCP<MV> U1_, C1_;
511 //
512 // Storage used in constructing harmonic Ritz values/vectors
513 Teuchos::RCP<DM> H2_;
514 Teuchos::RCP<DM> H_;
515 Teuchos::RCP<DM> PP_;
516 Teuchos::RCP<DM> HP_;
517 std::vector<ScalarType> tau_;
518 std::vector<ScalarType> work_;
519 Teuchos::RCP<DM> R_;
520 std::vector<int> ipiv_;
522
523 // Timers.
524 std::string label_;
525 Teuchos::RCP<Teuchos::Time> timerSolve_;
526
527 // Internal state variables.
528 bool isSet_;
529
530 // Have we generated or regenerated a recycle space yet this solve?
531 bool builtRecycleSpace_;
532 };
533
534
535// Empty Constructor
536template<class ScalarType, class MV, class OP, class DM>
538 achievedTol_(0.0),
539 numIters_(0)
540{
541 init ();
542}
543
544
545// Basic Constructor
546template<class ScalarType, class MV, class OP, class DM>
549 const Teuchos::RCP<Teuchos::ParameterList>& pl):
550 achievedTol_(0.0),
551 numIters_(0)
552{
553 // Initialize local pointers to null, and initialize local variables
554 // to default values.
555 init ();
556
558 problem == Teuchos::null, std::invalid_argument,
559 "Belos::GCRODRSolMgr constructor: The solver manager's "
560 "constructor needs the linear problem argument 'problem' "
561 "to be non-null.");
562 problem_ = problem;
563
564 // Set the parameters using the list that was passed in. If null,
565 // we defer initialization until a non-null list is set (by the
566 // client calling setParameters(), or by calling solve() -- in
567 // either case, a null parameter list indicates that default
568 // parameters should be used).
569 if (! pl.is_null ()) {
570 setParameters (pl);
571 }
572}
573
574// Common instructions executed in all constructors
575template<class ScalarType, class MV, class OP, class DM>
577 outputStream_ = Teuchos::rcpFromRef(std::cout);
579 orthoKappa_ = orthoKappa_default_;
580 maxRestarts_ = maxRestarts_default_;
581 maxIters_ = maxIters_default_;
582 numBlocks_ = numBlocks_default_;
583 recycledBlocks_ = recycledBlocks_default_;
584 verbosity_ = verbosity_default_;
585 outputStyle_ = outputStyle_default_;
586 outputFreq_ = outputFreq_default_;
587 isFlexible_ = flexibleGCRODR_default_;
588 orthoType_ = orthoType_default_;
589 impResScale_ = impResScale_default_;
590 expResScale_ = expResScale_default_;
591 label_ = label_default_;
592 isSet_ = false;
593 builtRecycleSpace_ = false;
594 keff = 0;
595 r_ = Teuchos::null;
596 V_ = Teuchos::null;
597 Z_ = Teuchos::null;
598 U_ = Teuchos::null;
599 C_ = Teuchos::null;
600 W_ = Teuchos::null;
601 W1_ = Teuchos::null;
602 U1_ = Teuchos::null;
603 C1_ = Teuchos::null;
604 PP_ = Teuchos::null;
605 HP_ = Teuchos::null;
606 H2_ = Teuchos::null;
607 R_ = Teuchos::null;
608 H_ = Teuchos::null;
609}
610
611template<class ScalarType, class MV, class OP, class DM>
613setParameters (const Teuchos::RCP<Teuchos::ParameterList> &params)
614{
615 using Teuchos::isParameterType;
616 using Teuchos::getParameter;
617 using Teuchos::null;
618 using Teuchos::ParameterList;
619 using Teuchos::parameterList;
620 using Teuchos::RCP;
621 using Teuchos::rcp;
622 using Teuchos::rcp_dynamic_cast;
623 using Teuchos::rcpFromRef;
624 using Teuchos::Exceptions::InvalidParameter;
625 using Teuchos::Exceptions::InvalidParameterName;
626 using Teuchos::Exceptions::InvalidParameterType;
627
628 // The default parameter list contains all parameters that
629 // GCRODRSolMgr understands, and none that it doesn't understand.
630 RCP<const ParameterList> defaultParams = getValidParameters();
631
632 // Create the internal parameter list if one doesn't already exist.
633 //
634 // (mfh 28 Feb 2011, 10 Mar 2011) At the time this code was written,
635 // ParameterList did not have validators or validateParameters().
636 // This is why the code below carefully validates the parameters one
637 // by one and fills in defaults. This code could be made a lot
638 // shorter by using validators. To do so, we would have to define
639 // appropriate validators for all the parameters. (This would more
640 // or less just move all that validation code out of this routine
641 // into to getValidParameters().)
642 //
643 // For an analogous reason, GCRODRSolMgr defines default parameter
644 // values as class data, as well as in the default ParameterList.
645 // This redundancy could be removed by defining the default
646 // parameter values only in the default ParameterList (which
647 // documents each parameter as well -- handy!).
648 if (params_.is_null()) {
649 params_ = parameterList (*defaultParams);
650 } else {
651 // A common case for setParameters() is for it to be called at the
652 // beginning of the solve() routine. This follows the Belos
653 // pattern of delaying initialization until the last possible
654 // moment (when the user asks Belos to perform the solve). In
655 // this common case, we save ourselves a deep copy of the input
656 // parameter list.
657 if (params_ != params) {
658 // Make a deep copy of the input parameter list. This allows
659 // the caller to modify or change params later, without
660 // affecting the behavior of this solver. This solver will then
661 // only change its internal parameters if setParameters() is
662 // called again.
663 params_ = parameterList (*params);
664 }
665
666 // Fill in any missing parameters and their default values. Also,
667 // throw an exception if the parameter list has any misspelled or
668 // "extra" parameters. If you don't like this behavior, you'll
669 // want to replace the line of code below with your desired
670 // validation scheme. Note that Teuchos currently only implements
671 // two options:
672 //
673 // 1. validateParameters() requires that params_ has all the
674 // parameters that the default list has, and none that it
675 // doesn't have.
676 //
677 // 2. validateParametersAndSetDefaults() fills in missing
678 // parameters in params_ using the default list, but requires
679 // that any parameter provided in params_ is also in the
680 // default list.
681 //
682 // Here is an easy way to ignore any "extra" or misspelled
683 // parameters: Make a deep copy of the default list, fill in any
684 // "missing" parameters from the _input_ list, and then validate
685 // the input list using the deep copy of the default list. We
686 // show this in code:
687 //
688 // RCP<ParameterList> defaultCopy = parameterList (*getValidParameters ());
689 // defaultCopy->validateParametersAndSetDefaults (params);
690 // params->validateParametersAndSetDefaults (defaultCopy);
691 //
692 // This method is not entirely robust, because the input list may
693 // have incorrect validators set for existing parameters in the
694 // default list. This would then cause "validation" of the
695 // default list to throw an exception. As a result, we've chosen
696 // for now to be intolerant of misspellings and "extra" parameters
697 // in the input list.
698 params_->validateParametersAndSetDefaults (*defaultParams);
699 }
700
701 // Check for maximum number of restarts.
702 if (params->isParameter ("Maximum Restarts")) {
703 maxRestarts_ = params->get("Maximum Restarts", maxRestarts_default_);
704
705 // Update parameter in our list.
706 params_->set ("Maximum Restarts", maxRestarts_);
707 }
708
709 // Check for maximum number of iterations
710 if (params->isParameter ("Maximum Iterations")) {
711 maxIters_ = params->get ("Maximum Iterations", maxIters_default_);
712
713 // Update parameter in our list and in status test.
714 params_->set ("Maximum Iterations", maxIters_);
715 if (! maxIterTest_.is_null())
716 maxIterTest_->setMaxIters (maxIters_);
717 }
718
719 // Check for the maximum number of blocks.
720 if (params->isParameter ("Num Blocks")) {
721 numBlocks_ = params->get ("Num Blocks", numBlocks_default_);
722 TEUCHOS_TEST_FOR_EXCEPTION(numBlocks_ <= 0, std::invalid_argument,
723 "Belos::GCRODRSolMgr: The \"Num Blocks\" parameter must "
724 "be strictly positive, but you specified a value of "
725 << numBlocks_ << ".");
726 // Update parameter in our list.
727 params_->set ("Num Blocks", numBlocks_);
728 }
729
730 // Check for the maximum number of blocks.
731 if (params->isParameter ("Num Recycled Blocks")) {
732 recycledBlocks_ = params->get ("Num Recycled Blocks",
733 recycledBlocks_default_);
734 TEUCHOS_TEST_FOR_EXCEPTION(recycledBlocks_ <= 0, std::invalid_argument,
735 "Belos::GCRODRSolMgr: The \"Num Recycled Blocks\" "
736 "parameter must be strictly positive, but you specified "
737 "a value of " << recycledBlocks_ << ".");
738 TEUCHOS_TEST_FOR_EXCEPTION(recycledBlocks_ >= numBlocks_, std::invalid_argument,
739 "Belos::GCRODRSolMgr: The \"Num Recycled Blocks\" "
740 "parameter must be less than the \"Num Blocks\" "
741 "parameter, but you specified \"Num Recycled Blocks\" "
742 "= " << recycledBlocks_ << " and \"Num Blocks\" = "
743 << numBlocks_ << ".");
744 // Update parameter in our list.
745 params_->set("Num Recycled Blocks", recycledBlocks_);
746 }
747
748 if (params->isParameter("Flexible GCRODR")) {
749 const bool newFlexible =
750 params->get("Flexible GCRODR", flexibleGCRODR_default_);
751 if (newFlexible != isFlexible_) {
752 impConvTest_ = null;
753 expConvTest_ = null;
754 convTest_ = null;
755 outputTest_ = null;
756 }
757 isFlexible_ = newFlexible;
758 params_->set("Flexible GCRODR", isFlexible_);
759 }
760
761 // Check to see if the timer label changed. If it did, update it in
762 // the parameter list, and create a new timer with that label (if
763 // Belos was compiled with timers enabled).
764 if (params->isParameter ("Timer Label")) {
765 std::string tempLabel = params->get ("Timer Label", label_default_);
766
767 // Update parameter in our list and solver timer
768 if (tempLabel != label_) {
769 label_ = tempLabel;
770 params_->set ("Timer Label", label_);
771 std::string solveLabel = label_ + ": GCRODRSolMgr total solve time";
772#ifdef BELOS_TEUCHOS_TIME_MONITOR
773 timerSolve_ = Teuchos::TimeMonitor::getNewCounter (solveLabel);
774#endif
775 if (ortho_ != Teuchos::null) {
776 ortho_->setLabel( label_ );
777 }
778 }
779 }
780
781 // Check for a change in verbosity level
782 if (params->isParameter ("Verbosity")) {
783 if (isParameterType<int> (*params, "Verbosity")) {
784 verbosity_ = params->get ("Verbosity", verbosity_default_);
785 } else {
786 verbosity_ = (int) getParameter<Belos::MsgType> (*params, "Verbosity");
787 }
788 // Update parameter in our list.
789 params_->set ("Verbosity", verbosity_);
790 // If the output manager (printer_) is null, then we will
791 // instantiate it later with the correct verbosity.
792 if (! printer_.is_null())
793 printer_->setVerbosity (verbosity_);
794 }
795
796 // Check for a change in output style
797 if (params->isParameter ("Output Style")) {
798 if (isParameterType<int> (*params, "Output Style")) {
799 outputStyle_ = params->get ("Output Style", outputStyle_default_);
800 } else {
801 outputStyle_ = (int) getParameter<OutputType> (*params, "Output Style");
802 }
803
804 // Update parameter in our list.
805 params_->set ("Output Style", outputStyle_);
806 // We will (re)instantiate the output status test afresh below.
807 outputTest_ = null;
808 }
809
810 // Get the output stream for the output manager.
811 //
812 // While storing the output stream in the parameter list (either as
813 // an RCP or as a nonconst reference) is convenient and safe for
814 // programming, it makes it impossible to serialize the parameter
815 // list, read it back in from the serialized representation, and get
816 // the same output stream as before. This is because output streams
817 // may be arbitrary constructed objects.
818 //
819 // In case the user tried reading in the parameter list from a
820 // serialized representation and the output stream can't be read
821 // back in, we set the output stream to point to std::cout. This
822 // ensures reasonable behavior.
823 if (params->isParameter ("Output Stream")) {
824 try {
825 outputStream_ = getParameter<RCP<std::ostream> > (*params, "Output Stream");
826 } catch (InvalidParameter&) {
827 outputStream_ = rcpFromRef (std::cout);
828 }
829 // We assume that a null output stream indicates that the user
830 // doesn't want to print anything, so we replace it with a "black
831 // hole" stream that prints nothing sent to it. (We can't use a
832 // null output stream, since the output manager always sends
833 // things it wants to print to the output stream.)
834 if (outputStream_.is_null()) {
835 outputStream_ = rcp (new Teuchos::oblackholestream);
836 }
837 // Update parameter in our list.
838 params_->set ("Output Stream", outputStream_);
839 // If the output manager (printer_) is null, then we will
840 // instantiate it later with the correct output stream.
841 if (! printer_.is_null()) {
842 printer_->setOStream (outputStream_);
843 }
844 }
845
846 // frequency level
847 if (verbosity_ & Belos::StatusTestDetails) {
848 if (params->isParameter ("Output Frequency")) {
849 outputFreq_ = params->get ("Output Frequency", outputFreq_default_);
850 }
851
852 // Update parameter in out list and output status test.
853 params_->set("Output Frequency", outputFreq_);
854 if (! outputTest_.is_null())
855 outputTest_->setOutputFrequency (outputFreq_);
856 }
857
858 // Create output manager if we need to, using the verbosity level
859 // and output stream that we fetched above. We do this here because
860 // instantiating an OrthoManager using OrthoManagerFactory requires
861 // a valid OutputManager.
862 if (printer_.is_null()) {
863 printer_ = rcp (new OutputManager<ScalarType> (verbosity_, outputStream_));
864 }
865
866 // Get the orthogonalization manager name ("Orthogonalization").
867 //
868 // Getting default values for the orthogonalization manager
869 // parameters ("Orthogonalization Parameters") requires knowing the
870 // orthogonalization manager name. Save it for later, and also
871 // record whether it's different than before.
873 bool changedOrthoType = false;
874 if (params->isParameter ("Orthogonalization")) {
875 const std::string& tempOrthoType =
876 params->get ("Orthogonalization", orthoType_default_);
877 // Ensure that the specified orthogonalization type is valid.
878 if (! factory.isValidName (tempOrthoType)) {
879 std::ostringstream os;
880 os << "Belos::GCRODRSolMgr: Invalid orthogonalization name \""
881 << tempOrthoType << "\". The following are valid options "
882 << "for the \"Orthogonalization\" name parameter: ";
883 factory.printValidNames (os);
884 throw std::invalid_argument (os.str());
885 }
886 if (tempOrthoType != orthoType_) {
887 changedOrthoType = true;
888 orthoType_ = tempOrthoType;
889 // Update parameter in our list.
890 params_->set ("Orthogonalization", orthoType_);
891 }
892 }
893
894 // Get any parameters for the orthogonalization ("Orthogonalization
895 // Parameters"). If not supplied, the orthogonalization manager
896 // factory will supply default values.
897 //
898 // NOTE (mfh 12 Jan 2011) For the sake of backwards compatibility,
899 // if params has an "Orthogonalization Constant" parameter and the
900 // DGKS orthogonalization manager is to be used, the value of this
901 // parameter will override DGKS's "depTol" parameter.
902 //
903 // Users must supply the orthogonalization manager parameters as a
904 // sublist (supplying it as an RCP<ParameterList> would make the
905 // resulting parameter list not serializable).
907 { // The nonmember function sublist() returns an RCP<ParameterList>,
908 // which is what we want here.
909 using Teuchos::sublist;
910 // Abbreviation to avoid typos.
911 const std::string paramName ("Orthogonalization Parameters");
912
913 try {
914 orthoParams = sublist (params_, paramName, true);
915 } catch (InvalidParameter&) {
916 // We didn't get the parameter list from params, so get a
917 // default parameter list from the OrthoManagerFactory. Modify
918 // params_ so that it has the default parameter list, and set
919 // orthoParams to ensure it's a sublist of params_ (and not just
920 // a copy of one).
921 params_->set (paramName, factory.getDefaultParameters (orthoType_));
922 orthoParams = sublist (params_, paramName, true);
923 }
924 }
925 TEUCHOS_TEST_FOR_EXCEPTION(orthoParams.is_null(), std::logic_error,
926 "Failed to get orthogonalization parameters. "
927 "Please report this bug to the Belos developers.");
928
929 // Instantiate a new MatOrthoManager subclass instance if necessary.
930 // If not necessary, then tell the existing instance about the new
931 // parameters.
932 if (ortho_.is_null() || changedOrthoType) {
933 // We definitely need to make a new MatOrthoManager, since either
934 // we haven't made one yet, or we've changed orthogonalization
935 // methods. Creating the orthogonalization manager requires that
936 // the OutputManager (printer_) already be initialized.
937 ortho_ = factory.makeMatOrthoManager (orthoType_, null, printer_,
938 label_, orthoParams);
939 } else {
940 // If the MatOrthoManager implements the ParameterListAcceptor
941 // mix-in interface, we can propagate changes to its parameters
942 // without reinstantiating the MatOrthoManager.
943 //
944 // We recommend that all MatOrthoManager subclasses implement
945 // Teuchos::ParameterListAcceptor, but do not (yet) require this.
946 typedef Teuchos::ParameterListAcceptor PLA;
948 if (pla.is_null()) {
949 // Oops, it's not a ParameterListAcceptor. We have to
950 // reinstantiate the MatOrthoManager in order to pass in the
951 // possibly new parameters.
952 ortho_ = factory.makeMatOrthoManager (orthoType_, null, printer_,
953 label_, orthoParams);
954 } else {
955 pla->setParameterList (orthoParams);
956 }
957 }
958
959 // The DGKS orthogonalization accepts a "Orthogonalization Constant"
960 // parameter (also called kappa in the code, but not in the
961 // parameter list). If its value is provided in the given parameter
962 // list, and its value is positive, use it. Ignore negative values.
963 //
964 // NOTE (mfh 12 Jan 2011) This overrides the "depTol" parameter that
965 // may have been specified in "Orthogonalization Parameters". We
966 // retain this behavior for backwards compatibility.
967 if (params->isParameter ("Orthogonalization Constant")) {
968 MagnitudeType orthoKappa = orthoKappa_default_;
969 if (params->isType<MagnitudeType> ("Orthogonalization Constant")) {
970 orthoKappa = params->get ("Orthogonalization Constant", orthoKappa);
971 }
972 else {
973 orthoKappa = params->get ("Orthogonalization Constant", orthoKappa_default_);
974 }
975
976 if (orthoKappa > 0) {
977 orthoKappa_ = orthoKappa;
978 // Update parameter in our list.
979 params_->set("Orthogonalization Constant", orthoKappa_);
980 // Only DGKS currently accepts this parameter.
981 if (orthoType_ == "DGKS" && ! ortho_.is_null()) {
983 // This cast should always succeed; it's a bug
984 // otherwise. (If the cast fails, then orthoType_
985 // doesn't correspond to the OrthoManager subclass
986 // instance that we think we have, so we initialized the
987 // wrong subclass somehow.)
988 rcp_dynamic_cast<ortho_man_type>(ortho_)->setDepTol (orthoKappa_);
989 }
990 }
991 }
992
993 // Convergence
994 typedef Belos::StatusTestCombo<ScalarType,MV,OP,DM> StatusTestCombo_t;
995 typedef Belos::StatusTestGenResNorm<ScalarType,MV,OP,DM> StatusTestResNorm_t;
996
997 // Check for convergence tolerance
998 if (params->isParameter("Convergence Tolerance")) {
999 if (params->isType<MagnitudeType> ("Convergence Tolerance")) {
1000 convTol_ = params->get ("Convergence Tolerance",
1001 static_cast<MagnitudeType> (DefaultSolverParameters::convTol));
1002 }
1003 else {
1004 convTol_ = params->get ("Convergence Tolerance", DefaultSolverParameters::convTol);
1005 }
1006
1007 // Update parameter in our list and residual tests.
1008 params_->set ("Convergence Tolerance", convTol_);
1009 if (! impConvTest_.is_null())
1010 impConvTest_->setTolerance (convTol_);
1011 if (! expConvTest_.is_null())
1012 expConvTest_->setTolerance (convTol_);
1013 }
1014
1015 // Check for a change in scaling, if so we need to build new residual tests.
1016 if (params->isParameter ("Implicit Residual Scaling")) {
1017 std::string tempImpResScale =
1018 getParameter<std::string> (*params, "Implicit Residual Scaling");
1019
1020 // Only update the scaling if it's different.
1021 if (impResScale_ != tempImpResScale) {
1023 impResScale_ = tempImpResScale;
1024
1025 // Update parameter in our list and residual tests
1026 params_->set("Implicit Residual Scaling", impResScale_);
1027 // NOTE (mfh 28 Feb 2011) StatusTestImpResNorm only lets you
1028 // call defineScaleForm() once. The code below attempts to call
1029 // defineScaleForm(); if the scale form has already been
1030 // defined, it constructs a new StatusTestImpResNorm instance.
1031 // StatusTestImpResNorm really should not expose the
1032 // defineScaleForm() method, since it's serving an
1033 // initialization purpose; all initialization should happen in
1034 // the constructor whenever possible. In that case, the code
1035 // below could be simplified into a single (re)instantiation.
1036 if (! impConvTest_.is_null()) {
1037 try {
1038 impConvTest_->defineScaleForm (impResScaleType, Belos::TwoNorm);
1039 }
1040 catch (StatusTestError&) {
1041 // Delete the convergence test so it gets constructed again.
1042 impConvTest_ = null;
1043 convTest_ = null;
1044 }
1045 }
1046 }
1047 }
1048
1049 if (params->isParameter("Explicit Residual Scaling")) {
1050 std::string tempExpResScale =
1051 getParameter<std::string> (*params, "Explicit Residual Scaling");
1052
1053 // Only update the scaling if it's different.
1054 if (expResScale_ != tempExpResScale) {
1056 expResScale_ = tempExpResScale;
1057
1058 // Update parameter in our list and residual tests
1059 params_->set("Explicit Residual Scaling", expResScale_);
1060 // NOTE (mfh 28 Feb 2011) See note above on the (re)construction
1061 // of StatusTestImpResNorm.
1062 if (! expConvTest_.is_null()) {
1063 try {
1064 expConvTest_->defineScaleForm (expResScaleType, Belos::TwoNorm);
1065 }
1066 catch (StatusTestError&) {
1067 // Delete the convergence test so it gets constructed again.
1068 expConvTest_ = null;
1069 convTest_ = null;
1070 }
1071 }
1072 }
1073 }
1074 //
1075 // Create iteration stopping criteria ("status tests") if we need
1076 // to, by combining three different stopping criteria.
1077 //
1078 // First, construct maximum-number-of-iterations stopping criterion.
1079 if (maxIterTest_.is_null())
1080 maxIterTest_ = rcp (new StatusTestMaxIters<ScalarType,MV,OP,DM> (maxIters_));
1081
1082 if (isFlexible_) {
1083 // Flexible GCRODR stores the correction basis Z and computes updates
1084 // directly in solution space. The generic explicit residual status
1085 // test machinery is not safe here unless it is made flexible-aware.
1086 // This follows BlockGmresSolMgr's flexible GMRES behavior: use the
1087 // native / implicit residual for convergence, then the solver manager
1088 // applies the final flexible update directly.
1089 if (impConvTest_.is_null()) {
1090 impConvTest_ = rcp (new StatusTestResNorm_t (convTol_));
1091 impConvTest_->defineScaleForm (convertStringToScaleType (impResScale_),
1093 }
1094
1095 expConvTest_ = impConvTest_;
1096 convTest_ = impConvTest_;
1097 }
1098 else {
1099 // Implicit residual test, using the native residual to determine if
1100 // convergence was achieved.
1101 if (impConvTest_.is_null()) {
1102 impConvTest_ = rcp (new StatusTestResNorm_t (convTol_));
1103 impConvTest_->defineScaleForm (convertStringToScaleType (impResScale_),
1105 }
1106
1107 // Explicit residual test once the native residual is below the tolerance.
1108 if (expConvTest_.is_null()) {
1109 expConvTest_ = rcp (new StatusTestResNorm_t (convTol_));
1110 expConvTest_->defineResForm (StatusTestResNorm_t::Explicit, Belos::TwoNorm);
1111 expConvTest_->defineScaleForm (convertStringToScaleType (expResScale_),
1113 }
1114
1115 // Convergence test first tests the implicit residual, then the
1116 // explicit residual if the implicit residual test passes.
1117 if (convTest_.is_null()) {
1118 convTest_ = rcp (new StatusTestCombo_t (StatusTestCombo_t::SEQ,
1119 impConvTest_,
1120 expConvTest_));
1121 }
1122 }
1123 // Construct the complete iteration stopping criterion:
1124 //
1125 // "Stop iterating if the maximum number of iterations has been
1126 // reached, or if the convergence test passes."
1127 sTest_ = rcp (new StatusTestCombo_t (StatusTestCombo_t::OR,
1128 maxIterTest_,
1129 convTest_));
1130 // Create the status test output class.
1131 // This class manages and formats the output from the status test.
1133 outputTest_ = stoFactory.create (printer_, sTest_, outputFreq_,
1135
1136 // Set the solver string for the output test
1137 std::string solverDesc = " GCRODR ";
1138 if (isFlexible_)
1139 solverDesc = "Flexible" + solverDesc;
1140 outputTest_->setSolverDesc( solverDesc );
1141
1142 // Create the timer if we need to.
1143 if (timerSolve_.is_null()) {
1144 std::string solveLabel = label_ + ": GCRODRSolMgr total solve time";
1145#ifdef BELOS_TEUCHOS_TIME_MONITOR
1146 timerSolve_ = Teuchos::TimeMonitor::getNewCounter(solveLabel);
1147#endif
1148 }
1149
1150 // Inform the solver manager that the current parameters were set.
1151 isSet_ = true;
1152}
1153
1154
1155template<class ScalarType, class MV, class OP, class DM>
1156Teuchos::RCP<const Teuchos::ParameterList>
1158{
1159 using Teuchos::ParameterList;
1160 using Teuchos::parameterList;
1161 using Teuchos::RCP;
1162
1164 if (is_null(validPL)) {
1166
1167 // Set all the valid parameters and their default values.
1168 pl->set("Convergence Tolerance", static_cast<MagnitudeType>(DefaultSolverParameters::convTol),
1169 "The relative residual tolerance that needs to be achieved by the\n"
1170 "iterative solver in order for the linear system to be declared converged.");
1171 pl->set("Maximum Restarts", static_cast<int>(maxRestarts_default_),
1172 "The maximum number of cycles allowed for each\n"
1173 "set of RHS solved.");
1174 pl->set("Maximum Iterations", static_cast<int>(maxIters_default_),
1175 "The maximum number of iterations allowed for each\n"
1176 "set of RHS solved.");
1177 // mfh 25 Oct 2010: "Block Size" must be 1 because GCRODR is
1178 // currently not a block method: i.e., it does not work on
1179 // multiple right-hand sides at once.
1180 pl->set("Block Size", static_cast<int>(blockSize_default_),
1181 "Block Size Parameter -- currently must be 1 for GCRODR");
1182 pl->set("Num Blocks", static_cast<int>(numBlocks_default_),
1183 "The maximum number of vectors allowed in the Krylov subspace\n"
1184 "for each set of RHS solved.");
1185 pl->set("Num Recycled Blocks", static_cast<int>(recycledBlocks_default_),
1186 "The maximum number of vectors in the recycled subspace." );
1187 pl->set("Flexible GCRODR", static_cast<bool>(flexibleGCRODR_default_),
1188 "Whether to use the flexible variant of GCRODR. The flexible variant stores the right-preconditioned correction basis Z.");
1189 pl->set("Verbosity", static_cast<int>(verbosity_default_),
1190 "What type(s) of solver information should be outputted\n"
1191 "to the output stream.");
1192 pl->set("Output Style", static_cast<int>(outputStyle_default_),
1193 "What style is used for the solver information outputted\n"
1194 "to the output stream.");
1195 pl->set("Output Frequency", static_cast<int>(outputFreq_default_),
1196 "How often convergence information should be outputted\n"
1197 "to the output stream.");
1198 pl->set("Output Stream", Teuchos::rcpFromRef(std::cout),
1199 "A reference-counted pointer to the output stream where all\n"
1200 "solver output is sent.");
1201 pl->set("Implicit Residual Scaling", static_cast<const char *>(impResScale_default_),
1202 "The type of scaling used in the implicit residual convergence test.");
1203 pl->set("Explicit Residual Scaling", static_cast<const char *>(expResScale_default_),
1204 "The type of scaling used in the explicit residual convergence test.");
1205 pl->set("Timer Label", static_cast<const char *>(label_default_),
1206 "The string to use as a prefix for the timer labels.");
1207 {
1209 pl->set("Orthogonalization", static_cast<const char *>(orthoType_default_),
1210 "The type of orthogonalization to use. Valid options: " +
1211 factory.validNamesString());
1213 factory.getDefaultParameters (orthoType_default_);
1214 pl->set ("Orthogonalization Parameters", *orthoParams,
1215 "Parameters specific to the type of orthogonalization used.");
1216 }
1217 pl->set("Orthogonalization Constant",static_cast<MagnitudeType>(orthoKappa_default_),
1218 "When using DGKS orthogonalization: the \"depTol\" constant, used "
1219 "to determine whether another step of classical Gram-Schmidt is "
1220 "necessary. Otherwise ignored.");
1221 validPL = pl;
1222 }
1223 return validPL;
1224}
1225
1226// initializeStateStorage
1227template<class ScalarType, class MV, class OP, class DM>
1229
1230 ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
1231
1232 // Check if there is any multivector to clone from.
1233 Teuchos::RCP<const MV> rhsMV = problem_->getRHS();
1234 if (rhsMV == Teuchos::null) {
1235 // Nothing to do
1236 return;
1237 }
1238 else {
1239
1240 // Initialize the state storage
1241 TEUCHOS_TEST_FOR_EXCEPTION(static_cast<ptrdiff_t>(numBlocks_) > MVT::GetGlobalLength(*rhsMV),std::invalid_argument,
1242 "Belos::GCRODRSolMgr::initializeStateStorage(): Cannot generate a Krylov basis with dimension larger the operator!");
1243
1244 // If the subspace has not been initialized before, generate it using the RHS from lp_.
1245 if (U_ == Teuchos::null) {
1246 U_ = MVT::Clone( *rhsMV, recycledBlocks_+1 );
1247 }
1248 else {
1249 // Generate U_ by cloning itself ONLY if more space is needed.
1250 if (MVT::GetNumberVecs(*U_) < recycledBlocks_+1) {
1251 Teuchos::RCP<const MV> tmp = U_;
1252 U_ = MVT::Clone( *tmp, recycledBlocks_+1 );
1253 }
1254 }
1255
1256 // If the subspace has not been initialized before, generate it using the RHS from lp_.
1257 if (C_ == Teuchos::null) {
1258 C_ = MVT::Clone( *rhsMV, recycledBlocks_+1 );
1259 }
1260 else {
1261 // Generate C_ by cloning itself ONLY if more space is needed.
1262 if (MVT::GetNumberVecs(*C_) < recycledBlocks_+1) {
1263 Teuchos::RCP<const MV> tmp = C_;
1264 C_ = MVT::Clone( *tmp, recycledBlocks_+1 );
1265 }
1266 }
1267
1268 // If the subspace has not been initialized before, generate it using the RHS from lp_.
1269 if (V_ == Teuchos::null) {
1270 V_ = MVT::Clone( *rhsMV, numBlocks_+1 );
1271 }
1272 else {
1273 // Generate V_ by cloning itself ONLY if more space is needed.
1274 if (MVT::GetNumberVecs(*V_) < numBlocks_+1) {
1275 Teuchos::RCP<const MV> tmp = V_;
1276 V_ = MVT::Clone( *tmp, numBlocks_+1 );
1277 }
1278 }
1279
1280 // If the subspace has not been initialized before, generate it using the RHS from lp_.
1281 if (U1_ == Teuchos::null) {
1282 U1_ = MVT::Clone( *rhsMV, recycledBlocks_+1 );
1283 }
1284 else {
1285 // Generate U1_ by cloning itself ONLY if more space is needed.
1286 if (MVT::GetNumberVecs(*U1_) < recycledBlocks_+1) {
1287 Teuchos::RCP<const MV> tmp = U1_;
1288 U1_ = MVT::Clone( *tmp, recycledBlocks_+1 );
1289 }
1290 }
1291
1292 // If the subspace has not been initialized before, generate it using the RHS from lp_.
1293 if (C1_ == Teuchos::null) {
1294 C1_ = MVT::Clone( *rhsMV, recycledBlocks_+1 );
1295 }
1296 else {
1297 // Generate C1_ by cloning itself ONLY if more space is needed.
1298 if (MVT::GetNumberVecs(*C1_) < recycledBlocks_+1) {
1299 Teuchos::RCP<const MV> tmp = C1_;
1300 C1_ = MVT::Clone( *tmp, recycledBlocks_+1 );
1301 }
1302 }
1303
1304
1305 if (isFlexible_) {
1306 if (Z_ == Teuchos::null) {
1307 Z_ = MVT::Clone(*rhsMV, numBlocks_+1);
1308 }
1309 else {
1310 if (MVT::GetNumberVecs(*Z_) < numBlocks_+1) {
1311 Teuchos::RCP<const MV> tmp = Z_;
1312 Z_ = MVT::Clone(*tmp, numBlocks_+1);
1313 }
1314 }
1315
1316 if (W_ == Teuchos::null) {
1317 W_ = MVT::Clone(*rhsMV, recycledBlocks_+1);
1318 }
1319 else {
1320 if (MVT::GetNumberVecs(*W_) < recycledBlocks_+1) {
1321 Teuchos::RCP<const MV> tmp = W_;
1322 W_ = MVT::Clone(*tmp, recycledBlocks_+1);
1323 }
1324 }
1325
1326 if (W1_ == Teuchos::null) {
1327 W1_ = MVT::Clone(*rhsMV, recycledBlocks_+1);
1328 }
1329 else {
1330 if (MVT::GetNumberVecs(*W1_) < recycledBlocks_+1) {
1331 Teuchos::RCP<const MV> tmp = W1_;
1332 W1_ = MVT::Clone(*tmp, recycledBlocks_+1);
1333 }
1334 }
1335 }
1336
1337 // Generate r_ only if it doesn't exist
1338 if (r_ == Teuchos::null)
1339 r_ = MVT::Clone( *rhsMV, 1 );
1340
1341 // Size of tau_ will change during computation, so just be sure it starts with appropriate size
1342 tau_.resize(recycledBlocks_+1);
1343
1344 // Size of work_ will change during computation, so just be sure it starts with appropriate size
1345 work_.resize(recycledBlocks_+1);
1346
1347 // Size of ipiv_ will change during computation, so just be sure it starts with appropriate size
1348 ipiv_.resize(recycledBlocks_+1);
1349
1350 // Generate H2_ only if it doesn't exist, otherwise resize it.
1351 if (H2_ == Teuchos::null)
1352 H2_ = DMT::Create( numBlocks_+recycledBlocks_+2, numBlocks_+recycledBlocks_+1 );
1353 else {
1354 if ( (DMT::GetNumRows(*H2_) != numBlocks_+recycledBlocks_+2) || (DMT::GetNumCols(*H2_) != numBlocks_+recycledBlocks_+1) )
1355 DMT::Reshape( *H2_, numBlocks_+recycledBlocks_+2, numBlocks_+recycledBlocks_+1 );
1356 }
1357 DMT::PutScalar(*H2_, zero);
1358
1359 // Generate R_ only if it doesn't exist, otherwise resize it.
1360 if (R_ == Teuchos::null)
1361 R_ = DMT::Create( recycledBlocks_+1, recycledBlocks_+1 );
1362 else {
1363 if ( (DMT::GetNumRows(*R_) != recycledBlocks_+1) || (DMT::GetNumCols(*R_) != recycledBlocks_+1) )
1364 DMT::Reshape( *R_, recycledBlocks_+1, recycledBlocks_+1 );
1365 }
1366 DMT::PutScalar(*R_,zero);
1367
1368 // Generate PP_ only if it doesn't exist, otherwise resize it.
1369 if (PP_ == Teuchos::null)
1370 PP_ = DMT::Create( numBlocks_+recycledBlocks_+2, recycledBlocks_+1 );
1371 else {
1372 if ( (DMT::GetNumRows(*PP_) != numBlocks_+recycledBlocks_+2) || (DMT::GetNumCols(*PP_) != recycledBlocks_+1) )
1373 DMT::Reshape( *PP_, numBlocks_+recycledBlocks_+2, recycledBlocks_+1 );
1374 }
1375
1376 // Generate HP_ only if it doesn't exist, otherwise resize it.
1377 if (HP_ == Teuchos::null)
1378 HP_ = DMT::Create( numBlocks_+recycledBlocks_+2, numBlocks_+recycledBlocks_+1 );
1379 else {
1380 if ( (DMT::GetNumRows(*HP_) != numBlocks_+recycledBlocks_+2) || (DMT::GetNumCols(*HP_) != numBlocks_+recycledBlocks_+1) )
1381 DMT::Reshape( *HP_, numBlocks_+recycledBlocks_+2, numBlocks_+recycledBlocks_+1 );
1382 }
1383
1384 } // end else
1385}
1386
1387
1388
1389template<class ScalarType, class MV, class OP, class DM>
1390void
1391GCRODRSolMgr<ScalarType,MV,OP,DM,true>::computeGCRODRResidual()
1392{
1393 if (isFlexible_) {
1394 problem_->computeCurrResVec(&*r_);
1395 }
1396 else {
1397 problem_->computeCurrPrecResVec(&*r_);
1398 }
1399}
1400
1401template<class ScalarType, class MV, class OP, class DM>
1402void
1403GCRODRSolMgr<ScalarType,MV,OP,DM,true>::
1404updateSolutionWithUpdate(const Teuchos::RCP<MV>& update)
1405{
1406 if (update == Teuchos::null) {
1407 return;
1408 }
1409
1410 const ScalarType one = SCT::one();
1411
1412 if (isFlexible_) {
1413 Teuchos::RCP<MV> curX = problem_->getCurrLHSVec();
1414 MVT::MvAddMv(one, *curX, one, *update, *curX);
1415 }
1416 else {
1417 problem_->updateSolution(update, true);
1418 }
1419}
1420
1421
1422// solve()
1423template<class ScalarType, class MV, class OP, class DM>
1425 using Teuchos::RCP;
1426 using Teuchos::rcp;
1427
1429
1430 // Set the current parameters if they were not set before.
1431 // NOTE: This may occur if the user generated the solver manager with the default constructor and
1432 // then didn't set any parameters using setParameters().
1433 if (!isSet_) { setParameters( params_ ); }
1434
1435 ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
1436 ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
1437 std::vector<int> index(numBlocks_+1);
1438
1439 TEUCHOS_TEST_FOR_EXCEPTION(problem_ == Teuchos::null,GCRODRSolMgrLinearProblemFailure, "Belos::GCRODRSolMgr::solve(): Linear problem is not a valid object.");
1440
1441 TEUCHOS_TEST_FOR_EXCEPTION(!problem_->isProblemSet(),GCRODRSolMgrLinearProblemFailure,"Belos::GCRODRSolMgr::solve(): Linear problem is not ready, setProblem() has not been called.");
1442
1443 if (isFlexible_) {
1445 !Teuchos::is_null(problem_->getLeftPrec()),
1447 "Belos::GCRODRSolMgr::solve(): Flexible GCRODR does not support left preconditioning; use no preconditioner or a right preconditioner.");
1448 }
1449
1450 // Create indices for the linear systems to be solved.
1451 int numRHS2Solve = MVT::GetNumberVecs( *(problem_->getRHS()) );
1452 std::vector<int> currIdx(1);
1453 currIdx[0] = 0;
1454
1455 // Inform the linear problem of the current linear system to solve.
1456 problem_->setLSIndex( currIdx );
1457
1458 // Check the number of blocks and change them is necessary.
1459 ptrdiff_t dim = MVT::GetGlobalLength( *(problem_->getRHS()) );
1460 if (static_cast<ptrdiff_t>(numBlocks_) > dim) {
1461 numBlocks_ = Teuchos::as<int>(dim);
1462 printer_->stream(Warnings) <<
1463 "Warning! Requested Krylov subspace dimension is larger than operator dimension!" << std::endl <<
1464 " The maximum number of blocks allowed for the Krylov subspace will be adjusted to " << numBlocks_ << std::endl;
1465 params_->set("Num Blocks", numBlocks_);
1466 }
1467
1468 // Assume convergence is achieved, then let any failed convergence set this to false.
1469 bool isConverged = true;
1470
1471 // Initialize storage for all state variables
1472 initializeStateStorage();
1473
1475 // Parameter list
1476 Teuchos::ParameterList plist;
1477
1478 plist.set("Num Blocks",numBlocks_);
1479 plist.set("Recycled Blocks",recycledBlocks_);
1480
1482 // GCRODR solver
1483
1485 if (isFlexible_) {
1486 gcrodr_iter = rcp(new FGCRODRIter<ScalarType,MV,OP,DM>(problem_,printer_,outputTest_,ortho_,plist));
1487 }
1488 else {
1489 gcrodr_iter = rcp(new GCRODRIter<ScalarType,MV,OP,DM>(problem_,printer_,outputTest_,ortho_,plist));
1490 }
1491 // Number of iterations required to generate initial recycle space (if needed)
1492 int prime_iterations = 0;
1493
1494 // Enter solve() iterations
1495 {
1496#ifdef BELOS_TEUCHOS_TIME_MONITOR
1497 Teuchos::TimeMonitor slvtimer(*timerSolve_);
1498#endif
1499
1500 while ( numRHS2Solve > 0 ) {
1501
1502 // Set flag indicating recycle space has not been generated this solve
1503 builtRecycleSpace_ = false;
1504
1505 // Reset the status test.
1506 outputTest_->reset();
1507
1509 // Initialize recycled subspace for GCRODR
1510
1511 // If there is a subspace to recycle, recycle it, otherwise generate the initial recycled subspace.
1512 if (keff > 0) {
1514 "Belos::GCRODRSolMgr::solve(): Requested size of recycled subspace is not consistent with the current recycle subspace.");
1515
1516 printer_->stream(Debug) << " Now solving RHS index " << currIdx[0] << " using recycled subspace of dimension " << keff << std::endl << std::endl;
1517 // Compute image of U_ under the new operator
1518 index.resize(keff);
1519 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1520 RCP<const MV> Utmp = MVT::CloneView( *U_, index );
1521 RCP<MV> Ctmp = MVT::CloneViewNonConst( *C_, index );
1522 if (isFlexible_) {
1523 problem_->applyOp(*Utmp, *Ctmp);
1524 }
1525 else {
1526 problem_->apply(*Utmp, *Ctmp);
1527 }
1528
1529 RCP<MV> U1tmp = MVT::CloneViewNonConst( *U1_, index );
1530
1531 // Orthogonalize this block
1532 // Get a matrix to hold the orthonormalization coefficients.
1533 Teuchos::RCP<DM> Rtmp = DMT::Subview( *R_, keff, keff );
1534 int rank = ortho_->normalize(*Ctmp, Rtmp);
1535 // Throw an error if we could not orthogonalize this block
1536 TEUCHOS_TEST_FOR_EXCEPTION(rank != keff,GCRODRSolMgrOrthoFailure,"Belos::GCRODRSolMgr::solve(): Failed to compute orthonormal basis for initial recycled subspace.");
1537
1538 // Synchronize R_ before calling LAPACK
1539 DMT::SyncDeviceToHost(*R_);
1540
1541 // U_ = U_*R^{-1}
1542 // First, compute LU factorization of R
1543 int info = 0;
1544 ipiv_.resize(DMT::GetNumRows(*Rtmp));
1545 lapack.GETRF(DMT::GetNumRows(*Rtmp), DMT::GetNumCols(*Rtmp), DMT::GetRawHostPtr(*Rtmp), DMT::GetStride(*Rtmp), &ipiv_[0], &info);
1546 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, GCRODRSolMgrLAPACKFailure,"Belos::GCRODRSolMgr::solve(): LAPACK _GETRF failed to compute an LU factorization.");
1547
1548 // Now, form inv(R)
1549 int lwork = DMT::GetNumRows(*Rtmp);
1550 work_.resize(lwork);
1551 lapack.GETRI(DMT::GetNumRows(*Rtmp), DMT::GetRawHostPtr(*Rtmp), DMT::GetStride(*Rtmp), &ipiv_[0], &work_[0], lwork, &info);
1552 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, GCRODRSolMgrLAPACKFailure,"Belos::GCRODRSolMgr::solve(): LAPACK _GETRI failed to invert triangular matrix.");
1553
1554 DMT::SyncHostToDevice(*R_);
1555
1556 // U_ = U1_; (via a swap)
1557 MVT::MvTimesMatAddMv( one, *Utmp, *Rtmp, zero, *U1tmp );
1558 if (isFlexible_) {
1559 Teuchos::RCP<const MV> Wtmp = MVT::CloneView(*W_, index);
1560 Teuchos::RCP<MV> W1tmp = MVT::CloneViewNonConst(*W1_, index);
1561 MVT::MvTimesMatAddMv(one, *Wtmp, *Rtmp, zero, *W1tmp);
1562 std::swap(W_, W1_);
1563 }
1564 std::swap(U_, U1_);
1565
1566 // Must reinitialize after swap
1567 index.resize(keff);
1568 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1569 Ctmp = MVT::CloneViewNonConst( *C_, index );
1570 Utmp = MVT::CloneView( *U_, index );
1571
1572 // Compute C_'*r_
1573 Teuchos::RCP<DM> Ctr = DMT::Create(keff, 1);
1574 computeGCRODRResidual();
1575 MVT::MvTransMv( one, *Ctmp, *r_, *Ctr );
1576
1577 // Update solution ( x += U_*C_'*r_ )
1578 RCP<MV> update = MVT::Clone( *problem_->getCurrLHSVec(), 1 );
1579 MVT::MvInit( *update, 0.0 );
1580 MVT::MvTimesMatAddMv( one, *Utmp, *Ctr, one, *update );
1581 updateSolutionWithUpdate(update);
1582
1583 // Update residual norm ( r -= C_*C_'*r_ )
1584 MVT::MvTimesMatAddMv( -one, *Ctmp, *Ctr, one, *r_ );
1585
1586 // We recycled space from previous call
1587 prime_iterations = 0;
1588
1589 }
1590 else {
1591
1592 // Do one cycle of Gmres to "prime the pump" if there is no subspace to recycle
1593 printer_->stream(Debug) << " No recycled subspace available for RHS index " << currIdx[0] << std::endl << std::endl;
1594
1595 Teuchos::ParameterList primeList;
1596 primeList.set("Num Blocks",numBlocks_);
1597 primeList.set("Recycled Blocks",recycledBlocks_);
1598
1599 // Create GCRODR iterator object to perform one cycle of GMRES.
1601 if (isFlexible_) {
1602 gcrodr_prime_iter = rcp(new FGCRODRIter<ScalarType,MV,OP,DM>(problem_,printer_,outputTest_,ortho_,primeList));
1603 }
1604 else {
1605 gcrodr_prime_iter = rcp(new GCRODRIter<ScalarType,MV,OP,DM>(problem_,printer_,outputTest_,ortho_,primeList));
1606 }
1607
1608 // Create the first block in the current Krylov basis (residual).
1609 computeGCRODRResidual();
1610 index.resize( 1 ); index[0] = 0;
1611 RCP<MV> v0 = MVT::CloneViewNonConst( *V_, index );
1612 MVT::SetBlock(*r_,index,*v0); // V(:,0) = r
1613
1614 // Set the new state and initialize the solver.
1616 index.resize( numBlocks_+1 );
1617 for (int ii=0; ii<(numBlocks_+1); ++ii) { index[ii] = ii; }
1618 newstate.V = MVT::CloneViewNonConst( *V_, index );
1619 if (isFlexible_) newstate.Z = MVT::CloneViewNonConst( *Z_, index );
1620 newstate.U = Teuchos::null;
1621 newstate.C = Teuchos::null;
1622 newstate.H2 = H2_;
1623 newstate.curDim = 0;
1624 gcrodr_prime_iter->initialize(newstate);
1625
1626 // Perform one cycle of GMRES
1627 bool primeConverged = false;
1628 try {
1629 gcrodr_prime_iter->iterate();
1630
1631 // Check convergence first
1632 if ( convTest_->getStatus() == Passed ) {
1633 // we have convergence
1634 primeConverged = true;
1635 }
1636 }
1637 catch (const GCRODRIterOrthoFailure &e) {
1638 // Try to recover the most recent least-squares solution
1639 gcrodr_prime_iter->updateLSQR( gcrodr_prime_iter->getCurSubspaceDim() );
1640
1641 // Check to see if the most recent least-squares solution yielded convergence.
1642 sTest_->checkStatus( &*gcrodr_prime_iter );
1643 if (convTest_->getStatus() == Passed)
1644 primeConverged = true;
1645 }
1646 catch (const StatusTestNaNError& e) {
1647 // A NaN was detected in the solver. Set the solution to zero and return unconverged.
1649 achievedTol_ = MT::one();
1650 Teuchos::RCP<MV> X = problem_->getLHS();
1651 MVT::MvInit( *X, SCT::zero() );
1652 printer_->stream(Warnings) << "Belos::GCRODRSolMgr::solve(): Warning! NaN has been detected!"
1653 << std::endl;
1654 return retType;
1655 }
1656 catch (const std::exception &e) {
1658 printer_->stream(Errors) << "Error! Caught exception in GCRODRIter::iterate() at iteration "
1659 << gcrodr_prime_iter->getNumIters() << std::endl
1660 << e.what() << std::endl;
1661 throw;
1662 }
1663 // Record number of iterations in generating initial recycle spacec
1664 prime_iterations = gcrodr_prime_iter->getNumIters();
1665
1666 // Update the linear problem.
1667 RCP<MV> update = gcrodr_prime_iter->getCurrentUpdate();
1668 updateSolutionWithUpdate(update);
1669
1670 // Get the state.
1671 newstate = gcrodr_prime_iter->getState();
1672 int p = newstate.curDim;
1673
1674 // Compute harmonic Ritz vectors
1675 // NOTE: The storage for the harmonic Ritz vectors (PP) is made one column larger
1676 // just in case we split a complex conjugate pair.
1677 // NOTE: Generate a recycled subspace only if we have enough vectors. If we converged
1678 // too early, move on to the next linear system and try to generate a subspace again.
1679 if (recycledBlocks_ < p+1) {
1680 int info = 0;
1681
1682 // Synchronize before calling getHarmonicVecs1; H2_ is const
1683 DMT::SyncDeviceToHost( *H2_ );
1684 DMT::SyncDeviceToHost( *PP_ );
1685 RCP<DM> PPtmp = DMT::Subview( *PP_, p, recycledBlocks_+1 );
1686
1687 // getHarmonicVecs1 assumes PP has recycledBlocks_+1 columns available
1688 keff = getHarmonicVecs1( p, *newstate.H, *PPtmp );
1689
1690 // Synchronize before forming U (the subspace to recycle)
1691 DMT::SyncHostToDevice( *PP_ );
1692 // Hereafter, only keff columns of PP are needed
1693 PPtmp = DMT::Subview( *PP_, p, keff );
1694
1695 // Now get views into C, U, V
1696 index.resize(keff);
1697 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1698 RCP<MV> Ctmp = MVT::CloneViewNonConst( *C_, index );
1699 RCP<MV> Utmp = MVT::CloneViewNonConst( *U_, index );
1700 RCP<MV> U1tmp = MVT::CloneViewNonConst( *U1_, index );
1701 index.resize(p);
1702 for (int ii=0; ii < p; ++ii) { index[ii] = ii; }
1703 RCP<const MV> Vtmp = MVT::CloneView( *V_, index );
1704
1705 // Form U (the subspace to recycle).
1706 // Standard GCRODR: U = V_m * P.
1707 // Flexible GCRODR: U = Z_m * P and W = V_m * P.
1708 if (isFlexible_) {
1709 RCP<const MV> Ztmp = MVT::CloneView(*Z_, index);
1710 MVT::MvTimesMatAddMv(one, *Ztmp, *PPtmp, zero, *U1tmp);
1711 std::vector<int> wind(keff);
1712 for (int wi = 0; wi < keff; ++wi) wind[wi] = wi;
1713 RCP<MV> W1tmp = MVT::CloneViewNonConst(*W1_, wind);
1714 MVT::MvTimesMatAddMv(one, *Vtmp, *PPtmp, zero, *W1tmp);
1715 }
1716 else {
1717 MVT::MvTimesMatAddMv( one, *Vtmp, *PPtmp, zero, *U1tmp );
1718 }
1719
1720 // Form orthonormalized C and adjust U so that C = A*U
1721
1722 // First, compute [Q, R] = qr(H*P);
1723
1724 // Step #1: Form HP = H*P
1725 DMT::SyncDeviceToHost( *HP_ );
1726
1727 RCP<DM> Htmp = DMT::Subview( *H2_, p+1, p, recycledBlocks_+1,recycledBlocks_+1 );
1728 RCP<DM> HPtmp = DMT::Subview( *HP_, p+1, keff );
1729
1730 Teuchos::BLAS<int,ScalarType> blas;
1731 blas.GEMM( Teuchos::NO_TRANS, Teuchos::NO_TRANS, p+1, keff, p, one,
1732 DMT::GetConstRawHostPtr(*Htmp), DMT::GetStride(*Htmp),
1733 DMT::GetConstRawHostPtr(*PPtmp), DMT::GetStride(*PPtmp),
1734 zero, DMT::GetRawHostPtr(*HPtmp), DMT::GetStride(*HPtmp));
1735
1736 // Step #1.5: Perform workspace size query for QR
1737 // factorization of HP. On input, lwork must be -1.
1738 // _GEQRF will put the workspace size in work_[0].
1739 int lwork = -1;
1740 tau_.resize (keff);
1741 lapack.GEQRF (DMT::GetNumRows(*HPtmp), DMT::GetNumCols(*HPtmp), DMT::GetRawHostPtr(*HPtmp),
1742 DMT::GetStride(*HPtmp), &tau_[0], &work_[0], lwork, &info);
1744 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve:"
1745 " LAPACK's _GEQRF failed to compute a workspace size.");
1746
1747 // Step #2: Compute QR factorization of HP
1748 //
1749 // NOTE (mfh 17 Apr 2014) LAPACK promises that the value of
1750 // work_[0] after the workspace query will fit in int. This
1751 // justifies the cast. We call real() first because
1752 // static_cast from std::complex to int doesn't work.
1753 lwork = std::abs (static_cast<int> (Teuchos::ScalarTraits<ScalarType>::real (work_[0])));
1754 work_.resize (lwork); // Allocate workspace for the QR factorization
1755 lapack.GEQRF (DMT::GetNumRows(*HPtmp), DMT::GetNumCols(*HPtmp), DMT::GetRawHostPtr(*HPtmp),
1756 DMT::GetStride(*HPtmp), &tau_[0], &work_[0], lwork, &info);
1758 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve:"
1759 " LAPACK's _GEQRF failed to compute a QR factorization.");
1760
1761 // Step #3: Explicitly construct Q and R factors
1762 // NOTE: The upper triangular part of HP is copied into R and HP becomes Q.
1763 // Synchronize R_ before and after copying over diagonal of HP
1764 DMT::SyncDeviceToHost( *R_ );
1765 RCP<DM> Rtmp = DMT::Subview( *R_, keff, keff );
1766 for (int ii = 0; ii < keff; ++ii) {
1767 for (int jj = ii; jj < keff; ++jj) {
1768 DMT::Value(*Rtmp,ii,jj) = DMT::ValueConst(*HPtmp,ii,jj);
1769 }
1770 }
1771 DMT::SyncHostToDevice( *R_ );
1772 // NOTE (mfh 17 Apr 2014): Teuchos::LAPACK's wrapper for
1773 // UNGQR dispatches to the correct Scalar-specific routine.
1774 // It calls {S,D}ORGQR if Scalar is real, and {C,Z}UNGQR if
1775 // Scalar is complex.
1776 lapack.UNGQR (DMT::GetNumRows(*HPtmp), DMT::GetNumCols(*HPtmp), DMT::GetNumCols(*HPtmp),
1777 DMT::GetRawHostPtr(*HPtmp), DMT::GetStride(*HPtmp), &tau_[0], &work_[0],
1778 lwork, &info);
1780 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve: "
1781 "LAPACK's _UNGQR failed to construct the Q factor.");
1782
1783 // Now we have [Q,R] = qr(H*P)
1784 // Synchronize HP_ after call to LAPACK
1785 DMT::SyncHostToDevice( *HP_ );
1786
1787 // Now compute C = V(:,1:p+1) * Q
1788 index.resize (p + 1);
1789 for (int ii = 0; ii < (p+1); ++ii) {
1790 index[ii] = ii;
1791 }
1792 Vtmp = MVT::CloneView( *V_, index ); // need new view into V (p+1 vectors now; needed p above)
1793 MVT::MvTimesMatAddMv( one, *Vtmp, *HPtmp, zero, *Ctmp );
1794
1795 // Finally, compute U = U*R^{-1}.
1796 // This unfortuntely requires me to form R^{-1} explicitly and execute U = U * R^{-1}, as
1797 // backsolve capabilities don't exist in the Belos::MultiVec class
1798
1799 // Step #1: First, compute LU factorization of R
1800 ipiv_.resize(DMT::GetNumRows(*Rtmp));
1801 lapack.GETRF(DMT::GetNumRows(*Rtmp), DMT::GetNumCols(*Rtmp), DMT::GetRawHostPtr(*Rtmp),
1802 DMT::GetStride(*Rtmp), &ipiv_[0], &info);
1804 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve: "
1805 "LAPACK's _GETRF failed to compute an LU factorization.");
1806
1807 // FIXME (mfh 17 Apr 2014) We have to compute the explicit
1808 // inverse of R here because Belos::MultiVecTraits doesn't
1809 // have a triangular solve (where the triangular matrix is
1810 // globally replicated and the "right-hand side" is the
1811 // distributed MultiVector).
1812
1813 // Step #2: Form inv(R)
1814 lwork = DMT::GetNumRows(*Rtmp);
1815 work_.resize(lwork);
1816 lapack.GETRI(DMT::GetNumRows(*Rtmp), DMT::GetRawHostPtr(*Rtmp), DMT::GetStride(*Rtmp),
1817 &ipiv_[0], &work_[0], lwork, &info);
1819 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve: "
1820 "LAPACK's _GETRI failed to invert triangular matrix.");
1821
1822 DMT::SyncHostToDevice( *R_ );
1823
1824 // Step #3: Let U = U * R^{-1}
1825 MVT::MvTimesMatAddMv( one, *U1tmp, *Rtmp, zero, *Utmp );
1826 if (isFlexible_) {
1827 std::vector<int> wind(keff);
1828 for (int wi = 0; wi < keff; ++wi) wind[wi] = wi;
1829 RCP<const MV> W1tmp = MVT::CloneView(*W1_, wind);
1830 RCP<MV> Wtmp = MVT::CloneViewNonConst(*W_, wind);
1831 MVT::MvTimesMatAddMv(one, *W1tmp, *Rtmp, zero, *Wtmp);
1832 }
1833
1834 printer_->stream(Debug)
1835 << " Generated recycled subspace using RHS index " << currIdx[0]
1836 << " of dimension " << keff << std::endl << std::endl;
1837
1838 } // if (recycledBlocks_ < p+1)
1839
1840 // Return to outer loop if the priming solve converged, set the next linear system.
1841 if (primeConverged) {
1842 // Inform the linear problem that we are finished with this block linear system.
1843 problem_->setCurrLS();
1844
1845 // Update indices for the linear systems to be solved.
1846 numRHS2Solve -= 1;
1847 if (numRHS2Solve > 0) {
1848 currIdx[0]++;
1849 problem_->setLSIndex (currIdx); // Set the next indices
1850 }
1851 else {
1852 currIdx.resize (numRHS2Solve);
1853 }
1854
1855 continue;
1856 }
1857 } // if (keff > 0) ...
1858
1859 // Prepare for the Gmres iterations with the recycled subspace.
1860
1861 // Set the current number of recycled blocks and subspace dimension with the GCRO-DR iteration.
1862 gcrodr_iter->setSize( keff, numBlocks_ );
1863
1864 // Reset the number of iterations.
1865 gcrodr_iter->resetNumIters(prime_iterations);
1866
1867 // Reset the number of calls that the status test output knows about.
1868 outputTest_->resetNumCalls();
1869
1870 // Compute the residual after the priming solve, it will be the first block in the current Krylov basis.
1871 computeGCRODRResidual();
1872 index.resize( 1 ); index[0] = 0;
1873 RCP<MV> v0 = MVT::CloneViewNonConst( *V_, index );
1874 MVT::SetBlock(*r_,index,*v0); // V(:,0) = r
1875
1876 // Set the new state and initialize the solver.
1877 DMT::SyncDeviceToHost( *H2_ );
1879 index.resize( numBlocks_+1 );
1880 for (int ii=0; ii<(numBlocks_+1); ++ii) { index[ii] = ii; }
1881 newstate.V = MVT::CloneViewNonConst( *V_, index );
1882 if (isFlexible_) newstate.Z = MVT::CloneViewNonConst( *Z_, index );
1883 index.resize( keff );
1884 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1885 newstate.C = MVT::CloneViewNonConst( *C_, index );
1886 newstate.U = MVT::CloneViewNonConst( *U_, index );
1887 newstate.H2 = H2_;
1888 newstate.curDim = 0;
1889 gcrodr_iter->initialize(newstate);
1890
1891 // variables needed for inner loop
1892 int numRestarts = 0;
1893 while(1) {
1894
1895 // tell gcrodr_iter to iterate
1896 try {
1897 gcrodr_iter->iterate();
1898
1900 //
1901 // check convergence first
1902 //
1904 if ( convTest_->getStatus() == Passed ) {
1905 // we have convergence
1906 break; // break from while(1){gcrodr_iter->iterate()}
1907 }
1909 //
1910 // check for maximum iterations
1911 //
1913 else if ( maxIterTest_->getStatus() == Passed ) {
1914 // we don't have convergence
1916 isConverged = false;
1917 break; // break from while(1){gcrodr_iter->iterate()}
1918 }
1920 //
1921 // check for restarting, i.e. the subspace is full
1922 //
1924 else if ( gcrodr_iter->getCurSubspaceDim() == gcrodr_iter->getMaxSubspaceDim() ) {
1925
1926 // Update the recycled subspace even if we have hit the maximum number of restarts.
1927
1928 // Update the linear problem.
1929 RCP<MV> update = gcrodr_iter->getCurrentUpdate();
1930 updateSolutionWithUpdate(update);
1931
1932 buildRecycleSpace2(gcrodr_iter);
1933
1934 printer_->stream(Debug)
1935 << " Generated new recycled subspace using RHS index "
1936 << currIdx[0] << " of dimension " << keff << std::endl
1937 << std::endl;
1938
1939 // NOTE: If we have hit the maximum number of restarts then quit
1940 if (numRestarts >= maxRestarts_) {
1942 isConverged = false;
1943 break; // break from while(1){gcrodr_iter->iterate()}
1944 }
1945 numRestarts++;
1946
1947 printer_->stream(Debug)
1948 << " Performing restart number " << numRestarts << " of "
1949 << maxRestarts_ << std::endl << std::endl;
1950
1951 // Create the restart vector (first block in the current Krylov basis)
1952 computeGCRODRResidual();
1953 index.resize( 1 ); index[0] = 0;
1954 RCP<MV> v00 = MVT::CloneViewNonConst( *V_, index );
1955 MVT::SetBlock(*r_,index,*v00); // V(:,0) = r
1956
1957 // Set the new state and initialize the solver.
1958 DMT::SyncDeviceToHost( *H2_ );
1960 index.resize( numBlocks_+1 );
1961 for (int ii=0; ii<(numBlocks_+1); ++ii) { index[ii] = ii; }
1962 restartState.V = MVT::CloneViewNonConst( *V_, index );
1963 if (isFlexible_) restartState.Z = MVT::CloneViewNonConst( *Z_, index );
1964 index.resize( keff );
1965 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1966 restartState.U = MVT::CloneViewNonConst( *U_, index );
1967 restartState.C = MVT::CloneViewNonConst( *C_, index );
1968 restartState.H2 = H2_;
1969 restartState.curDim = 0;
1970 gcrodr_iter->initialize(restartState);
1971
1972
1973 } // end of restarting
1974
1976 //
1977 // we returned from iterate(), but none of our status tests Passed.
1978 // something is wrong, and it is probably our fault.
1979 //
1981
1982 else {
1985 std::logic_error, "Belos::GCRODRSolMgr::solve: "
1986 "Invalid return from GCRODRIter::iterate().");
1987 }
1988 }
1989 catch (const GCRODRIterOrthoFailure &e) {
1990 // Try to recover the most recent least-squares solution
1991 gcrodr_iter->updateLSQR( gcrodr_iter->getCurSubspaceDim() );
1992
1993 // Check to see if the most recent least-squares solution yielded convergence.
1994 sTest_->checkStatus( &*gcrodr_iter );
1995 if (convTest_->getStatus() != Passed) {
1997 isConverged = false;
1998 }
1999 break;
2000 }
2001 catch (const std::exception& e) {
2003 printer_->stream(Errors)
2004 << "Error! Caught exception in GCRODRIter::iterate() at iteration "
2005 << gcrodr_iter->getNumIters() << std::endl << e.what() << std::endl;
2006 throw;
2007 }
2008 }
2009
2010 // Compute the current solution.
2011 // Update the linear problem.
2012 RCP<MV> update = gcrodr_iter->getCurrentUpdate();
2013 updateSolutionWithUpdate(update);
2014
2015 // Inform the linear problem that we are finished with this block linear system.
2016 problem_->setCurrLS();
2017
2018 // If we didn't build a recycle space this solve but ran at least k iterations,
2019 // force build of new recycle space
2020
2021 if (!builtRecycleSpace_) {
2022 buildRecycleSpace2(gcrodr_iter);
2023 printer_->stream(Debug)
2024 << " Generated new recycled subspace using RHS index " << currIdx[0]
2025 << " of dimension " << keff << std::endl << std::endl;
2026 }
2027
2028 // Update indices for the linear systems to be solved.
2029 numRHS2Solve -= 1;
2030 if (numRHS2Solve > 0) {
2031 currIdx[0]++;
2032 problem_->setLSIndex (currIdx); // Set the next indices
2033 }
2034 else {
2035 currIdx.resize (numRHS2Solve);
2036 }
2037 } // while (numRHS2Solve > 0)
2038 }
2039
2040 sTest_->print (printer_->stream (FinalSummary)); // print final summary
2041
2042 // print timing information
2043#ifdef BELOS_TEUCHOS_TIME_MONITOR
2044 // Calling summarize() can be expensive, so don't call unless the
2045 // user wants to print out timing details. summarize() will do all
2046 // the work even if it's passed a "black hole" output stream.
2047 if (verbosity_ & TimingDetails)
2048 Teuchos::TimeMonitor::summarize( printer_->stream(TimingDetails) );
2049#endif // BELOS_TEUCHOS_TIME_MONITOR
2050
2051 // get iteration information for this solve
2052 numIters_ = maxIterTest_->getNumIters ();
2053
2054 // Save the convergence test value ("achieved tolerance") for this
2055 // solve. This solver (unlike BlockGmresSolMgr) always has two
2056 // residual norm status tests: an explicit and an implicit test.
2057 // The master convergence test convTest_ is a SEQ combo of the
2058 // implicit resp. explicit tests. If the implicit test never
2059 // passes, then the explicit test won't ever be executed. This
2060 // manifests as expConvTest_->getTestValue()->size() < 1. We deal
2061 // with this case by using the values returned by
2062 // impConvTest_->getTestValue().
2063 {
2064 const std::vector<MagnitudeType>* pTestValues = NULL;
2065 if (! expConvTest_.is_null()) {
2066 pTestValues = expConvTest_->getTestValue();
2067 }
2068 if (pTestValues == NULL || pTestValues->size() < 1) {
2069 pTestValues = impConvTest_->getTestValue();
2070 }
2071 TEUCHOS_TEST_FOR_EXCEPTION(pTestValues == NULL, std::logic_error,
2072 "Belos::GCRODRSolMgr::solve(): The implicit convergence test's getTestValue() "
2073 "method returned NULL. Please report this bug to the Belos developers.");
2074 TEUCHOS_TEST_FOR_EXCEPTION(pTestValues->size() < 1, std::logic_error,
2075 "Belos::GCRODRSolMgr::solve(): The implicit convergence test's getTestValue() "
2076 "method returned a vector of length zero. Please report this bug to the "
2077 "Belos developers.");
2078
2079 // FIXME (mfh 12 Dec 2011) Does pTestValues really contain the
2080 // achieved tolerances for all vectors in the current solve(), or
2081 // just for the vectors from the last deflation?
2082 achievedTol_ = *std::max_element (pTestValues->begin(), pTestValues->end());
2083 }
2084
2085 if (!isConverged) {
2086 return retType; // return from solve()
2087 }
2088 return Converged; // return from solve()
2089}
2090
2091// Given existing recycle space and Krylov space, build new recycle space
2092template<class ScalarType, class MV, class OP, class DM>
2094
2095 if (isFlexible_) {
2096 buildFlexibleRecycleSpace2(gcrodr_iter);
2097 return;
2098 }
2099
2100 MagnitudeType one = Teuchos::ScalarTraits<MagnitudeType>::one();
2101 ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
2102
2103 std::vector<MagnitudeType> d(keff);
2104 std::vector<ScalarType> dscalar(keff);
2105 std::vector<int> index(numBlocks_+1);
2106
2107 // Get the state
2109 int p = oldState.curDim;
2110
2111 // insufficient new information to update recycle space
2112 if (p<1) return;
2113
2114 // Take the norm of the recycled vectors
2115 {
2116 index.resize(keff);
2117 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
2118 Teuchos::RCP<MV> Utmp = MVT::CloneViewNonConst( *U_, index );
2119 d.resize(keff);
2120 dscalar.resize(keff);
2121 MVT::MvNorm( *Utmp, d );
2122 for (int i=0; i<keff; ++i) {
2123 d[i] = one / d[i];
2124 dscalar[i] = (ScalarType)d[i];
2125 }
2126 MVT::MvScale( *Utmp, dscalar );
2127 }
2128
2129 // Get view into current "full" upper Hessenburg matrix
2130 DMT::SyncDeviceToHost( *H2_ );
2131 Teuchos::RCP<DM> H2tmp = DMT::Subview( *H2_, p+keff+1, p+keff );
2132
2133 // Insert D into the leading keff x keff block of H2
2134 for (int i=0; i<keff; ++i) {
2135 DMT::Value(*H2tmp,i,i) = d[i];
2136 }
2137
2138 DMT::SyncHostToDevice( *H2_ );
2139
2140 // Compute the harmoic Ritz pairs for the generalized eigenproblem
2141 // getHarmonicVecs2 assumes PP has recycledBlocks_+1 columns available
2142 int keff_new;
2143 {
2144 DMT::SyncDeviceToHost( *PP_ );
2145 Teuchos::RCP<DM> PPtmp = DMT::Subview( *PP_, p+keff, recycledBlocks_+1 );
2146 keff_new = getHarmonicVecs2( keff, p, *H2tmp, oldState.V, *PPtmp );
2147 DMT::SyncHostToDevice( *PP_ );
2148 }
2149
2150 // Code to form new U, C
2151 // U = [U V(:,1:p)] * P; (in two steps)
2152
2153 // U(:,1:keff) = matmul(U(:,1:keff_old),PP(1:keff_old,1:keff)) (step 1)
2154 Teuchos::RCP<MV> U1tmp;
2155 {
2156 index.resize( keff );
2157 for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
2158 Teuchos::RCP<const MV> Utmp = MVT::CloneView( *U_, index );
2159 index.resize( keff_new );
2160 for (int ii=0; ii<keff_new; ++ii) { index[ii] = ii; }
2161 U1tmp = MVT::CloneViewNonConst( *U1_, index );
2162 Teuchos::RCP<const DM> PPtmp = DMT::SubviewConst( *PP_, keff, keff_new );
2163 MVT::MvTimesMatAddMv( one, *Utmp, *PPtmp, zero, *U1tmp );
2164 }
2165
2166 // U(:,1:keff) = U(:,1:keff) + matmul(V(:,1:m-k),PP(keff_old+1:m-k+keff_old,1:keff)) (step 2)
2167 {
2168 index.resize(p);
2169 for (int ii=0; ii < p; ii++) { index[ii] = ii; }
2170 Teuchos::RCP<const MV> Vtmp = MVT::CloneView( *V_, index );
2171 Teuchos::RCP<const DM> PPtmp = DMT::SubviewConst( *PP_, p, keff_new, keff );
2172 MVT::MvTimesMatAddMv( one, *Vtmp, *PPtmp, one, *U1tmp );
2173 }
2174
2175 // Form HP = H*P
2176 DMT::SyncDeviceToHost( *HP_ );
2177 Teuchos::RCP<DM> HPtmp = DMT::Subview( *HP_, p+keff+1, keff_new );
2178 {
2179 DMT::SyncDeviceToHost( *PP_ );
2180 Teuchos::RCP<DM> PPtmp = DMT::Subview( *PP_, p+keff, keff_new );
2181
2182 Teuchos::BLAS<int,ScalarType> blas;
2183 blas.GEMM( Teuchos::NO_TRANS, Teuchos::NO_TRANS, p+keff+1, keff_new, p+keff, one,
2184 DMT::GetConstRawHostPtr(*H2tmp), DMT::GetStride(*H2tmp),
2185 DMT::GetConstRawHostPtr(*PPtmp), DMT::GetStride(*PPtmp),
2186 zero, DMT::GetRawHostPtr(*HPtmp), DMT::GetStride(*HPtmp));
2187 }
2188
2189 // Workspace size query for QR factorization of HP (the worksize will be placed in work_[0])
2190 int info = 0, lwork = -1;
2191 tau_.resize (keff_new);
2192 lapack.GEQRF (DMT::GetNumRows(*HPtmp), DMT::GetNumCols(*HPtmp), DMT::GetRawHostPtr(*HPtmp),
2193 DMT::GetStride(*HPtmp), &tau_[0], &work_[0], lwork, &info);
2195 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve: "
2196 "LAPACK's _GEQRF failed to compute a workspace size.");
2197
2198 // NOTE (mfh 18 Apr 2014) LAPACK promises that the value of work_[0]
2199 // after the workspace query will fit in int. This justifies the
2200 // cast. We call real() first because static_cast from std::complex
2201 // to int doesn't work.
2202 lwork = std::abs (static_cast<int> (Teuchos::ScalarTraits<ScalarType>::real (work_[0])));
2203 work_.resize (lwork); // Allocate workspace for the QR factorization
2204 lapack.GEQRF (DMT::GetNumRows(*HPtmp), DMT::GetNumCols(*HPtmp), DMT::GetRawHostPtr(*HPtmp),
2205 DMT::GetStride(*HPtmp), &tau_[0], &work_[0], lwork, &info);
2207 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve: "
2208 "LAPACK's _GEQRF failed to compute a QR factorization.");
2209
2210 // Explicitly construct Q and R factors
2211 // NOTE: The upper triangular part of HP is copied into R and HP becomes Q.
2212 DMT::SyncDeviceToHost( *R_ );
2213 Teuchos::RCP<DM> Rtmp = DMT::Subview( *R_, keff_new, keff_new );
2214 for(int i=0;i<keff_new;i++) { for(int j=i;j<keff_new;j++) DMT::Value(*Rtmp,i,j) = DMT::ValueConst(*HPtmp,i,j); }
2215
2216 // NOTE (mfh 18 Apr 2014): Teuchos::LAPACK's wrapper for UNGQR
2217 // dispatches to the correct Scalar-specific routine. It calls
2218 // {S,D}ORGQR if Scalar is real, and {C,Z}UNGQR if Scalar is
2219 // complex.
2220 lapack.UNGQR (DMT::GetNumRows(*HPtmp), DMT::GetNumCols(*HPtmp), DMT::GetNumCols(*HPtmp),
2221 DMT::GetRawHostPtr(*HPtmp), DMT::GetStride(*HPtmp), &tau_[0], &work_[0],
2222 lwork, &info);
2224 info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve: "
2225 "LAPACK's _UNGQR failed to construct the Q factor.");
2226
2227 DMT::SyncHostToDevice( *HP_ );
2228 HPtmp = Teuchos::null;
2229
2230 // Form orthonormalized C and adjust U accordingly so that C = A*U
2231 // C = [C V] * Q;
2232
2233 // C(:,1:keff) = matmul(C(:,1:keff_old),QQ(1:keff_old,1:keff))
2234 {
2235 Teuchos::RCP<MV> C1tmp;
2236 {
2237 index.resize(keff);
2238 for (int i=0; i < keff; i++) { index[i] = i; }
2239 Teuchos::RCP<const MV> Ctmp = MVT::CloneView( *C_, index );
2240 index.resize(keff_new);
2241 for (int i=0; i < keff_new; i++) { index[i] = i; }
2242 C1tmp = MVT::CloneViewNonConst( *C1_, index );
2243 Teuchos::RCP<const DM> PPtmp = DMT::SubviewConst( *HP_, keff, keff_new );
2244 MVT::MvTimesMatAddMv( one, *Ctmp, *PPtmp, zero, *C1tmp );
2245 }
2246 // Now compute C += V(:,1:p+1) * Q
2247 {
2248 index.resize( p+1 );
2249 for (int i=0; i < p+1; ++i) { index[i] = i; }
2250 Teuchos::RCP<const MV> Vtmp = MVT::CloneView( *V_, index );
2251 Teuchos::RCP<const DM> PPtmp = DMT::SubviewConst( *HP_, p+1, keff_new, keff, 0 );
2252 MVT::MvTimesMatAddMv( one, *Vtmp, *PPtmp, one, *C1tmp );
2253 }
2254 }
2255
2256 // C_ = C1_; (via a swap)
2257 std::swap(C_, C1_);
2258
2259 // Finally, compute U_ = U_*R^{-1}
2260 // First, compute LU factorization of R
2261 ipiv_.resize(DMT::GetNumRows(*Rtmp));
2262 lapack.GETRF(DMT::GetNumRows(*Rtmp),DMT::GetNumCols(*Rtmp),DMT::GetRawHostPtr(*Rtmp),DMT::GetStride(*Rtmp),&ipiv_[0],&info);
2263 TEUCHOS_TEST_FOR_EXCEPTION(info != 0,GCRODRSolMgrLAPACKFailure,"Belos::GCRODRSolMgr::buildRecycleSpace2(): LAPACK _GETRF failed to compute an LU factorization.");
2264
2265 // Now, form inv(R)
2266 lwork = DMT::GetNumRows(*Rtmp);
2267 work_.resize(lwork);
2268 lapack.GETRI(DMT::GetNumRows(*Rtmp),DMT::GetRawHostPtr(*Rtmp),DMT::GetStride(*Rtmp),&ipiv_[0],&work_[0],lwork,&info);
2269 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, GCRODRSolMgrLAPACKFailure,"Belos::GCRODRSolMgr::buildRecycleSpace2(): LAPACK _GETRI failed to compute an LU factorization.");
2270
2271 DMT::SyncHostToDevice(*R_);
2272
2273 {
2274 index.resize(keff_new);
2275 for (int i=0; i < keff_new; i++) { index[i] = i; }
2276 Teuchos::RCP<MV> Utmp = MVT::CloneViewNonConst( *U_, index );
2277 MVT::MvTimesMatAddMv( one, *U1tmp, *Rtmp, zero, *Utmp );
2278 }
2279
2280 // Set the current number of recycled blocks and subspace dimension with the GCRO-DR iteration.
2281 if (keff != keff_new) {
2282 keff = keff_new;
2283 gcrodr_iter->setSize( keff, numBlocks_ );
2284 // Important to zero this out before next cyle
2285 Teuchos::RCP<DM> b1 = DMT::Subview( *H2_, recycledBlocks_+2, 1, 0, recycledBlocks_ );
2286 DMT::PutScalar( *b1, zero );
2287 }
2288
2289}
2290
2291// Given existing recycle space and flexible Krylov space, build new recycle space.
2292// Flexible version:
2293// correction basis: [U, Z]
2294// image basis: [C, V]
2295// auxiliary basis: [W, V_m]
2296template<class ScalarType, class MV, class OP, class DM>
2297void
2298GCRODRSolMgr<ScalarType,MV,OP,DM,true>::
2299buildFlexibleRecycleSpace2(Teuchos::RCP<GCRODRIteration<ScalarType,MV,OP,DM> > gcrodr_iter)
2300{
2301 MagnitudeType magOne = Teuchos::ScalarTraits<MagnitudeType>::one();
2302 ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
2303 ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
2304
2305 std::vector<MagnitudeType> d(keff);
2306 std::vector<ScalarType> dscalar(keff);
2307 std::vector<int> index(numBlocks_+1);
2308
2310 int p = oldState.curDim;
2311
2312 if (p < 1) return;
2313
2315 oldState.Z == Teuchos::null,
2316 GCRODRSolMgrRecyclingFailure,
2317 "Belos::GCRODRSolMgr::buildFlexibleRecycleSpace2(): oldState.Z is null.");
2318
2320 W_ == Teuchos::null,
2321 GCRODRSolMgrRecyclingFailure,
2322 "Belos::GCRODRSolMgr::buildFlexibleRecycleSpace2(): W_ is null.");
2323
2324 // Scale U and W consistently.
2325 {
2326 index.resize(keff);
2327 for (int ii=0; ii<keff; ++ii) index[ii] = ii;
2328
2329 Teuchos::RCP<MV> Utmp = MVT::CloneViewNonConst(*U_, index);
2330 Teuchos::RCP<MV> Wtmp = MVT::CloneViewNonConst(*W_, index);
2331
2332 d.resize(keff);
2333 dscalar.resize(keff);
2334
2335 MVT::MvNorm(*Utmp, d);
2336 for (int i=0; i<keff; ++i) {
2337 d[i] = magOne / d[i];
2338 dscalar[i] = static_cast<ScalarType>(d[i]);
2339 }
2340
2341 MVT::MvScale(*Utmp, dscalar);
2342 MVT::MvScale(*Wtmp, dscalar);
2343 }
2344
2345 // Get view into current full projected matrix.
2346 DMT::SyncDeviceToHost(*H2_);
2347 Teuchos::RCP<DM> H2tmp = DMT::Subview(*H2_, p+keff+1, p+keff);
2348
2349 // Insert D into the leading keff x keff block of H2.
2350 for (int i=0; i<keff; ++i) {
2351 DMT::Value(*H2tmp, i, i) = d[i];
2352 }
2353
2354 DMT::SyncHostToDevice(*H2_);
2355
2356 // Compute flexible harmonic Ritz vectors.
2357 int keff_new;
2358 {
2359 DMT::SyncDeviceToHost(*PP_);
2360 Teuchos::RCP<DM> PPtmp = DMT::Subview(*PP_, p+keff, recycledBlocks_+1);
2361 keff_new = getFlexibleHarmonicVecs2(keff, p, *H2tmp, oldState.V, *PPtmp);
2362 DMT::SyncHostToDevice(*PP_);
2363 }
2364
2365 // U1 = [U, Z] * P.
2366 Teuchos::RCP<MV> U1tmp;
2367 {
2368 index.resize(keff);
2369 for (int ii=0; ii<keff; ++ii) index[ii] = ii;
2370
2371 Teuchos::RCP<const MV> Utmp = MVT::CloneView(*U_, index);
2372
2373 index.resize(keff_new);
2374 for (int ii=0; ii<keff_new; ++ii) index[ii] = ii;
2375
2376 U1tmp = MVT::CloneViewNonConst(*U1_, index);
2377
2378 Teuchos::RCP<const DM> PPtop = DMT::SubviewConst(*PP_, keff, keff_new);
2379 MVT::MvTimesMatAddMv(one, *Utmp, *PPtop, zero, *U1tmp);
2380 }
2381
2382 {
2383 index.resize(p);
2384 for (int ii=0; ii<p; ++ii) index[ii] = ii;
2385
2386 Teuchos::RCP<const MV> Ztmp = MVT::CloneView(*oldState.Z, index);
2387 Teuchos::RCP<const DM> PPbottom = DMT::SubviewConst(*PP_, p, keff_new, keff);
2388
2389 MVT::MvTimesMatAddMv(one, *Ztmp, *PPbottom, one, *U1tmp);
2390 }
2391
2392 // W1 = [W, V_m] * P.
2393 Teuchos::RCP<MV> W1tmp;
2394 {
2395 index.resize(keff);
2396 for (int ii=0; ii<keff; ++ii) index[ii] = ii;
2397
2398 Teuchos::RCP<const MV> Wtmp = MVT::CloneView(*W_, index);
2399
2400 index.resize(keff_new);
2401 for (int ii=0; ii<keff_new; ++ii) index[ii] = ii;
2402
2403 W1tmp = MVT::CloneViewNonConst(*W1_, index);
2404
2405 Teuchos::RCP<const DM> PPtop = DMT::SubviewConst(*PP_, keff, keff_new);
2406 MVT::MvTimesMatAddMv(one, *Wtmp, *PPtop, zero, *W1tmp);
2407 }
2408
2409 {
2410 index.resize(p);
2411 for (int ii=0; ii<p; ++ii) index[ii] = ii;
2412
2413 Teuchos::RCP<const MV> Vtmp = MVT::CloneView(*oldState.V, index);
2414 Teuchos::RCP<const DM> PPbottom = DMT::SubviewConst(*PP_, p, keff_new, keff);
2415
2416 MVT::MvTimesMatAddMv(one, *Vtmp, *PPbottom, one, *W1tmp);
2417 }
2418
2419 // HP = H * P.
2420 DMT::SyncDeviceToHost(*HP_);
2421 Teuchos::RCP<DM> HPtmp = DMT::Subview(*HP_, p+keff+1, keff_new);
2422
2423 {
2424 DMT::SyncDeviceToHost(*PP_);
2425 DMT::SyncDeviceToHost(*H2_);
2426 Teuchos::RCP<DM> PPtmp = DMT::Subview(*PP_, p+keff, keff_new);
2427
2428 Teuchos::BLAS<int,ScalarType> blas;
2429 blas.GEMM(Teuchos::NO_TRANS, Teuchos::NO_TRANS,
2430 p+keff+1, keff_new, p+keff,
2431 one,
2432 DMT::GetConstRawHostPtr(*H2tmp), DMT::GetStride(*H2tmp),
2433 DMT::GetConstRawHostPtr(*PPtmp), DMT::GetStride(*PPtmp),
2434 zero,
2435 DMT::GetRawHostPtr(*HPtmp), DMT::GetStride(*HPtmp));
2436 }
2437
2438 // QR factorization of HP.
2439 int info = 0;
2440 int lwork = -1;
2441
2442 tau_.resize(keff_new);
2443 if (work_.size() < 1) work_.resize(1);
2444
2445 lapack.GEQRF(DMT::GetNumRows(*HPtmp),
2446 DMT::GetNumCols(*HPtmp),
2447 DMT::GetRawHostPtr(*HPtmp),
2448 DMT::GetStride(*HPtmp),
2449 &tau_[0], &work_[0], lwork, &info);
2450
2452 info != 0,
2453 GCRODRSolMgrLAPACKFailure,
2454 "Belos::GCRODRSolMgr::buildFlexibleRecycleSpace2(): LAPACK GEQRF workspace query failed.");
2455
2456 lwork = std::abs(static_cast<int>(Teuchos::ScalarTraits<ScalarType>::real(work_[0])));
2457 work_.resize(lwork);
2458
2459 lapack.GEQRF(DMT::GetNumRows(*HPtmp),
2460 DMT::GetNumCols(*HPtmp),
2461 DMT::GetRawHostPtr(*HPtmp),
2462 DMT::GetStride(*HPtmp),
2463 &tau_[0], &work_[0], lwork, &info);
2464
2466 info != 0,
2467 GCRODRSolMgrLAPACKFailure,
2468 "Belos::GCRODRSolMgr::buildFlexibleRecycleSpace2(): LAPACK GEQRF failed.");
2469
2470 // Copy R from upper triangular part of HP.
2471 DMT::SyncDeviceToHost(*R_);
2472 Teuchos::RCP<DM> Rtmp = DMT::Subview(*R_, keff_new, keff_new);
2473
2474 for (int i=0; i<keff_new; ++i) {
2475 for (int j=i; j<keff_new; ++j) {
2476 DMT::Value(*Rtmp, i, j) = DMT::ValueConst(*HPtmp, i, j);
2477 }
2478 }
2479
2480 // Form Q explicitly in HPtmp.
2481 lapack.UNGQR(DMT::GetNumRows(*HPtmp),
2482 DMT::GetNumCols(*HPtmp),
2483 DMT::GetNumCols(*HPtmp),
2484 DMT::GetRawHostPtr(*HPtmp),
2485 DMT::GetStride(*HPtmp),
2486 &tau_[0], &work_[0], lwork, &info);
2487
2489 info != 0,
2490 GCRODRSolMgrLAPACKFailure,
2491 "Belos::GCRODRSolMgr::buildFlexibleRecycleSpace2(): LAPACK UNGQR failed.");
2492
2493 DMT::SyncHostToDevice(*HP_);
2494
2495 // C1 = [C, V_{p+1}] * Q.
2496 {
2497 Teuchos::RCP<MV> C1tmp;
2498
2499 {
2500 index.resize(keff);
2501 for (int i=0; i<keff; ++i) index[i] = i;
2502
2503 Teuchos::RCP<const MV> Ctmp = MVT::CloneView(*C_, index);
2504
2505 index.resize(keff_new);
2506 for (int i=0; i<keff_new; ++i) index[i] = i;
2507
2508 C1tmp = MVT::CloneViewNonConst(*C1_, index);
2509
2510 Teuchos::RCP<const DM> Qtop = DMT::SubviewConst(*HP_, keff, keff_new);
2511 MVT::MvTimesMatAddMv(one, *Ctmp, *Qtop, zero, *C1tmp);
2512 }
2513
2514 {
2515 index.resize(p+1);
2516 for (int i=0; i<p+1; ++i) index[i] = i;
2517
2518 Teuchos::RCP<const MV> Vtmp = MVT::CloneView(*oldState.V, index);
2519 Teuchos::RCP<const DM> Qbottom = DMT::SubviewConst(*HP_, p+1, keff_new, keff, 0);
2520
2521 MVT::MvTimesMatAddMv(one, *Vtmp, *Qbottom, one, *C1tmp);
2522 }
2523 }
2524
2525 std::swap(C_, C1_);
2526
2527 // Compute R^{-1}.
2528 ipiv_.resize(DMT::GetNumRows(*Rtmp));
2529
2530 lapack.GETRF(DMT::GetNumRows(*Rtmp),
2531 DMT::GetNumCols(*Rtmp),
2532 DMT::GetRawHostPtr(*Rtmp),
2533 DMT::GetStride(*Rtmp),
2534 &ipiv_[0], &info);
2535
2537 info != 0,
2538 GCRODRSolMgrLAPACKFailure,
2539 "Belos::GCRODRSolMgr::buildFlexibleRecycleSpace2(): LAPACK GETRF failed.");
2540
2541 lwork = DMT::GetNumRows(*Rtmp);
2542 work_.resize(lwork);
2543
2544 lapack.GETRI(DMT::GetNumRows(*Rtmp),
2545 DMT::GetRawHostPtr(*Rtmp),
2546 DMT::GetStride(*Rtmp),
2547 &ipiv_[0], &work_[0], lwork, &info);
2548
2550 info != 0,
2551 GCRODRSolMgrLAPACKFailure,
2552 "Belos::GCRODRSolMgr::buildFlexibleRecycleSpace2(): LAPACK GETRI failed.");
2553
2554 DMT::SyncHostToDevice(*R_);
2555
2556 {
2557 index.resize(keff_new);
2558 for (int i=0; i<keff_new; ++i) index[i] = i;
2559
2560 Teuchos::RCP<MV> Utmp = MVT::CloneViewNonConst(*U_, index);
2561 Teuchos::RCP<const MV> U1tmpConst = MVT::CloneView(*U1_, index);
2562 MVT::MvTimesMatAddMv(one, *U1tmpConst, *Rtmp, zero, *Utmp);
2563
2564 Teuchos::RCP<MV> Wtmp = MVT::CloneViewNonConst(*W_, index);
2565 Teuchos::RCP<const MV> W1tmpConst = MVT::CloneView(*W1_, index);
2566 MVT::MvTimesMatAddMv(one, *W1tmpConst, *Rtmp, zero, *Wtmp);
2567 }
2568
2569 if (keff != keff_new) {
2570 keff = keff_new;
2571 gcrodr_iter->setSize(keff, numBlocks_);
2572
2573 Teuchos::RCP<DM> b1 = DMT::Subview(*H2_, recycledBlocks_+2, 1, 0, recycledBlocks_);
2574 DMT::PutScalar(*b1, zero);
2575 }
2576}
2577
2578
2579// Compute the harmonic eigenpairs of the projected, dense system.
2580template<class ScalarType, class MV, class OP, class DM>
2581int GCRODRSolMgr<ScalarType,MV,OP,DM,true>::getHarmonicVecs1(int m, const DM& HH, DM& PP) {
2582
2583 int i, j;
2584 bool xtraVec = false;
2585 ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
2586
2587 // Real and imaginary eigenvalue components
2588 std::vector<MagnitudeType> wr(m), wi(m);
2589
2590 // Real and imaginary (right) eigenvectors; Don't zero out matrix when constructing
2591 Teuchos::RCP<DM> vr = DMT::Create(m,m,false);
2592
2593 // Magnitude of harmonic Ritz values
2594 std::vector<MagnitudeType> w(m);
2595
2596 // Sorted order of harmonic Ritz values, also used for GEEV
2597 std::vector<int> iperm(m);
2598
2599 // Output info
2600 int info = 0;
2601
2602 // Set flag indicating recycle space has been generated this solve
2603 builtRecycleSpace_ = true;
2604
2605 // Solve linear system: H_m^{-H}*e_m
2606 Teuchos::RCP<DM> HHt = DMT::CreateCopy( HH, true );
2607 Teuchos::RCP<DM> e_m = DMT::Create( m, 1 );
2608 DMT::SyncDeviceToHost( *HHt );
2609
2610 DMT::Value( *e_m, m-1, 0 ) = one;
2611 lapack.GESV(m, 1, DMT::GetRawHostPtr(*HHt), DMT::GetStride(*HHt), &iperm[0], DMT::GetRawHostPtr(*e_m), DMT::GetStride(*e_m), &info);
2612 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve(): LAPACK GESV failed to compute a solution.");
2613
2614 // Compute H_m + d*H_m^{-H}*e_m*e_m^H
2615 Teuchos::RCP<DM> tmpHH = DMT::CreateCopy( HH );
2616 DMT::SyncDeviceToHost( *tmpHH );
2617
2618 ScalarType d = DMT::ValueConst(*tmpHH, m, m-1) * DMT::ValueConst(*tmpHH, m, m-1);
2619 Teuchos::RCP<DM> harmHH = DMT::Subview( *tmpHH, m, m );
2620 for( i=0; i<m; ++i )
2621 DMT::Value(*harmHH, i, m-1) += d * DMT::ValueConst(*e_m, i, 0);
2622
2623 // Revise to do query for optimal workspace first
2624 // Create simple storage for the left eigenvectors, which we don't care about.
2625 const int ldvl = 1;
2626 ScalarType* vl = 0;
2627
2628 // Size of workspace and workspace for GEEV
2629 int lwork = -1;
2630 std::vector<ScalarType> work(1);
2631 std::vector<MagnitudeType> rwork(2*m);
2632
2633 // First query GEEV for the optimal workspace size
2634 lapack.GEEV('N', 'V', m, DMT::GetRawHostPtr(*harmHH), DMT::GetStride(*harmHH), &wr[0], &wi[0],
2635 vl, ldvl, DMT::GetRawHostPtr(*vr), DMT::GetStride(*vr), &work[0], lwork, &rwork[0], &info);
2636
2637 lwork = std::abs (static_cast<int> (Teuchos::ScalarTraits<ScalarType>::real (work[0])));
2638 work.resize( lwork );
2639
2640 lapack.GEEV('N', 'V', m, DMT::GetRawHostPtr(*harmHH), DMT::GetStride(*harmHH), &wr[0], &wi[0],
2641 vl, ldvl, DMT::GetRawHostPtr(*vr), DMT::GetStride(*vr), &work[0], lwork, &rwork[0], &info);
2642 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, GCRODRSolMgrLAPACKFailure,"Belos::GCRODRSolMgr::solve(): LAPACK GEEV failed to compute eigensolutions.");
2643
2644 // Construct magnitude of each harmonic Ritz value
2645 for( i=0; i<m; ++i )
2646 w[i] = Teuchos::ScalarTraits<MagnitudeType>::squareroot( wr[i]*wr[i] + wi[i]*wi[i] );
2647
2648 // Construct magnitude of each harmonic Ritz value
2649 this->sort(w, m, iperm);
2650
2651 const bool scalarTypeIsComplex = Teuchos::ScalarTraits<ScalarType>::isComplex;
2652
2653 // Select recycledBlocks_ smallest eigenvectors
2654 for( i=0; i<recycledBlocks_; ++i ) {
2655 for( j=0; j<m; j++ ) {
2656 DMT::Value(PP,j,i) = DMT::ValueConst(*vr,j,iperm[i]);
2657 }
2658 }
2659
2660 if(!scalarTypeIsComplex) {
2661
2662 // Determine exact size for PP (i.e., determine if we need to store an additional vector)
2663 if (wi[iperm[recycledBlocks_-1]] != 0.0) {
2664 int countImag = 0;
2665 for ( i=0; i<recycledBlocks_; ++i ) {
2666 if (wi[iperm[i]] != 0.0)
2667 countImag++;
2668 }
2669 // Check to see if this count is even or odd:
2670 if (countImag % 2)
2671 xtraVec = true;
2672 }
2673
2674 if (xtraVec) { // we need to store one more vector
2675 if (wi[iperm[recycledBlocks_-1]] > 0.0) { // I picked the "real" component
2676 for( j=0; j<m; ++j ) { // so get the "imag" component
2677 DMT::Value(PP,j,recycledBlocks_) = DMT::ValueConst(*vr,j,iperm[recycledBlocks_-1]+1);
2678 }
2679 }
2680 else { // I picked the "imag" component
2681 for( j=0; j<m; ++j ) { // so get the "real" component
2682 DMT::Value(PP,j,recycledBlocks_) = DMT::ValueConst(*vr,j,iperm[recycledBlocks_-1]-1);
2683 }
2684 }
2685 }
2686
2687 }
2688
2689 // Return whether we needed to store an additional vector
2690 if (xtraVec) {
2691 return recycledBlocks_+1;
2692 }
2693 else {
2694 return recycledBlocks_;
2695 }
2696
2697}
2698
2699// Compute the harmonic eigenpairs of the projected, dense system.
2700template<class ScalarType, class MV, class OP, class DM>
2701int GCRODRSolMgr<ScalarType,MV,OP,DM,true>::getHarmonicVecs2(int keffloc, int m,
2702 const DM& HH,
2703 const Teuchos::RCP<const MV>& VV,
2704 DM& PP) {
2705 int i, j;
2706 int m2 = DMT::GetNumCols(HH);
2707 bool xtraVec = false;
2708 ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
2709 ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
2710 std::vector<int> index;
2711
2712 // Real and imaginary eigenvalue components
2713 std::vector<MagnitudeType> wr(m2), wi(m2);
2714
2715 // Magnitude of harmonic Ritz values
2716 std::vector<MagnitudeType> w(m2);
2717
2718 // Real and imaginary (right) eigenvectors; Don't zero out matrix when constructing
2719 Teuchos::RCP<DM> vr = DMT::Create(m2,m2,false);
2720
2721 // Sorted order of harmonic Ritz values
2722 std::vector<int> iperm(m2);
2723
2724 // Set flag indicating recycle space has been generated this solve
2725 builtRecycleSpace_ = true;
2726
2727 // Form matrices for generalized eigenproblem
2728
2729 // B = H2' * H2; Don't zero out matrix when constructing
2730 Teuchos::RCP<DM> B = DMT::Create(m2,m2,false);
2731
2732 Teuchos::BLAS<int,ScalarType> blas;
2733 blas.GEMM( Teuchos::TRANS, Teuchos::NO_TRANS, m2, m2, DMT::GetNumRows(HH), one,
2734 DMT::GetConstRawHostPtr(HH), DMT::GetStride(HH),
2735 DMT::GetConstRawHostPtr(HH), DMT::GetStride(HH),
2736 zero, DMT::GetRawHostPtr(*B), DMT::GetStride(*B));
2737
2738 // A_tmp = | C'*U 0 |
2739 // | V_{m+1}'*U I |
2740 Teuchos::RCP<DM> A_tmp = DMT::Create( keffloc+m+1, keffloc+m );
2741
2742 // A_tmp(1:keffloc,1:keffloc) = C' * U;
2743 index.resize(keffloc);
2744 for (i=0; i<keffloc; ++i) { index[i] = i; }
2745 Teuchos::RCP<const MV> Ctmp = MVT::CloneView( *C_, index );
2746 Teuchos::RCP<const MV> Utmp = MVT::CloneView( *U_, index );
2747 Teuchos::RCP<DM> A11 = DMT::Subview( *A_tmp, keffloc, keffloc );
2748 MVT::MvTransMv( one, *Ctmp, *Utmp, *A11 );
2749
2750 // A_tmp(keffloc+1:m-k+keffloc+1,1:keffloc) = V' * U;
2751 Teuchos::RCP<DM> A21 = DMT::Subview( *A_tmp, m+1, keffloc, keffloc );
2752 index.resize(m+1);
2753 for (i=0; i < m+1; i++) { index[i] = i; }
2754 Teuchos::RCP<const MV> Vp = MVT::CloneView( *VV, index );
2755 MVT::MvTransMv( one, *Vp, *Utmp, *A21 );
2756
2757 A11 = Teuchos::null;
2758 A21 = Teuchos::null;
2759 DMT::SyncDeviceToHost(*A_tmp);
2760
2761 // A_tmp(keffloc+1:m-k+keffloc,keffloc+1:m-k+keffloc) = eye(m-k);
2762 for( i=keffloc; i<keffloc+m; i++ ) {
2763 DMT::Value(*A_tmp,i,i) = one;
2764 }
2765
2766 // A = H2' * A_tmp;
2767 Teuchos::RCP<DM> A = DMT::Create( m2, DMT::GetNumCols(*A_tmp) );
2768 blas.GEMM( Teuchos::TRANS, Teuchos::NO_TRANS, m2, DMT::GetNumCols(*A_tmp), DMT::GetNumRows(*A_tmp),
2769 one, DMT::GetConstRawHostPtr(HH), DMT::GetStride(HH),
2770 DMT::GetConstRawHostPtr(*A_tmp), DMT::GetStride(*A_tmp),
2771 zero, DMT::GetRawHostPtr(*A), DMT::GetStride(*A) );
2772
2773 // Compute k smallest harmonic Ritz pairs
2774 // SUBROUTINE DGGEVX( BALANC, JOBVL, JOBVR, SENSE, N, A, LDA, B, LDB,
2775 // ALPHAR, ALPHAI, BETA, VL, LDVL, VR, LDVR, ILO,
2776 // IHI, LSCALE, RSCALE, ABNRM, BBNRM, RCONDE,
2777 // RCONDV, WORK, LWORK, IWORK, BWORK, INFO )
2778 // MLP: 'SCALING' in DGGEVX generates incorrect eigenvalues. Therefore, only permuting
2779 char balanc='P', jobvl='N', jobvr='V', sense='N';
2780 int ld = DMT::GetNumRows(*A);
2781 int lwork = 6*ld;
2782 int ldvl = ld, ldvr = ld;
2783 int info = 0,ilo = 0,ihi = 0;
2784 MagnitudeType abnrm = 0.0, bbnrm = 0.0;
2785 ScalarType *vl = 0; // This is never referenced by dggevx if jobvl == 'N'
2786 std::vector<ScalarType> beta(ld);
2787 std::vector<ScalarType> work(lwork);
2788 std::vector<MagnitudeType> rwork(lwork);
2789 std::vector<MagnitudeType> lscale(ld), rscale(ld);
2790 std::vector<MagnitudeType> rconde(ld), rcondv(ld);
2791 std::vector<int> iwork(ld+6);
2792 int *bwork = 0; // If sense == 'N', bwork is never referenced
2793 //lapack.GGEVX(balanc, jobvl, jobvr, sense, ld, A.values(), ld, B.values(), ld, &wr[0], &wi[0],
2794 // &beta[0], vl, ldvl, vr.values(), ldvr, &ilo, &ihi, &lscale[0], &rscale[0],
2795 // &abnrm, &bbnrm, &rconde[0], &rcondv[0], &work[0], lwork, &iwork[0], bwork, &info);
2796 lapack.GGEVX(balanc, jobvl, jobvr, sense, ld, DMT::GetRawHostPtr(*A), ld, DMT::GetRawHostPtr(*B),
2797 ld, &wr[0], &wi[0], &beta[0], vl, ldvl, DMT::GetRawHostPtr(*vr), ldvr, &ilo, &ihi,
2798 &lscale[0], &rscale[0], &abnrm, &bbnrm, &rconde[0], &rcondv[0], &work[0], lwork, &rwork[0],
2799 &iwork[0], bwork, &info);
2800 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, GCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve(): LAPACK GGEVX failed to compute eigensolutions.");
2801
2802 // Construct magnitude of each harmonic Ritz value
2803 // NOTE : Forming alpha/beta *should* be okay here, given assumptions on construction of matrix pencil above
2804 for( i=0; i<ld; i++ ) {
2805 w[i] = Teuchos::ScalarTraits<MagnitudeType>::squareroot (wr[i]*wr[i] + wi[i]*wi[i]) /
2806 Teuchos::ScalarTraits<ScalarType>::magnitude (beta[i]);
2807 }
2808
2809 // Construct magnitude of each harmonic Ritz value
2810 this->sort(w,ld,iperm);
2811
2812 const bool scalarTypeIsComplex = Teuchos::ScalarTraits<ScalarType>::isComplex;
2813
2814 // Select recycledBlocks_ smallest eigenvectors
2815 for( i=0; i<recycledBlocks_; i++ ) {
2816 for( j=0; j<ld; j++ ) {
2817 DMT::Value(PP,j,i) = DMT::ValueConst(*vr,j,iperm[ld-recycledBlocks_+i]);
2818 }
2819 }
2820
2821 if(!scalarTypeIsComplex) {
2822
2823 // Determine exact size for PP (i.e., determine if we need to store an additional vector)
2824 if (wi[iperm[ld-recycledBlocks_]] != 0.0) {
2825 int countImag = 0;
2826 for ( i=ld-recycledBlocks_; i<ld; i++ ) {
2827 if (wi[iperm[i]] != 0.0)
2828 countImag++;
2829 }
2830 // Check to see if this count is even or odd:
2831 if (countImag % 2)
2832 xtraVec = true;
2833 }
2834
2835 if (xtraVec) { // we need to store one more vector
2836 if (wi[iperm[ld-recycledBlocks_]] > 0.0) { // I picked the "real" component
2837 for( j=0; j<ld; j++ ) { // so get the "imag" component
2838 DMT::Value(PP,j,recycledBlocks_) = DMT::ValueConst(*vr,j,iperm[ld-recycledBlocks_]+1);
2839 }
2840 }
2841 else { // I picked the "imag" component
2842 for( j=0; j<ld; j++ ) { // so get the "real" component
2843 DMT::Value(PP,j,recycledBlocks_) = DMT::ValueConst(*vr,j,iperm[ld-recycledBlocks_]-1);
2844 }
2845 }
2846 }
2847
2848 }
2849
2850 // Return whether we needed to store an additional vector
2851 if (xtraVec) {
2852 return recycledBlocks_+1;
2853 }
2854 else {
2855 return recycledBlocks_;
2856 }
2857
2858}
2859
2860
2861
2862// Compute harmonic Ritz vectors for flexible GCRODR.
2863//
2864// This uses the paper-compatible auxiliary space W:
2865// T = [C, V_{m+1}]
2866// Wfull = [W, V_m]
2867// and forms the small projected pencil
2868// H^H H p = theta H^H (T^H Wfull) p.
2869template<class ScalarType, class MV, class OP, class DM>
2870int
2871GCRODRSolMgr<ScalarType,MV,OP,DM,true>::
2872getFlexibleHarmonicVecs2(int keffloc, int m,
2873 const DM& HH,
2874 const Teuchos::RCP<const MV>& VV,
2875 DM& PP)
2876{
2877 int i, j;
2878 int m2 = DMT::GetNumCols(HH);
2879 bool xtraVec = false;
2880
2881 ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
2882 ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
2883
2884 std::vector<int> index;
2885
2886 std::vector<MagnitudeType> wr(m2), wi(m2);
2887 std::vector<MagnitudeType> w(m2);
2888
2889 Teuchos::RCP<DM> vr = DMT::Create(m2, m2, false);
2890
2891 std::vector<int> iperm(m2);
2892
2893 builtRecycleSpace_ = true;
2894
2895 // B = H^H H.
2896 Teuchos::RCP<DM> B = DMT::Create(m2, m2, false);
2897
2898 Teuchos::BLAS<int,ScalarType> blas;
2899 blas.GEMM(Teuchos::TRANS, Teuchos::NO_TRANS,
2900 m2, m2, DMT::GetNumRows(HH),
2901 one,
2902 DMT::GetConstRawHostPtr(HH), DMT::GetStride(HH),
2903 DMT::GetConstRawHostPtr(HH), DMT::GetStride(HH),
2904 zero,
2905 DMT::GetRawHostPtr(*B), DMT::GetStride(*B));
2906
2907 // A_tmp = T^H Wfull.
2908 Teuchos::RCP<DM> A_tmp = DMT::Create(keffloc + m + 1, keffloc + m);
2909 DMT::PutScalar(*A_tmp, zero);
2910
2911 // A11 = C^H W.
2912 index.resize(keffloc);
2913 for (i=0; i<keffloc; ++i) index[i] = i;
2914
2915 Teuchos::RCP<const MV> Ctmp = MVT::CloneView(*C_, index);
2916 Teuchos::RCP<const MV> Wtmp = MVT::CloneView(*W_, index);
2917 Teuchos::RCP<DM> A11 = DMT::Subview(*A_tmp, keffloc, keffloc);
2918
2919 MVT::MvTransMv(one, *Ctmp, *Wtmp, *A11);
2920
2921 // A21 = V_{m+1}^H W.
2922 Teuchos::RCP<DM> A21 = DMT::Subview(*A_tmp, m+1, keffloc, keffloc);
2923
2924 index.resize(m+1);
2925 for (i=0; i<m+1; ++i) index[i] = i;
2926
2927 Teuchos::RCP<const MV> Vp = MVT::CloneView(*VV, index);
2928
2929 index.resize(keffloc);
2930 for (i=0; i<keffloc; ++i) index[i] = i;
2931
2932 Wtmp = MVT::CloneView(*W_, index);
2933
2934 MVT::MvTransMv(one, *Vp, *Wtmp, *A21);
2935
2936 A11 = Teuchos::null;
2937 A21 = Teuchos::null;
2938
2939 DMT::SyncDeviceToHost(*A_tmp);
2940
2941 // A22 = V_{m+1}^H V_m = [I; 0].
2942 for (i=0; i<m; ++i) {
2943 DMT::Value(*A_tmp, keffloc+i, keffloc+i) = one;
2944 }
2945
2946 // A = H^H A_tmp.
2947 Teuchos::RCP<DM> A = DMT::Create(m2, DMT::GetNumCols(*A_tmp));
2948
2949 blas.GEMM(Teuchos::TRANS, Teuchos::NO_TRANS,
2950 m2, DMT::GetNumCols(*A_tmp), DMT::GetNumRows(*A_tmp),
2951 one,
2952 DMT::GetConstRawHostPtr(HH), DMT::GetStride(HH),
2953 DMT::GetConstRawHostPtr(*A_tmp), DMT::GetStride(*A_tmp),
2954 zero,
2955 DMT::GetRawHostPtr(*A), DMT::GetStride(*A));
2956
2957 char balanc = 'P', jobvl = 'N', jobvr = 'V', sense = 'N';
2958
2959 int ld = DMT::GetNumRows(*A);
2960 int lwork = 6 * ld;
2961 int ldvl = ld, ldvr = ld;
2962 int info = 0, ilo = 0, ihi = 0;
2963
2964 MagnitudeType abnrm = 0.0, bbnrm = 0.0;
2965 ScalarType* vl = 0;
2966
2967 std::vector<ScalarType> beta(ld);
2968 std::vector<ScalarType> work(lwork);
2969 std::vector<MagnitudeType> rwork(lwork);
2970 std::vector<MagnitudeType> lscale(ld), rscale(ld);
2971 std::vector<MagnitudeType> rconde(ld), rcondv(ld);
2972 std::vector<int> iwork(ld+6);
2973 int* bwork = 0;
2974
2975 lapack.GGEVX(balanc, jobvl, jobvr, sense, ld,
2976 DMT::GetRawHostPtr(*A), ld,
2977 DMT::GetRawHostPtr(*B), ld,
2978 &wr[0], &wi[0], &beta[0],
2979 vl, ldvl,
2980 DMT::GetRawHostPtr(*vr), ldvr,
2981 &ilo, &ihi,
2982 &lscale[0], &rscale[0],
2983 &abnrm, &bbnrm,
2984 &rconde[0], &rcondv[0],
2985 &work[0], lwork, &rwork[0],
2986 &iwork[0], bwork, &info);
2987
2989 info != 0,
2990 GCRODRSolMgrLAPACKFailure,
2991 "Belos::GCRODRSolMgr::getFlexibleHarmonicVecs2(): LAPACK GGEVX failed to compute eigensolutions.");
2992
2993 for (i=0; i<ld; ++i) {
2994 w[i] =
2995 Teuchos::ScalarTraits<MagnitudeType>::squareroot(wr[i]*wr[i] + wi[i]*wi[i]) /
2996 Teuchos::ScalarTraits<ScalarType>::magnitude(beta[i]);
2997 }
2998
2999 this->sort(w, ld, iperm);
3000
3001 const bool scalarTypeIsComplex = Teuchos::ScalarTraits<ScalarType>::isComplex;
3002
3003 for (i=0; i<recycledBlocks_; ++i) {
3004 for (j=0; j<ld; ++j) {
3005 DMT::Value(PP, j, i) =
3006 DMT::ValueConst(*vr, j, iperm[ld-recycledBlocks_+i]);
3007 }
3008 }
3009
3010 if (!scalarTypeIsComplex) {
3011 if (wi[iperm[ld-recycledBlocks_]] != 0.0) {
3012 int countImag = 0;
3013 for (i=ld-recycledBlocks_; i<ld; ++i) {
3014 if (wi[iperm[i]] != 0.0) {
3015 countImag++;
3016 }
3017 }
3018
3019 if (countImag % 2) {
3020 xtraVec = true;
3021 }
3022 }
3023
3024 if (xtraVec) {
3025 if (wi[iperm[ld-recycledBlocks_]] > 0.0) {
3026 for (j=0; j<ld; ++j) {
3027 DMT::Value(PP, j, recycledBlocks_) =
3028 DMT::ValueConst(*vr, j, iperm[ld-recycledBlocks_]+1);
3029 }
3030 }
3031 else {
3032 for (j=0; j<ld; ++j) {
3033 DMT::Value(PP, j, recycledBlocks_) =
3034 DMT::ValueConst(*vr, j, iperm[ld-recycledBlocks_]-1);
3035 }
3036 }
3037 }
3038 }
3039
3040 if (xtraVec) {
3041 return recycledBlocks_ + 1;
3042 }
3043 else {
3044 return recycledBlocks_;
3045 }
3046}
3047
3048
3049// This method sorts list of n floating-point numbers and return permutation vector
3050template<class ScalarType, class MV, class OP, class DM>
3051void GCRODRSolMgr<ScalarType,MV,OP,DM,true>::sort(std::vector<MagnitudeType>& dlist, int n, std::vector<int>& iperm) {
3052 int l, r, j, i, flag;
3053 int RR2;
3054 MagnitudeType dRR, dK;
3055
3056 // Initialize the permutation vector.
3057 for(j=0;j<n;j++)
3058 iperm[j] = j;
3059
3060 if (n <= 1) return;
3061
3062 l = n / 2 + 1;
3063 r = n - 1;
3064 l = l - 1;
3065 dRR = dlist[l - 1];
3066 dK = dlist[l - 1];
3067
3068 RR2 = iperm[l - 1];
3069 while (r != 0) {
3070 j = l;
3071 flag = 1;
3072
3073 while (flag == 1) {
3074 i = j;
3075 j = j + j;
3076
3077 if (j > r + 1)
3078 flag = 0;
3079 else {
3080 if (j < r + 1)
3081 if (dlist[j] > dlist[j - 1]) j = j + 1;
3082
3083 if (dlist[j - 1] > dK) {
3084 dlist[i - 1] = dlist[j - 1];
3085 iperm[i - 1] = iperm[j - 1];
3086 }
3087 else {
3088 flag = 0;
3089 }
3090 }
3091 }
3092 dlist[i - 1] = dRR;
3093 iperm[i - 1] = RR2;
3094
3095 if (l == 1) {
3096 dRR = dlist [r];
3097 RR2 = iperm[r];
3098 dK = dlist[r];
3099 dlist[r] = dlist[0];
3100 iperm[r] = iperm[0];
3101 r = r - 1;
3102 }
3103 else {
3104 l = l - 1;
3105 dRR = dlist[l - 1];
3106 RR2 = iperm[l - 1];
3107 dK = dlist[l - 1];
3108 }
3109 }
3110 dlist[0] = dRR;
3111 iperm[0] = RR2;
3112}
3113
3114
3115template<class ScalarType, class MV, class OP, class DM>
3117 std::ostringstream out;
3118 out << "Belos::GCRODRSolMgr<...,"<<Teuchos::ScalarTraits<ScalarType>::name()<<">";
3119 out << "{";
3120 out << "Ortho Type: \"" << orthoType_ << "\"";
3121 out << ", Flexible: " << (isFlexible_ ? "true" : "false");
3122 out << ", Num Blocks: " <<numBlocks_;
3123 out << ", Num Recycle Blocks: " << recycledBlocks_;
3124 out << ", Max Restarts: " << maxRestarts_;
3125 out << "}";
3126 return out.str ();
3127}
3128
3129} // namespace Belos
3130
3131#endif /* BELOS_GCRODR_SOLMGR_HPP */
Belos header file which uses auto-configuration information to include necessary C++ headers.
Belos concrete class for performing the flexible GCRO-DR iteration.
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...
Teuchos::Array< Teuchos::RCP< Teuchos::Time > > getTimers() const
Return the timers for this object.
const LinearProblem< ScalarType, MV, OP, DM > & getProblem() const override
Get current linear problem being solved for in this object.
Teuchos::RCP< const Teuchos::ParameterList > getCurrentParameters() const override
Get a parameter list containing the current parameters for this object.
bool isLOADetected() const override
Return whether a loss of accuracy was detected by this solver during the most current solve.
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, DM > > clone() const override
clone for Inverted Injection (DII)
void setProblem(const Teuchos::RCP< LinearProblem< ScalarType, MV, OP, DM > > &problem) override
Set the linear problem that needs to be solved.
int getNumIters() const override
Get the iteration count for the most recent call to solve().
MagnitudeType achievedTol() const override
Tolerance achieved by the last solve() invocation.
Implementation of the GCRODR (Recycling GMRES) iterative linear solver.
GCRODRSolMgr(const Teuchos::RCP< LinearProblem< ScalarType, MV, OP, DM > > &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