00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef O2SCL_GSL_ASTEP_H
00025 #define O2SCL_GSL_ASTEP_H
00026
00027 #include <gsl/gsl_math.h>
00028 #include <gsl/gsl_odeiv.h>
00029
00030 #include <o2scl/adapt_step.h>
00031
00032 #ifndef DOXYGENP
00033 namespace o2scl {
00034 #endif
00035
00036
00037
00038
00039
00040
00041
00042 template<class param_t, class func_t, class vec_t=ovector_view,
00043 class alloc_vec_t=ovector, class alloc_t=ovector_alloc> class gsl_astep :
00044 public adapt_step<param_t,func_t,vec_t,alloc_vec_t,alloc_t> {
00045
00046 #ifndef DOXYGEN_INTERNAL
00047
00048 protected:
00049
00050
00051 size_t ndim;
00052
00053
00054 alloc_t ao;
00055
00056
00057 size_t sdim;
00058
00059
00060 double *scale_abs;
00061
00062
00063
00064
00065
00066 class gsl_odeiv_evolve {
00067 public:
00068
00069
00070 size_t dimension;
00071
00072
00073 alloc_vec_t y0;
00074
00075 alloc_vec_t yerr;
00076
00077 alloc_vec_t dydt_in;
00078
00079 alloc_vec_t dydt_out;
00080
00081 size_t ndim;
00082
00083
00084 double last_step;
00085
00086 unsigned long int count;
00087
00088 unsigned long int failed_steps;
00089 };
00090
00091
00092 int hadjust(size_t dim, unsigned int ord, const vec_t &y,
00093 vec_t &yerr, vec_t &yp, double *h)
00094 {
00095
00096 gsl_ode_control *state = &con;
00097
00098 const double eps_abs = state->eps_abs;
00099 const double eps_rel = state->eps_rel;
00100 const double a_y = state->a_y;
00101 const double a_dydt = state->a_dydt;
00102
00103 const double S = 0.9;
00104 const double h_old = *h;
00105
00106 double rmax = DBL_MIN;
00107 size_t i;
00108
00109 for(i=0; i<dim; i++) {
00110 double D0;
00111 if (state->standard || sdim==0) {
00112 D0=eps_rel*(a_y*fabs(y[i])+a_dydt*fabs(h_old*yp[i]))+eps_abs;
00113 } else {
00114 D0=eps_rel*(a_y*fabs(y[i])+a_dydt*fabs(h_old*yp[i]))+
00115 eps_abs*scale_abs[i%sdim];
00116 }
00117 const double r=fabs(yerr[i]) / fabs(D0);
00118 rmax = GSL_MAX_DBL(r, rmax);
00119 }
00120
00121 if(rmax > 1.1) {
00122
00123
00124
00125
00126 double r = S / pow(rmax, 1.0/ord);
00127
00128 if (r < 0.2) {
00129 r = 0.2;
00130 }
00131
00132 *h = r * h_old;
00133
00134 return GSL_ODEIV_HADJ_DEC;
00135
00136 } else if (rmax < 0.5) {
00137
00138
00139 double r = S / pow(rmax, 1.0/(ord+1.0));
00140
00141 if (r > 5.0) {
00142 r = 5.0;
00143 }
00144
00145
00146 if (r < 1.0) {
00147 r = 1.0;
00148 }
00149
00150 *h = r * h_old;
00151
00152 return GSL_ODEIV_HADJ_INC;
00153
00154 } else {
00155
00156
00157 return GSL_ODEIV_HADJ_NIL;
00158
00159 }
00160
00161 }
00162
00163
00164 int evolve_apply(gsl_odeiv_evolve *e, size_t nvar, param_t &pa,
00165 func_t &derivs, double *t, double t1, double *h,
00166 vec_t &y)
00167 {
00168 double t0 = *t;
00169 double h0 = *h;
00170 int step_status;
00171 int final_step = 0;
00172
00173 double dt = t1 - t0;
00174
00175 if ((dt < 0.0 && h0 > 0.0) || (dt > 0.0 && h0 < 0.0)) {
00176 GSL_ERROR ("step direction must match interval direction",
00177 GSL_EINVAL);
00178 }
00179
00180 for(size_t ic=0;ic<nvar;ic++) e->y0[ic]=y[ic];
00181
00182
00183 int status=derivs(t0,nvar,y,e->dydt_in,pa);
00184 if (status) return status;
00185
00186 try_step:
00187
00188 if ((dt >= 0.0 && h0 > dt) || (dt < 0.0 && h0 < dt)) {
00189 h0 = dt;
00190 final_step = 1;
00191 } else{
00192 final_step = 0;
00193 }
00194
00195 step_status=this->stepp->step(t0,h0,nvar,y,e->dydt_in,y,e->yerr,
00196 e->dydt_out,pa,derivs);
00197
00198
00199 if (step_status != gsl_success) {
00200
00201 *h=h0;
00202 return step_status;
00203 }
00204
00205 e->count++;
00206 e->last_step = h0;
00207 if (final_step) {
00208 *t = t1;
00209 } else{
00210 *t = t0 + h0;
00211 }
00212
00213
00214 const int hadjust_status=hadjust(nvar,this->stepp->get_order(),
00215 y,e->yerr,e->dydt_out,&h0);
00216
00217 if (hadjust_status == GSL_ODEIV_HADJ_DEC) {
00218
00219
00220 for(size_t ic=0;ic<nvar;ic++) y[ic]=e->y0[ic];
00221 e->failed_steps++;
00222 goto try_step;
00223 }
00224
00225
00226 *h = h0;
00227
00228 return step_status;
00229 }
00230
00231 #endif
00232
00233 public:
00234
00235
00236 typedef struct
00237 {
00238
00239 double eps_abs;
00240
00241 double eps_rel;
00242
00243 double a_y;
00244
00245 double a_dydt;
00246
00247 bool standard;
00248
00249 } gsl_ode_control;
00250
00251
00252 gsl_ode_control con;
00253
00254 gsl_astep() {
00255
00256 this->verbose=0;
00257
00258 con.eps_abs=1.0e-6;
00259 con.eps_rel=0.0;
00260 con.a_y=1.0;
00261 con.a_dydt=0.0;
00262 con.standard=true;
00263
00264 ndim=0;
00265 sdim=0;
00266 }
00267
00268 virtual ~gsl_astep() {
00269 if (sdim!=0) delete[] scale_abs;
00270 }
00271
00272
00273 template<class svec_t> int set_scale(size_t nscal, const svec_t &scale) {
00274 if (nscal>=sdim) {
00275 if (sdim!=0) delete[] scale_abs;
00276 scale_abs=new double[nscal];
00277 sdim=nscal;
00278 }
00279 for(size_t i=0;i<nscal;i++) {
00280 scale_abs[i]=scale[i];
00281 }
00282 return 0;
00283 }
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 virtual int astep(double &x, double &h, double xmax, size_t n,
00294 vec_t &y, param_t &pa, func_t &derivs)
00295 {
00296
00297
00298 gsl_odeiv_evolve goe;
00299
00300 ao.allocate(goe.y0,n);
00301 ao.allocate(goe.yerr,n);
00302 ao.allocate(goe.dydt_in,n);
00303 ao.allocate(goe.dydt_out,n);
00304
00305
00306 goe.dimension=n;
00307
00308 goe.count=0;
00309 goe.failed_steps=0;
00310 goe.last_step=0.0;
00311
00312 int ret=evolve_apply(&goe,n,pa,derivs,&x,xmax,&h,y);
00313
00314 if (this->verbose>0) {
00315 std::cout << x << " ";
00316 for(size_t j=0;j<n;j++) std::cout << y[j] << " ";
00317 std::cout << std::endl;
00318 }
00319
00320 ao.free(goe.y0);
00321 ao.free(goe.yerr);
00322 ao.free(goe.dydt_in);
00323 ao.free(goe.dydt_out);
00324
00325 return ret;
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 virtual int astep_derivs(double &x, double &h, double xmax, size_t n,
00337 vec_t &y, vec_t &dydx, param_t &pa,
00338 func_t &derivs)
00339 {
00340
00341
00342 gsl_odeiv_evolve goe;
00343
00344 ao.allocate(goe.y0,n);
00345 ao.allocate(goe.yerr,n);
00346 ao.allocate(goe.dydt_in,n);
00347 ao.allocate(goe.dydt_out,n);
00348
00349
00350 goe.dimension=n;
00351
00352 goe.count=0;
00353 goe.failed_steps=0;
00354 goe.last_step=0.0;
00355
00356 int ret=evolve_apply(&goe,n,pa,derivs,&x,xmax,&h,y);
00357
00358
00359 derivs(x,n,y,dydx,pa);
00360
00361 if (this->verbose>0) {
00362 std::cout << x << " ";
00363 for(size_t j=0;j<n;j++) std::cout << y[j] << " ";
00364 std::cout << std::endl;
00365 }
00366
00367 ao.free(goe.y0);
00368 ao.free(goe.yerr);
00369 ao.free(goe.dydt_in);
00370 ao.free(goe.dydt_out);
00371
00372 return ret;
00373 }
00374
00375 };
00376
00377 #ifndef DOXYGENP
00378 }
00379 #endif
00380
00381 #endif