#include #include #include #include "rk.h" /* Runge-Kutta-Fehlberg method solve an ordinary differential equation dq/dt = f(t,q) where q is an n-dimensional vector consisting of n variables. */ /* solve an ordinary differential equation dq/dt = f(t,q) from the k-th time step to the (k+1)-th time step input: *pt time at the k-th time step dt time step (interval) n dimension of vector q q[] value of vector q at the k-th time step diff() function to compute f(t,q) function diff() should be in the following form: diff(double t, int n, double q[], double dotq[]) t time n dimension of vector q q[] vector (n-dimensional array) dotq[] array where value of f(t,q) is stored (n-dimensional array) output: *pt time at the (k+1)-th time step q[] value of vector q at the (k+1)-th time step */ extern void RKFOneStep (double *pt, double dt, int n, double q[], void diff(double, int, double *, double *)) { int i; double t2, t3, t4, t5, t6; double q2[MaxVars], q3[MaxVars], q4[MaxVars], q5[MaxVars], q6[MaxVars]; double d1[MaxVars], d2[MaxVars], d3[MaxVars], d4[MaxVars], d5[MaxVars], d6[MaxVars]; diff(*pt, n, q, d1); /* comp. d1 */ t2 = (*pt) + (1./4.)*dt; for(i=0;i MaxVars) { fprintf(stderr, "%d exceeds MaxVars (%d)\n", n, MaxVars); fprintf(stderr, "increase MaxVars in opt.h and recompile all\n"); exit(1); } for(k=1; k<=cnt; k++) { #if DEBUG printf("<<<<< count = %d >>>>>\n", k); #endif RKFOneStep(pt, dt, n, q, diff); RKFfprint(fd, *pt, n, q); } } /* adaptive Runge-Kutta-Fehlberg formula solve an ordinary differential equation dq/dt = f(t,q). time interval is updated adaptively */ #define SafetyRatio 0.80 #define Allowance 1e-6 #define PowerTwo(a) ((a)*(a)) #define PowerFive(a) ((a)*(a)*(a)*(a)*(a)) extern void RKFadaptiveOneStep(double *pt, double *pdt, int n, double q[], void diff(double, int, double *, double *)) { int i; double t1, t2, t3, t4, t5, t6; double q1[MaxVars], q2[MaxVars], q3[MaxVars], q4[MaxVars], q5[MaxVars], q6[MaxVars]; double d1[MaxVars], d2[MaxVars], d3[MaxVars], d4[MaxVars], d5[MaxVars], d6[MaxVars]; double qest[MaxVars]; double dt, error, limit; dt = (*pdt); /* current time step */ t1 = (*pt); for(i=0;i Allowance * PowerFive(SafetyRatio)) { limit = SafetyRatio * dt * pow(Allowance/error,0.20); while (*pdt > limit) { *pdt = (*pdt)/2; } } else { limit = SafetyRatio * dt * pow(Allowance/error,0.20); while ( 2*(*pdt) < limit) { *pdt = (*pdt)*2; } } } extern void RKFadaptivefprint(FILE *fd, double t, double dt, int n, double q[]) { int i; fprintf(fd, format, t); for(i=0;i MaxVars) { fprintf(stderr, "%d exceeds MaxVars (%d)\n", n, MaxVars); fprintf(stderr, "increase MaxVars in opt.h and recompile all\n"); exit(1); } for(k=1; k<=cnt; k++) { #if DEBUG printf("<<<<< count = %d dt = %lf >>>>>\n", k, *pdt); #endif RKFadaptiveOneStep(pt, pdt, n, q, diff); RKFadaptivefprint(fd, *pt, *pdt, n, q); if ((*pt) > tend) break; } }