Anasazi  Version of the Day
AnasaziBlockKrylovSchurSolMgr.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Anasazi: Block Eigensolvers Package
5 // Copyright 2004 Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8 // the U.S. Government retains certain rights in this software.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #ifndef ANASAZI_BLOCK_KRYLOV_SCHUR_SOLMGR_HPP
43 #define ANASAZI_BLOCK_KRYLOV_SCHUR_SOLMGR_HPP
44 
48 
49 #include "AnasaziConfigDefs.hpp"
50 #include "AnasaziTypes.hpp"
51 
52 #include "AnasaziEigenproblem.hpp"
53 #include "AnasaziSolverManager.hpp"
54 #include "AnasaziSolverUtils.hpp"
55 
57 #include "AnasaziBasicSort.hpp"
65 #include "Teuchos_BLAS.hpp"
66 #include "Teuchos_LAPACK.hpp"
67 #include "Teuchos_TimeMonitor.hpp"
68 
75 
123 namespace Anasazi {
124 
125 
152 template<class ScalarType, class MV, class OP>
153 class BlockKrylovSchurSolMgr : public SolverManager<ScalarType,MV,OP> {
154 
155  private:
158  typedef Teuchos::ScalarTraits<ScalarType> SCT;
159  typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MagnitudeType;
160  typedef Teuchos::ScalarTraits<MagnitudeType> MT;
161 
162  public:
163 
165 
166 
184  BlockKrylovSchurSolMgr( const Teuchos::RCP<Eigenproblem<ScalarType,MV,OP> > &problem,
185  Teuchos::ParameterList &pl );
186 
190 
192 
193 
196  return *_problem;
197  }
198 
200  int getNumIters() const {
201  return _numIters;
202  }
203 
206  std::vector<Value<ScalarType> > getRitzValues() const {
207  std::vector<Value<ScalarType> > ret( _ritzValues );
208  return ret;
209  }
210 
217  Teuchos::Array<Teuchos::RCP<Teuchos::Time> > getTimers() const {
218  return Teuchos::tuple(_timerSolve, _timerRestarting);
219  }
220 
222 
224 
225 
244  ReturnType solve();
245 
247  void setGlobalStatusTest(const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &global);
248 
250  const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > & getGlobalStatusTest() const;
251 
253  void setDebugStatusTest(const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &debug);
254 
256  const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > & getDebugStatusTest() const;
257 
259 
260  private:
261  Teuchos::RCP<Eigenproblem<ScalarType,MV,OP> > _problem;
262  Teuchos::RCP<SortManager<MagnitudeType> > _sort;
263 
264  std::string _whch, _ortho;
265  MagnitudeType _ortho_kappa;
266 
267  MagnitudeType _convtol;
268  int _maxRestarts;
269  bool _relconvtol,_conjSplit;
270  int _blockSize, _numBlocks, _stepSize, _nevBlocks, _xtra_nevBlocks;
271  int _numIters;
272  int _verbosity;
273  bool _inSituRestart, _dynXtraNev;
274 
275  std::vector<Value<ScalarType> > _ritzValues;
276 
277  int _printNum;
278  Teuchos::RCP<Teuchos::Time> _timerSolve, _timerRestarting;
279 
280  Teuchos::RCP<StatusTest<ScalarType,MV,OP> > globalTest_;
281  Teuchos::RCP<StatusTest<ScalarType,MV,OP> > debugTest_;
282 
283 };
284 
285 
286 // Constructor
287 template<class ScalarType, class MV, class OP>
289  const Teuchos::RCP<Eigenproblem<ScalarType,MV,OP> > &problem,
290  Teuchos::ParameterList &pl ) :
291  _problem(problem),
292  _whch("LM"),
293  _ortho("SVQB"),
294  _ortho_kappa(-1.0),
295  _convtol(0),
296  _maxRestarts(20),
297  _relconvtol(true),
298  _conjSplit(false),
299  _blockSize(0),
300  _numBlocks(0),
301  _stepSize(0),
302  _nevBlocks(0),
303  _xtra_nevBlocks(0),
304  _numIters(0),
305  _verbosity(Anasazi::Errors),
306  _inSituRestart(false),
307  _dynXtraNev(false),
308  _printNum(-1)
309 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
310  ,_timerSolve(Teuchos::TimeMonitor::getNewTimer("Anasazi: BlockKrylovSchurSolMgr::solve()")),
311  _timerRestarting(Teuchos::TimeMonitor::getNewTimer("Anasazi: BlockKrylovSchurSolMgr restarting"))
312 #endif
313 {
314  TEUCHOS_TEST_FOR_EXCEPTION(_problem == Teuchos::null, std::invalid_argument, "Problem not given to solver manager.");
315  TEUCHOS_TEST_FOR_EXCEPTION(!_problem->isProblemSet(), std::invalid_argument, "Problem not set.");
316  TEUCHOS_TEST_FOR_EXCEPTION(_problem->getInitVec() == Teuchos::null, std::invalid_argument, "Problem does not contain initial vectors to clone from.");
317 
318  const int nev = _problem->getNEV();
319 
320  // convergence tolerance
321  _convtol = pl.get("Convergence Tolerance",MT::prec());
322  _relconvtol = pl.get("Relative Convergence Tolerance",_relconvtol);
323 
324  // maximum number of restarts
325  _maxRestarts = pl.get("Maximum Restarts",_maxRestarts);
326 
327  // block size: default is 1
328  _blockSize = pl.get("Block Size",1);
329  TEUCHOS_TEST_FOR_EXCEPTION(_blockSize <= 0, std::invalid_argument,
330  "Anasazi::BlockKrylovSchurSolMgr: \"Block Size\" must be strictly positive.");
331 
332  // set the number of blocks we need to save to compute the nev eigenvalues of interest.
333  _xtra_nevBlocks = pl.get("Extra NEV Blocks",0);
334  if (nev%_blockSize) {
335  _nevBlocks = nev/_blockSize + 1;
336  } else {
337  _nevBlocks = nev/_blockSize;
338  }
339 
340  // determine if we should use the dynamic scheme for selecting the current number of retained eigenvalues.
341  // NOTE: This employs a technique similar to ARPACK in that it increases the number of retained eigenvalues
342  // by one for every converged eigenpair to accelerate convergence.
343  if (pl.isParameter("Dynamic Extra NEV")) {
344  if (Teuchos::isParameterType<bool>(pl,"Dynamic Extra NEV")) {
345  _dynXtraNev = pl.get("Dynamic Extra NEV",_dynXtraNev);
346  } else {
347  _dynXtraNev = ( Teuchos::getParameter<int>(pl,"Dynamic Extra NEV") != 0 );
348  }
349  }
350 
351  _numBlocks = pl.get("Num Blocks",3*_nevBlocks);
352  TEUCHOS_TEST_FOR_EXCEPTION(_numBlocks <= _nevBlocks, std::invalid_argument,
353  "Anasazi::BlockKrylovSchurSolMgr: \"Num Blocks\" must be strictly positive and large enough to compute the requested eigenvalues.");
354 
355  TEUCHOS_TEST_FOR_EXCEPTION(static_cast<ptrdiff_t>(_numBlocks)*_blockSize > MVT::GetGlobalLength(*_problem->getInitVec()),
356  std::invalid_argument,
357  "Anasazi::BlockKrylovSchurSolMgr: Potentially impossible orthogonality requests. Reduce basis size.");
358 
359  // step size: the default is _maxRestarts*_numBlocks, so that Ritz values are only computed every restart.
360  if (_maxRestarts) {
361  _stepSize = pl.get("Step Size", (_maxRestarts+1)*(_numBlocks+1));
362  } else {
363  _stepSize = pl.get("Step Size", _numBlocks+1);
364  }
365  TEUCHOS_TEST_FOR_EXCEPTION(_stepSize < 1, std::invalid_argument,
366  "Anasazi::BlockKrylovSchurSolMgr: \"Step Size\" must be strictly positive.");
367 
368  // get the sort manager
369  if (pl.isParameter("Sort Manager")) {
370  _sort = Teuchos::getParameter<Teuchos::RCP<Anasazi::SortManager<MagnitudeType> > >(pl,"Sort Manager");
371  } else {
372  // which values to solve for
373  _whch = pl.get("Which",_whch);
374  TEUCHOS_TEST_FOR_EXCEPTION(_whch != "SM" && _whch != "LM" && _whch != "SR" && _whch != "LR" && _whch != "SI" && _whch != "LI",
375  std::invalid_argument, "Invalid sorting string.");
376  _sort = Teuchos::rcp( new BasicSort<MagnitudeType>(_whch) );
377  }
378 
379  // which orthogonalization to use
380  _ortho = pl.get("Orthogonalization",_ortho);
381  if (_ortho != "DGKS" && _ortho != "SVQB") {
382  _ortho = "SVQB";
383  }
384 
385  // which orthogonalization constant to use
386  _ortho_kappa = pl.get("Orthogonalization Constant",_ortho_kappa);
387 
388  // verbosity level
389  if (pl.isParameter("Verbosity")) {
390  if (Teuchos::isParameterType<int>(pl,"Verbosity")) {
391  _verbosity = pl.get("Verbosity", _verbosity);
392  } else {
393  _verbosity = (int)Teuchos::getParameter<Anasazi::MsgType>(pl,"Verbosity");
394  }
395  }
396 
397  // restarting technique: V*Q or applyHouse(V,H,tau)
398  if (pl.isParameter("In Situ Restarting")) {
399  if (Teuchos::isParameterType<bool>(pl,"In Situ Restarting")) {
400  _inSituRestart = pl.get("In Situ Restarting",_inSituRestart);
401  } else {
402  _inSituRestart = ( Teuchos::getParameter<int>(pl,"In Situ Restarting") != 0 );
403  }
404  }
405 
406  _printNum = pl.get<int>("Print Number of Ritz Values",-1);
407 }
408 
409 
410 // solve()
411 template<class ScalarType, class MV, class OP>
414 
415  const int nev = _problem->getNEV();
416  ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
417  ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
418 
419  Teuchos::BLAS<int,ScalarType> blas;
420  Teuchos::LAPACK<int,ScalarType> lapack;
421  typedef SolverUtils<ScalarType,MV,OP> msutils;
422 
424  // Output manager
425  Teuchos::RCP<BasicOutputManager<ScalarType> > printer = Teuchos::rcp( new BasicOutputManager<ScalarType>(_verbosity) );
426 
428  // Status tests
429  //
430  // convergence
431  Teuchos::RCP<StatusTest<ScalarType,MV,OP> > convtest;
432  if (globalTest_ == Teuchos::null) {
433  convtest = Teuchos::rcp( new StatusTestResNorm<ScalarType,MV,OP>(_convtol,nev,RITZRES_2NORM,_relconvtol) );
434  }
435  else {
436  convtest = globalTest_;
437  }
438  Teuchos::RCP<StatusTestWithOrdering<ScalarType,MV,OP> > ordertest
439  = Teuchos::rcp( new StatusTestWithOrdering<ScalarType,MV,OP>(convtest,_sort,nev) );
440  // for a non-short-circuited OR test, the order doesn't matter
441  Teuchos::Array<Teuchos::RCP<StatusTest<ScalarType,MV,OP> > > alltests;
442  alltests.push_back(ordertest);
443 
444  if (debugTest_ != Teuchos::null) alltests.push_back(debugTest_);
445 
446  Teuchos::RCP<StatusTestCombo<ScalarType,MV,OP> > combotest
448  // printing StatusTest
449  Teuchos::RCP<StatusTestOutput<ScalarType,MV,OP> > outputtest;
450  if ( printer->isVerbosity(Debug) ) {
451  outputtest = Teuchos::rcp( new StatusTestOutput<ScalarType,MV,OP>( printer,combotest,1,Passed+Failed+Undefined ) );
452  }
453  else {
454  outputtest = Teuchos::rcp( new StatusTestOutput<ScalarType,MV,OP>( printer,combotest,1,Passed ) );
455  }
456 
458  // Orthomanager
459  Teuchos::RCP<OrthoManager<ScalarType,MV> > ortho;
460  if (_ortho=="SVQB") {
461  ortho = Teuchos::rcp( new SVQBOrthoManager<ScalarType,MV,OP>(_problem->getM()) );
462  } else if (_ortho=="DGKS") {
463  if (_ortho_kappa <= 0) {
464  ortho = Teuchos::rcp( new BasicOrthoManager<ScalarType,MV,OP>(_problem->getM()) );
465  }
466  else {
467  ortho = Teuchos::rcp( new BasicOrthoManager<ScalarType,MV,OP>(_problem->getM(),_ortho_kappa) );
468  }
469  } else {
470  TEUCHOS_TEST_FOR_EXCEPTION(_ortho!="SVQB"&&_ortho!="DGKS",std::logic_error,"Anasazi::BlockKrylovSchurSolMgr::solve(): Invalid orthogonalization type.");
471  }
472 
474  // Parameter list
475  Teuchos::ParameterList plist;
476  plist.set("Block Size",_blockSize);
477  plist.set("Num Blocks",_numBlocks);
478  plist.set("Step Size",_stepSize);
479  if (_printNum == -1) {
480  plist.set("Print Number of Ritz Values",_nevBlocks*_blockSize);
481  }
482  else {
483  plist.set("Print Number of Ritz Values",_printNum);
484  }
485 
487  // BlockKrylovSchur solver
488  Teuchos::RCP<BlockKrylovSchur<ScalarType,MV,OP> > bks_solver
489  = Teuchos::rcp( new BlockKrylovSchur<ScalarType,MV,OP>(_problem,_sort,printer,outputtest,ortho,plist) );
490  // set any auxiliary vectors defined in the problem
491  Teuchos::RCP< const MV > probauxvecs = _problem->getAuxVecs();
492  if (probauxvecs != Teuchos::null) {
493  bks_solver->setAuxVecs( Teuchos::tuple< Teuchos::RCP<const MV> >(probauxvecs) );
494  }
495 
496  // Create workspace for the Krylov basis generated during a restart
497  // Need at most (_nevBlocks*_blockSize+1) for the updated factorization and another block for the current factorization residual block (F).
498  // ---> (_nevBlocks*_blockSize+1) + _blockSize
499  // If Hermitian, this becomes _nevBlocks*_blockSize + _blockSize
500  // we only need this if there is the possibility of restarting, ex situ
501 
502  // Maximum allowable extra vectors that BKS can keep to accelerate convergence
503  int maxXtraBlocks = 0;
504  if ( _dynXtraNev ) maxXtraBlocks = ( ( bks_solver->getMaxSubspaceDim() - nev ) / _blockSize ) / 2;
505 
506  Teuchos::RCP<MV> workMV;
507  if (_maxRestarts > 0) {
508  if (_inSituRestart==true) {
509  // still need one work vector for applyHouse()
510  workMV = MVT::Clone( *_problem->getInitVec(), 1 );
511  }
512  else { // inSituRestart == false
513  if (_problem->isHermitian()) {
514  workMV = MVT::Clone( *_problem->getInitVec(), (_nevBlocks+maxXtraBlocks)*_blockSize + _blockSize );
515  } else {
516  // Increase workspace by 1 because of potential complex conjugate pairs on the Ritz vector boundary
517  workMV = MVT::Clone( *_problem->getInitVec(), (_nevBlocks+maxXtraBlocks)*_blockSize + 1 + _blockSize );
518  }
519  }
520  } else {
521  workMV = Teuchos::null;
522  }
523 
524  // go ahead and initialize the solution to nothing in case we throw an exception
526  sol.numVecs = 0;
527  _problem->setSolution(sol);
528 
529  int numRestarts = 0;
530  int cur_nevBlocks = 0;
531 
532  // enter solve() iterations
533  {
534 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
535  Teuchos::TimeMonitor slvtimer(*_timerSolve);
536 #endif
537 
538  // tell bks_solver to iterate
539  while (1) {
540  try {
541  bks_solver->iterate();
542 
544  //
545  // check convergence first
546  //
548  if ( ordertest->getStatus() == Passed ) {
549  // we have convergence
550  // ordertest->whichVecs() tells us which vectors from solver state are the ones we want
551  // ordertest->howMany() will tell us how many
552  break;
553  }
555  //
556  // check for restarting, i.e. the subspace is full
557  //
559  // this is for the Hermitian case, or non-Hermitian conjugate split situation.
560  // --> for the Hermitian case the current subspace dimension needs to match the maximum subspace dimension
561  // --> for the non-Hermitian case:
562  // --> if a conjugate pair was detected in the previous restart then the current subspace dimension needs to match the
563  // maximum subspace dimension (the BKS solver keeps one extra vector if the problem is non-Hermitian).
564  // --> if a conjugate pair was not detected in the previous restart then the current subspace dimension will be one less
565  // than the maximum subspace dimension.
566  else if ( (bks_solver->getCurSubspaceDim() == bks_solver->getMaxSubspaceDim()) ||
567  (!_problem->isHermitian() && !_conjSplit && (bks_solver->getCurSubspaceDim()+1 == bks_solver->getMaxSubspaceDim())) ) {
568 
569  // Update the Schur form of the projected eigenproblem, then sort it.
570  if (!bks_solver->isSchurCurrent()) {
571  bks_solver->computeSchurForm( true );
572 
573  // Check for convergence, just in case we wait for every restart to check
574  outputtest->checkStatus( &*bks_solver );
575  }
576 
577  // Don't bother to restart if we've converged or reached the maximum number of restarts
578  if ( numRestarts >= _maxRestarts || ordertest->getStatus() == Passed) {
579  break; // break from while(1){bks_solver->iterate()}
580  }
581 
582  // Start restarting timer and increment counter
583 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
584  Teuchos::TimeMonitor restimer(*_timerRestarting);
585 #endif
586  numRestarts++;
587 
588  int numConv = ordertest->howMany();
589  cur_nevBlocks = _nevBlocks*_blockSize;
590 
591  // Add in extra blocks for restarting if either static or dynamic boundaries are being used.
592  int moreNevBlocks = std::min( maxXtraBlocks, std::max( numConv/_blockSize, _xtra_nevBlocks) );
593  if ( _dynXtraNev )
594  cur_nevBlocks += moreNevBlocks * _blockSize;
595  else if ( _xtra_nevBlocks )
596  cur_nevBlocks += _xtra_nevBlocks * _blockSize;
597 /*
598  int cur_numConv = numConv;
599  while ( (cur_nevBlocks < (_nevBlocks + maxXtraVecs)) && cur_numConv > 0 ) {
600  cur_nevBlocks++;
601  cur_numConv--;
602 */
603 
604  printer->stream(Debug) << " Performing restart number " << numRestarts << " of " << _maxRestarts << std::endl << std::endl;
605  printer->stream(Debug) << " - Current NEV blocks is " << cur_nevBlocks << ", the minimum is " << _nevBlocks*_blockSize << std::endl;
606 
607  // Get the most current Ritz values before we continue.
608  _ritzValues = bks_solver->getRitzValues();
609 
610  // Get the state.
611  BlockKrylovSchurState<ScalarType,MV> oldState = bks_solver->getState();
612 
613  // Get the current dimension of the factorization
614  int curDim = oldState.curDim;
615 
616  // Determine if the storage for the nev eigenvalues of interest splits a complex conjugate pair.
617  std::vector<int> ritzIndex = bks_solver->getRitzIndex();
618  if (ritzIndex[cur_nevBlocks-1]==1) {
619  _conjSplit = true;
620  cur_nevBlocks++;
621  } else {
622  _conjSplit = false;
623  }
624 
625  // Print out a warning to the user if complex eigenvalues were found on the boundary of the restart subspace
626  // and the eigenproblem is Hermitian. This solver is not prepared to handle this situation.
627  if (_problem->isHermitian() && _conjSplit)
628  {
629  printer->stream(Warnings)
630  << " Eigenproblem is Hermitian, complex eigenvalues have been detected, and eigenvalues of interest split a conjugate pair!!!"
631  << std::endl
632  << " Block Krylov-Schur eigensolver cannot guarantee correct behavior in this situation, please turn Hermitian flag off!!!"
633  << std::endl;
634  }
635 
636  // Update the Krylov-Schur decomposition
637 
638  // Get a view of the Schur vectors of interest.
639  Teuchos::SerialDenseMatrix<int,ScalarType> Qnev(Teuchos::View, *(oldState.Q), curDim, cur_nevBlocks);
640 
641  // Get a view of the current Krylov basis.
642  std::vector<int> curind( curDim );
643  for (int i=0; i<curDim; i++) { curind[i] = i; }
644  Teuchos::RCP<const MV> basistemp = MVT::CloneView( *(oldState.V), curind );
645 
646  // Compute the new Krylov basis: Vnew = V*Qnev
647  //
648  // this will occur ex situ in workspace allocated for this purpose (tmpMV)
649  // or in situ in the solver's memory space.
650  //
651  // we will also set a pointer for the location that the current factorization residual block (F),
652  // currently located after the current basis in oldstate.V, will be moved to
653  //
654  Teuchos::RCP<MV> newF;
655  if (_inSituRestart) {
656  //
657  // get non-const pointer to solver's basis so we can work in situ
658  Teuchos::RCP<MV> solverbasis = Teuchos::rcp_const_cast<MV>(oldState.V);
659  Teuchos::SerialDenseMatrix<int,ScalarType> copyQnev(Teuchos::Copy, Qnev);
660  //
661  // perform Householder QR of copyQnev = Q [D;0], where D is unit diag. We will want D below.
662  std::vector<ScalarType> tau(cur_nevBlocks), work(cur_nevBlocks);
663  int info;
664  lapack.GEQRF(curDim,cur_nevBlocks,copyQnev.values(),copyQnev.stride(),&tau[0],&work[0],work.size(),&info);
665  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
666  "Anasazi::BlockKrylovSchurSolMgr::solve(): error calling GEQRF during restarting.");
667  // we need to get the diagonal of D
668  std::vector<ScalarType> d(cur_nevBlocks);
669  for (int j=0; j<copyQnev.numCols(); j++) {
670  d[j] = copyQnev(j,j);
671  }
672  if (printer->isVerbosity(Debug)) {
673  Teuchos::SerialDenseMatrix<int,ScalarType> R(Teuchos::Copy,copyQnev,cur_nevBlocks,cur_nevBlocks);
674  for (int j=0; j<R.numCols(); j++) {
675  R(j,j) = SCT::magnitude(R(j,j)) - 1.0;
676  for (int i=j+1; i<R.numRows(); i++) {
677  R(i,j) = zero;
678  }
679  }
680  printer->stream(Debug) << "||Triangular factor of Su - I||: " << R.normFrobenius() << std::endl;
681  }
682  //
683  // perform implicit V*Qnev
684  // this actually performs V*[Qnev Qtrunc*M] = [newV truncV], for some unitary M
685  // we are interested in only the first cur_nevBlocks vectors of the result
686  curind.resize(curDim);
687  for (int i=0; i<curDim; i++) curind[i] = i;
688  {
689  Teuchos::RCP<MV> oldV = MVT::CloneViewNonConst(*solverbasis,curind);
690  msutils::applyHouse(cur_nevBlocks,*oldV,copyQnev,tau,workMV);
691  }
692  // multiply newV*D
693  // get pointer to new basis
694  curind.resize(cur_nevBlocks);
695  for (int i=0; i<cur_nevBlocks; i++) { curind[i] = i; }
696  {
697  Teuchos::RCP<MV> newV = MVT::CloneViewNonConst( *solverbasis, curind );
698  MVT::MvScale(*newV,d);
699  }
700  // get pointer to new location for F
701  curind.resize(_blockSize);
702  for (int i=0; i<_blockSize; i++) { curind[i] = cur_nevBlocks + i; }
703  newF = MVT::CloneViewNonConst( *solverbasis, curind );
704  }
705  else {
706  // get pointer to first part of work space
707  curind.resize(cur_nevBlocks);
708  for (int i=0; i<cur_nevBlocks; i++) { curind[i] = i; }
709  Teuchos::RCP<MV> tmp_newV = MVT::CloneViewNonConst(*workMV, curind );
710  // perform V*Qnev
711  MVT::MvTimesMatAddMv( one, *basistemp, Qnev, zero, *tmp_newV );
712  tmp_newV = Teuchos::null;
713  // get pointer to new location for F
714  curind.resize(_blockSize);
715  for (int i=0; i<_blockSize; i++) { curind[i] = cur_nevBlocks + i; }
716  newF = MVT::CloneViewNonConst( *workMV, curind );
717  }
718 
719  // Move the current factorization residual block (F) to the last block of newV.
720  curind.resize(_blockSize);
721  for (int i=0; i<_blockSize; i++) { curind[i] = curDim + i; }
722  Teuchos::RCP<const MV> oldF = MVT::CloneView( *(oldState.V), curind );
723  for (int i=0; i<_blockSize; i++) { curind[i] = i; }
724  MVT::SetBlock( *oldF, curind, *newF );
725  newF = Teuchos::null;
726 
727  // Update the Krylov-Schur quasi-triangular matrix.
728  //
729  // Create storage for the new Schur matrix of the Krylov-Schur factorization
730  // Copy over the current quasi-triangular factorization of oldState.H which is stored in oldState.S.
731  Teuchos::RCP<Teuchos::SerialDenseMatrix<int,ScalarType> > newH =
732  Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>(Teuchos::Copy, *(oldState.S), cur_nevBlocks+_blockSize, cur_nevBlocks) );
733  //
734  // Get a view of the B block of the current factorization
735  Teuchos::SerialDenseMatrix<int,ScalarType> oldB(Teuchos::View, *(oldState.H), _blockSize, _blockSize, curDim, curDim-_blockSize);
736  //
737  // Get a view of the a block row of the Schur vectors.
738  Teuchos::SerialDenseMatrix<int,ScalarType> subQ(Teuchos::View, *(oldState.Q), _blockSize, cur_nevBlocks, curDim-_blockSize);
739  //
740  // Get a view of the new B block of the updated Krylov-Schur factorization
741  Teuchos::SerialDenseMatrix<int,ScalarType> newB(Teuchos::View, *newH, _blockSize, cur_nevBlocks, cur_nevBlocks);
742  //
743  // Compute the new B block.
744  blas.GEMM( Teuchos::NO_TRANS, Teuchos::NO_TRANS, _blockSize, cur_nevBlocks, _blockSize, one,
745  oldB.values(), oldB.stride(), subQ.values(), subQ.stride(), zero, newB.values(), newB.stride() );
746 
747 
748  //
749  // Set the new state and initialize the solver.
751  if (_inSituRestart) {
752  newstate.V = oldState.V;
753  } else {
754  newstate.V = workMV;
755  }
756  newstate.H = newH;
757  newstate.curDim = cur_nevBlocks;
758  bks_solver->initialize(newstate);
759 
760  } // end of restarting
762  //
763  // we returned from iterate(), but none of our status tests Passed.
764  // something is wrong, and it is probably our fault.
765  //
767  else {
768  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"Anasazi::BlockKrylovSchurSolMgr::solve(): Invalid return from bks_solver::iterate().");
769  }
770  }
771  catch (const AnasaziError &err) {
772  printer->stream(Errors)
773  << "Anasazi::BlockKrylovSchurSolMgr::solve() caught unexpected exception from Anasazi::BlockKrylovSchur::iterate() at iteration " << bks_solver->getNumIters() << std::endl
774  << err.what() << std::endl
775  << "Anasazi::BlockKrylovSchurSolMgr::solve() returning Unconverged with no solutions." << std::endl;
776  return Unconverged;
777  }
778  }
779 
780  //
781  // free temporary space
782  workMV = Teuchos::null;
783 
784  // Get the most current Ritz values before we return
785  _ritzValues = bks_solver->getRitzValues();
786 
787  sol.numVecs = ordertest->howMany();
788  printer->stream(Debug) << "ordertest->howMany() : " << sol.numVecs << std::endl;
789  std::vector<int> whichVecs = ordertest->whichVecs();
790 
791  // Place any converged eigenpairs in the solution container.
792  if (sol.numVecs > 0) {
793 
794  // Next determine if there is a conjugate pair on the boundary and resize.
795  std::vector<int> tmpIndex = bks_solver->getRitzIndex();
796  for (int i=0; i<(int)_ritzValues.size(); ++i) {
797  printer->stream(Debug) << _ritzValues[i].realpart << " + i " << _ritzValues[i].imagpart << ", Index = " << tmpIndex[i] << std::endl;
798  }
799  printer->stream(Debug) << "Number of converged eigenpairs (before) = " << sol.numVecs << std::endl;
800  for (int i=0; i<sol.numVecs; ++i) {
801  printer->stream(Debug) << "whichVecs[" << i << "] = " << whichVecs[i] << ", tmpIndex[" << whichVecs[i] << "] = " << tmpIndex[whichVecs[i]] << std::endl;
802  }
803  if (tmpIndex[whichVecs[sol.numVecs-1]]==1) {
804  printer->stream(Debug) << "There is a conjugate pair on the boundary, resizing sol.numVecs" << std::endl;
805  whichVecs.push_back(whichVecs[sol.numVecs-1]+1);
806  sol.numVecs++;
807  for (int i=0; i<sol.numVecs; ++i) {
808  printer->stream(Debug) << "whichVecs[" << i << "] = " << whichVecs[i] << ", tmpIndex[" << whichVecs[i] << "] = " << tmpIndex[whichVecs[i]] << std::endl;
809  }
810  }
811 
812  bool keepMore = false;
813  int numEvecs = sol.numVecs;
814  printer->stream(Debug) << "Number of converged eigenpairs (after) = " << sol.numVecs << std::endl;
815  printer->stream(Debug) << "whichVecs[sol.numVecs-1] > sol.numVecs-1 : " << whichVecs[sol.numVecs-1] << " > " << sol.numVecs-1 << std::endl;
816  if (whichVecs[sol.numVecs-1] > (sol.numVecs-1)) {
817  keepMore = true;
818  numEvecs = whichVecs[sol.numVecs-1]+1; // Add 1 to fix zero-based indexing
819  printer->stream(Debug) << "keepMore = true; numEvecs = " << numEvecs << std::endl;
820  }
821 
822  // Next set the number of Ritz vectors that the iteration must compute and compute them.
823  bks_solver->setNumRitzVectors(numEvecs);
824  bks_solver->computeRitzVectors();
825 
826  // If the leading Ritz pairs are the converged ones, get the information
827  // from the iteration to the solution container. Otherwise copy the necessary
828  // information using 'whichVecs'.
829  if (!keepMore) {
830  sol.index = bks_solver->getRitzIndex();
831  sol.Evals = bks_solver->getRitzValues();
832  sol.Evecs = MVT::CloneCopy( *(bks_solver->getRitzVectors()) );
833  }
834 
835  // Resize based on the number of solutions being returned and set the number of Ritz
836  // vectors for the iteration to compute.
837  sol.Evals.resize(sol.numVecs);
838  sol.index.resize(sol.numVecs);
839 
840  // If the converged Ritz pairs are not the leading ones, copy over the information directly.
841  if (keepMore) {
842  std::vector<Anasazi::Value<ScalarType> > tmpEvals = bks_solver->getRitzValues();
843  for (int vec_i=0; vec_i<sol.numVecs; ++vec_i) {
844  sol.index[vec_i] = tmpIndex[whichVecs[vec_i]];
845  sol.Evals[vec_i] = tmpEvals[whichVecs[vec_i]];
846  }
847  sol.Evecs = MVT::CloneCopy( *(bks_solver->getRitzVectors()), whichVecs );
848  }
849 
850  // Set the solution space to be the Ritz vectors at this time.
851  sol.Espace = sol.Evecs;
852  }
853  }
854 
855  // print final summary
856  bks_solver->currentStatus(printer->stream(FinalSummary));
857 
858  // print timing information
859 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
860  if ( printer->isVerbosity( TimingDetails ) ) {
861  Teuchos::TimeMonitor::summarize( printer->stream( TimingDetails ) );
862  }
863 #endif
864 
865  _problem->setSolution(sol);
866  printer->stream(Debug) << "Returning " << sol.numVecs << " eigenpairs to eigenproblem." << std::endl;
867 
868  // get the number of iterations performed during this solve.
869  _numIters = bks_solver->getNumIters();
870 
871  if (sol.numVecs < nev) {
872  return Unconverged; // return from BlockKrylovSchurSolMgr::solve()
873  }
874  return Converged; // return from BlockKrylovSchurSolMgr::solve()
875 }
876 
877 
878 template <class ScalarType, class MV, class OP>
879 void
881  const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &global)
882 {
883  globalTest_ = global;
884 }
885 
886 template <class ScalarType, class MV, class OP>
887 const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &
889 {
890  return globalTest_;
891 }
892 
893 template <class ScalarType, class MV, class OP>
894 void
896  const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &debug)
897 {
898  debugTest_ = debug;
899 }
900 
901 template <class ScalarType, class MV, class OP>
902 const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &
904 {
905  return debugTest_;
906 }
907 
908 } // end Anasazi namespace
909 
910 #endif /* ANASAZI_BLOCK_KRYLOV_SCHUR_SOLMGR_HPP */
static ptrdiff_t GetGlobalLength(const MV &mv)
Return the number of rows in the given multivector mv.
Pure virtual base class which describes the basic interface for a solver manager. ...
Teuchos::RCP< const Teuchos::SerialDenseMatrix< int, ScalarType > > H
The current Hessenberg matrix.
std::vector< Value< ScalarType > > Evals
The computed eigenvalues.
static void MvTimesMatAddMv(const ScalarType alpha, const MV &A, const Teuchos::SerialDenseMatrix< int, ScalarType > &B, const ScalarType beta, MV &mv)
Update mv with .
A special StatusTest for printing other status tests.
This class defines the interface required by an eigensolver and status test class to compute solution...
An implementation of the Anasazi::SortManager that performs a collection of common sorting techniques...
Virtual base class which defines basic traits for the operator type.
Teuchos::RCP< MV > Evecs
The computed eigenvectors.
ReturnType solve()
This method performs possibly repeated calls to the underlying eigensolver&#39;s iterate() routine until ...
Status test for forming logical combinations of other status tests.
The Anasazi::SolverManager is a templated virtual base class that defines the basic interface that an...
void setDebugStatusTest(const Teuchos::RCP< StatusTest< ScalarType, MV, OP > > &debug)
Set the status test for debugging.
Basic implementation of the Anasazi::SortManager class.
An implementation of the Anasazi::MatOrthoManager that performs orthogonalization using the SVQB iter...
Structure to contain pointers to BlockKrylovSchur state variables.
An exception class parent to all Anasazi exceptions.
const Teuchos::RCP< StatusTest< ScalarType, MV, OP > > & getDebugStatusTest() const
Get the status test for debugging.
The Anasazi::BlockKrylovSchurSolMgr provides a flexible solver manager over the BlockKrylovSchur eige...
Namespace Anasazi contains the classes, structs, enums and utilities used by the Anasazi package...
A status test for testing the norm of the eigenvectors residuals along with a set of auxiliary eigenv...
Anasazi&#39;s templated, static class providing utilities for the solvers.
int numVecs
The number of computed eigenpairs.
void setGlobalStatusTest(const Teuchos::RCP< StatusTest< ScalarType, MV, OP > > &global)
Set the status test defining global convergence.
BlockKrylovSchurSolMgr(const Teuchos::RCP< Eigenproblem< ScalarType, MV, OP > > &problem, Teuchos::ParameterList &pl)
Basic constructor for BlockKrylovSchurSolMgr.
Basic output manager for sending information of select verbosity levels to the appropriate output str...
Teuchos::RCP< MV > Espace
An orthonormal basis for the computed eigenspace.
Teuchos::Array< Teuchos::RCP< Teuchos::Time > > getTimers() const
Return the timers for this object.
Anasazi&#39;s basic output manager for sending information of select verbosity levels to the appropriate ...
Abstract base class which defines the interface required by an eigensolver and status test class to c...
ReturnType
Enumerated type used to pass back information from a solver manager.
A status test for testing the norm of the eigenvectors residuals.
Traits class which defines basic operations on multivectors.
static Teuchos::RCP< MV > CloneCopy(const MV &mv)
Creates a new MV and copies contents of mv into the new vector (deep copy).
std::vector< int > index
An index into Evecs to allow compressed storage of eigenvectors for real, non-Hermitian problems...
static void MvScale(MV &mv, const ScalarType alpha)
Scale each element of the vectors in mv with alpha.
Anasazi header file which uses auto-configuration information to include necessary C++ headers...
Orthogonalization manager based on the SVQB technique described in "A Block Orthogonalization Procedu...
static Teuchos::RCP< MV > CloneViewNonConst(MV &mv, const std::vector< int > &index)
Creates a new MV that shares the selected contents of mv (shallow copy).
Struct for storing an eigenproblem solution.
static Teuchos::RCP< const MV > CloneView(const MV &mv, const std::vector< int > &index)
Creates a new const MV that shares the selected contents of mv (shallow copy).
static void SetBlock(const MV &A, const std::vector< int > &index, MV &mv)
Copy the vectors in A to a set of vectors in mv indicated by the indices given in index...
const Eigenproblem< ScalarType, MV, OP > & getProblem() const
Return the eigenvalue problem.
std::vector< Value< ScalarType > > getRitzValues() const
Return the Ritz values from the most recent solve.
Teuchos::RCP< const MulVec > V
The current Krylov basis.
Special StatusTest for printing status tests.
A status test for testing the norm of the eigenvectors residuals along with a set of auxiliary eigenv...
Status test for forming logical combinations of other status tests.
An implementation of the Anasazi::MatOrthoManager that performs orthogonalization using (potentially)...
Types and exceptions used within Anasazi solvers and interfaces.
int getNumIters() const
Get the iteration count for the most recent call to solve().
Teuchos::RCP< const Teuchos::SerialDenseMatrix< int, ScalarType > > Q
The current Schur vectors of the valid part of H.
Implementation of a block Krylov-Schur eigensolver.
This class implements the block Krylov-Schur iteration, for solving linear eigenvalue problems...
int curDim
The current dimension of the reduction.
Common interface of stopping criteria for Anasazi&#39;s solvers.
A status test for testing the norm of the eigenvectors residuals.
Basic implementation of the Anasazi::OrthoManager class.
Teuchos::RCP< const Teuchos::SerialDenseMatrix< int, ScalarType > > S
The current Schur form reduction of the valid part of H.
const Teuchos::RCP< StatusTest< ScalarType, MV, OP > > & getGlobalStatusTest() const
Get the status test defining global convergence.
static Teuchos::RCP< MV > Clone(const MV &mv, const int numvecs)
Creates a new empty MV containing numvecs columns.
Class which provides internal utilities for the Anasazi solvers.