#include "Epetra_CrsMatrix.h"
#include "Epetra_InvOperator.h"
#include "Ifpack.h"
#ifdef HAVE_MPI
#include "Epetra_MpiComm.h"
#include <mpi.h>
#else
#include "Epetra_SerialComm.h"
#endif
#include "Epetra_Map.h"
#include "ModeLaplace2DQ2.h"
using namespace Anasazi;
int main(int argc, char *argv[]) {
#ifdef HAVE_MPI
  
  MPI_Init(&argc,&argv);
#endif
  
#ifdef HAVE_MPI
#else
#endif
  
  
  
  
  int    nev       = 10;
  int    blockSize = 10;
  int    numBlocks   = 4;
  int    maxRestarts = 100;
  double tol       = 1.0e-8;
  int numElements = 10;
  bool verbose = true;
  std::string which("SM");
  bool usePrec = true;
  double prec_dropTol = 1e-4;
  int prec_lofill = 0;
  cmdp.
setOption(
"nev",&nev,
"Number of eigenpairs to compted.");
 
  cmdp.
setOption(
"blockSize",&blockSize,
"Block size.");
 
  cmdp.
setOption(
"numBlocks",&numBlocks,
"Number of blocks in basis.");
 
  cmdp.
setOption(
"maxRestarts",&maxRestarts,
"Maximum number of restarts.");
 
  cmdp.
setOption(
"tol",&tol,
"Relative convergence tolerance.");
 
  cmdp.
setOption(
"numElements",&numElements,
"Number of elements in the discretization.");
 
  cmdp.
setOption(
"verbose",
"quiet",&verbose,
"Print messages and results.");
 
  cmdp.
setOption(
"sort",&which,
"Targetted eigenvalues (SM or LM).");
 
  cmdp.
setOption(
"usePrec",
"noPrec",&usePrec,
"Use Ifpack for preconditioning.");
 
  cmdp.
setOption(
"prec_dropTol",&prec_dropTol,
"Preconditioner: drop tolerance.");
 
  cmdp.
setOption(
"prec_lofill",&prec_lofill,
"Preconditioner: level of fill.");
 
#ifdef HAVE_MPI
    MPI_Finalize();
#endif
    return -1;
  }
  
  
  
  
  
  if (verbose) {
  }
  printer.
stream(
Errors) << Anasazi_Version() << std::endl << std::endl;
 
  
  
  
  
  
  
  
  
  printer.
stream(
Errors) << 
"Generating problem matrices..." << std::flush;
 
  
  const int space_dim = 2;
  
  std::vector<double> brick_dim( space_dim );
  brick_dim[0] = 1.0;
  brick_dim[1] = 1.0;
  
  std::vector<int> elements( space_dim );
  elements[0] = numElements;
  elements[1] = numElements;
  
    Teuchos::rcp( 
new ModeLaplace2DQ2(Comm, brick_dim[0], elements[0], brick_dim[1], elements[1]) );
 
  
  
  
  
  
  
  if (usePrec) {
    printer.
stream(
Errors) << 
"Constructing Incomplete Cholesky preconditioner..." << std::flush;
 
    Ifpack precFactory;
    
    std::string precType = "IC stand-alone";
    int overlapLevel = 0;
    
    precParams.
set(
"fact: drop tolerance",prec_dropTol);
 
    precParams.
set(
"fact: level-of-fill",prec_lofill);
 
    IFPACK_CHK_ERR(prec->SetParameters(precParams));
    IFPACK_CHK_ERR(prec->Initialize());
    IFPACK_CHK_ERR(prec->Compute());
    
      << " done." << std::endl;
    
  }
  
  
  
  
  
  
  ivec->Random();
  
  
  
  
  MyProblem->setHermitian(true);
  
  
  if (usePrec) {
    MyProblem->setPrec(PrecOp);
  }
  
  
  MyProblem->setNEV( nev );
  
  
  bool boolret = MyProblem->setProblem();
  if (boolret != true) {
    printer.
print(
Errors,
"Anasazi::BasicEigenproblem::setProblem() returned an error.\n");
 
#ifdef HAVE_MPI
    MPI_Finalize();
#endif
    return -1;
  }
  
  
  
  
  MyPL.
set( 
"Verbosity", verbosity );
 
  MyPL.
set( 
"Which", which );
 
  MyPL.
set( 
"Block Size", blockSize );
 
  MyPL.
set( 
"Num Blocks", numBlocks );
 
  MyPL.
set( 
"Maximum Restarts", maxRestarts );
 
  MyPL.
set( 
"Convergence Tolerance", tol );
 
  
  
  
  
  
  
  printer.
stream(
Errors) << 
"Solving eigenvalue problem..." << std::endl;
 
  
  if (usePrec) {
  }
  
  
  
  
  std::vector<Value<double> > evals = sol.
Evals;
 
  
  
  
  
  std::vector<double> normR(sol.
numVecs);
 
    for (
int i=0; i<sol.
numVecs; i++) {
 
      T(i,i) = evals[i].realpart;
    }
    K->
Apply( *evecs, Kvec );
 
    M->
Apply( *evecs, Mvec );
 
    MVT::MvTimesMatAddMv( -1.0, Mvec, T, 1.0, Kvec );
    MVT::MvNorm( Kvec, normR );
  }
  
  
  
  
  std::ostringstream os;
  os.setf(std::ios_base::right, std::ios_base::adjustfield);
  os<<
"Solver manager returned " << (returnCode == 
Converged ? 
"converged." : 
"unconverged.") << std::endl;
 
  os<<std::endl;
  os<<"------------------------------------------------------"<<std::endl;
  os<<std::setw(16)<<"Eigenvalue"
    <<std::setw(18)<<"Direct Residual"
    <<std::endl;
  os<<"------------------------------------------------------"<<std::endl;
  for (
int i=0; i<sol.
numVecs; i++) {
 
    os<<std::setw(16)<<evals[i].realpart
      <<std::setw(18)<<normR[i]/evals[i].realpart
      <<std::endl;
  }
  os<<"------------------------------------------------------"<<std::endl;
#ifdef HAVE_MPI
  MPI_Finalize();
#endif
  return 0;
}