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 #include "Ifpack_ConfigDefs.h"
00031 #include "Ifpack_Preconditioner.h"
00032 #include "Ifpack_ICT.h"
00033 #include "Ifpack_Condest.h"
00034 #include "Ifpack_Utils.h"
00035 #include "Ifpack_HashTable.h"
00036 #include "Epetra_SerialComm.h"
00037 #include "Epetra_Comm.h"
00038 #include "Epetra_Map.h"
00039 #include "Epetra_RowMatrix.h"
00040 #include "Epetra_CrsMatrix.h"
00041 #include "Epetra_Vector.h"
00042 #include "Epetra_MultiVector.h"
00043 #include "Epetra_Util.h"
00044 #include "Teuchos_ParameterList.hpp"
00045 #include "Teuchos_RefCountPtr.hpp"
00046
00047
00048
00049 Ifpack_ICT::Ifpack_ICT(const Epetra_RowMatrix* A) :
00050 A_(*A),
00051 Comm_(A_.Comm()),
00052 Condest_(-1.0),
00053 Athresh_(0.0),
00054 Rthresh_(1.0),
00055 LevelOfFill_(1.0),
00056 DropTolerance_(0.0),
00057 Relax_(0.0),
00058 IsInitialized_(false),
00059 IsComputed_(false),
00060 UseTranspose_(false),
00061 NumMyRows_(0),
00062 NumInitialize_(0),
00063 NumCompute_(0),
00064 NumApplyInverse_(0),
00065 InitializeTime_(0.0),
00066 ComputeTime_(0.0),
00067 ApplyInverseTime_(0.0),
00068 ComputeFlops_(0.0),
00069 ApplyInverseFlops_(0.0),
00070 Time_(Comm()),
00071 GlobalNonzeros_(0)
00072 {
00073
00074 }
00075
00076
00077 Ifpack_ICT::~Ifpack_ICT()
00078 {
00079 Destroy();
00080 }
00081
00082
00083 void Ifpack_ICT::Destroy()
00084 {
00085 IsInitialized_ = false;
00086 IsComputed_ = false;
00087 }
00088
00089
00090 int Ifpack_ICT::SetParameters(Teuchos::ParameterList& List)
00091 {
00092
00093 try
00094 {
00095 LevelOfFill_ = List.get("fact: ict level-of-fill",LevelOfFill_);
00096 Athresh_ = List.get("fact: absolute threshold", Athresh_);
00097 Rthresh_ = List.get("fact: relative threshold", Rthresh_);
00098 Relax_ = List.get("fact: relax value", Relax_);
00099 DropTolerance_ = List.get("fact: drop tolerance", DropTolerance_);
00100
00101
00102 Label_ = "ICT (fill=" + Ifpack_toString(LevelOfFill())
00103 + ", athr=" + Ifpack_toString(AbsoluteThreshold())
00104 + ", rthr=" + Ifpack_toString(RelativeThreshold())
00105 + ", relax=" + Ifpack_toString(RelaxValue())
00106 + ", droptol=" + Ifpack_toString(DropTolerance())
00107 + ")";
00108
00109 return(0);
00110 }
00111 catch (...)
00112 {
00113 cerr << "Caught an exception while parsing the parameter list" << endl;
00114 cerr << "This typically means that a parameter was set with the" << endl;
00115 cerr << "wrong type (for example, int instead of double). " << endl;
00116 cerr << "please check the documentation for the type required by each parameer." << endl;
00117 IFPACK_CHK_ERR(-1);
00118 }
00119 }
00120
00121
00122 int Ifpack_ICT::Initialize()
00123 {
00124
00125 Destroy();
00126
00127 Time_.ResetStartTime();
00128
00129
00130 if (Comm().NumProc() == 1 && Matrix().NumMyRows() != Matrix().NumMyCols())
00131 IFPACK_CHK_ERR(-2);
00132
00133 NumMyRows_ = Matrix().NumMyRows();
00134
00135
00136 IsInitialized_ = true;
00137 ++NumInitialize_;
00138 InitializeTime_ += Time_.ElapsedTime();
00139
00140 return(0);
00141 }
00142
00143
00144 int Ifpack_ICT::Compute()
00145 {
00146 if (!IsInitialized())
00147 IFPACK_CHK_ERR(Initialize());
00148
00149 Time_.ResetStartTime();
00150 IsComputed_ = false;
00151
00152 NumMyRows_ = A_.NumMyRows();
00153 int Length = A_.MaxNumEntries();
00154 vector<int> RowIndices(Length);
00155 vector<double> RowValues(Length);
00156
00157 bool distributed = (Comm().NumProc() > 1)?true:false;
00158
00159 if (distributed)
00160 {
00161 SerialComm_ = Teuchos::rcp(new Epetra_SerialComm);
00162 SerialMap_ = Teuchos::rcp(new Epetra_Map(NumMyRows_, 0, *SerialComm_));
00163 assert (SerialComm_.get() != 0);
00164 assert (SerialMap_.get() != 0);
00165 }
00166 else
00167 SerialMap_ = Teuchos::rcp(const_cast<Epetra_Map*>(&A_.RowMatrixRowMap()), false);
00168
00169 int RowNnz;
00170 double flops = 0.0;
00171
00172 H_ = Teuchos::rcp(new Epetra_CrsMatrix(Copy,*SerialMap_,0));
00173 if (H_.get() == 0)
00174 IFPACK_CHK_ERR(-5);
00175
00176
00177 IFPACK_CHK_ERR(A_.ExtractMyRowCopy(0,Length,RowNnz,
00178 &RowValues[0],&RowIndices[0]));
00179
00180
00181 if (distributed)
00182 {
00183 int count = 0;
00184 for (int i = 0 ;i < RowNnz ; ++i)
00185 {
00186 if (RowIndices[i] < NumMyRows_){
00187 RowIndices[count] = RowIndices[i];
00188 RowValues[count] = RowValues[i];
00189 ++count;
00190 }
00191 else
00192 continue;
00193 }
00194 RowNnz = count;
00195 }
00196
00197
00198 double diag_val = 0.0;
00199 for (int i = 0 ;i < RowNnz ; ++i) {
00200 if (RowIndices[i] == 0) {
00201 double& v = RowValues[i];
00202 diag_val = AbsoluteThreshold() * EPETRA_SGN(v) +
00203 RelativeThreshold() * v;
00204 break;
00205 }
00206 }
00207
00208 diag_val = sqrt(diag_val);
00209 int diag_idx = 0;
00210 EPETRA_CHK_ERR(H_->InsertGlobalValues(0,1,&diag_val, &diag_idx));
00211
00212 int oldSize = RowNnz;
00213
00214
00215 int hash_size = 1024;
00216 while (hash_size < (int)(A_.MaxNumEntries() * LevelOfFill()))
00217 hash_size *= 2;
00218 Ifpack_HashTable Hash(hash_size - 1, 1);
00219
00220
00221 for (int row_i = 1 ; row_i < NumMyRows_ ; ++row_i) {
00222
00223
00224 IFPACK_CHK_ERR(A_.ExtractMyRowCopy(row_i,Length,RowNnz,
00225 &RowValues[0],&RowIndices[0]));
00226
00227
00228 if (distributed)
00229 {
00230 int count = 0;
00231 for (int i = 0 ;i < RowNnz ; ++i)
00232 {
00233 if (RowIndices[i] < NumMyRows_){
00234 RowIndices[count] = RowIndices[i];
00235 RowValues[count] = RowValues[i];
00236 ++count;
00237 }
00238 else
00239 continue;
00240 }
00241 RowNnz = count;
00242 }
00243
00244
00245
00246 int LOF = (int)(LevelOfFill() * RowNnz);
00247 if (LOF == 0) LOF = 1;
00248
00249
00250 Hash.reset();
00251
00252 double h_ii = 0.0;
00253 for (int i = 0 ; i < RowNnz ; ++i) {
00254 if (RowIndices[i] == row_i) {
00255 double& v = RowValues[i];
00256 h_ii = AbsoluteThreshold() * EPETRA_SGN(v) + RelativeThreshold() * v;
00257 }
00258 else if (RowIndices[i] < row_i)
00259 {
00260 Hash.set(RowIndices[i], RowValues[i], true);
00261 }
00262 }
00263
00264
00265
00266
00267 for (int col_j = RowIndices[0] ; col_j < row_i ; ++col_j) {
00268
00269 double h_ij = 0.0, h_jj = 0.0;
00270
00271 h_ij = Hash.get(col_j);
00272
00273
00274 int* ColIndices;
00275 double* ColValues;
00276 int ColNnz;
00277 H_->ExtractGlobalRowView(col_j, ColNnz, ColValues, ColIndices);
00278
00279 for (int k = 0 ; k < ColNnz ; ++k) {
00280 int col_k = ColIndices[k];
00281
00282 if (col_k == col_j)
00283 h_jj = ColValues[k];
00284 else {
00285 double xxx = Hash.get(col_k);
00286 if (xxx != 0.0)
00287 {
00288 h_ij -= ColValues[k] * xxx;
00289 flops += 2.0;
00290 }
00291 }
00292 }
00293
00294 h_ij /= h_jj;
00295
00296 if (IFPACK_ABS(h_ij) > DropTolerance_)
00297 {
00298 Hash.set(col_j, h_ij);
00299 }
00300
00301
00302 ComputeFlops_ += 2.0 * flops + 1.0;
00303 }
00304
00305 int size = Hash.getNumEntries();
00306
00307 vector<double> AbsRow(size);
00308 int count = 0;
00309
00310
00311 vector<int> keys(size + 1);
00312 vector<double> values(size + 1);
00313
00314 Hash.arrayify(&keys[0], &values[0]);
00315
00316 for (int i = 0 ; i < size ; ++i)
00317 {
00318 AbsRow[i] = IFPACK_ABS(values[i]);
00319 }
00320 count = size;
00321
00322 double cutoff = 0.0;
00323 if (count > LOF) {
00324 nth_element(AbsRow.begin(), AbsRow.begin() + LOF, AbsRow.begin() + count,
00325 greater<double>());
00326 cutoff = AbsRow[LOF];
00327 }
00328
00329 for (int i = 0 ; i < size ; ++i)
00330 {
00331 h_ii -= values[i] * values[i];
00332 }
00333
00334 if (h_ii < 0.0) h_ii = 1e-12;;
00335
00336 h_ii = sqrt(h_ii);
00337
00338
00339 ComputeFlops_ += 2 * size + 1;
00340
00341 double DiscardedElements = 0.0;
00342
00343 count = 0;
00344 for (int i = 0 ; i < size ; ++i)
00345 {
00346 if (IFPACK_ABS(values[i]) > cutoff)
00347 {
00348 values[count] = values[i];
00349 keys[count] = keys[i];
00350 ++count;
00351 }
00352 else
00353 DiscardedElements += values[i];
00354 }
00355
00356 if (RelaxValue() != 0.0) {
00357 DiscardedElements *= RelaxValue();
00358 h_ii += DiscardedElements;
00359 }
00360
00361 values[count] = h_ii;
00362 keys[count] = row_i;
00363 ++count;
00364
00365 H_->InsertGlobalValues(row_i, count, &(values[0]), (int*)&(keys[0]));
00366
00367 oldSize = size;
00368 }
00369
00370 IFPACK_CHK_ERR(H_->FillComplete());
00371
00372 #if 0
00373
00374 Epetra_Vector LHS(Matrix().RowMatrixRowMap());
00375 Epetra_Vector RHS1(Matrix().RowMatrixRowMap());
00376 Epetra_Vector RHS2(Matrix().RowMatrixRowMap());
00377 Epetra_Vector RHS3(Matrix().RowMatrixRowMap());
00378 LHS.Random();
00379
00380 Matrix().Multiply(false,LHS,RHS1);
00381 H_->Multiply(true,LHS,RHS2);
00382 H_->Multiply(false,RHS2,RHS3);
00383
00384 RHS1.Update(-1.0, RHS3, 1.0);
00385 cout << endl;
00386 cout << RHS1;
00387 #endif
00388 int MyNonzeros = H_->NumGlobalNonzeros();
00389 Comm().SumAll(&MyNonzeros, &GlobalNonzeros_, 1);
00390
00391 IsComputed_ = true;
00392 double TotalFlops;
00393 A_.Comm().SumAll(&flops, &TotalFlops, 1);
00394 ComputeFlops_ += TotalFlops;
00395 ++NumCompute_;
00396 ComputeTime_ += Time_.ElapsedTime();
00397
00398 return(0);
00399
00400 }
00401
00402
00403 int Ifpack_ICT::ApplyInverse(const Epetra_MultiVector& X,
00404 Epetra_MultiVector& Y) const
00405 {
00406
00407 if (!IsComputed())
00408 IFPACK_CHK_ERR(-3);
00409
00410 if (X.NumVectors() != Y.NumVectors())
00411 IFPACK_CHK_ERR(-2);
00412
00413 Time_.ResetStartTime();
00414
00415
00416
00417 Teuchos::RefCountPtr<const Epetra_MultiVector> Xcopy;
00418 if (X.Pointers()[0] == Y.Pointers()[0])
00419 Xcopy = Teuchos::rcp( new Epetra_MultiVector(X) );
00420 else
00421 Xcopy = Teuchos::rcp( &X, false );
00422
00423
00424
00425
00426
00427 EPETRA_CHK_ERR(H_->Solve(false,false,false,*Xcopy,Y));
00428 EPETRA_CHK_ERR(H_->Solve(false,true,false,Y,Y));
00429
00430
00431 ApplyInverseFlops_ += 4.0 * GlobalNonzeros_;
00432
00433 ++NumApplyInverse_;
00434 ApplyInverseTime_ += Time_.ElapsedTime();
00435
00436 return(0);
00437 }
00438
00439
00440 int Ifpack_ICT::Apply(const Epetra_MultiVector& X,
00441 Epetra_MultiVector& Y) const
00442 {
00443
00444 IFPACK_CHK_ERR(-98);
00445 }
00446
00447
00448 double Ifpack_ICT::Condest(const Ifpack_CondestType CT,
00449 const int MaxIters, const double Tol,
00450 Epetra_RowMatrix* Matrix_in)
00451 {
00452 if (!IsComputed())
00453 return(-1.0);
00454
00455
00456 if (Condest_ == -1.0)
00457 Condest_ = Ifpack_Condest(*this, CT, MaxIters, Tol, Matrix_in);
00458
00459 return(Condest_);
00460 }
00461
00462
00463 std::ostream&
00464 Ifpack_ICT::Print(std::ostream& os) const
00465 {
00466 if (!Comm().MyPID()) {
00467 os << endl;
00468 os << "================================================================================" << endl;
00469 os << "Ifpack_ICT: " << Label() << endl << endl;
00470 os << "Level-of-fill = " << LevelOfFill() << endl;
00471 os << "Absolute threshold = " << AbsoluteThreshold() << endl;
00472 os << "Relative threshold = " << RelativeThreshold() << endl;
00473 os << "Relax value = " << RelaxValue() << endl;
00474 os << "Condition number estimate = " << Condest() << endl;
00475 os << "Global number of rows = " << Matrix().NumGlobalRows() << endl;
00476 if (IsComputed_) {
00477 os << "Number of nonzeros of H = " << H_->NumGlobalNonzeros() << endl;
00478 os << "nonzeros / rows = "
00479 << 1.0 * H_->NumGlobalNonzeros() / H_->NumGlobalRows() << endl;
00480 }
00481 os << endl;
00482 os << "Phase # calls Total Time (s) Total MFlops MFlops/s" << endl;
00483 os << "----- ------- -------------- ------------ --------" << endl;
00484 os << "Initialize() " << std::setw(5) << NumInitialize()
00485 << " " << std::setw(15) << InitializeTime()
00486 << " 0.0 0.0" << endl;
00487 os << "Compute() " << std::setw(5) << NumCompute()
00488 << " " << std::setw(15) << ComputeTime()
00489 << " " << std::setw(15) << 1.0e-6 * ComputeFlops();
00490 if (ComputeTime() != 0.0)
00491 os << " " << std::setw(15) << 1.0e-6 * ComputeFlops() / ComputeTime() << endl;
00492 else
00493 os << " " << std::setw(15) << 0.0 << endl;
00494 os << "ApplyInverse() " << std::setw(5) << NumApplyInverse()
00495 << " " << std::setw(15) << ApplyInverseTime()
00496 << " " << std::setw(15) << 1.0e-6 * ApplyInverseFlops();
00497 if (ApplyInverseTime() != 0.0)
00498 os << " " << std::setw(15) << 1.0e-6 * ApplyInverseFlops() / ApplyInverseTime() << endl;
00499 else
00500 os << " " << std::setw(15) << 0.0 << endl;
00501 os << "================================================================================" << endl;
00502 os << endl;
00503 }
00504
00505
00506 return(os);
00507 }