|
Teko Version of the Day
|
00001 /* 00002 // @HEADER 00003 // 00004 // *********************************************************************** 00005 // 00006 // Teko: A package for block and physics based preconditioning 00007 // Copyright 2010 Sandia Corporation 00008 // 00009 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, 00010 // the U.S. Government retains certain rights in this software. 00011 // 00012 // Redistribution and use in source and binary forms, with or without 00013 // modification, are permitted provided that the following conditions are 00014 // met: 00015 // 00016 // 1. Redistributions of source code must retain the above copyright 00017 // notice, this list of conditions and the following disclaimer. 00018 // 00019 // 2. Redistributions in binary form must reproduce the above copyright 00020 // notice, this list of conditions and the following disclaimer in the 00021 // documentation and/or other materials provided with the distribution. 00022 // 00023 // 3. Neither the name of the Corporation nor the names of the 00024 // contributors may be used to endorse or promote products derived from 00025 // this software without specific prior written permission. 00026 // 00027 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 00028 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00029 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00030 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 00031 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00032 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00033 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00034 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00035 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00036 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00037 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00038 // 00039 // Questions? Contact Eric C. Cyr (eccyr@sandia.gov) 00040 // 00041 // *********************************************************************** 00042 // 00043 // @HEADER 00044 00045 */ 00046 00047 #include "Teko_SIMPLEPreconditionerFactory.hpp" 00048 00049 #include "Teko_Utilities.hpp" 00050 #include "Teko_InverseFactory.hpp" 00051 #include "Teko_BlockLowerTriInverseOp.hpp" 00052 #include "Teko_BlockUpperTriInverseOp.hpp" 00053 #include "Teko_DiagonalPreconditionerFactory.hpp" 00054 00055 #include "Teuchos_Time.hpp" 00056 #include "Epetra_FECrsGraph.h" 00057 #include "EpetraExt_PointToBlockDiagPermute.h" 00058 #include "Thyra_EpetraOperatorWrapper.hpp" 00059 #include "Thyra_EpetraLinearOp.hpp" 00060 00061 00062 using Teuchos::RCP; 00063 00064 namespace Teko { 00065 namespace NS { 00066 00067 // Constructor definition 00068 SIMPLEPreconditionerFactory 00069 ::SIMPLEPreconditionerFactory(const RCP<InverseFactory> & inverse, 00070 double alpha) 00071 : invVelFactory_(inverse), invPrsFactory_(inverse), alpha_(alpha), fInverseType_(Diagonal), useMass_(false) 00072 { } 00073 00074 SIMPLEPreconditionerFactory 00075 ::SIMPLEPreconditionerFactory(const RCP<InverseFactory> & invVFact, 00076 const RCP<InverseFactory> & invPFact, 00077 double alpha) 00078 : invVelFactory_(invVFact), invPrsFactory_(invPFact), alpha_(alpha), fInverseType_(Diagonal), useMass_(false) 00079 { } 00080 00081 SIMPLEPreconditionerFactory::SIMPLEPreconditionerFactory() 00082 : alpha_(1.0), fInverseType_(Diagonal), useMass_(false) 00083 { } 00084 00085 // Use the factory to build the preconditioner (this is where the work goes) 00086 LinearOp SIMPLEPreconditionerFactory 00087 ::buildPreconditionerOperator(BlockedLinearOp & blockOp, 00088 BlockPreconditionerState & state) const 00089 { 00090 Teko_DEBUG_SCOPE("SIMPLEPreconditionerFactory::buildPreconditionerOperator",10); 00091 Teko_DEBUG_EXPR(Teuchos::Time timer("")); 00092 00093 int rows = blockRowCount(blockOp); 00094 int cols = blockColCount(blockOp); 00095 00096 TEUCHOS_ASSERT(rows==2); // sanity checks 00097 TEUCHOS_ASSERT(cols==2); 00098 00099 bool buildExplicitSchurComplement = true; 00100 00101 // extract subblocks 00102 const LinearOp F = getBlock(0,0,blockOp); 00103 const LinearOp Bt = getBlock(0,1,blockOp); 00104 const LinearOp B = getBlock(1,0,blockOp); 00105 const LinearOp C = getBlock(1,1,blockOp); 00106 00107 LinearOp matF = F; 00108 if(useMass_) { 00109 TEUCHOS_ASSERT(massMatrix_!=Teuchos::null); 00110 matF = massMatrix_; 00111 } 00112 00113 // get approximation of inv(F) name H 00114 std::string fApproxStr = "<error>"; 00115 LinearOp H; 00116 if(fInverseType_==NotDiag) { 00117 H = buildInverse(*customHFactory_,matF); 00118 fApproxStr = customHFactory_->toString(); 00119 00120 // since H is now implicit, we must build an implicit Schur complement 00121 buildExplicitSchurComplement = false; 00122 } 00123 else if(fInverseType_==BlkDiag) { 00124 // Block diagonal approximation for H 00125 DiagonalPreconditionerFactory Hfact; 00126 DiagonalPrecondState Hstate; 00127 Hfact.initializeFromParameterList(BlkDiagList_); 00128 LinearOp Hop=Hfact.buildPreconditionerOperator(matF,Hstate); 00129 00130 // A hacky way to get a CrsMatrix out of the BDP. 00131 // NTS: Should eventually add this functionality to the BDP proper. 00132 00133 // Build CrsGraph 00134 int ContiguousBlockSize=BlkDiagList_.get("contiguous block size",0); 00135 int Nlb=BlkDiagList_.get("number of local blocks",0); 00136 int *block_starts=BlkDiagList_.get("block start index",(int*)0); 00137 int *block_gids=BlkDiagList_.get("block entry gids",(int*)0); 00138 // NTS: Does not support PurelyLocalMode 00139 TEUCHOS_ASSERT(ContiguousBlockSize || block_gids); 00140 00141 Epetra_FECrsGraph *G=new Epetra_FECrsGraph(Copy,Hstate.BDP_->OperatorRangeMap(),0); 00142 // Manually create the block list for the contiguous case 00143 if(ContiguousBlockSize){ 00144 // Using contiguous blocks 00145 // NTS: In case of processor-crossing blocks, the lowest PID always gets the block; 00146 const Epetra_Map &RowMap=Hstate.BDP_->OperatorDomainMap(); 00147 00148 int MinMyGID=RowMap.MinMyGID(); 00149 int MaxMyGID=RowMap.MaxMyGID(); 00150 int Base=RowMap.IndexBase(); 00151 00152 // Find the GID that begins my first block 00153 int MyFirstBlockGID=ContiguousBlockSize*(int)ceil(((double)(MinMyGID - Base))/ContiguousBlockSize)+Base; 00154 Nlb=(int)ceil((double)((MaxMyGID-MyFirstBlockGID+1.0)) / ContiguousBlockSize); 00155 00156 // Insert the blocks into the graph 00157 std::vector<int> blist;blist.resize(ContiguousBlockSize); 00158 for(int i=0,ct=0;i<Nlb;i++){ 00159 for(int j=0;j<ContiguousBlockSize;j++,ct++) 00160 blist[j]=MyFirstBlockGID+ct; 00161 G->InsertGlobalIndices(ContiguousBlockSize,&blist[0],ContiguousBlockSize,&blist[0]); 00162 } 00163 } 00164 else{ 00165 // Using custom block lists 00166 for(int i=0;i<Nlb;i++){ 00167 int blksize=block_starts[i+1]-block_starts[i]; 00168 G->InsertGlobalIndices(blksize,&block_gids[block_starts[i]],blksize,&block_gids[block_starts[i]]); 00169 } 00170 } 00171 G->GlobalAssemble(); 00172 G->FillComplete(); 00173 RCP<const Epetra_CrsGraph> Gg=rcp(G); 00174 00175 // Probe H 00176 H=probe(Gg,Hop); 00177 00178 buildExplicitSchurComplement = true;//NTS: Do I need this? 00179 } 00180 else { 00181 // get generic diagonal 00182 H = getInvDiagonalOp(matF,fInverseType_); 00183 fApproxStr = getDiagonalName(fInverseType_); 00184 } 00185 00186 // adjust H for time scaling if it is a mass matrix 00187 if(useMass_) { 00188 RCP<const Teuchos::ParameterList> pl = state.getParameterList(); 00189 00190 if(pl->isParameter("stepsize")) { 00191 // get the step size 00192 double stepsize = pl->get<double>("stepsize"); 00193 00194 // scale by stepsize only if it is larger than 0 00195 if(stepsize>0.0) 00196 H = scale(stepsize,H); 00197 } 00198 } 00199 00200 // build approximate Schur complement: hatS = -C + B*H*Bt 00201 LinearOp HBt, hatS; 00202 00203 if(buildExplicitSchurComplement) { 00204 ModifiableLinearOp & mHBt = state.getModifiableOp("HBt"); 00205 ModifiableLinearOp & mhatS = state.getModifiableOp("hatS"); 00206 ModifiableLinearOp & BHBt = state.getModifiableOp("BHBt"); 00207 00208 // build H*Bt 00209 mHBt = explicitMultiply(H,Bt,mHBt); 00210 HBt = mHBt; 00211 00212 // build B*H*Bt 00213 BHBt = explicitMultiply(B,HBt,BHBt); 00214 00215 // build C-B*H*Bt 00216 mhatS = explicitAdd(C,scale(-1.0,BHBt),mhatS); 00217 hatS = mhatS; 00218 } 00219 else { 00220 // build an implicit Schur complement 00221 HBt = multiply(H,Bt); 00222 00223 hatS = add(C,scale(-1.0,multiply(B,HBt))); 00224 } 00225 00226 // build the inverse for F 00227 ModifiableLinearOp & invF = state.getModifiableOp("invF"); 00228 if(invF==Teuchos::null) 00229 invF = buildInverse(*invVelFactory_,F); 00230 else 00231 rebuildInverse(*invVelFactory_,F,invF); 00232 00233 // build the approximate Schur complement: This is inefficient! FIXME 00234 ModifiableLinearOp & invS = state.getModifiableOp("invS"); 00235 if(invS==Teuchos::null) 00236 invS = buildInverse(*invPrsFactory_,hatS); 00237 else 00238 rebuildInverse(*invPrsFactory_,hatS,invS); 00239 00240 std::vector<LinearOp> invDiag(2); // vector storing inverses 00241 00242 // build lower triangular inverse matrix 00243 BlockedLinearOp L = zeroBlockedOp(blockOp); 00244 setBlock(1,0,L,B); 00245 endBlockFill(L); 00246 00247 invDiag[0] = invF; 00248 invDiag[1] = invS; 00249 LinearOp invL = createBlockLowerTriInverseOp(L,invDiag); 00250 00251 // build upper triangular matrix 00252 BlockedLinearOp U = zeroBlockedOp(blockOp); 00253 setBlock(0,1,U,scale(1.0/alpha_,HBt)); 00254 endBlockFill(U); 00255 00256 invDiag[0] = identity(rangeSpace(invF)); 00257 invDiag[1] = scale(alpha_,identity(rangeSpace(invS))); 00258 LinearOp invU = createBlockUpperTriInverseOp(U,invDiag); 00259 00260 // return implicit product operator 00261 return multiply(invU,invL,"SIMPLE_"+fApproxStr); 00262 } 00263 00265 void SIMPLEPreconditionerFactory::initializeFromParameterList(const Teuchos::ParameterList & pl) 00266 { 00267 RCP<const InverseLibrary> invLib = getInverseLibrary(); 00268 00269 // default conditions 00270 useMass_ = false; 00271 customHFactory_ = Teuchos::null; 00272 fInverseType_ = Diagonal; 00273 00274 // get string specifying inverse 00275 std::string invStr="", invVStr="", invPStr=""; 00276 alpha_ = 1.0; 00277 00278 // "parse" the parameter list 00279 if(pl.isParameter("Inverse Type")) 00280 invStr = pl.get<std::string>("Inverse Type"); 00281 if(pl.isParameter("Inverse Velocity Type")) 00282 invVStr = pl.get<std::string>("Inverse Velocity Type"); 00283 if(pl.isParameter("Inverse Pressure Type")) 00284 invPStr = pl.get<std::string>("Inverse Pressure Type"); 00285 if(pl.isParameter("Alpha")) 00286 alpha_ = pl.get<double>("Alpha"); 00287 if(pl.isParameter("Explicit Velocity Inverse Type")) { 00288 std::string fInverseStr = pl.get<std::string>("Explicit Velocity Inverse Type"); 00289 00290 // build inverse types 00291 fInverseType_ = getDiagonalType(fInverseStr); 00292 if(fInverseType_==NotDiag) 00293 customHFactory_ = invLib->getInverseFactory(fInverseStr); 00294 00295 // Grab the sublist if we're using the block diagonal 00296 if(fInverseType_==BlkDiag) 00297 BlkDiagList_=pl.sublist("H options"); 00298 } 00299 if(pl.isParameter("Use Mass Scaling")) 00300 useMass_ = pl.get<bool>("Use Mass Scaling"); 00301 00302 Teko_DEBUG_MSG_BEGIN(5) 00303 DEBUG_STREAM << "SIMPLE Parameters: " << std::endl; 00304 DEBUG_STREAM << " inv type = \"" << invStr << "\"" << std::endl; 00305 DEBUG_STREAM << " inv v type = \"" << invVStr << "\"" << std::endl; 00306 DEBUG_STREAM << " inv p type = \"" << invPStr << "\"" << std::endl; 00307 DEBUG_STREAM << " alpha = " << alpha_ << std::endl; 00308 DEBUG_STREAM << " use mass = " << useMass_ << std::endl; 00309 DEBUG_STREAM << " vel scaling = " << getDiagonalName(fInverseType_) << std::endl; 00310 DEBUG_STREAM << "SIMPLE Parameter list: " << std::endl; 00311 pl.print(DEBUG_STREAM); 00312 Teko_DEBUG_MSG_END() 00313 00314 // set defaults as needed 00315 if(invStr=="") invStr = "Amesos"; 00316 if(invVStr=="") invVStr = invStr; 00317 if(invPStr=="") invPStr = invStr; 00318 00319 // two inverse factory objects 00320 RCP<InverseFactory> invVFact, invPFact; 00321 00322 // build velocity inverse factory 00323 invVFact = invLib->getInverseFactory(invVStr); 00324 invPFact = invVFact; // by default these are the same 00325 if(invVStr!=invPStr) // if different, build pressure inverse factory 00326 invPFact = invLib->getInverseFactory(invPStr); 00327 00328 // based on parameter type build a strategy 00329 invVelFactory_ = invVFact; 00330 invPrsFactory_ = invPFact; 00331 00332 if(useMass_) { 00333 Teuchos::RCP<Teko::RequestHandler> rh = getRequestHandler(); 00334 rh->preRequest<Teko::LinearOp>(Teko::RequestMesg("Velocity Mass Matrix")); 00335 Teko::LinearOp mass 00336 = rh->request<Teko::LinearOp>(Teko::RequestMesg("Velocity Mass Matrix")); 00337 setMassMatrix(mass); 00338 } 00339 } 00340 00342 Teuchos::RCP<Teuchos::ParameterList> SIMPLEPreconditionerFactory::getRequestedParameters() const 00343 { 00344 Teuchos::RCP<Teuchos::ParameterList> result; 00345 Teuchos::RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList()); 00346 00347 // grab parameters from F solver 00348 RCP<Teuchos::ParameterList> vList = invVelFactory_->getRequestedParameters(); 00349 if(vList!=Teuchos::null) { 00350 Teuchos::ParameterList::ConstIterator itr; 00351 for(itr=vList->begin();itr!=vList->end();++itr) 00352 pl->setEntry(itr->first,itr->second); 00353 result = pl; 00354 } 00355 00356 // grab parameters from S solver 00357 RCP<Teuchos::ParameterList> pList = invPrsFactory_->getRequestedParameters(); 00358 if(pList!=Teuchos::null) { 00359 Teuchos::ParameterList::ConstIterator itr; 00360 for(itr=pList->begin();itr!=pList->end();++itr) 00361 pl->setEntry(itr->first,itr->second); 00362 result = pl; 00363 } 00364 00365 // grab parameters from S solver 00366 if(customHFactory_!=Teuchos::null) { 00367 RCP<Teuchos::ParameterList> hList = customHFactory_->getRequestedParameters(); 00368 if(hList!=Teuchos::null) { 00369 Teuchos::ParameterList::ConstIterator itr; 00370 for(itr=hList->begin();itr!=hList->end();++itr) 00371 pl->setEntry(itr->first,itr->second); 00372 result = pl; 00373 } 00374 } 00375 00376 return result; 00377 } 00378 00380 bool SIMPLEPreconditionerFactory::updateRequestedParameters(const Teuchos::ParameterList & pl) 00381 { 00382 Teko_DEBUG_SCOPE("InvLSCStrategy::updateRequestedParameters",10); 00383 bool result = true; 00384 00385 // update requested parameters in solvers 00386 result &= invVelFactory_->updateRequestedParameters(pl); 00387 result &= invPrsFactory_->updateRequestedParameters(pl); 00388 if(customHFactory_!=Teuchos::null) 00389 result &= customHFactory_->updateRequestedParameters(pl); 00390 00391 return result; 00392 } 00393 00394 } // end namespace NS 00395 } // end namespace Teko
1.7.4