TEUCHOS_UNIT_TEST( Rythmos_TimeRange, copyAndScaleInvalid ) {
  TimeRange<double> tr;
  TimeRange<double> newTr = tr.copyAndScale(5.0);
  TEST_EQUALITY_CONST( newTr.isValid(), false );
  TEST_EQUALITY( newTr.lower(), tr.lower() );
  TEST_EQUALITY( newTr.upper(), tr.upper() );
  TEST_EQUALITY( newTr.length(), tr.length() );
}
bool Rythmos::isInRange_cc(const TimeRange<TimeType> &tr, const TimeType &p)
{
  return (
    compareTimeValues(p,tr.lower()) >= 0
    && compareTimeValues(p,tr.upper()) <= 0
    );
}
TEUCHOS_UNIT_TEST( Rythmos_TimeRange, copyAndScale ) {
  TimeRange<double> tr(1.0,2.0);
  TimeRange<double> newTr = tr.copyAndScale(5.0);
  TEST_EQUALITY_CONST( newTr.isValid(), true );
  TEST_EQUALITY_CONST( newTr.lower(), 5.0 );
  TEST_EQUALITY_CONST( newTr.upper(), 10.0 );
  TEST_EQUALITY_CONST( newTr.length(), 5.0 );
}
TEUCHOS_UNIT_TEST( Rythmos_TimeRange, newTimeRange ) {
  TimeRange<double> tr;
  // it should be initialized as [0,-1]
  TEST_EQUALITY_CONST( tr.isValid(), false );
  TEST_COMPARE( tr.lower(), >, tr.upper() );
  TEST_EQUALITY_CONST( tr.isInRange(0.5), false );
  TEST_EQUALITY_CONST( tr.isInRange(0.0), false );
  TEST_EQUALITY_CONST( tr.isInRange(-1.0), false );
  TEST_EQUALITY_CONST( tr.length(), -1.0 );
}
void Rythmos::assertNoTimePointsInsideCurrentTimeRange(
  const InterpolationBufferBase<Scalar>& interpBuffer,
  const Array<Scalar>& time_vec
  )
{
  typedef ScalarTraits<Scalar> ST;
  const int numTimePoints = time_vec.size();
  const TimeRange<Scalar> currentTimeRange = interpBuffer.getTimeRange();
  if (currentTimeRange.length() >= ST::zero()) {
    for ( int i = 0; i < numTimePoints; ++i ) {
      TEST_FOR_EXCEPTION(
        currentTimeRange.isInRange(time_vec[i]), std::out_of_range,
        "Error, time_vec["<<i<<"] = " << time_vec[i] << " is in TimeRange of " 
        << interpBuffer.description() << " = ["
        << currentTimeRange.lower() << "," << currentTimeRange.upper() << "]!"
        );
    }
  }
}
Example #6
0
TEUCHOS_UNIT_TEST( Rythmos_ExplicitRKStepper, getTimeRange ) {
  {
    RCP<SinCosModel> model = sinCosModel(false);
    RCP<ExplicitRKStepper<double> > stepper = explicitRKStepper<double>(model);
    Thyra::ModelEvaluatorBase::InArgs<double> ic = model->getNominalValues();
    stepper->setInitialCondition(ic);
    TimeRange<double> tr = stepper->getTimeRange();
    TEST_EQUALITY_CONST( tr.isValid(), true );
    TEST_EQUALITY_CONST( tr.lower(), 0.0 );
    TEST_EQUALITY_CONST( tr.upper(), 0.0 );
    TEST_EQUALITY_CONST( tr.length(), 0.0 );
  }
  {
    RCP<SinCosModel> model = sinCosModel(false);
    RCP<ExplicitRKStepper<double> > stepper = explicitRKStepper<double>();
    stepper->setModel(model);
    TimeRange<double> tr;
    TEST_NOTHROW( tr = stepper->getTimeRange() );
    TEST_EQUALITY_CONST( tr.isValid(), false );
  }
} 
TEUCHOS_UNIT_TEST( BasicDiscreteAdjointStepperTester, rawNonlinearAdjoint )
{

  using Teuchos::outArg;
  using Teuchos::describe;
  using Teuchos::getParametersFromXmlString;
  typedef Thyra::ModelEvaluatorBase MEB;

  //
  out << "\nA) Create the nonlinear ME ...\n";
  //

  RCP<VanderPolModel> stateModel = vanderPolModel(
    getParametersFromXmlString(
      "<ParameterList>"
      "  <Parameter name=\"Implicit model formulation\" type=\"bool\" value=\"1\"/>"
      "</ParameterList>"
      )
    );

  //
  out << "\nB) Create the nonlinear solver ...\n";
  //

  RCP<TimeStepNonlinearSolver<double> > nlSolver = timeStepNonlinearSolver<double>(
    getParametersFromXmlString(
      "<ParameterList>"
      "  <Parameter name=\"Default Tol\" type=\"double\" value=\"1.0e-10\"/>"
      "  <Parameter name=\"Default Max Iters\" type=\"int\" value=\"20\"/>"
      "</ParameterList>"
      )
    );

  //
  out << "\nC) Create the integrator for the forward state problem ...\n";
  //

  RCP<IntegratorBuilder<double> > ib = integratorBuilder<double>(
    Teuchos::getParametersFromXmlString(
      "<ParameterList>"
      "  <ParameterList name=\"Stepper Settings\">"
      "    <ParameterList name=\"Stepper Selection\">"
      "      <Parameter name=\"Stepper Type\" type=\"string\" value=\"Backward Euler\"/>"
      "    </ParameterList>"
      "  </ParameterList>"
      "  <ParameterList name=\"Integration Control Strategy Selection\">"
      "    <Parameter name=\"Integration Control Strategy Type\" type=\"string\""
      "      value=\"Simple Integration Control Strategy\"/>"
      "    <ParameterList name=\"Simple Integration Control Strategy\">"
      "      <Parameter name=\"Take Variable Steps\" type=\"bool\" value=\"false\"/>"
      "      <Parameter name=\"Fixed dt\" type=\"double\" value=\"0.5\"/>" // Gives 2 time steps!
      "    </ParameterList>"
      "  </ParameterList>"
      "  <ParameterList name=\"Interpolation Buffer Settings\">"
      "    <ParameterList name=\"Trailing Interpolation Buffer Selection\">"
      "      <Parameter name=\"Interpolation Buffer Type\" type=\"string\" value=\"Interpolation Buffer\"/>"
      "    </ParameterList>"
      "  </ParameterList>"
      "</ParameterList>"
      )
    );
  
  MEB::InArgs<double> ic = stateModel->getNominalValues();
  RCP<IntegratorBase<double> > integrator = ib->create(stateModel, ic, nlSolver);
  //integrator->setVerbLevel(Teuchos::VERB_EXTREME);

  // ToDo: Set the trailing IB to pick up the entire state solution!

  // 
  out << "\nD) Solve the basic forward problem ...\n";
  //

  const TimeRange<double> fwdTimeRange = integrator->getFwdTimeRange();
  const double t_final = fwdTimeRange.upper();
  RCP<const Thyra::VectorBase<double> > x_final, x_dot_final;
  get_fwd_x_and_x_dot( *integrator, t_final, outArg(x_final), outArg(x_dot_final) );

  out << "\nt_final = " << t_final << "\n";
  out << "\nx_final: " << *x_final;
  out << "\nx_dot_final: " << *x_dot_final;

  //
  out << "\nE) Create the basic adjoint model (no distributed response) ...\n";
  //

  RCP<AdjointModelEvaluator<double> > adjModel =
    adjointModelEvaluator<double>(
      stateModel, fwdTimeRange
      );
  adjModel->setFwdStateSolutionBuffer(integrator);

  //
  out << "\nF) Create a stepper and integrator for the adjoint ...\n";
  //
  
  RCP<Thyra::LinearNonlinearSolver<double> > adjTimeStepSolver =
    Thyra::linearNonlinearSolver<double>();
  RCP<Rythmos::StepperBase<double> > adjStepper =
    integrator->getStepper()->cloneStepperAlgorithm();

  //
  out << "\nG) Set up the initial condition for the adjoint at the final time ...\n";
  //
  
  const RCP<const Thyra::VectorSpaceBase<double> >
    f_space = stateModel->get_f_space();
  
  // lambda(t_final) = x_final
  const RCP<Thyra::VectorBase<double> > lambda_ic = createMember(f_space);
  V_V( lambda_ic.ptr(), *x_final );
  
  // lambda_dot(t_final,i) = 0.0
  const RCP<Thyra::VectorBase<double> > lambda_dot_ic = createMember(f_space);
  Thyra::V_S( lambda_dot_ic.ptr(), 0.0 );
  
  MEB::InArgs<double> adj_ic = adjModel->getNominalValues();
  adj_ic.set_x(lambda_ic);
  adj_ic.set_x_dot(lambda_dot_ic);
  out << "\nadj_ic: " << describe(adj_ic, Teuchos::VERB_EXTREME);

  RCP<Rythmos::IntegratorBase<double> > adjIntegrator =
    ib->create(adjModel, adj_ic, adjTimeStepSolver);
  
  //
  out << "\nH) Integrate the adjoint backwards in time (using backward time) ...\n";
  //
  
  adjStepper->setInitialCondition(adj_ic);
  adjIntegrator->setStepper(adjStepper, fwdTimeRange.length());
  
  const double adj_t_final = fwdTimeRange.length();
  RCP<const Thyra::VectorBase<double> > lambda_final, lambda_dot_final;
  get_fwd_x_and_x_dot( *adjIntegrator, adj_t_final,
    outArg(lambda_final), outArg(lambda_dot_final) );

  out << "\nadj_t_final = " << adj_t_final << "\n";
  out << "\nlambda_final: " << *lambda_final;
  out << "\nlambda_dot_final: " << *lambda_dot_final;

}
void PointwiseInterpolationBufferAppender<Scalar>::append(
  const InterpolationBufferBase<Scalar>& interpBuffSource, 
  const TimeRange<Scalar>& appendRange,
  const Ptr<InterpolationBufferBase<Scalar> > &interpBuffSink 
  ) 
{
  TEUCHOS_ASSERT( !is_null(interpBuffSink) );
#ifdef RYTHMOS_DEBUG
  this->assertAppendPreconditions(interpBuffSource,appendRange,*interpBuffSink);
#endif // RYTHMOS_DEBUG

  RCP<Teuchos::FancyOStream> out = this->getOStream();
  Teuchos::OSTab ostab(out,1,"PointwiseInterpolationBufferAppender::append");
  if ( Teuchos::as<int>(this->getVerbLevel()) >= Teuchos::as<int>(Teuchos::VERB_HIGH) ) {
    *out << "Interpolation Buffer source range = [" << interpBuffSource.getTimeRange().lower() << "," <<
      interpBuffSource.getTimeRange().upper() << "]" << std::endl;
    *out << "Append range = [" << appendRange.lower() << "," << appendRange.upper() << "]" << std::endl;
    *out << "Interpolation Buffer sink range = [" << interpBuffSink->getTimeRange().lower() << "," <<
      interpBuffSink->getTimeRange().upper() << "]" << std::endl;
  }
  // Set up appendRange correctly to be either (] or [):
  RCP<const TimeRange<Scalar> > correctedAppendRange = Teuchos::rcp(&appendRange,false);
  if (compareTimeValues<Scalar>(interpBuffSink->getTimeRange().upper(),appendRange.lower()) == 0) {
    // adding to end of buffer 
    correctedAppendRange = Teuchos::rcp(new TimeRange_oc<Scalar>(appendRange));
    if ( Teuchos::as<int>(this->getVerbLevel()) >= Teuchos::as<int>(Teuchos::VERB_HIGH) ) {
      *out << "Corrected append range = (" << correctedAppendRange->lower() << "," << 
        correctedAppendRange->upper() << "]" << std::endl;
    }
  } 
  else if (compareTimeValues<Scalar>(interpBuffSink->getTimeRange().lower(),appendRange.upper()) == 0) {
    // adding to beginning of buffer
    correctedAppendRange = Teuchos::rcp(new TimeRange_co<Scalar>(appendRange));
    if ( Teuchos::as<int>(this->getVerbLevel()) >= Teuchos::as<int>(Teuchos::VERB_HIGH) ) {
      *out << "Corrected append range = [" << correctedAppendRange->lower() << "," << 
        correctedAppendRange->upper() << ")" << std::endl;
    }
  }

  Array<Scalar> time_vec_in;
  interpBuffSource.getNodes(&time_vec_in);

  Array<Scalar> time_vec;
  selectPointsInTimeRange(time_vec_in,*correctedAppendRange,Teuchos::outArg(time_vec));
  if ( Teuchos::as<int>(this->getVerbLevel()) >= Teuchos::as<int>(Teuchos::VERB_HIGH) ) {
    *out << "Selected points for appending to sink buffer: " << time_vec << std::endl;
  }

  Array<RCP<const Thyra::VectorBase<Scalar> > > x_vec;
  Array<RCP<const Thyra::VectorBase<Scalar> > > xdot_vec;
  Array<ScalarMag> accuracy_vec;
  interpBuffSource.getPoints(time_vec, &x_vec, &xdot_vec, &accuracy_vec);

  if ( Teuchos::as<int>(this->getVerbLevel()) >= Teuchos::as<int>(Teuchos::VERB_HIGH) ) {
    *out << "Sink buffer range before addPoints = [" << interpBuffSink->getTimeRange().lower() << "," <<
      interpBuffSink->getTimeRange().upper() << "]" << std::endl;
  }

  interpBuffSink->addPoints(time_vec, x_vec, xdot_vec);

  if ( Teuchos::as<int>(this->getVerbLevel()) >= Teuchos::as<int>(Teuchos::VERB_HIGH) ) {
    *out << "Sink buffer range after addPoints = [" << interpBuffSink->getTimeRange().lower() << "," <<
      interpBuffSink->getTimeRange().upper() << "]" << std::endl;
  }

}
bool DefaultIntegrator<Scalar>::advanceStepperToTime( const Scalar& advance_to_t )
{

#ifdef ENABLE_RYTHMOS_TIMERS
  TEUCHOS_FUNC_TIME_MONITOR_DIFF("Rythmos:DefaultIntegrator::advanceStepperToTime",
    TopLevel);
#endif

  using std::endl;
  typedef std::numeric_limits<Scalar> NL;
  using Teuchos::incrVerbLevel; 
#ifndef _MSC_VER
  using Teuchos::Describable;
#endif
  using Teuchos::OSTab;
  typedef Teuchos::ScalarTraits<Scalar> ST;

  RCP<Teuchos::FancyOStream> out = this->getOStream();
  Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();

  if (!is_null(integrationControlStrategy_)) {
    integrationControlStrategy_->setOStream(out);
    integrationControlStrategy_->setVerbLevel(incrVerbLevel(verbLevel,-1));
  }

  if (!is_null(integrationObserver_)) {
    integrationObserver_->setOStream(out);
    integrationObserver_->setVerbLevel(incrVerbLevel(verbLevel,-1));
  }

  if ( includesVerbLevel(verbLevel,Teuchos::VERB_LOW) )
    *out << "\nEntering " << this->Describable::description()
         << "::advanceStepperToTime("<<advance_to_t<<") ...\n";

  // Remember what timestep index we are on so we can report it later
  const int initCurrTimeStepIndex = currTimeStepIndex_;

  // Take steps until we the requested time is reached (or passed)

  TimeRange<Scalar> currStepperTimeRange = stepper_->getTimeRange();

  // Start by assume we can reach the time advance_to_t
  bool return_val = true;
  
  while ( !currStepperTimeRange.isInRange(advance_to_t) ) {

    // Halt immediatly if exceeded max iterations
    if (currTimeStepIndex_ >= maxNumTimeSteps_) {
      if ( includesVerbLevel(verbLevel,Teuchos::VERB_LOW) )
        *out
          << "\n***"
          << "\n*** NOTICE: currTimeStepIndex = "<<currTimeStepIndex_
          << " >= maxNumTimeSteps = "<<maxNumTimeSteps_<< ", halting time integration!"
          << "\n***\n";
      return_val = false;
      break; // Exit the loop immediately!
    }

    if ( includesVerbLevel(verbLevel,Teuchos::VERB_LOW) )
      *out << "\nTake step:  current_stepper_t = " << currStepperTimeRange.upper()
           << ", currTimeStepIndex = " << currTimeStepIndex_ << endl;

    //
    // A) Reinitialize if a hard breakpoint was reached on the last time step
    //

    if (stepCtrlInfoLast_.limitedByBreakPoint) {
      if ( stepCtrlInfoLast_.breakPointType == BREAK_POINT_TYPE_HARD ) {
#ifdef ENABLE_RYTHMOS_TIMERS
        TEUCHOS_FUNC_TIME_MONITOR("Rythmos:DefaultIntegrator::restart");
#endif
        if ( includesVerbLevel(verbLevel,Teuchos::VERB_LOW) )
          *out << "\nAt a hard-breakpoint, restarting time integrator ...\n";
        restart(&*stepper_);
      }
      else  {
        if ( includesVerbLevel(verbLevel,Teuchos::VERB_LOW) )
          *out << "\nAt a soft-breakpoint, NOT restarting time integrator ...\n";
      }
    }

    //
    // B) Get the trial step control info
    //

    StepControlInfo<Scalar> trialStepCtrlInfo;
    {
#ifdef ENABLE_RYTHMOS_TIMERS
      TEUCHOS_FUNC_TIME_MONITOR("Rythmos:DefaultIntegrator::advanceStepperToTime: getStepCtrl");
#endif
      if (!is_null(integrationControlStrategy_)) {
        // Let an external strategy object determine the step size and type.
        // Note that any breakpoint info is also related through this call.
        trialStepCtrlInfo = integrationControlStrategy_->getNextStepControlInfo(
          *stepper_, stepCtrlInfoLast_, currTimeStepIndex_
          );
      }
      else {
        // Take a variable step if we have no control strategy
        trialStepCtrlInfo.stepType = STEP_TYPE_VARIABLE;
        trialStepCtrlInfo.stepSize = NL::max();
      }
    }

    // Print the initial trial step
    if ( includesVerbLevel(verbLevel,Teuchos::VERB_MEDIUM) ) {
      *out << "\nTrial step:\n";
      OSTab tab(out);
      *out << trialStepCtrlInfo;
    }

    // Halt immediately if we where told to do so
    if (trialStepCtrlInfo.stepSize < ST::zero()) {
      if ( includesVerbLevel(verbLevel,Teuchos::VERB_MEDIUM) )
        *out
          << "\n***"
          << "\n*** NOTICE: The IntegrationControlStrategy object return stepSize < 0.0, halting time integration!"
          << "\n***\n";
      return_val = false;
      break; // Exit the loop immediately!
    }

    // Make sure we don't step past the final time if asked not to
    bool updatedTrialStepCtrlInfo = false;
    {
      const Scalar finalTime = integrationTimeDomain_.upper();
      if (landOnFinalTime_ && trialStepCtrlInfo.stepSize + currStepperTimeRange.upper() > finalTime) {
        if ( includesVerbLevel(verbLevel,Teuchos::VERB_LOW) )
          *out << "\nCutting trial step to avoid stepping past final time ...\n";
        trialStepCtrlInfo.stepSize = finalTime - currStepperTimeRange.upper();
        updatedTrialStepCtrlInfo = true;
      }
    }
    
    // Print the modified trial step
    if ( updatedTrialStepCtrlInfo
      && includesVerbLevel(verbLevel,Teuchos::VERB_MEDIUM) )
    {
      *out << "\nUpdated trial step:\n";
      OSTab tab(out);
      *out << trialStepCtrlInfo;
    }

    //
    // C) Take the step
    //

    // Print step type and size
    if ( includesVerbLevel(verbLevel,Teuchos::VERB_MEDIUM) ) {
      if (trialStepCtrlInfo.stepType == STEP_TYPE_VARIABLE)
        *out << "\nTaking a variable time step with max step size = "
             << trialStepCtrlInfo.stepSize << " ....\n";
      else
        *out << "\nTaking a fixed time step of size = "
             << trialStepCtrlInfo.stepSize << " ....\n";
    }

    // Take step
    Scalar stepSizeTaken;
    {
#ifdef ENABLE_RYTHMOS_TIMERS
      TEUCHOS_FUNC_TIME_MONITOR("Rythmos:DefaultIntegrator::advanceStepperToTime: takeStep");
#endif
      stepSizeTaken = stepper_->takeStep(
        trialStepCtrlInfo.stepSize, trialStepCtrlInfo.stepType
        );
    }

    // Validate step taken
    if (trialStepCtrlInfo.stepType == STEP_TYPE_VARIABLE) {
      TEST_FOR_EXCEPTION(
        stepSizeTaken < ST::zero(), std::logic_error,
        "Error, stepper took negative step of dt = " << stepSizeTaken << "!\n"
        );
      TEST_FOR_EXCEPTION(
        stepSizeTaken > trialStepCtrlInfo.stepSize, std::logic_error,
        "Error, stepper took step of dt = " << stepSizeTaken
        << " > max step size of = " << trialStepCtrlInfo.stepSize << "!\n"
        );
    }
    else { // STEP_TYPE_FIXED
      TEST_FOR_EXCEPTION(
        stepSizeTaken != trialStepCtrlInfo.stepSize, std::logic_error,
        "Error, stepper took step of dt = " << stepSizeTaken 
        << " when asked to take step of dt = " << trialStepCtrlInfo.stepSize << "\n"
        );
    }

    // Update info about this step
    currStepperTimeRange = stepper_->getTimeRange();
    const StepControlInfo<Scalar> stepCtrlInfo =
      stepCtrlInfoTaken(trialStepCtrlInfo,stepSizeTaken);

    // Print the step actually taken 
    if ( includesVerbLevel(verbLevel,Teuchos::VERB_MEDIUM) ) {
      *out << "\nStep actually taken:\n";
      OSTab tab(out);
      *out << stepCtrlInfo;
    }

    // Append the trailing interpolation buffer (if defined)
    if (!is_null(trailingInterpBuffer_)) {
      interpBufferAppender_->append(*stepper_,currStepperTimeRange,
        trailingInterpBuffer_.ptr() );
    }

    //
    // D) Output info about step
    //

    {

#ifdef ENABLE_RYTHMOS_TIMERS
      TEUCHOS_FUNC_TIME_MONITOR("Rythmos:DefaultIntegrator::advanceStepperToTime: output");
#endif
      
      // Print our own brief output
      if ( includesVerbLevel(verbLevel,Teuchos::VERB_MEDIUM) ) {
        StepStatus<Scalar> stepStatus = stepper_->getStepStatus();
        *out << "\nTime point reached = " << stepStatus.time << endl;
        *out << "\nstepStatus:\n" << stepStatus;
        if ( includesVerbLevel(verbLevel,Teuchos::VERB_EXTREME) ) {
          RCP<const Thyra::VectorBase<Scalar> >
            solution = stepStatus.solution,
            solutionDot = stepStatus.solutionDot;
          if (!is_null(solution))
            *out << "\nsolution = \n" << Teuchos::describe(*solution,verbLevel);
          if (!is_null(solutionDot))
            *out << "\nsolutionDot = \n" << Teuchos::describe(*solutionDot,verbLevel);
        }
      }
      
      // Output to the observer
      if (!is_null(integrationObserver_))
        integrationObserver_->observeCompletedTimeStep(
          *stepper_, stepCtrlInfo, currTimeStepIndex_
          );

    }

    //
    // E) Update info for next time step
    //

    stepCtrlInfoLast_ = stepCtrlInfo;
    ++currTimeStepIndex_;
    
  }

  if ( includesVerbLevel(verbLevel,Teuchos::VERB_LOW) )
    *out << "\nNumber of steps taken in this call to advanceStepperToTime(...) = "
         << (currTimeStepIndex_ - initCurrTimeStepIndex) << endl
         << "\nLeaving" << this->Describable::description()
         << "::advanceStepperToTime("<<advance_to_t<<") ...\n";

  return return_val;
  
}
TEUCHOS_UNIT_TEST( Rythmos_GlobalErrorEstimator, SinCos ) {
  typedef Teuchos::ScalarTraits<double> ST;
  // Forward Solve, storing data in linear interpolation buffer
  int storageLimit = 100;
  double finalTime = 0.1;
  double dt = 0.1;
  RCP<IntegratorBuilder<double> > ib = integratorBuilder<double>();
  {
    RCP<ParameterList> ibPL = Teuchos::parameterList();
    ibPL->sublist("Integrator Settings").sublist("Integrator Selection").set("Integrator Type","Default Integrator");
    ibPL->sublist("Integrator Settings").set("Final Time",finalTime);
    ibPL->sublist("Integration Control Strategy Selection").set("Integration Control Strategy Type","Simple Integration Control Strategy");
    ibPL->sublist("Integration Control Strategy Selection").sublist("Simple Integration Control Strategy").set("Take Variable Steps",false);
    ibPL->sublist("Integration Control Strategy Selection").sublist("Simple Integration Control Strategy").set("Fixed dt",dt);

    ibPL->sublist("Stepper Settings").sublist("Stepper Selection").set("Stepper Type","Backward Euler");
    //ibPL->sublist("Stepper Settings").sublist("Stepper Selection").set("Stepper Type","Implicit RK");
    //ibPL->sublist("Stepper Settings").sublist("Runge Kutta Butcher Tableau Selection").set("Runge Kutta Butcher Tableau Type","Backward Euler");
    ibPL->sublist("Interpolation Buffer Settings").sublist("Trailing Interpolation Buffer Selection").set("Interpolation Buffer Type","Interpolation Buffer");
    ibPL->sublist("Interpolation Buffer Settings").sublist("Trailing Interpolation Buffer Selection").sublist("Interpolation Buffer").set("StorageLimit",storageLimit);
    ibPL->sublist("Interpolation Buffer Settings").sublist("Interpolator Selection").set("Interpolator Type","Linear Interpolator");
    ib->setParameterList(ibPL);
  }
  RCP<SinCosModel> fwdModel = sinCosModel(true); // implicit formulation
  Thyra::ModelEvaluatorBase::InArgs<double> fwdIC = fwdModel->getNominalValues();
  RCP<Thyra::NonlinearSolverBase<double> > fwdNLSolver = timeStepNonlinearSolver<double>();
  RCP<IntegratorBase<double> > fwdIntegrator = ib->create(fwdModel,fwdIC,fwdNLSolver);
  RCP<const VectorBase<double> > x_final;
  {
    Array<double> time_vec;
    time_vec.push_back(finalTime);
    Array<RCP<const Thyra::VectorBase<double> > > x_final_array;
    fwdIntegrator->getFwdPoints(time_vec,&x_final_array,NULL,NULL);
    x_final = x_final_array[0];
  }
  // Verify x_final is correct
  {
    // Defaults from SinCos Model:
    double f = 1.0;
    double L = 1.0;
    double a = 0.0;
    double x_ic_0 = 0.0;
    double x_ic_1 = 1.0;
    double x_0 = dt/(1.0+std::pow(dt*f/L,2))*(x_ic_0/dt+x_ic_1+dt*std::pow(f/L,2)*a);
    double x_1 = dt/(1.0+std::pow(dt*f/L,2))*(-std::pow(f/L,2)*x_ic_0+x_ic_1/dt+std::pow(f/L,2)*a);
    double tol = 1.0e-10;
    Thyra::ConstDetachedVectorView<double> x_final_view( *x_final );
    TEST_FLOATING_EQUALITY( x_final_view[0], x_0, tol );
    TEST_FLOATING_EQUALITY( x_final_view[1], x_1, tol );
  }
  // Copy InterpolationBuffer data into Cubic Spline interpolation buffer for use in Adjoint Solve
  TimeRange<double> fwdTimeRange; 
  RCP<InterpolationBufferBase<double> > fwdCubicSplineInterpBuffer;
  {
    RCP<PointwiseInterpolationBufferAppender<double> > piba = pointwiseInterpolationBufferAppender<double>();
    RCP<InterpolationBuffer<double> > sinkInterpBuffer = interpolationBuffer<double>();
    sinkInterpBuffer->setStorage(storageLimit);
    RCP<CubicSplineInterpolator<double> > csi = cubicSplineInterpolator<double>();
    sinkInterpBuffer->setInterpolator(csi);
    RCP<const InterpolationBufferBase<double> > sourceInterpBuffer;
    {
      RCP<TrailingInterpolationBufferAcceptingIntegratorBase<double> > tibaib = 
        Teuchos::rcp_dynamic_cast<TrailingInterpolationBufferAcceptingIntegratorBase<double> >(fwdIntegrator,true);
      sourceInterpBuffer = tibaib->getTrailingInterpolationBuffer();
    }
    fwdTimeRange = sourceInterpBuffer->getTimeRange();
    piba->append(*sourceInterpBuffer, fwdTimeRange, Teuchos::outArg(*sinkInterpBuffer));
    fwdCubicSplineInterpBuffer = sinkInterpBuffer;

    TimeRange<double> sourceRange = sourceInterpBuffer->getTimeRange();
    TimeRange<double> sinkRange = sinkInterpBuffer->getTimeRange();
    TEST_EQUALITY( sourceRange.lower(), sinkRange.lower() );
    TEST_EQUALITY( sourceRange.upper(), sinkRange.upper() );
  }
  // Adjoint Solve, reading forward solve data from Cubic Spline interpolation buffer
  {
    RCP<ParameterList> ibPL = Teuchos::parameterList();
    ibPL->sublist("Integrator Settings").sublist("Integrator Selection").set("Integrator Type","Default Integrator");
    ibPL->sublist("Integrator Settings").set("Final Time",finalTime);
    ibPL->sublist("Integration Control Strategy Selection").set("Integration Control Strategy Type","Simple Integration Control Strategy");
    ibPL->sublist("Integration Control Strategy Selection").sublist("Simple Integration Control Strategy").set("Take Variable Steps",false);
    ibPL->sublist("Integration Control Strategy Selection").sublist("Simple Integration Control Strategy").set("Fixed dt",dt);

    ibPL->sublist("Stepper Settings").sublist("Stepper Selection").set("Stepper Type","Backward Euler");
    //ibPL->sublist("Stepper Settings").sublist("Stepper Selection").set("Stepper Type","Implicit RK");
    //ibPL->sublist("Stepper Settings").sublist("Runge Kutta Butcher Tableau Selection").set("Runge Kutta Butcher Tableau Type","Implicit 1 Stage 2nd order Gauss");
    ibPL->sublist("Interpolation Buffer Settings").sublist("Trailing Interpolation Buffer Selection").set("Interpolation Buffer Type","Interpolation Buffer");
    ibPL->sublist("Interpolation Buffer Settings").sublist("Trailing Interpolation Buffer Selection").sublist("Interpolation Buffer").set("StorageLimit",storageLimit);
    ibPL->sublist("Interpolation Buffer Settings").sublist("Interpolator Selection").set("Interpolator Type","Linear Interpolator");
    ib->setParameterList(ibPL);
  }
  RCP<Thyra::ModelEvaluator<double> > adjModel;
  {
    RCP<Rythmos::AdjointModelEvaluator<double> > model = 
      Rythmos::adjointModelEvaluator<double>(
          fwdModel, fwdTimeRange
          );
    //model->setFwdStateSolutionBuffer(fwdCubicSplineInterpBuffer);
    adjModel = model;
  }
  Thyra::ModelEvaluatorBase::InArgs<double> adjIC = adjModel->getNominalValues();
  double phi_ic_0 = 2.0;
  double phi_ic_1 = 3.0;
  {
    // Initial conditions for adjoint:
    const RCP<const Thyra::VectorSpaceBase<double> >
      f_space = fwdModel->get_f_space();
    const RCP<Thyra::VectorBase<double> > x_ic = createMember(f_space);
    {
      Thyra::DetachedVectorView<double> x_ic_view( *x_ic );
      x_ic_view[0] = phi_ic_0;
      x_ic_view[1] = phi_ic_1;
    }
    const RCP<Thyra::VectorBase<double> > xdot_ic = createMember(f_space);
    V_S( Teuchos::outArg(*xdot_ic), ST::zero() );
    adjIC.set_x(x_ic);
    adjIC.set_x_dot(xdot_ic);
  }
  RCP<Thyra::LinearNonlinearSolver<double> > adjNLSolver = Thyra::linearNonlinearSolver<double>();
  RCP<IntegratorBase<double> > adjIntegrator = ib->create(adjModel,adjIC,adjNLSolver);
  RCP<const VectorBase<double> > phi_final;
  {
    Array<double> time_vec;
    time_vec.push_back(finalTime);
    Array<RCP<const Thyra::VectorBase<double> > > phi_final_array;
    adjIntegrator->getFwdPoints(time_vec,&phi_final_array,NULL,NULL);
    phi_final = phi_final_array[0];
  }
  // Verify phi_final is correct
  {
    // Defaults from SinCos Model:
    double f = 1.0;
    double L = 1.0;
    double h = -dt;
    double phi_0 = 1.0/(1.0+std::pow(f*h/L,2.0))*(phi_ic_0+std::pow(f/L,2.0)*h*phi_ic_1);
    double phi_1 = 1.0/(1.0+std::pow(f*h/L,2.0))*(-h*phi_ic_0+phi_ic_1);
    double tol = 1.0e-10;
    Thyra::ConstDetachedVectorView<double> phi_final_view( *phi_final );
    TEST_FLOATING_EQUALITY( phi_final_view[0], phi_0, tol );
    TEST_FLOATING_EQUALITY( phi_final_view[1], phi_1, tol );
  }
  // Compute error estimate
  //TEST_ASSERT( false );
}
TEUCHOS_UNIT_TEST( Rythmos_TimeRange, invalidTimeRange ) {
  TimeRange<double> tr = invalidTimeRange<double>();
  TEST_EQUALITY_CONST( tr.isValid(), false );
  TEST_COMPARE( tr.lower(), >, tr.upper() );
  TEST_EQUALITY_CONST( tr.isInRange(0.5), false );
}
TEUCHOS_UNIT_TEST( Rythmos_TimeRange, nonMemberConstructor ) {
  TimeRange<double> tr = timeRange(1.25,3.45);
  TEST_EQUALITY_CONST( tr.isValid(), true );
  TEST_EQUALITY_CONST( tr.lower(), 1.25 );
  TEST_EQUALITY_CONST( tr.upper(), 3.45 );
}