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::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
}