Esempio n. 1
0
int GMGSolver::solve() {
  int rank = Teuchos::GlobalMPISession::getRank();
  
  // in place of doing the scaling ourselves, for the moment I've switched
  // over to using Aztec's built-in scaling.  This appears to be functionally identical.
  bool useAztecToScaleDiagonally = true;
  
  AztecOO solver(problem());
  
  Epetra_CrsMatrix *A = dynamic_cast<Epetra_CrsMatrix *>( problem().GetMatrix() );
  
  if (A == NULL) {
    cout << "Error: GMGSolver requires an Epetra_CrsMatrix.\n";
    TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Error: GMGSolver requires an Epetra_CrsMatrix.\n");
  }
  
//  EpetraExt::RowMatrixToMatlabFile("/tmp/A_pre_scaling.dat",*A);

//  Epetra_MultiVector *b = problem().GetRHS();
//  EpetraExt::MultiVectorToMatlabFile("/tmp/b_pre_scaling.dat",*b);

//  Epetra_MultiVector *x = problem().GetLHS();
//  EpetraExt::MultiVectorToMatlabFile("/tmp/x_initial_guess.dat",*x);
  
  const Epetra_Map* map = &A->RowMatrixRowMap();
  
  Epetra_Vector diagA(*map);
  A->ExtractDiagonalCopy(diagA);

//  EpetraExt::MultiVectorToMatlabFile("/tmp/diagA.dat",diagA);
//  
  Epetra_Vector scale_vector(*map);
  Epetra_Vector diagA_sqrt_inv(*map);
  Epetra_Vector diagA_inv(*map);
  
  if (_diagonalScaling && !useAztecToScaleDiagonally) {
    int length = scale_vector.MyLength();
    for (int i=0; i<length; i++) scale_vector[i] = 1.0 / sqrt(fabs(diagA[i]));

    problem().LeftScale(scale_vector);
    problem().RightScale(scale_vector);
  }
  
  Teuchos::RCP<Epetra_MultiVector> diagA_ptr = Teuchos::rcp( &diagA, false );

  _gmgOperator.setStiffnessDiagonal(diagA_ptr);
  
  _gmgOperator.setApplyDiagonalSmoothing(_diagonalSmoothing);
  _gmgOperator.setFineSolverUsesDiagonalScaling(_diagonalScaling);
  
  _gmgOperator.computeCoarseStiffnessMatrix(A);

  if (_diagonalScaling && useAztecToScaleDiagonally) {
    solver.SetAztecOption(AZ_scaling, AZ_sym_diag);
  } else {
    solver.SetAztecOption(AZ_scaling, AZ_none);
  }
  if (_useCG) {
    if (_computeCondest) {
      solver.SetAztecOption(AZ_solver, AZ_cg_condnum);
    } else {
      solver.SetAztecOption(AZ_solver, AZ_cg);
    }
  } else {
    solver.SetAztecOption(AZ_kspace, 200); // default is 30
    if (_computeCondest) {
      solver.SetAztecOption(AZ_solver, AZ_gmres_condnum);
    } else {
      solver.SetAztecOption(AZ_solver, AZ_gmres);
    }
  }
  
  solver.SetPrecOperator(&_gmgOperator);
//  solver.SetAztecOption(AZ_precond, AZ_none);
  solver.SetAztecOption(AZ_precond, AZ_user_precond);
  solver.SetAztecOption(AZ_conv, _azConvergenceOption);
//  solver.SetAztecOption(AZ_output, AZ_last);
  solver.SetAztecOption(AZ_output, _azOutput);
  
  int solveResult = solver.Iterate(_maxIters,_tol);
  
  const double* status = solver.GetAztecStatus();
  int remainingIters = _maxIters;

  int whyTerminated = status[AZ_why];
  int maxRestarts = 1;
  int numRestarts = 0;
  while ((whyTerminated==AZ_loss) && (numRestarts < maxRestarts)) {
    remainingIters -= status[AZ_its];
    if (rank==0) cout << "Aztec warned that the recursive residual indicates convergence even though the true residual is too large.  Restarting with the new solution as initial guess, with maxIters = " << remainingIters << endl;
    solveResult = solver.Iterate(remainingIters,_tol);
    whyTerminated = status[AZ_why];
    numRestarts++;
  }
  remainingIters -= status[AZ_its];
  _iterationCount = _maxIters - remainingIters;
  _condest = solver.Condest(); // will be -1 if running without condest
  
  if (rank==0) {
    switch (whyTerminated) {
      case AZ_normal:
//        cout << "whyTerminated: AZ_normal " << endl;
        break;
      case AZ_param:
        cout << "whyTerminated: AZ_param " << endl;
        break;
      case AZ_breakdown:
        cout << "whyTerminated: AZ_breakdown " << endl;
        break;
      case AZ_loss:
        cout << "whyTerminated: AZ_loss " << endl;
        break;
      case AZ_ill_cond:
        cout << "whyTerminated: AZ_ill_cond " << endl;
        break;
      case AZ_maxits:
        cout << "whyTerminated: AZ_maxits " << endl;
        break;
      default:
        break;
    }
  }
  
//  Epetra_MultiVector *x = problem().GetLHS();
//  EpetraExt::MultiVectorToMatlabFile("/tmp/x.dat",*x);
  
  if (_diagonalScaling && !useAztecToScaleDiagonally) {
    // reverse the scaling here
    scale_vector.Reciprocal(scale_vector);
    problem().LeftScale(scale_vector);
    problem().RightScale(scale_vector);
  }

  double norminf = A->NormInf();
  double normone = A->NormOne();
  
  int numIters = solver.NumIters();
  
  if (_printToConsole) {
    cout << "\n Inf-norm of stiffness matrix after scaling = " << norminf;
    cout << "\n One-norm of stiffness matrix after scaling = " << normone << endl << endl;
    cout << "Num iterations: " << numIters << endl;
  }
  
  _gmgOperator.setStiffnessDiagonal(Teuchos::rcp((Epetra_MultiVector*) NULL ));
  
  return solveResult;
}
Esempio n. 2
0
int test_azoo_scaling(Epetra_CrsMatrix& A,
                      Epetra_Vector& x,
                      Epetra_Vector& b,
                      bool verbose)
{
  Epetra_Vector vec1(x);
  Epetra_Vector vec2(x);
  Epetra_Vector diag(x);
  Epetra_Vector vec3(x);
  Epetra_Vector vec4(x);
  Epetra_Vector rhs(x);
  Epetra_Vector soln_none(x);
  Epetra_Vector soln_jacobi(x);
  Epetra_Vector soln_rowsum(x);
  Epetra_Vector soln_symdiag(x);

  vec1.PutScalar(1.0);

  A.Multiply(false, vec1, vec2);

  A.ExtractDiagonalCopy(diag);

  double* diag_vals = NULL;
  diag.ExtractView(&diag_vals);

  int* options = new int[AZ_OPTIONS_SIZE];
  double* params = new double[AZ_PARAMS_SIZE];
  AZ_defaults(options, params);

  options[AZ_output] = verbose ? 1 : AZ_none;

  options[AZ_scaling] = AZ_Jacobi;
  AztecOO::MatrixData mdata(&A);
  AZ_MATRIX* Amat = AZ_matrix_create(vec1.Map().NumMyElements());
  AZ_set_MATFREE(Amat, (void*)(&mdata), Epetra_Aztec_matvec);

  AZ_SCALING* scaling = AZ_scaling_create();

  double* xvals = NULL, *bvals = NULL;
  x.ExtractView(&xvals);
  b.ExtractView(&bvals);

  int err = AztecOO_scale_epetra(AZ_SCALE_MAT_RHS_SOL, Amat,
                                 options, bvals, xvals, NULL, scaling);
  if (err != 0) {
    if (verbose) {
      cout << "AztecOO_scale_epetra returned err="<<err<<endl;
    }
    return(err);
  }

  A.Multiply(false, vec1, vec3);

  vec4.Multiply(1.0, diag, vec3, 0.0);

  double vec2nrm, vec4nrm;

  vec2.Norm2(&vec2nrm);
  vec4.Norm2(&vec4nrm);

  if (fabs(vec2nrm - vec4nrm) > 1.e-6) {
    return(-1);
  }

  //now call the scaling function again, just to allow for
  //testing memory-leak issues.
  err = AztecOO_scale_epetra(AZ_SCALE_MAT_RHS_SOL, Amat,
                             options, bvals, xvals, NULL, scaling);
  if (err != 0) {
    if (verbose) {
      cout << "AztecOO_scale_epetra returned err="<<err<<endl;
    }
    return(err);
  }

  AztecOO_scale_epetra(AZ_DESTROY_SCALING_DATA, Amat, options,
                       bvals, xvals, NULL, scaling);

  x.PutScalar(1.0);

  Epetra_CrsMatrix* Atmp = create_and_fill_crs_matrix(A.RowMap());
  Atmp->Multiply(false, x, rhs);

  x.PutScalar(0.0);

  AztecOO azoo(&A, &x, &b);

  azoo.SetAztecOption(AZ_scaling, AZ_Jacobi);
  if (verbose) {
    azoo.SetAztecOption(AZ_output, 1);
  }
  else {
    azoo.SetAztecOption(AZ_output, AZ_none);
  }

  azoo.Iterate(100, 1.e-6);

  delete Atmp;

  Epetra_CrsMatrix* Atmp1 = create_and_fill_crs_matrix(A.RowMap());

  x.PutScalar(1.0);

  Atmp1->Multiply(false, x, rhs);

  soln_rowsum.PutScalar(0.0);

  AztecOO azoo1(Atmp1, &soln_rowsum, &rhs);

  azoo1.SetAztecOption(AZ_scaling, AZ_row_sum);

  azoo1.Iterate(100, 1.e-8);

  delete Atmp1;

  Epetra_CrsMatrix* Atmp2 = create_and_fill_crs_matrix(A.RowMap());

  x.PutScalar(1.0);

  Atmp2->Multiply(false, x, rhs);

  soln_symdiag.PutScalar(0.0);

  AztecOO azoo2(Atmp2, &soln_symdiag, &rhs);

  azoo2.SetAztecOption(AZ_scaling, AZ_sym_diag);

  azoo2.Iterate(100, 1.e-8);

  delete Atmp2;

  Epetra_CrsMatrix* Atmp3 = create_and_fill_crs_matrix(A.RowMap());

  x.PutScalar(1.0);

  Atmp3->Multiply(false, x, rhs);

  soln_none.PutScalar(0.0);

  AztecOO azoo3(Atmp3, &soln_none, &rhs);

  azoo3.SetAztecOption(AZ_scaling, AZ_none);

  azoo3.Iterate(100, 1.e-8);

  delete Atmp3;


  Epetra_CrsMatrix* Atmp4 = create_and_fill_crs_matrix(A.RowMap());

  x.PutScalar(1.0);

  Atmp4->Multiply(false, x, rhs);

  soln_jacobi.PutScalar(0.0);

  AztecOO azoo4(Atmp4, &soln_jacobi, &rhs);

  azoo4.SetAztecOption(AZ_scaling, AZ_Jacobi);

  azoo4.Iterate(100, 1.e-8);

  delete Atmp4;

  //at this point, soln_none, soln_jacobi, soln_rowsum and soln_symdiag
  //should be the same or at least close to the same, since the
  //matrix used in the solution has well-behaved coefficients.
  
  //form vec1 = soln_none - soln_rowsum
  vec1.PutScalar(0.0);
  vec1.Update(1.0, soln_none, 0.0);
  vec1.Update(-1.0, soln_rowsum, 1.0);

  double norm_check1= 0.0;
  vec1.Norm2(&norm_check1);

  //form vec2 = soln_none - soln_symdiag
  vec2.PutScalar(0.0);
  vec2.Update(1.0, soln_none, 0.0);
  vec2.Update(-1.0, soln_symdiag, 1.0);

  double norm_check2= 0.0;
  vec2.Norm2(&norm_check2);

  //form vec3 = soln_none - soln_jacobi
  vec3.PutScalar(0.0);
  vec3.Update(1.0, soln_none, 0.0);
  vec3.Update(-1.0, soln_jacobi, 1.0);

  double norm_check3= 0.0;
  vec3.Norm2(&norm_check3);


  if (std::abs(norm_check1) > 1.e-6) {
    if (verbose) {
      cerr << "AZ_row_sum scaling produced bad soln"
      << endl;
    }
    return(-1);
  }

  if (std::abs(norm_check2) > 1.e-6) {
    if (verbose) {
      cerr << "AZ_sym_diag scaling produced bad soln"
      << endl;
    }
    return(-1);
  }

  if (std::abs(norm_check3) > 1.e-6) {
    if (verbose) {
      cerr << "AZ_Jacobi scaling produced bad soln"
      << endl;
    }
    return(-1);
  }

  options[AZ_pre_calc] = AZ_reuse;

  err = AztecOO_scale_epetra(AZ_SCALE_MAT_RHS_SOL, Amat,
                             options, bvals, xvals, NULL, scaling);
  if (err == 0) {
    if (verbose) {
      cerr << "AztecOO_scale_epetra failed to return err when"
        << " asked to reuse non-existent scaling data."<<endl;
    }
    return(-1);
  }

  options[AZ_keep_info] = 1;
  options[AZ_pre_calc] = AZ_calc;
  err = AztecOO_scale_epetra(AZ_SCALE_MAT_RHS_SOL, Amat,
                             options, bvals, xvals, NULL, scaling);
  if (err != 0) {
    if (verbose) {
      cerr << "AztecOO_scale_epetra returned err=="<<err<<endl;
    }
    return(err);
  }

  options[AZ_keep_info] = 0;
  options[AZ_pre_calc] = AZ_reuse;
  err = AztecOO_scale_epetra(AZ_SCALE_MAT_RHS_SOL, Amat,
                             options, bvals, xvals, NULL, scaling);
  if (err != 0) {
    if (verbose) {
      cerr << "AztecOO_scale_epetra returned err=="<<err
          <<" when asked to reuse scaling data"<<endl;
    }
    return(err);
  }

  options[AZ_pre_calc] = AZ_calc;
  err = AztecOO_scale_epetra(AZ_DESTROY_SCALING_DATA, Amat,
                             options, bvals, xvals, NULL, scaling);
  if (err != 0) {
    if (verbose) {
      std::cerr << "AztecOO_scale_epetra returned err=="<<err
      << " when asked to destroy scaling data."<<std::endl;
    }
    return(err);
  }

  AZ_matrix_destroy(&Amat);
  delete [] options; 
  delete [] params;
  AZ_scaling_destroy(&scaling);

  AZ_manage_memory(0, AZ_CLEAR_ALL, 0, 0, 0);

  return(0);
}