|
Belos
Version of the Day
|
00001 //@HEADER 00002 // ************************************************************************ 00003 // 00004 // Belos: Block Linear Solvers Package 00005 // Copyright 2004 Sandia Corporation 00006 // 00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, 00008 // the U.S. Government retains certain rights in this software. 00009 // 00010 // Redistribution and use in source and binary forms, with or without 00011 // modification, are permitted provided that the following conditions are 00012 // met: 00013 // 00014 // 1. Redistributions of source code must retain the above copyright 00015 // notice, this list of conditions and the following disclaimer. 00016 // 00017 // 2. Redistributions in binary form must reproduce the above copyright 00018 // notice, this list of conditions and the following disclaimer in the 00019 // documentation and/or other materials provided with the distribution. 00020 // 00021 // 3. Neither the name of the Corporation nor the names of the 00022 // contributors may be used to endorse or promote products derived from 00023 // this software without specific prior written permission. 00024 // 00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00036 // 00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 00038 // 00039 // ************************************************************************ 00040 //@HEADER 00041 00045 #ifndef __Belos_SimpleOrthoManager_hpp 00046 #define __Belos_SimpleOrthoManager_hpp 00047 00048 #include <BelosConfigDefs.hpp> 00049 #include <BelosMultiVecTraits.hpp> 00050 #include <BelosOrthoManager.hpp> 00051 #include <BelosOutputManager.hpp> 00052 #include <Teuchos_ParameterList.hpp> 00053 #include <Teuchos_ParameterListAcceptorDefaultBase.hpp> 00054 #include <Teuchos_StandardCatchMacros.hpp> 00055 #include <Teuchos_TimeMonitor.hpp> 00056 00057 namespace Belos { 00058 00067 template<class Scalar, class MV> 00068 class SimpleOrthoManager : 00069 public OrthoManager<Scalar, MV>, 00070 public Teuchos::ParameterListAcceptorDefaultBase 00071 { 00072 public: 00073 typedef Scalar scalar_type; 00074 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType magnitude_type; 00075 typedef Teuchos::SerialDenseMatrix<int, Scalar> mat_type; 00076 typedef Teuchos::RCP<Teuchos::SerialDenseMatrix<int, Scalar> > mat_ptr; 00077 00078 private: 00079 typedef MultiVecTraits<Scalar, MV> MVT; 00080 typedef Teuchos::ScalarTraits<Scalar> STS; 00081 typedef Teuchos::ScalarTraits<magnitude_type> STM; 00082 00084 std::string label_; 00086 Teuchos::RCP<OutputManager<Scalar> > outMan_; 00088 bool reorthogonalize_; 00090 bool useMgs_; 00092 mutable Teuchos::RCP<Teuchos::ParameterList> defaultParams_; 00093 00094 #ifdef BELOS_TEUCHOS_TIME_MONITOR 00095 00096 Teuchos::RCP<Teuchos::Time> timerOrtho_; 00098 Teuchos::RCP<Teuchos::Time> timerProject_; 00100 Teuchos::RCP<Teuchos::Time> timerNormalize_; 00101 00110 static Teuchos::RCP<Teuchos::Time> 00111 makeTimer (const std::string& prefix, 00112 const std::string& timerName) 00113 { 00114 const std::string timerLabel = 00115 prefix.empty() ? timerName : (prefix + ": " + timerName); 00116 return Teuchos::TimeMonitor::getNewCounter (timerLabel); 00117 } 00118 #endif // BELOS_TEUCHOS_TIME_MONITOR 00119 00120 public: 00121 00128 Teuchos::RCP<const Teuchos::ParameterList> 00129 getValidParameters () const 00130 { 00131 using Teuchos::ParameterList; 00132 using Teuchos::parameterList; 00133 using Teuchos::RCP; 00134 00135 const std::string defaultNormalizationMethod ("MGS"); 00136 const bool defaultReorthogonalization = false; 00137 00138 if (defaultParams_.is_null()) { 00139 RCP<ParameterList> params = parameterList ("Simple"); 00140 params->set ("Normalization", defaultNormalizationMethod, 00141 "Which normalization method to use. Valid values are \"MGS\"" 00142 " (for Modified Gram-Schmidt) and \"CGS\" (for Classical " 00143 "Gram-Schmidt)."); 00144 params->set ("Reorthogonalization", defaultReorthogonalization, 00145 "Whether to perform one (unconditional) reorthogonalization " 00146 "pass."); 00147 defaultParams_ = params; 00148 } 00149 return defaultParams_; 00150 } 00151 00161 static TEUCHOS_DEPRECATED Teuchos::RCP<const Teuchos::ParameterList> 00162 getDefaultParameters () 00163 { 00164 using Teuchos::ParameterList; 00165 using Teuchos::parameterList; 00166 using Teuchos::RCP; 00167 00168 const std::string defaultNormalizationMethod ("MGS"); 00169 const bool defaultReorthogonalization = false; 00170 00171 RCP<ParameterList> params = parameterList ("Simple"); 00172 params->set ("Normalization", defaultNormalizationMethod, 00173 "Which normalization method to use. Valid values are \"MGS\"" 00174 " (for Modified Gram-Schmidt) and \"CGS\" (for Classical " 00175 "Gram-Schmidt)."); 00176 params->set ("Reorthogonalization", defaultReorthogonalization, 00177 "Whether to perform one (unconditional) reorthogonalization " 00178 "pass."); 00179 return params; 00180 } 00181 00187 Teuchos::RCP<const Teuchos::ParameterList> 00188 getFastParameters () 00189 { 00190 using Teuchos::ParameterList; 00191 using Teuchos::parameterList; 00192 using Teuchos::RCP; 00193 using Teuchos::rcp; 00194 00195 const std::string fastNormalizationMethod ("CGS"); 00196 const bool fastReorthogonalization = false; 00197 00198 // Start with a clone of the default parameters. 00199 RCP<ParameterList> fastParams = parameterList (*getValidParameters()); 00200 fastParams->set ("Normalization", fastNormalizationMethod); 00201 fastParams->set ("Reorthogonalization", fastReorthogonalization); 00202 00203 return fastParams; 00204 } 00205 00206 void 00207 setParameterList (const Teuchos::RCP<Teuchos::ParameterList>& plist) 00208 { 00209 using Teuchos::ParameterList; 00210 using Teuchos::parameterList; 00211 using Teuchos::RCP; 00212 using Teuchos::Exceptions::InvalidParameter; 00213 00214 RCP<const ParameterList> defaultParams = getValidParameters(); 00215 RCP<ParameterList> params; 00216 if (plist.is_null ()) { 00217 params = parameterList (*defaultParams); 00218 } else { 00219 params = plist; 00220 params->validateParametersAndSetDefaults (*defaultParams); 00221 } 00222 const std::string normalizeImpl = params->get<std::string>("Normalization"); 00223 const bool reorthogonalize = params->get<bool>("Reorthogonalization"); 00224 00225 if (normalizeImpl == "MGS" || 00226 normalizeImpl == "Mgs" || 00227 normalizeImpl == "mgs") { 00228 useMgs_ = true; 00229 params->set ("Normalization", std::string ("MGS")); // Standardize. 00230 } else { 00231 useMgs_ = false; 00232 params->set ("Normalization", std::string ("CGS")); // Standardize. 00233 } 00234 reorthogonalize_ = reorthogonalize; 00235 00236 setMyParamList (params); 00237 } 00238 00249 SimpleOrthoManager (const Teuchos::RCP<OutputManager<Scalar> >& outMan, 00250 const std::string& label, 00251 const Teuchos::RCP<Teuchos::ParameterList>& params) : 00252 label_ (label), 00253 outMan_ (outMan) 00254 { 00255 #ifdef BELOS_TEUCHOS_TIME_MONITOR 00256 timerOrtho_ = makeTimer (label, "All orthogonalization"); 00257 timerProject_ = makeTimer (label, "Projection"); 00258 timerNormalize_ = makeTimer (label, "Normalization"); 00259 #endif // BELOS_TEUCHOS_TIME_MONITOR 00260 00261 setParameterList (params); 00262 if (! outMan_.is_null ()) { 00263 using std::endl; 00264 std::ostream& dbg = outMan_->stream(Debug); 00265 dbg << "Belos::SimpleOrthoManager constructor:" << endl 00266 << "-- Normalization method: " 00267 << (useMgs_ ? "MGS" : "CGS") << endl 00268 << "-- Reorthogonalize (unconditionally)? " 00269 << (reorthogonalize_ ? "Yes" : "No") << endl; 00270 } 00271 } 00272 00276 SimpleOrthoManager (const std::string& label) : 00277 label_ (label) 00278 { 00279 #ifdef BELOS_TEUCHOS_TIME_MONITOR 00280 timerOrtho_ = makeTimer (label, "All orthogonalization"); 00281 timerProject_ = makeTimer (label, "Projection"); 00282 timerNormalize_ = makeTimer (label, "Normalization"); 00283 #endif // BELOS_TEUCHOS_TIME_MONITOR 00284 00285 setParameterList (Teuchos::null); 00286 } 00287 00289 virtual ~SimpleOrthoManager() {} 00290 00291 void innerProd (const MV &X, const MV &Y, mat_type& Z) const { 00292 MVT::MvTransMv (STS::one (), X, Y, Z); 00293 } 00294 00295 void norm (const MV& X, std::vector<magnitude_type>& normVec) const { 00296 const int numCols = MVT::GetNumberVecs (X); 00297 // std::vector<T>::size_type is unsigned; int is signed. Mixed 00298 // unsigned/signed comparisons trigger compiler warnings. 00299 if (normVec.size () < static_cast<size_t> (numCols)) { 00300 normVec.resize (numCols); // Resize normvec if necessary. 00301 } 00302 MVT::MvNorm (X, normVec); 00303 } 00304 00305 void 00306 project (MV &X, 00307 Teuchos::Array<mat_ptr> C, 00308 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q) const 00309 { 00310 #ifdef BELOS_TEUCHOS_TIME_MONITOR 00311 Teuchos::TimeMonitor timerMonitorOrtho(*timerOrtho_); 00312 Teuchos::TimeMonitor timerMonitorProject(*timerProject_); 00313 #endif // BELOS_TEUCHOS_TIME_MONITOR 00314 00315 allocateProjectionCoefficients (C, Q, X, true); 00316 rawProject (X, Q, C); 00317 if (reorthogonalize_) { // Unconditional reorthogonalization 00318 Teuchos::Array<Teuchos::RCP<Teuchos::SerialDenseMatrix<int,Scalar> > > C2; 00319 allocateProjectionCoefficients (C2, Q, X, false); 00320 for (int k = 0; k < Q.size(); ++k) 00321 *C[k] += *C2[k]; 00322 } 00323 } 00324 00325 int 00326 normalize (MV &X, mat_ptr B) const 00327 { 00328 #ifdef BELOS_TEUCHOS_TIME_MONITOR 00329 Teuchos::TimeMonitor timerMonitorOrtho(*timerOrtho_); 00330 Teuchos::TimeMonitor timerMonitorProject(*timerNormalize_); 00331 #endif // BELOS_TEUCHOS_TIME_MONITOR 00332 00333 if (useMgs_) { 00334 return normalizeMgs (X, B); 00335 } else { 00336 return normalizeCgs (X, B); 00337 } 00338 } 00339 00340 protected: 00341 virtual int 00342 projectAndNormalizeImpl (MV &X, 00343 Teuchos::Array<mat_ptr> C, 00344 mat_ptr B, 00345 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q) const 00346 { 00347 // Don't need time monitors here: project() and normalize() have 00348 // their own. 00349 this->project (X, C, Q); 00350 return this->normalize (X, B); 00351 } 00352 00353 public: 00354 00355 magnitude_type 00356 orthonormError(const MV &X) const 00357 { 00358 const Scalar ONE = STS::one(); 00359 const int ncols = MVT::GetNumberVecs(X); 00360 mat_type XTX (ncols, ncols); 00361 innerProd (X, X, XTX); 00362 for (int k = 0; k < ncols; ++k) { 00363 XTX(k,k) -= ONE; 00364 } 00365 return XTX.normFrobenius(); 00366 } 00367 00368 magnitude_type 00369 orthogError(const MV &X1, const MV &X2) const 00370 { 00371 const int ncols_X1 = MVT::GetNumberVecs (X1); 00372 const int ncols_X2 = MVT::GetNumberVecs (X2); 00373 mat_type X1_T_X2 (ncols_X1, ncols_X2); 00374 innerProd (X1, X2, X1_T_X2); 00375 return X1_T_X2.normFrobenius(); 00376 } 00377 00378 void setLabel (const std::string& label) { label_ = label; } 00379 const std::string& getLabel() const { return label_; } 00380 00381 private: 00382 00383 int 00384 normalizeMgs (MV &X, 00385 Teuchos::RCP<Teuchos::SerialDenseMatrix<int,Scalar> > B) const 00386 { 00387 using Teuchos::Range1D; 00388 using Teuchos::RCP; 00389 using Teuchos::rcp; 00390 using Teuchos::View; 00391 00392 const int numCols = MVT::GetNumberVecs (X); 00393 if (numCols == 0) { 00394 return 0; 00395 } 00396 00397 if (B.is_null ()) { 00398 B = rcp (new mat_type (numCols, numCols)); 00399 } else if (B->numRows () != numCols || B->numCols () != numCols) { 00400 B->shape (numCols, numCols); 00401 } 00402 00403 // Modified Gram-Schmidt orthogonalization 00404 std::vector<magnitude_type> normVec (1); 00405 for (int j = 0; j < numCols; ++j) { 00406 RCP<MV> X_cur = MVT::CloneViewNonConst (X, Range1D(j, j)); 00407 MV& X_j = *X_cur; 00408 for (int i = 0; i < j; ++i) { 00409 RCP<const MV> X_prv = MVT::CloneView (X, Range1D(i, i)); 00410 const MV& X_i = *X_prv; 00411 mat_type B_ij (View, *B, 1, 1, i, j); 00412 innerProd (X_i, X_j, B_ij); 00413 MVT::MvTimesMatAddMv (-STS::one(), X_i, B_ij, STS::one(), X_j); 00414 if (reorthogonalize_) { // Unconditional reorthogonalization 00415 // innerProd() overwrites B(i,j), so save the 00416 // first-pass projection coefficient and update 00417 // B(i,j) afterwards. 00418 const Scalar B_ij_first = (*B)(i, j); 00419 innerProd (X_i, X_j, B_ij); 00420 MVT::MvTimesMatAddMv (-STS::one(), X_i, B_ij, STS::one(), X_j); 00421 (*B)(i, j) += B_ij_first; 00422 } 00423 } 00424 // Normalize column j of X 00425 norm (X_j, normVec); 00426 const magnitude_type theNorm = normVec[0]; 00427 (*B)(j, j) = theNorm; 00428 if (normVec[0] != STM::zero()) { 00429 MVT::MvScale (X_j, STS::one() / theNorm); 00430 } else { 00431 return j; // break out early 00432 } 00433 } 00434 return numCols; // full rank, as far as we know 00435 } 00436 00437 00438 int 00439 normalizeCgs (MV &X, mat_ptr B) const 00440 { 00441 using Teuchos::Range1D; 00442 using Teuchos::RCP; 00443 using Teuchos::rcp; 00444 using Teuchos::View; 00445 00446 const int numCols = MVT::GetNumberVecs (X); 00447 if (numCols == 0) { 00448 return 0; 00449 } 00450 00451 if (B.is_null ()) { 00452 B = rcp (new mat_type (numCols, numCols)); 00453 } else if (B->numRows() != numCols || B->numCols() != numCols) { 00454 B->shape (numCols, numCols); 00455 } 00456 mat_type& B_ref = *B; 00457 00458 // Classical Gram-Schmidt orthogonalization 00459 std::vector<magnitude_type> normVec (1); 00460 00461 // Space for reorthogonalization 00462 mat_type B2 (numCols, numCols); 00463 00464 // Do the first column first. 00465 { 00466 RCP<MV> X_cur = MVT::CloneViewNonConst (X, Range1D(0, 0)); 00467 // Normalize column 0 of X 00468 norm (*X_cur, normVec); 00469 const magnitude_type theNorm = normVec[0]; 00470 B_ref(0,0) = theNorm; 00471 if (theNorm != STM::zero ()) { 00472 const Scalar invNorm = STS::one () / theNorm; 00473 MVT::MvScale (*X_cur, invNorm); 00474 } 00475 else { 00476 return 0; // break out early 00477 } 00478 } 00479 00480 // Orthogonalize the remaining columns of X 00481 for (int j = 1; j < numCols; ++j) { 00482 RCP<MV> X_cur = MVT::CloneViewNonConst (X, Range1D(j, j)); 00483 RCP<const MV> X_prv = MVT::CloneView (X, Range1D(0, j-1)); 00484 mat_type B_prvcur (View, B_ref, j, 1, 0, j); 00485 00486 // Project X_cur against X_prv (first pass) 00487 innerProd (*X_prv, *X_cur, B_prvcur); 00488 MVT::MvTimesMatAddMv (-STS::one(), *X_prv, B_prvcur, STS::one(), *X_cur); 00489 // Unconditional reorthogonalization: 00490 // project X_cur against X_prv (second pass) 00491 if (reorthogonalize_) { 00492 mat_type B2_prvcur (View, B2, j, 1, 0, j); 00493 innerProd (*X_prv, *X_cur, B2_prvcur); 00494 MVT::MvTimesMatAddMv (-STS::one(), *X_prv, B2_prvcur, STS::one(), *X_cur); 00495 B_prvcur += B2_prvcur; 00496 } 00497 // Normalize column j of X 00498 norm (*X_cur, normVec); 00499 const magnitude_type theNorm = normVec[0]; 00500 B_ref(j,j) = theNorm; 00501 if (theNorm != STM::zero ()) { 00502 const Scalar invNorm = STS::one () / theNorm; 00503 MVT::MvScale (*X_cur, invNorm); 00504 } 00505 else { 00506 return j; // break out early 00507 } 00508 } 00509 return numCols; // full rank, as far as we know 00510 } 00511 00512 00513 void 00514 allocateProjectionCoefficients (Teuchos::Array<mat_ptr>& C, 00515 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q, 00516 const MV& X, 00517 const bool attemptToRecycle = true) const 00518 { 00519 using Teuchos::rcp; 00520 00521 const int num_Q_blocks = Q.size(); 00522 const int ncols_X = MVT::GetNumberVecs (X); 00523 C.resize (num_Q_blocks); 00524 // # of block(s) that had to be (re)allocated (either allocated 00525 // freshly, or resized). 00526 int numAllocated = 0; 00527 if (attemptToRecycle) { 00528 for (int i = 0; i < num_Q_blocks; ++i) { 00529 const int ncols_Qi = MVT::GetNumberVecs (*Q[i]); 00530 // Create a new C[i] if necessary, otherwise resize if 00531 // necessary, otherwise fill with zeros. 00532 if (C[i].is_null ()) { 00533 C[i] = rcp (new mat_type (ncols_Qi, ncols_X)); 00534 numAllocated++; 00535 } 00536 else { 00537 mat_type& Ci = *C[i]; 00538 if (Ci.numRows() != ncols_Qi || Ci.numCols() != ncols_X) { 00539 Ci.shape (ncols_Qi, ncols_X); 00540 numAllocated++; 00541 } 00542 else { 00543 Ci.putScalar (STS::zero()); 00544 } 00545 } 00546 } 00547 } 00548 else { // Just allocate; don't try to check if we can recycle 00549 for (int i = 0; i < num_Q_blocks; ++i) { 00550 const int ncols_Qi = MVT::GetNumberVecs (*Q[i]); 00551 C[i] = rcp (new mat_type (ncols_Qi, ncols_X)); 00552 numAllocated++; 00553 } 00554 } 00555 if (! outMan_.is_null()) { 00556 using std::endl; 00557 std::ostream& dbg = outMan_->stream(Debug); 00558 dbg << "SimpleOrthoManager::allocateProjectionCoefficients: " 00559 << "Allocated " << numAllocated << " blocks out of " 00560 << num_Q_blocks << endl; 00561 } 00562 } 00563 00564 void 00565 rawProject (MV& X, 00566 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q, 00567 Teuchos::ArrayView<mat_ptr> C) const 00568 { 00569 // "Modified Gram-Schmidt" version of Block Gram-Schmidt. 00570 const int num_Q_blocks = Q.size(); 00571 for (int i = 0; i < num_Q_blocks; ++i) { 00572 mat_type& Ci = *C[i]; 00573 const MV& Qi = *Q[i]; 00574 innerProd (Qi, X, Ci); 00575 MVT::MvTimesMatAddMv (-STS::one(), Qi, Ci, STS::one(), X); 00576 } 00577 } 00578 00579 }; 00580 } // namespace Belos 00581 00582 #endif // __Belos_SimpleOrthoManager_hpp
1.7.6.1