|
Stratimikos Package Browser (Single Doxygen Collection)
Version of the Day
|
00001 // @HEADER 00002 // *********************************************************************** 00003 // 00004 // Stratimikos: Thyra-based strategies for linear solvers 00005 // Copyright (2006) 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 // 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 Roscoe A. Bartlett (rabartl@sandia.gov) 00038 // 00039 // *********************************************************************** 00040 // @HEADER 00041 00042 #include "Thyra_MLPreconditionerFactory.hpp" 00043 00044 #include "Thyra_EpetraOperatorViewExtractorStd.hpp" 00045 #include "Thyra_EpetraLinearOp.hpp" 00046 #include "Thyra_DefaultPreconditioner.hpp" 00047 #include "ml_MultiLevelPreconditioner.h" 00048 #include "ml_MultiLevelOperator.h" 00049 #include "ml_ValidateParameters.h" 00050 #include "Epetra_RowMatrix.h" 00051 #include "Teuchos_StandardParameterEntryValidators.hpp" 00052 #include "Teuchos_dyn_cast.hpp" 00053 #include "Teuchos_TimeMonitor.hpp" 00054 #include "Teuchos_implicit_cast.hpp" 00055 #include "Teuchos_ValidatorXMLConverterDB.hpp" 00056 #include "Teuchos_StaticSetupMacro.hpp" 00057 #include "Teuchos_iostream_helpers.hpp" 00058 00059 00060 namespace { 00061 00062 00063 enum EMLProblemType { 00064 ML_PROBTYPE_NONE, 00065 ML_PROBTYPE_SMOOTHED_AGGREGATION, 00066 ML_PROBTYPE_DOMAIN_DECOMPOSITION, 00067 ML_PROBTYPE_DOMAIN_DECOMPOSITION_ML, 00068 ML_PROBTYPE_MAXWELL 00069 }; 00070 const std::string BaseMethodDefaults_valueNames_none = "none"; 00071 const Teuchos::Array<std::string> BaseMethodDefaults_valueNames 00072 = Teuchos::tuple<std::string>( 00073 BaseMethodDefaults_valueNames_none, 00074 "SA", 00075 "DD", 00076 "DD-ML", 00077 "maxwell" 00078 ); 00079 00080 00081 TEUCHOS_ENUM_INPUT_STREAM_OPERATOR(EMLProblemType) 00082 00083 00084 TEUCHOS_STATIC_SETUP() 00085 { 00086 TEUCHOS_ADD_STRINGTOINTEGRALVALIDATOR_CONVERTER(EMLProblemType); 00087 } 00088 00089 const std::string BaseMethodDefaults_name = "Base Method Defaults"; 00090 const std::string BaseMethodDefaults_default = "SA"; 00091 Teuchos::RCP< 00092 Teuchos::StringToIntegralParameterEntryValidator<EMLProblemType> 00093 > 00094 BaseMethodDefaults_validator; 00095 00096 const std::string ReuseFineLevelSmoother_name = "Reuse Fine Level Smoother"; 00097 const bool ReuseFineLevelSmoother_default = false; 00098 00099 const std::string MLSettings_name = "ML Settings"; 00100 00101 00102 } // namespace 00103 00104 00105 namespace Thyra { 00106 00107 00108 using Teuchos::RCP; 00109 using Teuchos::ParameterList; 00110 00111 00112 // Constructors/initializers/accessors 00113 00114 00115 MLPreconditionerFactory::MLPreconditionerFactory() 00116 :epetraFwdOpViewExtractor_(Teuchos::rcp(new EpetraOperatorViewExtractorStd())) 00117 {} 00118 00119 00120 // Overridden from PreconditionerFactoryBase 00121 00122 00123 bool MLPreconditionerFactory::isCompatible( 00124 const LinearOpSourceBase<double> &fwdOpSrc 00125 ) const 00126 { 00127 using Teuchos::outArg; 00128 Teuchos::RCP<const Epetra_Operator> epetraFwdOp; 00129 EOpTransp epetraFwdOpTransp; 00130 EApplyEpetraOpAs epetraFwdOpApplyAs; 00131 EAdjointEpetraOp epetraFwdOpAdjointSupport; 00132 double epetraFwdOpScalar; 00133 Teuchos::RCP<const LinearOpBase<double> > 00134 fwdOp = fwdOpSrc.getOp(); 00135 epetraFwdOpViewExtractor_->getEpetraOpView( 00136 fwdOp, 00137 outArg(epetraFwdOp),outArg(epetraFwdOpTransp), 00138 outArg(epetraFwdOpApplyAs), 00139 outArg(epetraFwdOpAdjointSupport), 00140 outArg(epetraFwdOpScalar) 00141 ); 00142 if( !dynamic_cast<const Epetra_RowMatrix*>(&*epetraFwdOp) ) 00143 return false; 00144 return true; 00145 } 00146 00147 00148 bool MLPreconditionerFactory::applySupportsConj(EConj conj) const 00149 { 00150 return true; 00151 } 00152 00153 00154 bool MLPreconditionerFactory::applyTransposeSupportsConj(EConj conj) const 00155 { 00156 return false; // See comment below 00157 } 00158 00159 00160 RCP<PreconditionerBase<double> > 00161 MLPreconditionerFactory::createPrec() const 00162 { 00163 return Teuchos::rcp(new DefaultPreconditioner<double>()); 00164 } 00165 00166 00167 void MLPreconditionerFactory::initializePrec( 00168 const Teuchos::RCP<const LinearOpSourceBase<double> > &fwdOpSrc, 00169 PreconditionerBase<double> *prec, 00170 const ESupportSolveUse supportSolveUse 00171 ) const 00172 { 00173 using Teuchos::outArg; 00174 using Teuchos::OSTab; 00175 using Teuchos::dyn_cast; 00176 using Teuchos::RCP; 00177 using Teuchos::null; 00178 using Teuchos::rcp; 00179 using Teuchos::rcp_dynamic_cast; 00180 using Teuchos::rcp_const_cast; 00181 using Teuchos::set_extra_data; 00182 using Teuchos::get_optional_extra_data; 00183 using Teuchos::implicit_cast; 00184 Teuchos::Time totalTimer(""), timer(""); 00185 totalTimer.start(true); 00186 const RCP<Teuchos::FancyOStream> out = this->getOStream(); 00187 const Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel(); 00188 Teuchos::OSTab tab(out); 00189 if(out.get() && implicit_cast<int>(verbLevel) > implicit_cast<int>(Teuchos::VERB_LOW)) 00190 *out << "\nEntering Thyra::MLPreconditionerFactory::initializePrec(...) ...\n"; 00191 00192 Teuchos::RCP<const LinearOpBase<double> > fwdOp = fwdOpSrc->getOp(); 00193 #ifdef _DEBUG 00194 TEUCHOS_TEST_FOR_EXCEPT(fwdOp.get()==NULL); 00195 TEUCHOS_TEST_FOR_EXCEPT(prec==NULL); 00196 #endif 00197 // 00198 // Unwrap and get the forward Epetra_Operator object 00199 // 00200 Teuchos::RCP<const Epetra_Operator> epetraFwdOp; 00201 EOpTransp epetraFwdOpTransp; 00202 EApplyEpetraOpAs epetraFwdOpApplyAs; 00203 EAdjointEpetraOp epetraFwdOpAdjointSupport; 00204 double epetraFwdOpScalar; 00205 epetraFwdOpViewExtractor_->getEpetraOpView( 00206 fwdOp,outArg(epetraFwdOp),outArg(epetraFwdOpTransp),outArg(epetraFwdOpApplyAs), 00207 outArg(epetraFwdOpAdjointSupport),outArg(epetraFwdOpScalar) 00208 ); 00209 // Validate what we get is what we need 00210 RCP<const Epetra_RowMatrix> 00211 epetraFwdRowMat = rcp_dynamic_cast<const Epetra_RowMatrix>(epetraFwdOp,true); 00212 TEUCHOS_TEST_FOR_EXCEPTION( 00213 epetraFwdOpApplyAs != EPETRA_OP_APPLY_APPLY, std::logic_error 00214 ,"Error, incorrect apply mode for an Epetra_RowMatrix" 00215 ); 00216 00217 // 00218 // Get the concrete preconditioner object 00219 // 00220 DefaultPreconditioner<double> 00221 *defaultPrec = &Teuchos::dyn_cast<DefaultPreconditioner<double> >(*prec); 00222 // 00223 // Get the EpetraLinearOp object that is used to implement the preconditoner linear op 00224 // 00225 RCP<EpetraLinearOp> 00226 epetra_precOp = rcp_dynamic_cast<EpetraLinearOp>(defaultPrec->getNonconstUnspecifiedPrecOp(),true); 00227 // 00228 // Get the embedded ML_Epetra::MultiLevelPreconditioner object if it exists 00229 // 00230 Teuchos::RCP<ML_Epetra::MultiLevelPreconditioner> ml_precOp; 00231 if(epetra_precOp.get()) 00232 ml_precOp = rcp_dynamic_cast<ML_Epetra::MultiLevelPreconditioner>(epetra_precOp->epetra_op(),true); 00233 // 00234 // Get the attached forward operator if it exists and make sure that it matches 00235 // 00236 if(ml_precOp!=Teuchos::null) { 00237 // Get the forward operator and make sure that it matches what is 00238 // already being used! 00239 const Epetra_RowMatrix & rm = ml_precOp->RowMatrix(); 00240 00241 TEUCHOS_TEST_FOR_EXCEPTION( 00242 &rm!=&*epetraFwdRowMat, std::logic_error 00243 ,"ML requires Epetra_RowMatrix to be the same for each initialization of the preconditioner" 00244 ); 00245 } 00246 // 00247 // Perform initialization if needed 00248 // 00249 const bool startingOver = (ml_precOp.get() == NULL); 00250 if(startingOver) 00251 { 00252 if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW)) 00253 *out << "\nCreating the initial ML_Epetra::MultiLevelPreconditioner object...\n"; 00254 timer.start(true); 00255 // Create the initial preconditioner: DO NOT compute it yet 00256 ml_precOp = rcp( 00257 new ML_Epetra::MultiLevelPreconditioner( 00258 *epetraFwdRowMat, paramList_->sublist(MLSettings_name),false 00259 ) 00260 ); 00261 00262 timer.stop(); 00263 if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW)) 00264 OSTab(out).o() <<"> Creation time = "<<timer.totalElapsedTime()<<" sec\n"; 00265 // RAB: Above, I am just passing a string to ML::Create(...) in order 00266 // get this code written. However, in the future, it would be good to 00267 // copy the contents of what is in ML::Create(...) into a local 00268 // function and then use switch(...) to create the initial 00269 // ML_Epetra::MultiLevelPreconditioner object. This would result in better validation 00270 // and faster code. 00271 // Set parameters if the list exists 00272 if(paramList_.get()) 00273 TEUCHOS_TEST_FOR_EXCEPT( 00274 0!=ml_precOp->SetParameterList(paramList_->sublist(MLSettings_name)) 00275 ); 00276 // Initialize the structure for the preconditioner 00277 // TEUCHOS_TEST_FOR_EXCEPT(0!=ml_precOp->Initialize()); 00278 } 00279 // 00280 // Attach the epetraFwdOp to the ml_precOp to guarantee that it will not go away 00281 // 00282 set_extra_data(epetraFwdOp, "IFPF::epetraFwdOp", Teuchos::inOutArg(ml_precOp), 00283 Teuchos::POST_DESTROY, false); 00284 // 00285 // Update the factorization 00286 // 00287 if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW)) 00288 *out << "\nComputing the preconditioner ...\n"; 00289 timer.start(true); 00290 if (startingOver) { 00291 TEUCHOS_TEST_FOR_EXCEPT(0!=ml_precOp->ComputePreconditioner()); 00292 } 00293 else { 00294 TEUCHOS_TEST_FOR_EXCEPT(0!=ml_precOp->ReComputePreconditioner(paramList_->get<bool>(ReuseFineLevelSmoother_name))); 00295 } 00296 timer.stop(); 00297 if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW)) 00298 OSTab(out).o() <<"=> Setup time = "<<timer.totalElapsedTime()<<" sec\n"; 00299 // 00300 // Compute the conditioner number estimate if asked 00301 // 00302 00303 // ToDo: Implement 00304 00305 // 00306 // Attach fwdOp to the ml_precOp 00307 // 00308 set_extra_data(fwdOp, "IFPF::fwdOp", Teuchos::inOutArg(ml_precOp), 00309 Teuchos::POST_DESTROY, false); 00310 // 00311 // Initialize the output EpetraLinearOp 00312 // 00313 if(startingOver) { 00314 epetra_precOp = rcp(new EpetraLinearOp); 00315 } 00316 epetra_precOp->initialize( 00317 ml_precOp 00318 ,epetraFwdOpTransp 00319 ,EPETRA_OP_APPLY_APPLY_INVERSE 00320 ,EPETRA_OP_ADJOINT_UNSUPPORTED // ToDo: Look into adjoints again. 00321 ); 00322 // 00323 // Initialize the preconditioner 00324 // 00325 defaultPrec->initializeUnspecified( 00326 Teuchos::rcp_implicit_cast<LinearOpBase<double> >(epetra_precOp) 00327 ); 00328 totalTimer.stop(); 00329 if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW)) 00330 *out << "\nTotal time in MLPreconditionerFactory = "<<totalTimer.totalElapsedTime()<<" sec\n"; 00331 if(out.get() && implicit_cast<int>(verbLevel) > implicit_cast<int>(Teuchos::VERB_LOW)) 00332 *out << "\nLeaving Thyra::MLPreconditionerFactory::initializePrec(...) ...\n"; 00333 } 00334 00335 00336 void MLPreconditionerFactory::uninitializePrec( 00337 PreconditionerBase<double> *prec, 00338 Teuchos::RCP<const LinearOpSourceBase<double> > *fwdOp, 00339 ESupportSolveUse *supportSolveUse 00340 ) const 00341 { 00342 TEUCHOS_TEST_FOR_EXCEPT(true); 00343 } 00344 00345 00346 // Overridden from ParameterListAcceptor 00347 00348 00349 void MLPreconditionerFactory::setParameterList( 00350 Teuchos::RCP<ParameterList> const& paramList 00351 ) 00352 { 00353 TEUCHOS_TEST_FOR_EXCEPT(paramList.get()==NULL); 00354 paramList->validateParameters(*this->getValidParameters(),0); 00355 paramList_ = paramList; 00356 00357 // set default for reuse of fine level smoother 00358 if(!paramList_->isType<bool>(ReuseFineLevelSmoother_name)) 00359 paramList_->set<bool>(ReuseFineLevelSmoother_name,ReuseFineLevelSmoother_default); 00360 00361 const EMLProblemType 00362 defaultType = BaseMethodDefaults_validator->getIntegralValue( 00363 *paramList_,BaseMethodDefaults_name,BaseMethodDefaults_default 00364 ); 00365 if( ML_PROBTYPE_NONE != defaultType ) { 00366 const std::string 00367 defaultTypeStr = BaseMethodDefaults_valueNames[defaultType]; 00368 Teuchos::ParameterList defaultParams; 00369 TEUCHOS_TEST_FOR_EXCEPTION( 00370 0!=ML_Epetra::SetDefaults(defaultTypeStr,defaultParams) 00371 ,Teuchos::Exceptions::InvalidParameterValue 00372 ,"Error, the ML problem type \"" << defaultTypeStr << "\' is not recognized by ML!" 00373 ); 00374 // Note, the only way the above exception message could be generated is if 00375 // a default problem type was removed from ML_Epetra::SetDefaults(...). 00376 // When a new problem type is added to this function, it must be added to 00377 // our enum EMLProblemType along with associated objects ... In other 00378 // words, this adapter must be maintained as ML is maintained. An 00379 // alternative design would be to just pass in whatever string to this 00380 // function. This would improve maintainability but it would not generate 00381 // very good error messages when a bad string was passed in. Currently, 00382 // the error message attached to the exception will contain the list of 00383 // valid problem types. 00384 paramList_->sublist(MLSettings_name).setParametersNotAlreadySet( 00385 defaultParams); 00386 } 00387 #ifdef TEUCHOS_DEBUG 00388 paramList->validateParameters(*this->getValidParameters(),0); 00389 #endif 00390 } 00391 00392 00393 RCP<ParameterList> 00394 MLPreconditionerFactory::getNonconstParameterList() 00395 { 00396 return paramList_; 00397 } 00398 00399 00400 RCP<ParameterList> 00401 MLPreconditionerFactory::unsetParameterList() 00402 { 00403 Teuchos::RCP<ParameterList> _paramList = paramList_; 00404 paramList_ = Teuchos::null; 00405 return _paramList; 00406 } 00407 00408 00409 RCP<const ParameterList> 00410 MLPreconditionerFactory::getParameterList() const 00411 { 00412 return paramList_; 00413 } 00414 00415 00416 RCP<const ParameterList> 00417 MLPreconditionerFactory::getValidParameters() const 00418 { 00419 00420 using Teuchos::rcp; 00421 using Teuchos::tuple; 00422 using Teuchos::implicit_cast; 00423 using Teuchos::rcp_implicit_cast; 00424 typedef Teuchos::ParameterEntryValidator PEV; 00425 00426 static RCP<const ParameterList> validPL; 00427 00428 if(is_null(validPL)) { 00429 00430 RCP<ParameterList> 00431 pl = rcp(new ParameterList()); 00432 00433 BaseMethodDefaults_validator = rcp( 00434 new Teuchos::StringToIntegralParameterEntryValidator<EMLProblemType>( 00435 BaseMethodDefaults_valueNames, 00436 tuple<std::string>( 00437 "Do not set any default parameters", 00438 "Set default parameters for a smoothed aggregation method", 00439 "Set default parameters for a domain decomposition method", 00440 "Set default parameters for a domain decomposition method special to ML", 00441 "Set default parameters for a Maxwell-type of linear operator" 00442 ), 00443 tuple<EMLProblemType>( 00444 ML_PROBTYPE_NONE, 00445 ML_PROBTYPE_SMOOTHED_AGGREGATION, 00446 ML_PROBTYPE_DOMAIN_DECOMPOSITION, 00447 ML_PROBTYPE_DOMAIN_DECOMPOSITION_ML, 00448 ML_PROBTYPE_MAXWELL 00449 ), 00450 BaseMethodDefaults_name 00451 ) 00452 ); 00453 00454 pl->set(BaseMethodDefaults_name,BaseMethodDefaults_default, 00455 "Select the default method type which also sets parameter defaults\n" 00456 "in the sublist \"" + MLSettings_name + "\"!", 00457 rcp_implicit_cast<const PEV>(BaseMethodDefaults_validator) 00458 ); 00459 00460 pl->set(ReuseFineLevelSmoother_name,ReuseFineLevelSmoother_default, 00461 "Enables/disables the reuse of the fine level smoother."); 00462 00463 /* 2007/07/02: rabartl: The statement below should be the correct way to 00464 * get the list of valid parameters but it seems to be causing problems so 00465 * I am commenting it out for now. 00466 */ 00467 /* 00468 pl->sublist( 00469 MLSettings_name, false, 00470 "Parameters directly accepted by ML_Epetra interface." 00471 ).setParameters(*rcp(ML_Epetra::GetValidMLPParameters())); 00472 */ 00473 00474 { 00475 ParameterList &mlSettingsPL = pl->sublist( 00476 MLSettings_name, false, 00477 "Sampling of the parameters directly accepted by ML\n" 00478 "This list of parameters is generated by combining all of\n" 00479 "the parameters set for all of the default problem types supported\n" 00480 "by ML. Therefore, do not assume these parameters are at values that\n" 00481 "are reasonable to ML. This list is just to give a sense of some of\n" 00482 "the parameters that ML accepts. Consult ML documentation on how to\n" 00483 "set these parameters. Also, you can print the parameter list after\n" 00484 "it is used and see what defaults where set for each default problem\n" 00485 "type. Warning! the parameters in this sublist are currently *not*\n" 00486 "being validated by ML!" 00487 ); 00488 //std::cout << "\nMLSettings doc before = " << pl->getEntryPtr(MLSettings_name)->docString() << "\n"; 00489 { // Set of valid parameters (but perhaps not acceptable values) 00490 for ( 00491 int i = 0; 00492 i < implicit_cast<int>(BaseMethodDefaults_valueNames.size()); 00493 ++i 00494 ) 00495 { 00496 ParameterList defaultParams; 00497 const std::string defaultTypeStr = BaseMethodDefaults_valueNames[i]; 00498 if (defaultTypeStr != BaseMethodDefaults_valueNames_none) { 00499 TEUCHOS_TEST_FOR_EXCEPTION( 00500 0!=ML_Epetra::SetDefaults(defaultTypeStr,defaultParams) 00501 ,Teuchos::Exceptions::InvalidParameterValue 00502 ,"Error, the ML problem type \"" << defaultTypeStr 00503 << "\' is not recognized by ML!" 00504 ); 00505 mlSettingsPL.setParameters(defaultParams); 00506 } 00507 } 00508 } 00509 } 00510 00511 validPL = pl; 00512 00513 } 00514 00515 return validPL; 00516 00517 } 00518 00519 00520 // Public functions overridden from Teuchos::Describable 00521 00522 00523 std::string MLPreconditionerFactory::description() const 00524 { 00525 std::ostringstream oss; 00526 oss << "Thyra::MLPreconditionerFactory"; 00527 return oss.str(); 00528 } 00529 00530 00531 } // namespace Thyra
1.7.6.1