EpetraExt_PETScAIJMatrix.cpp

Go to the documentation of this file.
00001 //@HEADER
00002 // ***********************************************************************
00003 // 
00004 //     EpetraExt: Epetra Extended - Linear Algebra Services Package
00005 //                 Copyright (2001) Sandia Corporation
00006 // 
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 // 
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 
00025 // 
00026 // ***********************************************************************
00027 //@HEADER
00028 
00029 /*#############################################################################
00030 # CVS File Information
00031 #    Current revision: $Revision: 1.4.2.1 $
00032 #    Last modified:    $Date: 2008/08/29 00:18:24 $
00033 #    Modified by:      $Author: jhu $
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; //numLocalCols is the total # of unique columns in the local matrix (the diagonal block)
00085   //TODO what happens if some columns are empty?
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; //PETSc stores nnz as double
00095   Comm_->SumAll(&(info.nz_used), &NumGlobalNonzeros_, 1);
00096 
00097   //The PETSc documentation warns that this may not be robust.
00098   //In particular, this will break if the ordering is not contiguous!
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   // get the GIDs of the non-local columns
00123   //FIXME what if the matrix is sequential?
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 } //Epetra_PETScAIJMatrix(Mat Amat)
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 } //Epetra_PETScAIJMatrix dtor
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   // PETSc assumes the row number is global, whereas Trilinos assumes it's local.
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   // I ripped this bit of code from PETSc's MatSetValues_MPIAIJ() in mpiaij.c.  The PETSc getrow returns everything in
00169   // global numbering, so we must convert to local numbering.
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       A PETSc parallel aij matrix uses two matrices to represent the local rows.
00178       The first matrix, A, is square and contains all local columns.
00179       The second matrix, B, is rectangular and contains all non-local columns.
00180 
00181       Matrix A:
00182       Local column ID's are mapped to global column id's by adding cmap.rstart.
00183       Given the global ID of a local column, the local ID is found by
00184       subtracting cmap.rstart.
00185 
00186       Matrix B:
00187       Non-local column ID's are mapped to global column id's by the local-to-
00188       global map garray.  Given the global ID of a local column, the local ID is
00189       found by the global-to-local map colmap.  colmap is either an array or
00190       hash table, the latter being the case when PETSC_USE_CTABLE is defined.
00191     */
00192     int offset = Amat_->cmap.n-1; //offset for non-local column indices
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     } //for i=0; i<nz; i++)
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 } //ExtractMyRowCopy()
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   //TODO optimization: only get this diagonal once
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);  // X and Y must have same number of vectors
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 /* new */
00285 //VecCreateMPIWithArray(MPI_Comm comm,PetscInt n,PetscInt N,const PetscScalar array[],Vec *vv)
00286 /* new */
00287 /*
00288   int ierr = VecCreate(Comm_->Comm(),&petscX);CHKERRQ(ierr);
00289   ierr = VecCreate(Comm_->Comm(),&petscY);CHKERRQ(ierr);
00290   ierr = VecSetSizes(petscX,X.MyLength(),X.GlobalLength()); CHKERRQ(ierr);
00291   ierr = VecSetSizes(petscY,Y.MyLength(),Y.GlobalLength()); CHKERRQ(ierr);
00292 #ifdef HAVE_MPI
00293   VecSetType(petscX,VECMPI);
00294   VecSetType(petscY,VECMPI);
00295 #else
00296   VecSetType(petscX,VECSEQ);
00297   VecSetType(petscY,VECSEQ);
00298 #endif
00299   int *localIndices = new int[X.MyLength()];
00300   for (int i=0; i<X.MyLength(); i++) localIndices[i] = i;
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     ierr = VecSetValuesLocal(petscX,X.MyLength(),localIndices,xptrs[i],INSERT_VALUES);CHKERRQ(ierr);
00313     ierr = VecAssemblyBegin(petscX); VecAssemblyEnd(petscX);CHKERRQ(ierr);
00314     ierr = VecSetValuesLocal(petscY,Y.MyLength(),localIndices,yptrs[i],INSERT_VALUES);CHKERRQ(ierr);
00315     ierr = VecAssemblyBegin(petscY); VecAssemblyEnd(petscY);CHKERRQ(ierr);
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 } //Multiply()
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); // Not implemented
00347 }
00348 
00349 //=============================================================================
00350 // Utility routine to get the specified row and put it into Values_ and Indices_ arrays
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 // Utility routine to get the specified row and put it into Values_ and Indices_ arrays
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 // Put inverse of the sum of absolute values of the ith row of A in x[i].
00383 //
00384 
00385   if (!OperatorRangeMap().SameAs(x.Map())) EPETRA_CHK_ERR(-2); // x must have the same distribution as the range of A
00386 
00387   int ierr = 0;
00388   int i, j;
00389   for (i=0; i < NumMyRows_; i++) {
00390     int NumEntries = GetRow(i); // Copies ith row of matrix into Values_ and Indices_
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; // Set error to 1 to signal that zero rowsum found (supercedes ierr = 2)
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 // Put inverse of the sum of absolute values of the jth column of A in x[j].
00410 //
00411 
00412   if (!Filled()) EPETRA_CHK_ERR(-1); // Matrix must be filled.
00413   if (!OperatorDomainMap().SameAs(x.Map())) EPETRA_CHK_ERR(-2); // x must have the same distribution as the domain of A
00414   
00415 
00416   Epetra_Vector * xp = 0;
00417   Epetra_Vector * x_tmp = 0;
00418   
00419 
00420   // If we have a non-trivial importer, we must export elements that are permuted or belong to other processors
00421   if (RowMatrixImporter()!=0) {
00422     x_tmp = new Epetra_Vector(RowMatrixColMap()); // Create import vector if needed
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);// Copies ith row of matrix into Values_ and Indices_
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); // Fill x with Values from import vector
00437     delete x_tmp;
00438     xp = &x;
00439   }
00440   // Invert values, don't allow them to get too large
00441   for (i=0; i < NumMyRows_; i++) {
00442     double scale = (*xp)[i];
00443     if (scale<Epetra_MinDouble) {
00444       if (scale==0.0) ierr = 1; // Set error to 1 to signal that zero rowsum found (supercedes ierr = 2)
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 // This function scales the ith row of A by x[i].
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 } //LeftScale()
00475 
00476 //=============================================================================
00477 int Epetra_PETScAIJMatrix::RightScale(const Epetra_Vector& X) {
00478 //
00479 // This function scales the jth row of A by x[j].
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 } //RightScale()
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); // Matrix must be filled.
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 /*HAVE_PETSC*/

Generated on Wed May 12 21:40:37 2010 for EpetraExt by  doxygen 1.4.7