/* Author: G. Jungman * RCS: $Id: rkck.c,v 1.9 1999/09/27 15:45:19 bjg Exp $ */ #include #include #include #include #include "odeiv_util.h" #include "gsl_odeiv.h" typedef struct gsl_odeiv_step_rkck_struct gsl_odeiv_step_rkck; struct gsl_odeiv_step_rkck_struct { gsl_odeiv_step parent; /* inherits from gsl_odeiv_step */ double * work; /* generic work space */ }; static int rkck_step(void * self, double t, double h, double y[], double yerr[], const double dydt_in[], double dydt_out[], const gsl_odeiv_system * dydt); static void rkck_free(void * self); gsl_odeiv_step * gsl_odeiv_step_rkck_new(void) { gsl_odeiv_step_rkck * s = (gsl_odeiv_step_rkck *) malloc(sizeof(gsl_odeiv_step_rkck)); if(s != 0) { gsl_odeiv_step_construct(&(s->parent), "rkck", rkck_step, 0, rkck_free, 0, 0, 4); s->work = 0; } return (gsl_odeiv_step *) s; } static int rkck_step( void * self, double t, double h, double y[], double yerr[], const double dydt_in[], double dydt_out[], const gsl_odeiv_system * sys) { /* Cash-Karp constants */ static const double ah[] = { 1.0/5.0, 0.3, 3.0/5.0, 1.0, 7.0/8.0 }; static const double b21 = 1.0/5.0; static const double b3[] = { 3.0/40.0, 9.0/40.0 }; static const double b4[] = { 0.3, -0.9, 1.2 }; static const double b5[] = { -11.0/54.0, 2.5, -70.0/27.0, 35.0/27.0 }; static const double b6[] = { 1631.0/55296.0, 175.0/512.0, 575.0/13824.0, 44275.0/110592.0, 253.0/4096.0 }; static const double c1 = 37.0/378.0; static const double c3 = 250.0/621.0; static const double c4 = 125.0/594.0; static const double c6 = 512.0/1771.0; const double ec[] = { 0.0, /* the first value is the same as c1, above */ 37.0/378.0 - 2825.0/27648.0, 0.0, /* the first value is the same as c3, above */ 250.0/621.0 - 18575.0/48384.0, /* the first value is the same as c4, above */ 125.0/594.0 - 13525.0/55296.0, -277.00/14336.0, /* the first value is the same as c6, above */ 512.0/1771.0 - 0.25 }; int i; int status = 0; size_t dim; double * k1; double * k2; double * k3; double * k4; double * k5; double * k6; double * ytmp; gsl_odeiv_step_rkck * my = (gsl_odeiv_step_rkck *) self; if(sys->dimension == 0) { return GSL_EINVAL; } if(sys->dimension != my->parent.dimension) { if(my->work != 0) free(my->work); my->parent.dimension = sys->dimension; my->work = (double *) malloc(7 * sys->dimension * sizeof(double)); if(my->work == 0) { my->parent.dimension = 0; return GSL_ENOMEM; } } dim = my->parent.dimension; /* divide up the work space */ k1 = my->work; k2 = my->work + dim; k3 = my->work + 2*dim; k4 = my->work + 3*dim; k5 = my->work + 4*dim; k6 = my->work + 5*dim; ytmp = my->work + 6*dim; /* k1 step */ if(dydt_in != 0) { memcpy(k1, dydt_in, dim * sizeof(double)); } else { status += ( GSL_ODEIV_FN_EVAL(sys, t, y, k1) != 0 ); } for(i=0;iwork != 0) free(my->work); free(self); } }