indii/ml/ode/NumericalSolver.hpp

00001 #ifndef INDII_ML_ODE_NUMERICALSOLVER_HPP
00002 #define INDII_ML_ODE_NUMERICALSOLVER_HPP
00003 
00004 #include "../aux/vector.hpp"
00005 
00006 #include <gsl/gsl_odeiv.h>
00007 
00008 namespace indii {
00009   namespace ml {
00010     namespace ode {
00011 
00012 /**
00013  * Type of functions for calculating derivatives.
00014  */
00015 typedef int df_t(double t, const double y[], double dydt[], void* params);
00016 
00017 /**
00018  * Abstract numerical solver for a system of differential equations.
00019  *
00020  * @author Lawrence Murray <lawrence@indii.org>
00021  * @version $Rev: 521 $
00022  * @date $Date: 2008-08-16 16:58:51 +0100 (Sat, 16 Aug 2008) $
00023  */
00024 class NumericalSolver {
00025 public:
00026   /**
00027    * Constructor.
00028    *
00029    * @param dimensions Dimensionality of the state space.
00030    *
00031    * The time is initialised to zero, but the state is uninitialised
00032    * and should be set with setVariable() or setState().
00033    */
00034   NumericalSolver(const unsigned int dimensions);
00035 
00036   /**
00037    * Constructor.
00038    *
00039    * @param y0 Initial state.
00040    *
00041    * The time is initialised to zero and the state to that given.
00042    */
00043   NumericalSolver(const indii::ml::aux::vector& y0);
00044 
00045   /**
00046    * Destructor.
00047    */
00048   virtual ~NumericalSolver();
00049 
00050   /**
00051    * Get dimensionality of the state space.
00052    */
00053   unsigned int getDimensions();
00054 
00055   /**
00056    * Get the current time.
00057    */
00058   double getTime();
00059 
00060   /**
00061    * Set the current time.
00062    *
00063    * @param t Time.
00064    *
00065    * @see setVariable() or setState() to update the state for the new
00066    * time also.
00067    */
00068   void setTime(const double t);
00069 
00070   /**
00071    * Get the value of a state variable at the current time.
00072    *
00073    * @param index Index of the state variable to retrieve.
00074    *
00075    * @return The value of the state variable at the current time.
00076    */
00077   double getVariable(const unsigned int index);
00078 
00079   /**
00080    * Set the value of a state variable.
00081    *
00082    * @param index Index of the state variable to set.
00083    * @param value The value to which to set the state variable.
00084    */
00085   void setVariable(const unsigned int index, const double value);
00086 
00087   /**
00088    * Get the state at the current time.
00089    *
00090    * @return Current state of the system.
00091    */
00092   indii::ml::aux::vector getState();
00093 
00094   /**
00095    * Set the state at the current time.
00096    *
00097    * @param y New state of the system.
00098    */
00099   void setState(const indii::ml::aux::vector& y);
00100 
00101   /**
00102    * Advance the system one time step. The size of the step is chosen
00103    * to be optimal given the provided error bounds. State variables
00104    * are updated to this new time after completion of the step.
00105    *
00106    * @param upper Upper bound on time. This must be greater than the
00107    * current time. The current time is guaranteed not to exceed this
00108    * value after the step is complete. It may equal this time, and
00109    * indeed if step() is continuously called with the same upper bound
00110    * it will eventually do so.
00111    *
00112    * @return The new current time.
00113    */
00114   virtual double step(double upper);
00115 
00116   /**
00117    * Advance the system to a particular time.
00118    *
00119    * This convenience method internally calls step() as many times as
00120    * necessary to advance the system to the given time. This is useful
00121    * if fixed time steps are required rather than the variable steps
00122    * taken by step().
00123    *
00124    * @param to The time to which to advance the system. This must be greater
00125    * than the current time. The current time is guaranteed to match this value
00126    * at the end of the call.
00127    */
00128   void stepTo(double to);
00129 
00130   /**
00131    * Rewind the system one time step. This works in the same fashion
00132    * at step(), except that the step is backwards in time.
00133    *
00134    * @param lower Lower bound on time. This must be less than the
00135    * current time. The current time is guaranteed not to be below this
00136    * value after the step is complete. It may equal this time, and
00137    * indeed if stepBack() is continuously called with the same lower
00138    * bound it will eventually do so.
00139    *
00140    * @return The new current time.
00141    */
00142   virtual double stepBack(double lower);
00143 
00144   /**
00145    * Rewind the system to a specific time.
00146    *
00147    * This convenience method internally calls stepBack() as many times
00148    * as necessary to rewind the system to a given point in time. This
00149    * is useful if fixed time steps are required rather than the
00150    * variable steps taken by stepBack().
00151    *
00152    * @param to The time to which to rewind the system. This must be
00153    * less than the current time. The current time is guaranteed to
00154    * match this value at the end of the call.
00155    */
00156   void stepBackTo(double to);
00157 
00158   /**
00159    * Set the error bounds. Smaller error bounds produce more accurate
00160    * estimates, but reduce the size of time steps, so that more steps
00161    * are required in order to estimate functions over the same length
00162    * of time.
00163    *
00164    * @param maxAbsoluteError The maximum permitted absolute error of
00165    * estimated values compared to real values.
00166    * @param maxRelativeError The maximum permitted relative error of
00167    * estimated values compared to real values.
00168    */
00169   void setErrorBounds(double maxAbsoluteError = 1e-6,
00170       double maxRelativeError = 1e-6);
00171 
00172   /**
00173    * Set the proposed size for the next time step. This is useful for
00174    * handling discontinuities, where step() may be called to advance
00175    * to the discontinuity, then setStepSize() used to propose a small
00176    * step size ensuring that the discontinuity is tiptoed across
00177    * rather than leapt.
00178    *
00179    * It should be called immediately before any call to step() or
00180    * stepTo(). Any other methods called in between may themselves adjust the
00181    * proposed step size.
00182    *
00183    * @param stepSize The proposed time step size for the next call to
00184    * step().
00185    *
00186    * Note that this sets only the proposed step size -- it will be
00187    * optimised, within some constraints, relative to the permitted
00188    * error bounds.
00189    */
00190   void setStepSize(double stepSize);
00191 
00192   /**
00193    * Get the proposed size for the next time step.
00194    *
00195    * @return The proposed time step size for the next call to step().
00196    */
00197   double getStepSize();
00198 
00199   /**
00200    * Set the suggested step size. The step size is set to this
00201    * immediately, and subsequently after any calls to
00202    * setDiscontinuity().
00203    *
00204    * @param stepSize The suggested step size.
00205    *
00206    * Note that this sets only the proposed step size -- it will be
00207    * optimised, within some constraints, relative to the permitted
00208    * error bounds.
00209    */
00210   void setSuggestedStepSize(double stepSize = 1.0e-7);
00211 
00212   /**
00213    * Get the suggested step size.
00214    *
00215    * @return The suggested step size.
00216    */
00217   double getSuggestedStepSize();
00218 
00219   /**
00220    * Set the maximum step size.
00221    *
00222    * @param stepSize The maximum step size.
00223    *
00224    * This is useful for bounding the step size on schemes which may propose
00225    * steps that, for some models, produce inf or nan derivative calculations.
00226    * Empirically, we particularly observe this with implicit schemes. By
00227    * default the step size is not bound.
00228    */
00229   void setMaxStepSize(double stepSize = 0.0);
00230 
00231   /**
00232    * Get the maximum step size.
00233    *
00234    * @return The maximum step size.
00235    */
00236   double getMaxStepSize();
00237 
00238   /**
00239    * Indicates a discontinuity at the current time. Internally, this simply
00240    * calls setStepSize() with the suggested step size.
00241    */
00242   void setDiscontinuity();
00243 
00244   /**
00245    * Set the stepping method.
00246    *
00247    * @param stepType The stepping method.
00248    *
00249    * This allows modification of the underlying numerical scheme used by
00250    * the solver, as specified by the GSL. For advanced users only.
00251    */
00252   void setStepType(const gsl_odeiv_step_type* stepType);
00253 
00254   /**
00255    * Calculate derivatives for forwards step.
00256    */
00257   virtual int calculateDerivativesForward(double t, const double y[],
00258       double dydt[]) = 0;
00259 
00260   /**
00261    * Calculate derivatives for backwards step.
00262    */
00263   virtual int calculateDerivativesBackward(double t, const double y[],
00264       double dydt[]) = 0;
00265 
00266 protected:
00267   /**
00268    * Dimensionality of the system of differential equations.
00269    */
00270   const size_t dimensions;
00271 
00272   /**
00273    * \f$t\f$; the current time
00274    */
00275   double t;
00276 
00277   /**
00278    * Array of state variables of the system.
00279    */
00280   double* y;
00281 
00282   /**
00283    * Base time used for backward steps.
00284    */
00285   double base;
00286 
00287   /**
00288    * Proposed size for the next time step.
00289    */
00290   double stepSize;
00291 
00292   /**
00293    * Maximum step size.
00294    */
00295   double maxStepSize;
00296 
00297   /**
00298    * Suggested step size.
00299    */
00300   double suggestedStepSize;
00301 
00302   /**
00303    * GSL ordinary differential equations step structure.
00304    */
00305   gsl_odeiv_step* gslStep;
00306 
00307   /**
00308    * GSL ordinary differential equations control structure.
00309    */
00310   gsl_odeiv_control* gslControl;
00311 
00312   /**
00313    * GSL ordinary differential equations evolution structure.
00314    */
00315   gsl_odeiv_evolve* gslEvolve;
00316  
00317   /**
00318    * GSL system of ordinary differential equations for forward steps
00319    * in time.
00320    */
00321   gsl_odeiv_system gslForwardSystem;
00322 
00323   /**
00324    * GSL system of ordinary differential equations for backward steps
00325    * in time.
00326    */
00327   gsl_odeiv_system gslBackwardSystem;
00328 
00329   /**
00330    * Initialise the system. Should be called before any calls to
00331    * step() or stepTo().
00332    */
00333   void init();
00334 
00335   /**
00336    * Terminate the system. Should be called after work with the system
00337    * has been finished. Will be called by the destructor if it hasn't
00338    * been already.
00339    */
00340   void terminate();
00341 
00342   /**
00343    * Reset the model. This is used internally to reset GSL structures when the
00344    * next step will not be a continuation of the last, usually when the time
00345    * or state is changed with a call to setTime(), setVariable() or
00346    * setState().
00347    */
00348   virtual void reset();
00349 
00350 private:
00351   /**
00352    * Function for calculating derivatives when moving forward in time.
00353    *
00354    * Required by gsl_odeiv_system struct of GSL, which is in turn
00355    * passed to the gsl_odeiv_evolve_apply() function. Acts as a
00356    * wrapper to call the calculateForwardDerivatives() function of the
00357    * particular NumericalSolver object.
00358    *
00359    * @see gsl_odeiv_system data type of GSL.
00360    * @see gsl_odeiv_evolve_apply() of GSL.
00361    */
00362   static int gslForwardFunction(double t, const double y[], double dydt[],
00363       void* params);
00364 
00365   /**
00366    * Function for calculating derivatives when moving backward in time.
00367    * Acts as a wrapper to call the calculateBackwardDerivatives() function
00368    * of the particular NumericalSolver object.
00369    *
00370    * @see gslForwardFunction()
00371    */
00372   static int gslBackwardFunction(double t, const double y[], double dydt[],
00373       void* params);
00374 
00375 };
00376 
00377 
00378     }
00379   }
00380 }
00381 
00382 inline unsigned int indii::ml::ode::NumericalSolver::getDimensions() {
00383   return dimensions;
00384 }
00385 
00386 inline double indii::ml::ode::NumericalSolver::getTime() {
00387   return t;
00388 }
00389 
00390 inline double indii::ml::ode::NumericalSolver::getVariable(
00391     const unsigned int index) {
00392   /* pre-condition */
00393   assert (index < dimensions);
00394 
00395   return y[index];
00396 }
00397 
00398 inline indii::ml::aux::vector indii::ml::ode::NumericalSolver::getState() {
00399   indii::ml::aux::vector y(dimensions);
00400   unsigned int i;
00401 
00402   for (i = 0; i < dimensions; i++) {
00403     y(i) = this->y[i];
00404   }
00405   return y;
00406 }
00407 
00408 inline double indii::ml::ode::NumericalSolver::getStepSize() {
00409   return stepSize;
00410 }
00411 
00412 inline double indii::ml::ode::NumericalSolver::getSuggestedStepSize() {
00413   return suggestedStepSize;
00414 }
00415 
00416 inline double indii::ml::ode::NumericalSolver::getMaxStepSize() {
00417   return maxStepSize;
00418 }
00419 
00420 #endif
00421 

Generated on Wed Dec 17 15:11:57 2008 for dysii Dynamical Systems Library by  doxygen 1.5.3