int Ifpack_SORa::TCompute(){
  using std::cout;
  using std::endl;

  Epetra_Map *RowMap=const_cast<Epetra_Map*>(&A_->RowMatrixRowMap());
  Epetra_Vector Adiag(*RowMap);
  Epetra_CrsMatrix *Askew2=0, *Aherm2=0,*W=0;
  int *rowptr_s,*colind_s,*rowptr_h,*colind_h;
  double *vals_s,*vals_h;
  bool RowMatrixMode=(Acrs_==Teuchos::null);

  // Label
  sprintf(Label_, "IFPACK SORa (alpha=%5.2f gamma=%5.2f)",Alpha_,Gamma_);

  if(RowMatrixMode){
    if(!A_->Comm().MyPID()) cout<<"SORa: RowMatrix mode enabled"<<endl;
    // RowMatrix mode, build Acrs_ the hard way.
    Epetra_RowMatrix *Arow=&*A_;
    Epetra_Map *ColMap=const_cast<Epetra_Map*>(&A_->RowMatrixColMap());

    int Nmax=A_->MaxNumEntries();
    int length;
    std::vector<double> values(Nmax);
    Epetra_CrsMatrix *Acrs=new Epetra_CrsMatrix(Copy,*RowMap,Nmax);

        std::vector<int> indices_local(Nmax);
#ifndef EPETRA_NO_32BIT_GLOBAL_INDICES
        if(RowMap->GlobalIndicesInt()) {
      for(int i=0;i<Arow->NumMyRows();i++) {
        Arow->ExtractMyRowCopy(i,Nmax,length,&values[0],&indices_local[0]);
        for(int j=0;j<length;j++)
          indices_local[j]= ColMap->GID(indices_local[j]);
        Acrs->InsertGlobalValues(RowMap->GID(i),length,&values[0],&indices_local[0]);
      }
        }
        else
#endif
#ifndef EPETRA_NO_64BIT_GLOBAL_INDICES
    if(RowMap->GlobalIndicesLongLong()) {
      std::vector<int_type> indices_global(Nmax);
      for(int i=0;i<Arow->NumMyRows();i++) {
        Arow->ExtractMyRowCopy(i,Nmax,length,&values[0],&indices_local[0]);
        for(int j=0;j<length;j++)
          indices_global[j]= (int_type) ColMap->GID64(indices_local[j]);
        Acrs->InsertGlobalValues((int_type) RowMap->GID64(i),length,&values[0],&indices_global[0]);
      }
        }
        else
#endif
    throw "Ifpack_SORa::TCompute: GlobalIndices type unknown";

    Acrs->FillComplete(A_->OperatorDomainMap(),A_->OperatorRangeMap());
    Acrs_ = Teuchos::rcp (Acrs, true);
  }

  // Create Askew2
  // Note: Here I let EpetraExt do the thinking for me.  Since it gets all the maps correct for the E + F^T stencil.
  // There are probably more efficient ways to do this but this method has the bonus of allowing code reuse.
  IFPACK_CHK_ERR(EpetraExt::MatrixMatrix::Add(*Acrs_,false,1,*Acrs_,true,-1,Askew2));
  Askew2->FillComplete();

  // Create Aherm2
  IFPACK_CHK_ERR(EpetraExt::MatrixMatrix::Add(*Acrs_,false,1,*Acrs_,true,1,Aherm2));
  Aherm2->FillComplete();

  int nnz2=Askew2->NumMyNonzeros();
  int N=Askew2->NumMyRows();


  // Grab pointers
  IFPACK_CHK_ERR(Askew2->ExtractCrsDataPointers(rowptr_s,colind_s,vals_s));
  IFPACK_CHK_ERR(Aherm2->ExtractCrsDataPointers(rowptr_h,colind_h,vals_h));

  // Sanity checking: Make sure the sparsity patterns are the same
#define SANITY_CHECK
#ifdef SANITY_CHECK
  for(int i=0;i<N;i++)
    if(rowptr_s[i]!=rowptr_h[i]) IFPACK_CHK_ERR(-2);
  for(int i=0;i<nnz2;i++)
    if(colind_s[i]!=colind_h[i]) IFPACK_CHK_ERR(-3);
#endif

  // Dirichlet Detection & Nuking of Aherm2 and Askew2
  // Note: Relies on Aherm2/Askew2 having identical sparsity patterns (see sanity check above)
  if(HaveOAZBoundaries_){
    int numBCRows;
    int* dirRows=FindLocalDiricheltRowsFromOnesAndZeros(*Acrs_,numBCRows);
    Epetra_IntVector* dirCols=FindLocalDirichletColumnsFromRows(dirRows,numBCRows,*Aherm2);
    Apply_BCsToMatrixRowsAndColumns(dirRows,numBCRows,*dirCols,*Aherm2);
    Apply_BCsToMatrixRowsAndColumns(dirRows,numBCRows,*dirCols,*Askew2);
    delete [] dirRows;
    delete dirCols;
  }

  // Grab diagonal of A
  A_->ExtractDiagonalCopy(Adiag);

  // Allocate the diagonal for W
  Epetra_Vector *Wdiag = new Epetra_Vector(*RowMap);

  // Build the W matrix (lower triangle only)
  // Note: Relies on EpetraExt giving me identical sparsity patterns for both Askew2 and Aherm2 (see sanity check above)
  int maxentries=Askew2->MaxNumEntries();
  int_type* gids=new int_type [maxentries];
  double* newvals=new double[maxentries];
  W=new Epetra_CrsMatrix(Copy,*RowMap,0);
  for(int i=0;i<N;i++){
    // Build the - (1+alpha)/2 E - (1-alpha)/2 F part of the W matrix
    int_type rowgid = (int_type) Acrs_->GRID64(i);
    double c_data=0.0;
    double ipdamp=0.0;
    int idx=0;

    for(int j=rowptr_s[i];j<rowptr_s[i+1];j++){
      int_type colgid = (int_type) Askew2->GCID64(colind_s[j]);
      c_data+=fabs(vals_s[j]);
      if(rowgid>colgid){
        // Rely on the fact that off-diagonal entries are always numbered last, dropping the entry entirely.
        if(colind_s[j] < N) {
          gids[idx]=colgid;
          newvals[idx]=vals_h[j]/2 + Alpha_ * vals_s[j]/2;
          idx++;
        }
        else{
          ipdamp+=fabs(vals_h[j]/2 + Alpha_ * vals_s[j]/2);
        }
      }
    }
    if(idx>0)
      IFPACK_CHK_ERR(W->InsertGlobalValues(rowgid,idx,newvals,gids));

    // Do the diagonal
    double w_val= c_data*Alpha_*Gamma_/4 + Adiag[Acrs_->LRID(rowgid)];
    if(UseInterprocDamping_) w_val+=ipdamp;

    W->InsertGlobalValues(rowgid,1,&w_val,&rowgid);
    IFPACK_CHK_ERR(Wdiag->ReplaceGlobalValues(1,&w_val,&rowgid));
  }
  W->FillComplete(A_->OperatorDomainMap(),A_->OperatorRangeMap());
  W_= Teuchos::rcp(W);
  Wdiag_= Teuchos::rcp(Wdiag);

  // Mark as computed
  IsComputed_=true;

  // Global damping, if wanted
  if(UseGlobalDamping_) {
    PowerMethod(10,LambdaMax_);
    if(!A_->Comm().MyPID()) printf("SORa: Global damping parameter = %6.4e (lmax=%6.4e)\n",GetOmega(),LambdaMax_);
  }

  // Cleanup
  delete [] gids;
  delete [] newvals;
  delete Aherm2;
  delete Askew2;
  if(RowMatrixMode) {
    Acrs_=Teuchos::null;
  }

  // Counters
  NumCompute_++;
  ComputeTime_ += Time_.ElapsedTime();
  return 0;
}
Example #2
0
int MultiVectorTests(const Epetra_BlockMap & Map, int NumVectors, bool verbose)
{
  const Epetra_Comm & Comm = Map.Comm();
  int ierr = 0, i;
  double *residual = new double[NumVectors];

  Epetra_BLAS BLAS;
  /* get number of processors and the name of this processor */

  // int NumProc = Comm.getNumProc();
  int MyPID   = Comm.MyPID();

  // Construct MultiVectors

  Epetra_MultiVector A(Map, NumVectors);
  Epetra_MultiVector sqrtA(Map, NumVectors);
  Epetra_MultiVector B(Map, NumVectors);
  Epetra_MultiVector C(Map, NumVectors);
  Epetra_MultiVector C_alphaA(Map, NumVectors);
  Epetra_MultiVector C_alphaAplusB(Map, NumVectors);
  Epetra_MultiVector C_plusB(Map, NumVectors);
  Epetra_MultiVector Weights(Map, NumVectors);

  // Construct double vectors
  double *dotvec_AB   = new double[NumVectors];
  double *norm1_A     = new double[NumVectors];
  double *norm2_sqrtA = new double[NumVectors];
  double *norminf_A = new double[NumVectors];
  double *normw_A = new double[NumVectors];
  double *minval_A = new double[NumVectors];
  double *maxval_A = new double[NumVectors];
  double *meanval_A = new double[NumVectors];

  // Generate data


  EPETRA_TEST_ERR(C.Random(),ierr); // Fill C with random numbers.
  double alpha = 2.0;
  BuildMultiVectorTests (C,alpha, A, sqrtA, B, C_alphaA, C_alphaAplusB,
			     C_plusB, dotvec_AB, norm1_A, norm2_sqrtA, norminf_A,
			     normw_A, Weights, minval_A, maxval_A, meanval_A);

  int err = 0;
  if (verbose) cout << "XXXXX Testing alpha * A     ";
  // Test alpha*A
  Epetra_MultiVector alphaA(A); // Copy of A
  EPETRA_TEST_ERR(alphaA.Scale(alpha),err);
  EPETRA_TEST_ERR(alphaA.Update(-1.0, C_alphaA, 1.0),err);
  EPETRA_TEST_ERR(alphaA.Norm2(residual),err);

  if (err) ierr += err;
  else {
    EPETRA_TEST_ERR(BadResidual(verbose,residual, NumVectors),ierr);
  }

  err = 0;
  if (verbose) cout << "XXXXX Testing C = alpha * A + B      ";
  // Test alpha*A + B
  Epetra_MultiVector alphaAplusB(A); // Copy of A
  EPETRA_TEST_ERR(alphaAplusB.Update(1.0, B, alpha, A, 0.0),err);
  EPETRA_TEST_ERR(alphaAplusB.Update(-1.0, C_alphaAplusB, 1.0),err);
  EPETRA_TEST_ERR(alphaAplusB.Norm2(residual),err);

  if (err) ierr += err;
  else {
    EPETRA_TEST_ERR(BadResidual(verbose,residual, NumVectors),ierr);
  }

  err = 0;
  if (verbose) cout << "XXXXX Testing C += B      ";
  // Test + B
  Epetra_MultiVector plusB(C); // Copy of C
  EPETRA_TEST_ERR(plusB.Update(1.0, B, 1.0),err);
  EPETRA_TEST_ERR(plusB.Update(-1.0, C_plusB, 1.0),err);
  EPETRA_TEST_ERR(plusB.Norm2(residual),err);

  if (err) ierr += err;
  else {
    EPETRA_TEST_ERR(BadResidual(verbose,residual, NumVectors),ierr);
  }

  err = 0;
  if (verbose) cout << "XXXXX Testing A.dotProd(B)     ";
  // Test A.dotvec(B)
  double *dotvec = residual;
  EPETRA_TEST_ERR(A.Dot(B,dotvec),err);
  BLAS.AXPY(NumVectors,-1.0,dotvec_AB,dotvec);

  if (err) ierr += err;
  else {
    EPETRA_TEST_ERR(BadResidual(verbose,residual, NumVectors),ierr);
  }

  err = 0;
  if (verbose) cout << "XXXXX Testing norm1_A      ";
  // Test A.norm1()
  double *norm1 = residual;
  EPETRA_TEST_ERR(A.Norm1(norm1),err);
  BLAS.AXPY(NumVectors,-1.0,norm1_A,norm1);

  if (err) ierr += err;
  else {
    EPETRA_TEST_ERR(BadResidual(verbose,residual, NumVectors),ierr);
  }

  err = 0;
  if (verbose) cout << "XXXXX Testing norm2_sqrtA     ";
  // Test sqrtA.norm2()
  double *norm2 = residual;
  EPETRA_TEST_ERR(sqrtA.Norm2(norm2),err);
  BLAS.AXPY(NumVectors,-1.0,norm2_sqrtA,norm2);

  if (err) ierr += err;
  else {
    EPETRA_TEST_ERR(BadResidual(verbose,residual, NumVectors),ierr);
  }

  err = 0;
  if (verbose) cout << "XXXXX Testing norminf_A     ";
  // Test A.norminf()
  double *norminf = residual;
  EPETRA_TEST_ERR(A.NormInf(norminf),err);
  BLAS.AXPY(NumVectors,-1.0,norminf_A,norminf);

  if (err) ierr += err;
  else {
    EPETRA_TEST_ERR(BadResidual(verbose,residual, NumVectors),ierr);
  }

  err = 0;
  if (verbose) cout << "XXXXX Testing normw_A     ";
  // Test A.NormWeighted()
  double *normw = residual;
  EPETRA_TEST_ERR(A.NormWeighted(Weights, normw),err);
  BLAS.AXPY(NumVectors,-1.0,normw_A,normw);

  if (err) ierr += err;
  else {
    EPETRA_TEST_ERR(BadResidual(verbose,residual, NumVectors),ierr);
  }

  err = 0;
  if (verbose) cout << "XXXXX Testing minval_A     ";
  // Test A.MinValue()
  double *minval = residual;
  EPETRA_TEST_ERR(A.MinValue(minval),err);
  BLAS.AXPY(NumVectors,-1.0,minval_A,minval);

  if (err) ierr += err;
  else {
    EPETRA_TEST_ERR(BadResidual(verbose,residual, NumVectors),ierr);
  }

  err = 0;
  if (verbose) cout << "XXXXX Testing maxval_A     ";
  // Test A.MaxValue()
  double *maxval = residual;
  EPETRA_TEST_ERR(A.MaxValue(maxval),err);
  BLAS.AXPY(NumVectors,-1.0,maxval_A,maxval);

  if (err) ierr += err;
  else {
    EPETRA_TEST_ERR(BadResidual(verbose,residual, NumVectors),ierr);
  }

  err = 0;
  if (verbose) cout << "XXXXX Testing meanval_A     ";
  // Test A.MeanValue()
  double *meanval = residual;
  EPETRA_TEST_ERR(A.MeanValue(meanval),err);
  BLAS.AXPY(NumVectors,-1.0,meanval_A,meanval);

  if (err) ierr += err;
  else {
    EPETRA_TEST_ERR(BadResidual(verbose,residual, NumVectors),ierr);
  }

  err = 0;
  if (verbose) cout << "XXXXX Testing abs_A     ";
  // Test A.Abs()
  Epetra_MultiVector Abs_A = A;
  EPETRA_TEST_ERR(Abs_A.Abs(A),err);
  EPETRA_TEST_ERR(Abs_A.Update(1.0, A, -1.0),err); // Abs_A = A - Abs_A (should be zero since A > 0)
  EPETRA_TEST_ERR(Abs_A.Norm2(residual),err);

  if (err) ierr += err;
  else {
    EPETRA_TEST_ERR(BadResidual(verbose,residual, NumVectors),ierr);
  }

  err = 0;
  if (verbose) cout << "XXXXX Testing random_A (Test1) ";
  // Test A.Random()
  Epetra_MultiVector Rand1_A(A);
  Epetra_MultiVector Rand2_A(A);
  EPETRA_TEST_ERR(Rand1_A.Random(),err);
  EPETRA_TEST_ERR(Rand2_A.Random(),err);
  // Rand2_A = Rand1_A - Rand2_A (should be nonzero since Random() should give different vectors > 0)
  EPETRA_TEST_ERR(Rand2_A.Update(1.0, Rand1_A, -1.0),err);
  EPETRA_TEST_ERR(Rand2_A.Norm2(residual),err);

  if (err) ierr += err;
  else {
    EPETRA_TEST_ERR(BadResidual1(verbose,residual, NumVectors),ierr);
  }

  err = 0;
  if (verbose) cout << "XXXXX Testing random_A (Test2) ";

  // Next test that each column of the multivector is different from all other columns by testing the first value
  // of each vector against the first value of every other vector.
  int randvalsdiffer = 1; // Assume they all differ
  for (i=0; i< NumVectors; i++)
    for (int j=i+1; j<NumVectors; j++)
      if (Rand1_A[i][0]==Rand1_A[j][0]) randvalsdiffer = 0; // make false if equal
  int allrandvals = 0;
  Comm.MinAll(&randvalsdiffer, &allrandvals, 1); // get min of all values across all processors

  EPETRA_TEST_ERR(1-allrandvals, err); // If allrandvals is anything but 1, this will cause an error
  int locerr = err;
  Comm.MinAll(&locerr, &err, 1);

  if (verbose) {
    if (err==0) {
      cout << "\t Checked OK" << endl;
    } else {
      cout << "\t Checked Failed" << endl;
    }
  }
  err = 0;
  if (verbose) cout << "XXXXX Testing random_A (Test3) ";

  // Next test that the first element on each processor of the first column of Rand1_A is different from all others
  // First we will gather them all to PE 0


  Epetra_Map RandstartsMap(-1, 1, 0, Comm); // This Map has a single element on each PE
  int itmp = 0;
  int nproc = Comm.NumProc();
  if (MyPID==0) itmp = nproc;
  Epetra_Map AllrandstartsMap(nproc, itmp, 0, Comm); // Map has NumProc elements on PE 0, none elsewhere
  Epetra_MultiVector Randstarts(RandstartsMap, NumVectors);
  Epetra_MultiVector Allrandstarts(AllrandstartsMap, NumVectors);
  for (i=0; i< NumVectors; i++) Randstarts[i][0] = Rand1_A[i][0]; // Load first value of local multivector

  Epetra_Import Randimporter(AllrandstartsMap,RandstartsMap);
  EPETRA_TEST_ERR(Allrandstarts.Import(Randstarts,Randimporter,Insert),err);
  // cout << "Randstarts = " << Randstarts << endl << "Allrandstarts = " << Allrandstarts << endl;
  // Allrandstarts now contains the first values for each local section of Rand1_A.
  // Next test that this is true.
  randvalsdiffer = 1; // Assume they all differ
  if (MyPID==0) {
    for (i=0; i< NumVectors; i++)
      for (int irand=0; irand<nproc; irand++)
	for (int jrand=irand+1; jrand<nproc; jrand++)
	  if (Allrandstarts[i][irand]==Allrandstarts[i][jrand]) randvalsdiffer = 0; // make false if equal
  }
  allrandvals = 0;
  Comm.MinAll(&randvalsdiffer, &allrandvals, 1); // get min of all values across all processors

  EPETRA_TEST_ERR(1-allrandvals, err); // If allrandvals is anything but 1, this will cause an error
  locerr = err;
  Comm.MinAll(&locerr, &err, 1);
  if (verbose) {
    if (err==0) {
      cout << "\t Checked OK" << endl;
    } else {
      cout << "\t Checked Failed" << endl;
    }
  }

  // Delete everything

  delete [] dotvec_AB;
  delete [] norm1_A;
  delete [] norm2_sqrtA;
  delete [] norminf_A;
  delete [] normw_A;
  delete [] minval_A;
  delete [] maxval_A;
  delete [] meanval_A;
  delete [] residual;

  //*******************************************************************
  // Post-construction modification tests
  //*******************************************************************

  if (verbose) cout <<  "\n\nXXXXX Testing Post-construction modification of a multivector"
		    <<endl<<endl;

  err = 0;

  Epetra_MultiVector X(Map, NumVectors);
  X.Random();

  // Pick middle range values for GID, LID and Vector Index
  int testGID = Map.NumGlobalElements()/2;
  int testVecIndex = NumVectors/2;

  int GIDSize = 1;
  int LIDOfGID = 0;
  int FirstEntryOfGID = 0;

  if (Map.MyGID(testGID)) {
    LIDOfGID = Map.LID(testGID);
    GIDSize = Map.ElementSize(LIDOfGID);
    FirstEntryOfGID = Map.FirstPointInElement(LIDOfGID);
  }

  // ========================================================================
  // Test int ReplaceGlobalValue (int GlobalRow, int VectorIndex, double ScalarValue)
  // ========================================================================

  double newGIDValue = 4.0;
  locerr = X.ReplaceGlobalValue(testGID, testVecIndex, newGIDValue);

  if (Map.MyGID(testGID)) {
    if (X[testVecIndex][FirstEntryOfGID]!=newGIDValue) err++;
    if (verbose) cout << "X["<<testVecIndex<<"]["<<FirstEntryOfGID<<"] = "
		      <<  X[testVecIndex][FirstEntryOfGID]
		      << " should = " << newGIDValue << endl;
  }
  else
    if (locerr!=1) err++; // Test for GID out of range error (=1)

  // ========================================================================
  // Test int ReplaceGlobalValue (int GlobalRow, intBlockRowOffset, int VectorIndex, double ScalarValue)
  // ========================================================================
  newGIDValue = 8.0;
  locerr = X.ReplaceGlobalValue(testGID, GIDSize-1, testVecIndex, newGIDValue);

  if (Map.MyGID(testGID)) {
    if (X[testVecIndex][FirstEntryOfGID+GIDSize-1]!=newGIDValue) err++;
    if (verbose) cout << "X["<<testVecIndex<<"]["<<FirstEntryOfGID+GIDSize-1<<"] = "
		      <<  X[testVecIndex][FirstEntryOfGID+GIDSize-1]
		      << " should = " << newGIDValue << endl;
  }
  else
    if (locerr!=1) err++; // Test for GID out of range error (=1)

  // ========================================================================
  // Test int SumIntoGlobalValue (int GlobalRow, int VectorIndex, double ScalarValue)
  // ========================================================================

  newGIDValue = 1.0;
  locerr = X.ReplaceGlobalValue(testGID, testVecIndex, newGIDValue);
  locerr = X.SumIntoGlobalValue(testGID, testVecIndex, newGIDValue);
  if (Map.MyGID(testGID)) {
    if (X[testVecIndex][FirstEntryOfGID]!=(newGIDValue+newGIDValue)) err++;
    if (verbose) cout << "X["<<testVecIndex<<"]["<<FirstEntryOfGID<<"] = "
		      <<  X[testVecIndex][FirstEntryOfGID]
		      << " should = " << newGIDValue << endl;
  }
  else
    if (locerr!=1) err++; // Test for GID out of range error (=1)

  // ========================================================================
  // Test int SumIntoGlobalValue (int GlobalRow, intBlockRowOffset, int VectorIndex, double ScalarValue)
  // ========================================================================

  newGIDValue = 1.0;
  locerr = X.ReplaceGlobalValue(testGID, GIDSize-1, testVecIndex, newGIDValue);
  locerr = X.SumIntoGlobalValue(testGID, GIDSize-1, testVecIndex, newGIDValue);

  if (Map.MyGID(testGID)) {
    if (X[testVecIndex][FirstEntryOfGID+GIDSize-1]!=(newGIDValue+newGIDValue)) err++;
    if (verbose) cout << "X["<<testVecIndex<<"]["<<FirstEntryOfGID+GIDSize-1<<"] = "
		      <<  X[testVecIndex][FirstEntryOfGID+GIDSize-1]
		      << " should = " << newGIDValue << endl;
  }
  else
    if (locerr!=1) err++; // Test for GID out of range error (=1)

  // ========================================================================
  // Test Local "My" versions of same routine (less complicated)
  // ========================================================================

  // Pick middle range values for LID
  int testLID = Map.NumMyElements()/2;

  int LIDSize = Map.ElementSize(testLID);
  int FirstEntryOfLID = Map.FirstPointInElement(testLID);


  double newLIDValue = 4.0;
  locerr = X.ReplaceMyValue(testLID, testVecIndex, newLIDValue);

  if (X[testVecIndex][FirstEntryOfLID]!=newLIDValue) err++;
  if (verbose) cout << "X["<<testVecIndex<<"]["<<FirstEntryOfLID<<"] = "
		    <<  X[testVecIndex][FirstEntryOfLID]
		    << " should = " << newLIDValue << endl;

  newLIDValue = 8.0;
  locerr = X.ReplaceMyValue(testLID, LIDSize-1, testVecIndex, newLIDValue);
  if (X[testVecIndex][FirstEntryOfLID+LIDSize-1]!=newLIDValue) err++;
  if (verbose) cout << "X["<<testVecIndex<<"]["<<FirstEntryOfLID+LIDSize-1<<"] = "
		    <<  X[testVecIndex][FirstEntryOfLID+LIDSize-1]
		    << " should = " << newLIDValue << endl;
  newLIDValue = 1.0;
  locerr = X.ReplaceMyValue(testLID, testVecIndex, newLIDValue);
  locerr = X.SumIntoMyValue(testLID, testVecIndex, newLIDValue);
  if (X[testVecIndex][FirstEntryOfLID]!=(newLIDValue+newLIDValue)) err++;
  if (verbose) cout << "X["<<testVecIndex<<"]["<<FirstEntryOfLID<<"] = "
		    <<  X[testVecIndex][FirstEntryOfLID]
		    << " should = " << newLIDValue << endl;
  newLIDValue = 2.0;
  locerr = X.ReplaceMyValue(testLID, LIDSize-1, testVecIndex, newLIDValue);
  locerr = X.SumIntoMyValue(testLID, LIDSize-1, testVecIndex, newLIDValue);
  if (verbose) cout << "X["<<testVecIndex<<"]["<<FirstEntryOfLID+LIDSize-1<<"] = "
		    <<  X[testVecIndex][FirstEntryOfLID+LIDSize-1]
		    << " should = " << newLIDValue << endl;
  if (X[testVecIndex][FirstEntryOfLID+LIDSize-1]!=(newLIDValue+newLIDValue)) err++;

  ierr += err;

  // ========================================================================
  // Test Post-construction modification of an Epetra_Vector using a vector
  // our multivector X
  // ========================================================================

  if (verbose) cout <<  "\n\nXXXXX Testing Post-construction modification of a vector"
		    << endl << endl;

  Epetra_Vector * x = X(testVecIndex);

  int NumEntries = 2;
  double * VecValues = new double[NumEntries];
  int * VecGIDs = new int[NumEntries];
  VecGIDs[0] = testGID;
  VecGIDs[1] = testGID+1; // Some pathological chance that these GIDs are not valid

  // ========================================================================
  // Test int ReplaceGlobalValues (int NumEntries, double *Values, int *Indices)
  // ========================================================================

  VecValues[0] = 2.0; VecValues[1] = 4.0;
  locerr = x->ReplaceGlobalValues(NumEntries, VecValues, VecGIDs);

  for (i=0; i<NumEntries; i++) {
    testGID = VecGIDs[i];
    if (Map.MyGID(testGID)) {
      LIDOfGID = Map.LID(testGID);
      GIDSize = EPETRA_MIN(GIDSize,Map.ElementSize(LIDOfGID)); // Need this value below
      FirstEntryOfGID = Map.FirstPointInElement(LIDOfGID);
      if ((*x)[FirstEntryOfGID]!=VecValues[i]) err++;
      if (verbose) cout << "x["<<FirstEntryOfGID<<"] = "
			<< (*x)[FirstEntryOfGID]
			<< " should = " << VecValues[i] << endl;
    }
    else
      if (locerr!=1) err++; // Test for GID out of range error (=1)
  }


  // ========================================================================
  // Test int ReplaceGlobalValues (int NumEntries, int BlockOffset, double *Values, int *Indices)
  // ========================================================================

  VecValues[0] = 4.0; VecValues[1] = 8.0;
  locerr = x->ReplaceGlobalValues(NumEntries, GIDSize-1, VecValues, VecGIDs);

  for (i=0; i<NumEntries; i++) {
    testGID = VecGIDs[i];
    if (Map.MyGID(testGID)) {
      LIDOfGID = Map.LID(testGID);
      FirstEntryOfGID = Map.FirstPointInElement(LIDOfGID);
      if ((*x)[FirstEntryOfGID+GIDSize-1]!=VecValues[i]) err++;
      if (verbose) cout << "x["<<FirstEntryOfGID+GIDSize-1<<"] = "
			<< (*x)[FirstEntryOfGID+GIDSize-1]
			<< " should = " << VecValues[i] << endl;
    }
    else
      if (locerr!=1) err++; // Test for GID out of range error (=1)
  }

  // ========================================================================
  // Test int SumIntoGlobalValues (int NumEntries, double *Values, int *Indices)
  // ========================================================================

  VecValues[0] = 1.0; VecValues[1] = 2.0;
  locerr = x->ReplaceGlobalValues(NumEntries, VecValues, VecGIDs);
  locerr = x->SumIntoGlobalValues(NumEntries, VecValues, VecGIDs);

  for (i=0; i<NumEntries; i++) {
    testGID = VecGIDs[i];
    if (Map.MyGID(testGID)) {
      LIDOfGID = Map.LID(testGID);
      FirstEntryOfGID = Map.FirstPointInElement(LIDOfGID);
      if ((*x)[FirstEntryOfGID]!=(VecValues[i]+VecValues[i])) err++;
      if (verbose) cout << "x["<<FirstEntryOfGID<<"] = "
			<< (*x)[FirstEntryOfGID]
			<< " should = " << (VecValues[i]+VecValues[i]) << endl;
    }
    else
      if (locerr!=1) err++; // Test for GID out of range error (=1)
  }
  // ========================================================================
  // Test int ReplaceGlobalValues (int NumEntries, int BlockOffset, double *Values, int *Indices)
  // ========================================================================

  VecValues[0] = 1.0; VecValues[1] = 2.0;
  locerr = x->ReplaceGlobalValues(NumEntries, GIDSize-1, VecValues, VecGIDs);
  locerr = x->SumIntoGlobalValues(NumEntries, GIDSize-1, VecValues, VecGIDs);

  for (i=0; i<NumEntries; i++) {
    testGID = VecGIDs[i];
    if (Map.MyGID(testGID)) {
      LIDOfGID = Map.LID(testGID);
      FirstEntryOfGID = Map.FirstPointInElement(LIDOfGID);
      if ((*x)[FirstEntryOfGID+GIDSize-1]!=(VecValues[i]+VecValues[i])) err++;
      if (verbose) cout << "x["<<FirstEntryOfGID+GIDSize-1<<"] = "
			<< (*x)[FirstEntryOfGID+GIDSize-1]
			<< " should = " << (VecValues[i]+VecValues[i]) << endl;
    }
    else
      if (locerr!=1) err++; // Test for GID out of range error (=1)
  }

  // ========================================================================
  // Test Local "My" versions of same routine (less complicated)
  // ========================================================================
  int * VecLIDs = new int[NumEntries];
  VecLIDs[0] = testLID;
  VecLIDs[1] = testLID+1; // Some pathological chance that these LIDs are not valid

  VecValues[0] = 2.0; VecValues[1] = 4.0;
  locerr = x->ReplaceMyValues(NumEntries, VecValues, VecLIDs);

  for (i=0; i<NumEntries; i++) {
    testLID = VecLIDs[i];
    LIDSize = EPETRA_MIN(LIDSize,Map.ElementSize(testLID)); // Need this value below
    FirstEntryOfLID = Map.FirstPointInElement(testLID);
    if ((*x)[FirstEntryOfLID]!=VecValues[i]) err++;
    if (verbose) cout << "x["<<FirstEntryOfLID<<"] = "
		      << (*x)[FirstEntryOfLID]
		      << " should = " << VecValues[i] << endl;
  }

  VecValues[0] = 4.0; VecValues[1] = 8.0;
  locerr = x->ReplaceMyValues(NumEntries, LIDSize-1, VecValues, VecLIDs);

  for (i=0; i<NumEntries; i++) {
    testLID = VecLIDs[i];
    LIDSize = EPETRA_MIN(LIDSize,Map.ElementSize(testLID)); // Need this value below
    FirstEntryOfLID = Map.FirstPointInElement(testLID);
    if ((*x)[FirstEntryOfLID+LIDSize-1]!=VecValues[i]) err++;
    if (verbose) cout << "x["<<FirstEntryOfLID+LIDSize-1<<"] = "
		      << (*x)[FirstEntryOfLID+LIDSize-1]
		      << " should = " << VecValues[i] << endl;
  }

  VecValues[0] = 1.0; VecValues[1] = 1.0;
  locerr = x->ReplaceMyValues(NumEntries, VecValues, VecLIDs);
  locerr = x->SumIntoMyValues(NumEntries, VecValues, VecLIDs);

  for (i=0; i<NumEntries; i++) {
    testLID = VecLIDs[i];
    LIDSize = EPETRA_MIN(LIDSize,Map.ElementSize(testLID)); // Need this value below
    FirstEntryOfLID = Map.FirstPointInElement(testLID);
    if ((*x)[FirstEntryOfLID]!=(VecValues[i]+VecValues[i])) err++;
    if (verbose) cout << "x["<<FirstEntryOfLID<<"] = "
		      << (*x)[FirstEntryOfLID]
		      << " should = " << (VecValues[i]+VecValues[i]) << endl;
  }

  VecValues[0] = 2.0; VecValues[1] = 4.0;
  locerr = x->ReplaceMyValues(NumEntries, LIDSize-1, VecValues, VecLIDs);
  locerr = x->SumIntoMyValues(NumEntries, LIDSize-1, VecValues, VecLIDs);

  for (i=0; i<NumEntries; i++) {
    testLID = VecLIDs[i];
    LIDSize = EPETRA_MIN(LIDSize,Map.ElementSize(testLID)); // Need this value below
    FirstEntryOfLID = Map.FirstPointInElement(testLID);
    if ((*x)[FirstEntryOfLID+LIDSize-1]!=(VecValues[i]+VecValues[i])) err++;
    if (verbose) cout << "x["<<FirstEntryOfLID+LIDSize-1<<"] = "
		      << (*x)[FirstEntryOfLID+LIDSize-1]
		      << " should = " << (VecValues[i]+VecValues[i]) << endl;
  }

    delete [] VecValues;
    delete [] VecGIDs;
    delete [] VecLIDs;

  return(ierr);
}