/*----------------------------------------------------------------------*
 |  ctor (public)                                             m.gee 3/06|
 *----------------------------------------------------------------------*/
NLNML::NLNML_ConstrainedMultiLevelOperator::NLNML_ConstrainedMultiLevelOperator(
              RefCountPtr<ML_Epetra::MultiLevelOperator> ml_operator,
              RefCountPtr<NLNML::NLNML_CoarseLevelNoxInterface> coarseinterface,
              bool applyconstraints) :
comm_(ml_operator->Comm()),
coarseinterface_(coarseinterface),
ml_operator_(ml_operator),
applyconstraints_(applyconstraints)
{
  label_ = "NLNML_ConstrainedMultiLevelOperator";
  return;
}
//==============================================================================
Ifpack2_NodeFilter::Ifpack2_NodeFilter(const RefCountPtr<const Tpetra_RowMatrix>& Matrix,int nodeID) :
  Matrix_(Matrix),
  NumMyRows_(0),
  NumGlobalRows_(0),
  NumMyNonzeros_(0),
  MaxNumEntries_(0),
  MaxNumEntriesA_(0)
{
  sprintf(Label_,"%s","Ifpack2_NodeFilter");

  //ImportVector_=null;
  //ExportVector_=null;
  ImportVector_=0;
  ExportVector_=0;

  ovA_ = dynamic_cast<const Ifpack2_OverlappingRowMatrix*>(&*Matrix_);
  assert(ovA_ != 0);

  Acrs_=dynamic_cast<const Tpetra_CrsMatrix*>(&ovA_->A());

  NumMyRowsA_ = ovA_->A().NumMyRows();
  NumMyRowsB_ = ovA_->B().NumMyRows();
  
#ifdef HAVE_MPI
  const Tpetra_MpiComm *pComm = dynamic_cast<const Tpetra_MpiComm*>( &(Matrix->Comm()) );
  assert(pComm != NULL);
  MPI_Comm_split(pComm->Comm(),nodeID,pComm->MyPID(),&nodeMPIComm_);
  SubComm_ = rcp( new Tpetra_MpiComm(nodeMPIComm_) );
#else
  SubComm_ = rcp( new Tpetra_SerialComm );
#endif

  NumMyRows_ = Matrix->NumMyRows();
  SubComm_->SumAll(&NumMyRows_,&NumGlobalRows_,1);
  NumMyCols_ = Matrix->NumMyCols();

  // build row map, based on the local communicator
  try {
    const Tpetra_Map &globRowMap = Matrix->RowMatrixRowMap();
    int *myGlobalElts =  globRowMap.MyGlobalElements();
    int numMyElts = globRowMap.NumMyElements();
    Map_ = rcp( new Tpetra_Map(-1,numMyElts,myGlobalElts,globRowMap.IndexBase(),*SubComm_) );
  }
  catch(...) {
    printf("** * Ifpack2_NodeFilter ctor: problem creating row map * **\n\n");
  }


  // build the column map, but don't use a copy constructor, b/c local communicator SubComm_ is
  // different from that of Matrix.
  try {
    const Tpetra_Map &globColMap = Matrix->RowMatrixColMap();
    int *myGlobalElts =  globColMap.MyGlobalElements();
    int numMyElts = globColMap.NumMyElements();
    colMap_ = rcp( new Tpetra_Map(-1,numMyElts,myGlobalElts,globColMap.IndexBase(),*SubComm_) );
  }
  catch(...) {
    printf("** * Ifpack2_NodeFilter ctor: problem creating col map * **\n\n");
  }

  // NumEntries_ will contain the actual number of nonzeros
  // for each localized row (that is, without external nodes,
  // and always with the diagonal entry)
  NumEntries_.resize(NumMyRows_);

  // want to store the diagonal vector. FIXME: am I really useful?
  Diagonal_ = rcp( new Tpetra_Vector(*Map_) );
  if (Diagonal_ == Teuchos::null) IFPACK2_CHK_ERRV(-5);

  // store this for future access to ExtractMyRowCopy().
  // This is the # of nonzeros in the non-local matrix
  MaxNumEntriesA_ = Matrix->MaxNumEntries();
  // tentative value for MaxNumEntries. This is the number of
  // nonzeros in the local matrix
  MaxNumEntries_ = Matrix->MaxNumEntries();

  // ExtractMyRowCopy() will use these vectors
  Indices_.resize(MaxNumEntries_);
  Values_.resize(MaxNumEntries_);

  // now compute:
  // - the number of nonzero per row
  // - the total number of nonzeros
  // - the diagonal entries


  // CMS: [A|B]-Local to Overlap-Local Column Indices
  if(ovA_){
    Ac_LIDMap_=new int[ovA_->A().NumMyCols()+1];
    for(int i=0;i<ovA_->A().NumMyCols();i++) Ac_LIDMap_[i]=colMap_->LID(ovA_->A().RowMatrixColMap().GID(i));    
    Bc_LIDMap_=new int[ovA_->B().NumMyCols()+1];
    for(int i=0;i<ovA_->B().NumMyCols();i++) Bc_LIDMap_[i]=colMap_->LID(ovA_->B().RowMatrixColMap().GID(i));

    Ar_LIDMap_=new int[ovA_->A().NumMyRows()+1];
    for(int i=0;i<ovA_->A().NumMyRows();i++) Ar_LIDMap_[i]=Map_->LID(ovA_->A().RowMatrixRowMap().GID(i));    
    Br_LIDMap_=new int[ovA_->B().NumMyRows()+1];
    for(int i=0;i<ovA_->B().NumMyRows();i++) Br_LIDMap_[i]=Map_->LID(ovA_->B().RowMatrixRowMap().GID(i));

  }
  // end CMS


  // compute nonzeros (total and per-row), and store the
  // diagonal entries (already modified)
  int ActualMaxNumEntries = 0;

  for (int i = 0 ; i < NumMyRows_ ; ++i) {
    
    NumEntries_[i] = 0;
    int Nnz, NewNnz = 0;
    IFPACK2_CHK_ERRV(ExtractMyRowCopy(i,MaxNumEntries_,Nnz,&Values_[0],&Indices_[0]));

    for (int j = 0 ; j < Nnz ; ++j) {
      NewNnz++;
      if (Indices_[j] == i) (*Diagonal_)[i] = Values_[j];
    }

    if (NewNnz > ActualMaxNumEntries)
      ActualMaxNumEntries = NewNnz;

    NumMyNonzeros_ += NewNnz;
    NumEntries_[i] = NewNnz;

  }

  SubComm_->SumAll(&NumMyNonzeros_,&NumGlobalNonzeros_,1);
  MaxNumEntries_ = ActualMaxNumEntries;

  int gpid = Matrix->Comm().MyPID();
  int lpid = SubComm_->MyPID();

  Exporter_ = null;
  Importer_ = null;
  // Check if non-trivial import/export operators
  if (!(RowMatrixRowMap().SameAs(OperatorRangeMap()))) {
    try{Exporter_ = rcp(new Tpetra_Export(RowMatrixRowMap(), OperatorRangeMap()));}
    catch(...) {
      printf("** * gpid %d: Ifpack2_NodeFilter ctor: problem creating Exporter_ * **\n\n",gpid);
    }
  }
  //if (gpid > 1) sleep(8);
/*
  if (gpid == 0)
    printf(">>> node 0 <<<\n");
  if (gpid == 2)
    printf(">>> node 1 <<<\n");
  if (lpid == 0) 
    printf("=======================================\ntarget: RowMatrixColMap()\n====================================\n");
  cout << RowMatrixColMap() << endl;
  sleep(1);
  if (gpid == 0)
    printf("=======================================\nsource: OperatorDomainMap()\n=======================================\n");
  cout << OperatorDomainMap() << endl;
  sleep(1);
*/
/*
  if (!(RowMatrixColMap().SameAs(OperatorDomainMap()))) {
    //TODO change this to RCP
    try{Importer_ = new Tpetra_Import(RowMatrixColMap(), OperatorDomainMap());}
    catch(...) {
      printf("** * gpid %d: Ifpack2_NodeFilter ctor: problem creating Importer_ * **\n\n",gpid);
    }
*/



  if (!(*colMap_).SameAs(*Map_)) {
    //TODO change this to RCP
    try{Importer_ = rcp(new Tpetra_Import(*colMap_, *Map_));}
    catch(...) {
      printf("** * gpid %d: Ifpack2_NodeFilter ctor: problem creating Importer_ * **\n\n",gpid);
    }
/*
    if (lpid == 0)
    printf("=======================================\nIfpack2_NodeFilter Importer_ on node %d\n=======================================\n",(gpid == 0 ? 0: 1)); fflush(stdout);
    cout << *Importer_ << endl;
    if (lpid == 0)
    printf("=======================================\nIfpack2_NodeFilter colmap on node %d\n=======================================\n",(gpid == 0 ? 0: 1)); fflush(stdout);
    cout << *colMap_ << endl;
*/
  }

} //Ifpack2_NodeFilter() ctor