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
00056 assert (upper > t);
00057
00058
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
00068 assert (t <= upper);
00069
00070 return t;
00071 }
00072
00073 void NumericalSolver::stepTo(double to) {
00074
00075 assert (t < to);
00076
00077 double p = t;
00078 while (p < to) {
00079 p = step(to);
00080 }
00081
00082
00083 assert (t == to);
00084 }
00085
00086 double NumericalSolver::stepBack(double lower) {
00087
00088 assert (lower < t);
00089 assert (lower >= 0.0);
00090
00091
00092
00093
00094
00095
00096
00097
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
00112 assert (t >= lower);
00113
00114 return t;
00115 }
00116
00117 void NumericalSolver::stepBackTo(double to) {
00118
00119 assert (to < t && to >= 0.0);
00120
00121 double p = t;
00122 while (p > to) {
00123 p = stepBack(to);
00124 }
00125
00126
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
00161 assert (index < dimensions);
00162
00163 y[index] = value;
00164 reset();
00165 }
00166
00167 void NumericalSolver::setState(const aux::vector& y) {
00168
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
00180 gslEvolve = gsl_odeiv_evolve_alloc(dimensions);
00181
00182
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
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
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