Teuchos::RCP<const ErrorEstimateBase<double> > GAASPErrorEstimator::controlGlobalError(double uTOL) {
  if (!isInitialized_) {
    initialize_();
  }
  Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
  Teuchos::RCP<Teuchos::FancyOStream> out = this->getOStream();
  Teuchos::OSTab ostab(out,1,"GAASPErrorEstimator::");

  paramList_->sublist(GAASPInterface_name_).set("uTOL",uTOL);
  gaaspInterfacePtr_->setParameterList(sublist(paramList_,GAASPInterface_name_));
  if (Teuchos::as<int>(verbLevel) != Teuchos::VERB_NONE) {
    *out << "controlGlobalError:  Global error tolerance = " << uTOL << std::endl;
  }

  Teuchos::RCP<const ErrorEstimateBase<double> > gaaspEE;

  gaaspEE = getErrorEstimate();
  while (fabs(gaaspEE->getTotalError()) > uTOL) {
    if (Teuchos::as<int>(verbLevel) != Teuchos::VERB_NONE) {
      *out << "controlGlobalError:  Calling GAASPInterface::refineMesh()..." << std::endl;
    }
    gaaspInterfacePtr_->refineMesh();
    gaaspEE = getErrorEstimate();
  }

  return(gaaspEE);
}
Teuchos::RCP<const Teuchos::ParameterList> GAASPErrorEstimator::getValidParameters() const {
  static Teuchos::RCP<Teuchos::ParameterList> validPL;

  if (is_null(validPL)) {

    Teuchos::RCP<Teuchos::ParameterList>
      pl = Teuchos::parameterList();

    Teuchos::RCP<Teuchos::ParameterList> gaaspPL = sublist(pl,GAASPInterface_name_);
    GAASPInterface gaaspI;
    gaaspPL->setParameters(*(gaaspI.getValidParameters()));
    
    Teuchos::setupVerboseObjectSublist(&*pl);

    validPL = pl;

  }

  Teuchos::RCP<Teuchos::FancyOStream> out = this->getOStream();
  Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
  Teuchos::OSTab ostab(out,1,"getValidParameters");
  if (Teuchos::as<int>(verbLevel) == Teuchos::VERB_HIGH) {
    *out << "Setting up valid parameterlist." << std::endl;
    validPL->print(*out);
  }

  return (validPL);
}
Teuchos::RCP<const ErrorEstimateBase<double> > GAASPErrorEstimator::getErrorEstimate() {
  if (!isInitialized_) {
    initialize_();
  }
  Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
  Teuchos::RCP<Teuchos::FancyOStream> out = this->getOStream();
  Teuchos::OSTab ostab(out,1,"GAASPErrorEstimator::");
  if (Teuchos::as<int>(verbLevel) != Teuchos::VERB_NONE) {
    *out << "getErrorEstimate:  Calling GAASPInterface::forwardSolve()..." << std::endl;
  }
  gaaspInterfacePtr_->forwardSolve();
  if (Teuchos::as<int>(verbLevel) != Teuchos::VERB_NONE) {
    *out << "getErrorEstimate:  Calling GAASPInterface::adjointSolve()..." << std::endl;
  }
  gaaspInterfacePtr_->adjointSolve();
  if (Teuchos::as<int>(verbLevel) != Teuchos::VERB_NONE) {
    *out << "getErrorEstimate:  Calling GAASPInterface::computeErrorEstimate()..." << std::endl;
  }
  Teuchos::RCP<const GAASPErrorEstimate> gaaspEE = gaaspInterfacePtr_->computeErrorEstimate();
  if (Teuchos::as<int>(verbLevel) != Teuchos::VERB_NONE) {
    *out << "getErrorEstimate:  Global Error Estimate = " << fabs(gaaspEE->getTotalError()) << std::endl;
  }
  return(gaaspEE);
}
Teuchos::RCP<const Teuchos::ParameterList> GAASPInterface::getValidParameters() const {
  static Teuchos::RCP<Teuchos::ParameterList> validPL;

  if (is_null(validPL)) {

    Teuchos::RCP<Teuchos::ParameterList>
      pl = Teuchos::parameterList();
    
    pl->set(sTime_name_, sTime_default_,
        "Set the start time for the simulation"
        );
    pl->set(eTime_name_, eTime_default_,
        "Set the end time for the simulation"
        );
    pl->set(timeStep_name_, timeStep_default_,
        "Set the fixed time step size for the simulation"
        );
    Teuchos::setStringToIntegralParameter<GAASP::TMethodFlag>(
        method_name_, method_default_, 
        "Set the pair of integration methods for the forward and adjoint solves",
        Teuchos::tuple<std::string>("DG0","DG1"),
        Teuchos::tuple<GAASP::TMethodFlag>(GAASP::Method_DG0,GAASP::Method_DG1),
        &*pl
        );
    Teuchos::setStringToIntegralParameter<GAASP::TErrorFlag>(
        qtyOfInterest_name_, qtyOfInterest_default_, 
        "Set the quantity of interest for the global error estimate",
        Teuchos::tuple<std::string>("End","Average"),
        Teuchos::tuple<GAASP::TErrorFlag>(GAASP::Error_End,GAASP::Error_Avg),
        &*pl
        );
    pl->set(uTOL_name_, uTOL_default_,
        "Set the global error tolerance for global error control"
        );
    Teuchos::setStringToIntegralParameter<GAASP::TRefinementFlag>(
        meshRefineMethod_name_, meshRefineMethod_default_, 
        "Set the mesh refinement method",
        Teuchos::tuple<std::string>(
          "By Contribution",
          "Probabilistic 1",
          "Probabilistic 2", 
          "Weighted Adaptive"
          ),
        Teuchos::tuple<GAASP::TRefinementFlag>(
          GAASP::Refine_ByContribution,
          GAASP::Refine_Probabilistic1,
          GAASP::Refine_Probabilistic2,
          GAASP::Refine_WeightedAdaptive
          ),
        &*pl
        );

    Teuchos::setupVerboseObjectSublist(&*pl);

    validPL = pl;

  }

  Teuchos::RCP<Teuchos::FancyOStream> out = this->getOStream();
  Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
  Teuchos::OSTab ostab(out,1,"getValidParameters");
  if (Teuchos::as<int>(verbLevel) == Teuchos::VERB_HIGH) {
    *out << "Setting up valid parameterlist." << std::endl;
    validPL->print(*out);
  }

  return (validPL);
}
void HermiteInterpolator<Scalar>::interpolate(
    const Array<Scalar> &t_values
    ,typename DataStore<Scalar>::DataStoreVector_t *data_out ) const
{

  //TEUCHOS_TEST_FOR_EXCEPT_MSG(true, "Error, ths function is not tested!" );

  typedef Teuchos::ScalarTraits<Scalar> ST;
#ifdef HAVE_RYTHMOS_DEBUG
  assertInterpolatePreconditions((*nodes_),t_values,data_out);
#endif // HAVE_RYTHMOS_DEBUG
  RCP<Teuchos::FancyOStream> out = this->getOStream();
  Teuchos::OSTab ostab(out,1,"HI::interpolator");
  if ( Teuchos::as<int>(this->getVerbLevel()) >= Teuchos::as<int>(Teuchos::VERB_HIGH) ) {
    *out << "(*nodes_):" << std::endl;
    for (Teuchos::Ordinal i=0 ; i<(*nodes_).size() ; ++i) {
      *out << "(*nodes_)[" << i << "] = " << std::endl;
      (*nodes_)[i].describe(*out,Teuchos::VERB_EXTREME);
    }
    *out << "t_values = " << std::endl;
    for (Teuchos::Ordinal i=0 ; i<t_values.size() ; ++i) {
      *out << "t_values[" << i << "] = " << t_values[i] << std::endl;
    }
    for (Teuchos::Ordinal i=0; i<data_out->size() ; ++i) {
      *out << "data_out[" << i << "] = " << std::endl;
      (*data_out)[i].describe(*out,Teuchos::VERB_EXTREME);
    }
  }
  data_out->clear();
  if (t_values.size() == 0) {
    return;
  }
  
  if ((*nodes_).size() == 1) {
    // trivial case of one node
    // preconditions assert that t_values[0] == (*nodes_)[0].time so we can just pass it out
    DataStore<Scalar> DS((*nodes_)[0]);
    data_out->push_back(DS);
  } else {
    // (*nodes_).size() >= 2
    int n = 0;
    for (int i=0 ; i<Teuchos::as<int>((*nodes_).size())-1 ; ++i) {
      const Scalar& t0 = (*nodes_)[i].time;
      const Scalar& t1 = (*nodes_)[i+1].time;
      while ((t0 <= t_values[n]) && (t_values[n] <= t1)) {
        const Scalar& t = t_values[n];
        // First we check for exact node matches:
        if (t == t0) {
          DataStore<Scalar> DS((*nodes_)[i]);
          data_out->push_back(DS);
        } else if (t == t1) {
          DataStore<Scalar> DS((*nodes_)[i+1]);
          data_out->push_back(DS);
        } else {
          RCP<const Thyra::VectorBase<Scalar> > x0    = (*nodes_)[i  ].x;
          RCP<const Thyra::VectorBase<Scalar> > x1    = (*nodes_)[i+1].x;
          RCP<const Thyra::VectorBase<Scalar> > xdot0 = (*nodes_)[i  ].xdot;
          RCP<const Thyra::VectorBase<Scalar> > xdot1 = (*nodes_)[i+1].xdot;
          
          // 10/10/06 tscoffe:  this could be expensive:
          RCP<Thyra::VectorBase<Scalar> > tmp_vec = x0->clone_v(); 
          RCP<Thyra::VectorBase<Scalar> > xdot_temp = x1->clone_v(); 
          Scalar dt = t1-t0;
          Scalar dt2 = dt*dt;
          Scalar t_t0 = t - t0;
          Scalar t_t1 = t - t1;
          Scalar tmp_t;

          // Compute numerical divided difference:
          Thyra::Vt_S(xdot_temp.ptr(),Scalar(ST::one()/dt));
          Thyra::Vp_StV(xdot_temp.ptr(),Scalar(-ST::one()/dt),*x0);

          // interpolate this point
          DataStore<Scalar> DS;
          DS.time = t;

          //  H_3(t) = x(t0) + xdot(t0)(t-t0) + ((x(t1)-x(t0))/(t1-t0) - xdot(t0))(t-t0)^2/(t1-t0)
          //           +(xdot(t1) - 2(x(t1)-x(t0))/(t1-t0) + xdot(t0))(t-t0)^2(t-t1)/(t1-t0)^2
          RCP<Thyra::VectorBase<Scalar> > x_vec = x0->clone_v(); 
          Thyra::Vp_StV(x_vec.ptr(),t_t0,*xdot0);
          tmp_t = t_t0*t_t0/dt;
          Thyra::V_StVpStV(tmp_vec.ptr(),tmp_t,*xdot_temp,Scalar(-ST::one()*tmp_t),*xdot0);
          Thyra::Vp_V(x_vec.ptr(),*tmp_vec);
          tmp_t = t_t0*t_t0*t_t1/dt2;
          Thyra::V_StVpStV(tmp_vec.ptr(),tmp_t,*xdot1,Scalar(-2*tmp_t),*xdot_temp);
          Thyra::Vp_StV(tmp_vec.ptr(),tmp_t,*xdot0);
          Thyra::Vp_V(x_vec.ptr(),*tmp_vec);
          DS.x = x_vec;

          //  H_3'(t) =        xdot(t0) + 2*((x(t1)-x(t0))/(t1-t0) - xdot(t0))(t-t0)/(t1-t0)
          //           +(xdot(t1) - 2(x(t1)-x(t0))/(t1-t0) + xdot(t0))[2*(t-t0)(t-t1) + (t-t0)^2]/(t1-t0)^2
          RCP<Thyra::VectorBase<Scalar> > xdot_vec = xdot0->clone_v(); 
          tmp_t = t_t0/dt;
          Thyra::Vp_StV(xdot_vec.ptr(),Scalar(2*tmp_t),*xdot_temp);
          Thyra::Vp_StV(xdot_vec.ptr(),Scalar(-2*tmp_t),*xdot0);
          tmp_t = Scalar((2*t_t0*t_t1+t_t0*t_t0)/dt2);
          Thyra::V_StVpStV(tmp_vec.ptr(),tmp_t,*xdot1,Scalar(-2*tmp_t),*xdot_temp);
          Thyra::Vp_StV(tmp_vec.ptr(),tmp_t,*xdot0);
          Thyra::Vp_V(xdot_vec.ptr(),*tmp_vec);
          DS.xdot = xdot_vec;
          
          // Accuracy:
          // f(x) - H_3(x) = (f^{(3)}(\xi(x))/(4!))(x-x0)^2(x-x1)^2
          DS.accuracy = (t_t0)*(t_t0)*(t_t1)*(t_t1);

          // Push DataStore object onto vector:
          data_out->push_back(DS);
        }
        n++;
        if (n == Teuchos::as<int>(t_values.size())) {
          return;
        }
      }
    }
  } // (*nodes_).size() == 1
}