Exemple #1
0
//-----------------------------------------------------------------------------
void EpetraVector::gather(std::vector<double>& x,
                          const std::vector<dolfin::la_index>& indices) const
{
  const std::size_t _size = indices.size();
  x.resize(_size);
  dolfin_assert(x.size() == _size);

  // Gather values into a vector
  EpetraVector y;
  this->gather(y, indices);

  dolfin_assert(y.size() == _size);
  const Epetra_FEVector& _y = *(y.vec());

  // Copy values into x
  for (std::size_t i = 0; i < _size; ++i)
    x[i] = (_y)[0][i];
}
//-----------------------------------------------------------------------------
std::size_t EpetraKrylovSolver::solve(EpetraVector& x, const EpetraVector& b)
{
  dolfin_assert(solver);
  dolfin_assert(_A);
  dolfin_assert(_P);

  // Check dimensions
  const std::size_t M = _A->size(0);
  const std::size_t N = _A->size(1);
  if (N != b.size())
  {
    dolfin_error("EpetraKrylovSolver.cpp",
                 "solve linear system using Epetra Krylov solver",
                 "Non-matching dimensions for linear system");
  }

  // Write a message
  const bool report = parameters["report"];
  if (report && dolfin::MPI::process_number() == 0)
    info("Solving linear system of size %d x %d (Epetra Krylov solver).", M, N);

  // Reinitialize solution vector if necessary
  if (x.size() != M)
  {
    _A->resize(x, 1);
    x.zero();
  }
  else if (!parameters["nonzero_initial_guess"])
    x.zero();

  // Create linear problem
  Epetra_LinearProblem linear_problem(_A->mat().get(), x.vec().get(),
                                      b.vec().get());
  // Set-up linear solver
  solver->SetProblem(linear_problem);

  // Set output level
  if (parameters["monitor_convergence"])
  {
    const std::size_t interval = parameters["monitor_interval"];
    solver->SetAztecOption(AZ_output, interval);
  }
  else
    solver->SetAztecOption(AZ_output, AZ_none);

  dolfin_assert(_P);
  _preconditioner->set(*this, *_P);

  // Set covergence check method
  solver->SetAztecOption(AZ_conv, AZ_rhs);

  // Start solve
  solver->Iterate(static_cast<int>(parameters["maximum_iterations"]),
                  parameters["relative_tolerance"]);

  // Check solve status
  const double* status = solver->GetAztecStatus();
  if ((int) status[AZ_why] != AZ_normal)
  {
    std::string errorDescription;
    if( status[AZ_why] == AZ_maxits )
      errorDescription = "maximum iters reached";
    else if( status[AZ_why] == AZ_loss )
      errorDescription = "loss of accuracy";
    else if( status[AZ_why] == AZ_ill_cond  )
      errorDescription = "ill-conditioned";
    else if( status[AZ_why] == AZ_breakdown )
      errorDescription = "breakdown";
    else
      errorDescription = "unknown error";

    std::stringstream message;
    message << "Epetra (AztecOO) Krylov solver (" << _method << ", " << _preconditioner->name() << ") "
            << "failed to converge after " << (int)status[AZ_its] << " iterations "
            << "(" << errorDescription << ", error code " << (int)status[AZ_why] << ")";

    if (parameters["error_on_nonconvergence"])
    {
      dolfin_error("EpetraKrylovSolver.cpp",
                   "solve linear system using Epetra Krylov solver",
                   message.str());
    }
    else
      warning(message.str());
  }
  else
  {
    info("Epetra (AztecOO) Krylov solver (%s, %s) converged in %d iterations.",
          _method.c_str(), _preconditioner->name().c_str(), solver->NumIters());
  }

  // Update residuals
  absolute_residual = solver->TrueResidual();
  relative_residual = solver->ScaledResidual();

  // Return number of iterations
  return solver->NumIters();
}