Rythmos_ImplicitRKStepper.hpp

00001 //@HEADER
00002 // ***********************************************************************
00003 //
00004 //                           Rythmos Package
00005 //                 Copyright (2006) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Todd S. Coffey (tscoffe@sandia.gov)
00025 //
00026 // ***********************************************************************
00027 //@HEADER
00028 
00029 #ifndef Rythmos_IMPLICIT_RK_STEPPER_H
00030 #define Rythmos_IMPLICIT_RK_STEPPER_H
00031 
00032 #include "Rythmos_Types.hpp"
00033 #include "Rythmos_StepperBase.hpp"
00034 #include "Rythmos_DataStore.hpp"
00035 #include "Rythmos_LinearInterpolator.hpp"
00036 #include "Rythmos_SingleResidualModelEvaluator.hpp"
00037 #include "Rythmos_SolverAcceptingStepperBase.hpp"
00038 #include "Rythmos_ImplicitRKModelEvaluator.hpp"
00039 
00040 #include "Thyra_VectorBase.hpp"
00041 #include "Thyra_ModelEvaluator.hpp"
00042 #include "Thyra_ModelEvaluatorHelpers.hpp"
00043 #include "Thyra_ProductVectorBase.hpp"
00044 #include "Thyra_AssertOp.hpp"
00045 #include "Thyra_NonlinearSolverBase.hpp"
00046 #include "Thyra_TestingTools.hpp"
00047 
00048 #include "Teuchos_VerboseObjectParameterListHelpers.hpp"
00049 #include "Teuchos_as.hpp"
00050 
00051 
00052 namespace Rythmos {
00053 
00054 
00056 template<class Scalar>
00057 class ImplicitRKStepper : virtual public SolverAcceptingStepperBase<Scalar>
00058 {
00059 public:
00060   
00062   typedef typename ScalarTraits<Scalar>::magnitudeType ScalarMag;
00063   
00066 
00068   ImplicitRKStepper();
00069   
00071   void initialize(
00072     const RCP<const Thyra::ModelEvaluator<Scalar> >  &model,
00073     const RCP<Thyra::NonlinearSolverBase<Scalar> >  &solver,
00074     const RCP<Thyra::LinearOpWithSolveFactoryBase<Scalar> > &irk_W_factory
00075     );
00076   
00078   void setInterpolator(RCP<InterpolatorBase<Scalar> > interpolator);
00079   
00081   RCP<InterpolatorBase<Scalar> > unsetInterpolator();
00082 
00084 
00087 
00089   void setSolver(
00090     const RCP<Thyra::NonlinearSolverBase<Scalar> > &solver
00091     );
00092 
00094   RCP<Thyra::NonlinearSolverBase<Scalar> >
00095   getNonconstSolver();
00096 
00098   RCP<const Thyra::NonlinearSolverBase<Scalar> >
00099   getSolver() const;
00100 
00102 
00105  
00107   bool supportsCloning() const;
00108 
00110   RCP<StepperBase<Scalar> > cloneStepperAlgorithm() const;
00111 
00113   void setModel(const RCP<const Thyra::ModelEvaluator<Scalar> > &model);
00114   
00116   RCP<const Thyra::ModelEvaluator<Scalar> >
00117   getModel() const;
00118 
00120   void setInitialCondition(
00121     const Thyra::ModelEvaluatorBase::InArgs<Scalar> &initialCondition
00122     );
00123 
00125   Scalar takeStep(Scalar dt, StepSizeType flag);
00126   
00128   const StepStatus<Scalar> getStepStatus() const;
00129   
00131 
00134 
00136   RCP<const Thyra::VectorSpaceBase<Scalar> >
00137   get_x_space() const;
00138 
00140   void addPoints(
00141     const Array<Scalar>& time_vec,
00142     const Array<RCP<const Thyra::VectorBase<Scalar> > >& x_vec,
00143     const Array<RCP<const Thyra::VectorBase<Scalar> > >& xdot_vec
00144     );
00145   
00147   TimeRange<Scalar> getTimeRange() const;
00148   
00150   void getPoints(
00151     const Array<Scalar>& time_vec,
00152     Array<RCP<const Thyra::VectorBase<Scalar> > >* x_vec,
00153     Array<RCP<const Thyra::VectorBase<Scalar> > >* xdot_vec,
00154     Array<ScalarMag>* accuracy_vec
00155     ) const;
00156   
00158   void getNodes(Array<Scalar>* time_vec) const;
00159   
00161   void removeNodes(Array<Scalar>& time_vec);
00162 
00164   int getOrder() const;
00165 
00167   
00170 
00172   void setParameterList(RCP<ParameterList> const& paramList);
00173   
00175   RCP<ParameterList> getNonconstParameterList();
00176   
00178   RCP<ParameterList> unsetParameterList();
00179   
00181   RCP<const ParameterList> getValidParameters() const;
00182  
00184 
00187   
00189   void describe(
00190     FancyOStream  &out,
00191     const Teuchos::EVerbosityLevel verbLevel
00192     ) const;
00193 
00195 
00196 private:
00197 
00198   // ///////////////////////
00199   // Private date members
00200 
00201   bool isInitialized_;
00202   RCP<const Thyra::ModelEvaluator<Scalar> > model_;
00203   RCP<Thyra::NonlinearSolverBase<Scalar> > solver_;
00204   RCP<Thyra::LinearOpWithSolveFactoryBase<Scalar> > irk_W_factory_;
00205   RCP<ParameterList> paramList_;
00206 
00207   int numStages_; // Temp hack to select between first and second order!
00208 
00209   Thyra::ModelEvaluatorBase::InArgs<Scalar> basePoint_;
00210   RCP<Thyra::VectorBase<Scalar> > x_;
00211   RCP<Thyra::VectorBase<Scalar> > x_old_;
00212   RCP<Thyra::VectorBase<Scalar> > x_dot_;
00213 
00214   TimeRange<Scalar> timeRange_;
00215 
00216   RCP<ImplicitRKModelEvaluator<Scalar> > irkModel_;
00217   RKButcherTableau<Scalar> irkButcherTableau_;
00218 
00219   // Cache
00220   RCP<Thyra::ProductVectorBase<Scalar> > x_stage_bar_;
00221 
00222   // //////////////////////////
00223   // Private member functions
00224 
00225   void initialize_();
00226 
00227 };
00228 
00229 
00234 template<class Scalar>
00235 RCP<ImplicitRKStepper<Scalar> >
00236 implicitRKStepper(
00237   const RCP<const Thyra::ModelEvaluator<Scalar> >  &model,
00238   const RCP<Thyra::NonlinearSolverBase<Scalar> >  &solver,
00239   const RCP<Thyra::LinearOpWithSolveFactoryBase<Scalar> > &irk_W_factory
00240   )
00241 {
00242   RCP<ImplicitRKStepper<Scalar> > stepper(new ImplicitRKStepper<Scalar>());
00243   stepper->initialize( model, solver, irk_W_factory );
00244   return stepper;
00245 }
00246 
00247 
00248 // ////////////////////////////
00249 // Defintions
00250 
00251 
00252 // Constructors, intializers, Misc.
00253 
00254 
00255 template<class Scalar>
00256 ImplicitRKStepper<Scalar>::ImplicitRKStepper()
00257   : isInitialized_(false),
00258     numStages_(1)
00259 {}
00260 
00261 
00262 template<class Scalar>
00263 void ImplicitRKStepper<Scalar>::initialize(
00264   const RCP<const Thyra::ModelEvaluator<Scalar> > &model,
00265   const RCP<Thyra::NonlinearSolverBase<Scalar> > &solver,
00266   const RCP<Thyra::LinearOpWithSolveFactoryBase<Scalar> > &irk_W_factory
00267   )
00268 {
00269 
00270   // ToDo: Validate input
00271 
00272   model_ = model;
00273   solver_ = solver;
00274   irk_W_factory_ = irk_W_factory;
00275 
00276 }
00277 
00278 
00279 template<class Scalar>
00280 void ImplicitRKStepper<Scalar>::setInterpolator(
00281   RCP<InterpolatorBase<Scalar> > interpolator
00282   )
00283 {
00284   TEST_FOR_EXCEPT(true);
00285 }
00286 
00287 
00288 template<class Scalar>
00289 RCP<InterpolatorBase<Scalar> >
00290 ImplicitRKStepper<Scalar>::unsetInterpolator()
00291 {
00292   TEST_FOR_EXCEPT(true);
00293   return Teuchos::null;
00294 }
00295 
00296 
00297 // Overridden from SolverAcceptingStepperBase
00298 
00299 
00300 template<class Scalar>
00301 void ImplicitRKStepper<Scalar>::setSolver(
00302   const RCP<Thyra::NonlinearSolverBase<Scalar> > &solver
00303   )
00304 {
00305   TEST_FOR_EXCEPT(true);
00306 }
00307 
00308 
00309 template<class Scalar>
00310 RCP<Thyra::NonlinearSolverBase<Scalar> >
00311 ImplicitRKStepper<Scalar>::getNonconstSolver()
00312 {
00313   return solver_;
00314 }
00315 
00316 
00317 template<class Scalar>
00318 RCP<const Thyra::NonlinearSolverBase<Scalar> >
00319 ImplicitRKStepper<Scalar>::getSolver() const
00320 {
00321   return solver_;
00322 }
00323 
00324 
00325 // Overridden from StepperBase
00326  
00327 
00328 template<class Scalar>
00329 bool ImplicitRKStepper<Scalar>::supportsCloning() const
00330 {
00331   return true;
00332 }
00333 
00334 
00335 template<class Scalar>
00336 RCP<StepperBase<Scalar> >
00337 ImplicitRKStepper<Scalar>::cloneStepperAlgorithm() const
00338 {
00339   TEST_FOR_EXCEPT(true);
00340   return Teuchos::null;
00341 }
00342 
00343 
00344 template<class Scalar>
00345 void ImplicitRKStepper<Scalar>::setModel(
00346   const RCP<const Thyra::ModelEvaluator<Scalar> > &model
00347   )
00348 {
00349   TEST_FOR_EXCEPT(true);
00350 }
00351 
00352 
00353 template<class Scalar>
00354 RCP<const Thyra::ModelEvaluator<Scalar> >
00355 ImplicitRKStepper<Scalar>::getModel() const
00356 {
00357   return model_;
00358 }
00359 
00360 
00361 template<class Scalar>
00362 void ImplicitRKStepper<Scalar>::setInitialCondition(
00363   const Thyra::ModelEvaluatorBase::InArgs<Scalar> &initialCondition
00364   )
00365 {
00366 
00367   typedef ScalarTraits<Scalar> ST;
00368   typedef Thyra::ModelEvaluatorBase MEB;
00369 
00370   TEST_FOR_EXCEPT( is_null(model_) );
00371 
00372   basePoint_ = initialCondition;
00373 
00374   // x
00375 
00376   RCP<const Thyra::VectorBase<Scalar> >
00377     x_init = initialCondition.get_x();
00378 
00379 #ifdef TEUCHOS_DEBUG
00380   TEST_FOR_EXCEPTION(
00381     is_null(x_init), std::logic_error,
00382     "Error, if the client passes in an intial condition to setInitialCondition(...),\n"
00383     "then x can not be null!" );
00384   THYRA_ASSERT_VEC_SPACES(
00385     "Rythmos::BackwardEulerStepper::setInitialCondition(...)",
00386     *x_init->space(), *model_->get_x_space() );
00387 #endif
00388 
00389   x_ = x_init->clone_v();
00390 
00391   // x_dot
00392 
00393   x_dot_ = createMember(model_->get_x_space());
00394 
00395   RCP<const Thyra::VectorBase<Scalar> >
00396     x_dot_init = initialCondition.get_x_dot();
00397 
00398   if (!is_null(x_dot_init))
00399     assign(&*x_dot_,*x_dot_init);
00400   else
00401     assign(&*x_dot_,ST::zero());
00402   
00403   // t
00404 
00405   const Scalar t =
00406     (
00407       initialCondition.supports(MEB::IN_ARG_t)
00408       ? initialCondition.get_t()
00409       : ST::zero()
00410       );
00411 
00412   timeRange_ = timeRange(t,t);
00413 
00414 }
00415 
00416 
00417 template<class Scalar>
00418 Scalar ImplicitRKStepper<Scalar>::takeStep(Scalar dt, StepSizeType stepSizeType)
00419 {
00420 
00421 
00422   using Teuchos::as;
00423   using Teuchos::incrVerbLevel;
00424   typedef ScalarTraits<Scalar> ST;
00425   typedef Thyra::NonlinearSolverBase<Scalar> NSB;
00426   typedef Teuchos::VerboseObjectTempState<NSB> VOTSNSB;
00427 
00428   RCP<FancyOStream> out = this->getOStream();
00429   Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
00430   Teuchos::OSTab ostab(out,1,"BES::takeStep");
00431   VOTSNSB solver_outputTempState(solver_,out,incrVerbLevel(verbLevel,-1));
00432 
00433   if ( !is_null(out) && as<int>(verbLevel) >= as<int>(Teuchos::VERB_LOW) ) {
00434     *out
00435       << "\nEntering " << Teuchos::TypeNameTraits<ImplicitRKStepper<Scalar> >::name()
00436       << "::takeStep("<<dt<<","<<toString(stepSizeType)<<") ...\n"; 
00437   }
00438 
00439   if (!isInitialized_) {
00440     initialize_();
00441   }
00442 
00443   TEST_FOR_EXCEPT( stepSizeType != STEP_TYPE_FIXED ); // ToDo: Handle variable case later
00444 
00445   // A) Set up the IRK ModelEvaluator so that it can represent the time step
00446   // equation to be solved.
00447 
00448   // Set irkModel_ with x_old_, t_old_, and dt
00449   V_V( &*x_old_, *x_ );
00450   Scalar current_dt = dt;
00451   Scalar t = timeRange_.upper();
00452   irkModel_->setTimeStepPoint( x_old_, t, current_dt );
00453 
00454   // B) Give the IRK ModelEvaluator to the nonlinear solver and solve the timestep equation
00455 
00456   // Set the guess for the stage derivatives to zero (unless we can think of
00457   // something better)
00458   V_S( &*x_stage_bar_, ST::zero() );
00459 
00460   // Solve timestep equation
00461   solver_->solve( &*x_stage_bar_ );
00462 
00463   // C) Complete the step ...
00464   
00465   // Combine the stage derivatives with the Butcher tableau "b" vector to obtain the solution at the final time.
00466   // x_{k+1} = x_k + dt*sum_{i}^{p}(b_i*x_stage_bar_[i])
00467 
00468   assembleIRKSolution( irkButcherTableau_.b(), current_dt, *x_old_, *x_stage_bar_,
00469     outArg(*x_)
00470     );
00471 
00472   // Update time range
00473   timeRange_ = timeRange(t,t+current_dt);
00474 
00475   return current_dt;
00476 
00477 }
00478 
00479 
00480 template<class Scalar>
00481 const StepStatus<Scalar> ImplicitRKStepper<Scalar>::getStepStatus() const
00482 {
00483   StepStatus<Scalar> stepStatus;
00484   TEST_FOR_EXCEPT(true);
00485   return(stepStatus);
00486 }
00487 
00488 
00489 // Overridden from InterpolationBufferBase
00490 
00491 
00492 template<class Scalar>
00493 RCP<const Thyra::VectorSpaceBase<Scalar> >
00494 ImplicitRKStepper<Scalar>::get_x_space() const
00495 {
00496   return ( !is_null(model_) ? model_->get_x_space() : Teuchos::null );
00497 }
00498 
00499 
00500 template<class Scalar>
00501 void ImplicitRKStepper<Scalar>::addPoints(
00502     const Array<Scalar>& time_vec
00503     ,const Array<RCP<const Thyra::VectorBase<Scalar> > >& x_vec
00504     ,const Array<RCP<const Thyra::VectorBase<Scalar> > >& xdot_vec
00505     )
00506 {
00507   TEST_FOR_EXCEPT(true);
00508 }
00509 
00510 
00511 template<class Scalar>
00512 TimeRange<Scalar> ImplicitRKStepper<Scalar>::getTimeRange() const
00513 {
00514   return timeRange_;
00515 }
00516 
00517 
00518 template<class Scalar>
00519 void ImplicitRKStepper<Scalar>::getPoints(
00520   const Array<Scalar>& time_vec
00521   ,Array<RCP<const Thyra::VectorBase<Scalar> > >* x_vec
00522   ,Array<RCP<const Thyra::VectorBase<Scalar> > >* xdot_vec
00523   ,Array<ScalarMag>* accuracy_vec) const
00524 {
00525 
00526   if (x_vec)
00527     x_vec->resize( time_vec.size() );
00528   if (xdot_vec)
00529     xdot_vec->resize( time_vec.size() );
00530   if (accuracy_vec)
00531     accuracy_vec->resize( time_vec.size() );
00532 
00533   // This is a temp hack!
00534   if (time_vec.size() == 1 && compareTimeValues(timeRange_.upper(),time_vec[0])==0 ) {
00535     if (x_vec) {
00536       (*x_vec)[0] = x_;
00537     }
00538     TEST_FOR_EXCEPT( 0 != xdot_vec ); // Can't handle xdot yet!
00539 
00540     return; // We are done!
00541   }
00542 
00543   TEST_FOR_EXCEPT(true); // ToDo: Implement the final version!
00544 
00545 }
00546 
00547 
00548 template<class Scalar>
00549 void ImplicitRKStepper<Scalar>::getNodes(Array<Scalar>* time_vec) const
00550 {
00551   TEST_FOR_EXCEPT(true);
00552 }
00553 
00554 
00555 template<class Scalar>
00556 void ImplicitRKStepper<Scalar>::removeNodes(Array<Scalar>& time_vec) 
00557 {
00558   TEST_FOR_EXCEPT(true);
00559 }
00560 
00561 
00562 template<class Scalar>
00563 int ImplicitRKStepper<Scalar>::getOrder() const
00564 {
00565   TEST_FOR_EXCEPT(true);
00566   return -1;
00567 }
00568 
00569 
00570 // Overridden from Teuchos::ParameterListAcceptor
00571 
00572 
00573 template <class Scalar>
00574 void ImplicitRKStepper<Scalar>::setParameterList(
00575   RCP<ParameterList> const& paramList
00576   )
00577 {
00578   TEST_FOR_EXCEPT(is_null(paramList));
00579   paramList->validateParametersAndSetDefaults(*this->getValidParameters());
00580   paramList_ = paramList;
00581   numStages_ = paramList_->get("Num Stages",numStages_); // Temp hack
00582   Teuchos::readVerboseObjectSublist(&*paramList_,this);
00583 }
00584 
00585 
00586 template <class Scalar>
00587 RCP<ParameterList>
00588 ImplicitRKStepper<Scalar>::getNonconstParameterList()
00589 {
00590   return(paramList_);
00591 }
00592 
00593 
00594 template <class Scalar>
00595 RCP<ParameterList>
00596 ImplicitRKStepper<Scalar>::unsetParameterList()
00597 {
00598   RCP<ParameterList>
00599     temp_param_list = paramList_;
00600   paramList_ = Teuchos::null;
00601   return(temp_param_list);
00602 }
00603 
00604 
00605 template<class Scalar>
00606 RCP<const ParameterList>
00607 ImplicitRKStepper<Scalar>::getValidParameters() const
00608 {
00609   static RCP<const ParameterList> validPL;
00610   if (is_null(validPL)) {
00611     RCP<ParameterList> pl = Teuchos::parameterList();
00612     pl->set("Num Stages",1); // Temp hack
00613     Teuchos::setupVerboseObjectSublist(&*pl);
00614     validPL = pl;
00615   }
00616   return validPL;
00617 }
00618 
00619 
00620 // Overridden from Teuchos::Describable
00621 
00622 
00623 template<class Scalar>
00624 void ImplicitRKStepper<Scalar>::describe(
00625   FancyOStream &out,
00626   const Teuchos::EVerbosityLevel verbLevel
00627   ) const
00628 {
00629   using std::endl;
00630   using Teuchos::as;
00631   Teuchos::OSTab tab(out);
00632   if (!isInitialized_) {
00633     out << this->description() << " : This stepper is not initialized yet" << std::endl;
00634     return;
00635   }
00636   if (
00637     as<int>(verbLevel) == as<int>(Teuchos::VERB_DEFAULT)
00638     ||
00639     as<int>(verbLevel) >= as<int>(Teuchos::VERB_LOW)
00640     )
00641   {
00642     out << this->description() << ":" << endl;
00643     Teuchos::OSTab tab(out);
00644     out << "model = " << Teuchos::describe(*model_,verbLevel);
00645     out << "solver = " << Teuchos::describe(*solver_,verbLevel);
00646     out << "irk_W_factory = " << Teuchos::describe(*irk_W_factory_,verbLevel);
00647   }
00648 }
00649 
00650 
00651 // private
00652 
00653 
00654 template <class Scalar>
00655 void ImplicitRKStepper<Scalar>::initialize_()
00656 {
00657 
00658   typedef ScalarTraits<Scalar> ST;
00659   const Scalar one = ST::one();
00660   const Scalar zero = ST::zero();
00661   using Teuchos::rcp_dynamic_cast;
00662 
00663   TEST_FOR_EXCEPT(model_ == Teuchos::null);
00664   TEST_FOR_EXCEPT(solver_ == Teuchos::null);
00665   TEST_FOR_EXCEPT(irk_W_factory_ == Teuchos::null);
00666 
00667   if (is_null(x_)) {
00668     // If x has not been set then setInitialCondition(...) was not
00669     // called by the client so the model had better have the 
00670     // initial condition!
00671     this->setInitialCondition(model_->getNominalValues());
00672   }
00673 
00674   if (is_null(x_dot_)) {
00675     x_dot_ = createMember(model_->get_x_space());
00676     V_S(&*x_dot_,ScalarTraits<Scalar>::zero());
00677   }
00678 
00679   x_old_ = x_->clone_v();
00680 
00681   // Set up the butcher tableau
00682 
00683   Teuchos::SerialDenseMatrix<int,Scalar> A(numStages_,numStages_);
00684   Teuchos::SerialDenseVector<int,Scalar> b(numStages_);
00685   Teuchos::SerialDenseVector<int,Scalar> c(numStages_);
00686 
00687   // For now just two simple versions!
00688   TEUCHOS_ASSERT( numStages_ == 1 || numStages_ == 2 );
00689 
00690   if (numStages_ == 1) {
00691 
00692     A(0,0) = one;
00693 
00694     b(0) = one;
00695     
00696     c(0) = one;
00697 
00698   }
00699   else if (numStages_ == 2) {
00700 
00701     const Scalar half = 0.5 * one;
00702 
00703     A(0,0) = half;   A(0,1) = -half;
00704     A(1,0) = half;   A(1,1) = half;
00705 
00706     b(0) = half;
00707     b(1) = half;
00708     
00709     c(0) = zero;
00710     c(1) = one;
00711 
00712 
00713   }
00714   else {
00715     TEST_FOR_EXCEPT(true); // Should never get here!
00716   }
00717   
00718   irkButcherTableau_ = RKButcherTableau<Scalar>(A,b,c);
00719 
00720   // Set up the IRK mdoel
00721 
00722   irkModel_ = implicitRKModelEvaluator(
00723     model_,basePoint_,irk_W_factory_,irkButcherTableau_);
00724 
00725   solver_->setModel(irkModel_);
00726 
00727   // Set up the vector of stage derivatives ...
00728   x_stage_bar_ = rcp_dynamic_cast<Thyra::ProductVectorBase<Scalar> >(
00729     createMember(irkModel_->get_x_space())
00730     );
00731 
00732   isInitialized_ = true;
00733 
00734 }
00735 
00736 
00737 } // namespace Rythmos
00738 
00739 #endif //Rythmos_IMPLICIT_RK_STEPPER_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends

Generated on Tue Oct 20 10:24:09 2009 for Rythmos - Transient Integration for Differential Equations by  doxygen 1.6.1