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