Epetra_BasicRowMatrix.cpp

Go to the documentation of this file.
00001 
00002 //@HEADER
00003 // ************************************************************************
00004 // 
00005 //               Epetra: Linear Algebra Services Package 
00006 //                 Copyright (2001) Sandia Corporation
00007 // 
00008 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00009 // license for use of this work by or on behalf of the U.S. Government.
00010 // 
00011 // This library is free software; you can redistribute it and/or modify
00012 // it under the terms of the GNU Lesser General Public License as
00013 // published by the Free Software Foundation; either version 2.1 of the
00014 // License, or (at your option) any later version.
00015 //  
00016 // This library is distributed in the hope that it will be useful, but
00017 // WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019 // Lesser General Public License for more details.
00020 //  
00021 // You should have received a copy of the GNU Lesser General Public
00022 // License along with this library; if not, write to the Free Software
00023 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00024 // USA
00025 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 
00026 // 
00027 // ************************************************************************
00028 //@HEADER
00029 
00030 #include "Epetra_BasicRowMatrix.h"
00031 #include "Epetra_Map.h"
00032 #include "Epetra_Import.h"
00033 #include "Epetra_Export.h"
00034 #include "Epetra_Vector.h"
00035 #include "Epetra_MultiVector.h"
00036 #include "Epetra_Comm.h"
00037 #include "Epetra_Util.h"
00038 #include "Epetra_IntSerialDenseVector.h"
00039 #include "Epetra_RowMatrix.h"
00040 #include "Epetra_CrsMatrix.h"
00041 
00042 
00043 //==============================================================================
00044 Epetra_BasicRowMatrix::Epetra_BasicRowMatrix(const Epetra_Comm & Comm) 
00045   : Comm_(Comm.Clone()),
00046     OperatorDomainMap_(Epetra_Map(0,0,Comm)),
00047     OperatorRangeMap_(Epetra_Map(0,0,Comm)),
00048     RowMatrixRowMap_(Epetra_Map(0,0,Comm)),
00049     RowMatrixColMap_(Epetra_Map(0,0,Comm)),
00050     NumMyNonzeros_(0),
00051     NumGlobalNonzeros_(0),
00052     MaxNumEntries_(0),
00053     NormInf_(0.0),
00054     NormOne_(0.0),
00055     UseTranspose_(false),
00056     HasNormInf_(true),
00057     LowerTriangular_(true),
00058     UpperTriangular_(true),
00059     HaveStructureConstants_(false),
00060     HaveNumericConstants_(false),
00061     HaveMaps_(false),
00062     ImportVector_(0),
00063     ExportVector_(0),
00064     Importer_(0),
00065     Exporter_(0)
00066 {
00067   SetLabel("Epetra::BasicRowMatrix");
00068 }
00069 
00070 //==============================================================================
00071 Epetra_BasicRowMatrix::~Epetra_BasicRowMatrix(){
00072 
00073   if (ImportVector_!=0) delete ImportVector_;
00074   ImportVector_=0;
00075   if (ExportVector_!=0) delete ExportVector_;
00076   ExportVector_=0;
00077   if (Importer_!=0) delete Importer_;
00078   Importer_=0;
00079   if (Exporter_!=0) delete Exporter_;
00080   Exporter_=0;
00081   delete Comm_;
00082 }
00083 
00084 //==============================================================================
00085 void Epetra_BasicRowMatrix::SetMaps(const Epetra_Map & RowMap, const Epetra_Map & ColMap) {
00086 
00087   SetMaps(RowMap, ColMap, RowMap, RowMap);
00088 }
00089 
00090 //==============================================================================
00091 void Epetra_BasicRowMatrix::SetMaps(const Epetra_Map & RowMap, const Epetra_Map & ColMap, 
00092       const Epetra_Map & DomainMap, const Epetra_Map & RangeMap) {
00093 
00094   RowMatrixRowMap_ = RowMap;
00095   RowMatrixColMap_ = ColMap;
00096   OperatorDomainMap_ = DomainMap;
00097   OperatorRangeMap_ = RangeMap;
00098   HaveMaps_ = true;
00099   HaveStructureConstants_ = false;
00100   HaveNumericConstants_ = false;
00101 
00102   if (!OperatorDomainMap().UniqueGIDs()) throw RowMatrixRowMap().ReportError("At least one GID is repeated in domain map. Domain and range maps must have unique GIDs", -1);
00103   if (!OperatorRangeMap().UniqueGIDs()) throw RowMatrixRowMap().ReportError("At least one GID is repeated in range map. Domain and range maps must have unique GIDs", -2);
00104   SetImportExport();
00105 }
00106 
00107 //==============================================================================
00108 void Epetra_BasicRowMatrix::SetImportExport() {
00109 
00110   // Check if non-trivial import/export operators
00111   if (!(RowMatrixRowMap().SameAs(OperatorRangeMap()))) 
00112     Exporter_ = new Epetra_Export(RowMatrixRowMap(), OperatorRangeMap());
00113   
00114   if (!(RowMatrixColMap().SameAs(OperatorDomainMap())))
00115     Importer_ = new Epetra_Import(RowMatrixColMap(), OperatorDomainMap());
00116 
00117   NumMyRows_ = RowMatrixRowMap().NumMyPoints();
00118   NumMyCols_ = RowMatrixColMap().NumMyPoints();
00119 }
00120 
00121 //==============================================================================
00122 void Epetra_BasicRowMatrix::ComputeStructureConstants() const {
00123   MaxNumEntries_ = 0;
00124   NumMyNonzeros_ = 0;
00125   NumGlobalNonzeros_ = 0;
00126   int NumEntries = 0;
00127   for (int i=0; i<NumMyRows_; i++) {
00128     NumMyRowEntries(i, NumEntries);
00129     NumMyNonzeros_ += NumEntries;
00130     if (NumEntries>MaxNumEntries_) MaxNumEntries_ = NumEntries;
00131   }
00132 
00133   RowMatrixRowMap().Comm().SumAll(&NumMyNonzeros_, &NumGlobalNonzeros_, 1);
00134   HaveStructureConstants_ = true;
00135 }
00136 //=============================================================================
00137 void Epetra_BasicRowMatrix::ComputeNumericConstants() const {
00138   Epetra_SerialDenseVector Values(MaxNumEntries());
00139   Epetra_IntSerialDenseVector Indices(MaxNumEntries());
00140   int NumEntries;
00141   Epetra_Vector x1(RowMatrixRowMap()); // Need temp vector for row sums
00142   Epetra_Vector x2(RowMatrixColMap()); // Need temp vector for column sums
00143   for(int i = 0; i < NumMyRows_; i++) {
00144     ExtractMyRowCopy(i, MaxNumEntries(), NumEntries, Values.Values(), Indices.Values());
00145     for(int j = 0; j < NumEntries; j++) {
00146       x1[i] += std::abs(Values[j]);
00147       x2[Indices[j]] += std::abs(Values[j]);
00148       if (Indices[j]<i) UpperTriangular_ = false;
00149       if (Indices[j]>i) LowerTriangular_ = false;
00150     }
00151   }
00152 
00153   // If we have a non-trivial exporter, we must export elements that are permuted or belong to other processors
00154   if(Exporter() != 0) {
00155     Epetra_Vector xtmp(OperatorRangeMap()); // Create temporary import vector if needed
00156     xtmp.Export(x1,*Exporter(),Add);
00157     xtmp.MaxValue(&NormInf_); // This is the NormInf
00158   }
00159   else
00160     x1.MaxValue(&NormInf_); // Find max
00161 
00162   // If we have a non-trivial importer, we must export elements that are permuted or belong to other processors
00163   if(Importer() != 0) {
00164     Epetra_Vector xtmp(OperatorDomainMap()); // Create temporary import vector if needed
00165     xtmp.Export(x2,*Importer(),Add);
00166     xtmp.MaxValue(&NormOne_); // This is the NormOne
00167   }
00168   else
00169     x2.MaxValue(&NormOne_); // Find max
00170 
00171   UpdateFlops(2*NumGlobalNonzeros());
00172   HaveNumericConstants_ = true;
00173 }
00174 //=============================================================================
00175 int Epetra_BasicRowMatrix::ExtractDiagonalCopy(Epetra_Vector & Diagonal) const {
00176 
00177   if(!RowMatrixRowMap().SameAs(Diagonal.Map())) 
00178     EPETRA_CHK_ERR(-2); // Maps must be the same
00179 
00180   // Crude implementation in terms of ExtractMyRowCopy
00181 
00182   Epetra_SerialDenseVector Values(MaxNumEntries());
00183   Epetra_IntSerialDenseVector Indices(MaxNumEntries());
00184   int NumEntries;
00185 
00186   for(int i = 0; i < NumMyRows_; i++) {
00187     EPETRA_CHK_ERR(ExtractMyRowCopy(i, MaxNumEntries(), NumEntries, Values.Values(), Indices.Values()));
00188     int ii = RowMatrixRowMap().GID(i);
00189     
00190     Diagonal[i] = 0.0;
00191     for(int j = 0; j < NumEntries; j++) {
00192       if(ii == RowMatrixColMap().GID(Indices[j])) {
00193   Diagonal[i] = Values[j];
00194   break;
00195       }
00196     }
00197   }
00198   return(0);
00199 }
00200 //=============================================================================
00201 int Epetra_BasicRowMatrix::InvRowSums(Epetra_Vector & x) const {
00202   int ierr = 0;
00203   int i, j;
00204   Epetra_SerialDenseVector Values(MaxNumEntries());
00205   Epetra_IntSerialDenseVector Indices(MaxNumEntries());
00206   int NumEntries;
00207   x.PutScalar(0.0); // Make sure we sum into a vector of zeros.
00208   double * xp = (double*)x.Values();
00209   if (OperatorRangeMap().SameAs(x.Map()) && Exporter() != 0) {
00210     Epetra_Vector x_tmp(RowMatrixRowMap());
00211     x_tmp.PutScalar(0.0);
00212     double * x_tmp_p = (double*)x_tmp.Values();
00213     for (i=0; i < NumMyRows_; i++) {
00214       EPETRA_CHK_ERR(ExtractMyRowCopy(i, MaxNumEntries(), NumEntries, Values.Values(), Indices.Values()));
00215       for (j=0; j < NumEntries; j++)  x_tmp_p[i] += std::abs(Values[j]);
00216     }
00217     EPETRA_CHK_ERR(x.Export(x_tmp, *Exporter(), Add)); //Export partial row sums to x.
00218     int myLength = x.MyLength();
00219     for (i=0; i<myLength; i++) { 
00220       if (xp[i]<Epetra_MinDouble) {
00221         if (xp[i]==0.0) ierr = 1; // Set error to 1 to signal that zero rowsum found (supercedes ierr = 2)
00222         else if (ierr!=1) ierr = 2;
00223         xp[i] = Epetra_MaxDouble;
00224       }
00225       else
00226         xp[i] = 1.0/xp[i];
00227     }
00228   }
00229   else if (RowMatrixRowMap().SameAs(x.Map())) {
00230     for (i=0; i < NumMyRows_; i++) {
00231       EPETRA_CHK_ERR(ExtractMyRowCopy(i, MaxNumEntries(), NumEntries, Values.Values(), Indices.Values()));
00232       double scale = 0.0;
00233       for (j=0; j < NumEntries; j++) scale += std::abs(Values[j]);
00234       if (scale<Epetra_MinDouble) {
00235         if (scale==0.0) ierr = 1; // Set error to 1 to signal that zero rowsum found (supercedes ierr = 2)
00236         else if (ierr!=1) ierr = 2;
00237         xp[i] = Epetra_MaxDouble;
00238       }
00239       else
00240         xp[i] = 1.0/scale;
00241     }
00242   }
00243   else { // x.Map different than both RowMatrixRowMap() and OperatorRangeMap()
00244     EPETRA_CHK_ERR(-2); // The map of x must be the RowMap or RangeMap of A.
00245   }
00246   EPETRA_CHK_ERR(ierr);  
00247   UpdateFlops(NumGlobalNonzeros());
00248   return(0);
00249 }
00250 //=============================================================================
00251 int Epetra_BasicRowMatrix::LeftScale(const Epetra_Vector & x) {
00252   double *curValue;
00253   int curRowIndex, curColIndex;
00254   if(OperatorRangeMap().SameAs(x.Map()) && Exporter() != 0) {
00255     Epetra_Vector xtmp(RowMatrixRowMap());
00256     xtmp.Import(x,*Exporter(),Insert);
00257     for (int i=0; i<NumMyNonzeros_; i++) {
00258       ExtractMyEntryView(i, curValue, curRowIndex, curColIndex);
00259       *curValue *= xtmp[curRowIndex];
00260     }
00261   }
00262   else if (RowMatrixRowMap().SameAs(x.Map()))
00263     for (int i=0; i<NumMyNonzeros_; i++) {
00264       ExtractMyEntryView(i, curValue, curRowIndex, curColIndex);
00265       *curValue *= x[curRowIndex];
00266     }
00267   else {
00268     EPETRA_CHK_ERR(-2); // The Map of x must be the RowMap or RangeMap of A.
00269   }
00270   HaveNumericConstants_ = false;
00271   UpdateFlops(NumGlobalNonzeros());
00272   return(0);
00273 }
00274 //=============================================================================
00275 int Epetra_BasicRowMatrix::InvColSums(Epetra_Vector & x) const {
00276   int ierr = 0;
00277   int i, j;
00278   Epetra_SerialDenseVector Values(MaxNumEntries());
00279   Epetra_IntSerialDenseVector Indices(MaxNumEntries());
00280   int NumEntries;
00281   int MapNumMyElements = x.Map().NumMyElements();
00282   x.PutScalar(0.0); // Make sure we sum into a vector of zeros.
00283   double* xp = (double*)x.Values();
00284   if(OperatorDomainMap().SameAs(x.Map()) && Importer() != 0) {
00285     Epetra_Vector x_tmp(RowMatrixColMap());
00286     x_tmp.PutScalar(0.0);
00287     double * x_tmp_p = (double*)x_tmp.Values();
00288     for(i = 0; i < NumMyRows_; i++) {
00289       EPETRA_CHK_ERR(ExtractMyRowCopy(i, MaxNumEntries(), NumEntries, Values.Values(), Indices.Values()));
00290       for(j = 0; j < NumEntries; j++) 
00291         x_tmp_p[Indices[j]] += std::abs(Values[j]);
00292     }
00293     EPETRA_CHK_ERR(x.Export(x_tmp, *Importer(), Add)); // Fill x with partial column sums
00294   }
00295   else if(RowMatrixColMap().SameAs(x.Map())) {
00296     for(i = 0; i < NumMyRows_; i++) {
00297       EPETRA_CHK_ERR(ExtractMyRowCopy(i, MaxNumEntries(), NumEntries, Values.Values(), Indices.Values()));
00298       for(j = 0; j < NumEntries; j++) 
00299         xp[Indices[j]] += std::abs(Values[j]);
00300     }
00301   }
00302   else { //x.Map different than both RowMatrixColMap() and OperatorDomainMap()
00303     EPETRA_CHK_ERR(-2); // x must have the same distribution as the domain of A
00304   }
00305 
00306   // Invert values, don't allow them to get too large
00307   for(i = 0; i < MapNumMyElements; i++) {
00308     double scale = xp[i];
00309     if(scale < Epetra_MinDouble) {
00310       if(scale == 0.0) 
00311   ierr = 1; // Set error to 1 to signal that zero rowsum found (supercedes ierr = 2)
00312       else if(ierr != 1) 
00313   ierr = 2;
00314       xp[i] = Epetra_MaxDouble;
00315     }
00316     else
00317       xp[i] = 1.0 / scale;
00318   }
00319 
00320   EPETRA_CHK_ERR(ierr);
00321   UpdateFlops(NumGlobalNonzeros());
00322   return(0);
00323 }
00324 //=============================================================================
00325 int Epetra_BasicRowMatrix::RightScale(const Epetra_Vector & x) {
00326   double *curValue;
00327   int curRowIndex, curColIndex;
00328   if(OperatorDomainMap().SameAs(x.Map()) && Importer() != 0) {
00329     Epetra_Vector xtmp(RowMatrixColMap());
00330     xtmp.Import(x,*Importer(),Insert);
00331     for (int i=0; i<NumMyNonzeros_; i++) {
00332       ExtractMyEntryView(i, curValue, curRowIndex, curColIndex);
00333       *curValue *= xtmp[curColIndex];
00334     }
00335   }
00336   else if (RowMatrixColMap().SameAs(x.Map()))
00337     for (int i=0; i<NumMyNonzeros_; i++) {
00338       ExtractMyEntryView(i, curValue, curRowIndex, curColIndex);
00339       *curValue *= x[curColIndex];
00340     }
00341   else {
00342     EPETRA_CHK_ERR(-2); // The Map of x must be the RowMap or RangeMap of A.
00343   }
00344   HaveNumericConstants_ = false;
00345   UpdateFlops(NumGlobalNonzeros());
00346   return(0);
00347 }
00348 //=============================================================================
00349 int Epetra_BasicRowMatrix::Multiply(bool TransA, const Epetra_MultiVector& X, Epetra_MultiVector& Y) const {
00350   //
00351   // This function forms the product Y = A * Y or Y = A' * X
00352   //
00353 
00354   Epetra_SerialDenseVector Values(MaxNumEntries());
00355   Epetra_IntSerialDenseVector Indices(MaxNumEntries());
00356   int NumEntries;
00357 
00358   int NumVectors = X.NumVectors();
00359   if (NumVectors!=Y.NumVectors()) {
00360     EPETRA_CHK_ERR(-1); // Need same number of vectors in each MV
00361   }
00362 
00363   UpdateImportVector(NumVectors); // Make sure Import and Export Vectors are compatible
00364   UpdateExportVector(NumVectors);
00365 
00366   double ** Xp = (double**) X.Pointers();
00367   double ** Yp = (double**) Y.Pointers();
00368 
00369   if (!TransA) {
00370 
00371     // If we have a non-trivial importer, we must import elements that are permuted or are on other processors
00372     if (Importer()!=0) {
00373       EPETRA_CHK_ERR(ImportVector_->Import(X, *Importer(), Insert));
00374       Xp = (double**)ImportVector_->Pointers();
00375     }
00376 
00377     // If we have a non-trivial exporter, we must export elements that are permuted or belong to other processors
00378     if (Exporter()!=0) {
00379       Yp = (double**)ExportVector_->Pointers();
00380     }
00381 
00382     // Do actual computation
00383     for(int i = 0; i < NumMyRows_; i++) {
00384       EPETRA_CHK_ERR(ExtractMyRowCopy(i, MaxNumEntries(), NumEntries, Values.Values(), Indices.Values()));
00385       for (int k=0; k<NumVectors; k++) {
00386   double sum = 0.0;
00387   for(int j = 0; j < NumEntries; j++)
00388     sum += Values[j]*Xp[k][Indices[j]];
00389   Yp[k][i] = sum;
00390       }
00391     }
00392     
00393     if (Exporter()!=0) {
00394       Y.PutScalar(0.0);  // Make sure target is zero
00395       Y.Export(*ExportVector_, *Exporter(), Add); // Fill Y with Values from export vector
00396     }
00397     // Handle case of rangemap being a local replicated map
00398     if (!OperatorRangeMap().DistributedGlobal() && Comm().NumProc()>1) EPETRA_CHK_ERR(Y.Reduce());
00399   }
00400   else { // Transpose operation
00401     
00402 
00403     // If we have a non-trivial exporter, we must import elements that are permuted or are on other processors
00404 
00405     if (Exporter()!=0) {
00406       EPETRA_CHK_ERR(ExportVector_->Import(X, *Exporter(), Insert));
00407       Xp = (double**)ExportVector_->Pointers();
00408     }
00409 
00410     // If we have a non-trivial importer, we must export elements that are permuted or belong to other processors
00411     if (Importer()!=0) {
00412       Yp = (double**)ImportVector_->Pointers();
00413       ImportVector_->PutScalar(0.0);  // Make sure target is zero
00414     }
00415     else Y.PutScalar(0.0); // Make sure target is zero
00416 
00417     // Do actual computation
00418     for(int i = 0; i < NumMyRows_; i++) {
00419       EPETRA_CHK_ERR(ExtractMyRowCopy(i, MaxNumEntries(), NumEntries, Values.Values(), Indices.Values()));
00420       for (int k=0; k<NumVectors; k++) {
00421   double xtmp = Xp[k][i];
00422   for(int j = 0; j < NumEntries; j++)
00423     Yp[k][Indices[j]] += Values[j]*xtmp;
00424       }
00425     }
00426     
00427     if (Importer()!=0) {
00428       Y.PutScalar(0.0);  // Make sure target is zero
00429       EPETRA_CHK_ERR(Y.Export(*ImportVector_, *Importer(), Add)); // Fill Y with Values from export vector
00430     }
00431     // Handle case of rangemap being a local replicated map
00432     if (!OperatorDomainMap().DistributedGlobal() && Comm().NumProc()>1)  EPETRA_CHK_ERR(Y.Reduce());
00433   }
00434 
00435   UpdateFlops(2*NumVectors*NumGlobalNonzeros());
00436   return(0);
00437 }
00438 //=======================================================================================================
00439 void Epetra_BasicRowMatrix::UpdateImportVector(int NumVectors) const {
00440   if(Importer() != 0) {
00441     if(ImportVector_ != 0) {
00442       if(ImportVector_->NumVectors() != NumVectors) {
00443      delete ImportVector_;
00444      ImportVector_= 0;
00445       }
00446     }
00447     if(ImportVector_ == 0)
00448       ImportVector_ = new Epetra_MultiVector(Importer_->TargetMap(),NumVectors); // Create import vector if needed
00449   }
00450   return;
00451 }
00452 //=======================================================================================================
00453 void Epetra_BasicRowMatrix::UpdateExportVector(int NumVectors) const {
00454   if(Exporter() != 0) {
00455     if(ExportVector_ != 0) {
00456       if(ExportVector_->NumVectors() != NumVectors) {
00457      delete ExportVector_;
00458      ExportVector_= 0;
00459       }
00460     }
00461     if(ExportVector_ == 0)
00462       ExportVector_ = new Epetra_MultiVector(Exporter_->SourceMap(),NumVectors); // Create Export vector if needed
00463   }
00464   return;
00465 }
00466 
00467 //=======================================================================================================
00468 void Epetra_BasicRowMatrix::Print(ostream& os) const {
00469 
00470   int MyPID = RowMatrixRowMap().Comm().MyPID();
00471   int NumProc = RowMatrixRowMap().Comm().NumProc();
00472 
00473   for (int iproc=0; iproc < NumProc; iproc++) {
00474     if (MyPID==iproc) {
00475       if (MyPID==0) {
00476   os <<    "Number of Global Nonzeros     = "; os << NumGlobalNonzeros_; os << endl;
00477       }
00478       
00479       os <<  "\nNumber of My Rows               = "; os << NumMyRows_; os << endl;
00480       os <<    "Number of My Nonzeros           = "; os << NumMyNonzeros_; os << endl; os << endl;
00481       
00482       os << flush;
00483       
00484     }
00485     // Do a few global ops to give I/O a chance to complete
00486     Comm().Barrier();
00487     Comm().Barrier();
00488     Comm().Barrier();
00489   }
00490   
00491   for (int iproc=0; iproc < NumProc; iproc++) {
00492     if (MyPID==iproc) {
00493       if (MyPID==0) {
00494   os.width(8);
00495   os <<  "   Processor ";
00496   os.width(10);
00497   os <<  "   Row Index ";
00498   os.width(10);
00499   os <<  "   Col Index ";
00500   os.width(20);
00501   os <<  "   Value     ";
00502   os << endl;
00503       }
00504       Epetra_SerialDenseVector Values(MaxNumEntries());
00505       Epetra_IntSerialDenseVector Indices(MaxNumEntries());
00506       int NumEntries;
00507       
00508       for(int i = 0; i < NumMyRows_; i++) {
00509   ExtractMyRowCopy(i, MaxNumEntries(), NumEntries, Values.Values(), Indices.Values());
00510   int Row = RowMatrixRowMap().GID(i);; // Get global row number
00511   
00512   for (int j = 0; j < NumEntries ; j++) {   
00513     int Index = RowMatrixColMap().GID(Indices[j]);
00514     os.width(8);
00515     os <<  MyPID ; os << "    ";  
00516     os.width(10);
00517     os <<  Row ; os << "    ";  
00518     os.width(10);
00519     os <<  Index; os << "    ";
00520     os.width(20);
00521     os <<  Values[j]; os << "    ";
00522     os << endl;
00523   }
00524       }
00525     
00526       os << flush;
00527       
00528     }
00529     // Do a few global ops to give I/O a chance to complete
00530     Comm().Barrier();
00531     Comm().Barrier();
00532     Comm().Barrier();
00533   }
00534   
00535   return;
00536 }

Generated on Thu Sep 18 12:37:56 2008 for Epetra Package Browser (Single Doxygen Collection) by doxygen 1.3.9.1