Anasazi  Version of the Day
AnasaziBlockDavidsonSolMgr.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_BLOCKDAVIDSON_SOLMGR_HPP
43 #define ANASAZI_BLOCKDAVIDSON_SOLMGR_HPP
44 
49 #include "AnasaziConfigDefs.hpp"
50 #include "AnasaziTypes.hpp"
51 
52 #include "AnasaziEigenproblem.hpp"
53 #include "AnasaziSolverManager.hpp"
54 #include "AnasaziSolverUtils.hpp"
55 
56 #include "AnasaziBlockDavidson.hpp"
57 #include "AnasaziBasicSort.hpp"
65 #include "Teuchos_BLAS.hpp"
66 #include "Teuchos_LAPACK.hpp"
67 #include "Teuchos_TimeMonitor.hpp"
68 #ifdef TEUCHOS_DEBUG
69 # include <Teuchos_FancyOStream.hpp>
70 #endif
71 #ifdef HAVE_MPI
72 #include <mpi.h>
73 #endif
74 
75 
76 
90 namespace Anasazi {
91 
92 
125 template<class ScalarType, class MV, class OP>
126 class BlockDavidsonSolMgr : public SolverManager<ScalarType,MV,OP> {
127 
128  private:
131  typedef Teuchos::ScalarTraits<ScalarType> SCT;
132  typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MagnitudeType;
133  typedef Teuchos::ScalarTraits<MagnitudeType> MT;
134 
135  public:
136 
138 
139 
162  BlockDavidsonSolMgr( const Teuchos::RCP<Eigenproblem<ScalarType,MV,OP> > &problem,
163  Teuchos::ParameterList &pl );
164 
166  virtual ~BlockDavidsonSolMgr() {};
168 
170 
171 
174  return *problem_;
175  }
176 
178  int getNumIters() const {
179  return numIters_;
180  }
181 
189  Teuchos::Array<Teuchos::RCP<Teuchos::Time> > getTimers() const {
190  return Teuchos::tuple(_timerSolve, _timerRestarting, _timerLocking);
191  }
192 
194 
196 
197 
219  ReturnType solve();
220 
222  void setGlobalStatusTest(const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &global);
223 
225  const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > & getGlobalStatusTest() const;
226 
228  void setLockingStatusTest(const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &locking);
229 
231  const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > & getLockingStatusTest() const;
232 
234  void setDebugStatusTest(const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &debug);
235 
237  const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > & getDebugStatusTest() const;
238 
240 
241  private:
242  Teuchos::RCP<Eigenproblem<ScalarType,MV,OP> > problem_;
243 
244  std::string whch_, ortho_;
245 
246  MagnitudeType convtol_, locktol_;
247  int maxRestarts_;
248  bool useLocking_;
249  bool relconvtol_, rellocktol_;
250  int blockSize_, numBlocks_, numIters_;
251  int maxLocked_;
252  int lockQuorum_;
253  bool inSituRestart_;
254  int numRestartBlocks_;
255  enum ResType convNorm_, lockNorm_;
256 
257  Teuchos::RCP<Teuchos::Time> _timerSolve, _timerRestarting, _timerLocking;
258 
259  Teuchos::RCP<StatusTest<ScalarType,MV,OP> > globalTest_;
260  Teuchos::RCP<StatusTest<ScalarType,MV,OP> > lockingTest_;
261  Teuchos::RCP<StatusTest<ScalarType,MV,OP> > debugTest_;
262 
263  Teuchos::RCP<BasicOutputManager<ScalarType> > printer_;
264 };
265 
266 
267 // Constructor
268 template<class ScalarType, class MV, class OP>
270  const Teuchos::RCP<Eigenproblem<ScalarType,MV,OP> > &problem,
271  Teuchos::ParameterList &pl ) :
272  problem_(problem),
273  whch_("SR"),
274  ortho_("SVQB"),
275  convtol_(MT::prec()),
276  maxRestarts_(20),
277  useLocking_(false),
278  relconvtol_(true),
279  rellocktol_(true),
280  blockSize_(0),
281  numBlocks_(0),
282  numIters_(0),
283  maxLocked_(0),
284  lockQuorum_(1),
285  inSituRestart_(false),
286  numRestartBlocks_(1)
287 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
288  , _timerSolve(Teuchos::TimeMonitor::getNewTimer("Anasazi: BlockDavidsonSolMgr::solve()")),
289  _timerRestarting(Teuchos::TimeMonitor::getNewTimer("Anasazi: BlockDavidsonSolMgr restarting")),
290  _timerLocking(Teuchos::TimeMonitor::getNewTimer("Anasazi: BlockDavidsonSolMgr locking"))
291 #endif
292 {
293  TEUCHOS_TEST_FOR_EXCEPTION(problem_ == Teuchos::null, std::invalid_argument, "Problem not given to solver manager.");
294  TEUCHOS_TEST_FOR_EXCEPTION(!problem_->isProblemSet(), std::invalid_argument, "Problem not set.");
295  TEUCHOS_TEST_FOR_EXCEPTION(!problem_->isHermitian(), std::invalid_argument, "Problem not symmetric.");
296  TEUCHOS_TEST_FOR_EXCEPTION(problem_->getInitVec() == Teuchos::null,std::invalid_argument, "Problem does not contain initial vectors to clone from.");
297 
298  std::string strtmp;
299 
300  // which values to solve for
301  whch_ = pl.get("Which",whch_);
302  TEUCHOS_TEST_FOR_EXCEPTION(whch_ != "SM" && whch_ != "LM" && whch_ != "SR" && whch_ != "LR",std::invalid_argument, "Invalid sorting string.");
303 
304  // which orthogonalization to use
305  ortho_ = pl.get("Orthogonalization",ortho_);
306  if (ortho_ != "DGKS" && ortho_ != "SVQB") {
307  ortho_ = "SVQB";
308  }
309 
310  // convergence tolerance
311  convtol_ = pl.get("Convergence Tolerance",convtol_);
312  relconvtol_ = pl.get("Relative Convergence Tolerance",relconvtol_);
313  strtmp = pl.get("Convergence Norm",std::string("2"));
314  if (strtmp == "2") {
315  convNorm_ = RES_2NORM;
316  }
317  else if (strtmp == "M") {
318  convNorm_ = RES_ORTH;
319  }
320  else {
321  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
322  "Anasazi::BlockDavidsonSolMgr: Invalid Convergence Norm.");
323  }
324 
325  // locking tolerance
326  useLocking_ = pl.get("Use Locking",useLocking_);
327  rellocktol_ = pl.get("Relative Locking Tolerance",rellocktol_);
328  // default: should be less than convtol_
329  locktol_ = convtol_/10;
330  locktol_ = pl.get("Locking Tolerance",locktol_);
331  strtmp = pl.get("Locking Norm",std::string("2"));
332  if (strtmp == "2") {
333  lockNorm_ = RES_2NORM;
334  }
335  else if (strtmp == "M") {
336  lockNorm_ = RES_ORTH;
337  }
338  else {
339  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
340  "Anasazi::BlockDavidsonSolMgr: Invalid Locking Norm.");
341  }
342 
343  // maximum number of restarts
344  maxRestarts_ = pl.get("Maximum Restarts",maxRestarts_);
345 
346  // block size: default is nev()
347  blockSize_ = pl.get("Block Size",problem_->getNEV());
348  TEUCHOS_TEST_FOR_EXCEPTION(blockSize_ <= 0, std::invalid_argument,
349  "Anasazi::BlockDavidsonSolMgr: \"Block Size\" must be strictly positive.");
350  numBlocks_ = pl.get("Num Blocks",2);
351  TEUCHOS_TEST_FOR_EXCEPTION(numBlocks_ <= 1, std::invalid_argument,
352  "Anasazi::BlockDavidsonSolMgr: \"Num Blocks\" must be >= 1.");
353 
354  // max locked: default is nev(), must satisfy maxLocked_ + blockSize_ >= nev
355  if (useLocking_) {
356  maxLocked_ = pl.get("Max Locked",problem_->getNEV());
357  }
358  else {
359  maxLocked_ = 0;
360  }
361  if (maxLocked_ == 0) {
362  useLocking_ = false;
363  }
364  TEUCHOS_TEST_FOR_EXCEPTION(maxLocked_ < 0, std::invalid_argument,
365  "Anasazi::BlockDavidsonSolMgr: \"Max Locked\" must be positive.");
366  TEUCHOS_TEST_FOR_EXCEPTION(maxLocked_ + blockSize_ < problem_->getNEV(),
367  std::invalid_argument,
368  "Anasazi::BlockDavidsonSolMgr: Not enough storage space for requested number of eigenpairs.");
369  TEUCHOS_TEST_FOR_EXCEPTION(static_cast<ptrdiff_t>(numBlocks_)*blockSize_ + maxLocked_ > MVT::GetGlobalLength(*problem_->getInitVec()),
370  std::invalid_argument,
371  "Anasazi::BlockDavidsonSolMgr: Potentially impossible orthogonality requests. Reduce basis size or locking size.");
372 
373  if (useLocking_) {
374  lockQuorum_ = pl.get("Locking Quorum",lockQuorum_);
375  TEUCHOS_TEST_FOR_EXCEPTION(lockQuorum_ <= 0,
376  std::invalid_argument,
377  "Anasazi::BlockDavidsonSolMgr: \"Locking Quorum\" must be strictly positive.");
378  }
379 
380  // restart size
381  numRestartBlocks_ = pl.get("Num Restart Blocks",numRestartBlocks_);
382  TEUCHOS_TEST_FOR_EXCEPTION(numRestartBlocks_ <= 0, std::invalid_argument,
383  "Anasazi::BlockDavidsonSolMgr: \"Num Restart Blocks\" must be strictly positive.");
384  TEUCHOS_TEST_FOR_EXCEPTION(numRestartBlocks_ >= numBlocks_, std::invalid_argument,
385  "Anasazi::BlockDavidsonSolMgr: \"Num Restart Blocks\" must be strictly less than \"Num Blocks\".");
386 
387  // restarting technique: V*Q or applyHouse(V,H,tau)
388  if (pl.isParameter("In Situ Restarting")) {
389  if (Teuchos::isParameterType<bool>(pl,"In Situ Restarting")) {
390  inSituRestart_ = pl.get("In Situ Restarting",inSituRestart_);
391  } else {
392  inSituRestart_ = ( Teuchos::getParameter<int>(pl,"In Situ Restarting") != 0 );
393  }
394  }
395 
396  // output stream
397  std::string fntemplate = "";
398  bool allProcs = false;
399  if (pl.isParameter("Output on all processors")) {
400  if (Teuchos::isParameterType<bool>(pl,"Output on all processors")) {
401  allProcs = pl.get("Output on all processors",allProcs);
402  } else {
403  allProcs = ( Teuchos::getParameter<int>(pl,"Output on all processors") != 0 );
404  }
405  }
406  fntemplate = pl.get("Output filename template",fntemplate);
407  int MyPID;
408 # ifdef HAVE_MPI
409  // Initialize MPI
410  int mpiStarted = 0;
411  MPI_Initialized(&mpiStarted);
412  if (mpiStarted) MPI_Comm_rank(MPI_COMM_WORLD, &MyPID);
413  else MyPID=0;
414 # else
415  MyPID = 0;
416 # endif
417  if (fntemplate != "") {
418  std::ostringstream MyPIDstr;
419  MyPIDstr << MyPID;
420  // replace %d in fntemplate with MyPID
421  int pos, start=0;
422  while ( (pos = fntemplate.find("%d",start)) != -1 ) {
423  fntemplate.replace(pos,2,MyPIDstr.str());
424  start = pos+2;
425  }
426  }
427  Teuchos::RCP<ostream> osp;
428  if (fntemplate != "") {
429  osp = Teuchos::rcp( new std::ofstream(fntemplate.c_str(),std::ios::out | std::ios::app) );
430  if (!*osp) {
431  osp = Teuchos::rcpFromRef(std::cout);
432  std::cout << "Anasazi::BlockDavidsonSolMgr::constructor(): Could not open file for write: " << fntemplate << std::endl;
433  }
434  }
435  else {
436  osp = Teuchos::rcpFromRef(std::cout);
437  }
438  // Output manager
439  int verbosity = Anasazi::Errors;
440  if (pl.isParameter("Verbosity")) {
441  if (Teuchos::isParameterType<int>(pl,"Verbosity")) {
442  verbosity = pl.get("Verbosity", verbosity);
443  } else {
444  verbosity = (int)Teuchos::getParameter<Anasazi::MsgType>(pl,"Verbosity");
445  }
446  }
447  if (allProcs) {
448  // print on all procs
449  printer_ = Teuchos::rcp( new BasicOutputManager<ScalarType>(verbosity,osp,MyPID) );
450  }
451  else {
452  // print only on proc 0
453  printer_ = Teuchos::rcp( new BasicOutputManager<ScalarType>(verbosity,osp,0) );
454  }
455 }
456 
457 
458 // solve()
459 template<class ScalarType, class MV, class OP>
460 ReturnType
462 
463  typedef SolverUtils<ScalarType,MV,OP> msutils;
464 
465  const int nev = problem_->getNEV();
466 
467 #ifdef TEUCHOS_DEBUG
468  Teuchos::RCP<Teuchos::FancyOStream>
469  out = Teuchos::getFancyOStream(Teuchos::rcpFromRef(printer_->stream(Debug)));
470  out->setShowAllFrontMatter(false).setShowProcRank(true);
471  *out << "Entering Anasazi::BlockDavidsonSolMgr::solve()\n";
472 #endif
473 
475  // Sort manager
476  Teuchos::RCP<BasicSort<MagnitudeType> > sorter = Teuchos::rcp( new BasicSort<MagnitudeType>(whch_) );
477 
479  // Status tests
480  //
481  // convergence
482  Teuchos::RCP<StatusTest<ScalarType,MV,OP> > convtest;
483  if (globalTest_ == Teuchos::null) {
484  convtest = Teuchos::rcp( new StatusTestResNorm<ScalarType,MV,OP>(convtol_,nev,convNorm_,relconvtol_) );
485  }
486  else {
487  convtest = globalTest_;
488  }
489  Teuchos::RCP<StatusTestWithOrdering<ScalarType,MV,OP> > ordertest
490  = Teuchos::rcp( new StatusTestWithOrdering<ScalarType,MV,OP>(convtest,sorter,nev) );
491  // locking
492  Teuchos::RCP<StatusTest<ScalarType,MV,OP> > locktest;
493  if (useLocking_) {
494  if (lockingTest_ == Teuchos::null) {
495  locktest = Teuchos::rcp( new StatusTestResNorm<ScalarType,MV,OP>(locktol_,lockQuorum_,lockNorm_,rellocktol_) );
496  }
497  else {
498  locktest = lockingTest_;
499  }
500  }
501  // for a non-short-circuited OR test, the order doesn't matter
502  Teuchos::Array<Teuchos::RCP<StatusTest<ScalarType,MV,OP> > > alltests;
503  alltests.push_back(ordertest);
504  if (locktest != Teuchos::null) alltests.push_back(locktest);
505  if (debugTest_ != Teuchos::null) alltests.push_back(debugTest_);
506 
507  Teuchos::RCP<StatusTestCombo<ScalarType,MV,OP> > combotest
509  // printing StatusTest
510  Teuchos::RCP<StatusTestOutput<ScalarType,MV,OP> > outputtest;
511  if ( printer_->isVerbosity(Debug) ) {
512  outputtest = Teuchos::rcp( new StatusTestOutput<ScalarType,MV,OP>( printer_,combotest,1,Passed+Failed+Undefined ) );
513  }
514  else {
515  outputtest = Teuchos::rcp( new StatusTestOutput<ScalarType,MV,OP>( printer_,combotest,1,Passed ) );
516  }
517 
519  // Orthomanager
520  Teuchos::RCP<MatOrthoManager<ScalarType,MV,OP> > ortho;
521  if (ortho_=="SVQB") {
522  ortho = Teuchos::rcp( new SVQBOrthoManager<ScalarType,MV,OP>(problem_->getM()) );
523  } else if (ortho_=="DGKS") {
524  ortho = Teuchos::rcp( new BasicOrthoManager<ScalarType,MV,OP>(problem_->getM()) );
525  } else {
526  TEUCHOS_TEST_FOR_EXCEPTION(ortho_!="SVQB"&&ortho_!="DGKS",std::logic_error,"Anasazi::BlockDavidsonSolMgr::solve(): Invalid orthogonalization type.");
527  }
528 
530  // Parameter list
531  Teuchos::ParameterList plist;
532  plist.set("Block Size",blockSize_);
533  plist.set("Num Blocks",numBlocks_);
534 
536  // BlockDavidson solver
537  Teuchos::RCP<BlockDavidson<ScalarType,MV,OP> > bd_solver
538  = Teuchos::rcp( new BlockDavidson<ScalarType,MV,OP>(problem_,sorter,printer_,outputtest,ortho,plist) );
539  // set any auxiliary vectors defined in the problem
540  Teuchos::RCP< const MV > probauxvecs = problem_->getAuxVecs();
541  if (probauxvecs != Teuchos::null) {
542  bd_solver->setAuxVecs( Teuchos::tuple< Teuchos::RCP<const MV> >(probauxvecs) );
543  }
544 
546  // Storage
547  //
548  // lockvecs will contain eigenvectors that have been determined "locked" by the status test
549  int curNumLocked = 0;
550  Teuchos::RCP<MV> lockvecs;
551  // lockvecs is used to hold the locked eigenvectors, as well as for temporary storage when locking.
552  // when locking, we will lock some number of vectors numnew, where numnew <= maxlocked - curlocked
553  // we will produce numnew random vectors, which will go into the space with the new basis.
554  // we will also need numnew storage for the image of these random vectors under A and M;
555  // columns [curlocked+1,curlocked+numnew] will be used for this storage
556  if (maxLocked_ > 0) {
557  lockvecs = MVT::Clone(*problem_->getInitVec(),maxLocked_);
558  }
559  std::vector<MagnitudeType> lockvals;
560  //
561  // Restarting occurs under two scenarios: when the basis is full and after locking.
562  //
563  // For the former, a new basis of size blockSize*numRestartBlocks is generated using the current basis
564  // and the most significant primitive Ritz vectors (projected eigenvectors).
565  // [S,L] = eig(KK)
566  // S = [Sr St] // some for "r"estarting, some are "t"runcated
567  // newV = V*Sr
568  // KK_new = newV'*K*newV = Sr'*V'*K*V*Sr = Sr'*KK*Sr
569  // Therefore, the only multivector operation needed is for the generation of newV.
570  //
571  // * If the multiplication is explicit, it requires a workspace of blockSize*numRestartBlocks vectors.
572  // This space must be specifically allocated for that task, as we don't have any space of that size.
573  // It (workMV) will be allocated at the beginning of solve()
574  // * Optionally, the multiplication can be performed implicitly, via a Householder QR factorization of
575  // Sr. This can be done in situ, using the basis multivector contained in the solver. This requires
576  // that we cast away the const on the multivector returned from getState(). Workspace for this approach
577  // is a single vector. the solver's internal storage must be preserved (X,MX,KX,R), requiring us to
578  // allocate this vector.
579  //
580  // For the latter (restarting after locking), the new basis is the same size as existing basis. If numnew
581  // vectors are locked, they are deflated from the current basis and replaced with randomly generated
582  // vectors.
583  // [S,L] = eig(KK)
584  // S = [Sl Su] // partitioned: "l"ocked and "u"nlocked
585  // newL = V*Sl = X(locked)
586  // defV = V*Su
587  // augV = rand(numnew) // orthogonal to oldL,newL,defV,auxvecs
588  // newV = [defV augV]
589  // Kknew = newV'*K*newV = [Su'*KK*Su defV'*K*augV]
590  // [augV'*K*defV augV'*K*augV]
591  // locked = [oldL newL]
592  // Clearly, this operation is more complicated than the previous.
593  // Here is a list of the significant computations that need to be performed:
594  // - newL will be put into space in lockvecs, but will be copied from getState().X at the end
595  // - defV,augV will be stored in workspace the size of the current basis.
596  // - If inSituRestart==true, we compute defV in situ in bd_solver::V_ and
597  // put augV at the end of bd_solver::V_
598  // - If inSituRestart==false, we must have curDim vectors available for
599  // defV and augV; we will allocate a multivector (workMV) at the beginning of solve()
600  // for this purpose.
601  // - M*augV and K*augV are needed; they will be stored in lockvecs. As a result, newL will
602  // not be put into lockvecs until the end.
603  //
604  // Therefore, we must allocate workMV when ((maxRestarts_ > 0) || (useLocking_ == true)) && inSituRestart == false
605  // It will be allocated to size (numBlocks-1)*blockSize
606  //
607  Teuchos::RCP<MV> workMV;
608  if (inSituRestart_ == false) {
609  // we need storage space to restart, either if we may lock or if may restart after a full basis
610  if (useLocking_==true || maxRestarts_ > 0) {
611  workMV = MVT::Clone(*problem_->getInitVec(),(numBlocks_-1)*blockSize_);
612  }
613  else {
614  // we will never need to restart.
615  workMV = Teuchos::null;
616  }
617  }
618  else { // inSituRestart_ == true
619  // we will restart in situ, if we need to restart
620  // three situation remain:
621  // - never restart => no space needed
622  // - only restart for locking (i.e., never restart full) => no space needed
623  // - restart for full basis => need one vector
624  if (maxRestarts_ > 0) {
625  workMV = MVT::Clone(*problem_->getInitVec(),1);
626  }
627  else {
628  workMV = Teuchos::null;
629  }
630  }
631 
632  // some consts and utils
633  const ScalarType ONE = SCT::one();
634  const ScalarType ZERO = SCT::zero();
635  Teuchos::LAPACK<int,ScalarType> lapack;
636  Teuchos::BLAS<int,ScalarType> blas;
637 
638  // go ahead and initialize the solution to nothing in case we throw an exception
640  sol.numVecs = 0;
641  problem_->setSolution(sol);
642 
643  int numRestarts = 0;
644 
645  // enter solve() iterations
646  {
647 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
648  Teuchos::TimeMonitor slvtimer(*_timerSolve);
649 #endif
650 
651  // tell bd_solver to iterate
652  while (1) {
653  try {
654  bd_solver->iterate();
655 
657  //
658  // check user-specified debug test; if it passed, return an exception
659  //
661  if (debugTest_ != Teuchos::null && debugTest_->getStatus() == Passed) {
662  throw AnasaziError("Anasazi::BlockDavidsonSolMgr::solve(): User-specified debug status test returned Passed.");
663  }
665  //
666  // check convergence next
667  //
669  else if (ordertest->getStatus() == Passed ) {
670  // we have convergence
671  // ordertest->whichVecs() tells us which vectors from lockvecs and solver state are the ones we want
672  // ordertest->howMany() will tell us how many
673  break;
674  }
676  //
677  // check for restarting before locking: if we need to lock, it will happen after the restart
678  //
680  else if ( bd_solver->getCurSubspaceDim() == bd_solver->getMaxSubspaceDim() ) {
681 
682 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
683  Teuchos::TimeMonitor restimer(*_timerRestarting);
684 #endif
685 
686  if ( numRestarts >= maxRestarts_ ) {
687  break; // break from while(1){bd_solver->iterate()}
688  }
689  numRestarts++;
690 
691  printer_->stream(IterationDetails) << " Performing restart number " << numRestarts << " of " << maxRestarts_ << std::endl << std::endl;
692 
693  BlockDavidsonState<ScalarType,MV> state = bd_solver->getState();
694  int curdim = state.curDim;
695  int newdim = numRestartBlocks_*blockSize_;
696 
697 # ifdef TEUCHOS_DEBUG
698  {
699  std::vector<Value<ScalarType> > ritzvalues = bd_solver->getRitzValues();
700  *out << "Ritz values from solver:\n";
701  for (unsigned int i=0; i<ritzvalues.size(); i++) {
702  *out << ritzvalues[i].realpart << " ";
703  }
704  *out << "\n";
705  }
706 # endif
707 
708  //
709  // compute eigenvectors of the projected problem
710  Teuchos::SerialDenseMatrix<int,ScalarType> S(curdim,curdim);
711  std::vector<MagnitudeType> theta(curdim);
712  int rank = curdim;
713 # ifdef TEUCHOS_DEBUG
714  {
715  std::stringstream os;
716  os << "KK before HEEV...\n"
717  << *state.KK << "\n";
718  *out << os.str();
719  }
720 # endif
721  int info = msutils::directSolver(curdim,*state.KK,Teuchos::null,S,theta,rank,10);
722  TEUCHOS_TEST_FOR_EXCEPTION(info != 0 ,std::logic_error,
723  "Anasazi::BlockDavidsonSolMgr::solve(): error calling SolverUtils::directSolver."); // this should never happen
724  TEUCHOS_TEST_FOR_EXCEPTION(rank != curdim,std::logic_error,
725  "Anasazi::BlockDavidsonSolMgr::solve(): direct solve did not compute all eigenvectors."); // this should never happen
726 
727 # ifdef TEUCHOS_DEBUG
728  {
729  std::stringstream os;
730  *out << "Ritz values from heev(KK):\n";
731  for (unsigned int i=0; i<theta.size(); i++) *out << theta[i] << " ";
732  os << "\nRitz vectors from heev(KK):\n"
733  << S << "\n";
734  *out << os.str();
735  }
736 # endif
737 
738  //
739  // sort the eigenvalues (so that we can order the eigenvectors)
740  {
741  std::vector<int> order(curdim);
742  sorter->sort(theta,Teuchos::rcpFromRef(order),curdim);
743  //
744  // apply the same ordering to the primitive ritz vectors
745  msutils::permuteVectors(order,S);
746  }
747 # ifdef TEUCHOS_DEBUG
748  {
749  std::stringstream os;
750  *out << "Ritz values from heev(KK) after sorting:\n";
751  std::copy(theta.begin(), theta.end(), std::ostream_iterator<ScalarType>(*out, " "));
752  os << "\nRitz vectors from heev(KK) after sorting:\n"
753  << S << "\n";
754  *out << os.str();
755  }
756 # endif
757  //
758  // select the significant primitive ritz vectors
759  Teuchos::SerialDenseMatrix<int,ScalarType> Sr(Teuchos::View,S,curdim,newdim);
760 # ifdef TEUCHOS_DEBUG
761  {
762  std::stringstream os;
763  os << "Significant primitive Ritz vectors:\n"
764  << Sr << "\n";
765  *out << os.str();
766  }
767 # endif
768  //
769  // generate newKK = Sr'*KKold*Sr
770  Teuchos::SerialDenseMatrix<int,ScalarType> newKK(newdim,newdim);
771  {
772  Teuchos::SerialDenseMatrix<int,ScalarType> KKtmp(curdim,newdim),
773  KKold(Teuchos::View,*state.KK,curdim,curdim);
774  int teuchosRet;
775  // KKtmp = KKold*Sr
776  teuchosRet = KKtmp.multiply(Teuchos::NO_TRANS,Teuchos::NO_TRANS,ONE,KKold,Sr,ZERO);
777  TEUCHOS_TEST_FOR_EXCEPTION(teuchosRet != 0,std::logic_error,
778  "Anasazi::BlockDavidsonSolMgr::solve(): Logic error calling SerialDenseMatrix::multiply.");
779  // newKK = Sr'*KKtmp = Sr'*KKold*Sr
780  teuchosRet = newKK.multiply(Teuchos::CONJ_TRANS,Teuchos::NO_TRANS,ONE,Sr,KKtmp,ZERO);
781  TEUCHOS_TEST_FOR_EXCEPTION(teuchosRet != 0,std::logic_error,
782  "Anasazi::BlockDavidsonSolMgr::solve(): Logic error calling SerialDenseMatrix::multiply.");
783  // make it Hermitian in memory
784  for (int j=0; j<newdim-1; ++j) {
785  for (int i=j+1; i<newdim; ++i) {
786  newKK(i,j) = SCT::conjugate(newKK(j,i));
787  }
788  }
789  }
790 # ifdef TEUCHOS_DEBUG
791  {
792  std::stringstream os;
793  os << "Sr'*KK*Sr:\n"
794  << newKK << "\n";
795  *out << os.str();
796  }
797 # endif
798 
799  // prepare new state
801  rstate.curDim = newdim;
802  rstate.KK = Teuchos::rcpFromRef(newKK);
803  //
804  // we know that newX = newV*Sr(:,1:bS) = oldV*S(:1:bS) = oldX
805  // the restarting preserves the Ritz vectors and residual
806  // for the Ritz values, we want all of the values associated with newV.
807  // these have already been placed at the beginning of theta
808  rstate.X = state.X;
809  rstate.KX = state.KX;
810  rstate.MX = state.MX;
811  rstate.R = state.R;
812  rstate.T = Teuchos::rcp( new std::vector<MagnitudeType>(theta.begin(),theta.begin()+newdim) );
813 
814  if (inSituRestart_ == true) {
815 # ifdef TEUCHOS_DEBUG
816  *out << "Beginning in-situ restart...\n";
817 # endif
818  //
819  // get non-const pointer to solver's basis so we can work in situ
820  Teuchos::RCP<MV> solverbasis = Teuchos::rcp_const_cast<MV>(state.V);
821  //
822  // perform Householder QR of Sr = Q [D;0], where D is unit diag.
823  // WARNING: this will overwrite Sr; however, we do not need Sr anymore after this
824  std::vector<ScalarType> tau(newdim), work(newdim);
825  int geqrf_info;
826  lapack.GEQRF(curdim,newdim,Sr.values(),Sr.stride(),&tau[0],&work[0],work.size(),&geqrf_info);
827  TEUCHOS_TEST_FOR_EXCEPTION(geqrf_info != 0,std::logic_error,
828  "Anasazi::BlockDavidsonSolMgr::solve(): error calling GEQRF during restarting.");
829  if (printer_->isVerbosity(Debug)) {
830  Teuchos::SerialDenseMatrix<int,ScalarType> R(Teuchos::Copy,Sr,newdim,newdim);
831  for (int j=0; j<newdim; j++) {
832  R(j,j) = SCT::magnitude(R(j,j)) - 1.0;
833  for (int i=j+1; i<newdim; i++) {
834  R(i,j) = ZERO;
835  }
836  }
837  printer_->stream(Debug) << "||Triangular factor of Sr - I||: " << R.normFrobenius() << std::endl;
838  }
839  //
840  // perform implicit oldV*Sr
841  // this actually performs oldV*[Sr Su*M] = [newV truncV], for some unitary M
842  // we are actually interested in only the first newdim vectors of the result
843  {
844  std::vector<int> curind(curdim);
845  for (int i=0; i<curdim; i++) curind[i] = i;
846  Teuchos::RCP<MV> oldV = MVT::CloneViewNonConst(*solverbasis,curind);
847  msutils::applyHouse(newdim,*oldV,Sr,tau,workMV);
848  }
849  //
850  // put the new basis into the state for initialize()
851  // the new basis is contained in the the first newdim columns of solverbasis
852  // initialize() will recognize that pointer bd_solver.V_ == pointer rstate.V, and will neglect the copy.
853  rstate.V = solverbasis;
854  }
855  else { // inSituRestart == false)
856 # ifdef TEUCHOS_DEBUG
857  *out << "Beginning ex-situ restart...\n";
858 # endif
859  // newV = oldV*Sr, explicitly. workspace is in workMV
860  std::vector<int> curind(curdim), newind(newdim);
861  for (int i=0; i<curdim; i++) curind[i] = i;
862  for (int i=0; i<newdim; i++) newind[i] = i;
863  Teuchos::RCP<const MV> oldV = MVT::CloneView(*state.V,curind);
864  Teuchos::RCP<MV> newV = MVT::CloneViewNonConst(*workMV ,newind);
865 
866  MVT::MvTimesMatAddMv(ONE,*oldV,Sr,ZERO,*newV);
867  //
868  // put the new basis into the state for initialize()
869  rstate.V = newV;
870  }
871 
872  //
873  // send the new state to the solver
874  bd_solver->initialize(rstate);
875  } // end of restarting
877  //
878  // check locking if we didn't converge or restart
879  //
881  else if (locktest != Teuchos::null && locktest->getStatus() == Passed) {
882 
883 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
884  Teuchos::TimeMonitor lcktimer(*_timerLocking);
885 #endif
886 
887  //
888  // get current state
889  BlockDavidsonState<ScalarType,MV> state = bd_solver->getState();
890  const int curdim = state.curDim;
891 
892  //
893  // get number,indices of vectors to be locked
894  TEUCHOS_TEST_FOR_EXCEPTION(locktest->howMany() <= 0,std::logic_error,
895  "Anasazi::BlockDavidsonSolMgr::solve(): status test mistake: howMany() non-positive.");
896  TEUCHOS_TEST_FOR_EXCEPTION(locktest->howMany() != (int)locktest->whichVecs().size(),std::logic_error,
897  "Anasazi::BlockDavidsonSolMgr::solve(): status test mistake: howMany() not consistent with whichVecs().");
898  // we should have room to lock vectors; otherwise, locking should have been deactivated
899  TEUCHOS_TEST_FOR_EXCEPTION(curNumLocked == maxLocked_,std::logic_error,
900  "Anasazi::BlockDavidsonSolMgr::solve(): status test mistake: locking not deactivated.");
901  //
902  // don't lock more than maxLocked_; we didn't allocate enough space.
903  std::vector<int> tmp_vector_int;
904  if (curNumLocked + locktest->howMany() > maxLocked_) {
905  // just use the first of them
906  tmp_vector_int.insert(tmp_vector_int.begin(),locktest->whichVecs().begin(),locktest->whichVecs().begin()+maxLocked_-curNumLocked);
907  }
908  else {
909  tmp_vector_int = locktest->whichVecs();
910  }
911  const std::vector<int> lockind(tmp_vector_int);
912  const int numNewLocked = lockind.size();
913  //
914  // generate indices of vectors left unlocked
915  // curind = [0,...,curdim-1] = UNION( lockind, unlockind )
916  const int numUnlocked = curdim-numNewLocked;
917  tmp_vector_int.resize(curdim);
918  for (int i=0; i<curdim; i++) tmp_vector_int[i] = i;
919  const std::vector<int> curind(tmp_vector_int); // curind = [0 ... curdim-1]
920  tmp_vector_int.resize(numUnlocked);
921  std::set_difference(curind.begin(),curind.end(),lockind.begin(),lockind.end(),tmp_vector_int.begin());
922  const std::vector<int> unlockind(tmp_vector_int); // unlockind = [0 ... curdim-1] - lockind
923  tmp_vector_int.clear();
924 
925  //
926  // debug printing
927  if (printer_->isVerbosity(Debug)) {
928  printer_->print(Debug,"Locking vectors: ");
929  for (unsigned int i=0; i<lockind.size(); i++) {printer_->stream(Debug) << " " << lockind[i];}
930  printer_->print(Debug,"\n");
931  printer_->print(Debug,"Not locking vectors: ");
932  for (unsigned int i=0; i<unlockind.size(); i++) {printer_->stream(Debug) << " " << unlockind[i];}
933  printer_->print(Debug,"\n");
934  }
935 
936  //
937  // we need primitive ritz vectors/values:
938  // [S,L] = eig(oldKK)
939  //
940  // this will be partitioned as follows:
941  // locked: Sl = S(lockind) // we won't actually need Sl
942  // unlocked: Su = S(unlockind)
943  //
944  Teuchos::SerialDenseMatrix<int,ScalarType> S(curdim,curdim);
945  std::vector<MagnitudeType> theta(curdim);
946  {
947  int rank = curdim;
948  int info = msutils::directSolver(curdim,*state.KK,Teuchos::null,S,theta,rank,10);
949  TEUCHOS_TEST_FOR_EXCEPTION(info != 0 ,std::logic_error,
950  "Anasazi::BlockDavidsonSolMgr::solve(): error calling SolverUtils::directSolver."); // this should never happen
951  TEUCHOS_TEST_FOR_EXCEPTION(rank != curdim,std::logic_error,
952  "Anasazi::BlockDavidsonSolMgr::solve(): direct solve did not compute all eigenvectors."); // this should never happen
953  //
954  // sort the eigenvalues (so that we can order the eigenvectors)
955  std::vector<int> order(curdim);
956  sorter->sort(theta,Teuchos::rcpFromRef(order),curdim);
957  //
958  // apply the same ordering to the primitive ritz vectors
959  msutils::permuteVectors(order,S);
960  }
961  //
962  // select the unlocked ritz vectors
963  // the indexing in unlockind is relative to the ordered primitive ritz vectors
964  // (this is why we ordered theta,S above)
965  Teuchos::SerialDenseMatrix<int,ScalarType> Su(curdim,numUnlocked);
966  for (int i=0; i<numUnlocked; i++) {
967  blas.COPY(curdim, S[unlockind[i]], 1, Su[i], 1);
968  }
969 
970 
971  //
972  // newV has the following form:
973  // newV = [defV augV]
974  // - defV will be of size curdim - numNewLocked, and contain the generated basis: defV = oldV*Su
975  // - augV will be of size numNewLocked, and contain random directions to make up for the lost space
976  //
977  // we will need a pointer to defV below to generate the off-diagonal block of newKK
978  // go ahead and setup pointer to augV
979  //
980  Teuchos::RCP<MV> defV, augV;
981  if (inSituRestart_ == true) {
982  //
983  // get non-const pointer to solver's basis so we can work in situ
984  Teuchos::RCP<MV> solverbasis = Teuchos::rcp_const_cast<MV>(state.V);
985  //
986  // perform Householder QR of Su = Q [D;0], where D is unit diag.
987  // work on a copy of Su, since we need Su below to build newKK
988  Teuchos::SerialDenseMatrix<int,ScalarType> copySu(Su);
989  std::vector<ScalarType> tau(numUnlocked), work(numUnlocked);
990  int info;
991  lapack.GEQRF(curdim,numUnlocked,copySu.values(),copySu.stride(),&tau[0],&work[0],work.size(),&info);
992  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
993  "Anasazi::BlockDavidsonSolMgr::solve(): error calling GEQRF during restarting.");
994  if (printer_->isVerbosity(Debug)) {
995  Teuchos::SerialDenseMatrix<int,ScalarType> R(Teuchos::Copy,copySu,numUnlocked,numUnlocked);
996  for (int j=0; j<numUnlocked; j++) {
997  R(j,j) = SCT::magnitude(R(j,j)) - 1.0;
998  for (int i=j+1; i<numUnlocked; i++) {
999  R(i,j) = ZERO;
1000  }
1001  }
1002  printer_->stream(Debug) << "||Triangular factor of Su - I||: " << R.normFrobenius() << std::endl;
1003  }
1004  //
1005  // perform implicit oldV*Su
1006  // this actually performs oldV*[Su Sl*M] = [defV lockV], for some unitary M
1007  // we are actually interested in only the first numUnlocked vectors of the result
1008  {
1009  Teuchos::RCP<MV> oldV = MVT::CloneViewNonConst(*solverbasis,curind);
1010  msutils::applyHouse(numUnlocked,*oldV,copySu,tau,workMV);
1011  }
1012  std::vector<int> defind(numUnlocked), augind(numNewLocked);
1013  for (int i=0; i<numUnlocked ; i++) defind[i] = i;
1014  for (int i=0; i<numNewLocked; i++) augind[i] = numUnlocked+i;
1015  defV = MVT::CloneViewNonConst(*solverbasis,defind);
1016  augV = MVT::CloneViewNonConst(*solverbasis,augind);
1017  }
1018  else { // inSituRestart == false)
1019  // defV = oldV*Su, explicitly. workspace is in workMV
1020  std::vector<int> defind(numUnlocked), augind(numNewLocked);
1021  for (int i=0; i<numUnlocked ; i++) defind[i] = i;
1022  for (int i=0; i<numNewLocked; i++) augind[i] = numUnlocked+i;
1023  Teuchos::RCP<const MV> oldV = MVT::CloneView(*state.V,curind);
1024  defV = MVT::CloneViewNonConst(*workMV,defind);
1025  augV = MVT::CloneViewNonConst(*workMV,augind);
1026 
1027  MVT::MvTimesMatAddMv(ONE,*oldV,Su,ZERO,*defV);
1028  }
1029 
1030  //
1031  // lockvecs will be partitioned as follows:
1032  // lockvecs = [curlocked augTmp ...]
1033  // - augTmp will be used for the storage of M*augV and K*augV
1034  // later, the locked vectors (stored in state.X and referenced via const MV view newLocked)
1035  // will be moved into lockvecs on top of augTmp when it is no longer needed as workspace.
1036  // - curlocked will be used in orthogonalization of augV
1037  //
1038  // newL is the new locked vectors; newL = oldV*Sl = RitzVectors(lockind)
1039  // we will not produce them, but instead retrieve them from RitzVectors
1040  //
1041  Teuchos::RCP<const MV> curlocked, newLocked;
1042  Teuchos::RCP<MV> augTmp;
1043  {
1044  // setup curlocked
1045  if (curNumLocked > 0) {
1046  std::vector<int> curlockind(curNumLocked);
1047  for (int i=0; i<curNumLocked; i++) curlockind[i] = i;
1048  curlocked = MVT::CloneView(*lockvecs,curlockind);
1049  }
1050  else {
1051  curlocked = Teuchos::null;
1052  }
1053  // setup augTmp
1054  std::vector<int> augtmpind(numNewLocked);
1055  for (int i=0; i<numNewLocked; i++) augtmpind[i] = curNumLocked+i;
1056  augTmp = MVT::CloneViewNonConst(*lockvecs,augtmpind);
1057  // setup newLocked
1058  newLocked = MVT::CloneView(*bd_solver->getRitzVectors(),lockind);
1059  }
1060 
1061  //
1062  // generate augV and perform orthogonalization
1063  //
1064  MVT::MvRandom(*augV);
1065  //
1066  // orthogonalize it against auxvecs, defV, and all locked vectors (new and current)
1067  // use augTmp as storage for M*augV, if hasM
1068  {
1069  Teuchos::Array<Teuchos::RCP<const MV> > against;
1070  Teuchos::Array<Teuchos::RCP<Teuchos::SerialDenseMatrix<int,ScalarType> > > dummyC;
1071  if (probauxvecs != Teuchos::null) against.push_back(probauxvecs);
1072  if (curlocked != Teuchos::null) against.push_back(curlocked);
1073  against.push_back(newLocked);
1074  against.push_back(defV);
1075  if (problem_->getM() != Teuchos::null) {
1076  OPT::Apply(*problem_->getM(),*augV,*augTmp);
1077  }
1078  ortho->projectAndNormalizeMat(*augV,against,dummyC,Teuchos::null,augTmp);
1079  }
1080 
1081  //
1082  // form newKK
1083  //
1084  // newKK = newV'*K*newV = [Su'*KK*Su defV'*K*augV]
1085  // [augV'*K*defV augV'*K*augV]
1086  //
1087  // first, generate the principal submatrix, the projection of K onto the unlocked portion of oldV
1088  //
1089  Teuchos::SerialDenseMatrix<int,ScalarType> newKK(curdim,curdim);
1090  {
1091  Teuchos::SerialDenseMatrix<int,ScalarType> KKtmp(curdim,numUnlocked),
1092  KKold(Teuchos::View,*state.KK,curdim,curdim),
1093  KK11(Teuchos::View,newKK,numUnlocked,numUnlocked);
1094  int teuchosRet;
1095  // KKtmp = KKold*Su
1096  teuchosRet = KKtmp.multiply(Teuchos::NO_TRANS,Teuchos::NO_TRANS,ONE,KKold,Su,ZERO);
1097  TEUCHOS_TEST_FOR_EXCEPTION(teuchosRet != 0,std::logic_error,
1098  "Anasazi::BlockDavidsonSolMgr::solve(): Logic error calling SerialDenseMatrix::multiply.");
1099  // KK11 = Su'*KKtmp = Su'*KKold*Su
1100  teuchosRet = KK11.multiply(Teuchos::CONJ_TRANS,Teuchos::NO_TRANS,ONE,Su,KKtmp,ZERO);
1101  TEUCHOS_TEST_FOR_EXCEPTION(teuchosRet != 0,std::logic_error,
1102  "Anasazi::BlockDavidsonSolMgr::solve(): Logic error calling SerialDenseMatrix::multiply.");
1103  }
1104  //
1105  // project the stiffness matrix on augV
1106  {
1107  OPT::Apply(*problem_->getOperator(),*augV,*augTmp);
1108  Teuchos::SerialDenseMatrix<int,ScalarType> KK12(Teuchos::View,newKK,numUnlocked,numNewLocked,0,numUnlocked),
1109  KK22(Teuchos::View,newKK,numNewLocked,numNewLocked,numUnlocked,numUnlocked);
1110  MVT::MvTransMv(ONE,*defV,*augTmp,KK12);
1111  MVT::MvTransMv(ONE,*augV,*augTmp,KK22);
1112  }
1113  //
1114  // done with defV,augV
1115  defV = Teuchos::null;
1116  augV = Teuchos::null;
1117  //
1118  // make it hermitian in memory (fill in KK21)
1119  for (int j=0; j<curdim; ++j) {
1120  for (int i=j+1; i<curdim; ++i) {
1121  newKK(i,j) = SCT::conjugate(newKK(j,i));
1122  }
1123  }
1124  //
1125  // we are done using augTmp as storage
1126  // put newLocked into lockvecs, new values into lockvals
1127  augTmp = Teuchos::null;
1128  {
1129  std::vector<Value<ScalarType> > allvals = bd_solver->getRitzValues();
1130  for (int i=0; i<numNewLocked; i++) {
1131  lockvals.push_back(allvals[lockind[i]].realpart);
1132  }
1133 
1134  std::vector<int> indlock(numNewLocked);
1135  for (int i=0; i<numNewLocked; i++) indlock[i] = curNumLocked+i;
1136  MVT::SetBlock(*newLocked,indlock,*lockvecs);
1137  newLocked = Teuchos::null;
1138 
1139  curNumLocked += numNewLocked;
1140  std::vector<int> curlockind(curNumLocked);
1141  for (int i=0; i<curNumLocked; i++) curlockind[i] = i;
1142  curlocked = MVT::CloneView(*lockvecs,curlockind);
1143  }
1144  // add locked vecs as aux vecs, along with aux vecs from problem
1145  // add lockvals to ordertest
1146  // disable locktest if curNumLocked == maxLocked
1147  {
1148  ordertest->setAuxVals(lockvals);
1149 
1150  Teuchos::Array< Teuchos::RCP<const MV> > aux;
1151  if (probauxvecs != Teuchos::null) aux.push_back(probauxvecs);
1152  aux.push_back(curlocked);
1153  bd_solver->setAuxVecs(aux);
1154 
1155  if (curNumLocked == maxLocked_) {
1156  // disabled locking now
1157  combotest->removeTest(locktest);
1158  }
1159  }
1160 
1161  //
1162  // prepare new state
1164  rstate.curDim = curdim;
1165  if (inSituRestart_) {
1166  // data is already in the solver's memory
1167  rstate.V = state.V;
1168  }
1169  else {
1170  // data is in workspace and will be copied to solver memory
1171  rstate.V = workMV;
1172  }
1173  rstate.KK = Teuchos::rcpFromRef(newKK);
1174  //
1175  // pass new state to the solver
1176  bd_solver->initialize(rstate);
1177  } // end of locking
1179  //
1180  // we returned from iterate(), but none of our status tests Passed.
1181  // something is wrong, and it is probably our fault.
1182  //
1184  else {
1185  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"Anasazi::BlockDavidsonSolMgr::solve(): Invalid return from bd_solver::iterate().");
1186  }
1187  }
1188  catch (const AnasaziError &err) {
1189  printer_->stream(Errors)
1190  << "Anasazi::BlockDavidsonSolMgr::solve() caught unexpected exception from Anasazi::BlockDavidson::iterate() at iteration " << bd_solver->getNumIters() << std::endl
1191  << err.what() << std::endl
1192  << "Anasazi::BlockDavidsonSolMgr::solve() returning Unconverged with no solutions." << std::endl;
1193  return Unconverged;
1194  }
1195  }
1196 
1197  // clear temp space
1198  workMV = Teuchos::null;
1199 
1200  sol.numVecs = ordertest->howMany();
1201  if (sol.numVecs > 0) {
1202  sol.Evecs = MVT::Clone(*problem_->getInitVec(),sol.numVecs);
1203  sol.Espace = sol.Evecs;
1204  sol.Evals.resize(sol.numVecs);
1205  std::vector<MagnitudeType> vals(sol.numVecs);
1206 
1207  // copy them into the solution
1208  std::vector<int> which = ordertest->whichVecs();
1209  // indices between [0,blockSize) refer to vectors/values in the solver
1210  // indices between [-curNumLocked,-1] refer to locked vectors/values [0,curNumLocked)
1211  // everything has already been ordered by the solver; we just have to partition the two references
1212  std::vector<int> inlocked(0), insolver(0);
1213  for (unsigned int i=0; i<which.size(); i++) {
1214  if (which[i] >= 0) {
1215  TEUCHOS_TEST_FOR_EXCEPTION(which[i] >= blockSize_,std::logic_error,"Anasazi::BlockDavidsonSolMgr::solve(): positive indexing mistake from ordertest.");
1216  insolver.push_back(which[i]);
1217  }
1218  else {
1219  // sanity check
1220  TEUCHOS_TEST_FOR_EXCEPTION(which[i] < -curNumLocked,std::logic_error,"Anasazi::BlockDavidsonSolMgr::solve(): negative indexing mistake from ordertest.");
1221  inlocked.push_back(which[i] + curNumLocked);
1222  }
1223  }
1224 
1225  TEUCHOS_TEST_FOR_EXCEPTION(insolver.size() + inlocked.size() != (unsigned int)sol.numVecs,std::logic_error,"Anasazi::BlockDavidsonSolMgr::solve(): indexing mistake.");
1226 
1227  // set the vecs,vals in the solution
1228  if (insolver.size() > 0) {
1229  // set vecs
1230  int lclnum = insolver.size();
1231  std::vector<int> tosol(lclnum);
1232  for (int i=0; i<lclnum; i++) tosol[i] = i;
1233  Teuchos::RCP<const MV> v = MVT::CloneView(*bd_solver->getRitzVectors(),insolver);
1234  MVT::SetBlock(*v,tosol,*sol.Evecs);
1235  // set vals
1236  std::vector<Value<ScalarType> > fromsolver = bd_solver->getRitzValues();
1237  for (unsigned int i=0; i<insolver.size(); i++) {
1238  vals[i] = fromsolver[insolver[i]].realpart;
1239  }
1240  }
1241 
1242  // get the vecs,vals from locked storage
1243  if (inlocked.size() > 0) {
1244  int solnum = insolver.size();
1245  // set vecs
1246  int lclnum = inlocked.size();
1247  std::vector<int> tosol(lclnum);
1248  for (int i=0; i<lclnum; i++) tosol[i] = solnum + i;
1249  Teuchos::RCP<const MV> v = MVT::CloneView(*lockvecs,inlocked);
1250  MVT::SetBlock(*v,tosol,*sol.Evecs);
1251  // set vals
1252  for (unsigned int i=0; i<inlocked.size(); i++) {
1253  vals[i+solnum] = lockvals[inlocked[i]];
1254  }
1255  }
1256 
1257  // sort the eigenvalues and permute the eigenvectors appropriately
1258  {
1259  std::vector<int> order(sol.numVecs);
1260  sorter->sort(vals,Teuchos::rcpFromRef(order),sol.numVecs);
1261  // store the values in the Eigensolution
1262  for (int i=0; i<sol.numVecs; i++) {
1263  sol.Evals[i].realpart = vals[i];
1264  sol.Evals[i].imagpart = MT::zero();
1265  }
1266  // now permute the eigenvectors according to order
1267  msutils::permuteVectors(sol.numVecs,order,*sol.Evecs);
1268  }
1269 
1270  // setup sol.index, remembering that all eigenvalues are real so that index = {0,...,0}
1271  sol.index.resize(sol.numVecs,0);
1272  }
1273  }
1274 
1275  // print final summary
1276  bd_solver->currentStatus(printer_->stream(FinalSummary));
1277 
1278  // print timing information
1279 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
1280  if ( printer_->isVerbosity( TimingDetails ) ) {
1281  Teuchos::TimeMonitor::summarize( printer_->stream( TimingDetails ) );
1282  }
1283 #endif
1284 
1285  problem_->setSolution(sol);
1286  printer_->stream(Debug) << "Returning " << sol.numVecs << " eigenpairs to eigenproblem." << std::endl;
1287 
1288  // get the number of iterations taken for this call to solve().
1289  numIters_ = bd_solver->getNumIters();
1290 
1291  if (sol.numVecs < nev) {
1292  return Unconverged; // return from BlockDavidsonSolMgr::solve()
1293  }
1294  return Converged; // return from BlockDavidsonSolMgr::solve()
1295 }
1296 
1297 
1298 template <class ScalarType, class MV, class OP>
1299 void
1301  const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &global)
1302 {
1303  globalTest_ = global;
1304 }
1305 
1306 template <class ScalarType, class MV, class OP>
1307 const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &
1309 {
1310  return globalTest_;
1311 }
1312 
1313 template <class ScalarType, class MV, class OP>
1314 void
1316  const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &debug)
1317 {
1318  debugTest_ = debug;
1319 }
1320 
1321 template <class ScalarType, class MV, class OP>
1322 const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &
1324 {
1325  return debugTest_;
1326 }
1327 
1328 template <class ScalarType, class MV, class OP>
1329 void
1331  const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &locking)
1332 {
1333  lockingTest_ = locking;
1334 }
1335 
1336 template <class ScalarType, class MV, class OP>
1337 const Teuchos::RCP< StatusTest<ScalarType,MV,OP> > &
1339 {
1340  return lockingTest_;
1341 }
1342 
1343 } // end Anasazi namespace
1344 
1345 #endif /* ANASAZI_BLOCKDAVIDSON_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. ...
static void MvRandom(MV &mv)
Replace the vectors in mv with random vectors.
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 .
void setLockingStatusTest(const Teuchos::RCP< StatusTest< ScalarType, MV, OP > > &locking)
Set the status test defining locking.
ResType
Enumerated type used to specify which residual norm used by residual norm status tests.
A special StatusTest for printing other status tests.
BlockDavidsonSolMgr(const Teuchos::RCP< Eigenproblem< ScalarType, MV, OP > > &problem, Teuchos::ParameterList &pl)
Basic constructor for BlockDavidsonSolMgr.
This class defines the interface required by an eigensolver and status test class to compute solution...
Teuchos::RCP< const MV > R
The current residual vectors.
Teuchos::RCP< const Teuchos::SerialDenseMatrix< int, ScalarType > > KK
The current projected K matrix.
An implementation of the Anasazi::SortManager that performs a collection of common sorting techniques...
const Teuchos::RCP< StatusTest< ScalarType, MV, OP > > & getDebugStatusTest() const
Get the status test for debugging.
Virtual base class which defines basic traits for the operator type.
Teuchos::RCP< MV > Evecs
The computed eigenvectors.
Status test for forming logical combinations of other status tests.
Teuchos::RCP< const MV > KX
The image of the current eigenvectors under K.
The Anasazi::SolverManager is a templated virtual base class that defines the basic interface that an...
static void Apply(const OP &Op, const MV &x, MV &y)
Application method which performs operation y = Op*x. An OperatorError exception is thrown if there i...
Basic implementation of the Anasazi::SortManager class.
An implementation of the Anasazi::MatOrthoManager that performs orthogonalization using the SVQB iter...
An exception class parent to all Anasazi exceptions.
This class implements a Block Davidson iteration, a preconditioned iteration for solving linear Hermi...
Implementation of the block Davidson method.
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.
Basic output manager for sending information of select verbosity levels to the appropriate output str...
const Teuchos::RCP< StatusTest< ScalarType, MV, OP > > & getLockingStatusTest() const
Get the status test defining locking.
Teuchos::RCP< MV > Espace
An orthonormal basis for the computed eigenspace.
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.
Teuchos::RCP< const MV > V
The basis for the Krylov space.
Teuchos::Array< Teuchos::RCP< Teuchos::Time > > getTimers() const
Return the timers for this object.
A status test for testing the norm of the eigenvectors residuals.
Traits class which defines basic operations on multivectors.
static void MvTransMv(const ScalarType alpha, const MV &A, const MV &B, Teuchos::SerialDenseMatrix< int, ScalarType > &C)
Compute C := alpha * A^H B.
std::vector< int > index
An index into Evecs to allow compressed storage of eigenvectors for real, non-Hermitian problems...
const Teuchos::RCP< StatusTest< ScalarType, MV, OP > > & getGlobalStatusTest() const
Get the status test defining global convergence.
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.
const Eigenproblem< ScalarType, MV, OP > & getProblem() const
Return the eigenvalue problem.
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...
int curDim
The current dimension of the solver.
Structure to contain pointers to BlockDavidson state variables.
Special StatusTest for printing status tests.
A status test for testing the norm of the eigenvectors residuals along with a set of auxiliary eigenv...
int getNumIters() const
Get the iteration count for the most recent call to solve().
void setDebugStatusTest(const Teuchos::RCP< StatusTest< ScalarType, MV, OP > > &debug)
Set the status test for debugging.
Teuchos::RCP< const MV > X
The current eigenvectors.
Teuchos::RCP< const MV > MX
The image of the current eigenvectors under M, or Teuchos::null if M was not specified.
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.
The BlockDavidsonSolMgr provides a powerful solver manager over the BlockDavidson eigensolver...
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.
void setGlobalStatusTest(const Teuchos::RCP< StatusTest< ScalarType, MV, OP > > &global)
Set the status test defining global convergence.
ReturnType solve()
This method performs possibly repeated calls to the underlying eigensolver&#39;s iterate() routine until ...
static Teuchos::RCP< MV > Clone(const MV &mv, const int numvecs)
Creates a new empty MV containing numvecs columns.
Teuchos::RCP< const std::vector< typename Teuchos::ScalarTraits< ScalarType >::magnitudeType > > T
The current Ritz values. This vector is a copy of the internal data.
Class which provides internal utilities for the Anasazi solvers.