00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include "Ifpack_ConfigDefs.h"
00044 #include "Ifpack_Preconditioner.h"
00045 #include "Ifpack_IKLU.h"
00046 #include "Ifpack_Condest.h"
00047 #include "Ifpack_Utils.h"
00048 #include "Ifpack_HashTable.h"
00049 #include "Epetra_SerialComm.h"
00050 #include "Epetra_Comm.h"
00051 #include "Epetra_Map.h"
00052 #include "Epetra_RowMatrix.h"
00053 #include "Epetra_CrsMatrix.h"
00054 #include "Epetra_Vector.h"
00055 #include "Epetra_MultiVector.h"
00056 #include "Epetra_Util.h"
00057 #include "Teuchos_ParameterList.hpp"
00058 #include "Teuchos_RefCountPtr.hpp"
00059 #include <functional>
00060 #include <algorithm>
00061
00062 using namespace Teuchos;
00063
00064
00065
00066 Ifpack_IKLU::Ifpack_IKLU(const Epetra_RowMatrix* A) :
00067 A_(*A),
00068 Comm_(A->Comm()),
00069 Condest_(-1.0),
00070 Relax_(0.),
00071 Athresh_(0.0),
00072 Rthresh_(1.0),
00073 LevelOfFill_(1.0),
00074 DropTolerance_(1e-12),
00075 IsInitialized_(false),
00076 IsComputed_(false),
00077 UseTranspose_(false),
00078 NumMyRows_(-1),
00079 NumInitialize_(0),
00080 NumCompute_(0),
00081 NumApplyInverse_(0),
00082 InitializeTime_(0.0),
00083 ComputeTime_(0.0),
00084 ApplyInverseTime_(0.0),
00085 ComputeFlops_(0.0),
00086 ApplyInverseFlops_(0.0),
00087 Time_(Comm()),
00088 GlobalNonzeros_(0),
00089 csrA_(0),
00090 cssS_(0),
00091 csrnN_(0)
00092 {
00093
00094 }
00095
00096
00097 Ifpack_IKLU::~Ifpack_IKLU()
00098 {
00099 Destroy();
00100 }
00101
00102
00103 void Ifpack_IKLU::Destroy()
00104 {
00105 IsInitialized_ = false;
00106 IsComputed_ = false;
00107 if (csrA_)
00108 csr_spfree( csrA_ );
00109 if (cssS_)
00110 csr_sfree( cssS_ );
00111 if (csrnN_)
00112 csr_nfree( csrnN_ );
00113 }
00114
00115
00116 int Ifpack_IKLU::SetParameters(Teuchos::ParameterList& List)
00117 {
00118 try
00119 {
00120 LevelOfFill_ = List.get<double>("fact: ilut level-of-fill", LevelOfFill());
00121 if (LevelOfFill_ <= 0.0)
00122 IFPACK_CHK_ERR(-2);
00123
00124 Athresh_ = List.get<double>("fact: absolute threshold", Athresh_);
00125 Rthresh_ = List.get<double>("fact: relative threshold", Rthresh_);
00126 Relax_ = List.get<double>("fact: relax value", Relax_);
00127 DropTolerance_ = List.get<double>("fact: drop tolerance", DropTolerance_);
00128
00129 Label_ = "IFPACK IKLU (fill=" + Ifpack_toString(LevelOfFill())
00130 + ", relax=" + Ifpack_toString(RelaxValue())
00131 + ", athr=" + Ifpack_toString(AbsoluteThreshold())
00132 + ", rthr=" + Ifpack_toString(RelativeThreshold())
00133 + ", droptol=" + Ifpack_toString(DropTolerance())
00134 + ")";
00135 return(0);
00136 }
00137 catch (...)
00138 {
00139 cerr << "Caught an exception while parsing the parameter list" << endl;
00140 cerr << "This typically means that a parameter was set with the" << endl;
00141 cerr << "wrong type (for example, int instead of double). " << endl;
00142 cerr << "please check the documentation for the type required by each parameer." << endl;
00143 IFPACK_CHK_ERR(-1);
00144 }
00145
00146 return(0);
00147 }
00148
00149
00150 int Ifpack_IKLU::Initialize()
00151 {
00152
00153 Destroy();
00154
00155 Time_.ResetStartTime();
00156
00157 if (A_.Comm().NumProc() != 1) {
00158 cout << " There are too many processors !!! " << endl;
00159 cerr << "Ifpack_IKLU can be used with Comm().NumProc() == 1" << endl;
00160 cerr << "only. This class is a subdomain solver for Ifpack_AdditiveSchwarz," << endl;
00161 cerr << "and it is currently not meant to be used otherwise." << endl;
00162 exit(EXIT_FAILURE);
00163 }
00164
00165
00166 if (Comm().NumProc() == 1 && Matrix().NumMyRows() != Matrix().NumMyCols())
00167 IFPACK_CHK_ERR(-2);
00168
00169 NumMyRows_ = Matrix().NumMyRows();
00170 NumMyNonzeros_ = Matrix().NumMyNonzeros();
00171
00172 int RowNnz, Length = Matrix().MaxNumEntries();
00173 std::vector<int> RowIndices(Length);
00174 std::vector<double> RowValues(Length);
00175
00176
00177
00178 csrA_ = csr_spalloc( NumMyRows_, NumMyRows_, NumMyNonzeros_, 1, 0 );
00179
00180
00181 int count = 0;
00182 csrA_->p[0] = 0;
00183 for (int i = 0; i < NumMyRows_; ++i ) {
00184
00185 IFPACK_CHK_ERR(A_.ExtractMyRowCopy(i,Length,RowNnz,
00186 &RowValues[0],&RowIndices[0]));
00187 for (int j = 0 ; j < RowNnz ; ++j) {
00188 csrA_->j[count++] = RowIndices[j];
00189
00190 }
00191 csrA_->p[i+1] = csrA_->p[i] + RowNnz;
00192 }
00193
00194
00195 int order = 1;
00196 cssS_ = csr_sqr( order, csrA_ );
00197 for (int i = 0; i < NumMyRows_; ++i ) {
00198 cout << "AMD Perm (from inside KLU) [" << i << "] = " << cssS_->q[i] << endl;
00199 }
00200
00201
00202 IsInitialized_ = true;
00203 ++NumInitialize_;
00204 InitializeTime_ += Time_.ElapsedTime();
00205
00206 return(0);
00207 }
00208
00209
00210 class Ifpack_AbsComp
00211 {
00212 public:
00213 inline bool operator()(const double& x, const double& y)
00214 {
00215 return(IFPACK_ABS(x) > IFPACK_ABS(y));
00216 }
00217 };
00218
00219
00220
00221 int Ifpack_IKLU::Compute()
00222 {
00223 if (!IsInitialized())
00224 IFPACK_CHK_ERR(Initialize());
00225
00226 Time_.ResetStartTime();
00227 IsComputed_ = false;
00228
00229 NumMyRows_ = A_.NumMyRows();
00230 int Length = A_.MaxNumEntries();
00231
00232 bool distributed = (Comm().NumProc() > 1)?true:false;
00233 #if !defined(EPETRA_NO_32BIT_GLOBAL_INDICES) || !defined(EPETRA_NO_64BIT_GLOBAL_INDICES)
00234 if (distributed)
00235 {
00236 SerialComm_ = rcp(new Epetra_SerialComm);
00237 SerialMap_ = rcp(new Epetra_Map(NumMyRows_, 0, *SerialComm_));
00238 assert (SerialComm_.get() != 0);
00239 assert (SerialMap_.get() != 0);
00240 }
00241 else
00242 SerialMap_ = rcp(const_cast<Epetra_Map*>(&A_.RowMatrixRowMap()), false);
00243 #endif
00244
00245 int RowNnz;
00246 std::vector<int> RowIndices(Length);
00247 std::vector<double> RowValues(Length);
00248
00249
00250 int count = 0;
00251 for (int i = 0; i < NumMyRows_; ++i ) {
00252
00253 IFPACK_CHK_ERR(A_.ExtractMyRowCopy(i,Length,RowNnz,
00254 &RowValues[0],&RowIndices[0]));
00255
00256 if (RowNnz != (csrA_->p[i+1]-csrA_->p[i])) {
00257 cout << "The number of nonzeros for this row does not math the expected number of nonzeros!!!" << endl;
00258 }
00259 for (int j = 0 ; j < RowNnz ; ++j) {
00260
00261 csrA_->x[count++] = RowValues[j];
00262
00263 }
00264 }
00265
00266
00267 double tol = 0.1;
00268 csrnN_ = csr_lu( &*csrA_, &*cssS_, tol );
00269
00270
00271 csr* L_tmp = csrnN_->L;
00272 csr* U_tmp = csrnN_->U;
00273 std::vector<int> numEntriesL( NumMyRows_ ), numEntriesU( NumMyRows_ );
00274 for (int i=0; i < NumMyRows_; ++i) {
00275 numEntriesL[i] = ( L_tmp->p[i+1] - L_tmp->p[i] );
00276 numEntriesU[i] = ( U_tmp->p[i+1] - U_tmp->p[i] );
00277 }
00278 L_ = rcp(new Epetra_CrsMatrix(View, *SerialMap_, &numEntriesL[0]));
00279 U_ = rcp(new Epetra_CrsMatrix(View, *SerialMap_, &numEntriesU[0]));
00280
00281
00282 #ifndef EPETRA_NO_32BIT_GLOBAL_INDICES
00283 if(SerialMap_->GlobalIndicesInt()) {
00284 for (int i=0; i < NumMyRows_; ++i) {
00285 L_->InsertGlobalValues( i, numEntriesL[i], &(L_tmp->x[L_tmp->p[i]]), &(L_tmp->j[L_tmp->p[i]]) );
00286 U_->InsertGlobalValues( i, numEntriesU[i], &(U_tmp->x[U_tmp->p[i]]), &(U_tmp->j[U_tmp->p[i]]) );
00287 }
00288 }
00289 else
00290 #endif
00291 #ifndef EPETRA_NO_64BIT_GLOBAL_INDICES
00292 if(SerialMap_->GlobalIndicesLongLong()) {
00293
00294 const int MaxNumEntries_L_U = std::max(L_->MaxNumEntries(), U_->MaxNumEntries());
00295 std::vector<long long> entries(MaxNumEntries_L_U);
00296
00297 for (int i=0; i < NumMyRows_; ++i) {
00298 std::copy(&(L_tmp->j[L_tmp->p[i]]), &(L_tmp->j[L_tmp->p[i]]) + numEntriesL[i], entries.begin());
00299 L_->InsertGlobalValues( i, numEntriesL[i], &(L_tmp->x[L_tmp->p[i]]), &(entries[0]) );
00300
00301 std::copy(&(U_tmp->j[U_tmp->p[i]]), &(U_tmp->j[U_tmp->p[i]]) + numEntriesU[i], entries.begin());
00302 U_->InsertGlobalValues( i, numEntriesU[i], &(U_tmp->x[U_tmp->p[i]]), &(entries[0]) );
00303 }
00304 }
00305 else
00306 #endif
00307 throw "Ifpack_IKLU::Compute: GlobalIndices type unknown for SerialMap_";
00308
00309 IFPACK_CHK_ERR(L_->FillComplete());
00310 IFPACK_CHK_ERR(U_->FillComplete());
00311
00312 long long MyNonzeros = L_->NumGlobalNonzeros64() + U_->NumGlobalNonzeros64();
00313 Comm().SumAll(&MyNonzeros, &GlobalNonzeros_, 1);
00314
00315 IsComputed_ = true;
00316
00317 ++NumCompute_;
00318 ComputeTime_ += Time_.ElapsedTime();
00319
00320 return(0);
00321
00322 }
00323
00324
00325 int Ifpack_IKLU::ApplyInverse(const Epetra_MultiVector& X,
00326 Epetra_MultiVector& Y) const
00327 {
00328 if (!IsComputed())
00329 IFPACK_CHK_ERR(-2);
00330
00331 if (X.NumVectors() != Y.NumVectors())
00332 IFPACK_CHK_ERR(-3);
00333
00334 Time_.ResetStartTime();
00335
00336
00337
00338
00339
00340
00341
00342 std::vector<int> invq( NumMyRows_ );
00343
00344 for (int i=0; i<NumMyRows_; ++i ) {
00345 csrnN_->perm[ csrnN_->pinv[i] ] = i;
00346 invq[ cssS_->q[i] ] = i;
00347 }
00348
00349 Teuchos::RefCountPtr<Epetra_MultiVector> Xcopy = Teuchos::rcp( new Epetra_MultiVector(X.Map(),X.NumVectors()), false );
00350 Teuchos::RefCountPtr<Epetra_MultiVector> Ytemp = Teuchos::rcp( new Epetra_MultiVector(Y.Map(),Y.NumVectors()) );
00351
00352 for (int i=0; i<NumMyRows_; ++i) {
00353 for (int j=0; j<X.NumVectors(); ++j) {
00354 Xcopy->ReplaceMyValue( invq[i], j, (*X(j))[i] );
00355 }
00356 }
00357
00358 if (!UseTranspose_)
00359 {
00360
00361 IFPACK_CHK_ERR(L_->Solve(false,false,false,*Xcopy,*Ytemp));
00362 IFPACK_CHK_ERR(U_->Solve(true,false,false,*Ytemp,*Ytemp));
00363 }
00364 else
00365 {
00366
00367 IFPACK_CHK_ERR(U_->Solve(true,true,false,*Xcopy,*Ytemp));
00368 IFPACK_CHK_ERR(L_->Solve(false,true,false,*Ytemp,*Ytemp));
00369 }
00370
00371
00372 for (int i=0; i<NumMyRows_; ++i) {
00373 for (int j=0; j<Y.NumVectors(); ++j) {
00374 Y.ReplaceMyValue( csrnN_->perm[i], j, (*(*Ytemp)(j))[i] );
00375 }
00376 }
00377
00378 ++NumApplyInverse_;
00379 #ifdef IFPACK_FLOPCOUNTERS
00380 ApplyInverseFlops_ += X.NumVectors() * 2 * GlobalNonzeros_;
00381 #endif
00382 ApplyInverseTime_ += Time_.ElapsedTime();
00383
00384 return(0);
00385
00386 }
00387
00388
00389 int Ifpack_IKLU::Apply(const Epetra_MultiVector& X,
00390 Epetra_MultiVector& Y) const
00391 {
00392
00393 return(-98);
00394 }
00395
00396
00397 double Ifpack_IKLU::Condest(const Ifpack_CondestType CT,
00398 const int MaxIters, const double Tol,
00399 Epetra_RowMatrix* Matrix_in)
00400 {
00401 if (!IsComputed())
00402 return(-1.0);
00403
00404
00405 if (Condest_ == -1.0)
00406 Condest_ = Ifpack_Condest(*this, CT, MaxIters, Tol, Matrix_in);
00407
00408 return(Condest_);
00409 }
00410
00411
00412 std::ostream&
00413 Ifpack_IKLU::Print(std::ostream& os) const
00414 {
00415 if (!Comm().MyPID()) {
00416 os << endl;
00417 os << "================================================================================" << endl;
00418 os << "Ifpack_IKLU: " << Label() << endl << endl;
00419 os << "Level-of-fill = " << LevelOfFill() << endl;
00420 os << "Absolute threshold = " << AbsoluteThreshold() << endl;
00421 os << "Relative threshold = " << RelativeThreshold() << endl;
00422 os << "Relax value = " << RelaxValue() << endl;
00423 os << "Condition number estimate = " << Condest() << endl;
00424 os << "Global number of rows = " << A_.NumGlobalRows64() << endl;
00425 if (IsComputed_) {
00426 os << "Number of nonzeros in A = " << A_.NumGlobalNonzeros64() << endl;
00427 os << "Number of nonzeros in L + U = " << NumGlobalNonzeros64()
00428 << " ( = " << 100.0 * NumGlobalNonzeros64() / A_.NumGlobalNonzeros64()
00429 << " % of A)" << endl;
00430 os << "nonzeros / rows = "
00431 << 1.0 * NumGlobalNonzeros64() / U_->NumGlobalRows64() << endl;
00432 }
00433 os << endl;
00434 os << "Phase # calls Total Time (s) Total MFlops MFlops/s" << endl;
00435 os << "----- ------- -------------- ------------ --------" << endl;
00436 os << "Initialize() " << std::setw(5) << NumInitialize()
00437 << " " << std::setw(15) << InitializeTime()
00438 << " 0.0 0.0" << endl;
00439 os << "Compute() " << std::setw(5) << NumCompute()
00440 << " " << std::setw(15) << ComputeTime()
00441 << " " << std::setw(15) << 1.0e-6 * ComputeFlops();
00442 if (ComputeTime() != 0.0)
00443 os << " " << std::setw(15) << 1.0e-6 * ComputeFlops() / ComputeTime() << endl;
00444 else
00445 os << " " << std::setw(15) << 0.0 << endl;
00446 os << "ApplyInverse() " << std::setw(5) << NumApplyInverse()
00447 << " " << std::setw(15) << ApplyInverseTime()
00448 << " " << std::setw(15) << 1.0e-6 * ApplyInverseFlops();
00449 if (ApplyInverseTime() != 0.0)
00450 os << " " << std::setw(15) << 1.0e-6 * ApplyInverseFlops() / ApplyInverseTime() << endl;
00451 else
00452 os << " " << std::setw(15) << 0.0 << endl;
00453 os << "================================================================================" << endl;
00454 os << endl;
00455 }
00456
00457 return(os);
00458 }