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 #ifdef IFPACK_FLOPCOUNTERS
00171 double flops = 0.0;
00172 #endif
00173
00174 H_ = Teuchos::rcp(new Epetra_CrsMatrix(Copy,*SerialMap_,0));
00175 if (H_.get() == 0)
00176 IFPACK_CHK_ERR(-5);
00177
00178
00179 IFPACK_CHK_ERR(A_.ExtractMyRowCopy(0,Length,RowNnz,
00180 &RowValues[0],&RowIndices[0]));
00181
00182
00183 if (distributed)
00184 {
00185 int count = 0;
00186 for (int i = 0 ;i < RowNnz ; ++i)
00187 {
00188 if (RowIndices[i] < NumMyRows_){
00189 RowIndices[count] = RowIndices[i];
00190 RowValues[count] = RowValues[i];
00191 ++count;
00192 }
00193 else
00194 continue;
00195 }
00196 RowNnz = count;
00197 }
00198
00199
00200 double diag_val = 0.0;
00201 for (int i = 0 ;i < RowNnz ; ++i) {
00202 if (RowIndices[i] == 0) {
00203 double& v = RowValues[i];
00204 diag_val = AbsoluteThreshold() * EPETRA_SGN(v) +
00205 RelativeThreshold() * v;
00206 break;
00207 }
00208 }
00209
00210 diag_val = sqrt(diag_val);
00211 int diag_idx = 0;
00212 EPETRA_CHK_ERR(H_->InsertGlobalValues(0,1,&diag_val, &diag_idx));
00213
00214 int oldSize = RowNnz;
00215
00216
00217
00218
00219 Ifpack_HashTable Hash( 10 * A_.MaxNumEntries() * LevelOfFill(), 1);
00220
00221
00222 for (int row_i = 1 ; row_i < NumMyRows_ ; ++row_i) {
00223
00224
00225 IFPACK_CHK_ERR(A_.ExtractMyRowCopy(row_i,Length,RowNnz,
00226 &RowValues[0],&RowIndices[0]));
00227
00228
00229 if (distributed)
00230 {
00231 int count = 0;
00232 for (int i = 0 ;i < RowNnz ; ++i)
00233 {
00234 if (RowIndices[i] < NumMyRows_){
00235 RowIndices[count] = RowIndices[i];
00236 RowValues[count] = RowValues[i];
00237 ++count;
00238 }
00239 else
00240 continue;
00241 }
00242 RowNnz = count;
00243 }
00244
00245
00246
00247 int LOF = (int)(LevelOfFill() * RowNnz);
00248 if (LOF == 0) LOF = 1;
00249
00250
00251 Hash.reset();
00252
00253 double h_ii = 0.0;
00254 for (int i = 0 ; i < RowNnz ; ++i) {
00255 if (RowIndices[i] == row_i) {
00256 double& v = RowValues[i];
00257 h_ii = AbsoluteThreshold() * EPETRA_SGN(v) + RelativeThreshold() * v;
00258 }
00259 else if (RowIndices[i] < row_i)
00260 {
00261 Hash.set(RowIndices[i], RowValues[i], true);
00262 }
00263 }
00264
00265
00266
00267
00268 for (int col_j = RowIndices[0] ; col_j < row_i ; ++col_j) {
00269
00270 double h_ij = 0.0, h_jj = 0.0;
00271
00272 h_ij = Hash.get(col_j);
00273
00274
00275 int* ColIndices;
00276 double* ColValues;
00277 int ColNnz;
00278 H_->ExtractGlobalRowView(col_j, ColNnz, ColValues, ColIndices);
00279
00280 for (int k = 0 ; k < ColNnz ; ++k) {
00281 int col_k = ColIndices[k];
00282
00283 if (col_k == col_j)
00284 h_jj = ColValues[k];
00285 else {
00286 double xxx = Hash.get(col_k);
00287 if (xxx != 0.0)
00288 {
00289 h_ij -= ColValues[k] * xxx;
00290 #ifdef IFPACK_FLOPCOUNTERS
00291 flops += 2.0;
00292 #endif
00293 }
00294 }
00295 }
00296
00297 h_ij /= h_jj;
00298
00299 if (IFPACK_ABS(h_ij) > DropTolerance_)
00300 {
00301 Hash.set(col_j, h_ij);
00302 }
00303
00304 #ifdef IFPACK_FLOPCOUNTERS
00305
00306 ComputeFlops_ += 2.0 * flops + 1.0;
00307 #endif
00308 }
00309
00310 int size = Hash.getNumEntries();
00311
00312 vector<double> AbsRow(size);
00313 int count = 0;
00314
00315
00316 vector<int> keys(size + 1);
00317 vector<double> values(size + 1);
00318
00319 Hash.arrayify(&keys[0], &values[0]);
00320
00321 for (int i = 0 ; i < size ; ++i)
00322 {
00323 AbsRow[i] = IFPACK_ABS(values[i]);
00324 }
00325 count = size;
00326
00327 double cutoff = 0.0;
00328 if (count > LOF) {
00329 nth_element(AbsRow.begin(), AbsRow.begin() + LOF, AbsRow.begin() + count,
00330 greater<double>());
00331 cutoff = AbsRow[LOF];
00332 }
00333
00334 for (int i = 0 ; i < size ; ++i)
00335 {
00336 h_ii -= values[i] * values[i];
00337 }
00338
00339 if (h_ii < 0.0) h_ii = 1e-12;;
00340
00341 h_ii = sqrt(h_ii);
00342
00343 #ifdef IFPACK_FLOPCOUNTERS
00344
00345 ComputeFlops_ += 2 * size + 1;
00346 #endif
00347
00348 double DiscardedElements = 0.0;
00349
00350 count = 0;
00351 for (int i = 0 ; i < size ; ++i)
00352 {
00353 if (IFPACK_ABS(values[i]) > cutoff)
00354 {
00355 values[count] = values[i];
00356 keys[count] = keys[i];
00357 ++count;
00358 }
00359 else
00360 DiscardedElements += values[i];
00361 }
00362
00363 if (RelaxValue() != 0.0) {
00364 DiscardedElements *= RelaxValue();
00365 h_ii += DiscardedElements;
00366 }
00367
00368 values[count] = h_ii;
00369 keys[count] = row_i;
00370 ++count;
00371
00372 H_->InsertGlobalValues(row_i, count, &(values[0]), (int*)&(keys[0]));
00373
00374 oldSize = size;
00375 }
00376
00377 IFPACK_CHK_ERR(H_->FillComplete());
00378
00379 #if 0
00380
00381 Epetra_Vector LHS(Matrix().RowMatrixRowMap());
00382 Epetra_Vector RHS1(Matrix().RowMatrixRowMap());
00383 Epetra_Vector RHS2(Matrix().RowMatrixRowMap());
00384 Epetra_Vector RHS3(Matrix().RowMatrixRowMap());
00385 LHS.Random();
00386
00387 Matrix().Multiply(false,LHS,RHS1);
00388 H_->Multiply(true,LHS,RHS2);
00389 H_->Multiply(false,RHS2,RHS3);
00390
00391 RHS1.Update(-1.0, RHS3, 1.0);
00392 cout << endl;
00393 cout << RHS1;
00394 #endif
00395 int MyNonzeros = H_->NumGlobalNonzeros();
00396 Comm().SumAll(&MyNonzeros, &GlobalNonzeros_, 1);
00397
00398 IsComputed_ = true;
00399 #ifdef IFPACK_FLOPCOUNTERS
00400 double TotalFlops;
00401 A_.Comm().SumAll(&flops, &TotalFlops, 1);
00402 ComputeFlops_ += TotalFlops;
00403 #endif
00404 ++NumCompute_;
00405 ComputeTime_ += Time_.ElapsedTime();
00406
00407 return(0);
00408
00409 }
00410
00411
00412 int Ifpack_ICT::ApplyInverse(const Epetra_MultiVector& X,
00413 Epetra_MultiVector& Y) const
00414 {
00415
00416 if (!IsComputed())
00417 IFPACK_CHK_ERR(-3);
00418
00419 if (X.NumVectors() != Y.NumVectors())
00420 IFPACK_CHK_ERR(-2);
00421
00422 Time_.ResetStartTime();
00423
00424
00425
00426 Teuchos::RefCountPtr<const Epetra_MultiVector> Xcopy;
00427 if (X.Pointers()[0] == Y.Pointers()[0])
00428 Xcopy = Teuchos::rcp( new Epetra_MultiVector(X) );
00429 else
00430 Xcopy = Teuchos::rcp( &X, false );
00431
00432
00433
00434
00435
00436 EPETRA_CHK_ERR(H_->Solve(false,false,false,*Xcopy,Y));
00437 EPETRA_CHK_ERR(H_->Solve(false,true,false,Y,Y));
00438
00439 #ifdef IFPACK_FLOPCOUNTERS
00440
00441 ApplyInverseFlops_ += 4.0 * GlobalNonzeros_;
00442 #endif
00443
00444 ++NumApplyInverse_;
00445 ApplyInverseTime_ += Time_.ElapsedTime();
00446
00447 return(0);
00448 }
00449
00450
00451 int Ifpack_ICT::Apply(const Epetra_MultiVector& X,
00452 Epetra_MultiVector& Y) const
00453 {
00454
00455 IFPACK_CHK_ERR(-98);
00456 }
00457
00458
00459 double Ifpack_ICT::Condest(const Ifpack_CondestType CT,
00460 const int MaxIters, const double Tol,
00461 Epetra_RowMatrix* Matrix_in)
00462 {
00463 if (!IsComputed())
00464 return(-1.0);
00465
00466
00467 if (Condest_ == -1.0)
00468 Condest_ = Ifpack_Condest(*this, CT, MaxIters, Tol, Matrix_in);
00469
00470 return(Condest_);
00471 }
00472
00473
00474 std::ostream&
00475 Ifpack_ICT::Print(std::ostream& os) const
00476 {
00477 if (!Comm().MyPID()) {
00478 os << endl;
00479 os << "================================================================================" << endl;
00480 os << "Ifpack_ICT: " << Label() << endl << endl;
00481 os << "Level-of-fill = " << LevelOfFill() << endl;
00482 os << "Absolute threshold = " << AbsoluteThreshold() << endl;
00483 os << "Relative threshold = " << RelativeThreshold() << endl;
00484 os << "Relax value = " << RelaxValue() << endl;
00485 os << "Condition number estimate = " << Condest() << endl;
00486 os << "Global number of rows = " << Matrix().NumGlobalRows() << endl;
00487 if (IsComputed_) {
00488 os << "Number of nonzeros of H = " << H_->NumGlobalNonzeros() << endl;
00489 os << "nonzeros / rows = "
00490 << 1.0 * H_->NumGlobalNonzeros() / H_->NumGlobalRows() << endl;
00491 }
00492 os << endl;
00493 os << "Phase # calls Total Time (s) Total MFlops MFlops/s" << endl;
00494 os << "----- ------- -------------- ------------ --------" << endl;
00495 os << "Initialize() " << std::setw(5) << NumInitialize()
00496 << " " << std::setw(15) << InitializeTime()
00497 << " 0.0 0.0" << endl;
00498 os << "Compute() " << std::setw(5) << NumCompute()
00499 << " " << std::setw(15) << ComputeTime()
00500 << " " << std::setw(15) << 1.0e-6 * ComputeFlops();
00501 if (ComputeTime() != 0.0)
00502 os << " " << std::setw(15) << 1.0e-6 * ComputeFlops() / ComputeTime() << endl;
00503 else
00504 os << " " << std::setw(15) << 0.0 << endl;
00505 os << "ApplyInverse() " << std::setw(5) << NumApplyInverse()
00506 << " " << std::setw(15) << ApplyInverseTime()
00507 << " " << std::setw(15) << 1.0e-6 * ApplyInverseFlops();
00508 if (ApplyInverseTime() != 0.0)
00509 os << " " << std::setw(15) << 1.0e-6 * ApplyInverseFlops() / ApplyInverseTime() << endl;
00510 else
00511 os << " " << std::setw(15) << 0.0 << endl;
00512 os << "================================================================================" << endl;
00513 os << endl;
00514 }
00515
00516
00517 return(os);
00518 }