|
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_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 }
1.7.4