|
Anasazi
Version of the Day
|
00001 // @HEADER 00002 // *********************************************************************** 00003 // 00004 // Anasazi: Block Eigensolvers Package 00005 // Copyright (2004) Sandia Corporation 00006 // 00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 00008 // license for use of this work by or on behalf of the U.S. Government. 00009 // 00010 // This library is free software; you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as 00012 // published by the Free Software Foundation; either version 2.1 of the 00013 // License, or (at your option) any later version. 00014 // 00015 // This library is distributed in the hope that it will be useful, but 00016 // WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 // Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public 00021 // License along with this library; if not, write to the Free Software 00022 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 00023 // USA 00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 00025 // 00026 // *********************************************************************** 00027 // @HEADER 00028 00029 #ifndef ANASAZI_TraceMinBase_SOLMGR_HPP 00030 #define ANASAZI_TraceMinBase_SOLMGR_HPP 00031 00036 #include "AnasaziBasicOrthoManager.hpp" 00037 #include "AnasaziBasicOutputManager.hpp" 00038 #include "AnasaziBasicSort.hpp" 00039 #include "AnasaziConfigDefs.hpp" 00040 #include "AnasaziEigenproblem.hpp" 00041 #include "AnasaziICGSOrthoManager.hpp" 00042 #include "AnasaziSolverManager.hpp" 00043 #include "AnasaziSolverUtils.hpp" 00044 #include "AnasaziStatusTestCombo.hpp" 00045 #include "AnasaziStatusTestOutput.hpp" 00046 #include "AnasaziStatusTestResNorm.hpp" 00047 #include "AnasaziStatusTestSpecTrans.hpp" 00048 #include "AnasaziStatusTestWithOrdering.hpp" 00049 #include "AnasaziSVQBOrthoManager.hpp" 00050 #include "AnasaziTraceMinBase.hpp" 00051 #include "AnasaziTraceMinTypes.hpp" 00052 #include "AnasaziTypes.hpp" 00053 00054 #include "Teuchos_TimeMonitor.hpp" 00055 #ifdef TEUCHOS_DEBUG 00056 # include <Teuchos_FancyOStream.hpp> 00057 #endif 00058 #ifdef HAVE_MPI 00059 #include <mpi.h> 00060 #endif 00061 00062 using Teuchos::RCP; 00063 using Teuchos::rcp; 00064 00065 namespace Anasazi { 00066 namespace Experimental { 00067 00068 00101 template<class ScalarType, class MV, class OP> 00102 class TraceMinBaseSolMgr : public SolverManager<ScalarType,MV,OP> { 00103 00104 private: 00105 typedef MultiVecTraits<ScalarType,MV> MVT; 00106 typedef MultiVecTraitsExt<ScalarType,MV> MVText; 00107 typedef OperatorTraits<ScalarType,MV,OP> OPT; 00108 typedef Teuchos::ScalarTraits<ScalarType> SCT; 00109 typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MagnitudeType; 00110 typedef Teuchos::ScalarTraits<MagnitudeType> MT; 00111 00112 public: 00113 00115 00116 00158 TraceMinBaseSolMgr( const RCP<Eigenproblem<ScalarType,MV,OP> > &problem, 00159 Teuchos::ParameterList &pl ); 00160 00162 virtual ~TraceMinBaseSolMgr() {}; 00164 00166 00167 00169 const Eigenproblem<ScalarType,MV,OP>& getProblem() const { 00170 return *problem_; 00171 } 00172 00174 int getNumIters() const { 00175 return numIters_; 00176 } 00177 00185 Teuchos::Array<RCP<Teuchos::Time> > getTimers() const { 00186 return Teuchos::tuple(_timerSolve, _timerRestarting, _timerLocking); 00187 } 00188 00190 00192 00193 00217 ReturnType solve(); 00218 00220 void setGlobalStatusTest(const RCP< StatusTest<ScalarType,MV,OP> > &global); 00221 00223 const RCP< StatusTest<ScalarType,MV,OP> > & getGlobalStatusTest() const; 00224 00226 void setLockingStatusTest(const RCP< StatusTest<ScalarType,MV,OP> > &locking); 00227 00229 const RCP< StatusTest<ScalarType,MV,OP> > & getLockingStatusTest() const; 00230 00232 void setDebugStatusTest(const RCP< StatusTest<ScalarType,MV,OP> > &debug); 00233 00235 const RCP< StatusTest<ScalarType,MV,OP> > & getDebugStatusTest() const; 00236 00238 00239 protected: 00240 RCP<Eigenproblem<ScalarType,MV,OP> > problem_; 00241 00242 int numIters_; 00243 00244 // Block variables 00245 int blockSize_, numBlocks_, numRestartBlocks_; 00246 00247 // Output variables 00248 RCP<BasicOutputManager<ScalarType> > printer_; 00249 00250 // Convergence variables 00251 MagnitudeType convTol_; 00252 bool relConvTol_; 00253 enum ResType convNorm_; 00254 00255 // Locking variables 00256 MagnitudeType lockTol_; 00257 int maxLocked_, lockQuorum_; 00258 bool useLocking_, relLockTol_; 00259 enum ResType lockNorm_; 00260 00261 // Shifting variables 00262 enum WhenToShiftType whenToShift_; 00263 MagnitudeType traceThresh_, shiftTol_; 00264 enum HowToShiftType howToShift_; 00265 bool useMultipleShifts_, relShiftTol_, considerClusters_; 00266 std::string shiftNorm_; 00267 00268 // Other variables 00269 int maxKrylovIter_; 00270 std::string ortho_, which_; 00271 enum SaddleSolType saddleSolType_; 00272 bool projectAllVecs_, projectLockedVecs_, computeAllRes_, useRHSR_; 00273 00274 // Timers 00275 RCP<Teuchos::Time> _timerSolve, _timerRestarting, _timerLocking; 00276 00277 // Status tests 00278 RCP<StatusTest<ScalarType,MV,OP> > globalTest_; 00279 RCP<StatusTest<ScalarType,MV,OP> > lockingTest_; 00280 RCP<StatusTest<ScalarType,MV,OP> > debugTest_; 00281 00282 // TraceMin specific functions 00283 void copyPartOfState(const TraceMinBaseState<ScalarType,MV>& oldState, TraceMinBaseState<ScalarType,MV>& newState, const std::vector<int> indToCopy) const; 00284 00285 void setParameters(Teuchos::ParameterList &pl) const; 00286 00287 void printParameters(std::ostream &os) const; 00288 00289 virtual RCP< TraceMinBase<ScalarType,MV,OP> > createSolver( 00290 const RCP<SortManager<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> > &sorter, 00291 const RCP<StatusTest<ScalarType,MV,OP> > &outputtest, 00292 const RCP<MatOrthoManager<ScalarType,MV,OP> > &ortho, 00293 Teuchos::ParameterList &plist 00294 ) =0; 00295 00296 virtual bool needToRestart(const RCP< TraceMinBase<ScalarType,MV,OP> > solver) =0; 00297 00298 virtual bool performRestart(int &numRestarts, RCP< TraceMinBase<ScalarType,MV,OP> > solver) =0; 00299 }; 00300 00301 00304 // Constructor 00305 template<class ScalarType, class MV, class OP> 00306 TraceMinBaseSolMgr<ScalarType,MV,OP>::TraceMinBaseSolMgr( 00307 const RCP<Eigenproblem<ScalarType,MV,OP> > &problem, 00308 Teuchos::ParameterList &pl ) : 00309 problem_(problem) 00310 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR 00311 , _timerSolve(Teuchos::TimeMonitor::getNewTimer("Anasazi: TraceMinBaseSolMgr::solve()")), 00312 _timerRestarting(Teuchos::TimeMonitor::getNewTimer("Anasazi: TraceMinBaseSolMgr restarting")), 00313 _timerLocking(Teuchos::TimeMonitor::getNewTimer("Anasazi: TraceMinBaseSolMgr locking")) 00314 #endif 00315 { 00316 TEUCHOS_TEST_FOR_EXCEPTION(problem_ == Teuchos::null, std::invalid_argument, "Problem not given to solver manager."); 00317 TEUCHOS_TEST_FOR_EXCEPTION(!problem_->isProblemSet(), std::invalid_argument, "Problem not set."); 00318 TEUCHOS_TEST_FOR_EXCEPTION(!problem_->isHermitian(), std::invalid_argument, "Problem not symmetric."); 00319 TEUCHOS_TEST_FOR_EXCEPTION(problem_->getInitVec() == Teuchos::null,std::invalid_argument, "Problem does not contain initial vectors to clone from."); 00320 00321 std::string strtmp; 00322 00324 // Block parameters 00325 00326 // TODO: the default is different for TraceMin and TraceMin-Davidson 00327 // block size: default is nev() 00328 // blockSize_ = pl.get("Block Size",problem_->getNEV()); 00329 // TEUCHOS_TEST_FOR_EXCEPTION(blockSize_ <= 0, std::invalid_argument, 00330 // "Anasazi::TraceMinBaseSolMgr: \"Block Size\" must be strictly positive."); 00331 00332 // TODO: add Num Blocks as a parameter to both child classes, since they have different default values 00333 // numBlocks_ = pl.get("Num Blocks",5); 00334 // TEUCHOS_TEST_FOR_EXCEPTION(numBlocks_ < 2, std::invalid_argument, 00335 // "Anasazi::TraceMinBaseSolMgr: \"Num Blocks\" must be >= 2."); 00336 00338 // Output parameters 00339 00340 // output stream 00341 std::string fntemplate = ""; 00342 bool allProcs = false; 00343 if (pl.isParameter("Output on all processors")) { 00344 if (Teuchos::isParameterType<bool>(pl,"Output on all processors")) { 00345 allProcs = pl.get("Output on all processors",allProcs); 00346 } else { 00347 allProcs = ( Teuchos::getParameter<int>(pl,"Output on all processors") != 0 ); 00348 } 00349 } 00350 fntemplate = pl.get("Output filename template",fntemplate); 00351 int MyPID; 00352 # ifdef HAVE_MPI 00353 // Initialize MPI 00354 int mpiStarted = 0; 00355 MPI_Initialized(&mpiStarted); 00356 if (mpiStarted) MPI_Comm_rank(MPI_COMM_WORLD, &MyPID); 00357 else MyPID=0; 00358 # else 00359 MyPID = 0; 00360 # endif 00361 if (fntemplate != "") { 00362 std::ostringstream MyPIDstr; 00363 MyPIDstr << MyPID; 00364 // replace %d in fntemplate with MyPID 00365 int pos, start=0; 00366 while ( (pos = fntemplate.find("%d",start)) != -1 ) { 00367 fntemplate.replace(pos,2,MyPIDstr.str()); 00368 start = pos+2; 00369 } 00370 } 00371 RCP<ostream> osp; 00372 if (fntemplate != "") { 00373 osp = rcp( new std::ofstream(fntemplate.c_str(),std::ios::out | std::ios::app) ); 00374 if (!*osp) { 00375 osp = Teuchos::rcpFromRef(std::cout); 00376 std::cout << "Anasazi::TraceMinBaseSolMgr::constructor(): Could not open file for write: " << fntemplate << std::endl; 00377 } 00378 } 00379 else { 00380 osp = Teuchos::rcpFromRef(std::cout); 00381 } 00382 // Output manager 00383 int verbosity = Anasazi::Errors; 00384 if (pl.isParameter("Verbosity")) { 00385 if (Teuchos::isParameterType<int>(pl,"Verbosity")) { 00386 verbosity = pl.get("Verbosity", verbosity); 00387 } else { 00388 verbosity = (int)Teuchos::getParameter<Anasazi::MsgType>(pl,"Verbosity"); 00389 } 00390 } 00391 if (allProcs) { 00392 // print on all procs 00393 printer_ = rcp( new BasicOutputManager<ScalarType>(verbosity,osp,MyPID) ); 00394 } 00395 else { 00396 // print only on proc 0 00397 printer_ = rcp( new BasicOutputManager<ScalarType>(verbosity,osp,0) ); 00398 } 00399 00400 // TODO: Add restart parameters to TraceMin-Davidson 00401 00403 // Convergence parameters 00404 convTol_ = pl.get("Convergence Tolerance",MT::prec()); 00405 TEUCHOS_TEST_FOR_EXCEPTION(convTol_ < 0, std::invalid_argument, 00406 "Anasazi::TraceMinBaseSolMgr: \"Convergence Tolerance\" must be nonnegative."); 00407 00408 relConvTol_ = pl.get("Relative Convergence Tolerance",true); 00409 strtmp = pl.get("Convergence Norm",std::string("2")); 00410 if (strtmp == "2") { 00411 convNorm_ = RES_2NORM; 00412 } 00413 else if (strtmp == "M") { 00414 convNorm_ = RES_ORTH; 00415 } 00416 else { 00417 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, 00418 "Anasazi::TraceMinBaseSolMgr: Invalid Convergence Norm."); 00419 } 00420 00422 // Locking parameters 00423 useLocking_ = pl.get("Use Locking",true); 00424 relLockTol_ = pl.get("Relative Locking Tolerance",true); 00425 lockTol_ = pl.get("Locking Tolerance",convTol_/10); 00426 00427 TEUCHOS_TEST_FOR_EXCEPTION(relConvTol_ != relLockTol_, std::invalid_argument, 00428 "Anasazi::TraceMinBaseSolMgr: \"Relative Convergence Tolerance\" and \"Relative Locking Tolerance\" have different values. If you set one, you should always set the other."); 00429 00430 TEUCHOS_TEST_FOR_EXCEPTION(lockTol_ < 0, std::invalid_argument, 00431 "Anasazi::TraceMinBaseSolMgr: \"Locking Tolerance\" must be nonnegative."); 00432 00433 strtmp = pl.get("Locking Norm",std::string("2")); 00434 if (strtmp == "2") { 00435 lockNorm_ = RES_2NORM; 00436 } 00437 else if (strtmp == "M") { 00438 lockNorm_ = RES_ORTH; 00439 } 00440 else { 00441 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, 00442 "Anasazi::TraceMinBaseSolMgr: Invalid Locking Norm."); 00443 } 00444 00445 // max locked: default is nev(), must satisfy maxLocked_ + blockSize_ >= nev 00446 if (useLocking_) { 00447 maxLocked_ = pl.get("Max Locked",problem_->getNEV()); 00448 TEUCHOS_TEST_FOR_EXCEPTION(maxLocked_ <= 0, std::invalid_argument, 00449 "Anasazi::TraceMinBaseSolMgr: \"Max Locked\" must be strictly positive."); 00450 } 00451 else { 00452 maxLocked_ = 0; 00453 } 00454 00455 if (useLocking_) { 00456 lockQuorum_ = pl.get("Locking Quorum",1); 00457 TEUCHOS_TEST_FOR_EXCEPTION(lockQuorum_ <= 0, std::invalid_argument, 00458 "Anasazi::TraceMinBaseSolMgr: \"Locking Quorum\" must be strictly positive."); 00459 } 00460 00462 // Ritz shift parameters 00463 00464 // When to shift - what triggers a shift? 00465 strtmp = pl.get("When To Shift", "Always"); 00466 00467 if(strtmp == "Never") 00468 whenToShift_ = NEVER_SHIFT; 00469 else if(strtmp == "After Trace Levels") 00470 whenToShift_ = SHIFT_WHEN_TRACE_LEVELS; 00471 else if(strtmp == "Residual Becomes Small") 00472 whenToShift_ = SHIFT_WHEN_RESID_SMALL; 00473 else if(strtmp == "Always") 00474 whenToShift_ = ALWAYS_SHIFT; 00475 else 00476 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, 00477 "Anasazi::TraceMinBaseSolMgr: Invalid value for \"When To Shift\"; valid options are \"Never\", \"After Trace Levels\", \"Residual Becomes Small\", \"Always\"."); 00478 00479 00480 // How small does the % change in trace have to get before shifting? 00481 traceThresh_ = pl.get("Trace Threshold", 0.02); 00482 00483 TEUCHOS_TEST_FOR_EXCEPTION(traceThresh_ < 0, std::invalid_argument, 00484 "Anasazi::TraceMinBaseSolMgr: \"Trace Threshold\" must be nonnegative."); 00485 00486 // Shift threshold - if the residual of an eigenpair is less than this, then shift 00487 shiftTol_ = pl.get("Shift Tolerance", 0.1); 00488 00489 TEUCHOS_TEST_FOR_EXCEPTION(shiftTol_ < 0, std::invalid_argument, 00490 "Anasazi::TraceMinBaseSolMgr: \"Shift Tolerance\" must be nonnegative."); 00491 00492 // Use relative convergence tolerance - scale by eigenvalue? 00493 relShiftTol_ = pl.get("Relative Shift Tolerance", true); 00494 00495 // Which norm to use in determining whether to shift 00496 shiftNorm_ = pl.get("Shift Norm", "2"); 00497 00498 TEUCHOS_TEST_FOR_EXCEPTION(shiftNorm_ != "2" && shiftNorm_ != "M", std::invalid_argument, 00499 "Anasazi::TraceMinBaseSolMgr: Invalid value for \"Shift Norm\"; valid options are \"2\" and \"M\"."); 00500 00501 // How to choose shift 00502 strtmp = pl.get("How To Choose Shift", "Adjusted Ritz Values"); 00503 00504 if(strtmp == "Largest Converged") 00505 howToShift_ = LARGEST_CONVERGED_SHIFT; 00506 else if(strtmp == "Adjusted Ritz Values") 00507 howToShift_ = ADJUSTED_RITZ_SHIFT; 00508 else if(strtmp == "Ritz Values") 00509 howToShift_ = RITZ_VALUES_SHIFT; 00510 else 00511 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, 00512 "Anasazi::TraceMinBaseSolMgr: Invalid value for \"How To Choose Shift\"; valid options are \"Largest Converged\", \"Adjusted Ritz Values\", \"Ritz Values\"."); 00513 00514 // Consider clusters - if all eigenvalues are in one cluster, it's not expecially safe to shift 00515 considerClusters_ = pl.get("Consider Clusters", true); 00516 00517 // Use multiple shifts 00518 useMultipleShifts_ = pl.get("Use Multiple Shifts", true); 00519 00521 // Other parameters 00522 00523 // which orthogonalization to use 00524 ortho_ = pl.get("Orthogonalization", "SVQB"); 00525 TEUCHOS_TEST_FOR_EXCEPTION(ortho_ != "DGKS" && ortho_ != "SVQB" && ortho_ != "ICGS", std::invalid_argument, 00526 "Anasazi::TraceMinBaseSolMgr: Invalid value for \"Orthogonalization\"; valid options are \"DGKS\", \"SVQB\", \"ICGS\"."); 00527 00528 strtmp = pl.get("Saddle Solver Type", "Projected Krylov"); 00529 00530 if(strtmp == "Projected Krylov") 00531 saddleSolType_ = PROJECTED_KRYLOV_SOLVER; 00532 else if(strtmp == "Schur Complement") 00533 saddleSolType_ = SCHUR_COMPLEMENT_SOLVER; 00534 else if(strtmp == "Block Diagonal Preconditioned Minres") 00535 saddleSolType_ = BD_PREC_MINRES; 00536 else 00537 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, 00538 "Anasazi::TraceMinBaseSolMgr: Invalid value for \"Saddle Solver Type\"; valid options are \"Projected Krylov\", \"Schur Complement\", and \"Block Diagonal Preconditioned Minres\"."); 00539 00540 projectAllVecs_ = pl.get("Project All Vectors", true); 00541 projectLockedVecs_ = pl.get("Project Locked Vectors", true); 00542 computeAllRes_ = pl.get("Compute All Residuals", true); 00543 useRHSR_ = pl.get("Use Residual as RHS", true); 00544 00545 TEUCHOS_TEST_FOR_EXCEPTION(projectLockedVecs_ && ! projectAllVecs_, std::invalid_argument, 00546 "Anasazi::TraceMinBaseSolMgr: If you want to project out the locked vectors, you should really project out ALL the vectors of X."); 00547 00548 // Maximum number of inner iterations 00549 maxKrylovIter_ = pl.get("Maximum Krylov Iterations", 1000); 00550 TEUCHOS_TEST_FOR_EXCEPTION(maxKrylovIter_ < 1, std::invalid_argument, 00551 "Anasazi::TraceMinBaseSolMgr: \"Maximum Krylov Iterations\" must be greater than 0."); 00552 00553 // Which eigenvalues we want to get 00554 which_ = pl.get("Which", "SM"); 00555 TEUCHOS_TEST_FOR_EXCEPTION(which_ != "SM" && which_ != "LM", std::invalid_argument, 00556 "Anasazi::TraceMinBaseSolMgr: Invalid value for \"Which\"; valid options are \"SM\" and \"LM\"."); 00557 00558 // Test whether we are shifting without an operator K 00559 // This is a really bad idea 00560 TEUCHOS_TEST_FOR_EXCEPTION(problem_->getOperator() == Teuchos::null && whenToShift_ != NEVER_SHIFT, std::invalid_argument, 00561 "Anasazi::TraceMinBaseSolMgr: It is an exceptionally bad idea to use Ritz shifts when finding the largest eigenpairs of a standard eigenvalue problem. If we don't use Ritz shifts, it may take extra iterations to converge, but we NEVER have to solve a single linear system. Using Ritz shifts forces us to solve systems of the form (I + sigma A)x=f, and it probably doesn't benefit us enough to outweigh the extra cost. We may add support for this feature in the future, but for now, please set \"When To Shift\" to \"Never\"."); 00562 00563 #ifdef BELOS_PSEUDO_BLOCK_GMRES_SOLMGR_HPP 00564 // Test whether we are using a projected preconditioner with multiple Ritz shifts 00565 // We can't currently do this for reasons that are complicated and are explained in the user manual 00566 TEUCHOS_TEST_FOR_EXCEPTION(problem_->getPrec() != Teuchos::null && saddleSolType_ == PROJECTED_KRYLOV_SOLVER && useMultipleShifts_, std::invalid_argument, 00567 "Anasazi::TraceMinBaseSolMgr: When you use the projected Krylov solver with preconditioning, the preconditioner must be projected as well. In theory, if the preconditioner is SPD, the projected preconditioner will be SPSD, but in practice, it can have small negative eigenvalues, presumably due to machine arithmetic. This means we can't use TraceMin's built-in MINRES, and we are forced to use Belos for now. When you use multiple Ritz shifts, you are essentially using a different operator to solve each linear system. Belos can't handle this right now, but we're working on a solution. For now, please set \"Use Multiple Shifts\" to false."); 00568 #else 00569 // Test whether we are using a projected preconditioner without Belos. 00570 // P Prec P should be positive definite if Prec is positive-definite, 00571 // but it tends not to be in practice, presumably due to machine arithmetic 00572 // As a result, we have to use pseudo-block gmres for now. 00573 // Make sure it's available. 00574 TEUCHOS_TEST_FOR_EXCEPTION(problem_->getPrec() != Teuchos::null && saddleSolType_ == PROJECTED_KRYLOV_SOLVER, std::invalid_argument, 00575 "Anasazi::TraceMinBaseSolMgr: When you use the projected Krylov solver with preconditioning, the preconditioner must be projected as well. In theory, if the preconditioner is SPD, the projected preconditioner will be SPSD, but in practice, it can have small negative eigenvalues, presumably due to machine arithmetic. This means we can't use TraceMin's built-in MINRES, and we are forced to use Belos for now. You didn't install Belos. You have three options to correct this problem:\n1. Reinstall Trilinos with Belos enabled (Recommended)\n2. Don't use a preconditioner\n3. Choose a different method for solving the saddle-point problem"); 00576 00577 00578 #endif 00579 00580 00581 } 00582 00583 00586 // solve() 00587 template<class ScalarType, class MV, class OP> 00588 ReturnType 00589 TraceMinBaseSolMgr<ScalarType,MV,OP>::solve() 00590 { 00591 typedef SolverUtils<ScalarType,MV,OP> msutils; 00592 00593 const int nev = problem_->getNEV(); 00594 00595 #ifdef TEUCHOS_DEBUG 00596 RCP<Teuchos::FancyOStream> 00597 out = Teuchos::getFancyOStream(Teuchos::rcpFromRef(printer_->stream(Debug))); 00598 out->setShowAllFrontMatter(false).setShowProcRank(true); 00599 *out << "Entering Anasazi::TraceMinBaseSolMgr::solve()\n"; 00600 #endif 00601 00603 // Sort manager 00604 RCP<BasicSort<MagnitudeType> > sorter = rcp( new BasicSort<MagnitudeType>("SM") ); 00605 00607 // Handle the spectral transformation if necessary 00608 // TODO: Make sure we undo this before returning... 00609 if(which_ == "LM") 00610 { 00611 RCP<const OP> swapHelper = problem_->getOperator(); 00612 problem_->setOperator(problem_->getM()); 00613 problem_->setM(swapHelper); 00614 problem_->setProblem(); 00615 } 00616 00618 // Status tests 00619 // 00620 // convergence 00621 RCP<StatusTest<ScalarType,MV,OP> > convtest; 00622 if (globalTest_ == Teuchos::null) { 00623 if(which_ == "SM") 00624 convtest = rcp( new StatusTestResNorm<ScalarType,MV,OP>(convTol_,nev,convNorm_,relConvTol_) ); 00625 else 00626 convtest = rcp( new StatusTestSpecTrans<ScalarType,MV,OP>(convTol_,nev,convNorm_,relConvTol_,true,problem_->getOperator()) ); 00627 } 00628 else { 00629 convtest = globalTest_; 00630 } 00631 RCP<StatusTestWithOrdering<ScalarType,MV,OP> > ordertest 00632 = rcp( new StatusTestWithOrdering<ScalarType,MV,OP>(convtest,sorter,nev) ); 00633 // locking 00634 RCP<StatusTest<ScalarType,MV,OP> > locktest; 00635 if (useLocking_) { 00636 if (lockingTest_ == Teuchos::null) { 00637 if(which_ == "SM") 00638 locktest = rcp( new StatusTestResNorm<ScalarType,MV,OP>(lockTol_,lockQuorum_,lockNorm_,relLockTol_) ); 00639 else 00640 locktest = rcp( new StatusTestSpecTrans<ScalarType,MV,OP>(lockTol_,lockQuorum_,lockNorm_,relLockTol_,true,problem_->getOperator()) ); 00641 } 00642 else { 00643 locktest = lockingTest_; 00644 } 00645 } 00646 // for a non-short-circuited OR test, the order doesn't matter 00647 Teuchos::Array<RCP<StatusTest<ScalarType,MV,OP> > > alltests; 00648 alltests.push_back(ordertest); 00649 if (locktest != Teuchos::null) alltests.push_back(locktest); 00650 if (debugTest_ != Teuchos::null) alltests.push_back(debugTest_); 00651 00652 RCP<StatusTestCombo<ScalarType,MV,OP> > combotest 00653 = rcp( new StatusTestCombo<ScalarType,MV,OP>( StatusTestCombo<ScalarType,MV,OP>::OR, alltests) ); 00654 // printing StatusTest 00655 RCP<StatusTestOutput<ScalarType,MV,OP> > outputtest; 00656 if ( printer_->isVerbosity(Debug) ) { 00657 outputtest = rcp( new StatusTestOutput<ScalarType,MV,OP>( printer_,combotest,1,Passed+Failed+Undefined ) ); 00658 } 00659 else { 00660 outputtest = rcp( new StatusTestOutput<ScalarType,MV,OP>( printer_,combotest,1,Passed ) ); 00661 } 00662 00664 // Orthomanager 00665 RCP<MatOrthoManager<ScalarType,MV,OP> > ortho; 00666 if (ortho_=="SVQB") { 00667 ortho = rcp( new SVQBOrthoManager<ScalarType,MV,OP>(problem_->getM()) ); 00668 } else if (ortho_=="DGKS") { 00669 ortho = rcp( new BasicOrthoManager<ScalarType,MV,OP>(problem_->getM()) ); 00670 } else if (ortho_=="ICGS") { 00671 ortho = rcp( new ICGSOrthoManager<ScalarType,MV,OP>(problem_->getM()) ); 00672 } else { 00673 TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"Anasazi::TraceMinBaseSolMgr::solve(): Invalid orthogonalization type."); 00674 } 00675 00677 // Parameter list 00678 Teuchos::ParameterList plist; 00679 setParameters(plist); 00680 00682 // TraceMinBase solver 00683 RCP<TraceMinBase<ScalarType,MV,OP> > tm_solver 00684 = createSolver(sorter,outputtest,ortho,plist); 00685 // set any auxiliary vectors defined in the problem 00686 RCP< const MV > probauxvecs = problem_->getAuxVecs(); 00687 if (probauxvecs != Teuchos::null) { 00688 tm_solver->setAuxVecs( Teuchos::tuple< RCP<const MV> >(probauxvecs) ); 00689 } 00690 00692 // Storage 00693 // 00694 // lockvecs will contain eigenvectors that have been determined "locked" by the status test 00695 int curNumLocked = 0; 00696 RCP<MV> lockvecs; 00697 // lockvecs is used to hold the locked eigenvectors, as well as for temporary storage when locking. 00698 // when locking, we will lock some number of vectors numnew, where numnew <= maxlocked - curlocked 00699 // we will produce numnew random vectors, which will go into the space with the new basis. 00700 // we will also need numnew storage for the image of these random vectors under A and M; 00701 // columns [curlocked+1,curlocked+numnew] will be used for this storage 00702 if (maxLocked_ > 0) { 00703 lockvecs = MVT::Clone(*problem_->getInitVec(),maxLocked_); 00704 } 00705 std::vector<MagnitudeType> lockvals; 00706 // 00707 // Restarting occurs under two scenarios: when the basis is full and after locking. 00708 // 00709 // For the former, a new basis of size blockSize*numRestartBlocks is generated using the current basis 00710 // and the most significant primitive Ritz vectors (projected eigenvectors). 00711 // [S,L] = eig(KK) 00712 // S = [Sr St] // some for "r"estarting, some are "t"runcated 00713 // newV = V*Sr 00714 // KK_new = newV'*K*newV = Sr'*V'*K*V*Sr = Sr'*KK*Sr 00715 // Therefore, the only multivector operation needed is for the generation of newV. 00716 // 00717 // * If the multiplication is explicit, it requires a workspace of blockSize*numRestartBlocks vectors. 00718 // This space must be specifically allocated for that task, as we don't have any space of that size. 00719 // It (workMV) will be allocated at the beginning of solve() 00720 // * Optionally, the multiplication can be performed implicitly, via a Householder QR factorization of 00721 // Sr. This can be done in situ, using the basis multivector contained in the solver. This requires 00722 // that we cast away the const on the multivector returned from getState(). Workspace for this approach 00723 // is a single vector. the solver's internal storage must be preserved (X,MX,KX,R), requiring us to 00724 // allocate this vector. 00725 // 00726 // For the latter (restarting after locking), the new basis is the same size as existing basis. If numnew 00727 // vectors are locked, they are deflated from the current basis and replaced with randomly generated 00728 // vectors. 00729 // [S,L] = eig(KK) 00730 // S = [Sl Su] // partitioned: "l"ocked and "u"nlocked 00731 // newL = V*Sl = X(locked) 00732 // defV = V*Su 00733 // augV = rand(numnew) // orthogonal to oldL,newL,defV,auxvecs 00734 // newV = [defV augV] 00735 // Kknew = newV'*K*newV = [Su'*KK*Su defV'*K*augV] 00736 // [augV'*K*defV augV'*K*augV] 00737 // locked = [oldL newL] 00738 // Clearly, this operation is more complicated than the previous. 00739 // Here is a list of the significant computations that need to be performed: 00740 // - newL will be put into space in lockvecs, but will be copied from getState().X at the end 00741 // - defV,augV will be stored in workspace the size of the current basis. 00742 // - M*augV and K*augV are needed; they will be stored in lockvecs. As a result, newL will 00743 // not be put into lockvecs until the end. 00744 // 00745 // Therefore, we must allocate workMV when ((maxRestarts_ > 0) || (useLocking_ == true)) && inSituRestart == false 00746 // It will be allocated to size (numBlocks-1)*blockSize 00747 // 00748 00749 // some consts and utils 00750 const ScalarType ONE = SCT::one(); 00751 const ScalarType ZERO = SCT::zero(); 00752 00753 // go ahead and initialize the solution to nothing in case we throw an exception 00754 Eigensolution<ScalarType,MV> sol; 00755 sol.numVecs = 0; 00756 problem_->setSolution(sol); 00757 00758 int numRestarts = 0; 00759 00760 // enter solve() iterations 00761 { 00762 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR 00763 Teuchos::TimeMonitor slvtimer(*_timerSolve); 00764 #endif 00765 00766 // tell tm_solver to iterate 00767 while (1) { 00768 try { 00769 tm_solver->iterate(); 00770 00772 // 00773 // 00775 if (debugTest_ != Teuchos::null && debugTest_->getStatus() == Passed) { 00776 throw AnasaziError("Anasazi::TraceMinBaseSolMgr::solve(): User-specified debug status test returned Passed."); 00777 } 00779 // 00780 // check convergence next 00781 // 00783 else if (ordertest->getStatus() == Passed ) { 00784 // we have convergence 00785 // ordertest->whichVecs() tells us which vectors from lockvecs and solver state are the ones we want 00786 // ordertest->howMany() will tell us how many 00787 break; 00788 } 00790 // 00791 // check locking if we didn't converge or restart 00792 // 00794 else if (locktest != Teuchos::null && locktest->getStatus() == Passed) { 00795 00796 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR 00797 Teuchos::TimeMonitor lcktimer(*_timerLocking); 00798 #endif 00799 00800 // 00801 // get current state 00802 TraceMinBaseState<ScalarType,MV> state = tm_solver->getState(); 00803 const int curdim = state.curDim; 00804 00805 // 00806 // get number,indices of vectors to be locked 00807 TEUCHOS_TEST_FOR_EXCEPTION(locktest->howMany() <= 0,std::logic_error, 00808 "Anasazi::TraceMinBaseSolMgr::solve(): status test mistake: howMany() non-positive."); 00809 TEUCHOS_TEST_FOR_EXCEPTION(locktest->howMany() != (int)locktest->whichVecs().size(),std::logic_error, 00810 "Anasazi::TraceMinBaseSolMgr::solve(): status test mistake: howMany() not consistent with whichVecs()."); 00811 // we should have room to lock vectors; otherwise, locking should have been deactivated 00812 TEUCHOS_TEST_FOR_EXCEPTION(curNumLocked == maxLocked_,std::logic_error, 00813 "Anasazi::TraceMinBaseSolMgr::solve(): status test mistake: locking not deactivated."); 00814 // 00815 // don't lock more than maxLocked_; we didn't allocate enough space. 00816 std::vector<int> tmp_vector_int; 00817 if (curNumLocked + locktest->howMany() > maxLocked_) { 00818 // just use the first of them 00819 tmp_vector_int.insert(tmp_vector_int.begin(),locktest->whichVecs().begin(),locktest->whichVecs().begin()+maxLocked_-curNumLocked); 00820 } 00821 else { 00822 tmp_vector_int = locktest->whichVecs(); 00823 } 00824 00825 const std::vector<int> lockind(tmp_vector_int); 00826 const int numNewLocked = lockind.size(); 00827 // 00828 // generate indices of vectors left unlocked 00829 // curind = [0,...,curdim-1] = UNION( lockind, unlockind ) 00830 const int numUnlocked = curdim-numNewLocked; 00831 tmp_vector_int.resize(curdim); 00832 for (int i=0; i<curdim; i++) tmp_vector_int[i] = i; 00833 const std::vector<int> curind(tmp_vector_int); // curind = [0 ... curdim-1] 00834 tmp_vector_int.resize(numUnlocked); 00835 std::set_difference(curind.begin(),curind.end(),lockind.begin(),lockind.end(),tmp_vector_int.begin()); 00836 const std::vector<int> unlockind(tmp_vector_int); // unlockind = [0 ... curdim-1] - lockind 00837 tmp_vector_int.clear(); 00838 00839 // 00840 // debug printing 00841 if (printer_->isVerbosity(Debug)) { 00842 printer_->print(Debug,"Locking vectors: "); 00843 for (unsigned int i=0; i<lockind.size(); i++) {printer_->stream(Debug) << " " << lockind[i];} 00844 printer_->print(Debug,"\n"); 00845 printer_->print(Debug,"Not locking vectors: "); 00846 for (unsigned int i=0; i<unlockind.size(); i++) {printer_->stream(Debug) << " " << unlockind[i];} 00847 printer_->print(Debug,"\n"); 00848 } 00849 00850 // Copy eigenvalues we want to lock into lockvals 00851 std::vector<Value<ScalarType> > allvals = tm_solver->getRitzValues(); 00852 for (int i=0; i<numNewLocked; i++) { 00853 lockvals.push_back(allvals[lockind[i]].realpart); 00854 } 00855 00856 // Copy vectors we want to lock into lockvecs 00857 RCP<const MV> newLocked = MVT::CloneView(*tm_solver->getRitzVectors(),lockind); 00858 std::vector<int> indlock(numNewLocked); 00859 for (int i=0; i<numNewLocked; i++) indlock[i] = curNumLocked+i; 00860 MVT::SetBlock(*newLocked,indlock,*lockvecs); 00861 00862 // Tell the StatusTestWithOrdering that things have been locked 00863 // This is VERY important 00864 // If this set of lines is removed, the code does not terminate correctly 00865 ordertest->setAuxVals(lockvals); 00866 00867 // Set the auxiliary vectors so that we remain orthogonal to the ones we locked 00868 // Remember to include any aux vecs provided by the user 00869 curNumLocked += numNewLocked; 00870 00871 if(ordertest->getStatus() == Passed) break; 00872 00873 std::vector<int> curlockind(curNumLocked); 00874 for (int i=0; i<curNumLocked; i++) curlockind[i] = i; 00875 RCP<const MV> curlocked = MVT::CloneView(*lockvecs,curlockind); 00876 00877 Teuchos::Array< RCP<const MV> > aux; 00878 if (probauxvecs != Teuchos::null) aux.push_back(probauxvecs); 00879 aux.push_back(curlocked); 00880 tm_solver->setAuxVecs(aux); 00881 00882 // Disable locking if we have locked the maximum number of things 00883 printer_->stream(Debug) << "curNumLocked: " << curNumLocked << std::endl; 00884 printer_->stream(Debug) << "maxLocked: " << maxLocked_ << std::endl; 00885 if (curNumLocked == maxLocked_) { 00886 // disabled locking now 00887 combotest->removeTest(locktest); 00888 locktest = Teuchos::null; 00889 printer_->stream(Debug) << "Removed locking test\n"; 00890 } 00891 00892 int newdim = numRestartBlocks_*blockSize_; 00893 TraceMinBaseState<ScalarType,MV> newstate; 00894 if(newdim <= numUnlocked) 00895 { 00896 std::vector<int> desiredSubscripts(newdim); 00897 for(int i=0; i<newdim; i++) 00898 { 00899 desiredSubscripts[i] = unlockind[i]; 00900 printer_->stream(Debug) << "desiredSubscripts[" << i << "] = " << desiredSubscripts[i] << std::endl; 00901 } 00902 00903 copyPartOfState(state, newstate, desiredSubscripts); 00904 } 00905 else 00906 { 00907 // TODO: Come back to this and make it more efficient 00908 00909 // Replace the converged eigenvectors with random ones 00910 int nrandom = newdim-numUnlocked; 00911 00912 RCP<const MV> helperMV; 00913 RCP<MV> totalV = MVT::Clone(*tm_solver->getRitzVectors(),newdim); 00914 00915 // Holds old things that we're keeping 00916 tmp_vector_int.resize(numUnlocked); 00917 for(int i=0; i<numUnlocked; i++) tmp_vector_int[i] = i; 00918 RCP<MV> oldV = MVT::CloneViewNonConst(*totalV,tmp_vector_int); 00919 00920 // Copy over the old things 00921 helperMV = MVT::CloneView(*state.V,unlockind); 00922 MVT::Assign(*helperMV,*oldV); 00923 00924 // Holds random vectors we're generating 00925 tmp_vector_int.resize(nrandom); 00926 for(int i=0; i<nrandom; i++) tmp_vector_int[i] = i+numUnlocked; 00927 RCP<MV> newV = MVT::CloneViewNonConst(*totalV,tmp_vector_int); 00928 00929 // Create random things 00930 MVT::MvRandom(*newV); 00931 00932 newstate.V = totalV; 00933 newstate.curDim = newdim; 00934 00935 // Copy Ritz shifts 00936 RCP< std::vector<ScalarType> > helperRS = rcp( new std::vector<ScalarType>(blockSize_) ); 00937 for(unsigned int i=0; i<(unsigned int)blockSize_; i++) 00938 { 00939 if(i < unlockind.size() && unlockind[i] < blockSize_) 00940 (*helperRS)[i] = (*state.ritzShifts)[unlockind[i]]; 00941 else 00942 (*helperRS)[i] = ZERO; 00943 } 00944 newstate.ritzShifts = helperRS; 00945 } 00946 00947 // Determine the largest safe shift 00948 newstate.largestSafeShift = std::abs(lockvals[0]); 00949 for(size_t i=0; i<lockvals.size(); i++) 00950 newstate.largestSafeShift = std::max(std::abs(lockvals[i]), newstate.largestSafeShift); 00951 00952 // Prepare new state, removing converged vectors 00953 // TODO: Init will perform some unnecessary calculations; look into it 00954 // TODO: The residual norms should be part of the state 00955 newstate.NEV = state.NEV - numNewLocked; 00956 tm_solver->initialize(newstate); 00957 } // end of locking 00959 // 00960 // check for restarting before locking: if we need to lock, it will happen after the restart 00961 // 00963 else if ( needToRestart(tm_solver) ) { 00964 // if performRestart returns false, we exceeded the maximum number of restarts 00965 if(performRestart(numRestarts, tm_solver) == false) 00966 break; 00967 } // end of restarting 00969 // 00970 // we returned from iterate(), but none of our status tests Passed. 00971 // something is wrong, and it is probably our fault. 00972 // 00974 else { 00975 TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"Anasazi::TraceMinBaseSolMgr::solve(): Invalid return from tm_solver::iterate()."); 00976 } 00977 } 00978 catch (const AnasaziError &err) { 00979 printer_->stream(Errors) 00980 << "Anasazi::TraceMinBaseSolMgr::solve() caught unexpected exception from Anasazi::TraceMinBase::iterate() at iteration " << tm_solver->getNumIters() << std::endl 00981 << err.what() << std::endl 00982 << "Anasazi::TraceMinBaseSolMgr::solve() returning Unconverged with no solutions." << std::endl; 00983 return Unconverged; 00984 } 00985 } 00986 00987 sol.numVecs = ordertest->howMany(); 00988 if (sol.numVecs > 0) { 00989 sol.Evecs = MVT::Clone(*problem_->getInitVec(),sol.numVecs); 00990 sol.Espace = sol.Evecs; 00991 sol.Evals.resize(sol.numVecs); 00992 std::vector<MagnitudeType> vals(sol.numVecs); 00993 00994 // copy them into the solution 00995 std::vector<int> which = ordertest->whichVecs(); 00996 // indices between [0,blockSize) refer to vectors/values in the solver 00997 // indices between [-curNumLocked,-1] refer to locked vectors/values [0,curNumLocked) 00998 // everything has already been ordered by the solver; we just have to partition the two references 00999 std::vector<int> inlocked(0), insolver(0); 01000 for (unsigned int i=0; i<which.size(); i++) { 01001 if (which[i] >= 0) { 01002 TEUCHOS_TEST_FOR_EXCEPTION(which[i] >= blockSize_,std::logic_error,"Anasazi::TraceMinBaseSolMgr::solve(): positive indexing mistake from ordertest."); 01003 insolver.push_back(which[i]); 01004 } 01005 else { 01006 // sanity check 01007 TEUCHOS_TEST_FOR_EXCEPTION(which[i] < -curNumLocked,std::logic_error,"Anasazi::TraceMinBaseSolMgr::solve(): negative indexing mistake from ordertest."); 01008 inlocked.push_back(which[i] + curNumLocked); 01009 } 01010 } 01011 01012 TEUCHOS_TEST_FOR_EXCEPTION(insolver.size() + inlocked.size() != (unsigned int)sol.numVecs,std::logic_error,"Anasazi::TraceMinBaseSolMgr::solve(): indexing mistake."); 01013 01014 // set the vecs,vals in the solution 01015 if (insolver.size() > 0) { 01016 // set vecs 01017 int lclnum = insolver.size(); 01018 std::vector<int> tosol(lclnum); 01019 for (int i=0; i<lclnum; i++) tosol[i] = i; 01020 RCP<const MV> v = MVT::CloneView(*tm_solver->getRitzVectors(),insolver); 01021 MVT::SetBlock(*v,tosol,*sol.Evecs); 01022 // set vals 01023 std::vector<Value<ScalarType> > fromsolver = tm_solver->getRitzValues(); 01024 for (unsigned int i=0; i<insolver.size(); i++) { 01025 vals[i] = fromsolver[insolver[i]].realpart; 01026 } 01027 } 01028 01029 // get the vecs,vals from locked storage 01030 if (inlocked.size() > 0) { 01031 int solnum = insolver.size(); 01032 // set vecs 01033 int lclnum = inlocked.size(); 01034 std::vector<int> tosol(lclnum); 01035 for (int i=0; i<lclnum; i++) tosol[i] = solnum + i; 01036 RCP<const MV> v = MVT::CloneView(*lockvecs,inlocked); 01037 MVT::SetBlock(*v,tosol,*sol.Evecs); 01038 // set vals 01039 for (unsigned int i=0; i<inlocked.size(); i++) { 01040 vals[i+solnum] = lockvals[inlocked[i]]; 01041 } 01042 } 01043 01044 // undo the spectral transformation if necessary 01045 // if we really passed the solver Bx = \lambda A x, invert the eigenvalues 01046 if(which_ == "LM") 01047 { 01048 for(size_t i=0; i<vals.size(); i++) 01049 vals[i] = ONE/vals[i]; 01050 } 01051 01052 // sort the eigenvalues and permute the eigenvectors appropriately 01053 { 01054 std::vector<int> order(sol.numVecs); 01055 sorter->sort(vals,Teuchos::rcpFromRef(order),sol.numVecs); 01056 // store the values in the Eigensolution 01057 for (int i=0; i<sol.numVecs; i++) { 01058 sol.Evals[i].realpart = vals[i]; 01059 sol.Evals[i].imagpart = MT::zero(); 01060 } 01061 // now permute the eigenvectors according to order 01062 msutils::permuteVectors(sol.numVecs,order,*sol.Evecs); 01063 } 01064 01065 // setup sol.index, remembering that all eigenvalues are real so that index = {0,...,0} 01066 sol.index.resize(sol.numVecs,0); 01067 } 01068 } 01069 01070 // print final summary 01071 tm_solver->currentStatus(printer_->stream(FinalSummary)); 01072 01073 printParameters(printer_->stream(FinalSummary)); 01074 01075 // print timing information 01076 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR 01077 if ( printer_->isVerbosity( TimingDetails ) ) { 01078 Teuchos::TimeMonitor::summarize( printer_->stream( TimingDetails ) ); 01079 } 01080 #endif 01081 01082 problem_->setSolution(sol); 01083 printer_->stream(Debug) << "Returning " << sol.numVecs << " eigenpairs to eigenproblem." << std::endl; 01084 01085 // get the number of iterations taken for this call to solve(). 01086 numIters_ = tm_solver->getNumIters(); 01087 01088 if (sol.numVecs < nev) { 01089 return Unconverged; // return from TraceMinBaseSolMgr::solve() 01090 } 01091 return Converged; // return from TraceMinBaseSolMgr::solve() 01092 } 01093 01094 01095 template <class ScalarType, class MV, class OP> 01096 void 01097 TraceMinBaseSolMgr<ScalarType,MV,OP>::setGlobalStatusTest( 01098 const RCP< StatusTest<ScalarType,MV,OP> > &global) 01099 { 01100 globalTest_ = global; 01101 } 01102 01103 template <class ScalarType, class MV, class OP> 01104 const RCP< StatusTest<ScalarType,MV,OP> > & 01105 TraceMinBaseSolMgr<ScalarType,MV,OP>::getGlobalStatusTest() const 01106 { 01107 return globalTest_; 01108 } 01109 01110 template <class ScalarType, class MV, class OP> 01111 void 01112 TraceMinBaseSolMgr<ScalarType,MV,OP>::setDebugStatusTest( 01113 const RCP< StatusTest<ScalarType,MV,OP> > &debug) 01114 { 01115 debugTest_ = debug; 01116 } 01117 01118 template <class ScalarType, class MV, class OP> 01119 const RCP< StatusTest<ScalarType,MV,OP> > & 01120 TraceMinBaseSolMgr<ScalarType,MV,OP>::getDebugStatusTest() const 01121 { 01122 return debugTest_; 01123 } 01124 01125 template <class ScalarType, class MV, class OP> 01126 void 01127 TraceMinBaseSolMgr<ScalarType,MV,OP>::setLockingStatusTest( 01128 const RCP< StatusTest<ScalarType,MV,OP> > &locking) 01129 { 01130 lockingTest_ = locking; 01131 } 01132 01133 template <class ScalarType, class MV, class OP> 01134 const RCP< StatusTest<ScalarType,MV,OP> > & 01135 TraceMinBaseSolMgr<ScalarType,MV,OP>::getLockingStatusTest() const 01136 { 01137 return lockingTest_; 01138 } 01139 01140 template <class ScalarType, class MV, class OP> 01141 void TraceMinBaseSolMgr<ScalarType,MV,OP>::copyPartOfState(const TraceMinBaseState<ScalarType,MV>& oldState, TraceMinBaseState<ScalarType,MV>& newState, const std::vector<int> indToCopy) const 01142 { 01143 const ScalarType ONE = Teuchos::ScalarTraits<MagnitudeType>::one(); 01144 const ScalarType ZERO = Teuchos::ScalarTraits<MagnitudeType>::zero(); 01145 01146 newState.curDim = indToCopy.size(); 01147 std::vector<int> fullIndices(oldState.curDim); 01148 for(int i=0; i<oldState.curDim; i++) fullIndices[i] = i; 01149 01150 // Initialize with X. 01151 // Note that we didn't compute enough vectors of X, but we can very easily using the Ritz vectors. 01152 // That's why they're part of the state. 01153 // Note that there will ALWAYS be enough vectors 01154 01155 // Helpful vectors for computing views and whatnot 01156 std::vector<int> oldIndices; 01157 std::vector<int> newIndices; 01158 for(int i=0; i<newState.curDim; i++) 01159 { 01160 if(indToCopy[i] < blockSize_) 01161 oldIndices.push_back(indToCopy[i]); 01162 else 01163 newIndices.push_back(indToCopy[i]); 01164 } 01165 01166 int olddim = oldIndices.size(); 01167 int newdim = newIndices.size(); 01168 01169 // If there are no new vectors being copied 01170 if(computeAllRes_) 01171 { 01172 newState.V = MVT::CloneView(*oldState.X, indToCopy); 01173 newState.R = MVT::CloneView(*oldState.R, indToCopy); 01174 newState.X = newState.V; 01175 01176 if(problem_->getOperator() != Teuchos::null) 01177 { 01178 newState.KV = MVT::CloneView(*oldState.KX, indToCopy); 01179 newState.KX = newState.KV; 01180 } 01181 else 01182 { 01183 newState.KV = Teuchos::null; 01184 newState.KX = Teuchos::null; 01185 } 01186 01187 if(problem_->getM() != Teuchos::null) 01188 { 01189 newState.MopV = MVT::CloneView(*oldState.MX, indToCopy); 01190 newState.MX = newState.MopV; 01191 } 01192 else 01193 { 01194 newState.MopV = Teuchos::null; 01195 newState.MX = Teuchos::null; 01196 } 01197 } 01198 else if(newdim == 0) 01199 { 01200 std::vector<int> blockind(blockSize_); 01201 for(int i=0; i<blockSize_; i++) 01202 blockind[i] = i; 01203 01204 // Initialize with X 01205 newState.V = MVT::CloneView(*oldState.X, blockind); 01206 newState.KV = MVT::CloneView(*oldState.KX, blockind); 01207 newState.R = MVT::CloneView(*oldState.R, blockind); 01208 newState.X = MVT::CloneView(*newState.V, blockind); 01209 newState.KX = MVT::CloneView(*newState.KV, blockind); 01210 01211 if(problem_->getM() != Teuchos::null) 01212 { 01213 newState.MopV = MVT::CloneView(*oldState.MX, blockind); 01214 newState.MX = MVT::CloneView(*newState.MopV, blockind); 01215 } 01216 else 01217 { 01218 newState.MopV = Teuchos::null; 01219 newState.MX = Teuchos::null; 01220 } 01221 } 01222 else 01223 { 01224 // More helpful vectors 01225 std::vector<int> oldPart(olddim); 01226 for(int i=0; i<olddim; i++) oldPart[i] = i; 01227 std::vector<int> newPart(newdim); 01228 for(int i=0; i<newdim; i++) newPart[i] = olddim+i; 01229 01230 // Helpful multivectors for views and whatnot 01231 RCP<MV> helper = MVT::Clone(*oldState.V,newState.curDim); 01232 RCP<MV> oldHelper = MVT::CloneViewNonConst(*helper,oldPart); 01233 RCP<MV> newHelper = MVT::CloneViewNonConst(*helper,newPart); 01234 RCP<const MV> viewHelper; 01235 01236 // Get the parts of the Ritz vectors we are interested in. 01237 Teuchos::SerialDenseMatrix<int,ScalarType> newRV(oldState.curDim,newdim); 01238 for(int r=0; r<oldState.curDim; r++) 01239 { 01240 for(int c=0; c<newdim; c++) 01241 newRV(r,c) = (*oldState.RV)(r,newIndices[c]); 01242 } 01243 01244 // We're going to compute X as V*RitzVecs 01245 viewHelper = MVT::CloneView(*oldState.V,fullIndices); 01246 MVT::MvTimesMatAddMv(ONE,*viewHelper,newRV,ZERO,*newHelper); 01247 viewHelper = MVT::CloneView(*oldState.X,oldIndices); 01248 MVT::Assign(*viewHelper,*oldHelper); 01249 newState.V = MVT::CloneCopy(*helper); 01250 01251 // Also compute KX as KV*RitzVecs 01252 viewHelper = MVT::CloneView(*oldState.KV,fullIndices); 01253 MVT::MvTimesMatAddMv(ONE,*viewHelper,newRV,ZERO,*newHelper); 01254 viewHelper = MVT::CloneView(*oldState.KX,oldIndices); 01255 MVT::Assign(*viewHelper,*oldHelper); 01256 newState.KV = MVT::CloneCopy(*helper); 01257 01258 // Do the same with MX if necessary 01259 if(problem_->getM() != Teuchos::null) 01260 { 01261 viewHelper = MVT::CloneView(*oldState.MopV,fullIndices); 01262 MVT::MvTimesMatAddMv(ONE,*viewHelper,newRV,ZERO,*newHelper); 01263 viewHelper = MVT::CloneView(*oldState.MX,oldIndices); 01264 MVT::Assign(*viewHelper,*oldHelper); 01265 newState.MopV = MVT::CloneCopy(*helper); 01266 } 01267 else 01268 newState.MopV = newState.V; 01269 01270 // Get X, MX, KX 01271 std::vector<int> blockVec(blockSize_); 01272 for(int i=0; i<blockSize_; i++) blockVec[i] = i; 01273 newState.X = MVT::CloneView(*newState.V,blockVec); 01274 newState.KX = MVT::CloneView(*newState.KV,blockVec); 01275 newState.MX = MVT::CloneView(*newState.MopV,blockVec); 01276 01277 // Update the residuals 01278 if(blockSize_-oldIndices.size() > 0) 01279 { 01280 // There are vectors we have not computed the residual for yet 01281 newPart.resize(blockSize_-oldIndices.size()); 01282 helper = MVT::Clone(*oldState.V,blockSize_); 01283 oldHelper = MVT::CloneViewNonConst(*helper,oldPart); 01284 newHelper = MVT::CloneViewNonConst(*helper,newPart); 01285 01286 RCP<MV> scaledMV = MVT::CloneCopy(*newState.MX,newPart); 01287 RCP<const MV> localKV = MVT::CloneView(*newState.KX,newPart); 01288 std::vector<ScalarType> scalarVec(blockSize_-oldIndices.size()); 01289 for(unsigned int i=0; i<(unsigned int)blockSize_-oldIndices.size(); i++) scalarVec[i] = (*oldState.T)[newPart[i]]; 01290 MVT::MvScale(*scaledMV,scalarVec); 01291 01292 helper = MVT::Clone(*oldState.V,blockSize_); 01293 oldHelper = MVT::CloneViewNonConst(*helper,oldPart); 01294 newHelper = MVT::CloneViewNonConst(*helper,newPart); 01295 MVT::MvAddMv(ONE,*localKV,-ONE,*scaledMV,*newHelper); 01296 viewHelper = MVT::CloneView(*oldState.R,oldIndices); 01297 MVT::Assign(*viewHelper,*oldHelper); 01298 newState.R = MVT::CloneCopy(*helper); 01299 } 01300 else 01301 newState.R = oldState.R; 01302 } 01303 01304 // Since we are setting V:=X, V is orthonormal 01305 newState.isOrtho = true; 01306 01307 // Get the first eigenvalues 01308 RCP< std::vector<ScalarType> > helperT = rcp( new std::vector<ScalarType>(newState.curDim) ); 01309 for(int i=0; i<newState.curDim; i++) (*helperT)[i] = (*oldState.T)[indToCopy[i]]; 01310 newState.T = helperT; 01311 01312 // X'KX is diag(T) 01313 RCP< Teuchos::SerialDenseMatrix<int,ScalarType> > newKK = rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>(newState.curDim,newState.curDim) ); 01314 for(int i=0; i<newState.curDim; i++) 01315 (*newKK)(i,i) = (*newState.T)[i]; 01316 newState.KK = newKK; 01317 01318 // The associated Ritz vectors are I 01319 RCP< Teuchos::SerialDenseMatrix<int,ScalarType> > newRV = rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>(newState.curDim,newState.curDim) ); 01320 for(int i=0; i<newState.curDim; i++) 01321 (*newRV)(i,i) = ONE; 01322 newState.RV = newRV; 01323 01324 // Get the Ritz shifts 01325 RCP< std::vector<ScalarType> > helperRS = rcp( new std::vector<ScalarType>(blockSize_) ); 01326 for(int i=0; i<blockSize_; i++) 01327 { 01328 if(indToCopy[i] < blockSize_) 01329 (*helperRS)[i] = (*oldState.ritzShifts)[indToCopy[i]]; 01330 else 01331 (*helperRS)[i] = ZERO; 01332 } 01333 newState.ritzShifts = helperRS; 01334 } 01335 01336 01337 template <class ScalarType, class MV, class OP> 01338 void TraceMinBaseSolMgr<ScalarType,MV,OP>::setParameters(Teuchos::ParameterList &pl) const 01339 { 01340 pl.set("Block Size", blockSize_); 01341 pl.set("Num Blocks", numBlocks_); 01342 pl.set("Num Restart Blocks", numRestartBlocks_); 01343 pl.set("When To Shift", whenToShift_); 01344 pl.set("Trace Threshold", traceThresh_); 01345 pl.set("Shift Tolerance", shiftTol_); 01346 pl.set("Relative Shift Tolerance", relShiftTol_); 01347 pl.set("Shift Norm", shiftNorm_); 01348 pl.set("How To Choose Shift", howToShift_); 01349 pl.set("Consider Clusters", considerClusters_); 01350 pl.set("Use Multiple Shifts", useMultipleShifts_); 01351 pl.set("Saddle Solver Type", saddleSolType_); 01352 pl.set("Project All Vectors", projectAllVecs_); 01353 pl.set("Project Locked Vectors", projectLockedVecs_); 01354 pl.set("Compute All Residuals", computeAllRes_); 01355 pl.set("Use Residual as RHS", useRHSR_); 01356 pl.set("Maximum Krylov Iterations", maxKrylovIter_); 01357 } 01358 01359 01360 template <class ScalarType, class MV, class OP> 01361 void TraceMinBaseSolMgr<ScalarType,MV,OP>::printParameters(std::ostream &os) const 01362 { 01363 os << "\n\n\n"; 01364 os << "========================================\n"; 01365 os << "========= TraceMin parameters ==========\n"; 01366 os << "========================================\n"; 01367 os << "=========== Block parameters ===========\n"; 01368 os << "Block Size: " << blockSize_ << std::endl; 01369 os << "Num Blocks: " << numBlocks_ << std::endl; 01370 os << "Num Restart Blocks: " << numRestartBlocks_ << std::endl; 01371 os << "======== Convergence parameters ========\n"; 01372 os << "Convergence Tolerance: " << convTol_ << std::endl; 01373 os << "Relative Convergence Tolerance: " << relConvTol_ << std::endl; 01374 os << "========== Locking parameters ==========\n"; 01375 os << "Use Locking: " << useLocking_ << std::endl; 01376 os << "Locking Tolerance: " << lockTol_ << std::endl; 01377 os << "Relative Locking Tolerance: " << relLockTol_ << std::endl; 01378 os << "Max Locked: " << maxLocked_ << std::endl; 01379 os << "Locking Quorum: " << lockQuorum_ << std::endl; 01380 os << "========== Shifting parameters =========\n"; 01381 os << "When To Shift: "; 01382 if(whenToShift_ == NEVER_SHIFT) os << "Never\n"; 01383 else if(whenToShift_ == SHIFT_WHEN_TRACE_LEVELS) os << "After Trace Levels\n"; 01384 else if(whenToShift_ == SHIFT_WHEN_RESID_SMALL) os << "Residual Becomes Small\n"; 01385 else if(whenToShift_ == ALWAYS_SHIFT) os << "Always\n"; 01386 os << "Consider Clusters: " << considerClusters_ << std::endl; 01387 os << "Trace Threshohld: " << traceThresh_ << std::endl; 01388 os << "Shift Tolerance: " << shiftTol_ << std::endl; 01389 os << "Relative Shift Tolerance: " << relShiftTol_ << std::endl; 01390 os << "How To Choose Shift: "; 01391 if(howToShift_ == LARGEST_CONVERGED_SHIFT) os << "Largest Converged\n"; 01392 else if(howToShift_ == ADJUSTED_RITZ_SHIFT) os << "Adjusted Ritz Values\n"; 01393 else if(howToShift_ == RITZ_VALUES_SHIFT) os << "Ritz Values\n"; 01394 os << "Use Multiple Shifts: " << useMultipleShifts_ << std::endl; 01395 os << "=========== Other parameters ===========\n"; 01396 os << "Orthogonalization: " << ortho_ << std::endl; 01397 os << "Saddle Solver Type: "; 01398 if(saddleSolType_ == PROJECTED_KRYLOV_SOLVER) os << "Projected Krylov\n"; 01399 else if(saddleSolType_ == SCHUR_COMPLEMENT_SOLVER) os << "Schur Complement\n"; 01400 os << "Project All Vectors: " << projectAllVecs_ << std::endl; 01401 os << "Project Locked Vectors: " << projectLockedVecs_ << std::endl; 01402 os << "Compute All Residuals: " << computeAllRes_ << std::endl; 01403 os << "========================================\n\n\n"; 01404 } 01405 01406 01407 }} // end Anasazi namespace 01408 01409 #endif /* ANASAZI_TraceMinBase_SOLMGR_HPP */
1.7.6.1