int
Piro::Thyra::PerformOptiPackAnalysis(
    ::Thyra::ModelEvaluatorDefaultBase<double>& piroModel,
    Teuchos::ParameterList& optipackParams,
    Teuchos::ParameterList& globipackParams,
    RCP< ::Thyra::VectorBase<double> >& p)
{
    RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
#ifdef Piro_ENABLE_OptiPack
    // First, Linesearch stuff
    const RCP<GlobiPack::BrentsLineSearch<double> >
    linesearch = GlobiPack::brentsLineSearch<double>();
    const RCP<ParameterList> lsPL = rcp(&globipackParams, false);
    linesearch->setParameterList(lsPL);

    // Temporary Debug
    *out << "\nCurrent LineSearch parameters" << endl;
    lsPL->print(*out);

    // Second, Optimization stuff

    p = ::Thyra::createMember(piroModel.get_p_space(0));

    RCP<const ::Thyra::VectorBase<double> > p_init = piroModel.getNominalValues().get_p(0);

    ::Thyra::copy(*p_init, p.ptr());

    const RCP<OptiPack::NonlinearCG<double> > cgSolver =
        OptiPack::nonlinearCG<double>(rcp(&piroModel,false), 0, 0, linesearch);

    const RCP<ParameterList> pl = rcp(&optipackParams,false);
    cgSolver->setParameterList(pl);

    // Temporary Debug Info
    *out << "\nCurrent nonlinearCG parameter list" << endl;
    pl->print(*out);

    // Solve the prob
    double g_opt;  // optimal value of the response
    int numIters;  // number of iteration taken
    const OptiPack::NonlinearCGUtils::ESolveReturn solveResult =
        cgSolver->doSolve( p.ptr(), outArg(g_opt),
                           null, null, null, outArg(numIters) );

    return (int) solveResult;
#else
    *out << "ERROR: Trilinos/Piro was not configured to include OptiPack analysis."
         << endl;
    return 0;  // should not fail tests
#endif
}
int
Piro::Thyra::PerformMoochoAnalysis(
    ::Thyra::ModelEvaluatorDefaultBase<double>& piroModel,
    Teuchos::ParameterList& moochoParams,
    RCP< ::Thyra::VectorBase<double> >& p)
{
#ifdef Piro_ENABLE_MOOCHO
    MoochoPack::MoochoThyraSolver solver;

    // Set the model and parameter list
    solver.setModel(rcp(&piroModel,false));
    solver.setParameterList(rcp(&moochoParams,false));

    // Solve the NLP
    const  MoochoPack::MoochoSolver::ESolutionStatus
    solution_status = solver.solve();

    // Extract the final solution
    p = ::Thyra::createMember(piroModel.get_p_space(0));
    RCP<const ::Thyra::VectorBase<double> > p_final = solver.getFinalPoint().get_p(0);
    ::Thyra::copy(*p_final, p.ptr());

    return (int) solution_status;
#else
    RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
    *out << "ERROR: Trilinos/Piro was not configured to include MOOCHO analysis."
         << endl;
    return 0;  // should not fail tests
#endif
}
int
Piro::PerformDakotaAnalysis(
    Thyra::ModelEvaluatorDefaultBase<double>& piroModel,
    Teuchos::ParameterList& dakotaParams,
    RCP< Thyra::VectorBase<double> >& p)
{
#ifdef HAVE_PIRO_TRIKOTA
  dakotaParams.validateParameters(*Piro::getValidPiroAnalysisDakotaParameters(),0);
  using std::string;

  string dakotaIn  = dakotaParams.get("Input File","dakota.in");
  string dakotaOut = dakotaParams.get("Output File","dakota.out");
  string dakotaErr = dakotaParams.get("Error File","dakota.err");
  string dakotaRes = dakotaParams.get("Restart File","dakota_restart.out");
  string dakotaRestartIn;
  if (dakotaParams.isParameter("Restart File To Read"))
    dakotaRestartIn = dakotaParams.get<string>("Restart File To Read");

  int dakotaRestartEvals= dakotaParams.get("Restart Evals To Read", 0);

  int p_index = dakotaParams.get("Parameter Vector Index", 0);
  int g_index = dakotaParams.get("Response Vector Index", 0);

  TriKota::Driver dakota(dakotaIn, dakotaOut, dakotaErr, dakotaRes,
                         dakotaRestartIn, dakotaRestartEvals);

  RCP<TriKota::ThyraDirectApplicInterface> trikota_interface =
    rcp(new TriKota::ThyraDirectApplicInterface
         (dakota.getProblemDescDB(), rcp(&piroModel,false), p_index, g_index),
	false);

  dakota.run(trikota_interface.get());

  Dakota::RealVector finalValues;
  if (dakota.rankZero())
    finalValues = dakota.getFinalSolution().all_continuous_variables();

  // Copy Dakota parameters into Thyra
  p = Thyra::createMember(piroModel.get_p_space(p_index));
  {
      Thyra::DetachedVectorView<double> global_p(p);
      for (int i = 0; i < finalValues.length(); ++i)
        global_p[i] = finalValues[i];
  }

  return 0;
#else
 RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
 *out << "ERROR: Trilinos/Piro was not configured to include Dakota analysis."
      << "\nYou must enable TriKota." << endl;
 return 0;  // should not fail tests
#endif
}
int
Piro::Thyra::PerformDakotaAnalysis(
    ::Thyra::ModelEvaluatorDefaultBase<double>& piroModel,
    Teuchos::ParameterList& dakotaParams,
    RCP< ::Thyra::VectorBase<double> >& p)
{
#ifdef Piro_ENABLE_TriKota
  string dakotaIn = dakotaParams.get("Input File","dakota.in");
  string dakotaOut= dakotaParams.get("Output File","dakota.out");
  string dakotaErr= dakotaParams.get("Error File","dakota.err");
  string dakotaRes= dakotaParams.get("Restart File","dakota_restart.out");

  TriKota::Driver dakota(dakotaIn.c_str(), dakotaOut.c_str(),
                         dakotaErr.c_str(), dakotaRes.c_str());

  RCP<TriKota::ThyraDirectApplicInterface> trikota_interface =
    rcp(new TriKota::ThyraDirectApplicInterface
         (dakota.getProblemDescDB(), rcp(&piroModel,false)), false);

  dakota.run(trikota_interface.get());

  Dakota::RealVector finalValues =
    dakota.getFinalSolution().all_continuous_variables();

  // Copy Dakota parameters into Thyra
  p = ::Thyra::createMember(piroModel.get_p_space(0));
  {
      ::Thyra::DetachedVectorView<double> global_p(p);
      for (int i = 0; i < finalValues.length(); ++i) 
        global_p[i] = finalValues[i];
  }

  return 0;
#else
 RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
 *out << "ERROR: Trilinos/Piro was not configured to include Dakota analysis."
      << "\nYou must enable TriKota." << endl;
 return 0;  // should not fail tests
#endif
}
int
Piro::PerformROLAnalysis(
    Thyra::ModelEvaluatorDefaultBase<double>& piroModel,
    Teuchos::ParameterList& rolParams,
    RCP< Thyra::VectorBase<double> >& p)
{
#ifdef HAVE_PIRO_ROL
  using std::string;

  RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
  int g_index = rolParams.get<int>("Response Vector Index", 0);
  int p_index = rolParams.get<int>("Parameter Vector Index", 0);
  p = Thyra::createMember(piroModel.get_p_space(p_index));
  RCP<const Thyra::VectorBase<double> > p_init = piroModel.getNominalValues().get_p(p_index);
  Thyra::copy(*p_init, p.ptr());

  ROL::ThyraVector<double> rol_p(p);


  ROL::ThyraME_Objective<double> obj(piroModel, g_index, p_index);

  bool print = rolParams.get<bool>("Print Output", false);

  int seed = rolParams.get<int>("Seed For Thyra Randomize", 42);

  //! set initial guess (or use the one provided by the Model Evaluator)
  std::string init_guess_type = rolParams.get<string>("Parameter Initial Guess Type", "From Model Evaluator");
  if(init_guess_type == "Uniform Vector")
    rol_p.putScalar(rolParams.get<double>("Uniform Parameter Guess", 1.0));
  else if(init_guess_type == "Random Vector") {
    Teuchos::Array<double> minmax(2); minmax[0] = -1; minmax[1] = 1;
    minmax = rolParams.get<Teuchos::Array<double> >("Min And Max Of Random Parameter Guess", minmax);
    ::Thyra::randomize<double>( minmax[0], minmax[1],  rol_p.getVector().ptr());
  }
  else if(init_guess_type != "From Model Evaluator") {
    TEUCHOS_TEST_FOR_EXCEPTION(true, Teuchos::Exceptions::InvalidParameter,
              std::endl << "Error in Piro::PerformROLAnalysis:  " <<
              "Parameter Initial Guess Type \"" << init_guess_type << "\" is not Known.\nValid options are: \"Parameter Scalar Guess\", \"Uniform Vector\" and \"Random Vector\""<<std::endl);
  }

  //! test thyra implementation of ROL vector
  if(rolParams.get<bool>("Test Vector", false)) {
    Teuchos::RCP<Thyra::VectorBase<double> > rand_vec_x = p->clone_v();
    Teuchos::RCP<Thyra::VectorBase<double> > rand_vec_y = p->clone_v();
    Teuchos::RCP<Thyra::VectorBase<double> > rand_vec_z = p->clone_v();
    ::Thyra::seed_randomize<double>( seed );

    int num_tests = rolParams.get<int>("Number Of Vector Tests", 1);

    for(int i=0; i< num_tests; i++) {

      *out << "\nROL performing vector test " << i+1 << " of " << num_tests  << std::endl;

      ::Thyra::randomize<double>( -1.0, 1.0,  rand_vec_x.ptr());
      ::Thyra::randomize<double>( -1.0, 1.0,  rand_vec_y.ptr());
      ::Thyra::randomize<double>( -1.0, 1.0,  rand_vec_z.ptr());

      ROL::ThyraVector<double> rol_x(rand_vec_x);
      ROL::ThyraVector<double> rol_y(rand_vec_y);
      ROL::ThyraVector<double> rol_z(rand_vec_z);

      rol_x.checkVector(rol_y, rol_z,print, *out);
    }
  }

  //! check correctness of Gradient prvided by Model Evaluator
  if(rolParams.get<bool>("Check Gradient", false)) {
    Teuchos::RCP<Thyra::VectorBase<double> > rand_vec = p->clone_v();
    ::Thyra::seed_randomize<double>( seed );

    int num_checks = rolParams.get<int>("Number Of Gradient Checks", 1);
    double norm_p = rol_p.norm();

    for(int i=0; i< num_checks; i++) {

      *out << "\nROL performing gradient check " << i+1 << " of " << num_checks << ", at parameter initial guess" << std::endl;

      ::Thyra::randomize<double>( -1.0, 1.0,  rand_vec.ptr());

      ROL::ThyraVector<double> rol_direction(rand_vec);

      double norm_d = rol_direction.norm();
      if(norm_d*norm_p > 0.0)
        rol_direction.scale(norm_p/norm_d);

      obj.checkGradient(rol_p, rol_direction, print, *out);
    }
  }

  // Define Step
  Teuchos::RCP<ROL::LineSearchStep<double> > step = 
    Teuchos::rcp(new ROL::LineSearchStep<double>(rolParams.sublist("ROL Options")));
  *out << "\nROL options:" << std::endl;
  rolParams.sublist("ROL Options").print(*out);
  *out << std::endl;


  // Define Status Test
  double gtol  = rolParams.get("Gradient Tolerance", 1e-5);  // norm of gradient tolerance
  double stol  = rolParams.get("Step Tolerance", 1e-5);  // norm of step tolerance
  int   maxit = rolParams.get("Max Iterations", 100);    // maximum number of iterations
  Teuchos::RCP<ROL::StatusTest<double> > status =
    Teuchos::rcp(new ROL::StatusTest<double>(gtol, stol, maxit));

  // Define Algorithm
  ROL::Algorithm<double> algo(step,status,print);

  // Run Algorithm
  std::vector<std::string> output;
  if(rolParams.get<bool>("Bound Constrained", false)) {
    double eps_bound = rolParams.get<double>("epsilon bound", 1e-6);
    Teuchos::RCP<const Thyra::VectorBase<double> > p_lo = piroModel.getLowerBounds().get_p(p_index);
    Teuchos::RCP<const Thyra::VectorBase<double> > p_up = piroModel.getUpperBounds().get_p(p_index);
    TEUCHOS_TEST_FOR_EXCEPTION((p_lo == Teuchos::null)  || (p_up == Teuchos::null), Teuchos::Exceptions::InvalidParameter,
          std::endl << "Error in Piro::PerformROLAnalysis:  " <<
          "Lower and/or Upper bounds pointers are null, cannot perform bound constrained optimization"<<std::endl);

    ROL::Thyra_BoundConstraint<double>  boundConstraint(p_lo->clone_v(), p_up->clone_v(), eps_bound);
    output  = algo.run(rol_p, obj, boundConstraint, print, *out);
  }
  else
    output = algo.run(rol_p, obj, print, *out);


  for ( unsigned i = 0; i < output.size(); i++ ) {
    *out << output[i];
  }

  return 0;
#else
 RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
 *out << "ERROR: Trilinos/Piro was not configured to include ROL analysis."
      << "\nYou must enable ROL." << endl;
 return 0;  // should not fail tests
#endif
}