Teko Version of the Day
Teko_SIMPLEPreconditionerFactory.cpp
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
 All Classes Files Functions Variables