Exemple #1
0
// ====================================================================== 
void Eig(const Operator& Op, MultiVector& ER, MultiVector& EI)
{
  int ierr;
  if (Op.GetDomainSpace() != Op.GetRangeSpace())
    ML_THROW("Matrix is not square", -1);

  ER.Reshape(Op.GetDomainSpace());
  EI.Reshape(Op.GetDomainSpace());

  Epetra_LinearProblem Problem;
  Problem.SetOperator(const_cast<Epetra_RowMatrix*>(Op.GetRowMatrix()));
  Amesos_Lapack Lapack(Problem);

  Epetra_Vector ER_Epetra(Op.GetRowMatrix()->RowMatrixRowMap());
  Epetra_Vector EI_Epetra(Op.GetRowMatrix()->RowMatrixRowMap());

  ierr = Lapack.GEEV(ER_Epetra, EI_Epetra);

  if (ierr)
    ML_THROW("GEEV returned error code = " + GetString(ierr), -1);
  
  for (int i = 0 ; i < ER.GetMyLength() ; ++i) {
    ER(i) = ER_Epetra[i];
    EI(i) = EI_Epetra[i];
  }
}
Exemple #2
0
// ====================================================================== 
// FIXME: Add List
void Eigs(const Operator& A, int NumEigenvalues, 
          MultiVector& ER, MultiVector& EI)
{

  if (A.GetDomainSpace() != A.GetRangeSpace())
    ML_THROW("Input Operator is not square", -1);

  double time;

  time = GetClock();

  int length = NumEigenvalues;
  double tol = 1e-3;
  int restarts = 1;
  int output = 10;
  bool PrintStatus = true;

  // 1.- set parameters for Anasazi
  Teuchos::ParameterList AnasaziList;
  // MatVec should be either "A" or "ML^{-1}A"
  AnasaziList.set("eigen-analysis: matrix operation", "A");
  AnasaziList.set("eigen-analysis: use diagonal scaling", false);
  AnasaziList.set("eigen-analysis: symmetric problem", false);
  AnasaziList.set("eigen-analysis: length", length);
  AnasaziList.set("eigen-analysis: block-size",1);
  AnasaziList.set("eigen-analysis: tolerance", tol);
  AnasaziList.set("eigen-analysis: restart", restarts);
  AnasaziList.set("eigen-analysis: output", output);
  AnasaziList.get("eigen-analysis: print current status",PrintStatus);

  // data to hold real and imag for eigenvalues and eigenvectors
  Space ESpace(-1, NumEigenvalues);
  ER.Reshape(ESpace);
  EI.Reshape(ESpace);

  // this is the starting value -- random
  Epetra_MultiVector EigenVectors(A.GetRowMatrix()->OperatorDomainMap(),
                                  NumEigenvalues);
  EigenVectors.Random();
#ifdef HAVE_ML_ANASAxI
  //int NumRealEigenvectors, NumImagEigenvectors;
#endif

  AnasaziList.set("eigen-analysis: action", "LM");

#ifdef HAVE_ML_ANASAxI
  ML_THROW("fixme...", -1);
  /* FIXME
  ML_Anasazi::Interface(A.GetRowMatrix(),EigenVectors,ER.GetValues(),
			EI.GetValues(), AnasaziList, 0, 0,
			&NumRealEigenvectors, &NumImagEigenvectors, 0);
                        */
#else
  ML_THROW("Anasazi is no longer supported", -1);
#endif

  return;
}
Exemple #3
0
// ======================================================================
void Krylov(const Operator& A, const MultiVector& LHS,
            const MultiVector& RHS, const BaseOperator& Prec,
            Teuchos::ParameterList& List)
{
#ifndef HAVE_ML_AZTECOO
      std::cerr << "Please configure ML with --enable-aztecoo to use" << std::endl;
      std::cerr << "MLAPI Krylov solvers" << std::endl;
      exit(EXIT_FAILURE);
#else
  if (LHS.GetNumVectors() != 1)
    ML_THROW("FIXME: only one vector is currently supported", -1);

  Epetra_LinearProblem Problem;

  const Epetra_RowMatrix& A_Epetra = *(A.GetRowMatrix());

  Epetra_Vector LHS_Epetra(View,A_Epetra.OperatorDomainMap(),
                           (double*)&(LHS(0)));
  Epetra_Vector RHS_Epetra(View,A_Epetra.OperatorRangeMap(),
                           (double*)&(RHS(0)));

  // FIXME: this works only for Epetra-based operators
  Problem.SetOperator((const_cast<Epetra_RowMatrix*>(&A_Epetra)));
  Problem.SetLHS(&LHS_Epetra);
  Problem.SetRHS(&RHS_Epetra);

  AztecOO solver(Problem);

  EpetraBaseOperator Prec_Epetra(A_Epetra.OperatorDomainMap(),Prec);
  solver.SetPrecOperator(&Prec_Epetra);

  // get options from List
  int    NumIters = List.get("krylov: max iterations", 1550);
  double Tol      = List.get("krylov: tolerance", 1e-9);
  std::string type     = List.get("krylov: type", "gmres");
  int    output   = List.get("krylov: output level", GetPrintLevel());

  // set options in `solver'
  if (type == "cg")
    solver.SetAztecOption(AZ_solver, AZ_cg);
  else if (type == "cg_condnum")
    solver.SetAztecOption(AZ_solver, AZ_cg_condnum);
  else if (type == "gmres")
    solver.SetAztecOption(AZ_solver, AZ_gmres);
  else if (type == "gmres_condnum")
    solver.SetAztecOption(AZ_solver, AZ_gmres_condnum);
  else if (type == "fixed point")
    solver.SetAztecOption(AZ_solver, AZ_fixed_pt);
  else
    ML_THROW("krylov: type has incorrect value (" +
             type + ")", -1);

  solver.SetAztecOption(AZ_output, output);
  solver.Iterate(NumIters, Tol);
#endif

}
// ====================================================================== 
Operator GetPtent1D(const MultiVector& D, const int offset = 0)
{
  if (D.GetNumVectors() != 1)
    ML_THROW("D.GetNumVectors() != 1", -1);

  int size = D.GetMyLength();
  if (size == 0)
    ML_THROW("empty diagonal vector in input", -1);

  double* diag = new double[size];
  for (int i = 0 ; i < size ; ++i)
    diag[i] = D(i);

  // creates the ML operator and store the diag pointer,
  // as well as the function pointers
  ML_Operator* MLDiag = ML_Operator_Create(GetML_Comm());

  int invec_leng = size / 3 + size % 3;
  int outvec_leng = size;

  MLDiag->invec_leng = invec_leng;
  MLDiag->outvec_leng = outvec_leng;
  MLDiag->data = (void*)diag;
  MLDiag->data_destroy = Ptent1D_destroy;
  MLDiag->matvec->func_ptr = Ptent1D_matvec;

  MLDiag->matvec->ML_id = ML_NONEMPTY;
  MLDiag->matvec->Nrows = outvec_leng;
  MLDiag->from_an_ml_operator = 0;

  MLDiag->getrow->func_ptr = Ptent1D_getrows;

  MLDiag->getrow->ML_id = ML_NONEMPTY;
  MLDiag->getrow->Nrows = outvec_leng;

  // creates the domain space
  vector<int> MyGlobalElements(invec_leng);
  for (int i = 0 ; i < invec_leng ; ++i) 
    MyGlobalElements[i] = D.GetVectorSpace()(i * 3) / 3;
  Space DomainSpace(invec_leng, -1, &MyGlobalElements[0]);
  Space RangeSpace = D.GetVectorSpace();

  // creates the MLAPI wrapper
  Operator Diag(DomainSpace,RangeSpace,MLDiag,true);
  return(Diag);
}
int 
InverseOperator::Apply(const MultiVector& x, MultiVector& y) const
{
  ResetTimer();
  StackPush();

  if (GetDomainSpace() != x.GetVectorSpace())
    ML_THROW("DomainSpace and x.GetVectorSpace() differ", -1);

  if (GetRangeSpace() != y.GetVectorSpace())
    ML_THROW("RangeSpace and y.GetVectorSpace() differ", -1);

  int x_nv = x.GetNumVectors();
  int y_nv = y.GetNumVectors();
  double FL = 0.0;
  if (RCPData_ != Teuchos::null)
    FL = RCPData_->ComputeFlops();

  if (x_nv != y_nv)
    ML_THROW("Number of vectors of x and y differ (" +
             GetString(x_nv) + " vs. " + GetString(x_nv), -1);

  for (int v = 0 ; v < x_nv ; ++v) {

    Epetra_Vector x_Epetra(View,RowMatrix()->OperatorDomainMap(),
                           (double*)&(x(0,v)));
    Epetra_Vector y_Epetra(View,RowMatrix()->OperatorRangeMap(),
                           (double*)&(y(0,v)));

    if (RCPData_ != Teuchos::null)
      RCPData_->ApplyInverse(x_Epetra,y_Epetra);
    else if (RCPMLPrec_ != Teuchos::null)
      RCPMLPrec_->ApplyInverse(x_Epetra,y_Epetra);
    else
      ML_THROW("Neither Ifpack nor ML smoother is properly set up", -1);
  }

  StackPop();
  if (RCPData_ != Teuchos::null)
    UpdateFlops(RCPData_->ComputeFlops() - FL);
  UpdateTime();

  return(0);
}
// ======================================================================
MultiVector Extract(const MultiVector& y, const int v)
{
  if ((v < 0) || v >= y.GetNumVectors())
    ML_THROW("Wrong input parameter v (" +
             GetString(v) + ")", -1);

  MultiVector x(y.GetVectorSpace(), y.GetRCPValues(v));

  return(x);
}
// ======================================================================
MultiVector Redistribute(const MultiVector& y, const int NumEquations)
{
  StackPush();

  if (y.GetMyLength() % NumEquations)
    ML_THROW("NumEquations does not divide MyLength()", -1);

  if (y.GetNumVectors() != 1)
    ML_THROW("Redistribute() works with single vectors only", -1);

  Space NewSpace(y.GetMyLength() / NumEquations);

  MultiVector y2(NewSpace, NumEquations);

  for (int i = 0 ; i < y2.GetMyLength() ; ++i)
    for (int j = 0 ; j < NumEquations ; ++j)
      y2(i, j) = y(j + NumEquations * i);

  StackPop();

  return(y2);
}
// ======================================================================
MultiVector Duplicate(const MultiVector& y, const int v)
{
  if ((v < 0) || v >= y.GetNumVectors())
    ML_THROW("Wrong input parameter v (" +
             GetString(v) + ")", -1);

  // FIXME: use Extract
  MultiVector x(y.GetVectorSpace(), 1);
  for (int i = 0 ; i < x.GetMyLength() ; ++i)
    x(i) = y(i,v);

  return(x);
}
// ====================================================================== 
MultiVector GetDiagonal(const Operator& A, const int offset)
{
  // FIXME
  if (A.GetDomainSpace() != A.GetRangeSpace())
    ML_THROW("Currently only square matrices are supported", -1);

  MultiVector D(A.GetDomainSpace());
  D = 0.0;
  
  ML_Operator* matrix = A.GetML_Operator();

  if (matrix->getrow == NULL)
    ML_THROW("getrow() not set!", -1);

  int row_length;
  int allocated = 128;
  int*    bindx = (int    *)  ML_allocate(allocated*sizeof(int   ));
  double* val   = (double *)  ML_allocate(allocated*sizeof(double));

  for (int i = 0 ; i < matrix->getrow->Nrows; i++) {
    int GlobalRow = A.GetGRID(i);
    ML_get_matrix_row(matrix, 1, &i, &allocated, &bindx, &val,
                      &row_length, 0);
    for  (int j = 0; j < row_length; j++) {
      D(i) = 0.0;
      if (A.GetGCID(bindx[j]) == GlobalRow + offset) {
        D(i) = val[j];
        break;
      }
    }
  }

  ML_free(val);
  ML_free(bindx);
  return (D);

}
// ====================================================================== 
Operator GetScaledOperator(const Operator& A, const double alpha) 
{
  ML_Operator* ScaledA = 0;
  ScaledA = ML_Operator_ExplicitlyScale(A.GetML_Operator(),
                                        (double)alpha);

  if (ScaledA == 0)
    ML_THROW("ML_Operator_ExplicitlyScale returned 0", -1);

  Operator res;
  res.Reshape(A.GetDomainSpace(), A.GetRangeSpace(), ScaledA,
              true, A.GetRCPOperatorBox());
    
  return(res);
}
// ====================================================================== 
Operator GetDiagonal(const MultiVector& D)
{
  if (D.GetNumVectors() != 1)
    ML_THROW("D.GetNumVectors() != 1", -1);

  int size = D.GetMyLength();
  if (size == 0)
    ML_THROW("empty diagonal vector in input", -1);

  double* diag = new double[size];
  for (int i = 0 ; i < size ; ++i) 
    diag[i] = D(i);

  // creates the ML operator and store the diag pointer,
  // as well as the function pointers
  ML_Operator* MLDiag = ML_Operator_Create(GetML_Comm());

  MLDiag->invec_leng = size;
  MLDiag->outvec_leng = size;
  MLDiag->data = (void*)diag;
  MLDiag->matvec->func_ptr = diag_matvec;

  MLDiag->matvec->ML_id = ML_NONEMPTY;
  MLDiag->matvec->Nrows = size;
  MLDiag->from_an_ml_operator = 0;
  MLDiag->data_destroy = diag_destroy;

  MLDiag->getrow->func_ptr = diag_getrows;

  MLDiag->getrow->ML_id = ML_NONEMPTY;
  MLDiag->getrow->Nrows = size;

  // creates the MLAPI wrapper
  Operator Diag(D.GetVectorSpace(),D.GetVectorSpace(),MLDiag,true);
  return(Diag);
}
Exemple #12
0
// ====================================================================== 
double MaxEigAnasazi(const Operator& Op, const bool DiagonalScaling) 
{

  double MaxEigen = 0.0;

#if defined(HAVE_ML_EPETRA) && defined(HAVE_ML_ANASAxI) && defined(HAVE_ML_TEUCHOS)
  bool DiagScal;
  if (DiagonalScaling)
    DiagScal = ML_TRUE;
  else
    DiagScal = ML_FALSE;

  ML_Anasazi_Get_SpectralNorm_Anasazi(Op.GetML_Operator(), 0, 10, 1e-5,
                                      ML_FALSE, DiagScal, &MaxEigen);
#else
  //ML_THROW("Configure w/ --enable-epetra --enable-anasazi --enable-teuchos", -1);
  ML_THROW("Anasazi is no longer supported", -1);
#endif
  return(MaxEigen);
}
// ======================================================================
void GetPtent(const Operator& A, Teuchos::ParameterList& List,
              const MultiVector& ThisNS,
              Operator& Ptent, MultiVector& NextNS)
{
  std::string CoarsenType     = List.get("aggregation: type", "Uncoupled");
  /* old version
  int    NodesPerAggr    = List.get("aggregation: per aggregate", 64);
  */
  double Threshold       = List.get("aggregation: threshold", 0.0);
  int    NumPDEEquations = List.get("PDE equations", 1);

  ML_Aggregate* agg_object;
  ML_Aggregate_Create(&agg_object);
  ML_Aggregate_Set_MaxLevels(agg_object,2);
  ML_Aggregate_Set_StartLevel(agg_object,0);
  ML_Aggregate_Set_Threshold(agg_object,Threshold);
  //agg_object->curr_threshold = 0.0;

  ML_Operator* ML_Ptent = 0;
  ML_Ptent = ML_Operator_Create(GetML_Comm());

  if (ThisNS.GetNumVectors() == 0)
    ML_THROW("zero-dimension null space", -1);

  int size = ThisNS.GetMyLength();

  double* null_vect = 0;
  ML_memory_alloc((void **)(&null_vect), sizeof(double) * size * ThisNS.GetNumVectors(), "ns");

  int incr = 1;
  for (int v = 0 ; v < ThisNS.GetNumVectors() ; ++v)
    DCOPY_F77(&size, (double*)ThisNS.GetValues(v), &incr,
              null_vect + v * ThisNS.GetMyLength(), &incr);


  ML_Aggregate_Set_NullSpace(agg_object, NumPDEEquations,
                             ThisNS.GetNumVectors(), null_vect,
                             ThisNS.GetMyLength());

  if (CoarsenType == "Uncoupled")
    agg_object->coarsen_scheme = ML_AGGR_UNCOUPLED;
  else if (CoarsenType == "Uncoupled-MIS")
    agg_object->coarsen_scheme = ML_AGGR_HYBRIDUM;
  else if (CoarsenType == "MIS") {
   /* needed for MIS, otherwise it sets the number of equations to
    * the null space dimension */
    agg_object->max_levels  = -7;
    agg_object->coarsen_scheme = ML_AGGR_MIS;
  }
  else if (CoarsenType == "METIS")
    agg_object->coarsen_scheme = ML_AGGR_METIS;
  else {
    ML_THROW("Requested aggregation scheme (" + CoarsenType +
             ") not recognized", -1);
  }

  int NextSize = ML_Aggregate_Coarsen(agg_object, A.GetML_Operator(),
                                      &ML_Ptent, GetML_Comm());

  /* This is the old version
  int NextSize;

  if (CoarsenType == "Uncoupled") {
    NextSize = ML_Aggregate_CoarsenUncoupled(agg_object, A.GetML_Operator(),
  }
  else if (CoarsenType == "MIS") {
    NextSize = ML_Aggregate_CoarsenMIS(agg_object, A.GetML_Operator(),
                                       &ML_Ptent, GetML_Comm());
  }
  else if (CoarsenType == "METIS") {
    ML ml_object;
    ml_object.ML_num_levels = 1; // crap for line below
    ML_Aggregate_Set_NodesPerAggr(&ml_object,agg_object,0,NodesPerAggr);
    NextSize = ML_Aggregate_CoarsenMETIS(agg_object, A.GetML_Operator(),
                                         &ML_Ptent, GetML_Comm());
  }
  else {
    ML_THROW("Requested aggregation scheme (" + CoarsenType +
             ") not recognized", -1);
  }
  */

  ML_Operator_ChangeToSinglePrecision(ML_Ptent);

  int NumMyElements = NextSize;
  Space CoarseSpace(-1,NumMyElements);
  Ptent.Reshape(CoarseSpace,A.GetRangeSpace(),ML_Ptent,true);

  assert (NextSize * ThisNS.GetNumVectors() != 0);

  NextNS.Reshape(CoarseSpace, ThisNS.GetNumVectors());

  size = NextNS.GetMyLength();
  for (int v = 0 ; v < NextNS.GetNumVectors() ; ++v)
    DCOPY_F77(&size, agg_object->nullspace_vect + v * size, &incr,
              NextNS.GetValues(v), &incr);

  ML_Aggregate_Destroy(&agg_object);
  ML_memory_free((void**)(&null_vect));
}
// ======================================================================
void GetPtent(const Epetra_RowMatrix& A, Teuchos::ParameterList& List,
              double* thisns, Teuchos::RCP<Epetra_CrsMatrix>& Ptent,
              Teuchos::RCP<Epetra_MultiVector>& NextNS, const int domainoffset)
{
  const int nsdim = List.get<int>("null space: dimension",-1);
  if (nsdim<=0) ML_THROW("null space dimension not given",-1);
  const Epetra_Map& rowmap = A.RowMatrixRowMap();
  const int mylength = rowmap.NumMyElements();

  // wrap nullspace into something more handy
  Epetra_MultiVector ns(View,rowmap,thisns,mylength,nsdim);

  // vector to hold aggregation information
  Epetra_IntVector aggs(rowmap,false);

  // aggregation with global aggregate numbering
  int naggregates = GetGlobalAggregates(const_cast<Epetra_RowMatrix&>(A),List,thisns,aggs);

  // build a domain map for Ptent
  // find first aggregate on proc
  int firstagg = -1;
  int offset = -1;
  for (int i=0; i<mylength; ++i)
    if (aggs[i]>=0)
    {
      offset = firstagg = aggs[i];
      break;
    }
  offset *= nsdim;
  if (offset<0) ML_THROW("could not find any aggregate on proc",-2);
  std::vector<int> coarsegids(naggregates*nsdim);
  for (int i=0; i<naggregates; ++i)
    for (int j=0; j<nsdim; ++j)
    {
      coarsegids[i*nsdim+j] = offset + domainoffset;
      ++offset;
    }
  Epetra_Map pdomainmap(-1,naggregates*nsdim,&coarsegids[0],0,A.Comm());

  // loop aggregates and build ids for dofs
  std::map<int,std::vector<int> > aggdofs;
  std::map<int,std::vector<int> >::iterator fool;
  for (int i=0; i<naggregates; ++i)
  {
    std::vector<int> gids(0);
    aggdofs.insert(std::pair<int,std::vector<int> >(firstagg+i,gids));
  }
  for (int i=0; i<mylength; ++i)
  {
    if (aggs[i]<0) continue;
    std::vector<int>& gids = aggdofs[aggs[i]];
    gids.push_back(aggs.Map().GID(i));
  }

#if 0 // debugging output
  for (int proc=0; proc<A.Comm().NumProc(); ++proc)
  {
    if (proc==A.Comm().MyPID())
    {
      for (fool=aggdofs.begin(); fool!=aggdofs.end(); ++fool)
      {
        std::cout << "Proc " << proc << " Aggregate " << fool->first << " Dofs ";
        std::vector<int>& gids = fool->second;
        for (int i=0; i<(int)gids.size(); ++i) std::cout << gids[i] << " ";
        std::cout << std::endl;
      }
    }
    fflush(stdout);
    A.Comm().Barrier();
  }
#endif

  // coarse level nullspace to be filled
  NextNS = Teuchos::rcp(new Epetra_MultiVector(pdomainmap,nsdim,true));
  Epetra_MultiVector& nextns = *NextNS;

  // matrix Ptent
  Ptent = Teuchos::rcp(new Epetra_CrsMatrix(Copy,rowmap,nsdim));

  // loop aggregates and extract the appropriate slices of the nullspace.
  // do QR and assemble Q and R to Ptent and NextNS
  for (fool=aggdofs.begin(); fool!=aggdofs.end(); ++fool)
  {
    // extract aggregate-local junk of nullspace
    const int aggsize = (int)fool->second.size();
    Epetra_SerialDenseMatrix Bagg(aggsize,nsdim);
    for (int i=0; i<aggsize; ++i)
      for (int j=0; j<nsdim; ++j)
        Bagg(i,j) = (*ns(j))[ns.Map().LID(fool->second[i])];

    // Bagg = Q*R
    int m = Bagg.M();
    int n = Bagg.N();
    int lwork = n*10;
    int info = 0;
    int k = std::min(m,n);
    if (k!=n) ML_THROW("Aggregate too small, fatal!",-1);
    std::vector<double> work(lwork);
    std::vector<double> tau(k);
    Epetra_LAPACK lapack;
    lapack.GEQRF(m,n,Bagg.A(),m,&tau[0],&work[0],lwork,&info);
    if (info) ML_THROW("Lapack dgeqrf returned nonzero",info);
    if (work[0]>lwork)
    {
      lwork = (int)work[0];
      work.resize(lwork);
    }

    // get R (stored on Bagg) and assemble it into nextns
    int agg_cgid = fool->first*nsdim;
    if (!nextns.Map().MyGID(agg_cgid+domainoffset))
      ML_THROW("Missing coarse column id on this proc",-1);
    for (int i=0; i<n; ++i)
      for (int j=i; j<n; ++j)
        (*nextns(j))[nextns.Map().LID(domainoffset+agg_cgid+i)] = Bagg(i,j);

    // get Q and assemble it into Ptent
    lapack.ORGQR(m,n,k,Bagg.A(),m,&tau[0],&work[0],lwork,&info);
    if (info) ML_THROW("Lapack dorgqr returned nonzero",info);
    for (int i=0; i<aggsize; ++i)
    {
      const int actgrow = fool->second[i];
      for (int j=0; j<nsdim; ++j)
      {
        int actgcol = fool->first*nsdim+j+domainoffset;
        int errone = Ptent->SumIntoGlobalValues(actgrow,1,&Bagg(i,j),&actgcol);
        if (errone>0)
        {
          int errtwo = Ptent->InsertGlobalValues(actgrow,1,&Bagg(i,j),&actgcol);
          if (errtwo<0) ML_THROW("Epetra_CrsMatrix::InsertGlobalValues returned negative nonzero",errtwo);
        }
        else if (errone) ML_THROW("Epetra_CrsMatrix::SumIntoGlobalValues returned negative nonzero",errone);
      }
    } // for (int i=0; i<aggsize; ++i)
  } // for (fool=aggdofs.begin(); fool!=aggdofs.end(); ++fool)
  int err = Ptent->FillComplete(pdomainmap,rowmap);
  if (err) ML_THROW("Epetra_CrsMatrix::FillComplete returned nonzero",err);
  err = Ptent->OptimizeStorage();
  if (err) ML_THROW("Epetra_CrsMatrix::OptimizeStorage returned nonzero",err);

  return;
}
// ======================================================================
int GetAggregates(Epetra_RowMatrix& A, Teuchos::ParameterList& List,
                  double* thisns, Epetra_IntVector& aggrinfo)
{
  if (!A.RowMatrixRowMap().SameAs(aggrinfo.Map()))
    ML_THROW("map of aggrinfo must match row map of operator", -1);

  std::string CoarsenType     = List.get("aggregation: type", "Uncoupled");
  double Threshold       = List.get("aggregation: threshold", 0.0);
  int    NumPDEEquations = List.get("PDE equations", 1);
  int    nsdim           = List.get("null space: dimension",-1);
  if (nsdim==-1) ML_THROW("dimension of nullspace not set", -1);
  int size = A.RowMatrixRowMap().NumMyElements();

  ML_Aggregate* agg_object;
  ML_Aggregate_Create(&agg_object);
  ML_Aggregate_KeepInfo(agg_object,1);
  ML_Aggregate_Set_MaxLevels(agg_object,2);
  ML_Aggregate_Set_StartLevel(agg_object,0);
  ML_Aggregate_Set_Threshold(agg_object,Threshold);
  //agg_object->curr_threshold = 0.0;

  ML_Operator* ML_Ptent = 0;
  ML_Ptent = ML_Operator_Create(GetML_Comm());

  if (!thisns)
    ML_THROW("nullspace is NULL", -1);

  ML_Aggregate_Set_NullSpace(agg_object, NumPDEEquations,
                             nsdim, thisns,size);

  if (CoarsenType == "Uncoupled")
    agg_object->coarsen_scheme = ML_AGGR_UNCOUPLED;
  else if (CoarsenType == "Uncoupled-MIS")
    agg_object->coarsen_scheme = ML_AGGR_HYBRIDUM;
  else if (CoarsenType == "MIS") {
   /* needed for MIS, otherwise it sets the number of equations to
    * the null space dimension */
    agg_object->max_levels  = -7;
    agg_object->coarsen_scheme = ML_AGGR_MIS;
  }
  else if (CoarsenType == "METIS")
    agg_object->coarsen_scheme = ML_AGGR_METIS;
  else {
    ML_THROW("Requested aggregation scheme (" + CoarsenType +
             ") not recognized", -1);
  }

  ML_Operator* ML_A = ML_Operator_Create(GetML_Comm());
  ML_Operator_WrapEpetraMatrix(&A,ML_A);

  int NextSize = ML_Aggregate_Coarsen(agg_object, ML_A,
                                      &ML_Ptent, GetML_Comm());

  int* aggrmap = NULL;
  ML_Aggregate_Get_AggrMap(agg_object,0,&aggrmap);
  if (!aggrmap) ML_THROW("aggr_info not available", -1);

#if 0 // debugging
  fflush(stdout);
  for (int proc=0; proc<A.GetRowMatrix()->Comm().NumProc(); ++proc)
  {
    if (A.GetRowMatrix()->Comm().MyPID()==proc)
    {
      std::cout << "Proc " << proc << ":" << std::endl;
      std::cout << "aggrcount " << aggrcount << std::endl;
      std::cout << "NextSize " << NextSize << std::endl;
      for (int i=0; i<size; ++i)
        std::cout << "aggrmap[" << i << "] = " << aggrmap[i] << std::endl;
      fflush(stdout);
    }
    A.GetRowMatrix()->Comm().Barrier();
  }
#endif

  assert (NextSize * nsdim != 0);
  for (int i=0; i<size; ++i) aggrinfo[i] = aggrmap[i];

  ML_Aggregate_Destroy(&agg_object);

  return (NextSize/nsdim);
}
void InverseOperator::Reshape(const Operator& Op, const string Type,
             Teuchos::ParameterList& List, Teuchos::ParameterList* pushlist)
{
  ResetTimer();
  StackPush();

  Op_ = Op;

  RCPRowMatrix_ = Op.GetRCPRowMatrix();

  // FIXME: to add overlap and level-of-fill
  int NumSweeps   = List.get("smoother: sweeps", 1);
  double Damping  = List.get("smoother: damping factor", 0.67); 
  int LOF_ilu     = List.get("smoother: ilu fill", 0);
  double LOF_ict  = List.get("smoother: ilut fill", 1.0);
  double LOF_ilut = List.get("smoother: ict fill", 1.0);
  string reorder  = List.get("schwarz: reordering type","rcm");

  Teuchos::ParameterList IFPACKList;

  // any parameters from the main list List are overwritten by the pushlist
  IFPACKList.set("relaxation: sweeps", NumSweeps);
  IFPACKList.set("relaxation: damping factor", Damping);
  IFPACKList.set("fact: level-of-fill", LOF_ilu);
  IFPACKList.set("fact: ict level-of-fill", LOF_ict);
  IFPACKList.set("fact: ilut level-of-fill", LOF_ilut);
  IFPACKList.set("relaxation: zero starting solution", false);
  IFPACKList.set("schwarz: reordering type",reorder);
  IFPACKList.set("fact: relative threshold",1.0);

  // if present, the pushlist is assumed to be a preconstructed ifpack list
  // that is copied straight to the ifpack list here
  // entries in pushlist overwrite previous list entries
  if (pushlist)
    IFPACKList.setParameters(*pushlist);


  bool verbose = false; //(GetMyPID() == 0 && GetPrintLevel() > 5);

  // the ML smoother
  RCPMLPrec_ = Teuchos::null;
  // The Ifpack smoother
  Ifpack_Preconditioner* Prec = NULL;

  if (Type == "Jacobi") {
    if (verbose) {
      cout << "Damping factor = " << Damping 
        << ", sweeps = " << NumSweeps << endl;
      cout << endl;
    }
    IFPACKList.set("relaxation: type", "Jacobi");
    Prec = new Ifpack_PointRelaxation(RowMatrix());
  }
  else if (Type == "Gauss-Seidel") {
    if (verbose) {
      cout << "Damping factor = " << Damping 
        << ", sweeps = " << NumSweeps << endl;
      cout << endl;
    }
    IFPACKList.set("relaxation: type", "Gauss-Seidel");
    Prec = new Ifpack_PointRelaxation(RowMatrix());
  }
  else if (Type == "symmetric Gauss-Seidel") {
    if (verbose) {
      cout << "Damping factor = " << Damping 
        << ", sweeps = " << NumSweeps << endl;
      cout << endl;
    }
    IFPACKList.set("relaxation: type", "symmetric Gauss-Seidel");

    Prec = new Ifpack_PointRelaxation(RowMatrix());
  }
  else if (Type == "ILU") {
    if (verbose) {
      cout << "ILU factorization, ov = 0, no reordering, LOF = "
        << LOF_ilu << endl;
      cout << endl;
    }
    
    // use the Additive Schwarz class because it does reordering
    Prec = new Ifpack_AdditiveSchwarz<Ifpack_ILU>(RowMatrix());
  }
  else if (Type == "ILUT") {
    if (verbose) {
      cout << "ILUT factorization, ov = 0, no reordering, LOF = "
        << LOF_ilu << endl;
      cout << endl;
    }
    Prec = new Ifpack_ILUT(RowMatrix());
  }
  else if (Type == "IC") {
    if (verbose) {
      cout << "IC factorization, ov = 0, no reordering, LOF = "
        << LOF_ilu << endl;
      cout << endl;
    }
    Prec = new Ifpack_IC(RowMatrix());
  }
  else if (Type == "ICT") {
    if (verbose) {
      cout << "ICT factorization, ov = 0, no reordering, LOF = "
        << LOF_ilu << endl;
      cout << endl;
    }
    Prec = new Ifpack_ICT(RowMatrix());
  }
  else if (Type == "LU") {
    if (verbose) {
      cout << "LU factorization, ov = 0, local solver = KLU" << endl;
      cout << endl;
    }
    Prec = new Ifpack_AdditiveSchwarz<Ifpack_Amesos>(RowMatrix());
  }
  else if (Type == "Amesos" || Type == "Amesos-KLU")  {
    if (verbose) {
      cout << "Amesos-KLU direct solver" << endl;
      cout << endl;
    }
    Prec = new Ifpack_Amesos(RowMatrix());
  }
  else if (Type == "MLS" || Type == "ML MLS" || 
           Type == "ML symmetric Gauss-Seidel" ||
           Type == "ML Gauss-Seidel") 
  {
    if (verbose) {
      cout << "ML's MLS smoother" << endl;
      cout << endl;
      }
    Teuchos::ParameterList mlparams;
    ML_Epetra::SetDefaults("SA",mlparams);
    int output = List.get("ML output",-47);
    if (output == -47) output = List.get("output",-1);
    if (output != -1) mlparams.set("ML output",output);
    mlparams.set("max levels",1);
    int sweeps = List.get("smoother: sweeps",1);
    mlparams.set("coarse: sweeps",sweeps);
    double damp = List.get("smoother: damping factor",0.67);
    mlparams.set("coarse: damping factor",damp);
    mlparams.set("zero starting solution", false);
    if (Type == "MLS" || Type == "ML MLS")
    {
      mlparams.set("coarse: type","MLS"); // MLS symmetric Gauss-Seidel Amesos-KLU
      int poly = List.get("smoother: MLS polynomial order",3);
      mlparams.set("coarse: MLS polynomial order",poly);
    }
    else if (Type == "ML symmetric Gauss-Seidel")
      mlparams.set("coarse: type","symmetric Gauss-Seidel"); // MLS symmetric Gauss-Seidel Amesos-KLU
    else if (Type == "ML Gauss-Seidel")
      mlparams.set("coarse: type","Gauss-Seidel");
    else if (Type == "ML Jacobi")
      mlparams.set("coarse: type","Jacobi");
    else
      ML_THROW("Requested type (" + Type + ") not recognized", -1);
    RCPMLPrec_ = Teuchos::rcp(new ML_Epetra::MultiLevelPreconditioner(*RowMatrix(),mlparams,true));
  }
  else
    ML_THROW("Requested type (" + Type + ") not recognized", -1);

  if (Prec)
  {
    RCPData_ = Teuchos::rcp(Prec);
    RCPData_->SetParameters(IFPACKList);
    RCPData_->Initialize();
    RCPData_->Compute();
    UpdateFlops(RCPData_->InitializeFlops());
    UpdateFlops(RCPData_->ComputeFlops());
  }
  else 
    RCPData_ = Teuchos::null;
    
  StackPop();
  UpdateTime();

}