Teko Version of the Day
Teko_Utilities.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_Config.h"
00048 #include "Teko_Utilities.hpp"
00049 
00050 // Thyra includes
00051 #include "Thyra_MultiVectorStdOps.hpp"
00052 #include "Thyra_ZeroLinearOpBase.hpp"
00053 #include "Thyra_DefaultDiagonalLinearOp.hpp"
00054 #include "Thyra_DefaultAddedLinearOp.hpp"
00055 #include "Thyra_EpetraExtDiagScaledMatProdTransformer.hpp"
00056 #include "Thyra_EpetraExtDiagScalingTransformer.hpp"
00057 #include "Thyra_EpetraExtAddTransformer.hpp"
00058 #include "Thyra_DefaultScaledAdjointLinearOp.hpp"
00059 #include "Thyra_DefaultMultipliedLinearOp.hpp"
00060 #include "Thyra_DefaultZeroLinearOp.hpp"
00061 #include "Thyra_DefaultProductMultiVector.hpp"
00062 #include "Thyra_DefaultProductVectorSpace.hpp"
00063 #include "Thyra_MultiVectorStdOps.hpp"
00064 #include "Thyra_VectorStdOps.hpp"
00065 #include "Thyra_get_Epetra_Operator.hpp"
00066 #include "Thyra_EpetraThyraWrappers.hpp"
00067 #include "Thyra_EpetraOperatorWrapper.hpp"
00068 #include "Thyra_EpetraLinearOp.hpp"
00069 
00070 // Teuchos includes
00071 #include "Teuchos_Array.hpp"
00072 
00073 // Epetra includes
00074 #include "Epetra_Operator.h"
00075 #include "Epetra_CrsGraph.h"
00076 #include "Epetra_Vector.h"
00077 #include "Epetra_Map.h"
00078 
00079 // Anasazi includes
00080 #include "AnasaziBasicEigenproblem.hpp"
00081 #include "AnasaziThyraAdapter.hpp"
00082 #include "AnasaziBlockKrylovSchurSolMgr.hpp"
00083 #include "AnasaziBlockKrylovSchur.hpp"
00084 #include "AnasaziStatusTestMaxIters.hpp"
00085 
00086 // Isorropia includes
00087 #ifdef Teko_ENABLE_Isorropia
00088 #include "Isorropia_EpetraProber.hpp"
00089 #endif
00090 
00091 // Teko includes
00092 #include "Epetra/Teko_EpetraHelpers.hpp"
00093 #include "Epetra/Teko_EpetraOperatorWrapper.hpp"
00094 
00095 #include <cmath>
00096 
00097 namespace Teko {
00098 
00099 using Teuchos::rcp;
00100 using Teuchos::rcp_dynamic_cast;
00101 using Teuchos::RCP;
00102 #ifdef Teko_ENABLE_Isorropia
00103 using Isorropia::Epetra::Prober;
00104 #endif
00105 
00106 const Teuchos::RCP<Teuchos::FancyOStream> getOutputStream()
00107 { 
00108    Teuchos::RCP<Teuchos::FancyOStream> os = 
00109          Teuchos::VerboseObjectBase::getDefaultOStream(); 
00110   
00111    //os->setShowProcRank(true);
00112    //os->setOutputToRootOnly(-1);
00113    return os;
00114 }
00115 
00116 // distance function...not parallel...entirely internal to this cpp file
00117 inline double dist(int dim,double * coords,int row,int col)
00118 {
00119    double value = 0.0;
00120    for(int i=0;i<dim;i++)
00121       value += std::pow(coords[dim*row+i]-coords[dim*col+i],2.0);
00122 
00123    // the distance between the two
00124    return std::sqrt(value);
00125 }
00126 
00127 // distance function...not parallel...entirely internal to this cpp file
00128 inline double dist(double * x,double * y,double * z,int stride,int row,int col)
00129 {
00130    double value = 0.0;
00131    if(x!=0) value += std::pow(x[stride*row]-x[stride*col],2.0);
00132    if(y!=0) value += std::pow(y[stride*row]-y[stride*col],2.0);
00133    if(z!=0) value += std::pow(z[stride*row]-z[stride*col],2.0);
00134 
00135    // the distance between the two
00136    return std::sqrt(value);
00137 }
00138 
00157 RCP<Epetra_CrsMatrix> buildGraphLaplacian(int dim,double * coords,const Epetra_CrsMatrix & stencil)
00158 {
00159    // allocate a new matrix with storage for the laplacian...in case of diagonals add one extra storage
00160    RCP<Epetra_CrsMatrix> gl = rcp(new Epetra_CrsMatrix(Copy,stencil.RowMap(),stencil.ColMap(),
00161                                                        stencil.MaxNumEntries()+1),true);
00162 
00163    // allocate an additional value for the diagonal, if neccessary
00164    std::vector<double> rowData(stencil.GlobalMaxNumEntries()+1);
00165    std::vector<int> rowInd(stencil.GlobalMaxNumEntries()+1);
00166 
00167    // loop over all the rows
00168    for(int j=0;j<gl->NumMyRows();j++) {
00169       int row = gl->GRID(j);
00170       double diagValue = 0.0;
00171       int diagInd = -1;
00172       int rowSz = 0;
00173 
00174       // extract a copy of this row...put it in rowData, rowIndicies
00175       stencil.ExtractGlobalRowCopy(row,stencil.MaxNumEntries(),rowSz,&rowData[0],&rowInd[0]);
00176  
00177       // loop over elements of row
00178       for(int i=0;i<rowSz;i++) {
00179          int col = rowInd[i];
00180 
00181          // is this a 0 entry masquerading as some thing else?
00182          double value = rowData[i];
00183          if(value==0) continue;
00184 
00185          // for nondiagonal entries
00186          if(row!=col) {
00187             double d = dist(dim,coords,row,col);
00188             rowData[i] = -1.0/d;
00189             diagValue += rowData[i];
00190          }
00191          else 
00192             diagInd = i;
00193       }
00194     
00195       // handle diagonal entry
00196       if(diagInd<0) { // diagonal not in row
00197          rowData[rowSz] = -diagValue;
00198          rowInd[rowSz] = row;
00199          rowSz++;
00200       }
00201       else { // diagonal in row
00202          rowData[diagInd] = -diagValue;
00203          rowInd[diagInd] = row;
00204       }
00205 
00206       // insert row data into graph Laplacian matrix
00207       TEST_FOR_EXCEPT(gl->InsertGlobalValues(row,rowSz,&rowData[0],&rowInd[0]));
00208    }
00209 
00210    gl->FillComplete();
00211 
00212    return gl;
00213 }
00214 
00237 RCP<Epetra_CrsMatrix> buildGraphLaplacian(double * x,double * y,double * z,int stride,const Epetra_CrsMatrix & stencil)
00238 {
00239    // allocate a new matrix with storage for the laplacian...in case of diagonals add one extra storage
00240    RCP<Epetra_CrsMatrix> gl = rcp(new Epetra_CrsMatrix(Copy,stencil.RowMap(),stencil.ColMap(),
00241                                                        stencil.MaxNumEntries()+1),true);
00242 
00243    // allocate an additional value for the diagonal, if neccessary
00244    std::vector<double> rowData(stencil.GlobalMaxNumEntries()+1);
00245    std::vector<int> rowInd(stencil.GlobalMaxNumEntries()+1);
00246 
00247    // loop over all the rows
00248    for(int j=0;j<gl->NumMyRows();j++) {
00249       int row = gl->GRID(j);
00250       double diagValue = 0.0;
00251       int diagInd = -1;
00252       int rowSz = 0;
00253 
00254       // extract a copy of this row...put it in rowData, rowIndicies
00255       stencil.ExtractGlobalRowCopy(row,stencil.MaxNumEntries(),rowSz,&rowData[0],&rowInd[0]);
00256  
00257       // loop over elements of row
00258       for(int i=0;i<rowSz;i++) {
00259          int col = rowInd[i];
00260 
00261          // is this a 0 entry masquerading as some thing else?
00262          double value = rowData[i];
00263          if(value==0) continue;
00264 
00265          // for nondiagonal entries
00266          if(row!=col) {
00267             double d = dist(x,y,z,stride,row,col);
00268             rowData[i] = -1.0/d;
00269             diagValue += rowData[i];
00270          }
00271          else 
00272             diagInd = i;
00273       }
00274     
00275       // handle diagonal entry
00276       if(diagInd<0) { // diagonal not in row
00277          rowData[rowSz] = -diagValue;
00278          rowInd[rowSz] = row;
00279          rowSz++;
00280       }
00281       else { // diagonal in row
00282          rowData[diagInd] = -diagValue;
00283          rowInd[diagInd] = row;
00284       }
00285 
00286       // insert row data into graph Laplacian matrix
00287       TEST_FOR_EXCEPT(gl->InsertGlobalValues(row,rowSz,&rowData[0],&rowInd[0]));
00288    }
00289 
00290    gl->FillComplete();
00291 
00292    return gl;
00293 }
00294 
00310 void applyOp(const LinearOp & A,const MultiVector & x,MultiVector & y,double alpha,double beta)
00311 {
00312    // Thyra::apply(*A,Thyra::NONCONJ_ELE,*x,&*y,alpha,beta);
00313    Thyra::apply(*A,Thyra::NOTRANS,*x,y.ptr(),alpha,beta);
00314 }
00315 
00318 void update(double alpha,const MultiVector & x,double beta,MultiVector & y)
00319 {
00320    Teuchos::Array<double> scale;
00321    Teuchos::Array<Teuchos::Ptr<const Thyra::MultiVectorBase<double> > >  vec;
00322 
00323    // build arrays needed for linear combo
00324    scale.push_back(alpha);
00325    vec.push_back(x.ptr());
00326 
00327    // compute linear combination
00328    Thyra::linear_combination<double>(scale,vec,beta,y.ptr());
00329 }
00330 
00332 BlockedLinearOp getUpperTriBlocks(const BlockedLinearOp & blo,bool callEndBlockFill)
00333 {
00334    int rows = blockRowCount(blo);
00335 
00336    TEUCHOS_ASSERT(rows==blockColCount(blo));
00337 
00338    RCP<const Thyra::ProductVectorSpaceBase<double> > range = blo->productRange();
00339    RCP<const Thyra::ProductVectorSpaceBase<double> > domain = blo->productDomain();
00340 
00341    // allocate new operator
00342    BlockedLinearOp upper = createBlockedOp();
00343  
00344    // build new operator 
00345    upper->beginBlockFill(rows,rows);
00346 
00347    for(int i=0;i<rows;i++) {
00348       // put zero operators on the diagonal
00349       // this gurantees the vector space of
00350       // the new operator are fully defined
00351       RCP<const Thyra::LinearOpBase<double> > zed 
00352             = Thyra::zero<double>(range->getBlock(i),domain->getBlock(i));
00353       upper->setBlock(i,i,zed);
00354 
00355       for(int j=i+1;j<rows;j++) {
00356          // get block i,j
00357          LinearOp uij = blo->getBlock(i,j);
00358 
00359          // stuff it in U
00360          if(uij!=Teuchos::null)
00361             upper->setBlock(i,j,uij);
00362       }
00363    }
00364    if(callEndBlockFill)
00365       upper->endBlockFill();
00366 
00367    return upper;
00368 }
00369 
00371 BlockedLinearOp getLowerTriBlocks(const BlockedLinearOp & blo,bool callEndBlockFill)
00372 {
00373    int rows = blockRowCount(blo);
00374 
00375    TEUCHOS_ASSERT(rows==blockColCount(blo));
00376 
00377    RCP<const Thyra::ProductVectorSpaceBase<double> > range = blo->productRange();
00378    RCP<const Thyra::ProductVectorSpaceBase<double> > domain = blo->productDomain();
00379 
00380    // allocate new operator
00381    BlockedLinearOp lower = createBlockedOp();
00382  
00383    // build new operator 
00384    lower->beginBlockFill(rows,rows);
00385 
00386    for(int i=0;i<rows;i++) {
00387       // put zero operators on the diagonal
00388       // this gurantees the vector space of
00389       // the new operator are fully defined
00390       RCP<const Thyra::LinearOpBase<double> > zed 
00391             = Thyra::zero<double>(range->getBlock(i),domain->getBlock(i));
00392       lower->setBlock(i,i,zed);
00393 
00394       for(int j=0;j<i;j++) {
00395          // get block i,j
00396          LinearOp uij = blo->getBlock(i,j);
00397 
00398          // stuff it in U
00399          if(uij!=Teuchos::null)
00400             lower->setBlock(i,j,uij);
00401       }
00402    }
00403    if(callEndBlockFill)
00404       lower->endBlockFill();
00405 
00406    return lower;
00407 }
00408 
00428 BlockedLinearOp zeroBlockedOp(const BlockedLinearOp & blo)
00429 {
00430    int rows = blockRowCount(blo);
00431 
00432    TEUCHOS_ASSERT(rows==blockColCount(blo)); // assert that matrix is square
00433 
00434    RCP<const Thyra::ProductVectorSpaceBase<double> > range = blo->productRange();
00435    RCP<const Thyra::ProductVectorSpaceBase<double> > domain = blo->productDomain();
00436 
00437    // allocate new operator
00438    BlockedLinearOp zeroOp = createBlockedOp();
00439  
00440    // build new operator 
00441    zeroOp->beginBlockFill(rows,rows);
00442 
00443    for(int i=0;i<rows;i++) {
00444       // put zero operators on the diagonal
00445       // this gurantees the vector space of
00446       // the new operator are fully defined
00447       RCP<const Thyra::LinearOpBase<double> > zed 
00448             = Thyra::zero<double>(range->getBlock(i),domain->getBlock(i));
00449       zeroOp->setBlock(i,i,zed);
00450    }
00451 
00452    return zeroOp;
00453 }
00454 
00456 bool isZeroOp(const LinearOp op)
00457 {
00458    // if operator is null...then its zero!
00459    if(op==Teuchos::null) return true;
00460 
00461    // try to cast it to a zero linear operator
00462    const LinearOp test = rcp_dynamic_cast<const Thyra::ZeroLinearOpBase<double> >(op);
00463 
00464    // if it works...then its zero...otherwise its null
00465    return test!=Teuchos::null;
00466 }
00467 
00476 ModifiableLinearOp getAbsRowSumMatrix(const LinearOp & op)
00477 {
00478    RCP<const Epetra_CrsMatrix> eCrsOp;
00479 
00480    try {
00481       // get Epetra_Operator
00482       RCP<const Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*op);
00483 
00484       // cast it to a CrsMatrix
00485       eCrsOp = rcp_dynamic_cast<const Epetra_CrsMatrix>(eOp,true);
00486    }
00487    catch (std::exception & e) {
00488       RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
00489 
00490       *out << "Teko: getAbsRowSumMatrix requires an Epetra_CrsMatrix\n";
00491       *out << "    Could not extract an Epetra_Operator from a \"" << op->description() << std::endl;
00492       *out << "           OR\n";
00493       *out << "    Could not cast an Epetra_Operator to a Epetra_CrsMatrix\n";
00494       *out << std::endl;
00495       *out << "*** THROWN EXCEPTION ***\n";
00496       *out << e.what() << std::endl;
00497       *out << "************************\n";
00498       
00499       throw e;
00500    }
00501 
00502    // extract diagonal
00503    const RCP<Epetra_Vector> ptrDiag = rcp(new Epetra_Vector(eCrsOp->RowMap()));
00504    Epetra_Vector & diag = *ptrDiag;
00505    
00506    // compute absolute value row sum
00507    diag.PutScalar(0.0);
00508    for(int i=0;i<eCrsOp->NumMyRows();i++) {
00509       double * values = 0;
00510       int numEntries;
00511       eCrsOp->ExtractMyRowView(i,numEntries,values);
00512 
00513       // build abs value row sum
00514       for(int j=0;j<numEntries;j++)
00515          diag[i] += std::abs(values[j]);
00516    }
00517 
00518    // build Thyra diagonal operator
00519    return Teko::Epetra::thyraDiagOp(ptrDiag,eCrsOp->RowMap(),"absRowSum( " + op->getObjectLabel() + " )");
00520 }
00521 
00530 ModifiableLinearOp getAbsRowSumInvMatrix(const LinearOp & op)
00531 {
00532    RCP<const Epetra_CrsMatrix> eCrsOp;
00533 
00534    try {
00535       // get Epetra_Operator
00536       RCP<const Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*op);
00537 
00538       // cast it to a CrsMatrix
00539       eCrsOp = rcp_dynamic_cast<const Epetra_CrsMatrix>(eOp,true);
00540    }
00541    catch (std::exception & e) {
00542       RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
00543 
00544       *out << "Teko: getAbsRowSumMatrix requires an Epetra_CrsMatrix\n";
00545       *out << "    Could not extract an Epetra_Operator from a \"" << op->description() << std::endl;
00546       *out << "           OR\n";
00547       *out << "    Could not cast an Epetra_Operator to a Epetra_CrsMatrix\n";
00548       *out << std::endl;
00549       *out << "*** THROWN EXCEPTION ***\n";
00550       *out << e.what() << std::endl;
00551       *out << "************************\n";
00552       
00553       throw e;
00554    }
00555 
00556    // extract diagonal
00557    const RCP<Epetra_Vector> ptrDiag = rcp(new Epetra_Vector(eCrsOp->RowMap()));
00558    Epetra_Vector & diag = *ptrDiag;
00559    
00560    // compute absolute value row sum
00561    diag.PutScalar(0.0);
00562    for(int i=0;i<eCrsOp->NumMyRows();i++) {
00563       double * values = 0;
00564       int numEntries;
00565       eCrsOp->ExtractMyRowView(i,numEntries,values);
00566 
00567       // build abs value row sum
00568       for(int j=0;j<numEntries;j++)
00569          diag[i] += std::abs(values[j]);
00570    }
00571    diag.Reciprocal(diag); // invert entries
00572 
00573    // build Thyra diagonal operator
00574    return Teko::Epetra::thyraDiagOp(ptrDiag,eCrsOp->RowMap(),"absRowSumInv( " + op->getObjectLabel() + " )");
00575 }
00576 
00584 ModifiableLinearOp getLumpedMatrix(const LinearOp & op)
00585 {
00586    RCP<Thyra::VectorBase<double> > ones = Thyra::createMember(op->domain());
00587    RCP<Thyra::VectorBase<double> > diag = Thyra::createMember(op->range());
00588 
00589    // set to all ones
00590    Thyra::assign(ones.ptr(),1.0);
00591 
00592    // compute lumped diagonal
00593    // Thyra::apply(*op,Thyra::NONCONJ_ELE,*ones,&*diag);
00594    Thyra::apply(*op,Thyra::NOTRANS,*ones,diag.ptr());
00595 
00596    return rcp(new Thyra::DefaultDiagonalLinearOp<double>(diag));
00597 }
00598 
00607 ModifiableLinearOp getInvLumpedMatrix(const LinearOp & op)
00608 {
00609    RCP<Thyra::VectorBase<double> > ones = Thyra::createMember(op->domain());
00610    RCP<Thyra::VectorBase<double> > diag = Thyra::createMember(op->range());
00611 
00612    // set to all ones
00613    Thyra::assign(ones.ptr(),1.0);
00614 
00615    // compute lumped diagonal
00616    // Thyra::apply(*op,Thyra::NONCONJ_ELE,*ones,&*diag);
00617    Thyra::apply(*op,Thyra::NOTRANS,*ones,diag.ptr());
00618    Thyra::reciprocal(diag.ptr(),*diag);
00619 
00620    return rcp(new Thyra::DefaultDiagonalLinearOp<double>(diag));
00621 }
00622 
00634 const ModifiableLinearOp getDiagonalOp(const LinearOp & op)
00635 {
00636    RCP<const Epetra_CrsMatrix> eCrsOp;
00637 
00638    try {
00639       // get Epetra_Operator
00640       RCP<const Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*op);
00641 
00642       // cast it to a CrsMatrix
00643       eCrsOp = rcp_dynamic_cast<const Epetra_CrsMatrix>(eOp,true);
00644    }
00645    catch (std::exception & e) {
00646       RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
00647 
00648       *out << "Teko: getDiagonalOp requires an Epetra_CrsMatrix\n";
00649       *out << "    Could not extract an Epetra_Operator from a \"" << op->description() << std::endl;
00650       *out << "           OR\n";
00651       *out << "    Could not cast an Epetra_Operator to a Epetra_CrsMatrix\n";
00652       *out << std::endl;
00653       *out << "*** THROWN EXCEPTION ***\n";
00654       *out << e.what() << std::endl;
00655       *out << "************************\n";
00656       
00657       throw e;
00658    }
00659 
00660    // extract diagonal
00661    const RCP<Epetra_Vector> diag = rcp(new Epetra_Vector(eCrsOp->RowMap()));
00662    TEST_FOR_EXCEPT(eCrsOp->ExtractDiagonalCopy(*diag));
00663 
00664    // build Thyra diagonal operator
00665    return Teko::Epetra::thyraDiagOp(diag,eCrsOp->RowMap(),"diag( " + op->getObjectLabel() + " )");
00666 }
00667 
00668 const MultiVector getDiagonal(const LinearOp & op)
00669 {
00670    RCP<const Epetra_CrsMatrix> eCrsOp;
00671 
00672    try {
00673       // get Epetra_Operator
00674       RCP<const Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*op);
00675 
00676       // cast it to a CrsMatrix
00677       eCrsOp = rcp_dynamic_cast<const Epetra_CrsMatrix>(eOp,true);
00678    }
00679    catch (std::exception & e) {
00680       RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
00681 
00682       *out << "Teko: getDiagonal requires an Epetra_CrsMatrix\n";
00683       *out << "    Could not extract an Epetra_Operator from a \"" << op->description() << std::endl;
00684       *out << "           OR\n";
00685       *out << "    Could not cast an Epetra_Operator to a Epetra_CrsMatrix\n";
00686       *out << std::endl;
00687       *out << "*** THROWN EXCEPTION ***\n";
00688       *out << e.what() << std::endl;
00689       *out << "************************\n";
00690       
00691       throw e;
00692    }
00693 
00694    // extract diagonal
00695    const RCP<Epetra_Vector> diag = rcp(new Epetra_Vector(eCrsOp->RowMap()));
00696    TEST_FOR_EXCEPT(eCrsOp->ExtractDiagonalCopy(*diag));
00697 
00698    return Thyra::create_Vector(diag,Thyra::create_VectorSpace(Teuchos::rcpFromRef(eCrsOp->RowMap())));
00699 }
00700 
00712 const ModifiableLinearOp getInvDiagonalOp(const LinearOp & op)
00713 {
00714    RCP<const Epetra_CrsMatrix> eCrsOp;
00715 
00716    try {
00717       // get Epetra_Operator
00718       RCP<const Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*op);
00719 
00720       // cast it to a CrsMatrix
00721       eCrsOp = rcp_dynamic_cast<const Epetra_CrsMatrix>(eOp,true);
00722    }
00723    catch (std::exception & e) {
00724       RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
00725 
00726       *out << "Teko: getInvDiagonalOp requires an Epetra_CrsMatrix\n";
00727       *out << "    Could not extract an Epetra_Operator from a \"" << op->description() << std::endl;
00728       *out << "           OR\n";
00729       *out << "    Could not cast an Epetra_Operator to a Epetra_CrsMatrix\n";
00730       *out << std::endl;
00731       *out << "*** THROWN EXCEPTION ***\n";
00732       *out << e.what() << std::endl;
00733       *out << "************************\n";
00734       
00735       throw e;
00736    }
00737 
00738    // extract diagonal
00739    const RCP<Epetra_Vector> diag = rcp(new Epetra_Vector(eCrsOp->RowMap()));
00740    TEST_FOR_EXCEPT(eCrsOp->ExtractDiagonalCopy(*diag));
00741    diag->Reciprocal(*diag);
00742 
00743    // build Thyra diagonal operator
00744    return Teko::Epetra::thyraDiagOp(diag,eCrsOp->RowMap(),"inv(diag( " + op->getObjectLabel() + " ))");
00745 }
00746 
00759 const LinearOp explicitMultiply(const LinearOp & opl,const LinearOp & opm,const LinearOp & opr)
00760 {
00761    // build implicit multiply
00762    const LinearOp implicitOp = Thyra::multiply(opl,opm,opr);
00763 
00764    // build transformer
00765    const RCP<Thyra::LinearOpTransformerBase<double> > prodTrans =
00766        Thyra::epetraExtDiagScaledMatProdTransformer();
00767 
00768    // build operator and multiply
00769    const RCP<Thyra::LinearOpBase<double> > explicitOp = prodTrans->createOutputOp();
00770    prodTrans->transform(*implicitOp,explicitOp.ptr());
00771    explicitOp->setObjectLabel("explicit( " + opl->getObjectLabel() +
00772                                      " * " + opm->getObjectLabel() +
00773                                      " * " + opr->getObjectLabel() + " )");
00774 
00775    return explicitOp;
00776 }
00777 
00792 const ModifiableLinearOp explicitMultiply(const LinearOp & opl,const LinearOp & opm,const LinearOp & opr,
00793                                           const ModifiableLinearOp & destOp)
00794 {
00795    // build implicit multiply
00796    const LinearOp implicitOp = Thyra::multiply(opl,opm,opr);
00797 
00798    // build transformer
00799    const RCP<Thyra::LinearOpTransformerBase<double> > prodTrans =
00800        Thyra::epetraExtDiagScaledMatProdTransformer();
00801 
00802    // build operator destination operator
00803    ModifiableLinearOp explicitOp; 
00804 
00805    // if neccessary build a operator to put the explicit multiply into
00806    if(destOp==Teuchos::null)
00807       explicitOp = prodTrans->createOutputOp();
00808    else
00809       explicitOp = destOp;
00810 
00811    // perform multiplication
00812    prodTrans->transform(*implicitOp,explicitOp.ptr());
00813 
00814    // label it
00815    explicitOp->setObjectLabel("explicit( " + opl->getObjectLabel() +
00816                                      " * " + opm->getObjectLabel() +
00817                                      " * " + opr->getObjectLabel() + " )");
00818 
00819    return explicitOp;
00820 }
00821 
00832 const LinearOp explicitMultiply(const LinearOp & opl,const LinearOp & opr)
00833 {
00834    // build implicit multiply
00835    const LinearOp implicitOp = Thyra::multiply(opl,opr);
00836 
00837    // build a scaling transformer
00838    RCP<Thyra::LinearOpTransformerBase<double> > prodTrans  
00839          = Thyra::epetraExtDiagScalingTransformer();
00840 
00841    // check to see if a scaling transformer works: if not use the 
00842    // DiagScaledMatrixProduct transformer
00843    if(not prodTrans->isCompatible(*implicitOp))
00844        prodTrans = Thyra::epetraExtDiagScaledMatProdTransformer();
00845 
00846    // build operator and multiply
00847    const RCP<Thyra::LinearOpBase<double> > explicitOp = prodTrans->createOutputOp();
00848    prodTrans->transform(*implicitOp,explicitOp.ptr());
00849    explicitOp->setObjectLabel("explicit( " + opl->getObjectLabel() +
00850                                      " * " + opr->getObjectLabel() + " )");
00851 
00852    return explicitOp;
00853 }
00854 
00868 const ModifiableLinearOp explicitMultiply(const LinearOp & opl,const LinearOp & opr,
00869                                           const ModifiableLinearOp & destOp)
00870 {
00871    // build implicit multiply
00872    const LinearOp implicitOp = Thyra::multiply(opl,opr);
00873 
00874    // build a scaling transformer
00875    RCP<Thyra::LinearOpTransformerBase<double> > prodTrans  
00876          = Thyra::epetraExtDiagScalingTransformer();
00877 
00878    // check to see if a scaling transformer works: if not use the 
00879    // DiagScaledMatrixProduct transformer
00880    if(not prodTrans->isCompatible(*implicitOp))
00881        prodTrans = Thyra::epetraExtDiagScaledMatProdTransformer();
00882 
00883    // build operator destination operator
00884    ModifiableLinearOp explicitOp; 
00885 
00886    // if neccessary build a operator to put the explicit multiply into
00887    if(destOp==Teuchos::null)
00888       explicitOp = prodTrans->createOutputOp();
00889    else
00890       explicitOp = destOp;
00891 
00892    // perform multiplication
00893    prodTrans->transform(*implicitOp,explicitOp.ptr());
00894 
00895    // label it
00896    explicitOp->setObjectLabel("explicit( " + opl->getObjectLabel() +
00897                                      " * " + opr->getObjectLabel() + " )");
00898 
00899    return explicitOp;
00900 }
00901 
00912 const LinearOp explicitAdd(const LinearOp & opl,const LinearOp & opr)
00913 {
00914    // build implicit multiply
00915    const LinearOp implicitOp = Thyra::add(opl,opr);
00916  
00917    // build transformer
00918    const RCP<Thyra::LinearOpTransformerBase<double> > prodTrans =
00919        Thyra::epetraExtAddTransformer();
00920 
00921    // build operator and multiply
00922    const RCP<Thyra::LinearOpBase<double> > explicitOp = prodTrans->createOutputOp();
00923    prodTrans->transform(*implicitOp,explicitOp.ptr());
00924    explicitOp->setObjectLabel("explicit( " + opl->getObjectLabel() +
00925                                      " + " + opr->getObjectLabel() + " )");
00926 
00927    return explicitOp;
00928 }
00929 
00942 const ModifiableLinearOp explicitAdd(const LinearOp & opl,const LinearOp & opr,
00943                                      const ModifiableLinearOp & destOp)
00944 {
00945    // build implicit multiply
00946    const LinearOp implicitOp = Thyra::add(opl,opr);
00947  
00948    // build transformer
00949    const RCP<Thyra::LinearOpTransformerBase<double> > prodTrans =
00950        Thyra::epetraExtAddTransformer();
00951 
00952    // build or reuse destination operator
00953    RCP<Thyra::LinearOpBase<double> > explicitOp;
00954    if(destOp!=Teuchos::null)
00955       explicitOp = destOp;
00956    else
00957       explicitOp = prodTrans->createOutputOp();
00958 
00959    // perform multiplication
00960    prodTrans->transform(*implicitOp,explicitOp.ptr());
00961    explicitOp->setObjectLabel("explicit( " + opl->getObjectLabel() +
00962                                      " + " + opr->getObjectLabel() + " )");
00963 
00964    return explicitOp;
00965 }
00966 
00967 const LinearOp buildDiagonal(const MultiVector & src,const std::string & lbl)
00968 {
00969    RCP<Thyra::VectorBase<double> > dst = Thyra::createMember(src->range()); 
00970    Thyra::copy(*src->col(0),dst.ptr());
00971    
00972    return Thyra::diagonal<double>(dst,lbl);
00973 }
00974 
00975 const LinearOp buildInvDiagonal(const MultiVector & src,const std::string & lbl)
00976 {
00977    const RCP<const Thyra::VectorBase<double> > srcV = src->col(0);
00978    RCP<Thyra::VectorBase<double> > dst = Thyra::createMember(srcV->range()); 
00979    Thyra::reciprocal<double>(dst.ptr(),*srcV);
00980 
00981    return Thyra::diagonal<double>(dst,lbl);
00982 }
00983 
00985 BlockedMultiVector buildBlockedMultiVector(const std::vector<MultiVector> & mvv)
00986 {
00987    Teuchos::Array<MultiVector> mvA;
00988    Teuchos::Array<VectorSpace> vsA;
00989 
00990    // build arrays of multi vectors and vector spaces
00991    std::vector<MultiVector>::const_iterator itr;
00992    for(itr=mvv.begin();itr!=mvv.end();++itr) {
00993       mvA.push_back(*itr);
00994       vsA.push_back((*itr)->range());
00995    }
00996 
00997    // construct the product vector space
00998    const RCP<const Thyra::DefaultProductVectorSpace<double> > vs
00999          = Thyra::productVectorSpace<double>(vsA);
01000 
01001    return Thyra::defaultProductMultiVector<double>(vs,mvA);
01002 }
01003 
01014 Teuchos::RCP<Thyra::VectorBase<double> > indicatorVector(
01015                                  const std::vector<int> & indices,
01016                                  const VectorSpace & vs,
01017                                  double onValue, double offValue)
01018 
01019 {
01020    using Teuchos::RCP;
01021  
01022    // create a new vector
01023    RCP<Thyra::VectorBase<double> > v = Thyra::createMember<double>(vs);
01024    Thyra::put_scalar<double>(offValue,v.ptr()); // fill it with "off" values
01025 
01026    // set on values
01027    for(std::size_t i=0;i<indices.size();i++) 
01028       Thyra::set_ele<double>(indices[i],onValue,v.ptr());
01029 
01030    return v;
01031 }
01032 
01057 double computeSpectralRad(const RCP<const Thyra::LinearOpBase<double> > & A, double tol,
01058                           bool isHermitian,int numBlocks,int restart,int verbosity)
01059 {
01060    typedef Thyra::LinearOpBase<double> OP;
01061    typedef Thyra::MultiVectorBase<double> MV;
01062 
01063    int startVectors = 1;
01064 
01065    // construct an initial guess
01066    const RCP<MV> ivec = Thyra::createMember(A->domain());
01067    Thyra::randomize(-1.0,1.0,&*ivec);
01068    
01069    RCP<Anasazi::BasicEigenproblem<double,MV,OP> > eigProb
01070          = rcp(new Anasazi::BasicEigenproblem<double,MV,OP>(A,ivec));
01071    eigProb->setNEV(1);
01072    eigProb->setHermitian(isHermitian);
01073 
01074    // set the problem up
01075    if(not eigProb->setProblem()) {
01076       // big time failure!
01077       return Teuchos::ScalarTraits<double>::nan();
01078    }
01079 
01080    // we want largert magnitude eigenvalue
01081    std::string which("LM"); // largest magnitude
01082 
01083    // Create the parameter list for the eigensolver
01084    // verbosity+=Anasazi::TimingDetails;
01085    Teuchos::ParameterList MyPL;
01086    MyPL.set( "Verbosity", verbosity );
01087    MyPL.set( "Which", which );
01088    MyPL.set( "Block Size", startVectors );
01089    MyPL.set( "Num Blocks", numBlocks );
01090    MyPL.set( "Maximum Restarts", restart ); 
01091    MyPL.set( "Convergence Tolerance", tol );
01092 
01093    // build status test manager
01094    // RCP<Anasazi::StatusTestMaxIters<double,MV,OP> > statTest
01095    //       = rcp(new Anasazi::StatusTestMaxIters<double,MV,OP>(numBlocks*(restart+1)));
01096 
01097    // Create the Block Krylov Schur solver
01098    // This takes as inputs the eigenvalue problem and the solver parameters
01099    Anasazi::BlockKrylovSchurSolMgr<double,MV,OP> MyBlockKrylovSchur(eigProb, MyPL );
01100  
01101    // Solve the eigenvalue problem, and save the return code
01102    Anasazi::ReturnType solverreturn = MyBlockKrylovSchur.solve();
01103 
01104    if(solverreturn==Anasazi::Unconverged) {
01105       double real = MyBlockKrylovSchur.getRitzValues().begin()->realpart;
01106       double comp = MyBlockKrylovSchur.getRitzValues().begin()->imagpart;
01107 
01108       return -std::abs(std::sqrt(real*real+comp*comp));
01109 
01110       // cout << "Anasazi::BlockKrylovSchur::solve() did not converge!" << std::endl; 
01111       // return -std::abs(MyBlockKrylovSchur.getRitzValues().begin()->realpart);
01112    }
01113    else { // solverreturn==Anasazi::Converged
01114       double real = eigProb->getSolution().Evals.begin()->realpart;
01115       double comp = eigProb->getSolution().Evals.begin()->imagpart;
01116 
01117       return std::abs(std::sqrt(real*real+comp*comp));
01118 
01119       // cout << "Anasazi::BlockKrylovSchur::solve() converged!" << endl;
01120       // return std::abs(eigProb->getSolution().Evals.begin()->realpart);
01121    }
01122 }
01123 
01147 double computeSmallestMagEig(const RCP<const Thyra::LinearOpBase<double> > & A, double tol,
01148                              bool isHermitian,int numBlocks,int restart,int verbosity)
01149 {
01150    typedef Thyra::LinearOpBase<double> OP;
01151    typedef Thyra::MultiVectorBase<double> MV;
01152 
01153    int startVectors = 1;
01154 
01155    // construct an initial guess
01156    const RCP<MV> ivec = Thyra::createMember(A->domain());
01157    Thyra::randomize(-1.0,1.0,&*ivec);
01158    
01159    RCP<Anasazi::BasicEigenproblem<double,MV,OP> > eigProb
01160          = rcp(new Anasazi::BasicEigenproblem<double,MV,OP>(A,ivec));
01161    eigProb->setNEV(1);
01162    eigProb->setHermitian(isHermitian);
01163 
01164    // set the problem up
01165    if(not eigProb->setProblem()) {
01166       // big time failure!
01167       return Teuchos::ScalarTraits<double>::nan();
01168    }
01169 
01170    // we want largert magnitude eigenvalue
01171    std::string which("SM"); // smallest magnitude
01172 
01173    // Create the parameter list for the eigensolver
01174    Teuchos::ParameterList MyPL;
01175    MyPL.set( "Verbosity", verbosity );
01176    MyPL.set( "Which", which );
01177    MyPL.set( "Block Size", startVectors );
01178    MyPL.set( "Num Blocks", numBlocks );
01179    MyPL.set( "Maximum Restarts", restart ); 
01180    MyPL.set( "Convergence Tolerance", tol );
01181 
01182    // build status test manager
01183    // RCP<Anasazi::StatusTestMaxIters<double,MV,OP> > statTest
01184    //       = rcp(new Anasazi::StatusTestMaxIters<double,MV,OP>(10));
01185 
01186    // Create the Block Krylov Schur solver
01187    // This takes as inputs the eigenvalue problem and the solver parameters
01188    Anasazi::BlockKrylovSchurSolMgr<double,MV,OP> MyBlockKrylovSchur(eigProb, MyPL );
01189  
01190    // Solve the eigenvalue problem, and save the return code
01191    Anasazi::ReturnType solverreturn = MyBlockKrylovSchur.solve();
01192 
01193    if(solverreturn==Anasazi::Unconverged) {
01194       // cout << "Anasazi::BlockKrylovSchur::solve() did not converge! " << std::endl;
01195       return -std::abs(MyBlockKrylovSchur.getRitzValues().begin()->realpart);
01196    }
01197    else { // solverreturn==Anasazi::Converged
01198       // cout << "Anasazi::BlockKrylovSchur::solve() converged!" << endl;
01199       return std::abs(eigProb->getSolution().Evals.begin()->realpart);
01200    }
01201 }
01202 
01211 ModifiableLinearOp getDiagonalOp(const Teko::LinearOp & A,const DiagonalType & dt)
01212 {
01213    switch(dt) {
01214    case Diagonal:
01215       return getDiagonalOp(A);  
01216    case Lumped:
01217       return getLumpedMatrix(A);  
01218    case AbsRowSum:
01219       return getAbsRowSumMatrix(A);  
01220    case NotDiag:
01221    default:
01222       TEST_FOR_EXCEPT(true);
01223    };
01224 
01225    return Teuchos::null;
01226 }
01227 
01236 ModifiableLinearOp getInvDiagonalOp(const Teko::LinearOp & A,const Teko::DiagonalType & dt)
01237 {
01238    switch(dt) {
01239    case Diagonal:
01240       return getInvDiagonalOp(A);  
01241    case Lumped:
01242       return getInvLumpedMatrix(A);  
01243    case AbsRowSum:
01244       return getAbsRowSumInvMatrix(A);  
01245    case NotDiag:
01246    default:
01247       TEST_FOR_EXCEPT(true);
01248    };
01249 
01250    return Teuchos::null;
01251 }
01252 
01259 std::string getDiagonalName(const DiagonalType & dt)
01260 {
01261    switch(dt) {
01262    case Diagonal:
01263       return "Diagonal";
01264    case Lumped:
01265       return "Lumped";
01266    case AbsRowSum:
01267       return "AbsRowSum";
01268    case NotDiag:
01269       return "NotDiag";
01270    case BlkDiag:
01271       return "BlkDiag";
01272    };
01273 
01274    return "<error>";
01275 }
01276 
01285 DiagonalType getDiagonalType(std::string name)
01286 {
01287    if(name=="Diagonal")
01288       return Diagonal;
01289    if(name=="Lumped")
01290      return Lumped;
01291    if(name=="AbsRowSum")
01292       return AbsRowSum;
01293    if(name=="BlkDiag")
01294       return BlkDiag;
01295  
01296    return NotDiag;
01297 }
01298 
01299 LinearOp probe(Teuchos::RCP<const Epetra_CrsGraph> &G,const LinearOp & Op){
01300 #ifdef Teko_ENABLE_Isorropia
01301   Teuchos::ParameterList probeList;
01302   Prober prober(G,probeList,true);
01303   Teuchos::RCP<Epetra_CrsMatrix> Mat=rcp(new Epetra_CrsMatrix(Copy,*G));
01304   Teko::Epetra::EpetraOperatorWrapper Mwrap(Op);
01305   prober.probe(Mwrap,*Mat);
01306   return Thyra::epetraLinearOp(Mat);    
01307 #else
01308   TEST_FOR_EXCEPTION(true,std::runtime_error,"Probe requires Isorropia");
01309 #endif
01310 }
01311 
01312 double norm_1(const MultiVector & v,std::size_t col)
01313 {
01314    Teuchos::Array<double> n(v->domain()->dim());
01315    Thyra::norms_1<double>(*v,n);
01316 
01317    return n[col];
01318 }
01319 
01320 double norm_2(const MultiVector & v,std::size_t col)
01321 {
01322    Teuchos::Array<double> n(v->domain()->dim());
01323    Thyra::norms_2<double>(*v,n);
01324 
01325    return n[col];
01326 }
01327 
01328 }
 All Classes Files Functions Variables