indii/ml/ode/NumericalSolver.cpp

00001 #include "NumericalSolver.hpp"
00002 
00003 #include <assert.h>
00004 #include <math.h>
00005 
00006 #include <gsl/gsl_errno.h>
00007 #include <gsl/gsl_odeiv.h>
00008 
00009 using namespace indii::ml::ode;
00010 
00011 namespace aux = indii::ml::aux;
00012 
00013 NumericalSolver::NumericalSolver(const unsigned int dimensions) :
00014     dimensions(dimensions) {
00015   this->t = 0.0;
00016   this->gslStep = NULL;
00017   this->gslControl = NULL;
00018   this->gslEvolve = NULL;
00019   this->y = new double[dimensions];
00020 
00021   setSuggestedStepSize();
00022   setMaxStepSize();
00023   setErrorBounds();
00024   setDiscontinuity();
00025   init();
00026 }
00027 
00028 NumericalSolver::NumericalSolver(const aux::vector& y0) :
00029     dimensions(y0.size()) {
00030   this->t = 0.0;
00031   this->gslStep = NULL;
00032   this->gslControl = NULL;
00033   this->gslEvolve = NULL;
00034   this->y = new double[dimensions];
00035 
00036   setSuggestedStepSize();
00037   setMaxStepSize();
00038   setErrorBounds();
00039   setDiscontinuity();
00040   init();
00041   setState(y0);
00042 }
00043 
00044 NumericalSolver::~NumericalSolver() {
00045   terminate();
00046   delete[] y;
00047 }
00048 
00049 void NumericalSolver::setTime(const double t) {
00050   this->t = t;
00051   reset();
00052 }
00053 
00054 double NumericalSolver::step(double upper) {
00055   /* pre-condition */
00056   assert (upper > t);
00057 
00058   /* solve differential equations */
00059   int err;
00060   if (maxStepSize > 0.0 && stepSize > maxStepSize) {
00061     stepSize = maxStepSize;
00062   }
00063   err = gsl_odeiv_evolve_apply(gslEvolve, gslControl, gslStep,
00064       &gslForwardSystem, &t, upper, &stepSize, y);
00065   assert (err == GSL_SUCCESS);
00066 
00067   /* post-condition */
00068   assert (t <= upper);
00069 
00070   return t;
00071 }
00072 
00073 void NumericalSolver::stepTo(double to) {
00074   /* pre-condition */
00075   assert (t < to);
00076   
00077   double p = t;
00078   while (p < to) {
00079     p = step(to);
00080   }
00081   
00082   /* post-condition */
00083   assert (t == to);
00084 }
00085 
00086 double NumericalSolver::stepBack(double lower) {
00087   /* pre-condition */
00088   assert (lower < t);
00089   assert (lower >= 0.0);
00090 
00091   /* Solve differential equations, pretending this is a forward step
00092      and converting the lower bound to an upper bound an equivalent
00093      distance from the current time. gslBackwardFunction() and
00094      gslForwardFunction() handle the conversion of the resulting
00095      forward time step proposals to backward time steps proposals. The
00096      GSL is only able to make forward steps with its Runge-Kutta
00097      algorithms. */
00098   gsl_odeiv_step_reset(gslStep);
00099   gsl_odeiv_evolve_reset(gslEvolve);
00100 
00101   base = t;
00102   int err;
00103   if (stepSize > maxStepSize) {
00104     stepSize = maxStepSize;
00105   }
00106   err = gsl_odeiv_evolve_apply(gslEvolve, gslControl, gslStep,
00107       &gslBackwardSystem, &t, 2.0 * base - lower, &stepSize, y);
00108   assert (err == GSL_SUCCESS);
00109   t = 2.0 * base - t;
00110 
00111   /* post-condition */
00112   assert (t >= lower);
00113 
00114   return t;
00115 }
00116 
00117 void NumericalSolver::stepBackTo(double to) {
00118   /* pre-condition */
00119   assert (to < t && to >= 0.0);
00120   
00121   double p = t;
00122   while (p > to) {
00123     p = stepBack(to);
00124   }
00125   
00126   /* post-condition */
00127   assert (t == to);
00128 }
00129 
00130 void NumericalSolver::setErrorBounds(double maxAbsoluteError,
00131       double maxRelativeError) {
00132   if (gslControl == NULL) {
00133     gslControl = gsl_odeiv_control_standard_new(maxAbsoluteError,
00134         maxRelativeError, 1.0, 0.0);
00135   } else {
00136     gsl_odeiv_control_init(gslControl, maxAbsoluteError, maxRelativeError,
00137          1.0, 0.0);
00138   }
00139 }
00140 
00141 void NumericalSolver::setStepSize(double stepSize) {
00142   this->stepSize = stepSize;
00143 }
00144 
00145 void NumericalSolver::setSuggestedStepSize(double stepSize) {
00146   this->suggestedStepSize = stepSize;
00147   this->stepSize = stepSize;
00148 }
00149 
00150 void NumericalSolver::setMaxStepSize(double stepSize) {
00151   this->maxStepSize = stepSize;
00152 }
00153 
00154 void NumericalSolver::setDiscontinuity() {
00155   setStepSize(suggestedStepSize);
00156 }
00157 
00158 void NumericalSolver::setVariable(const unsigned int index,
00159       const double value) {
00160   /* pre-condition */
00161   assert (index < dimensions);
00162 
00163   y[index] = value;
00164   reset();
00165 }
00166 
00167 void NumericalSolver::setState(const aux::vector& y) {
00168   /* pre-condition */
00169   assert (y.size() == dimensions);
00170 
00171   unsigned int i;
00172   for (i = 0; i < dimensions; i++) {
00173     this->y[i] = y(i);
00174   }
00175   reset();
00176 }
00177 
00178 void NumericalSolver::init() {
00179   /* allocate GSL structures */
00180   gslEvolve = gsl_odeiv_evolve_alloc(dimensions);
00181 
00182   /* set up systems of differential equations */
00183   gslForwardSystem.function = gslForwardFunction;
00184   gslForwardSystem.jacobian = NULL;
00185   gslForwardSystem.dimension = dimensions;
00186   gslForwardSystem.params = this;
00187 
00188   gslBackwardSystem.function = gslBackwardFunction;
00189   gslBackwardSystem.jacobian = NULL;
00190   gslBackwardSystem.dimension = dimensions;
00191   gslBackwardSystem.params = this;
00192 }
00193 
00194 void NumericalSolver::terminate() {
00195   /* free GSL structures */
00196   if (gslStep != NULL) {
00197     gsl_odeiv_step_free(gslStep);
00198     gslStep = NULL;
00199   }
00200   if (gslControl != NULL) {
00201     gsl_odeiv_control_free(gslControl);
00202     gslControl = NULL;
00203   }
00204   if (gslEvolve != NULL) {
00205     gsl_odeiv_evolve_free(gslEvolve);
00206     gslEvolve = NULL;
00207   }
00208 }
00209 
00210 void NumericalSolver::reset() {
00211   /* reset GSL structures */
00212   gsl_odeiv_step_reset(gslStep);
00213   gsl_odeiv_evolve_reset(gslEvolve);
00214 }
00215 
00216 void NumericalSolver::setStepType(const gsl_odeiv_step_type* stepType) {
00217   if (gslStep != NULL) {
00218     gsl_odeiv_step_free(gslStep);
00219   }
00220   gslStep = gsl_odeiv_step_alloc(stepType, dimensions);
00221 }
00222 
00223 int NumericalSolver::gslForwardFunction(double t, const double y[],
00224     double dydt[], void* params) {
00225   NumericalSolver* solver = static_cast<NumericalSolver*>(params);
00226   return solver->calculateDerivativesForward(t, y, dydt);
00227 }
00228 
00229 int NumericalSolver::gslBackwardFunction(double t, const double y[],
00230     double dydt[], void* params) {
00231   NumericalSolver* solver = static_cast<NumericalSolver*>(params);
00232   return solver->calculateDerivativesBackward(t, y, dydt);
00233 }
00234 

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