Belos Package Browser (Single Doxygen Collection)  Development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BelosBlockGCRODRSolMgr.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Belos: Block Linear Solvers Package
4 //
5 // Copyright 2004-2016 NTESS and the Belos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
13 #ifndef BELOS_BLOCK_GCRODR_SOLMGR_HPP
14 #define BELOS_BLOCK_GCRODR_SOLMGR_HPP
15 
16 #include "BelosConfigDefs.hpp"
17 #include "BelosTypes.hpp"
19 #include "BelosLinearProblem.hpp"
20 #include "BelosSolverManager.hpp"
21 #include "BelosGmresIteration.hpp"
22 #include "BelosBlockGCRODRIter.hpp"
23 #include "BelosBlockGmresIter.hpp"
24 #include "BelosBlockFGmresIter.hpp"
27 #include "BelosStatusTestCombo.hpp"
29 #include "BelosOutputManager.hpp"
30 #include "Teuchos_LAPACK.hpp"
31 #include "Teuchos_as.hpp"
32 #ifdef BELOS_TEUCHOS_TIME_MONITOR
33 #include "Teuchos_TimeMonitor.hpp"
34 #endif // BELOS_TEUCHOS_TIME_MONITOR
35 
36 // MLP: Add links to examples here
37 
38 namespace Belos{
39 
41 
42 
48  public:
49  BlockGCRODRSolMgrLinearProblemFailure(const std::string& what_arg) : BelosError(what_arg) {}
50  };
51 
57  public:
58  BlockGCRODRSolMgrOrthoFailure(const std::string& what_arg) : BelosError(what_arg) {}
59  };
60 
66  public:
67  BlockGCRODRSolMgrLAPACKFailure(const std::string& what_arg) : BelosError(what_arg) {}
68  };
69 
75  public:
76  BlockGCRODRSolMgrRecyclingFailure(const std::string& what_arg) : BelosError(what_arg) {}
77  };
78 
80 
92 
93 template<class ScalarType, class MV, class OP>
94 class BlockGCRODRSolMgr : public SolverManager<ScalarType, MV, OP> {
95 private:
96 
106 
107 public:
109 
110 
117 
145 
147  virtual ~BlockGCRODRSolMgr() {};
149 
152 
154  std::string description() const;
155 
157 
158 
160 
161 
164  return *problem_;
165  }
166 
169 
172 
175  return achievedTol_;
176  }
177 
179  int getNumIters() const { return numIters_; }
180 
182  bool isLOADetected() const { return loaDetected_; }
183 
185 
187 
188 
191  TEUCHOS_TEST_FOR_EXCEPTION(problem.is_null(), std::invalid_argument,
192  "Belos::BlockGCRODRSolMgr::setProblem: The input LinearProblem cannot be null.");
193 
194  // Check state of problem object before proceeding
195  if (! problem->isProblemSet()) {
196  const bool success = problem->setProblem();
197  TEUCHOS_TEST_FOR_EXCEPTION(success, std::runtime_error,
198  "Belos::BlockGCRODRSolMgr::setProblem: Calling the input LinearProblem's setProblem() method failed. This likely means that the "
199  "LinearProblem has a missing (null) matrix A, solution vector X, or right-hand side vector B. Please set these items in the LinearProblem and try again.");
200  }
201 
202  problem_ = problem;
203  }
204 
207 
209 
211 
212 
219  void reset (const ResetType type) {
220  if ((type & Belos::Problem) && ! problem_.is_null ())
221  problem_->setProblem();
222  else if (type & Belos::RecycleSubspace)
223  keff = 0;
224  }
225 
227 
229 
230 
246  // \returns ::ReturnType specifying:
249  ReturnType solve();
250 
252 
253 private:
254 
255  // Called by all constructors; Contains init instructions common to all constructors
256  void init();
257 
258  // Initialize solver state storage
259  void initializeStateStorage();
260 
261  // Recycling Methods
262  // Appending Function name by:
263  // "Kryl" indicates it is specialized for building a recycle space after an
264  // initial run of Block GMRES which generates an initial unaugmented block Krylov subspace
265  // "AugKryl" indicates it is specialized for building a recycle space from the augmented Krylov subspace
266 
267  // Functions which control the building of a recycle space
270 
271  // Recycling with Harmonic Ritz Vectors
272  // Computes harmonic eigenpairs of projected matrix created during the priming solve.
273  // The return value is the number of vectors needed to be stored, recycledBlocks or recycledBlocks+1.
274 
275  // HH is the projected problem from the initial cycle of Gmres, it is (at least) of dimension (numBlocks+1)*blockSize x numBlocks.
276  // PP contains the harmonic eigenvectors corresponding to the recycledBlocks eigenvalues of smallest magnitude.
277  int getHarmonicVecsKryl (int m, const SDM& HH, SDM& PP);
278 
279  // HH is the total block projected problem from the GCRO-DR algorithm, it is (at least) of dimension keff+(numBlocks+1)*blockSize x keff+numBlocksm.
280  // VV is the Krylov vectors from the projected GMRES algorithm, which has (at least) (numBlocks+1)*blockSize vectors.
281  // PP contains the harmonic eigenvectors corresponding to the recycledBlocks eigenvalues of smallest magnitude.
282  int getHarmonicVecsAugKryl (int keff,
283  int m,
284  const SDM& HH,
285  const Teuchos::RCP<const MV>& VV,
286  SDM& PP);
287 
288  // Sort list of n floating-point numbers and return permutation vector
289  void sort (std::vector<MagnitudeType>& dlist, int n, std::vector<int>& iperm);
290 
291  // Lapack interface
293 
296 
297  //Output Manager
300 
301  //Status Test
307 
310 
317 
320 
332 
333  //Default Solver Values
334  static const bool adaptiveBlockSize_default_;
335  static const std::string recycleMethod_default_;
336 
337  //Current Solver Values
344  std::string label_;
345 
347  // Solver State Storage
349  //
350  // The number of blocks and recycle blocks (m and k, respectively)
352  // Current size of recycled subspace
353  int keff;
354  //
355  // Residual Vector
357  //
358  // Search Space
360  //
361  // Recycle subspace and its image under action of the operator
363  //
364  // Updated recycle Space and its image under action of the operator
366  //
367  // Storage used in constructing recycle space
373  std::vector<ScalarType> tau_;
374  std::vector<ScalarType> work_;
376  std::vector<int> ipiv_;
377 
380 
382  bool isSet_;
383 
386 
389 };
390 
391  //
392  // Set default solver values
393  //
394  template<class ScalarType, class MV, class OP>
396 
397  template<class ScalarType, class MV, class OP>
399 
400  //
401  // Method definitions
402  //
403 
404  template<class ScalarType, class MV, class OP>
406  init();
407  }
408 
409  //Basic Constructor
410  template<class ScalarType, class MV, class OP>
414  // Initialize local pointers to null, and initialize local
415  // variables to default values.
416  init ();
417 
418  TEUCHOS_TEST_FOR_EXCEPTION(problem.is_null(), std::invalid_argument,
419  "Belos::BlockGCRODR constructor: The solver manager's constructor needs "
420  "the linear problem argument 'problem' to be nonnull.");
421 
422  problem_ = problem;
423 
424  // Set the parameters using the list that was passed in. If null, we defer initialization until a non-null list is set (by the
425  // client calling setParameters(), or by calling solve() -- in either case, a null parameter list indicates that default parameters should be used).
426  if (! pl.is_null())
427  setParameters (pl);
428  }
429 
430  template<class ScalarType, class MV, class OP>
432  adaptiveBlockSize_ = adaptiveBlockSize_default_;
433  recycleMethod_ = recycleMethod_default_;
434  isSet_ = false;
435  loaDetected_ = false;
436  builtRecycleSpace_ = false;
437  keff = 0;//Effective Size of Recycle Space
438  //The following are all RCP smart pointers to indicated matrices/vectors.
439  //Some MATLAB notation used in comments.
440  R_ = Teuchos::null;//The Block Residual
441  V_ = Teuchos::null;//Block Arnoldi Vectors
442  U_ = Teuchos::null;//Recycle Space
443  C_ = Teuchos::null;//Image of U Under Action of Operator
444  U1_ = Teuchos::null;//Newly Computed Recycle Space
445  C1_ = Teuchos::null;//Image of Newly Computed Recycle Space
446  PP_ = Teuchos::null;//Coordinates of New Recyc. Vectors in Augmented Space
447  HP_ = Teuchos::null;//H_*PP_ or G_*PP_
448  G_ = Teuchos::null;//G_ such that A*[U V(:,1:numBlocks_*blockSize_)] = [C V_]*G_
449  F_ = Teuchos::null;//Upper Triangular portion of QR factorization for HP_
450  H_ = Teuchos::null;//H_ such that A*V(:,1:numBlocks_*blockSize_) = V_*H_ + C_*C_'*V_
451  B_ = Teuchos::null;//B_ = C_'*V_
452 
453  //THIS BLOCK OF CODE IS COMMENTED OUT AND PLACED ELSEWHERE IN THE CODE
454 /*
455  //WE TEMPORARILY INITIALIZE STATUS TESTS HERE FOR TESTING PURPOSES, BUT THEY SHOULD BE
456  //INITIALIZED SOMEWHERE ELSE, LIKE THE setParameters() FUNCTION
457 
458  //INSTANTIATE AND INITIALIZE TEST OBJECTS AS NEEDED
459  if (maxIterTest_.is_null()){
460  maxIterTest_ = rcp (new StatusTestMaxIters<ScalarType,MV,OP> (maxIters_));
461  }
462  //maxIterTest_->setMaxIters (maxIters_);
463 
464  //INSTANTIATE THE PRINTER
465  if (printer_.is_null()) {
466  printer_ = Teuchos::rcp (new OutputManager<ScalarType> (verbosity_, outputStream_));
467  }
468 
469  if (ortho_.is_null()) // || changedOrthoType) %%%In other codes, this is also triggered if orthogonalization type changed {
470  // Create orthogonalization manager. This requires that the OutputManager (printer_) already be initialized.
471  Teuchos::RCP<const Teuchos::ParameterList> orthoParams = orthoFactory_.getDefaultParameters (orthoType_);
472  ortho_ = orthoFactory_.makeMatOrthoManager (orthoType_, Teuchos::null, printer_, label_, orthoParams);
473  }
474 
475  // Convenience typedefs
476  typedef Belos::StatusTestCombo<ScalarType,MV,OP> StatusTestCombo_t;
477  typedef Belos::StatusTestGenResNorm<ScalarType,MV,OP> StatusTestResNorm_t;
478 
479  if (impConvTest_.is_null()) {
480  impConvTest_ = rcp (new StatusTestResNorm_t (convTol_));
481  impConvTest_->defineScaleForm (convertStringToScaleType (impResScale_), Belos::TwoNorm);
482  impConvTest_->setShowMaxResNormOnly( true );
483  }
484 
485  if (expConvTest_.is_null()) {
486  expConvTest_ = rcp (new StatusTestResNorm_t (convTol_));
487  expConvTest_->defineResForm (StatusTestResNorm_t::Explicit, Belos::TwoNorm);
488  expConvTest_->defineScaleForm (convertStringToScaleType (expResScale_), Belos::TwoNorm);
489  expConvTest_->setShowMaxResNormOnly( true );
490  }
491 
492  if (convTest_.is_null()) {
493  convTest_ = rcp (new StatusTestCombo_t (StatusTestCombo_t::SEQ, impConvTest_, expConvTest_));
494  }
495 
496  sTest_ = rcp (new StatusTestCombo_t (StatusTestCombo_t::OR, maxIterTest_, convTest_));
497 
498  StatusTestOutputFactory<ScalarType,MV,OP> stoFactory (outputStyle_);
499  outputTest_ = stoFactory.create (printer_, sTest_, outputFreq_,
500  Passed+Failed+Undefined);
501 
502  */
503 
504  }
505 
506  // This method requires the solver manager to return a string that describes itself.
507  template<class ScalarType, class MV, class OP>
509  std::ostringstream oss;
510  oss << "Belos::BlockGCRODRSolMgr<" << SCT::name() << ", ...>";
511  oss << "{";
512  oss << "Ortho Type='"<<orthoType_ ;
513  oss << ", Num Blocks=" <<numBlocks_;
514  oss << ", Block Size=" <<blockSize_;
515  oss << ", Num Recycle Blocks=" << recycledBlocks_;
516  oss << ", Max Restarts=" << maxRestarts_;
517  oss << "}";
518  return oss.str();
519  }
520 
521  template<class ScalarType, class MV, class OP>
525  using Teuchos::parameterList;
526  using Teuchos::RCP;
527  using Teuchos::rcpFromRef;
528 
529  if (defaultParams_.is_null()) {
530  RCP<ParameterList> pl = parameterList ();
531 
532  const MagnitudeType convTol = SMT::squareroot (SCT::magnitude (SCT::eps()));
533  const int maxRestarts = 1000;
534  const int maxIters = 5000;
535  const int blockSize = 2;
536  const int numBlocks = 100;
537  const int numRecycledBlocks = 25;
539  const Belos::OutputType outputStyle = Belos::General;
540  const int outputFreq = 1;
541  RCP<std::ostream> outputStream = rcpFromRef (std::cout);
542  const std::string impResScale ("Norm of Preconditioned Initial Residual");
543  const std::string expResScale ("Norm of Initial Residual");
544  const std::string timerLabel ("Belos");
545  const std::string orthoType ("ICGS");
546  RCP<const ParameterList> orthoParams = orthoFactory_.getDefaultParameters (orthoType);
547  //const MagnitudeType orthoKappa = SCT::magnitude (SCT::eps());
548  //
549  // mfh 31 Dec 2011: Negative values of orthoKappa are ignored.
550  // Setting this to a negative value by default ensures that
551  // this parameter is only _not_ ignored if the user
552  // specifically sets a valid value.
553  const MagnitudeType orthoKappa = -SMT::one();
554 
555  // Set all the valid parameters and their default values.
556  pl->set ("Convergence Tolerance", convTol,
557  "The tolerance that the solver needs to achieve in order for "
558  "the linear system(s) to be declared converged. The meaning "
559  "of this tolerance depends on the convergence test details.");
560  pl->set("Maximum Restarts", maxRestarts,
561  "The maximum number of restart cycles (not counting the first) "
562  "allowed for each set of right-hand sides solved.");
563  pl->set("Maximum Iterations", maxIters,
564  "The maximum number of iterations allowed for each set of "
565  "right-hand sides solved.");
566  pl->set("Block Size", blockSize,
567  "How many linear systems to solve at once.");
568  pl->set("Num Blocks", numBlocks,
569  "The maximum number of blocks allowed in the Krylov subspace "
570  "for each set of right-hand sides solved. This includes the "
571  "initial block. Total Krylov basis storage, not counting the "
572  "recycled subspace, is \"Num Blocks\" times \"Block Size\".");
573  pl->set("Num Recycled Blocks", numRecycledBlocks,
574  "The maximum number of vectors in the recycled subspace." );
575  pl->set("Verbosity", verbosity,
576  "What type(s) of solver information should be written "
577  "to the output stream.");
578  pl->set("Output Style", outputStyle,
579  "What style is used for the solver information to write "
580  "to the output stream.");
581  pl->set("Output Frequency", outputFreq,
582  "How often convergence information should be written "
583  "to the output stream.");
584  pl->set("Output Stream", outputStream,
585  "A reference-counted pointer to the output stream where all "
586  "solver output is sent.");
587  pl->set("Implicit Residual Scaling", impResScale,
588  "The type of scaling used in the implicit residual convergence test.");
589  pl->set("Explicit Residual Scaling", expResScale,
590  "The type of scaling used in the explicit residual convergence test.");
591  pl->set("Timer Label", timerLabel,
592  "The string to use as a prefix for the timer labels.");
593  pl->set("Orthogonalization", orthoType,
594  "The orthogonalization method to use. Valid options: " +
595  orthoFactory_.validNamesString());
596  pl->set ("Orthogonalization Parameters", *orthoParams,
597  "Sublist of parameters specific to the orthogonalization method to use.");
598  pl->set("Orthogonalization Constant", orthoKappa,
599  "When using DGKS orthogonalization: the \"depTol\" constant, used "
600  "to determine whether another step of classical Gram-Schmidt is "
601  "necessary. Otherwise ignored. Nonpositive values are ignored.");
602  defaultParams_ = pl;
603  }
604  return defaultParams_;
605  }
606 
607  template<class ScalarType, class MV, class OP>
608  void
611  using Teuchos::isParameterType;
612  using Teuchos::getParameter;
613  using Teuchos::null;
615  using Teuchos::parameterList;
616  using Teuchos::RCP;
617  using Teuchos::rcp;
618  using Teuchos::rcp_dynamic_cast;
619  using Teuchos::rcpFromRef;
623 
624  // The default parameter list contains all parameters that BlockGCRODRSolMgr understands, and none that it doesn't
625  RCP<const ParameterList> defaultParams = getValidParameters();
626 
627  if (params.is_null()) {
628  // Users really should supply a non-null input ParameterList,
629  // so that we can fill it in. However, if they really did give
630  // us a null list, be nice and use default parameters. In this
631  // case, we don't have to do any validation.
632  params_ = parameterList (*defaultParams);
633  }
634  else {
635  // Validate the user's parameter list and fill in any missing parameters with default values.
636  //
637  // Currently, validation is quite strict. The following line
638  // will throw an exception for misspelled or extra parameters.
639  // However, it will _not_ throw an exception if there are
640  // missing parameters: these will be filled in with their
641  // default values. There is additional discussion of other
642  // validation strategies in the comments of this function for
643  // Belos::GCRODRSolMgr.
644  params->validateParametersAndSetDefaults (*defaultParams);
645  // No side effects on the solver until after validation passes.
646  params_ = params;
647  }
648 
649  //
650  // Validate and set parameters relating to the Krylov subspace
651  // dimensions and the number of blocks.
652  //
653  // We try to read and validate all these parameters' values
654  // before setting them in the solver. This is because the
655  // validity of each may depend on the others' values. Our goal
656  // is to avoid incorrect side effects, so we don't set the values
657  // in the solver until we know they are right.
658  //
659  {
660  const int maxRestarts = params_->get<int> ("Maximum Restarts");
661  TEUCHOS_TEST_FOR_EXCEPTION(maxRestarts <= 0, std::invalid_argument,
662  "Belos::BlockGCRODRSolMgr: The \"Maximum Restarts\" parameter "
663  "must be nonnegative, but you specified a negative value of "
664  << maxRestarts << ".");
665 
666  const int maxIters = params_->get<int> ("Maximum Iterations");
667  TEUCHOS_TEST_FOR_EXCEPTION(maxIters <= 0, std::invalid_argument,
668  "Belos::BlockGCRODRSolMgr: The \"Maximum Iterations\" parameter "
669  "must be positive, but you specified a nonpositive value of "
670  << maxIters << ".");
671 
672  const int numBlocks = params_->get<int> ("Num Blocks");
673  TEUCHOS_TEST_FOR_EXCEPTION(numBlocks <= 0, std::invalid_argument,
674  "Belos::BlockGCRODRSolMgr: The \"Num Blocks\" parameter must be "
675  "positive, but you specified a nonpositive value of " << numBlocks
676  << ".");
677 
678  const int blockSize = params_->get<int> ("Block Size");
679  TEUCHOS_TEST_FOR_EXCEPTION(blockSize <= 0, std::invalid_argument,
680  "Belos::BlockGCRODRSolMgr: The \"Block Size\" parameter must be "
681  "positive, but you specified a nonpositive value of " << blockSize
682  << ".");
683 
684  const int recycledBlocks = params_->get<int> ("Num Recycled Blocks");
685  TEUCHOS_TEST_FOR_EXCEPTION(recycledBlocks <= 0, std::invalid_argument,
686  "Belos::BlockGCRODRSolMgr: The \"Num Recycled Blocks\" parameter must "
687  "be positive, but you specified a nonpositive value of "
688  << recycledBlocks << ".");
689  TEUCHOS_TEST_FOR_EXCEPTION(recycledBlocks >= numBlocks,
690  std::invalid_argument, "Belos::BlockGCRODRSolMgr: The \"Num Recycled "
691  "Blocks\" parameter must be less than the \"Num Blocks\" parameter, "
692  "but you specified \"Num Recycled Blocks\" = " << recycledBlocks
693  << " and \"Num Blocks\" = " << numBlocks << ".");
694 
695  // Now that we've validated the various dimension-related
696  // parameters, we can set them in the solvers.
697  maxRestarts_ = maxRestarts;
698  maxIters_ = maxIters;
699  numBlocks_ = numBlocks;
700  blockSize_ = blockSize;
701  recycledBlocks_ = recycledBlocks;
702  }
703 
704  // Check to see if the timer label changed. If it did, update it in
705  // the parameter list, and create a new timer with that label (if
706  // Belos was compiled with timers enabled).
707  {
708  std::string tempLabel = params_->get<std::string> ("Timer Label");
709  const bool labelChanged = (tempLabel != label_);
710 
711 #ifdef BELOS_TEUCHOS_TIME_MONITOR
712  std::string solveLabel = label_ + ": BlockGCRODRSolMgr total solve time";
713  if (timerSolve_.is_null()) {
714  // We haven't created a timer yet.
715  timerSolve_ = Teuchos::TimeMonitor::getNewCounter (solveLabel);
716  } else if (labelChanged) {
717  // We created a timer before with a different label. In that
718  // case, clear the old timer and create a new timer with the
719  // new label. Clearing old timers prevents them from piling
720  // up, since they are stored statically, possibly without
721  // checking for duplicates.
723  timerSolve_ = Teuchos::TimeMonitor::getNewCounter (solveLabel);
724  }
725 #endif // BELOS_TEUCHOS_TIME_MONITOR
726  }
727 
728  // Check for a change in verbosity level. Just in case, we allow
729  // the type of this parameter to be either int or MsgType (an
730  // enum).
731  if (params_->isParameter ("Verbosity")) {
732  if (isParameterType<int> (*params_, "Verbosity")) {
733  verbosity_ = params_->get<int> ("Verbosity");
734  }
735  else {
736  verbosity_ = (int) getParameter<MsgType> (*params_, "Verbosity");
737  }
738  }
739 
740  // Check for a change in output style. Just in case, we allow
741  // the type of this parameter to be either int or OutputType (an
742  // enum).
743  if (params_->isParameter ("Output Style")) {
744  if (isParameterType<int> (*params_, "Output Style")) {
745  outputStyle_ = params_->get<int> ("Output Style");
746  }
747  else {
748  outputStyle_ = (int) getParameter<OutputType> (*params_, "Output Style");
749  }
750 
751  // Currently, the only way we can update the output style is to
752  // create a new output test. This is because we must first
753  // instantiate a new StatusTestOutputFactory with the new
754  // style, and then use the factory to make a new output test.
755  // Thus, we set outputTest_ to null for now, so we remember
756  // later to create a new one.
757  outputTest_ = null;
758  }
759 
760  // Get the output stream for the output manager.
761  //
762  // It has been pointed out (mfh 28 Feb 2011 in GCRODRSolMgr code)
763  // that including an RCP<std::ostream> parameter makes it
764  // impossible to serialize the parameter list. If you serialize
765  // the list and read it back in from the serialized
766  // representation, you might not even get a valid
767  // RCP<std::ostream>, let alone the same output stream that you
768  // serialized.
769  //
770  // However, existing Belos users depend on setting the output
771  // stream in the parameter list. We retain this behavior for
772  // backwards compatibility.
773  //
774  // In case the output stream can't be read back in, we default to
775  // stdout (std::cout), just to ensure reasonable behavior.
776  if (params_->isParameter ("Output Stream")) {
777  try {
778  outputStream_ = getParameter<RCP<std::ostream> > (*params_, "Output Stream");
779  }
780  catch (InvalidParameter&) {
781  outputStream_ = rcpFromRef (std::cout);
782  }
783  // We assume that a null output stream indicates that the user
784  // doesn't want to print anything, so we replace it with a
785  // "black hole" stream that prints nothing sent to it. (We
786  // can't use outputStream_ = Teuchos::null, since the output
787  // manager assumes that operator<< works on its output stream.)
788  if (outputStream_.is_null()) {
789  outputStream_ = rcp (new Teuchos::oblackholestream);
790  }
791  }
792 
793  outputFreq_ = params_->get<int> ("Output Frequency");
794  if (verbosity_ & Belos::StatusTestDetails) {
795  // Update parameter in our output status test.
796  if (! outputTest_.is_null()) {
797  outputTest_->setOutputFrequency (outputFreq_);
798  }
799  }
800 
801  // Create output manager if we need to, using the verbosity level
802  // and output stream that we fetched above. We do this here because
803  // instantiating an OrthoManager using OrthoManagerFactory requires
804  // a valid OutputManager.
805  if (printer_.is_null()) {
806  printer_ = rcp (new OutputManager<ScalarType> (verbosity_, outputStream_));
807  } else {
808  printer_->setVerbosity (verbosity_);
809  printer_->setOStream (outputStream_);
810  }
811 
812  // Get the orthogonalization manager name ("Orthogonalization").
813  //
814  // Getting default values for the orthogonalization manager
815  // parameters ("Orthogonalization Parameters") requires knowing the
816  // orthogonalization manager name. Save it for later, and also
817  // record whether it's different than before.
818 
819  //bool changedOrthoType = false; // silence warning about not being used
820  if (params_->isParameter ("Orthogonalization")) {
821  const std::string& tempOrthoType =
822  params_->get<std::string> ("Orthogonalization");
823  // Ensure that the specified orthogonalization type is valid.
824  if (! orthoFactory_.isValidName (tempOrthoType)) {
825  std::ostringstream os;
826  os << "Belos::BlockGCRODRSolMgr: Invalid orthogonalization name \""
827  << tempOrthoType << "\". The following are valid options "
828  << "for the \"Orthogonalization\" name parameter: ";
829  orthoFactory_.printValidNames (os);
830  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, os.str());
831  }
832  if (tempOrthoType != orthoType_) {
833  //changedOrthoType = true;
834  orthoType_ = tempOrthoType;
835  }
836  }
837 
838  // Get any parameters for the orthogonalization
839  // ("Orthogonalization Parameters"). If not supplied, the
840  // orthogonalization manager factory will supply default values.
841  //
842  // NOTE (mfh 12 Jan 2011, summer 2011, 31 Dec 2011) For backwards
843  // compatibility with other Belos GMRES-type solvers, if params
844  // has an "Orthogonalization Constant" parameter and the DGKS
845  // orthogonalization manager is to be used, the value of this
846  // parameter will override DGKS's "depTol" parameter.
847  //
848  // Users must supply the orthogonalization manager parameters as
849  // a sublist (supplying it as an RCP<ParameterList> would make
850  // the resulting parameter list not serializable).
851  RCP<ParameterList> orthoParams = sublist (params, "Orthogonalization Parameters", true);
852  TEUCHOS_TEST_FOR_EXCEPTION(orthoParams.is_null(), std::logic_error,
853  "Failed to get orthogonalization parameters. "
854  "Please report this bug to the Belos developers.");
855 
856  // Check if the desired orthogonalization method changed, or if
857  // the orthogonalization manager has not yet been instantiated.
858  // If either is the case, instantiate a new MatOrthoManager
859  // subclass instance corresponding to the desired
860  // orthogonalization method. We've already fetched the
861  // orthogonalization method name (orthoType_) and its parameters
862  // (orthoParams) above.
863  //
864  // As suggested (by mfh 12 Jan 2011 in Belos::GCRODRSolMgr) In
865  // order to ensure parameter changes get propagated to the
866  // orthomanager we simply reinstantiate the OrthoManager every
867  // time, whether or not the orthogonalization method name or
868  // parameters have changed. This is not efficient for some
869  // orthogonalization managers that keep a lot of internal state.
870  // A more general way to fix this inefficiency would be to
871  //
872  // 1. make each orthogonalization implement
873  // Teuchos::ParameterListAcceptor, and
874  //
875  // 2. make each orthogonalization implement a way to set the
876  // OutputManager instance and timer label.
877  //
878  // Create orthogonalization manager. This requires that the
879  // OutputManager (printer_) already be initialized.
880  ortho_ = orthoFactory_.makeMatOrthoManager (orthoType_, null, printer_,
881  label_, orthoParams);
882 
883  // The DGKS orthogonalization accepts a "Orthogonalization
884  // Constant" parameter (also called kappa in the code, but not in
885  // the parameter list). If its value is provided in the given
886  // parameter list and its value is positive, use it. Ignore
887  // negative values.
888  //
889  // The "Orthogonalization Constant" parameter is retained only
890  // for backwards compatibility.
891 
892  //bool gotValidOrthoKappa = false; // silence warning about not being used
893  if (params_->isParameter ("Orthogonalization Constant")) {
894  const MagnitudeType orthoKappa =
895  params_->get<MagnitudeType> ("Orthogonalization Constant");
896  if (orthoKappa > 0) {
897  orthoKappa_ = orthoKappa;
898  //gotValidOrthoKappa = true;
899  // Only DGKS currently accepts this parameter.
900  if (orthoType_ == "DGKS" && ! ortho_.is_null()) {
901  typedef DGKSOrthoManager<ScalarType, MV, OP> ortho_man_type;
902  // This cast should always succeed; it's a bug otherwise.
903  // (If the cast fails, then orthoType_ doesn't correspond
904  // to the OrthoManager subclass instance that we think we
905  // have, so we initialized the wrong subclass somehow.)
906  rcp_dynamic_cast<ortho_man_type>(ortho_)->setDepTol (orthoKappa_);
907  }
908  }
909  }
910 
911  // Convergence
912  typedef Belos::StatusTestCombo<ScalarType,MV,OP> StatusTestCombo_t;
913  typedef Belos::StatusTestGenResNorm<ScalarType,MV,OP> StatusTestResNorm_t;
914 
915  // Check for convergence tolerance
916  convTol_ = params_->get<MagnitudeType> ("Convergence Tolerance");
917  if (! impConvTest_.is_null()) {
918  impConvTest_->setTolerance (convTol_);
919  }
920  if (! expConvTest_.is_null()) {
921  expConvTest_->setTolerance (convTol_);
922  }
923 
924  // Check for a change in scaling, if so we need to build new residual tests.
925  if (params_->isParameter ("Implicit Residual Scaling")) {
926  std::string tempImpResScale =
927  getParameter<std::string> (*params_, "Implicit Residual Scaling");
928 
929  // Only update the scaling if it's different.
930  if (impResScale_ != tempImpResScale) {
931  ScaleType impResScaleType = convertStringToScaleType (tempImpResScale);
932  impResScale_ = tempImpResScale;
933 
934  if (! impConvTest_.is_null()) {
935  try {
936  impConvTest_->defineScaleForm (impResScaleType, Belos::TwoNorm);
937  }
938  catch (StatusTestError&) {
939  // Delete the convergence test so it gets constructed again.
940  impConvTest_ = null;
941  convTest_ = null;
942  }
943  }
944  }
945  }
946 
947  if (params_->isParameter("Explicit Residual Scaling")) {
948  std::string tempExpResScale =
949  getParameter<std::string> (*params_, "Explicit Residual Scaling");
950 
951  // Only update the scaling if it's different.
952  if (expResScale_ != tempExpResScale) {
953  ScaleType expResScaleType = convertStringToScaleType (tempExpResScale);
954  expResScale_ = tempExpResScale;
955 
956  if (! expConvTest_.is_null()) {
957  try {
958  expConvTest_->defineScaleForm (expResScaleType, Belos::TwoNorm);
959  }
960  catch (StatusTestError&) {
961  // Delete the convergence test so it gets constructed again.
962  expConvTest_ = null;
963  convTest_ = null;
964  }
965  }
966  }
967  }
968 
969  //
970  // Create iteration stopping criteria ("status tests") if we need
971  // to, by combining three different stopping criteria.
972  //
973  // First, construct maximum-number-of-iterations stopping criterion.
974  if (maxIterTest_.is_null()) {
975  maxIterTest_ = rcp (new StatusTestMaxIters<ScalarType,MV,OP> (maxIters_));
976  } else {
977  maxIterTest_->setMaxIters (maxIters_);
978  }
979 
980  // Implicit residual test, using the native residual to determine if
981  // convergence was achieved.
982  if (impConvTest_.is_null()) {
983  impConvTest_ = rcp (new StatusTestResNorm_t (convTol_));
984  impConvTest_->defineScaleForm (convertStringToScaleType (impResScale_),
986  }
987 
988  // Explicit residual test once the native residual is below the tolerance
989  if (expConvTest_.is_null()) {
990  expConvTest_ = rcp (new StatusTestResNorm_t (convTol_));
991  expConvTest_->defineResForm (StatusTestResNorm_t::Explicit, Belos::TwoNorm);
992  expConvTest_->defineScaleForm (convertStringToScaleType (expResScale_),
994  }
995  // Convergence test first tests the implicit residual, then the
996  // explicit residual if the implicit residual test passes.
997  if (convTest_.is_null()) {
998  convTest_ = rcp (new StatusTestCombo_t (StatusTestCombo_t::SEQ,
999  impConvTest_,
1000  expConvTest_));
1001  }
1002  // Construct the complete iteration stopping criterion:
1003  //
1004  // "Stop iterating if the maximum number of iterations has been
1005  // reached, or if the convergence test passes."
1006  sTest_ = rcp (new StatusTestCombo_t (StatusTestCombo_t::OR,
1007  maxIterTest_, convTest_));
1008  // Create the status test output class.
1009  // This class manages and formats the output from the status test.
1010  StatusTestOutputFactory<ScalarType,MV,OP> stoFactory (outputStyle_);
1011  outputTest_ = stoFactory.create (printer_, sTest_, outputFreq_,
1013 
1014  // Set the solver string for the output test
1015  std::string solverDesc = "Block GCRODR ";
1016  outputTest_->setSolverDesc (solverDesc);
1017 
1018  // Inform the solver manager that the current parameters were set.
1019  isSet_ = true;
1020  }
1021 
1022  // initializeStateStorage.
1023  template<class ScalarType, class MV, class OP>
1024  void
1026  {
1027 
1028  ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
1029 
1030  // Check if there is any multivector to clone from.
1031  Teuchos::RCP<const MV> rhsMV = problem_->getRHS();
1032 
1033  //The Dimension of the Krylov Subspace
1034  int KrylSpaDim = (numBlocks_ - 1) * blockSize_;
1035 
1036  //Number of columns in [U_ V_(:,1:KrylSpaDim)]
1037  int augSpaDim = KrylSpaDim + recycledBlocks_ + 1;// + 1 is for possible extra recycle vector
1038 
1039  //Number of columns in [C_ V_]
1040  int augSpaImgDim = KrylSpaDim + blockSize_ + recycledBlocks_+1;
1041 
1042  //TEMPORARY SKELETON DEFINITION OF THIS FUNCTION TO GET THINGS WORKING
1043  //NOT EVERYTHING IS INITIALIZE CORRECTLY YET.
1044 
1045  //INITIALIZE RECYCLE SPACE VARIABLES HERE
1046 
1047  //WE DO NOT ALLOCATE V HERE IN THIS SOLVERMANAGER. If no recycle space exists, then block_gmres_iter
1048  //will allocated V for us. If a recycle space already exists, then we will allocate V after updating the
1049  //recycle space for the current problem.
1050  // If the block Krylov subspace has not been initialized before, generate it using the RHS from lp_.
1051  /*if (V_ == Teuchos::null) {
1052  V_ = MVT::Clone( *rhsMV, (numBlocks_+1)*blockSize_ );
1053  }
1054  else{
1055  // Generate V_ by cloning itself ONLY if more space is needed.
1056  if (MVT::GetNumberVecs(*V_) < numBlocks_+1) {
1057  Teuchos::RCP<const MV> tmp = V_;
1058  V_ = MVT::Clone( *tmp, numBlocks_+1 );
1059  }
1060  }*/
1061 
1062  //INTITIALIZE SPACE FOR THE NEWLY COMPUTED RECYCLE SPACE VARIABLES HERE
1063 
1064  if (U_ == Teuchos::null) {
1065  U_ = MVT::Clone( *rhsMV, recycledBlocks_+1 );
1066  }
1067  else {
1068  // Generate U_ by cloning itself ONLY if more space is needed.
1069  if (MVT::GetNumberVecs(*U_) < recycledBlocks_+1) {
1070  Teuchos::RCP<const MV> tmp = U_;
1071  U_ = MVT::Clone( *tmp, recycledBlocks_+1 );
1072  }
1073  }
1074 
1075  // If the subspace has not been initialized before, generate it using the RHS from lp_.
1076  if (C_ == Teuchos::null) {
1077  C_ = MVT::Clone( *rhsMV, recycledBlocks_+1 );
1078  }
1079  else {
1080  // Generate C_ by cloning itself ONLY if more space is needed.
1081  if (MVT::GetNumberVecs(*C_) < recycledBlocks_+1) {
1082  Teuchos::RCP<const MV> tmp = C_;
1083  C_ = MVT::Clone( *tmp, recycledBlocks_+1 );
1084  }
1085  }
1086 
1087  // If the subspace has not been initialized before, generate it using the RHS from lp_.
1088  if (U1_ == Teuchos::null) {
1089  U1_ = MVT::Clone( *rhsMV, recycledBlocks_+1 );
1090  }
1091  else {
1092  // Generate U1_ by cloning itself ONLY if more space is needed.
1093  if (MVT::GetNumberVecs(*U1_) < recycledBlocks_+1) {
1094  Teuchos::RCP<const MV> tmp = U1_;
1095  U1_ = MVT::Clone( *tmp, recycledBlocks_+1 );
1096  }
1097  }
1098 
1099  // If the subspace has not been initialized before, generate it using the RHS from lp_.
1100  if (C1_ == Teuchos::null) {
1101  C1_ = MVT::Clone( *rhsMV, recycledBlocks_+1 );
1102  }
1103  else {
1104  // Generate C1_ by cloning itself ONLY if more space is needed.
1105  if (MVT::GetNumberVecs(*U1_) < recycledBlocks_+1) {
1106  Teuchos::RCP<const MV> tmp = C1_;
1107  C1_ = MVT::Clone( *tmp, recycledBlocks_+1 );
1108  }
1109  }
1110 
1111  // Generate R_ only if it doesn't exist
1112  if (R_ == Teuchos::null){
1113  R_ = MVT::Clone( *rhsMV, blockSize_ );
1114  }
1115 
1116  //INITIALIZE SOME WORK VARIABLES
1117 
1118  // Generate G_ only if it doesn't exist, otherwise resize it.
1119  if (G_ == Teuchos::null){
1120  G_ = Teuchos::rcp( new SDM( augSpaImgDim, augSpaDim ) );
1121  }
1122  else{
1123  if ( (G_->numRows() != augSpaImgDim) || (G_->numCols() != augSpaDim) )
1124  {
1125  G_->reshape( augSpaImgDim, augSpaDim );
1126  }
1127  G_->putScalar(zero);
1128  }
1129 
1130  // Generate H_ only if it doesn't exist by pointing it to a view of G_.
1131  if (H_ == Teuchos::null){
1132  H_ = Teuchos::rcp (new SDM ( Teuchos::View, *G_, KrylSpaDim + blockSize_, KrylSpaDim, recycledBlocks_+1 ,recycledBlocks_+1 ) );
1133  }
1134 
1135  // Generate F_ only if it doesn't exist, otherwise resize it.
1136  if (F_ == Teuchos::null){
1137  F_ = Teuchos::rcp( new SDM( recycledBlocks_+1, recycledBlocks_+1 ) );
1138  }
1139  else {
1140  if ( (F_->numRows() != recycledBlocks_+1) || (F_->numCols() != recycledBlocks_+1) ){
1141  F_->reshape( recycledBlocks_+1, recycledBlocks_+1 );
1142  }
1143  }
1144  F_->putScalar(zero);
1145 
1146  // Generate PP_ only if it doesn't exist, otherwise resize it.
1147  if (PP_ == Teuchos::null){
1148  PP_ = Teuchos::rcp( new SDM( augSpaImgDim, recycledBlocks_+1 ) );
1149  }
1150  else{
1151  if ( (PP_->numRows() != augSpaImgDim) || (PP_->numCols() != recycledBlocks_+1) ){
1152  PP_->reshape( augSpaImgDim, recycledBlocks_+1 );
1153  }
1154  }
1155 
1156  // Generate HP_ only if it doesn't exist, otherwise resize it.
1157  if (HP_ == Teuchos::null)
1158  HP_ = Teuchos::rcp( new SDM( augSpaImgDim, augSpaDim ) );
1159  else{
1160  if ( (HP_->numRows() != augSpaImgDim) || (HP_->numCols() != augSpaDim) ){
1161  HP_->reshape( augSpaImgDim, augSpaDim );
1162  }
1163  }
1164 
1165  // Size of tau_ will change during computation, so just be sure it starts with appropriate size
1166  tau_.resize(recycledBlocks_+1);
1167 
1168  // Size of work_ will change during computation, so just be sure it starts with appropriate size
1169  work_.resize(recycledBlocks_+1);
1170 
1171  // Size of ipiv_ will change during computation, so just be sure it starts with appropriate size
1172  ipiv_.resize(recycledBlocks_+1);
1173 
1174  }
1175 
1176 template<class ScalarType, class MV, class OP>
1178 
1179  ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
1180  ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
1181 
1182  int p = block_gmres_iter->getState().curDim; //Dimension of the Krylov space generated
1183  std::vector<int> index(keff);//we use this to index certain columns of U, C, and V to
1184  //get views into pieces of these matrices.
1185 
1186  //GET CORRECT PIECE OF MATRIX H APPROPRIATE TO SIZE OF KRYLOV SUBSPACE
1187  SDM HH(Teuchos::Copy, *H_, p+blockSize_, p);
1188  if(recycledBlocks_ >= p + blockSize_){//keep whole block Krylov subspace
1189  //IF THIS HAS HAPPENED, THIS MEANS WE CONVERGED DURING THIS CYCLE
1190  //THEREFORE, WE DO NOT CONSTRUCT C = A*U;
1191  index.resize(p);
1192  for (int ii=0; ii < p; ++ii) index[ii] = ii;
1193  Teuchos::RCP<MV> Utmp = MVT::CloneViewNonConst( *U_, index );
1194  MVT::SetBlock(*V_, index, *Utmp);
1195  keff = p;
1196  }
1197  else{ //use a subspace selection method to get recycle space
1198  int info = 0;
1199  Teuchos::RCP<SDM > PPtmp = Teuchos::rcp (new SDM ( Teuchos::View, *PP_, p, recycledBlocks_+1 ) );
1200  if(recycleMethod_ == "harmvecs"){
1201  keff = getHarmonicVecsKryl(p, HH, *PPtmp);
1202  printer_->stream(Debug) << "keff = " << keff << std::endl;
1203  }
1204 // Hereafter, only keff columns of PP are needed
1205 PPtmp = Teuchos::rcp (new SDM ( Teuchos::View, *PP_, p, keff ) );
1206 // Now get views into C, U, V
1207 index.resize(keff);
1208 for (int ii=0; ii<keff; ++ii) index[ii] = ii;
1209 Teuchos::RCP<MV> Ctmp = MVT::CloneViewNonConst( *C_, index );
1210 Teuchos::RCP<MV> Utmp = MVT::CloneViewNonConst( *U_, index );
1211 Teuchos::RCP<MV> U1tmp = MVT::CloneViewNonConst( *U1_, index );
1212 index.resize(p);
1213 for (int ii=0; ii < p; ++ii) index[ii] = ii;
1214 Teuchos::RCP<const MV> Vtmp = MVT::CloneView( *V_, index );
1215 
1216 // Form U (the subspace to recycle)
1217 // U = newstate.V(:,1:p) * PP;
1218 MVT::MvTimesMatAddMv( one, *Vtmp, *PPtmp, zero, *U1tmp );
1219 
1220 // Step #1: Form HP = H*P
1221 SDM HPtmp( Teuchos::View, *HP_, p+blockSize_, keff );
1222 HPtmp.multiply( Teuchos::NO_TRANS, Teuchos::NO_TRANS, one, *H_, *PPtmp, zero );
1223 // Step #1.5: Perform workspace size query for QR factorization of HP
1224 int lwork = -1;
1225 tau_.resize(keff);
1226 lapack.GEQRF(HPtmp.numRows(),HPtmp.numCols(),HPtmp.values(),HPtmp.stride(),&tau_[0],&work_[0],lwork,&info);
1227 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, BlockGCRODRSolMgrLAPACKFailure, "Belos::BlockGCRODRSolMgr::solve(): LAPACK _GEQRF failed to compute a workspace size.");
1228 
1229 // Step #2: Compute QR factorization of HP
1230  lwork = static_cast<int> (Teuchos::ScalarTraits<ScalarType>::magnitude (work_[0]));
1231 work_.resize(lwork);
1232 lapack.GEQRF(HPtmp.numRows(),HPtmp.numCols(),HPtmp.values(),HPtmp.stride(),&tau_[0],&work_[0],lwork,&info);
1233 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, BlockGCRODRSolMgrLAPACKFailure, "Belos::BlockGCRODRSolMgr::solve(): LAPACK _GEQRF failed to compute a QR factorization.");
1234 
1235 // Step #3: Explicitly construct Q and R factors
1236 // The upper triangular part of HP is copied into R and HP becomes Q.
1237 SDM Rtmp( Teuchos::View, *F_, keff, keff );
1238 for(int ii=0;ii<keff;ii++) { for(int jj=ii;jj<keff;jj++) Rtmp(ii,jj) = HPtmp(ii,jj); }
1239 //lapack.ORGQR(HPtmp.numRows(),HPtmp.numCols(),HPtmp.numCols(),HPtmp.values(),HPtmp.stride(),&tau_[0],&work_[0],lwork,&info);
1240 lapack.UNGQR(HPtmp.numRows(),HPtmp.numCols(),HPtmp.numCols(),HPtmp.values(),HPtmp.stride(),&tau_[0],&work_[0],lwork,&info);
1241 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, BlockGCRODRSolMgrLAPACKFailure, "Belos::BlockGCRODRSolMgr::solve(): LAPACK _UNGQR failed to construct the Q factor.");
1242  // Now we have [Q,R] = qr(H*P)
1243 
1244  // Now compute C = V(:,1:p+blockSize_) * Q
1245  index.resize( p+blockSize_ );
1246  for (int ii=0; ii < (p+blockSize_); ++ii) { index[ii] = ii; }
1247  Vtmp = MVT::CloneView( *V_, index ); // need new view into V (p+blockSize_ vectors now; needed p above)
1248  MVT::MvTimesMatAddMv( one, *Vtmp, HPtmp, zero, *Ctmp );
1249 
1250  // Finally, compute U = U*R^{-1}.
1251  // This unfortuntely requires me to form R^{-1} explicitly and execute U = U * R^{-1}, as
1252  // backsolve capabilities don't exist in the Belos::MultiVec class
1253 
1254 // Step #1: First, compute LU factorization of R
1255 ipiv_.resize(Rtmp.numRows());
1256 lapack.GETRF(Rtmp.numRows(),Rtmp.numCols(),Rtmp.values(),Rtmp.stride(),&ipiv_[0],&info);
1257 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, BlockGCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve(): LAPACK _GETRF failed to compute an LU factorization.");
1258 // Step #2: Form inv(R)
1259 lwork = Rtmp.numRows();
1260 work_.resize(lwork);
1261 lapack.GETRI(Rtmp.numRows(),Rtmp.values(),Rtmp.stride(),&ipiv_[0],&work_[0],lwork,&info);
1262 //TEUCHOS_TEST_FOR_EXCEPTION(info != 0, BlockGCRODRSolMgrLAPACKFailure, "Belos::GCRODRSolMgr::solve(): LAPACK _GETRI failed to invert triangular matrix.");
1263 // Step #3: Let U = U * R^{-1}
1264 MVT::MvTimesMatAddMv( one, *U1tmp, Rtmp, zero, *Utmp );
1265 
1266 } //end else from if(recycledBlocks_ >= p + 1)
1267 return;
1268 } // end buildRecycleSpaceKryl defnition
1269 
1270 template<class ScalarType, class MV, class OP>
1273  const ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
1274 
1275  std::vector<MagnitudeType> d(keff);
1276  std::vector<ScalarType> dscalar(keff);
1277  std::vector<int> index(numBlocks_+1);
1278 
1279  // Get the state
1280  BlockGCRODRIterState<ScalarType,MV> oldState = block_gcrodr_iter->getState();
1281  int p = oldState.curDim;
1282 
1283  // insufficient new information to update recycle space
1284  if (p<1) return;
1285 
1286  if(recycledBlocks_ >= keff + p){ //we add new Krylov vectors to existing recycle space
1287  // If this has happened, we have converged during this cycle. Therefore, do not construct C = A*C;
1288  index.resize(p);
1289  for (int ii=0; ii < p; ++ii) { index[ii] = keff+ii; } //get a view after current reycle vectors
1290  Teuchos::RCP<MV> Utmp = MVT::CloneViewNonConst( *U_, index );
1291  for (int ii=0; ii < p; ++ii) { index[ii] =ii; }
1292  MVT::SetBlock(*V_, index, *Utmp);
1293  keff += p;
1294  }
1295 
1296  // Take the norm of the recycled vectors
1297  {
1298  index.resize(keff);
1299  for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1300  Teuchos::RCP<MV> Utmp = MVT::CloneViewNonConst( *U_, index );
1301  d.resize(keff);
1302  dscalar.resize(keff);
1303  MVT::MvNorm( *Utmp, d );
1304  for (int i=0; i<keff; ++i) {
1305  d[i] = one / d[i];
1306  dscalar[i] = (ScalarType)d[i];
1307  }
1308  MVT::MvScale( *Utmp, dscalar );
1309  }
1310 
1311  // Get view into current "full" upper Hessnburg matrix
1312  // note that p describes the dimension of the iter+1 block Krylov space so we have to adjust how we use it to index Gtmp
1313  Teuchos::RCP<SDM> Gtmp = Teuchos::rcp( new SDM( Teuchos::View, *G_, p+keff, p+keff-blockSize_ ) );
1314 
1315  // Insert D into the leading keff x keff block of G
1316  for (int i=0; i<keff; ++i)
1317  (*Gtmp)(i,i) = d[i];
1318 
1319  // Compute the harmoic Ritz pairs for the generalized eigenproblem
1320  // getHarmonicVecsKryl assumes PP has recycledBlocks_+1 columns available
1321  // See previous block of comments for why we subtract p-blockSize_
1322  int keff_new;
1323  {
1324  SDM PPtmp( Teuchos::View, *PP_, p+keff-blockSize_, recycledBlocks_+1 );
1325  keff_new = getHarmonicVecsAugKryl( keff, p-blockSize_, *Gtmp, oldState.V, PPtmp );
1326  }
1327 
1328  // Code to form new U, C
1329  // U = [U V(:,1:p)] * P; (in two steps)
1330 
1331  // U(:,1:keff) = matmul(U(:,1:keff_old),PP(1:keff_old,1:keff)) (step 1)
1332  Teuchos::RCP<MV> U1tmp;
1333  {
1334  index.resize( keff );
1335  for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1336  Teuchos::RCP<const MV> Utmp = MVT::CloneView( *U_, index );
1337  index.resize( keff_new );
1338  for (int ii=0; ii<keff_new; ++ii) { index[ii] = ii; }
1339  U1tmp = MVT::CloneViewNonConst( *U1_, index );
1340  SDM PPtmp( Teuchos::View, *PP_, keff, keff_new );
1341  MVT::MvTimesMatAddMv( one, *Utmp, PPtmp, zero, *U1tmp );
1342  }
1343 
1344  // U(:,1:keff) = U(:,1:keff) + matmul(V(:,1:m-k),PP(keff_old+1:m-k+keff_old,1:keff)) (step 2)
1345  {
1346  index.resize(p-blockSize_);
1347  for (int ii=0; ii < p-blockSize_; ii++) { index[ii] = ii; }
1348  Teuchos::RCP<const MV> Vtmp = MVT::CloneView( *V_, index );
1349  SDM PPtmp( Teuchos::View, *PP_, p-blockSize_, keff_new, keff );
1350  MVT::MvTimesMatAddMv( one, *Vtmp, PPtmp, one, *U1tmp );
1351  }
1352 
1353  // Form GP = G*P
1354  SDM HPtmp( Teuchos::View, *HP_, p+keff, keff_new );
1355  {
1356  SDM PPtmp( Teuchos::View, *PP_, p-blockSize_+keff, keff_new );
1357  HPtmp.multiply(Teuchos::NO_TRANS,Teuchos::NO_TRANS,one,*Gtmp,PPtmp,zero);
1358  }
1359 
1360  // Workspace size query for QR factorization HP= QF (the worksize will be placed in work_[0])
1361  int info = 0, lwork = -1;
1362  tau_.resize(keff_new);
1363  lapack.GEQRF(HPtmp.numRows(),HPtmp.numCols(),HPtmp.values(),HPtmp.stride(),&tau_[0],&work_[0],lwork,&info);
1364  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,BlockGCRODRSolMgrLAPACKFailure,"Belos::BlockGCRODRSolMgr::solve(): LAPACK _GEQRF failed to compute a workspace size.");
1365 
1366  lwork = static_cast<int> (Teuchos::ScalarTraits<ScalarType>::real (work_[0]));
1367  work_.resize(lwork);
1368  lapack.GEQRF(HPtmp.numRows(),HPtmp.numCols(),HPtmp.values(),HPtmp.stride(),&tau_[0],&work_[0],lwork,&info);
1369  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,BlockGCRODRSolMgrLAPACKFailure,"Belos::BlockGCRODRSolMgr::solve(): LAPACK _GEQRF failed to compute a QR factorization.");
1370 
1371  // Explicitly construct Q and F factors
1372  // NOTE: The upper triangular part of HP is copied into F and HP becomes Q.
1373  SDM Ftmp( Teuchos::View, *F_, keff_new, keff_new );
1374  for(int i=0;i<keff_new;i++) { for(int j=i;j<keff_new;j++) Ftmp(i,j) = HPtmp(i,j); }
1375  //lapack.ORGQR(HPtmp.numRows(),HPtmp.numCols(),HPtmp.numCols(),HPtmp.values(),HPtmp.stride(),&tau_[0],&work_[0],lwork,&info);
1376  lapack.UNGQR(HPtmp.numRows(),HPtmp.numCols(),HPtmp.numCols(),HPtmp.values(),HPtmp.stride(),&tau_[0],&work_[0],lwork,&info);
1377  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,BlockGCRODRSolMgrLAPACKFailure,"Belos::BlockGCRODRSolMgr::solve(): LAPACK _UNGQR failed to construct the Q factor.");
1378 
1379  // Form orthonormalized C and adjust U accordingly so that C = A*U
1380  // C = [C V] * Q;
1381 
1382  // C(:,1:keff) = matmul(C(:,1:keff_old),QQ(1:keff_old,1:keff))
1383  {
1384  Teuchos::RCP<MV> C1tmp;
1385  {
1386  index.resize(keff);
1387  for (int i=0; i < keff; i++) { index[i] = i; }
1388  Teuchos::RCP<const MV> Ctmp = MVT::CloneView( *C_, index );
1389  index.resize(keff_new);
1390  for (int i=0; i < keff_new; i++) { index[i] = i; }
1391  C1tmp = MVT::CloneViewNonConst( *C1_, index );
1392  SDM PPtmp( Teuchos::View, *HP_, keff, keff_new );
1393  MVT::MvTimesMatAddMv( one, *Ctmp, PPtmp, zero, *C1tmp );
1394  }
1395  // Now compute C += V(:,1:p+1) * Q
1396  {
1397  index.resize( p );
1398  for (int i=0; i < p; ++i) { index[i] = i; }
1399  Teuchos::RCP<const MV> Vtmp = MVT::CloneView( *V_, index );
1400  SDM PPtmp( Teuchos::View, *HP_, p, keff_new, keff, 0 );
1401  MVT::MvTimesMatAddMv( one, *Vtmp, PPtmp, one, *C1tmp );
1402  }
1403  }
1404 
1405  // C_ = C1_; (via a swap)
1406  std::swap(C_, C1_);
1407 
1408  // Finally, compute U_ = U_*R^{-1}
1409  // First, compute LU factorization of R
1410  ipiv_.resize(Ftmp.numRows());
1411  lapack.GETRF(Ftmp.numRows(),Ftmp.numCols(),Ftmp.values(),Ftmp.stride(),&ipiv_[0],&info);
1412  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,BlockGCRODRSolMgrLAPACKFailure,"Belos::BlockGCRODRSolMgr::solve(): LAPACK _GETRF failed to compute an LU factorization.");
1413 
1414  // Now, form inv(R)
1415  lwork = Ftmp.numRows();
1416  work_.resize(lwork);
1417  lapack.GETRI(Ftmp.numRows(),Ftmp.values(),Ftmp.stride(),&ipiv_[0],&work_[0],lwork,&info);
1418  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, BlockGCRODRSolMgrLAPACKFailure,"Belos::BlockGCRODRSolMgr::solve(): LAPACK _GETRI failed to compute an LU factorization.");
1419 
1420  {
1421  index.resize(keff_new);
1422  for (int i=0; i < keff_new; i++) { index[i] = i; }
1423  Teuchos::RCP<MV> Utmp = MVT::CloneViewNonConst( *U_, index );
1424  MVT::MvTimesMatAddMv( one, *U1tmp, Ftmp, zero, *Utmp );
1425  }
1426 
1427  // Set the current number of recycled blocks and subspace
1428  // dimension with the Block GCRO-DR iteration.
1429  if (keff != keff_new) {
1430  keff = keff_new;
1431  block_gcrodr_iter->setSize( keff, numBlocks_ );
1432  // Important to zero this out before next cyle
1433  SDM b1( Teuchos::View, *G_, recycledBlocks_+2, 1, 0, recycledBlocks_ );
1434  b1.putScalar(zero);
1435  }
1436 
1437 } //end buildRecycleSpaceAugKryl definition
1438 
1439 template<class ScalarType, class MV, class OP>
1441  int i, j;
1442  int m2 = GG.numCols();
1443  bool xtraVec = false;
1444  ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
1445  ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
1446  std::vector<int> index;
1447 
1448  // Real and imaginary eigenvalue components
1449  std::vector<MagnitudeType> wr(m2), wi(m2);
1450 
1451  // Magnitude of harmonic Ritz values
1452  std::vector<MagnitudeType> w(m2);
1453 
1454  // Real and imaginary (right) eigenvectors; Don't zero out matrix when constructing
1455  SDM vr(m2,m2,false);
1456 
1457  // Sorted order of harmonic Ritz values
1458  std::vector<int> iperm(m2);
1459 
1460  // Set flag indicating recycle space has been generated this solve
1461  builtRecycleSpace_ = true;
1462 
1463  // Form matrices for generalized eigenproblem
1464 
1465  // B = G' * G; Don't zero out matrix when constructing
1466  SDM B(m2,m2,false);
1467  B.multiply(Teuchos::TRANS,Teuchos::NO_TRANS,one,GG,GG,zero);
1468 
1469  // A_tmp = | C'*U 0 |
1470  // | V_{m+1}'*U I |
1471  SDM A_tmp( keff+m+blockSize_, keff+m );
1472 
1473 
1474  // A_tmp(1:keff,1:keff) = C' * U;
1475  index.resize(keff);
1476  for (int i=0; i<keff; ++i) { index[i] = i; }
1477  Teuchos::RCP<const MV> Ctmp = MVT::CloneView( *C_, index );
1478  Teuchos::RCP<const MV> Utmp = MVT::CloneView( *U_, index );
1479  SDM A11( Teuchos::View, A_tmp, keff, keff );
1480  MVT::MvTransMv( one, *Ctmp, *Utmp, A11 );
1481 
1482  // A_tmp(keff+1:m-k+keff+1,1:keff) = V' * U;
1483  SDM A21( Teuchos::View, A_tmp, m+blockSize_, keff, keff );
1484  index.resize(m+blockSize_);
1485  for (i=0; i < m+blockSize_; i++) { index[i] = i; }
1486  Teuchos::RCP<const MV> Vp = MVT::CloneView( *VV, index );
1487  MVT::MvTransMv( one, *Vp, *Utmp, A21 );
1488 
1489  // A_tmp(keff+1:m-k+keff,keff+1:m-k+keff) = eye(m-k);
1490  for( i=keff; i<keff+m; i++)
1491  A_tmp(i,i) = one;
1492 
1493  // A = G' * A_tmp;
1494  SDM A( m2, A_tmp.numCols() );
1495  A.multiply( Teuchos::TRANS, Teuchos::NO_TRANS, one, GG, A_tmp, zero );
1496 
1497  // Compute k smallest harmonic Ritz pairs
1498  // SUBROUTINE DGGEVX( BALANC, JOBVL, JOBVR, SENSE, N, A, LDA, B, LDB,
1499  // ALPHAR, ALPHAI, BETA, VL, LDVL, VR, LDVR, ILO,
1500  // IHI, LSCALE, RSCALE, ABNRM, BBNRM, RCONDE,
1501  // RCONDV, WORK, LWORK, IWORK, BWORK, INFO )
1502  // MLP: 'SCALING' in DGGEVX generates incorrect eigenvalues. Therefore, only permuting
1503  char balanc='P', jobvl='N', jobvr='V', sense='N';
1504  int ld = A.numRows();
1505  int lwork = 6*ld;
1506  int ldvl = ld, ldvr = ld;
1507  int info = 0,ilo = 0,ihi = 0;
1508  MagnitudeType abnrm = 0.0, bbnrm = 0.0;
1509  ScalarType *vl = 0; // This is never referenced by dggevx if jobvl == 'N'
1510  std::vector<ScalarType> beta(ld);
1511  std::vector<ScalarType> work(lwork);
1512  std::vector<MagnitudeType> rwork(lwork);
1513  std::vector<MagnitudeType> lscale(ld), rscale(ld);
1514  std::vector<MagnitudeType> rconde(ld), rcondv(ld);
1515  std::vector<int> iwork(ld+6);
1516  int *bwork = 0; // If sense == 'N', bwork is never referenced
1517  //lapack.GGEVX(balanc, jobvl, jobvr, sense, ld, A.values(), ld, B.values(), ld, &wr[0], &wi[0],
1518  // &beta[0], vl, ldvl, vr.values(), ldvr, &ilo, &ihi, &lscale[0], &rscale[0],
1519  // &abnrm, &bbnrm, &rconde[0], &rcondv[0], &work[0], lwork, &iwork[0], bwork, &info);
1520  lapack.GGEVX(balanc, jobvl, jobvr, sense, ld, A.values(), ld, B.values(), ld, &wr[0], &wi[0],
1521  &beta[0], vl, ldvl, vr.values(), ldvr, &ilo, &ihi, &lscale[0], &rscale[0],
1522  &abnrm, &bbnrm, &rconde[0], &rcondv[0], &work[0], lwork, &rwork[0],
1523  &iwork[0], bwork, &info);
1524  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, BlockGCRODRSolMgrLAPACKFailure, "Belos::BlockGCRODRSolMgr::solve(): LAPACK GGEVX failed to compute eigensolutions.");
1525 
1526  // Construct magnitude of each harmonic Ritz value
1527  // NOTE : Forming alpha/beta *should* be okay here, given assumptions on construction of matrix pencil above
1528  for( i=0; i<ld; i++ ) // Construct magnitude of each harmonic Ritz value
1529  w[i] = Teuchos::ScalarTraits<MagnitudeType>::squareroot( wr[i]*wr[i] + wi[i]*wi[i] ) / std::abs( beta[i] );
1530 
1531  this->sort(w,ld,iperm);
1532 
1533  bool scalarTypeIsComplex = Teuchos::ScalarTraits<ScalarType>::isComplex;
1534 
1535  // Select recycledBlocks_ smallest eigenvectors
1536  for( i=0; i<recycledBlocks_; i++ )
1537  for( j=0; j<ld; j++ )
1538  PP(j,i) = vr(j,iperm[ld-recycledBlocks_+i]);
1539 
1540  if(scalarTypeIsComplex==false) {
1541 
1542  // Determine exact size for PP (i.e., determine if we need to store an additional vector)
1543  if (wi[iperm[ld-recycledBlocks_]] != 0.0) {
1544  int countImag = 0;
1545  for ( i=ld-recycledBlocks_; i<ld; i++ )
1546  if (wi[iperm[i]] != 0.0) countImag++;
1547  // Check to see if this count is even or odd:
1548  if (countImag % 2) xtraVec = true;
1549  }
1550 
1551  if (xtraVec) { // we need to store one more vector
1552  if (wi[iperm[ld-recycledBlocks_]] > 0.0) { // I picked the "real" component
1553  for( j=0; j<ld; j++ ) // so get the "imag" component
1554  PP(j,recycledBlocks_) = vr(j,iperm[ld-recycledBlocks_]+1);
1555  }
1556  else { // I picked the "imag" component
1557  for( j=0; j<ld; j++ ) // so get the "real" component
1558  PP(j,recycledBlocks_) = vr(j,iperm[ld-recycledBlocks_]-1);
1559  }
1560  }
1561 
1562  }
1563 
1564  // Return whether we needed to store an additional vector
1565  if (xtraVec)
1566  return recycledBlocks_+1;
1567  else
1568  return recycledBlocks_;
1569 
1570 } //end getHarmonicVecsAugKryl definition
1571 
1572 template<class ScalarType, class MV, class OP>
1574  bool xtraVec = false;
1575  ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
1576  ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
1577 
1578  // Real and imaginary eigenvalue components
1579  std::vector<MagnitudeType> wr(m), wi(m);
1580 
1581  // Real and imaginary (right) eigenvectors; Don't zero out matrix when constructing
1582  SDM vr(m,m,false);
1583 
1584  // Magnitude of harmonic Ritz values
1585  std::vector<MagnitudeType> w(m);
1586 
1587  // Sorted order of harmonic Ritz values, also used for DGEEV
1588  std::vector<int> iperm(m);
1589 
1590  // Output info
1591  int info = 0;
1592 
1593  // Set flag indicating recycle space has been generated this solve
1594  builtRecycleSpace_ = true;
1595 
1596  // Solve linear system: H_m^{-H}*E_m where E_m is the last blockSize_ columns of the identity matrix
1597  SDM HHt( HH, Teuchos::TRANS );
1598  Teuchos::RCP<SDM> harmRitzMatrix = Teuchos::rcp( new SDM( m, blockSize_));
1599 
1600  //Initialize harmRitzMatrix as E_m
1601  for(int i=0; i<=blockSize_-1; i++) (*harmRitzMatrix)[blockSize_-1-i][harmRitzMatrix->numRows()-1-i] = 1;
1602 
1603  //compute harmRitzMatrix <- H_m^{-H}*E_m
1604  lapack.GESV(m, blockSize_, HHt.values(), HHt.stride(), &iperm[0], harmRitzMatrix->values(), harmRitzMatrix->stride(), &info);
1605 
1606  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, BlockGCRODRSolMgrLAPACKFailure, "Belos::BlockGCRODRSolMgr::solve(): LAPACK GESV failed to compute a solution.");
1607  // Compute H_m + H_m^{-H}*E_m*H_lbl^{H}*H_lbl
1608  // H_lbl is bottom-right block of H_, which is a blockSize_ x blockSize_ matrix
1609 
1610  Teuchos::SerialDenseMatrix<int, ScalarType> H_lbl(Teuchos::View, HH, blockSize_, blockSize_, (HH).numRows()-blockSize_, (HH).numCols()-blockSize_ );
1612 
1613  { //So that HTemp will fall out of scope
1614 
1615  // HH_lbl_t <- H_lbl_t*H_lbl
1617  Htemp = Teuchos::rcp(new SDM(H_lbl_t.numRows(), H_lbl_t.numCols()));
1618  Htemp -> multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, one, H_lbl_t, H_lbl, zero);
1619  H_lbl_t.assign(*Htemp);
1620  // harmRitzMatrix <- harmRitzMatrix*HH_lbl_t
1621  Htemp = Teuchos::rcp(new SDM(harmRitzMatrix -> numRows(), harmRitzMatrix -> numCols()));
1622  Htemp -> multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, one, *harmRitzMatrix, H_lbl_t, zero);
1623  harmRitzMatrix -> assign(*Htemp);
1624 
1625  // We need to add harmRitzMatrix to the last blockSize_ columns of HH and store the result harmRitzMatrix
1626  int harmColIndex, HHColIndex;
1627  Htemp = Teuchos::rcp(new SDM(Teuchos::Copy,HH,HH.numRows()-blockSize_,HH.numCols()));
1628  for(int i = 0; i<blockSize_; i++){
1629  harmColIndex = harmRitzMatrix -> numCols() - i -1;
1630  HHColIndex = m-i-1;
1631  for(int j=0; j<m; j++) (*Htemp)[HHColIndex][j] += (*harmRitzMatrix)[harmColIndex][j];
1632  }
1633  harmRitzMatrix = Htemp;
1634  }
1635 
1636  // Revise to do query for optimal workspace first
1637  // Create simple storage for the left eigenvectors, which we don't care about.
1638 
1639  // Size of workspace and workspace for DGEEV
1640  int lwork = -1;
1641  std::vector<ScalarType> work(1);
1642  std::vector<MagnitudeType> rwork(2*m);
1643 
1644  const int ldvl = 1;
1645  ScalarType* vl = 0;
1646 
1647  // First query GEEV for the optimal workspace size
1648  lapack.GEEV('N', 'V', m, harmRitzMatrix->values(), harmRitzMatrix->stride(), &wr[0], &wi[0],
1649  vl, ldvl, vr.values(), vr.stride(), &work[0], lwork, &rwork[0], &info);
1650 
1651  lwork = std::abs (static_cast<int> (Teuchos::ScalarTraits<ScalarType>::real (work[0])));
1652  work.resize( lwork );
1653 
1654  lapack.GEEV('N', 'V', m, harmRitzMatrix->values(), harmRitzMatrix->stride(), &wr[0], &wi[0],
1655  vl, ldvl, vr.values(), vr.stride(), &work[0], lwork, &rwork[0], &info);
1656 
1657  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, BlockGCRODRSolMgrLAPACKFailure,"Belos::BlockGCRODRSolMgr::solve(): LAPACK GEEV failed to compute eigensolutions.");
1658 
1659  // Construct magnitude of each harmonic Ritz value
1660  for( int i=0; i<m; ++i ) w[i] = Teuchos::ScalarTraits<MagnitudeType>::squareroot( wr[i]*wr[i] + wi[i]*wi[i] );
1661 
1662  this->sort(w, m, iperm);
1663 
1664  bool scalarTypeIsComplex = Teuchos::ScalarTraits<ScalarType>::isComplex;
1665 
1666  // Select recycledBlocks_ smallest eigenvectors
1667  for( int i=0; i<recycledBlocks_; ++i )
1668  for(int j=0; j<m; j++ )
1669  PP(j,i) = vr(j,iperm[i]);
1670 
1671  if(scalarTypeIsComplex==false) {
1672 
1673  // Determine exact size for PP (i.e., determine if we need to store an additional vector)
1674  if (wi[iperm[recycledBlocks_-1]] != 0.0) {
1675  int countImag = 0;
1676  for (int i=0; i<recycledBlocks_; ++i )
1677  if (wi[iperm[i]] != 0.0) countImag++;
1678  // Check to see if this count is even or odd:
1679  if (countImag % 2) xtraVec = true;
1680  }
1681 
1682  if (xtraVec) { // we need to store one more vector
1683  if (wi[iperm[recycledBlocks_-1]] > 0.0) { // I picked the "real" component
1684  for(int j=0; j<m; ++j ) // so get the "imag" component
1685  PP(j,recycledBlocks_) = vr(j,iperm[recycledBlocks_-1]+1);
1686  }
1687  else{ // I picked the "imag" component
1688  for(int j=0; j<m; ++j ) // so get the "real" component
1689  PP(j,recycledBlocks_) = vr(j,iperm[recycledBlocks_-1]-1);
1690  }
1691  }
1692 
1693  }
1694 
1695  // Return whether we needed to store an additional vector
1696  if (xtraVec) {
1697  printer_->stream(Debug) << "Recycled " << recycledBlocks_+1 << " vectors" << std::endl;
1698  return recycledBlocks_+1;
1699  }
1700  else {
1701  printer_->stream(Debug) << "Recycled " << recycledBlocks_ << " vectors" << std::endl;
1702  return recycledBlocks_;
1703  }
1704 } //end getHarmonicVecsKryl
1705 
1706 // This method sorts list of n floating-point numbers and return permutation vector
1707 template<class ScalarType, class MV, class OP>
1708 void BlockGCRODRSolMgr<ScalarType,MV,OP>::sort(std::vector<MagnitudeType>& dlist, int n, std::vector<int>& iperm) {
1709  int l, r, j, i, flag;
1710  int RR2;
1711  MagnitudeType dRR, dK;
1712 
1713  // Initialize the permutation vector.
1714  for(j=0;j<n;j++)
1715  iperm[j] = j;
1716 
1717  if (n <= 1) return;
1718 
1719  l = n / 2 + 1;
1720  r = n - 1;
1721  l = l - 1;
1722  dRR = dlist[l - 1];
1723  dK = dlist[l - 1];
1724 
1725  RR2 = iperm[l - 1];
1726  while (r != 0) {
1727  j = l;
1728  flag = 1;
1729  while (flag == 1) {
1730  i = j;
1731  j = j + j;
1732  if (j > r + 1)
1733  flag = 0;
1734  else {
1735  if (j < r + 1)
1736  if (dlist[j] > dlist[j - 1]) j = j + 1;
1737  if (dlist[j - 1] > dK) {
1738  dlist[i - 1] = dlist[j - 1];
1739  iperm[i - 1] = iperm[j - 1];
1740  }
1741  else {
1742  flag = 0;
1743  }
1744  }
1745  }
1746  dlist[i - 1] = dRR;
1747  iperm[i - 1] = RR2;
1748  if (l == 1) {
1749  dRR = dlist [r];
1750  RR2 = iperm[r];
1751  dK = dlist[r];
1752  dlist[r] = dlist[0];
1753  iperm[r] = iperm[0];
1754  r = r - 1;
1755  }
1756  else {
1757  l = l - 1;
1758  dRR = dlist[l - 1];
1759  RR2 = iperm[l - 1];
1760  dK = dlist[l - 1];
1761  }
1762  }
1763  dlist[0] = dRR;
1764  iperm[0] = RR2;
1765 } //end sort() definition
1766 
1767 template<class ScalarType, class MV, class OP>
1769  using Teuchos::RCP;
1770  using Teuchos::rcp;
1771  using Teuchos::rcp_const_cast;
1772 
1773  // MLP: NEED TO ADD CHECK IF PARAMETERS ARE SET LATER
1774 
1775  ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
1776  ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
1777  std::vector<int> index(numBlocks_+1);
1778 
1779  // MLP: EXCEPTION TESTING SHOULD GO HERE
1780 
1781  //THE FOLLOWING BLOCK OF CODE IS TO INFORM THE PROBLEM HOW MANY RIGHT HAND
1782  //SIDES WILL BE SOLVED. IF THE CHOSEN BLOCK SIZE IS THE SAME AS THE NUMBER
1783  //OF RIGHT HAND SIDES IN THE PROBLEM THEN WE PASS THE PROBLEM
1784  //INDICES FOR ALL RIGHT HAND SIDES. IF BLOCK SIZE IS GREATER THAN
1785  //THE NUMBER OF RIGHT HAND SIDES AND THE USER HAS ADAPTIVE BLOCK SIZING
1786  //TURNED OFF, THEN THE PROBLEM WILL GENERATE RANDOM RIGHT HAND SIDES SO WE HAVE AS MANY
1787  //RIGHT HAND SIDES AS BLOCK SIZE INDICATES. THIS MAY NEED TO BE CHANGED
1788  //LATER TO ACCOMADATE SMARTER CHOOSING OF FICTITIOUS RIGHT HAND SIDES.
1789  //THIS CODE IS DIRECTLY LIFTED FROM BelosBlockGmresSolMgr.hpp.
1790 
1791  // Create indices for the linear systems to be solved.
1792  int startPtr = 0;
1793  int numRHS2Solve = MVT::GetNumberVecs( *(problem_->getRHS()) );
1794  int numCurrRHS = ( numRHS2Solve < blockSize_) ? numRHS2Solve : blockSize_;
1795 
1796  //currIdx holds indices to all right-hand sides to be solved
1797  //or -1's to indicate that random right-hand sides should be generated
1798  std::vector<int> currIdx;
1799 
1800  if ( adaptiveBlockSize_ ) {
1801  blockSize_ = numCurrRHS;
1802  currIdx.resize( numCurrRHS );
1803  for (int i=0; i<numCurrRHS; ++i)
1804  currIdx[i] = startPtr+i;
1805  }
1806  else {
1807  currIdx.resize( blockSize_ );
1808  for (int i=0; i<numCurrRHS; ++i)
1809  currIdx[i] = startPtr+i;
1810  for (int i=numCurrRHS; i<blockSize_; ++i)
1811  currIdx[i] = -1;
1812  }
1813 
1814  // Inform the linear problem of the linear systems to solve/generate.
1815  problem_->setLSIndex( currIdx );
1816 
1817  //ADD ERROR CHECKING TO MAKE SURE SIZE OF BLOCK KRYLOV SUBSPACE NOT LARGER THAN dim
1818  //ptrdiff_t dim = MVT::GetGlobalLength( *(problem_->getRHS()) );
1819 
1820  // reset loss of orthogonality flag
1821  loaDetected_ = false;
1822 
1823  // Assume convergence is achieved, then let any failed convergence set this to false.
1824  bool isConverged = true;
1825 
1826  // Initialize storage for all state variables
1827  initializeStateStorage();
1828 
1829  // Parameter list MLP: WE WILL NEED TO ASSIGN SOME PARAMETER VALUES LATER
1830  Teuchos::ParameterList plist;
1831 
1832  while (numRHS2Solve > 0){ //This loops through each block of RHS's being solved
1833  // **************************************************************************************************************************
1834  // Begin initial solver preparations. Either update U,C for new operator or generate an initial space using a cycle of GMRES
1835  // **************************************************************************************************************************
1836  //int prime_iterations; // silence warning about not being used
1837  if(keff > 0){//If there is already a subspace to recycle, then use it
1838  // Update U, C for the new operator
1839 
1840 // TEUCHOS_TEST_FOR_EXCEPTION(keff < recycledBlocks_,BlockGCRODRSolMgrRecyclingFailure,
1841 // "Belos::BlockGCRODRSolMgr::solve(): Requested size of recycled subspace is not consistent with the current recycle subspace.");
1842  printer_->stream(Debug) << " Now solving RHS index " << currIdx[0] << " using recycled subspace of dimension " << keff << std::endl << std::endl;
1843 
1844  // Compute image of U_ under the new operator
1845  index.resize(keff);
1846  for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1847  RCP<const MV> Utmp = MVT::CloneView( *U_, index );
1848  RCP<MV> Ctmp = MVT::CloneViewNonConst( *C_, index );
1849  problem_->apply( *Utmp, *Ctmp );
1850 
1851  RCP<MV> U1tmp = MVT::CloneViewNonConst( *U1_, index );
1852 
1853  // Orthogonalize this block
1854  // Get a matrix to hold the orthonormalization coefficients.
1855  SDM Ftmp( Teuchos::View, *F_, keff, keff );
1856  int rank = ortho_->normalize(*Ctmp, rcp(&Ftmp,false));
1857  // Throw an error if we could not orthogonalize this block
1858  TEUCHOS_TEST_FOR_EXCEPTION(rank != keff,BlockGCRODRSolMgrOrthoFailure,"Belos::BlockGCRODRSolMgr::solve(): Failed to compute orthonormal basis for initial recycled subspace.");
1859 
1860  // U_ = U_*F^{-1}
1861  // First, compute LU factorization of R
1862  int info = 0;
1863  ipiv_.resize(Ftmp.numRows());
1864  lapack.GETRF(Ftmp.numRows(),Ftmp.numCols(),Ftmp.values(),Ftmp.stride(),&ipiv_[0],&info);
1865  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, BlockGCRODRSolMgrLAPACKFailure,"Belos::BlockGCRODRSolMgr::solve(): LAPACK _GETRF failed to compute an LU factorization.");
1866 
1867  // Now, form inv(F)
1868  int lwork = Ftmp.numRows();
1869  work_.resize(lwork);
1870  lapack.GETRI(Ftmp.numRows(),Ftmp.values(),Ftmp.stride(),&ipiv_[0],&work_[0],lwork,&info);
1871  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, BlockGCRODRSolMgrLAPACKFailure,"Belos::BlockGCRODRSolMgr::solve(): LAPACK _GETRI failed to invert triangular matrix.");
1872 
1873  // U_ = U1_; (via a swap)
1874  MVT::MvTimesMatAddMv( one, *Utmp, Ftmp, zero, *U1tmp );
1875  std::swap(U_, U1_);
1876 
1877  // Must reinitialize after swap
1878  index.resize(keff);
1879  for (int ii=0; ii<keff; ++ii) { index[ii] = ii; }
1880  Ctmp = MVT::CloneViewNonConst( *C_, index );
1881  Utmp = MVT::CloneView( *U_, index );
1882 
1883  // Compute C_'*R_
1884  SDM Ctr(keff,blockSize_);
1885  problem_->computeCurrPrecResVec( &*R_ );
1886  MVT::MvTransMv( one, *Ctmp, *R_, Ctr );
1887 
1888  // Update solution ( x += U_*C_'*R_ )
1889  RCP<MV> update = MVT::Clone( *problem_->getCurrLHSVec(), blockSize_ );
1890  MVT::MvInit( *update, 0.0 );
1891  MVT::MvTimesMatAddMv( one, *Utmp, Ctr, one, *update );
1892  problem_->updateSolution( update, true );
1893 
1894  // Update residual norm ( r -= C_*C_'*R_ )
1895  MVT::MvTimesMatAddMv( -one, *Ctmp, Ctr, one, *R_ );
1896 
1897  // We recycled space from previous call
1898  //prime_iterations = 0;
1899 
1900  // Since we have a previous recycle space, we do not need block_gmres_iter
1901  // and we must allocate V ourselves. See comments in initialize() routine for
1902  // further explanation.
1903  if (V_ == Teuchos::null) {
1904  // Check if there is a multivector to clone from.
1905  Teuchos::RCP<const MV> rhsMV = problem_->getRHS();
1906  V_ = MVT::Clone( *rhsMV, (numBlocks_+1)*blockSize_ );
1907  }
1908  else{
1909  // Generate V_ by cloning itself ONLY if more space is needed.
1910  if (MVT::GetNumberVecs(*V_) < (numBlocks_+1)*blockSize_ ) {
1911  Teuchos::RCP<const MV> tmp = V_;
1912  V_ = MVT::Clone( *tmp, (numBlocks_+1)*blockSize_ );
1913  }
1914  }
1915  } //end if(keff > 0)
1916  else{ //if there was no subspace to recycle, then build one
1917  printer_->stream(Debug) << " No recycled subspace available for RHS index " << std::endl << std::endl;
1918 
1919  Teuchos::ParameterList primeList;
1920  //we set this as numBlocks-1 because that is the Krylov dimension we want
1921  //so that the size of the Hessenberg created matches that of what we were expecting.
1922  primeList.set("Num Blocks",numBlocks_-1);
1923  primeList.set("Block Size",blockSize_);
1924  primeList.set("Recycled Blocks",0);
1925  primeList.set("Keep Hessenberg",true);
1926  primeList.set("Initialize Hessenberg",true);
1927 
1928  ptrdiff_t dim = MVT::GetGlobalLength( *(problem_->getRHS()) );
1929  if (blockSize_*static_cast<ptrdiff_t>(numBlocks_) > dim) {//if user has selected a total subspace dimension larger than system dimension
1930  ptrdiff_t tmpNumBlocks = 0;
1931  if (blockSize_ == 1)
1932  tmpNumBlocks = dim / blockSize_; // Allow for a good breakdown.
1933  else{
1934  tmpNumBlocks = ( dim - blockSize_) / blockSize_; // Allow for restarting.
1935  printer_->stream(Warnings) << "Belos::BlockGCRODRSolMgr::solve(): Warning! Requested Krylov subspace dimension is larger than operator dimension!"
1936  << std::endl << "The maximum number of blocks allowed for the Krylov subspace will be adjusted to " << tmpNumBlocks << std::endl;
1937  primeList.set("Num Blocks",Teuchos::as<int>(tmpNumBlocks));
1938  }
1939  }
1940  else{
1941  primeList.set("Num Blocks",numBlocks_-1);
1942  }
1943  //Create Block GMRES iteration object to perform one cycle of GMRES
1945  block_gmres_iter = Teuchos::rcp( new BlockGmresIter<ScalarType,MV,OP>(problem_,printer_,outputTest_,ortho_,primeList) );
1946 
1947  // MLP: ADD LOGIC TO DEAL WITH USER ASKING TO GENERATE A LARGER SPACE THAN dim AS IN HEIDI'S BlockGmresSolMgr CODE (DIDN'T WE ALREADY DO THIS SOMEWHERE?)
1948  block_gmres_iter->setSize( blockSize_, numBlocks_-1 );
1949 
1950  //Create the first block in the current BLOCK Krylov basis (using residual)
1951  Teuchos::RCP<MV> V_0;
1952  if (currIdx[blockSize_-1] == -1) {//if augmented with random RHS's
1953  V_0 = MVT::Clone( *(problem_->getInitPrecResVec()), blockSize_ );
1954  problem_->computeCurrPrecResVec( &*V_0 );
1955  }
1956  else {
1957  V_0 = MVT::CloneCopy( *(problem_->getInitPrecResVec()), currIdx );
1958  }
1959 
1960  // Get a matrix to hold the orthonormalization coefficients.
1961  Teuchos::RCP<SDM > z_0 = Teuchos::rcp( new SDM( blockSize_, blockSize_ ) );
1962 
1963  // Orthonormalize the new V_0
1964  int rank = ortho_->normalize( *V_0, z_0 );
1965  (void) rank; // silence compiler warning for unused variable
1966  // MLP: ADD EXCEPTION IF INITIAL BLOCK IS RANK DEFFICIENT
1967 
1968  // Set the new state and initialize the iteration.
1970  newstate.V = V_0;
1971  newstate.z = z_0;
1972  newstate.curDim = 0;
1973  block_gmres_iter->initializeGmres(newstate);
1974 
1975  bool primeConverged = false;
1976 
1977  try {
1978  printer_->stream(Debug) << " Preparing to Iterate!!!!" << std::endl << std::endl;
1979  block_gmres_iter->iterate();
1980 
1981  // *********************
1982  // check for convergence
1983  // *********************
1984  if ( convTest_->getStatus() == Passed ) {
1985  printer_->stream(Debug) << "We converged during the prime the pump stage" << std::endl << std::endl;
1986  primeConverged = !(expConvTest_->getLOADetected());
1987  if ( expConvTest_->getLOADetected() ) {
1988  // we don't have convergence
1989  loaDetected_ = true;
1990  printer_->stream(Warnings) << "Belos::BlockGCRODRSolMgr::solve(): Warning! Solver has experienced a loss of accuracy!" << std::endl;
1991  }
1992  }
1993  // *******************************************
1994  // check for maximum iterations of block GMRES
1995  // *******************************************
1996  else if( maxIterTest_->getStatus() == Passed ) {
1997  // we don't have convergence
1998  primeConverged = false;
1999  }
2000  // ****************************************************************
2001  // We need to recycle and continue, print a message indicating this
2002  // ****************************************************************
2003  else{ //debug statements
2004  printer_->stream(Debug) << " We did not converge on priming cycle of Block GMRES. Therefore we recycle and restart. " << std::endl << std::endl;
2005  }
2006  } //end try
2007  catch (const GmresIterationOrthoFailure &e) {
2008  // If the block size is not one, it's not considered a lucky breakdown.
2009  if (blockSize_ != 1) {
2010  printer_->stream(Errors) << "Error! Caught std::exception in BlockGmresIter::iterate() at iteration "
2011  << block_gmres_iter->getNumIters() << std::endl
2012  << e.what() << std::endl;
2013  if (convTest_->getStatus() != Passed)
2014  primeConverged = false;
2015  }
2016  else {
2017  // If the block size is one, try to recover the most recent least-squares solution
2018  block_gmres_iter->updateLSQR( block_gmres_iter->getCurSubspaceDim() );
2019  // Check to see if the most recent least-squares solution yielded convergence.
2020  sTest_->checkStatus( &*block_gmres_iter );
2021  if (convTest_->getStatus() != Passed)
2022  isConverged = false;
2023  }
2024  } // end catch (const GmresIterationOrthoFailure &e)
2025  catch (const StatusTestNaNError& e) {
2026  // A NaN was detected in the solver. Set the solution to zero and return unconverged.
2027  achievedTol_ = MT::one();
2028  Teuchos::RCP<MV> X = problem_->getLHS();
2029  MVT::MvInit( *X, SCT::zero() );
2030  printer_->stream(Warnings) << "Belos::BlockGCRODRSolMgr::solve(): Warning! NaN has been detected!"
2031  << std::endl;
2032  return Unconverged;
2033  }
2034  catch (const std::exception &e) {
2035  printer_->stream(Errors) << "Error! Caught std::exception in BlockGmresIter::iterate() at iteration "
2036  << block_gmres_iter->getNumIters() << std::endl
2037  << e.what() << std::endl;
2038  throw;
2039  }
2040 
2041  // Record number of iterations in generating initial recycle spacec
2042  //prime_iterations = block_gmres_iter->getNumIters();//instantiated here because it is not needed outside of else{} scope; we'll see if this is true or not
2043 
2044  // Update the linear problem.
2045  RCP<MV> update = block_gmres_iter->getCurrentUpdate();
2046  problem_->updateSolution( update, true );
2047 
2048  // Update the block residual
2049 
2050  problem_->computeCurrPrecResVec( &*R_ );
2051 
2052  // Get the state.
2053  newstate = block_gmres_iter->getState();
2054  int p = newstate.curDim;
2055  (void) p; // silence compiler warning for unused variable
2056  H_->assign(*(newstate.H));//IS THIS A GOOD IDEA? I DID IT SO MEMBERS WOULD HAVE ACCESS TO H.
2057  // Get new Krylov vectors, store in V_
2058 
2059  // Since the block_gmres_iter returns the state
2060  // with const RCP's we need to cast newstate.V as
2061  // a non const RCP. This is okay because block_gmres_iter
2062  // is about to fall out of scope, so we are simply
2063  // rescuing *newstate.V from being destroyed so we can
2064  // use it for future block recycled GMRES cycles
2065  V_ = rcp_const_cast<MV>(newstate.V);
2066  newstate.V.release();
2067  //COMPUTE NEW RECYCLE SPACE SOMEHOW
2068  buildRecycleSpaceKryl(keff, block_gmres_iter);
2069  printer_->stream(Debug) << "Generated recycled subspace using RHS index " << currIdx[0] << " of dimension " << keff << std::endl << std::endl;
2070 
2071  // Return to outer loop if the priming solve
2072  // converged, set the next linear system.
2073  if (primeConverged) {
2074  /* MLP: POSSIBLY INCORRECT CODE WE ARE REPLACING *********************************
2075  // Inform the linear problem that we are
2076  // finished with this block linear system.
2077  problem_->setCurrLS();
2078 
2079  // Update indices for the linear systems to be solved.
2080  // KMS: Fix the numRHS2Solve; Copy from Heidi's BlockGmres code
2081  numRHS2Solve -= 1;
2082  printer_->stream(Debug) << numRHS2Solve << " Right hand sides left to solve" << std::endl;
2083  if ( numRHS2Solve > 0 ) {
2084  currIdx[0]++;
2085  // Set the next indices
2086  problem_->setLSIndex( currIdx );
2087  }
2088  else {
2089  currIdx.resize( numRHS2Solve );
2090  }
2091  *****************************************************************************/
2092 
2093  // Inform the linear problem that we are finished with this block linear system.
2094  problem_->setCurrLS();
2095 
2096  // Update indices for the linear systems to be solved.
2097  startPtr += numCurrRHS;
2098  numRHS2Solve -= numCurrRHS;
2099  if ( numRHS2Solve > 0 ) {
2100  numCurrRHS = ( numRHS2Solve < blockSize_) ? numRHS2Solve : blockSize_;
2101  if ( adaptiveBlockSize_ ) {
2102  blockSize_ = numCurrRHS;
2103  currIdx.resize( numCurrRHS );
2104  for (int i=0; i<numCurrRHS; ++i) currIdx[i] = startPtr+i;
2105  }
2106  else {
2107  currIdx.resize( blockSize_ );
2108  for (int i=0; i<numCurrRHS; ++i) currIdx[i] = startPtr+i;
2109  for (int i=numCurrRHS; i<blockSize_; ++i) currIdx[i] = -1;
2110  }
2111  // Set the next indices.
2112  problem_->setLSIndex( currIdx );
2113  }
2114  else {
2115  currIdx.resize( numRHS2Solve );
2116  }
2117  continue;//Begin solving the next block of RHS's
2118  } //end if (primeConverged)
2119  } //end else [if(keff > 0)]
2120 
2121  // *****************************************
2122  // Initial subspace update/construction done
2123  // Start cycles of recycled GMRES
2124  // *****************************************
2125  Teuchos::ParameterList blockgcrodrList;
2126  blockgcrodrList.set("Num Blocks",numBlocks_);
2127  blockgcrodrList.set("Block Size",blockSize_);
2128  blockgcrodrList.set("Recycled Blocks",keff);
2129 
2131  block_gcrodr_iter = Teuchos::rcp( new BlockGCRODRIter<ScalarType,MV,OP>(problem_,printer_,outputTest_,ortho_,blockgcrodrList) );
2133 
2134  index.resize( blockSize_ );
2135  for(int ii = 0; ii < blockSize_; ii++) index[ii] = ii;
2136  Teuchos::RCP<MV> V0 = MVT::CloneViewNonConst( *V_, index );
2137 
2138  // MLP: MVT::SetBlock(*R_,index,*V0);
2139  MVT::Assign(*R_,*V0);
2140 
2141  index.resize(keff);//resize to get appropriate recycle space vectors
2142  for(int i=0; i < keff; i++){ index[i] = i;};
2143  B_ = rcp(new SDM(Teuchos::View, *G_, keff, numBlocks_*blockSize_, 0, keff));
2144  H_ = rcp(new SDM(Teuchos::View, *G_, (numBlocks_-1)*blockSize_ + blockSize_, (numBlocks_-1)*blockSize_, keff ,keff ));
2145 
2146  newstate.V = V_;
2147  newstate.B= B_;
2148  newstate.U = MVT::CloneViewNonConst(*U_, index);
2149  newstate.C = MVT::CloneViewNonConst(*C_, index);
2150  newstate.H = H_;
2151  newstate.curDim = blockSize_;
2152  block_gcrodr_iter -> initialize(newstate);
2153 
2154  int numRestarts = 0;
2155 
2156  while(1){//Each execution of this loop is a cycle of block GCRODR
2157  try{
2158  block_gcrodr_iter -> iterate();
2159 
2160  // ***********************
2161  // Check Convergence First
2162  // ***********************
2163  if( convTest_->getStatus() == Passed ) {
2164  // we have convergence
2165  break;//from while(1)
2166  } //end if converged
2167 
2168  // ***********************************
2169  // Check if maximum iterations reached
2170  // ***********************************
2171  else if(maxIterTest_->getStatus() == Passed ){
2172  // no convergence; hit maxit
2173  isConverged = false;
2174  break; // from while(1)
2175  } //end elseif reached maxit
2176 
2177  // **********************************************
2178  // Check if subspace full; do we need to restart?
2179  // **********************************************
2180  else if (block_gcrodr_iter->getCurSubspaceDim() == block_gcrodr_iter->getMaxSubspaceDim()){
2181 
2182  // Update recycled space even if we have reached max number of restarts
2183 
2184  // Update linear problem
2185  Teuchos::RCP<MV> update = block_gcrodr_iter->getCurrentUpdate();
2186  problem_->updateSolution(update, true);
2187  buildRecycleSpaceAugKryl(block_gcrodr_iter);
2188 
2189  printer_->stream(Debug) << " Generated new recycled subspace using RHS index " << currIdx[0] << " of dimension " << keff << std::endl << std::endl;
2190  // NOTE: If we have hit the maximum number of restarts, then we will quit
2191  if(numRestarts >= maxRestarts_) {
2192  isConverged = false;
2193  break; //from while(1)
2194  } //end if max restarts
2195 
2196  numRestarts++;
2197 
2198  printer_ -> stream(Debug) << " Performing restart number " << numRestarts << " of " << maxRestarts_ << std::endl << std::endl;
2199 
2200  // Create the restart vector (first block in the current Krylov basis)
2201  problem_->computeCurrPrecResVec( &*R_ );
2202  index.resize( blockSize_ );
2203  for (int ii=0; ii<blockSize_; ++ii) index[ii] = ii;
2204  Teuchos::RCP<MV> V0 = MVT::CloneViewNonConst( *V_, index );
2205  MVT::SetBlock(*R_,index,*V0);
2206 
2207  // Set the new state and initialize the solver.
2209  index.resize( numBlocks_*blockSize_ );
2210  for (int ii=0; ii<(numBlocks_*blockSize_); ++ii) index[ii] = ii;
2211  restartState.V = MVT::CloneViewNonConst( *V_, index );
2212  index.resize( keff );
2213  for (int ii=0; ii<keff; ++ii) index[ii] = ii;
2214  restartState.U = MVT::CloneViewNonConst( *U_, index );
2215  restartState.C = MVT::CloneViewNonConst( *C_, index );
2216  B_ = rcp(new SDM(Teuchos::View, *G_, keff, (numBlocks_-1)*blockSize_, 0, keff));
2217  H_ = rcp(new SDM(Teuchos::View, *G_, numBlocks_*blockSize_, (numBlocks_-1)*blockSize_, keff ,keff ));
2218  restartState.B = B_;
2219  restartState.H = H_;
2220  restartState.curDim = blockSize_;
2221  block_gcrodr_iter->initialize(restartState);
2222 
2223  } //end else if need to restart
2224 
2225  // ****************************************************************
2226  // We returned from iterate(), but none of our status tests passed.
2227  // Something is wrong, and it is probably our fault.
2228  // ****************************************************************
2229  else {
2230  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"Belos::BlockGCRODRSolMgr::solve(): Invalid return from BlockGCRODRIter::iterate().");
2231  } //end else (no status test passed)
2232 
2233  }//end try
2234  catch(const BlockGCRODRIterOrthoFailure &e){ //there was an exception
2235  // Try to recover the most recent least-squares solution
2236  block_gcrodr_iter->updateLSQR( block_gcrodr_iter->getCurSubspaceDim() );
2237  // Check to see if the most recent least-squares solution yielded convergence.
2238  sTest_->checkStatus( &*block_gcrodr_iter );
2239  if (convTest_->getStatus() != Passed) isConverged = false;
2240  break;
2241  } // end catch orthogonalization failure
2242  catch(const std::exception &e){
2243  printer_->stream(Errors) << "Error! Caught exception in BlockGCRODRIter::iterate() at iteration "
2244  << block_gcrodr_iter->getNumIters() << std::endl
2245  << e.what() << std::endl;
2246  throw;
2247  } //end catch standard exception
2248  } //end while(1)
2249 
2250  // Compute the current solution.
2251  // Update the linear problem.
2252  Teuchos::RCP<MV> update = block_gcrodr_iter->getCurrentUpdate();
2253  problem_->updateSolution( update, true );
2254 
2255  /* MLP: POSSIBLY INCORRECT CODE WE ARE REPLACING *********************************
2256  // Inform the linear problem that we are finished with this block linear system.
2257  problem_->setCurrLS();
2258 
2259  // Update indices for the linear systems to be solved.
2260  numRHS2Solve -= 1;
2261  if ( numRHS2Solve > 0 ) {
2262  currIdx[0]++;
2263  // Set the next indices.
2264  problem_->setLSIndex( currIdx );
2265  }
2266  else {
2267  currIdx.resize( numRHS2Solve );
2268  }
2269  ******************************************************************************/
2270 
2271  // Inform the linear problem that we are finished with this block linear system.
2272  problem_->setCurrLS();
2273 
2274  // Update indices for the linear systems to be solved.
2275  startPtr += numCurrRHS;
2276  numRHS2Solve -= numCurrRHS;
2277  if ( numRHS2Solve > 0 ) {
2278  numCurrRHS = ( numRHS2Solve < blockSize_) ? numRHS2Solve : blockSize_;
2279  if ( adaptiveBlockSize_ ) {
2280  blockSize_ = numCurrRHS;
2281  currIdx.resize( numCurrRHS );
2282  for (int i=0; i<numCurrRHS; ++i) currIdx[i] = startPtr+i;
2283  }
2284  else {
2285  currIdx.resize( blockSize_ );
2286  for (int i=0; i<numCurrRHS; ++i) currIdx[i] = startPtr+i;
2287  for (int i=numCurrRHS; i<blockSize_; ++i) currIdx[i] = -1;
2288  }
2289  // Set the next indices.
2290  problem_->setLSIndex( currIdx );
2291  }
2292  else {
2293  currIdx.resize( numRHS2Solve );
2294  }
2295 
2296  // If we didn't build a recycle space this solve but ran at least k iterations, force build of new recycle space
2297  if (!builtRecycleSpace_) {
2298  buildRecycleSpaceAugKryl(block_gcrodr_iter);
2299  printer_->stream(Debug) << " Generated new recycled subspace using RHS index " << currIdx[0] << " of dimension " << keff << std::endl << std::endl;
2300  }
2301  }//end while (numRHS2Solve > 0)
2302 
2303  // print final summary
2304  sTest_->print( printer_->stream(FinalSummary) );
2305 
2306  // print timing information
2307  #ifdef BELOS_TEUCHOS_TIME_MONITOR
2308  // Calling summarize() can be expensive, so don't call unless the user wants to print out timing details.
2309  // summarize() will do all the work even if it's passed a "black hole" output stream.
2310  if (verbosity_ & TimingDetails) Teuchos::TimeMonitor::summarize( printer_->stream(TimingDetails) );
2311  #endif
2312  // get iteration information for this solve
2313  numIters_ = maxIterTest_->getNumIters();
2314 
2315  // get residual information for this solve
2316  const std::vector<MagnitudeType>* pTestValues = NULL;
2317  pTestValues = impConvTest_->getTestValue();
2318  TEUCHOS_TEST_FOR_EXCEPTION(pTestValues == NULL, std::logic_error,
2319  "Belos::BlockGCRODRSolMgr::solve(): The implicit convergence test's "
2320  "getTestValue() method returned NULL. Please report this bug to the "
2321  "Belos developers.");
2322  TEUCHOS_TEST_FOR_EXCEPTION(pTestValues->size() < 1, std::logic_error,
2323  "Belos::BlockGCRODRSolMgr::solve(): The implicit convergence test's "
2324  "getTestValue() method returned a vector of length zero. Please report "
2325  "this bug to the Belos developers.");
2326  // FIXME (mfh 12 Dec 2011) Does pTestValues really contain the
2327  // achieved tolerances for all vectors in the current solve(), or
2328  // just for the vectors from the last deflation?
2329  achievedTol_ = *std::max_element (pTestValues->begin(), pTestValues->end());
2330 
2331  if (!isConverged) return Unconverged; // return from BlockGCRODRSolMgr::solve()
2332  return Converged; // return from BlockGCRODRSolMgr::solve()
2333 } //end solve()
2334 
2335 } //End Belos Namespace
2336 
2337 #endif /* BELOS_BLOCK_GCRODR_SOLMGR_HPP */
ScaleType convertStringToScaleType(const std::string &scaleType)
Convert the given string to its ScaleType enum value.
Definition: BelosTypes.cpp:74
ScalarType * values() const
Collection of types and exceptions used within the Belos solvers.
const LinearProblem< ScalarType, MV, OP > & getProblem() const
Get current linear problem being solved for in this object.
OperatorTraits< ScalarType, MV, OP > OPT
Belos&#39;s basic output manager for sending information of select verbosity levels to the appropriate ou...
int getHarmonicVecsAugKryl(int keff, int m, const SDM &HH, const Teuchos::RCP< const MV > &VV, SDM &PP)
Teuchos::LAPACK< int, ScalarType > lapack
Class which manages the output and verbosity of the Belos solvers.
Structure to contain pointers to BlockGCRODRIter state variables.
static const bool adaptiveBlockSize_default_
virtual ~BlockGCRODRSolMgr()
Destructor.
Teuchos::RCP< StatusTestOutput< ScalarType, MV, OP > > outputTest_
int getNumIters() const
Get the iteration count for the most recent call to solve().
Teuchos::RCP< MatOrthoManager< ScalarType, MV, OP > > ortho_
Orthogonalization manager.
static void clearCounter(const std::string &name)
bool loaDetected_
Whether a loss of accuracy was detected during the solve.
OrthoManagerFactory< ScalarType, MV, OP > ortho_factory_type
ScaleType
The type of scaling to use on the residual norm value.
Definition: BelosTypes.hpp:88
Teuchos::RCP< Teuchos::SerialDenseMatrix< int, ScalarType > > B
The projection of the Krylov subspace against the recycled subspace *.
Exception thrown to signal error in a status test during Belos::StatusTest::checkStatus().
void buildRecycleSpaceAugKryl(Teuchos::RCP< BlockGCRODRIter< ScalarType, MV, OP > > gcrodr_iter)
Teuchos::RCP< const Teuchos::ParameterList > getCurrentParameters() const
Get a parameter list containing the current parameters for this object.
This class implements the block GMRES iteration, where a block Krylov subspace is constructed...
Teuchos::RCP< const MV > V
The current Krylov basis.
T & get(ParameterList &l, const std::string &name)
BlockGCRODRIterOrthoFailure is thrown when the BlockGCRODRIter object is unable to compute independen...
static RCP< Time > getNewCounter(const std::string &name)
Teuchos::ScalarTraits< MagnitudeType > SMT
int multiply(ETransp transa, ETransp transb, ScalarType alpha, const SerialDenseMatrix< OrdinalType, ScalarType > &A, const SerialDenseMatrix< OrdinalType, ScalarType > &B, ScalarType beta)
Thrown when the linear problem was not set up correctly.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
A factory class for generating StatusTestOutput objects.
static magnitudeType real(T a)
void setParameters(const Teuchos::RCP< Teuchos::ParameterList > &params)
Set the parameters the solver should use to solve the linear problem.
bool isSet_
Whether setParameters() successfully finished setting parameters.
Teuchos::RCP< const Teuchos::SerialDenseMatrix< int, ScalarType > > z
The current right-hand side of the least squares system RY = Z.
An implementation of StatusTestResNorm using a family of residual norms.
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
Teuchos::RCP< StatusTest< ScalarType, MV, OP > > sTest_
Teuchos::SerialDenseVector< int, ScalarType > SDV
Structure to contain pointers to GmresIteration state variables.
Belos::StatusTest class for specifying a maximum number of iterations.
Teuchos::RCP< StatusTestGenResNorm< ScalarType, MV, OP > > expConvTest_
Teuchos::RCP< Teuchos::ParameterList > params_
This solver&#39;s current parameter list.
BlockGCRODRSolMgrRecyclingFailure(const std::string &what_arg)
void reset(const ResetType type)
Performs a reset of the solver manager specified by the ResetType.
Thrown if any problem occurs in using or creating the recycle subspace.
A factory class for generating StatusTestOutput objects.
Teuchos::RCP< MV > V
The current Krylov basis.
BlockGCRODRSolMgrOrthoFailure(const std::string &what_arg)
int curDim
The current dimension of the reduction.
Traits class which defines basic operations on multivectors.
Belos::StatusTest for logically combining several status tests.
MultiVecTraits< ScalarType, MV > MVT
Teuchos::RCP< Teuchos::Time > timerSolve_
Timer for solve().
Teuchos::ScalarTraits< MagnitudeType > MT
void sort(std::vector< MagnitudeType > &dlist, int n, std::vector< int > &iperm)
Teuchos::ScalarTraits< ScalarType >::magnitudeType MagnitudeType
A Belos::StatusTest class for specifying a maximum number of iterations.
ResetType
How to reset the solver.
Definition: BelosTypes.hpp:174
BlockGCRODRSolMgrLAPACKFailure(const std::string &what_arg)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Teuchos::RCP< LinearProblem< ScalarType, MV, OP > > problem_
The current linear problem to solve.
A solver manager for the Block GCRO-DR (Block Recycling GMRES) linear solver.
Pure virtual base class which describes the basic interface for a solver manager. ...
int curDim
The current dimension of the reduction.
static const std::string recycleMethod_default_
static void summarize(Ptr< const Comm< int > > comm, std::ostream &out=std::cout, const bool alwaysWriteLocal=false, const bool writeGlobalStats=true, const bool writeZeroTimers=true, const ECounterSetOp setOp=Intersection, const std::string &filter="", const bool ignoreZeroTimers=false)
bool is_null(const RCP< T > &p)
MagnitudeType achievedTol() const
Get the residual for the most recent call to solve().
Belos concrete class for performing the block GCRO-DR (block GMRES with recycling) iteration...
int putScalar(const ScalarType value=Teuchos::ScalarTraits< ScalarType >::zero())
std::vector< ScalarType > work_
BlockGCRODRSolMgr()
Default constructor.
A linear system to solve, and its associated information.
std::string description() const
A description of the Block GCRODR solver manager.
Class which describes the linear problem to be solved by the iterative solver.
void setProblem(const Teuchos::RCP< LinearProblem< ScalarType, MV, OP > > &problem)
Set the linear problem to solve on the next call to solve().
void validateParametersAndSetDefaults(ParameterList const &validParamList, int const depth=1000)
Teuchos::RCP< OutputManager< ScalarType > > printer_
ReturnType
Whether the Belos solve converged for all linear systems.
Definition: BelosTypes.hpp:123
The Belos::SolverManager is a templated virtual base class that defines the basic interface that any ...
Thrown when the solution manager was unable to orthogonalize the basis vectors.
Teuchos::RCP< MV > U
The recycled subspace and its projection.
Teuchos::ScalarTraits< ScalarType > SCT
Teuchos::RCP< StatusTestGenResNorm< ScalarType, MV, OP > > impConvTest_
Belos concrete class for performing the block GMRES iteration.
Ptr< T > release()
Implementation of the Block GCRO-DR (Block Recycling GMRES) iteration.
Teuchos::RCP< std::ostream > outputStream_
void buildRecycleSpaceKryl(int &keff, Teuchos::RCP< BlockGmresIter< ScalarType, MV, OP > > block_gmres_iter)
static magnitudeType magnitude(T a)
OrdinalType numCols() const
int setTolerance(MagnitudeType tolerance)
Set the value of the tolerance.
Teuchos::RCP< StatusTestOutput< ScalarType, MV, OP > > create(const Teuchos::RCP< OutputManager< ScalarType > > &printer, Teuchos::RCP< StatusTest< ScalarType, MV, OP > > test, int mod, int printStates)
Create the StatusTestOutput object specified by the outputStyle.
Teuchos::RCP< StatusTest< ScalarType, MV, OP > > convTest_
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Get a parameter list containing the valid parameters for this object.
Belos::StatusTestResNorm for specifying general residual norm stopping criteria.
Teuchos::RCP< Teuchos::SerialDenseMatrix< int, ScalarType > > H
The current Hessenberg matrix.
An implementation of the Belos::MatOrthoManager that performs orthogonalization using (potentially) m...
A class for extending the status testing capabilities of Belos via logical combinations.
int getHarmonicVecsKryl(int m, const SDM &HH, SDM &PP)
Class which defines basic traits for the operator type.
Teuchos::RCP< StatusTestMaxIters< ScalarType, MV, OP > > maxIterTest_
Parent class to all Belos exceptions.
Definition: BelosTypes.hpp:28
Pure virtual base class which augments the basic interface for a Gmres linear solver iteration...
GmresIterationOrthoFailure is thrown when the GmresIteration object is unable to compute independent ...
Belos header file which uses auto-configuration information to include necessary C++ headers...
BlockGCRODRSolMgrLinearProblemFailure(const std::string &what_arg)
std::vector< ScalarType > tau_
SerialDenseMatrix< OrdinalType, ScalarType > & assign(const SerialDenseMatrix< OrdinalType, ScalarType > &Source)
Teuchos::RCP< const Teuchos::ParameterList > defaultParams_
Default parameter list.
Teuchos::SerialDenseMatrix< int, ScalarType > SDM
ReturnType solve()
Solve the current linear problem.
bool builtRecycleSpace_
Whether we have generated or regenerated a recycle space yet this solve.
Thrown when an LAPACK call fails.
OrdinalType stride() const
ortho_factory_type orthoFactory_
Factory for creating MatOrthoManager subclass instances.
OrdinalType numRows() const
Belos concrete class for performing the block, flexible GMRES iteration.
bool isLOADetected() const
Whether a loss of accuracy was detected during the most recent solve.
OutputType
Style of output used to display status test information.
Definition: BelosTypes.hpp:109
Teuchos::RCP< const Teuchos::SerialDenseMatrix< int, ScalarType > > H
The current Hessenberg matrix.