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 #include "EpetraExt_ConfigDefs.h"
00037 #ifdef HAVE_PETSC
00038
00039 #include "Epetra_Import.h"
00040 #include "Epetra_Export.h"
00041 #include "Epetra_Vector.h"
00042 #include "Epetra_MultiVector.h"
00043 #include "EpetraExt_PETScAIJMatrix.h"
00044
00045
00046 Epetra_PETScAIJMatrix::Epetra_PETScAIJMatrix(Mat Amat)
00047 : Epetra_Object("Epetra::PETScAIJMatrix"),
00048 Amat_(Amat),
00049 Values_(0),
00050 Indices_(0),
00051 MaxNumEntries_(-1),
00052 ImportVector_(0),
00053 NormInf_(-1.0),
00054 NormOne_(-1.0)
00055 {
00056 #ifdef HAVE_MPI
00057 Comm_ = new Epetra_MpiComm(Amat->comm);
00058 #else
00059 Comm_ = new Epetra_SerialComm();
00060 #endif
00061 int ierr;
00062 char errMsg[80];
00063 MatGetType(Amat, &MatType_);
00064 if ( strcmp(MatType_,MATSEQAIJ) != 0 && strcmp(MatType_,MATMPIAIJ) != 0 ) {
00065 sprintf(errMsg,"PETSc matrix must be either seqaij or mpiaij (but it is %s)",MatType_);
00066 throw Comm_->ReportError(errMsg,-1);
00067 }
00068 petscMatrixType mt;
00069 Mat_MPIAIJ* aij=0;
00070 if (strcmp(MatType_,MATMPIAIJ) == 0) {
00071 mt = PETSC_MPI_AIJ;
00072 aij = (Mat_MPIAIJ*)Amat->data;
00073 }
00074 else if (strcmp(MatType_,MATSEQAIJ) == 0) {
00075 mt = PETSC_SEQ_AIJ;
00076 }
00077 int numLocalRows, numLocalCols;
00078 ierr = MatGetLocalSize(Amat,&numLocalRows,&numLocalCols);
00079 if (ierr) {
00080 sprintf(errMsg,"EpetraExt_PETScAIJMatrix.cpp, line %d, MatGetLocalSize() returned error code %d",__LINE__,ierr);
00081 throw Comm_->ReportError(errMsg,-1);
00082 }
00083 NumMyRows_ = numLocalRows;
00084 NumMyCols_ = numLocalCols;
00085
00086 if (mt == PETSC_MPI_AIJ)
00087 NumMyCols_ += aij->B->cmap.n;
00088 MatInfo info;
00089 ierr = MatGetInfo(Amat,MAT_LOCAL,&info);
00090 if (ierr) {
00091 sprintf(errMsg,"EpetraExt_PETScAIJMatrix.cpp, line %d, MatGetInfo() returned error code %d",__LINE__,ierr);
00092 throw Comm_->ReportError(errMsg,-1);
00093 }
00094 NumMyNonzeros_ = (int) info.nz_used;
00095 Comm_->SumAll(&(info.nz_used), &NumGlobalNonzeros_, 1);
00096
00097
00098
00099 int rowStart, rowEnd;
00100 ierr = MatGetOwnershipRange(Amat,&rowStart,&rowEnd);
00101 if (ierr) {
00102 sprintf(errMsg,"EpetraExt_PETScAIJMatrix.cpp, line %d, MatGetOwnershipRange() returned error code %d",__LINE__,ierr);
00103 throw Comm_->ReportError(errMsg,-1);
00104 }
00105
00106 PetscRowStart_ = rowStart;
00107 PetscRowEnd_ = rowEnd;
00108
00109 int* MyGlobalElements = new int[rowEnd-rowStart];
00110 for (int i=0; i<rowEnd-rowStart; i++)
00111 MyGlobalElements[i] = rowStart+i;
00112
00113 ierr = MatGetInfo(Amat,MAT_GLOBAL_SUM,&info);
00114 if (ierr) {
00115 sprintf(errMsg,"EpetraExt_PETScAIJMatrix.cpp, line %d, MatGetInfo() returned error code %d",__LINE__,ierr);
00116 throw Comm_->ReportError(errMsg,-1);
00117 }
00118 NumGlobalRows_ = (info.rows_global);
00119
00120 DomainMap_ = new Epetra_Map(NumGlobalRows_, NumMyRows_, MyGlobalElements, 0, *Comm_);
00121
00122
00123
00124
00125 int * ColGIDs = new int[NumMyCols_];
00126 for (int i=0; i<numLocalCols; i++) ColGIDs[i] = MyGlobalElements[i];
00127 for (int i=numLocalCols; i<NumMyCols_; i++) ColGIDs[i] = aij->garray[i-numLocalCols];
00128
00129 ColMap_ = new Epetra_Map(-1, NumMyCols_, ColGIDs, 0, *Comm_);
00130
00131 Importer_ = new Epetra_Import(*ColMap_, *DomainMap_);
00132
00133 delete [] MyGlobalElements;
00134 delete [] ColGIDs;
00135 }
00136
00137
00138
00139 Epetra_PETScAIJMatrix::~Epetra_PETScAIJMatrix(){
00140 if (ImportVector_!=0) delete ImportVector_;
00141 delete Importer_;
00142 delete ColMap_;
00143 delete DomainMap_;
00144 delete Comm_;
00145
00146 if (Values_!=0) {delete [] Values_; Values_=0;}
00147 if (Indices_!=0) {delete [] Indices_; Indices_=0;}
00148 }
00149
00150
00151
00152 extern "C" {
00153 PetscErrorCode CreateColmap_MPIAIJ_Private(Mat);
00154 }
00155
00156 int Epetra_PETScAIJMatrix::ExtractMyRowCopy(int Row, int Length, int & NumEntries, double * Values,
00157 int * Indices) const
00158 {
00159 int nz;
00160 PetscInt *gcols, *lcols, ierr;
00161 PetscScalar *vals;
00162
00163
00164 int globalRow = PetscRowStart_ + Row;
00165 assert(globalRow < PetscRowEnd_);
00166 ierr=MatGetRow(Amat_, globalRow, &nz, (const PetscInt**) &gcols, (const PetscScalar **) &vals);CHKERRQ(ierr);
00167
00168
00169
00170 if (strcmp(MatType_,MATMPIAIJ) == 0) {
00171 Mat_MPIAIJ *aij = (Mat_MPIAIJ*)Amat_->data;
00172 lcols = (PetscInt *) malloc(nz * sizeof(int));
00173 if (!aij->colmap) {
00174 ierr = CreateColmap_MPIAIJ_Private(Amat_);CHKERRQ(ierr);
00175 }
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 int offset = Amat_->cmap.n-1;
00193
00194 for (int i=0; i<nz; i++) {
00195 if (gcols[i] >= Amat_->cmap.rstart && gcols[i] < Amat_->cmap.rend) {
00196 lcols[i] = gcols[i] - Amat_->cmap.rstart;
00197 } else {
00198 # ifdef PETSC_USE_CTABLE
00199 ierr = PetscTableFind(aij->colmap,gcols[i]+1,lcols+i);CHKERRQ(ierr);
00200 lcols[i] = lcols[i] + offset;
00201 # else
00202 lcols[i] = aij->colmap[gcols[i]] + offset;
00203 # endif
00204 }
00205
00206 }
00207 }
00208 else lcols = gcols;
00209
00210 NumEntries = nz;
00211 if (NumEntries > Length) return(-1);
00212 for (int i=0; i<NumEntries; i++) {
00213 Indices[i] = lcols[i];
00214 Values[i] = vals[i];
00215 }
00216 MatRestoreRow(Amat_,globalRow,&nz,(const PetscInt**) &gcols, (const PetscScalar **) &vals);
00217 return(0);
00218 }
00219
00220
00221
00222 int Epetra_PETScAIJMatrix::NumMyRowEntries(int Row, int & NumEntries) const
00223 {
00224 int globalRow = PetscRowStart_ + Row;
00225 MatGetRow(Amat_, globalRow, &NumEntries, PETSC_NULL, PETSC_NULL);
00226 MatRestoreRow(Amat_,globalRow,&NumEntries, PETSC_NULL, PETSC_NULL);
00227 return(0);
00228 }
00229
00230
00231
00232 int Epetra_PETScAIJMatrix::ExtractDiagonalCopy(Epetra_Vector & Diagonal) const
00233 {
00234
00235
00236 Vec petscDiag;
00237 double *vals=0;
00238 int length;
00239
00240 int ierr=VecCreate(Comm_->Comm(),&petscDiag);CHKERRQ(ierr);
00241 VecSetSizes(petscDiag,NumMyRows_,NumGlobalRows_);
00242 # ifdef HAVE_MPI
00243 ierr = VecSetType(petscDiag,VECMPI);CHKERRQ(ierr);
00244 # else //TODO untested!!
00245 VecSetType(petscDiag,VECSEQ);
00246 # endif
00247
00248 MatGetDiagonal(Amat_, petscDiag);
00249 VecGetArray(petscDiag,&vals);
00250 VecGetLocalSize(petscDiag,&length);
00251 for (int i=0; i<length; i++) Diagonal[i] = vals[i];
00252 VecRestoreArray(petscDiag,&vals);
00253 VecDestroy(petscDiag);
00254 return(0);
00255 }
00256
00257
00258
00259 int Epetra_PETScAIJMatrix::Multiply(bool TransA,
00260 const Epetra_MultiVector& X,
00261 Epetra_MultiVector& Y) const
00262 {
00263 (void)TransA;
00264 int NumVectors = X.NumVectors();
00265 if (NumVectors!=Y.NumVectors()) EPETRA_CHK_ERR(-1);
00266
00267 double ** xptrs;
00268 double ** yptrs;
00269 X.ExtractView(&xptrs);
00270 Y.ExtractView(&yptrs);
00271 if (RowMatrixImporter()!=0) {
00272 if (ImportVector_!=0) {
00273 if (ImportVector_->NumVectors()!=NumVectors) { delete ImportVector_; ImportVector_= 0;}
00274 }
00275 if (ImportVector_==0) ImportVector_ = new Epetra_MultiVector(RowMatrixColMap(),NumVectors);
00276 ImportVector_->Import(X, *RowMatrixImporter(), Insert);
00277 ImportVector_->ExtractView(&xptrs);
00278 }
00279
00280 Vec petscDiag;
00281 double *vals=0;
00282 int length;
00283 Vec petscX, petscY;
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 int ierr;
00303 for (int i=0; i<NumVectors; i++) {
00304 # ifdef HAVE_MPI
00305 ierr=VecCreateMPIWithArray(Comm_->Comm(),X.MyLength(),X.GlobalLength(),xptrs[i],&petscX); CHKERRQ(ierr);
00306 ierr=VecCreateMPIWithArray(Comm_->Comm(),Y.MyLength(),Y.GlobalLength(),yptrs[i],&petscY); CHKERRQ(ierr);
00307 # else //FIXME I suspect this will bomb in serial (i.e., w/o MPI
00308 ierr=VecCreateSeqWithArray(Comm_->Comm(),X.MyLength(),X.GlobalLength(),xptrs[i],&petscX); CHKERRQ(ierr);
00309 ierr=VecCreateSeqWithArray(Comm_->Comm(),Y.MyLength(),Y.GlobalLength(),yptrs[i],&petscY); CHKERRQ(ierr);
00310 # endif
00311
00312
00313
00314
00315
00316
00317
00318 ierr = MatMult(Amat_,petscX,petscY);CHKERRQ(ierr);
00319
00320 ierr = VecGetArray(petscY,&vals);CHKERRQ(ierr);
00321 ierr = VecGetLocalSize(petscY,&length);CHKERRQ(ierr);
00322 for (int j=0; j<length; j++) yptrs[i][j] = vals[j];
00323 ierr = VecRestoreArray(petscY,&vals);CHKERRQ(ierr);
00324 }
00325
00326 VecDestroy(petscX); VecDestroy(petscY);
00327
00328 double flops = NumGlobalNonzeros();
00329 flops *= 2.0;
00330 flops *= (double) NumVectors;
00331 UpdateFlops(flops);
00332 return(0);
00333 }
00334
00335
00336
00337 int Epetra_PETScAIJMatrix::Solve(bool Upper, bool Trans, bool UnitDiagonal,
00338 const Epetra_MultiVector& X,
00339 Epetra_MultiVector& Y) const
00340 {
00341 (void)Upper;
00342 (void)Trans;
00343 (void)UnitDiagonal;
00344 (void)X;
00345 (void)Y;
00346 return(-1);
00347 }
00348
00349
00350
00351 int Epetra_PETScAIJMatrix::MaxNumEntries() const {
00352 int NumEntries;
00353
00354 if (MaxNumEntries_==-1) {
00355 for (int i=0; i < NumMyRows_; i++) {
00356 NumMyRowEntries(i, NumEntries);
00357 if (NumEntries>MaxNumEntries_) MaxNumEntries_ = NumEntries;
00358 }
00359 }
00360 return(MaxNumEntries_);
00361 }
00362
00363
00364
00365 int Epetra_PETScAIJMatrix::GetRow(int Row) const {
00366
00367 int NumEntries;
00368 int MaxNumEntries = Epetra_PETScAIJMatrix::MaxNumEntries();
00369
00370 if (MaxNumEntries>0) {
00371 if (Values_==0) Values_ = new double[MaxNumEntries];
00372 if (Indices_==0) Indices_ = new int[MaxNumEntries];
00373 }
00374 Epetra_PETScAIJMatrix::ExtractMyRowCopy(Row, MaxNumEntries, NumEntries, Values_, Indices_);
00375
00376 return(NumEntries);
00377 }
00378
00379
00380 int Epetra_PETScAIJMatrix::InvRowSums(Epetra_Vector& x) const {
00381
00382
00383
00384
00385 if (!OperatorRangeMap().SameAs(x.Map())) EPETRA_CHK_ERR(-2);
00386
00387 int ierr = 0;
00388 int i, j;
00389 for (i=0; i < NumMyRows_; i++) {
00390 int NumEntries = GetRow(i);
00391 double scale = 0.0;
00392 for (j=0; j < NumEntries; j++) scale += fabs(Values_[j]);
00393 if (scale<Epetra_MinDouble) {
00394 if (scale==0.0) ierr = 1;
00395 else if (ierr!=1) ierr = 2;
00396 x[i] = Epetra_MaxDouble;
00397 }
00398 else
00399 x[i] = 1.0/scale;
00400 }
00401 UpdateFlops(NumGlobalNonzeros());
00402 EPETRA_CHK_ERR(ierr);
00403 return(0);
00404 }
00405
00406
00407 int Epetra_PETScAIJMatrix::InvColSums(Epetra_Vector& x) const {
00408
00409
00410
00411
00412 if (!Filled()) EPETRA_CHK_ERR(-1);
00413 if (!OperatorDomainMap().SameAs(x.Map())) EPETRA_CHK_ERR(-2);
00414
00415
00416 Epetra_Vector * xp = 0;
00417 Epetra_Vector * x_tmp = 0;
00418
00419
00420
00421 if (RowMatrixImporter()!=0) {
00422 x_tmp = new Epetra_Vector(RowMatrixColMap());
00423 xp = x_tmp;
00424 }
00425 int ierr = 0;
00426 int i, j;
00427
00428 for (i=0; i < NumMyCols_; i++) (*xp)[i] = 0.0;
00429
00430 for (i=0; i < NumMyRows_; i++) {
00431 int NumEntries = GetRow(i);
00432 for (j=0; j < NumEntries; j++) (*xp)[Indices_[j]] += fabs(Values_[j]);
00433 }
00434
00435 if (RowMatrixImporter()!=0){
00436 x.Export(*x_tmp, *RowMatrixImporter(), Add);
00437 delete x_tmp;
00438 xp = &x;
00439 }
00440
00441 for (i=0; i < NumMyRows_; i++) {
00442 double scale = (*xp)[i];
00443 if (scale<Epetra_MinDouble) {
00444 if (scale==0.0) ierr = 1;
00445 else if (ierr!=1) ierr = 2;
00446 (*xp)[i] = Epetra_MaxDouble;
00447 }
00448 else
00449 (*xp)[i] = 1.0/scale;
00450 }
00451 UpdateFlops(NumGlobalNonzeros());
00452 EPETRA_CHK_ERR(ierr);
00453 return(0);
00454 }
00455
00456
00457 int Epetra_PETScAIJMatrix::LeftScale(const Epetra_Vector& X) {
00458
00459
00460
00461 double *xptr;
00462 X.ExtractView(&xptr);
00463 Vec petscX;
00464 # ifdef HAVE_MPI
00465 int ierr=VecCreateMPIWithArray(Comm_->Comm(),X.MyLength(),X.GlobalLength(),xptr,&petscX); CHKERRQ(ierr);
00466 # else //FIXME I suspect this will bomb in serial (i.e., w/o MPI)
00467 int ierr=VecCreateSeqWithArray(Comm_->Comm(),X.MyLength(),X.GlobalLength(),xptr,&petscX); CHKERRQ(ierr);
00468 # endif
00469
00470 MatDiagonalScale(Amat_, petscX, PETSC_NULL);
00471
00472 ierr=VecDestroy(petscX); CHKERRQ(ierr);
00473 return(0);
00474 }
00475
00476
00477 int Epetra_PETScAIJMatrix::RightScale(const Epetra_Vector& X) {
00478
00479
00480
00481 double *xptr;
00482 X.ExtractView(&xptr);
00483 Vec petscX;
00484 # ifdef HAVE_MPI
00485 int ierr=VecCreateMPIWithArray(Comm_->Comm(),X.MyLength(),X.GlobalLength(),xptr,&petscX); CHKERRQ(ierr);
00486 # else //FIXME I suspect this will bomb in serial (i.e., w/o MPI)
00487 int ierr=VecCreateSeqWithArray(Comm_->Comm(),X.MyLength(),X.GlobalLength(),xptr,&petscX); CHKERRQ(ierr);
00488 # endif
00489
00490 MatDiagonalScale(Amat_, PETSC_NULL, petscX);
00491
00492 ierr=VecDestroy(petscX); CHKERRQ(ierr);
00493 return(0);
00494 }
00495
00496
00497
00498 double Epetra_PETScAIJMatrix::NormInf() const {
00499
00500 if (NormInf_>-1.0) return(NormInf_);
00501
00502 MatNorm(Amat_, NORM_INFINITY,&NormInf_);
00503 UpdateFlops(NumGlobalNonzeros());
00504
00505 return(NormInf_);
00506 }
00507
00508
00509
00510 double Epetra_PETScAIJMatrix::NormOne() const {
00511
00512 if (NormOne_>-1.0) return(NormOne_);
00513 if (!Filled()) EPETRA_CHK_ERR(-1);
00514
00515 MatNorm(Amat_, NORM_1,&NormOne_);
00516 UpdateFlops(NumGlobalNonzeros());
00517
00518 return(NormOne_);
00519 }
00520
00521
00522
00523 void Epetra_PETScAIJMatrix::Print(ostream& os) const {
00524 return;
00525 }
00526
00527 #endif