Exemplo n.º 1
0
int testTransposeSolve(
         int NumGlobalElements,
         int nRHS,
         double reltol,
         double abstol,
         Epetra_Comm& Comm,
         const Teuchos::RCP<LOCA::GlobalData>& globalData,
         const Teuchos::RCP<Teuchos::ParameterList>& paramList)
{
  int ierr = 0;

  double left_bc = 0.0;
  double right_bc = 1.0;
  double nonlinear_factor = 1.0;

  // Create the FiniteElementProblem class.  This creates all required
  // Epetra objects for the problem and allows calls to the
  // function (RHS) and Jacobian evaluation routines.
  Tcubed_FiniteElementProblem Problem(NumGlobalElements, Comm);

  // Get the vector from the Problem
  Epetra_Vector& soln = Problem.getSolution();

  // Initialize Solution
  soln.PutScalar(0.0);

  // Create and initialize the parameter vector
  LOCA::ParameterVector pVector;
  pVector.addParameter("Nonlinear Factor",nonlinear_factor);
  pVector.addParameter("Left BC", left_bc);
  pVector.addParameter("Right BC", right_bc);

  // Create the interface between the test problem and the nonlinear solver
  // This is created by the user using inheritance of the abstract base
  // class:
  Teuchos::RCP<Problem_Interface> interface =
    Teuchos::rcp(new Problem_Interface(Problem));
  Teuchos::RCP<LOCA::Epetra::Interface::Required> iReq = interface;
  Teuchos::RCP<NOX::Epetra::Interface::Jacobian> iJac = interface;

  // Create the Epetra_RowMatrixfor the Jacobian/Preconditioner
  Teuchos::RCP<Epetra_RowMatrix> Amat =
    Teuchos::rcp(&Problem.getJacobian(),false);

  // Get sublists
  Teuchos::ParameterList& nlParams = paramList->sublist("NOX");
  Teuchos::ParameterList& nlPrintParams = nlParams.sublist("Printing");
  Teuchos::ParameterList& dirParams = nlParams.sublist("Direction");
  Teuchos::ParameterList& newParams = dirParams.sublist("Newton");
  Teuchos::ParameterList& lsParams = newParams.sublist("Linear Solver");

  // Create the linear systems
  Teuchos::RCP<NOX::Epetra::LinearSystemAztecOO> linsys =
    Teuchos::rcp(new NOX::Epetra::LinearSystemAztecOO(nlPrintParams,
                              lsParams, iReq, iJac,
                              Amat, soln));

  // Create the loca vector
  NOX::Epetra::Vector locaSoln(soln);

  // Create the Group
  Teuchos::RCP<LOCA::Epetra::Group> grp_tp =
    Teuchos::rcp(new LOCA::Epetra::Group(globalData, nlPrintParams,
                     iReq, locaSoln,
                     linsys, pVector));

  // Create the Group
  Teuchos::RCP<LOCA::Epetra::Group> grp_lp =
    Teuchos::rcp(new LOCA::Epetra::Group(globalData, nlPrintParams,
                     iReq, locaSoln,
                     linsys, pVector));

  // Create the Group
  Teuchos::RCP<LOCA::Epetra::Group> grp_ep =
    Teuchos::rcp(new LOCA::Epetra::Group(globalData, nlPrintParams,
                     iReq, locaSoln,
                     linsys, pVector));

  // Change initial guess to a random vector
  Teuchos::RCP<NOX::Abstract::Vector> xnew =
    grp_tp->getX().clone();
  xnew->random();
  grp_tp->setX(*xnew);
  grp_lp->setX(*xnew);
  grp_ep->setX(*xnew);

  // Check some statistics on the solution
  Teuchos::RCP<NOX::TestCompare> testCompare =
    Teuchos::rcp(new NOX::TestCompare(globalData->locaUtils->out(),
                      *(globalData->locaUtils)));

  // Evaluate blocks
  grp_tp->computeF();
  grp_lp->computeF();
  grp_ep->computeF();
  grp_tp->computeJacobian();
  grp_lp->computeJacobian();
  grp_ep->computeJacobian();

    // Set up left- and right-hand sides
  Teuchos::RCP<NOX::Abstract::MultiVector> F =
    grp_tp->getX().createMultiVector(nRHS);
  F->random();
  Teuchos::RCP<NOX::Abstract::MultiVector> X_tp =
    F->clone(NOX::ShapeCopy);
  X_tp->init(0.0);
  Teuchos::RCP<NOX::Abstract::MultiVector> X_lp =
    F->clone(NOX::ShapeCopy);
  X_lp->init(0.0);
  Teuchos::RCP<NOX::Abstract::MultiVector> X_ep =
    F->clone(NOX::ShapeCopy);
  X_ep->init(0.0);

  // Set up residuals
  Teuchos::RCP<NOX::Abstract::MultiVector> R_tp =
    F->clone(NOX::ShapeCopy);
  Teuchos::RCP<NOX::Abstract::MultiVector> R_lp =
    F->clone(NOX::ShapeCopy);
  Teuchos::RCP<NOX::Abstract::MultiVector> R_ep =
    F->clone(NOX::ShapeCopy);

  // Set up linear solver lists
  Teuchos::ParameterList lsParams_tp = lsParams;
  Teuchos::ParameterList lsParams_lp = lsParams;
  Teuchos::ParameterList lsParams_ep = lsParams;
  lsParams_tp.set("Transpose Solver Method",
               "Transpose Preconditioner");
  lsParams_lp.set("Transpose Solver Method",
               "Left Preconditioning");
  lsParams_ep.set("Transpose Solver Method",
               "Explicit Transpose");

  NOX::Abstract::Group::ReturnType status;

  // Test transpose solve with transposed preconditioner
  if (globalData->locaUtils->isPrintType(NOX::Utils::TestDetails))
    globalData->locaUtils->out() << std::endl <<
      "\t***** " <<
      "Testing Transposed Preconditioner Residual" <<
      " *****" << std::endl;

  status = grp_tp->applyJacobianTransposeInverseMultiVector(lsParams_tp, *F,
                                *X_tp);
  if (status == NOX::Abstract::Group::Failed)
    ++ierr;
  status = grp_tp->applyJacobianTransposeMultiVector(*X_tp, *R_tp);
  ierr += testCompare->testMultiVector(*R_tp, *F, reltol, abstol,
                       "Residual");

  // Test transpose solve with transposed left-preconditioner
  if (lsParams.get("Preconditioner", "None") != "None") {
    if (globalData->locaUtils->isPrintType(NOX::Utils::TestDetails))
      globalData->locaUtils->out() << std::endl <<
    "\t***** " <<
    "Testing Transposed Left Preconditioner Residual" <<
    " *****" << std::endl;

    status = grp_lp->applyJacobianTransposeInverseMultiVector(lsParams_lp, *F,
                                  *X_lp);
    if (status == NOX::Abstract::Group::Failed)
      ++ierr;
    status = grp_lp->applyJacobianTransposeMultiVector(*X_lp, *R_lp);
    ierr += testCompare->testMultiVector(*R_lp, *F, reltol, abstol,
                     "Residual");
  }

#ifdef HAVE_NOX_EPETRAEXT
  // Test transpose solve with explicit preconditioner
  if (globalData->locaUtils->isPrintType(NOX::Utils::TestDetails))
    globalData->locaUtils->out() << std::endl <<
      "\t***** " <<
      "Testing Explicit Preconditioner Residual" <<
      " *****" << std::endl;

  status = grp_ep->applyJacobianTransposeInverseMultiVector(lsParams_ep, *F,
                                *X_ep);
  if (status == NOX::Abstract::Group::Failed)
    ++ierr;
  status = grp_ep->applyJacobianTransposeMultiVector(*X_ep, *R_ep);
  ierr += testCompare->testMultiVector(*R_ep, *F, reltol, abstol,
                       "Residual");
#endif


  // Compare solutions
  if (lsParams.get("Preconditioner", "None") != "None") {
    if (globalData->locaUtils->isPrintType(NOX::Utils::TestDetails))
      globalData->locaUtils->out() << std::endl <<
    "\t***** " <<
    "Comparing Transposed Preconditioner and Left Preconditioner Solutions"
                   <<
    " *****" << std::endl;
    ierr += testCompare->testMultiVector(*X_lp, *X_tp,
                     reltol, abstol, "Solution");
  }

#ifdef HAVE_NOX_EPETRAEXT
  if (globalData->locaUtils->isPrintType(NOX::Utils::TestDetails))
    globalData->locaUtils->out() << std::endl <<
      "\t***** " <<
      "Comparing Transposed Preconditioner and Explicit Preconditioner Solutions"
                 <<
      " *****" << std::endl;
  ierr += testCompare->testMultiVector(*X_ep, *X_tp,
                       reltol, abstol, "Solution");
#endif

  return ierr;
}
Exemplo n.º 2
0
int main( int argc, char **argv )
{

// check for parallel computation
#ifdef HAVE_MPI
  MPI_Init(&argc, &argv);
  Epetra_MpiComm Comm(MPI_COMM_WORLD);
#else
  Epetra_SerialComm Comm;
#endif


// define main parameters

  double c = 0.9999;           // continuation parameter
  int N = 50;                  // number of grid points
  int maxNewtonIters = 20;     // max number of Newton iterations
  int maxSteps = 50;           // max number of continuation steps taken
  int ilocal, iglobal;         // counter variables used for loops:
                               //   ilocal = counter for local elements on this processor;
                               //   iglobal = counter to signify global position across all procs 
  int Myele;                   // holds the number of elements on the processor

// Set flag for whether the computations will be Matrix-free (true) or will use a computed
//   Jacobian (false)
  bool doMatFree = false;      
   
// Create output file to save solutions
  ofstream outFile("Heq5.dat");
  outFile.setf(ios::scientific, ios::floatfield);
  outFile.precision(10);

// Define the problem class
  HeqProblem Problem(N,&Comm,outFile);
  
// Build initial guess.  The initial guess should be a solution vector x close to the 
//   bifurcation point.

  // Create the initial guess vector
  Epetra_Vector InitialGuess(Problem.GetMap());

  // Get the number of elements on this processor  
  Myele = Problem.GetMap().NumMyElements();

  // Compute the initial guess.  For this example, it is a line from (0,1) to (1,8/3)
  for (ilocal=0; ilocal<Myele; ilocal++) {
     iglobal=Problem.GetMap().GID(ilocal);
     InitialGuess[ilocal]= 1.0 + (5.0*iglobal)/(3.0*(N-1));
  }

// Create the null vector for the Jacobian (ie, J*v=0, used to solve the system of equations
//   f(x,p)=0; J*v=0; v0*v=1.  The solution of the system is [x*,v*,p*]. )
  Teuchos::RCP<NOX::Abstract::Vector> nullVec =
    Teuchos::rcp(new NOX::Epetra::Vector(InitialGuess));

  // Initialize to all ones
  nullVec->init(1.0);  
    // NOTE:  init is a function within the NOX::Abstract:Vector class which initializes every
    // value of the vector to the value within the parentheses (must be in 'double' format) 

// Create the top level parameter list
  Teuchos::RCP<Teuchos::ParameterList> ParamList = Teuchos::rcp(new Teuchos::ParameterList);

  // Create LOCA sublist
  Teuchos::ParameterList& locaParamsList = ParamList->sublist("LOCA");

  // Create the sublist for continuation and set the stepper parameters
  Teuchos::ParameterList& stepperList = locaParamsList.sublist("Stepper");
    //stepperList.set("Continuation Method", "Arc Length");// Default
    stepperList.set("Continuation Method", "Natural");
    stepperList.set("Continuation Parameter", "dummy");  // Must set
    stepperList.set("Initial Value", 999.0);             // Must set
    stepperList.set("Max Value", 50.0e4);             // Must set
    stepperList.set("Min Value", 0.0);             // Must set
    stepperList.set("Max Steps", maxSteps);                    // Should set
    stepperList.set("Max Nonlinear Iterations", maxNewtonIters); // Should set
    stepperList.set("Bordered Solver Method", "Bordering");

  //  Teuchos::ParameterList& nestedList = 
  //    stepperList.sublist("Nested Bordered Solver");
  //  nestedList.set("Bordered Solver Method", "Householder");
  //  nestedList.set("Include UV In Preconditioner", true);
  //  //nestedList.set("Use P For Preconditioner", true);
  //  nestedList.set("Preconditioner Method", "SMW");

// Set up parameters to compute Eigenvalues
#ifdef HAVE_LOCA_ANASAZI
  // Create Anasazi Eigensolver sublist (needs --with-loca-anasazi)
  stepperList.set("Compute Eigenvalues",true);
  Teuchos::ParameterList& aList = stepperList.sublist("Eigensolver");
  aList.set("Method", "Anasazi");
  aList.set("Block Size", 1);        // Size of blocks
  aList.set("Num Blocks", 20);       // Size of Arnoldi factorization
  aList.set("Num Eigenvalues", 5);   // Number of eigenvalues
  //  aList.set("Sorting Order", "SR");
  aList.set("Convergence Tolerance", 2.0e-7);          // Tolerance
  aList.set("Step Size", 1);         // How often to check convergence
  aList.set("Maximum Restarts",2);   // Maximum number of restarts
  aList.set("Verbosity",  
	    Anasazi::Errors + 
	    Anasazi::Warnings +
	    Anasazi::FinalSummary);        // Verbosity
#else
    stepperList.set("Compute Eigenvalues",false);
#endif
  
  // Create bifurcation sublist.  Note that for turning point continuation, the "type"
  //   is set to "Turning Point".  If not doing TP, type should be "None".
  Teuchos::ParameterList& bifurcationList = locaParamsList.sublist("Bifurcation");
  bifurcationList.set("Type", "Turning Point");
  bifurcationList.set("Bifurcation Parameter", "c");
  //  bifurcationList.set("Formulation", "Minimally Augmented");
  bifurcationList.set("Symmetric Jacobian", false); 
  bifurcationList.set("Update Null Vectors Every Continuation Step", true);
  bifurcationList.set("Update Null Vectors Every Nonlinear Iteration", false);
  bifurcationList.set("Transpose Solver Method","Explicit Transpose");
  //  bifurcationList.set("Transpose Solver Method","Transpose Preconditioner");
  //  bifurcationList.set("Transpose Solver Method","Left Preconditioning");
  bifurcationList.set("Initial Null Vector Computation", "Solve df/dp");
  //  bifurcationList.set("Initial A Vector", nullVec);      // minimally augmented
  //  bifurcationList.set("Initial B Vector", nullVec);      //minimally augmented
  
  //  bifurcationList.set("Bordered Solver Method", "Householder");
  //  bifurcationList.set("Include UV In Preconditioner", true);
  //  //bifurcationList.set("Use P For Preconditioner", true);
  //  bifurcationList.set("Preconditioner Method", "SMW");

  bifurcationList.set("Formulation", "Moore-Spence");
  bifurcationList.set("Solver Method", "Phipps Bordering"); // better for nearly singular matrices
  //  bifurcationList.set("Solver Method", "Salinger Bordering");   
  bifurcationList.set("Initial Null Vector", nullVec);
  bifurcationList.set("Length Normalization Vector", nullVec);

    // Create the sublist for the predictor
    Teuchos::ParameterList& predictorList = locaParamsList.sublist("Predictor");
    predictorList.set("Method", "Secant");         // Default
    // predictorList.set("Method", "Constant");     // Other options
    // predictorList.set("Method", "Tangent");      // Other options

    // Create step size sublist
    Teuchos::ParameterList& stepSizeList = locaParamsList.sublist("Step Size");
    stepSizeList.set("Method", "Adaptive");             // Default
    stepSizeList.set("Initial Step Size", 0.1);   // Should set
    stepSizeList.set("Min Step Size", 1.0e-6);    // Should set
    stepSizeList.set("Max Step Size", 1.0);      // Should set
    stepSizeList.set("Aggressiveness", 0.1);

// Set up NOX info
  Teuchos::ParameterList& nlParams = ParamList->sublist("NOX");

// Set the nonlinear solver method
  nlParams.set("Nonlinear Solver", "Line Search Based");

// Set the printing parameters in the "Printing" sublist.  This list determines how much
//   of the NOX information is output
  Teuchos::ParameterList& printParams = nlParams.sublist("Printing");
  printParams.set("MyPID", Comm.MyPID()); 
  printParams.set("Output Precision", 5);
  printParams.set("Output Processor", 0);
  printParams.set("Output Information", 
			NOX::Utils::OuterIteration + 
			NOX::Utils::OuterIterationStatusTest + 
			NOX::Utils::InnerIteration +
			NOX::Utils::LinearSolverDetails +
			NOX::Utils::Parameters + 
			NOX::Utils::Details + 
			NOX::Utils::Warning +
         NOX::Utils::StepperIteration +
         NOX::Utils::StepperDetails +
         NOX::Utils::StepperParameters);

  // NOX parameters - Sublist for line search 
  Teuchos::ParameterList& searchParams = nlParams.sublist("Line Search");
  searchParams.set("Method", "Backtrack");
  //  searchParams.set("Method", "Full Step");

  // Sublist for direction
  Teuchos::ParameterList& dirParams = nlParams.sublist("Direction");
  dirParams.set("Method", "Newton");

  Teuchos::ParameterList& newtonParams = dirParams.sublist("Newton");
  newtonParams.set("Forcing Term Method", "Constant");

  // Sublist for linear solver for the Newton method
  Teuchos::ParameterList& lsParams = newtonParams.sublist("Linear Solver");
  lsParams.set("Aztec Solver", "GMRES");  
  lsParams.set("Max Iterations", 800);  
  lsParams.set("Tolerance", 1e-8);
  lsParams.set("Output Frequency", 1);    
  lsParams.set("Preconditioner", "None");
  //  lsParams.set("Preconditioner", "AztecOO");
  //  lsParams.set("Aztec Preconditioner", "ilu"); 
  //  lsParams.set("Scaling", "None");
  //  lsParams.set("Scaling", "Row Sum");  
  lsParams.set("Compute Scaling Manually", false);
  //  lsParams.set("Preconditioner", "Ifpack");
  //  lsParams.set("Ifpack Preconditioner", "ILU");
  //  lsParams.set("Preconditioner", "New Ifpack");
  //  Teuchos::ParameterList& ifpackParams = lsParams.sublist("Ifpack");
  //  ifpackParams.set("fact: level-of-fill", 1);

// Set up the continuation parameter vector
  LOCA::ParameterVector p;
  p.addParameter("c",c);  
  p.addParameter("dummy",999.0);  

// Create the problem interface
  Teuchos::RCP<SimpleProblemInterface> interface = 
    Teuchos::rcp(new SimpleProblemInterface(&Problem,c) );

  Teuchos::RCP<LOCA::Epetra::Interface::Required> iReq = interface;

// Create the operator to hold either the Jacobian matrix or the Matrix-free operator
  Teuchos::RCP<Epetra_Operator> A;
  //  Teuchos::RCP<Epetra_RowMatrix> A;
  Teuchos::RCP<NOX::Epetra::Interface::Jacobian> iJac;

  // Need a NOX::Epetra::Vector for constructor
  // This becomes the initial guess vector that is used for the nonlinear solves
  NOX::Epetra::Vector noxInitGuess(InitialGuess, NOX::DeepCopy);   

  if (doMatFree) {
    // Matrix Free application (Epetra Operator):
    Teuchos::RCP<NOX::Epetra::MatrixFree> MF = 
      Teuchos::rcp(new NOX::Epetra::MatrixFree(printParams, interface, noxInitGuess)); 
    A = MF;
    iJac = MF;
  }
  else  {  // Computed Jacobian application
    A = Teuchos::rcp( Problem.GetMatrix(), false );
    iJac = interface;
  }
 
  // Create scaling object
  Teuchos::RCP<NOX::Epetra::Scaling> scaling = Teuchos::null;
  //   scaling = Teuchos::rcp(new NOX::Epetra::Scaling);
  //   Teuchos::RCP<Epetra_Vector> scalingVector = 
  //     Teuchos::rcp(new Epetra_Vector(soln.Map()));
  //   //scaling->addRowSumScaling(NOX::Epetra::Scaling::Left, scalingVector);
  //   scaling->addColSumScaling(NOX::Epetra::Scaling::Right, scalingVector);

  // Create transpose scaling object
  Teuchos::RCP<NOX::Epetra::Scaling> trans_scaling = Teuchos::null;
  //   trans_scaling = Teuchos::rcp(new NOX::Epetra::Scaling);
  //   Teuchos::RCP<Epetra_Vector> transScalingVector = 
  //     Teuchos::rcp(new Epetra_Vector(soln.Map()));
  //   trans_scaling->addRowSumScaling(NOX::Epetra::Scaling::Right, 
  // 				  transScalingVector);
  //   trans_scaling->addColSumScaling(NOX::Epetra::Scaling::Left, 
  // 				  transScalingVector);
    //bifurcationList.set("Transpose Scaling", trans_scaling);

// Build the linear system solver
  Teuchos::RCP<NOX::Epetra::LinearSystemAztecOO> linSys = 
    Teuchos::rcp(new NOX::Epetra::LinearSystemAztecOO(printParams, lsParams,
						      iReq,
						      iJac, A, 
                        noxInitGuess, scaling));            // use if scaling
//                        noxInitGuess));                     // use if no scaling

// Create the Loca (continuation) vector
  NOX::Epetra::Vector locaSoln(noxInitGuess);
  
  // Create Epetra Factory
  Teuchos::RCP<LOCA::Abstract::Factory> epetraFactory = Teuchos::rcp(new LOCA::Epetra::Factory);

  // Create global data object
  Teuchos::RCP<LOCA::GlobalData> globalData = LOCA::createGlobalData(ParamList, epetraFactory);
 
  // Create the Group - must be LOCA group
  Teuchos::RCP<LOCA::Epetra::Group> grpPtr = 
    Teuchos::rcp(new LOCA::Epetra::Group(globalData, printParams, 
					iReq, locaSoln, 
					linSys, p)); 

  // Calculate the first F(x0) as a starting point.  This is only needed for
  // certain status tests, to ensure that an initial residual (|r0|) is calculated
  grpPtr->computeF();

// Set up the status tests to check for convergence
  // Determines the error tolerance for the Newton solves 
  Teuchos::RCP<NOX::StatusTest::NormF> testNormF = 
    Teuchos::rcp(new NOX::StatusTest::NormF(1.0e-4));
  // Sets the max number of nonlinear (Newton) iterations that will be taken.  If this is not
  //   already set, it will default to the '20' given 
  Teuchos::RCP<NOX::StatusTest::MaxIters> testMaxIters = 
    Teuchos::rcp(new NOX::StatusTest::MaxIters(stepperList.get("Max Nonlinear Iterations", 20)));
// This combination of tests will be used by NOX to determine whether the step converged
  Teuchos::RCP<NOX::StatusTest::Combo> combo = 
    Teuchos::rcp(new NOX::StatusTest::Combo(NOX::StatusTest::Combo::OR, 
					    testNormF, testMaxIters));

// This is sample code to write and read parameters to/from a file.  Currently not activated! 
// To use, change the 'XXXHAVE_TEUCHOS_EXTENDED' TO 'HAVE_TEUCHOS_EXTENDED'
#ifdef XXXHAVE_TEUCHOS_EXTENDED
  // Write the parameter list to a file
  cout << "Writing parameter list to \"input.xml\"" << endl;
  Teuchos::writeParameterListToXmlFile(*ParamList, "input.xml");

  // Read in the parameter list from a file
  cout << "Reading parameter list from \"input.xml\"" << endl;
  Teuchos::RCP<Teuchos::ParameterList> paramList2 = 
    Teuchos::rcp(new Teuchos::ParameterList);
  Teuchos::updateParametersFromXmlFile("input.xml", paramList2.get());
  ParamList = paramList2;
#endif


// Create the stepper
  LOCA::Stepper stepper(globalData, grpPtr, combo, ParamList);
  LOCA::Abstract::Iterator::IteratorStatus status = stepper.run();
  
  // Check if the stepper completed
  if  (status == LOCA::Abstract::Iterator::Finished)
    globalData->locaUtils->out() << "\nAll tests passed!" << endl;
  else 
    if (globalData->locaUtils->isPrintType(NOX::Utils::Error))
      globalData->locaUtils->out() << "\nStepper failed to converge!"  << endl;

// Output the stepper parameter list info
  if (globalData->locaUtils->isPrintType(NOX::Utils::StepperParameters)) {
    globalData->locaUtils->out() << endl << "Final Parameters" << endl
    << "*******************" << endl;
    stepper.getList()->print(globalData->locaUtils->out());
    globalData->locaUtils->out() << endl;
  }

// Make sure all processors are done and close the output file
Comm.Barrier();
outFile.close();

// Deallocate memory
LOCA::destroyGlobalData(globalData);

#ifdef HAVE_MPI
  MPI_Finalize();
#endif
  return(EXIT_SUCCESS);
}  // DONE!!
Exemplo n.º 3
0
int main( int argc, char **argv )
{

// check for parallel computation
#ifdef HAVE_MPI
  MPI_Init(&argc, &argv);
  Epetra_MpiComm Comm(MPI_COMM_WORLD);
#else
  Epetra_SerialComm Comm;
#endif


// define main parameters

  double c = 0.25;             // continuation parameter
  int N = 50;                  // number of grid points
  int maxNewtonIters = 20;     // max number of Newton iterations
  int maxSteps = 75;           // max number of continuation steps taken

// Set flag for whether the computations will be Matrix-free (true) or will use a computed
//   Jacobian (false)
  bool doMatFree = false;      
      
// Create output file to save solutions
  ofstream outFile("Heq4.dat");
  outFile.setf(ios::scientific, ios::floatfield);
  outFile.precision(10);

// Define the problem class
  HeqProblem Problem(N,&Comm,outFile);
  
// Create the initial guess vector and set it to all ones
  Epetra_Vector InitialGuess(Problem.GetMap());
  InitialGuess.PutScalar(1.0);     

// Create the top level parameter list
  Teuchos::RCP<Teuchos::ParameterList> ParamList = Teuchos::rcp(new Teuchos::ParameterList);

  // Create LOCA sublist
  Teuchos::ParameterList& locaParamsList = ParamList->sublist("LOCA");

  // Create the sublist for continuation and set the stepper parameters
  Teuchos::ParameterList& stepperList = locaParamsList.sublist("Stepper");
  stepperList.set("Continuation Method", "Arc Length");// Default
  // stepperList.set("Continuation Method", "Natural");
  stepperList.set("Continuation Parameter", "c");  // Must set
  stepperList.set("Initial Value", c);             // Must set
  stepperList.set("Max Value", 100.0);             // Must set
  stepperList.set("Min Value", 0.0);             // Must set
  stepperList.set("Max Steps", maxSteps);                    // Should set
  stepperList.set("Max Nonlinear Iterations", maxNewtonIters); // Should set

// Set up parameters to compute Eigenvalues
#ifdef HAVE_LOCA_ANASAZI
  // Create Anasazi Eigensolver sublist (needs --with-loca-anasazi)
  stepperList.set("Compute Eigenvalues",true);
  Teuchos::ParameterList& aList = stepperList.sublist("Eigensolver");
  aList.set("Method", "Anasazi");
  aList.set("Block Size", 1);        // Size of blocks
  aList.set("Num Blocks", 20);       // Size of Arnoldi factorization
  aList.set("Num Eigenvalues", 5);   // Number of eigenvalues
  //  aList.set("Sorting Order", "SR");
  aList.set("Convergence Tolerance", 2.0e-7);          // Tolerance
  aList.set("Step Size", 1);         // How often to check convergence
  aList.set("Maximum Restarts",2);   // Maximum number of restarts
  aList.set("Verbosity",  
	    Anasazi::Errors + 
	    Anasazi::Warnings +
	    Anasazi::FinalSummary);        // Verbosity
#else
    stepperList.set("Compute Eigenvalues",false);
#endif
 
    stepperList.set("Bordered Solver Method", "Householder");
//    stepperList.set("Bordered Solver Method", "Bordering");

  //  Teuchos::ParameterList& nestedList = 
  //    stepperList.sublist("Nested Bordered Solver");
  //  nestedList.set("Bordered Solver Method", "Householder");
  //  nestedList.set("Include UV In Preconditioner", true);
  //  //nestedList.set("Use P For Preconditioner", true);
  //  nestedList.set("Preconditioner Method", "SMW");

 
// Create bifurcation sublist -- use if not doing turning point
  Teuchos::ParameterList& bifurcationList = locaParamsList.sublist("Bifurcation");
  bifurcationList.set("Type", "None");                 // Default

  // Create predictor sublist
  Teuchos::ParameterList& predictorList = locaParamsList.sublist("Predictor");
  predictorList.set("Method", "Secant");               // Default
  // predictorList.set("Method", "Constant");     // Other options
  // predictorList.set("Method", "Tangent");      // Other options

  // Create step size sublist
  Teuchos::ParameterList& stepSizeList = locaParamsList.sublist("Step Size");
  stepSizeList.set("Method", "Adaptive");             // Default
  stepSizeList.set("Initial Step Size", 0.1);   // Should set
  stepSizeList.set("Min Step Size", 1.0e-4);    // Should set
  stepSizeList.set("Max Step Size", 1.0);      // Should set
  stepSizeList.set("Aggressiveness", 0.1);

  // Set up NOX info
  Teuchos::ParameterList& nlParams = ParamList->sublist("NOX");

  // Set the nonlinear solver method
  nlParams.set("Nonlinear Solver", "Line Search Based");

  // Set the printing parameters in the "Printing" sublist
  Teuchos::ParameterList& printParams = nlParams.sublist("Printing");
  printParams.set("MyPID", Comm.MyPID()); 
  printParams.set("Output Precision", 5);
  printParams.set("Output Processor", 0);
  printParams.set("Output Information", 
			NOX::Utils::OuterIteration + 
			NOX::Utils::OuterIterationStatusTest + 
			NOX::Utils::InnerIteration +
			NOX::Utils::LinearSolverDetails +
			NOX::Utils::Parameters + 
			NOX::Utils::Details + 
			NOX::Utils::Warning +
         NOX::Utils::StepperIteration +
         NOX::Utils::StepperDetails +
         NOX::Utils::StepperParameters);


  // NOX parameters - Sublist for line search 
  Teuchos::ParameterList& searchParams = nlParams.sublist("Line Search");
  searchParams.set("Method", "Full Step");
//  searchParams.set("Method", "Backtrack");

  // Sublist for direction
  Teuchos::ParameterList& dirParams = nlParams.sublist("Direction");
  dirParams.set("Method", "Newton");

  Teuchos::ParameterList& newtonParams = dirParams.sublist("Newton");
  newtonParams.set("Forcing Term Method", "Constant");

  // Sublist for linear solver for the Newton method
  Teuchos::ParameterList& lsParams = newtonParams.sublist("Linear Solver");
  lsParams.set("Aztec Solver", "GMRES");  
  lsParams.set("Max Iterations", 800);  
  lsParams.set("Tolerance", 1e-8);
  lsParams.set("Output Frequency", 1);    
  lsParams.set("Preconditioner", "None");
//  lsParams.set("Preconditioner", "AztecOO");
//  lsParams.set("Aztec Preconditioner", "ilu"); 
//  lsParams.set("Preconditioner", "Ifpack");
//  lsParams.set("Ifpack Preconditioner", "ILU");
//  lsParams.set("Preconditioner", "New Ifpack");
//  Teuchos::ParameterList& ifpackParams = lsParams.sublist("Ifpack");
//    ifpackParams.set("fact: level-of-fill", 1);


  // set up the continuation parameter vector
  LOCA::ParameterVector p;
  p.addParameter("c",c);  

  // Set up the problem interface
  Teuchos::RCP<SimpleProblemInterface> interface = 
    Teuchos::rcp(new SimpleProblemInterface(&Problem,c) );

  Teuchos::RCP<LOCA::Epetra::Interface::Required> iReq = interface;

// Create the operator to hold either the Jacobian matrix or the Matrix-free operator
  Teuchos::RCP<Epetra_Operator> A;
  Teuchos::RCP<NOX::Epetra::Interface::Jacobian> iJac;

  // Need a NOX::Epetra::Vector for constructor
  // This becomes the initial guess vector that is used for the nonlinear solves
  NOX::Epetra::Vector noxInitGuess(InitialGuess, NOX::DeepCopy);   

  if (doMatFree) {
    // Matrix Free application (Epetra Operator):
    Teuchos::RCP<NOX::Epetra::MatrixFree> MF = 
      Teuchos::rcp(new NOX::Epetra::MatrixFree(printParams, interface, noxInitGuess)); 
    A = MF;
    iJac = MF;
  }
  else  {  // Computed Jacobian application
    A = Teuchos::rcp( Problem.GetMatrix(), false );
    iJac = interface;
  }
 
// Build the linear system solver
  Teuchos::RCP<NOX::Epetra::LinearSystemAztecOO> linSys = 
    Teuchos::rcp(new NOX::Epetra::LinearSystemAztecOO(printParams, lsParams,
						      iReq,
						      iJac, A, 
						      noxInitGuess));

// Create the Loca (continuation) vector
  NOX::Epetra::Vector locaSoln(noxInitGuess);
  
  // Create Epetra Factory
  Teuchos::RCP<LOCA::Abstract::Factory> epetraFactory = Teuchos::rcp(new LOCA::Epetra::Factory);

  // Create global data object
  Teuchos::RCP<LOCA::GlobalData> globalData = LOCA::createGlobalData(ParamList, epetraFactory);
 
  // Create the Group - must be LOCA group
  Teuchos::RCP<LOCA::Epetra::Group> grpPtr = 
    Teuchos::rcp(new LOCA::Epetra::Group(globalData, printParams, 
					iReq, locaSoln, 
					linSys, p)); 

  // Calculate the first F(x0) as a starting point.  This is only needed for
  // certain status tests, to ensure that an initial residual (|r0|) is calculated
  grpPtr->computeF();

// Set up the status tests to check for convergence
  // Determines the error tolerance for the Newton solves 
  Teuchos::RCP<NOX::StatusTest::NormF> testNormF = 
    Teuchos::rcp(new NOX::StatusTest::NormF(1.0e-4));
  // Sets the max number of nonlinear (Newton) iterations that will be taken.  If this is not
  //   already set, it will default to the '20' given 
  Teuchos::RCP<NOX::StatusTest::MaxIters> testMaxIters = 
    Teuchos::rcp(new NOX::StatusTest::MaxIters(stepperList.get("Max Nonlinear Iterations", 20)));
// This combination of tests will be used by NOX to determine whether the step converged
  Teuchos::RCP<NOX::StatusTest::Combo> combo = 
    Teuchos::rcp(new NOX::StatusTest::Combo(NOX::StatusTest::Combo::OR, 
					    testNormF, testMaxIters));

// This is sample code to write and read parameters to/from a file.  Currently not activated! 
// To use, change the 'XXXHAVE_TEUCHOS_EXTENDED' TO 'HAVE_TEUCHOS_EXTENDED'
#ifdef XXXHAVE_TEUCHOS_EXTENDED
  // Write the parameter list to a file
  cout << "Writing parameter list to \"input.xml\"" << endl;
  Teuchos::writeParameterListToXmlFile(*ParamList, "input.xml");

  // Read in the parameter list from a file
  cout << "Reading parameter list from \"input.xml\"" << endl;
  Teuchos::RCP<Teuchos::ParameterList> paramList2 = 
    Teuchos::rcp(new Teuchos::ParameterList);
  Teuchos::updateParametersFromXmlFile("input.xml", paramList2.get());
  ParamList = paramList2;
#endif


// Create the stepper
  LOCA::Stepper stepper(globalData, grpPtr, combo, ParamList);
  LOCA::Abstract::Iterator::IteratorStatus status = stepper.run();

  // Check if the stepper completed  
  if  (status == LOCA::Abstract::Iterator::Finished)
    globalData->locaUtils->out() << "\nAll tests passed!" << endl;
  else 
    if (globalData->locaUtils->isPrintType(NOX::Utils::Error))
      globalData->locaUtils->out() << "\nStepper failed to converge!"  << endl;

// Output the stepper parameter list info
  if (globalData->locaUtils->isPrintType(NOX::Utils::StepperParameters)) {
    globalData->locaUtils->out() << endl << "Final Parameters" << endl
    << "*******************" << endl;
    stepper.getList()->print(globalData->locaUtils->out());
    globalData->locaUtils->out() << endl;
  }

// Make sure all processors are done and close the output file
Comm.Barrier();
outFile.close();

// Deallocate memory
LOCA::destroyGlobalData(globalData);

#ifdef HAVE_MPI
  MPI_Finalize();
#endif
  return(EXIT_SUCCESS);
}  // DONE!!
int main(int argc, char *argv[])
{
  int nConstraints = 10;
  int nRHS = 7;

  double left_bc = 0.0;
  double right_bc = 1.0;
  double nonlinear_factor = 1.0;
  int ierr = 0;
  double reltol = 1.0e-8;
  double abstol = 1.0e-8;
  double lstol = 1.0e-11;

  int MyPID = 0;

  try {

    // Initialize MPI
#ifdef HAVE_MPI
    MPI_Init(&argc,&argv);
#endif

    // Create a communicator for Epetra objects
#ifdef HAVE_MPI
    Epetra_MpiComm Comm( MPI_COMM_WORLD );
#else
    Epetra_SerialComm Comm;
#endif

    // Get the total number of processors
    MyPID = Comm.MyPID();
    int NumProc = Comm.NumProc();

    bool verbose = false;
    // Check for verbose output
    if (argc>1)
      if (argv[1][0]=='-' && argv[1][1]=='v')
    verbose = true;

    // Get the number of elements from the command line
    int NumGlobalElements = 0;
    if ((argc > 2) && (verbose))
      NumGlobalElements = atoi(argv[2]) + 1;
    else if ((argc > 1) && (!verbose))
      NumGlobalElements = atoi(argv[1]) + 1;
    else
      NumGlobalElements = 101;

    // The number of unknowns must be at least equal to the
    // number of processors.
    if (NumGlobalElements < NumProc) {
      std::cout << "numGlobalBlocks = " << NumGlobalElements
       << " cannot be < number of processors = " << NumProc << std::endl;
      exit(1);
    }

    // Seed the random number generator in Teuchos.  We create random
    // bordering matrices and it is possible different processors might generate
    // different matrices.  By setting the seed, this shouldn't happen.
    Teuchos::ScalarTraits<double>::seedrandom(12345);

    // Create parameter list
    Teuchos::RCP<Teuchos::ParameterList> paramList =
      Teuchos::rcp(new Teuchos::ParameterList);

    // Create LOCA sublist
    Teuchos::ParameterList& locaParamsList = paramList->sublist("LOCA");

    // Create the constraints list
    Teuchos::ParameterList& constraintsList =
      locaParamsList.sublist("Constraints");
    constraintsList.set("Bordered Solver Method", "Bordering");

    // Create the "Solver" parameters sublist to be used with NOX Solvers
    Teuchos::ParameterList& nlParams = paramList->sublist("NOX");

    Teuchos::ParameterList& nlPrintParams = nlParams.sublist("Printing");
    nlPrintParams.set("MyPID", MyPID);
    if (verbose)
       nlPrintParams.set("Output Information",
                  NOX::Utils::Error +
                  NOX::Utils::Details +
                      NOX::Utils::LinearSolverDetails +
                  NOX::Utils::OuterIteration +
                  NOX::Utils::InnerIteration +
                  NOX::Utils::Warning +
                  NOX::Utils::TestDetails +
                  NOX::Utils::StepperIteration +
                  NOX::Utils::StepperDetails);
     else
       nlPrintParams.set("Output Information", NOX::Utils::Error);

    // Create the "Direction" sublist for the "Line Search Based" solver
    Teuchos::ParameterList& dirParams = nlParams.sublist("Direction");
    Teuchos::ParameterList& newParams = dirParams.sublist("Newton");
    Teuchos::ParameterList& lsParams = newParams.sublist("Linear Solver");
    lsParams.set("Aztec Solver", "GMRES");
    lsParams.set("Max Iterations", 100);
    lsParams.set("Tolerance", lstol);
    if (verbose)
      lsParams.set("Output Frequency", 1);
    else
      lsParams.set("Output Frequency", 0);
    lsParams.set("Scaling", "None");
    lsParams.set("Preconditioner", "Ifpack");
    //lsParams.set("Preconditioner", "AztecOO");
    //lsParams.set("Jacobian Operator", "Matrix-Free");
    //lsParams.set("Preconditioner Operator", "Finite Difference");
    lsParams.set("Aztec Preconditioner", "ilut");
    //lsParams.set("Overlap", 2);
    //lsParams.set("Fill Factor", 2.0);
    //lsParams.set("Drop Tolerance", 1.0e-12);
    lsParams.set("Max Age Of Prec", -2);

    // Create the FiniteElementProblem class.  This creates all required
    // Epetra objects for the problem and allows calls to the
    // function (RHS) and Jacobian evaluation routines.
    Tcubed_FiniteElementProblem Problem(NumGlobalElements, Comm);

    // Get the vector from the Problem
    Epetra_Vector& soln = Problem.getSolution();

    // Initialize Solution
    soln.PutScalar(0.0);

    // Create and initialize the parameter vector
    LOCA::ParameterVector pVector;
    pVector.addParameter("Nonlinear Factor",nonlinear_factor);
    pVector.addParameter("Left BC", left_bc);
    pVector.addParameter("Right BC", right_bc);

    // Create the interface between the test problem and the nonlinear solver
    // This is created by the user using inheritance of the abstract base
    // class:
    Teuchos::RCP<Problem_Interface> interface =
      Teuchos::rcp(new Problem_Interface(Problem));
    Teuchos::RCP<LOCA::Epetra::Interface::Required> iReq = interface;
    Teuchos::RCP<NOX::Epetra::Interface::Jacobian> iJac = interface;

    // Create the Epetra_RowMatrixfor the Jacobian/Preconditioner
    Teuchos::RCP<Epetra_RowMatrix> Amat =
      Teuchos::rcp(&Problem.getJacobian(),false);

    // Create the linear systems
    Teuchos::RCP<NOX::Epetra::LinearSystemAztecOO> linsys =
      Teuchos::rcp(new NOX::Epetra::LinearSystemAztecOO(nlPrintParams,
                            lsParams, iReq, iJac,
                            Amat, soln));

    // Create the loca vector
    NOX::Epetra::Vector locaSoln(soln);

    // Create Epetra factory
    Teuchos::RCP<LOCA::Abstract::Factory> epetraFactory =
      Teuchos::rcp(new LOCA::Epetra::Factory);

     // Create global data object
    globalData = LOCA::createGlobalData(paramList, epetraFactory);

    // Create parsed parameter list
    parsedParams =
      Teuchos::rcp(new LOCA::Parameter::SublistParser(globalData));
    parsedParams->parseSublists(paramList);

    // Create the Group
    grp = Teuchos::rcp(new LOCA::Epetra::Group(globalData, nlPrintParams,
                           iReq, locaSoln,
                           linsys, pVector));

    // Create Jacobian operator
    op = Teuchos::rcp(new LOCA::BorderedSolver::JacobianOperator(grp));

    // Change initial guess to a random vector
    Teuchos::RCP<NOX::Abstract::Vector> xnew =
      grp->getX().clone();
    xnew->random();
    grp->setX(*xnew);

    // Create the constraints object & constraint param IDs list
    constraints =
      Teuchos::rcp(new LinearConstraint(nConstraints, LOCA::ParameterVector(),
                    locaSoln));

    // Create bordering solver
    bordering
      = globalData->locaFactory->createBorderedSolverStrategy(
                     parsedParams,
                     parsedParams->getSublist("Constraints"));

    // Change strategy to Householder
    constraintsList.set("Bordered Solver Method",
                 "Householder");

    // Create householder solver
    householder
      = globalData->locaFactory->createBorderedSolverStrategy(
                     parsedParams,
                     parsedParams->getSublist("Constraints"));

    // Check some statistics on the solution
    testCompare = Teuchos::rcp(new NOX::TestCompare(
                                 globalData->locaUtils->out(),
                         *(globalData->locaUtils)));

    // Evaluate blocks
    grp->computeF();
    grp->computeJacobian();

    // A
    A = grp->getX().createMultiVector(nConstraints);
    A->random();

    // B
    constraints->setX(grp->getX());
    B = grp->getX().createMultiVector(nConstraints);
    B->random();
    constraints->setDgDx(*B);
    constraints->computeConstraints();
    constraints->computeDX();

    // C
    C = Teuchos::rcp(new NOX::Abstract::MultiVector::DenseMatrix(nConstraints,
                                 nConstraints));
    C->random();

    // Set up left- and right-hand sides
    F = grp->getX().createMultiVector(nRHS);
    F->random();
    G = Teuchos::rcp(new NOX::Abstract::MultiVector::DenseMatrix(nConstraints,
                                 nRHS));
    G->random();
    X_bordering = F->clone(NOX::ShapeCopy);
    Y_bordering =
      Teuchos::rcp(new NOX::Abstract::MultiVector::DenseMatrix(nConstraints,
                                   nRHS));
    X_householder = F->clone(NOX::ShapeCopy);
    Y_householder =
      Teuchos::rcp(new NOX::Abstract::MultiVector::DenseMatrix(nConstraints,
                                   nRHS));

    std::string testName;

    // Test all nonzero
    testName = "Testing all nonzero";
    ierr += testSolve(false, false, false, false, false,
              reltol, abstol, testName);

    // Test A = 0
    testName = "Testing A=0";
    ierr += testSolve(true, false, false, false, false,
              reltol, abstol, testName);

    // Test B = 0
    testName = "Testing B=0";
    ierr += testSolve(false, true, false, false, false,
              reltol, abstol, testName);

    // Test C = 0
    testName = "Testing C=0";
    ierr += testSolve(false, false, true, false, false,
              reltol, abstol, testName);

    // Test F = 0
    testName = "Testing F=0";
    ierr += testSolve(false, false, false, true, false,
              reltol, abstol, testName);

    // Test G = 0
    testName = "Testing G=0";
    ierr += testSolve(false, false, false, false, true,
              reltol, abstol, testName);

    // Test A,B = 0
    testName = "Testing A,B=0";
    ierr += testSolve(true, true, false, false, false,
              reltol, abstol, testName);

    // Test A,F = 0
    testName = "Testing A,F=0";
    ierr += testSolve(true, false, false, true, false,
              reltol, abstol, testName);

    // Test A,G = 0
    testName = "Testing A,G=0";
    ierr += testSolve(true, false, false, false, true,
              reltol, abstol, testName);

    // Test B,F = 0
    testName = "Testing B,F=0";
    ierr += testSolve(false, true, false, true, false,
              reltol, abstol, testName);

    // Test B,G = 0
    testName = "Testing B,G=0";
    ierr += testSolve(false, true, false, false, true,
              reltol, abstol, testName);

    // Test C,F = 0
    testName = "Testing C,F=0";
    ierr += testSolve(false, false, true, true, false,
              reltol, abstol, testName);

    // Test C,G = 0
    testName = "Testing C,G=0";
    ierr += testSolve(false, false, true, false, true,
              reltol, abstol, testName);

    // Test F,G = 0
    testName = "Testing F,G=0";
    ierr += testSolve(false, false, false, true, true,
              reltol, abstol, testName);

    // Test A,B,F = 0
    testName = "Testing A,B,F=0";
    ierr += testSolve(true, true, false, true, false,
              reltol, abstol, testName);

    // Test A,B,G = 0
    testName = "Testing A,B,G=0";
    ierr += testSolve(true, true, false, false, true,
              reltol, abstol, testName);

    // Test A,F,G = 0
    testName = "Testing A,F,G=0";
    ierr += testSolve(true, false, false, true, true,
              reltol, abstol, testName);

    // Test B,F,G = 0
    testName = "Testing B,F,G=0";
    ierr += testSolve(false, true, false, true, true,
              reltol, abstol, testName);

    // Test C,F,G = 0
    testName = "Testing C,F,G=0";
    ierr += testSolve(false, false, true, true, true,
              reltol, abstol, testName);

    // Test A,B,F,G = 0
    testName = "Testing A,B,F,G=0";
    ierr += testSolve(true, true, false, true, true,
              reltol, abstol, testName);

    LOCA::destroyGlobalData(globalData);

  }

  catch (std::exception& e) {
    std::cout << e.what() << std::endl;
    ierr = 1;
  }
  catch (const char *s) {
    std::cout << s << std::endl;
    ierr = 1;
  }
  catch (...) {
    std::cout << "Caught unknown exception!" << std::endl;
    ierr = 1;
  }

  if (MyPID == 0) {
    if (ierr == 0)
      std::cout << "All tests passed!" << std::endl;
    else
      std::cout << ierr << " test(s) failed!" << std::endl;
  }

#ifdef HAVE_MPI
  MPI_Finalize() ;
#endif

  return ierr;
}