odesolve.c
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | //----------------------------------------------------------------------------- | ||
| 2 | // odesolve.c | ||
| 3 | // | ||
| 4 | // Fifth-order Runge-Kutta integration with adaptive step size control | ||
| 5 | // based on code from Numerical Recipes in C (Cambridge University | ||
| 6 | // Press, 1992). | ||
| 7 | // | ||
| 8 | // Date: 11/15/06 | ||
| 9 | // Author: L. Rossman | ||
| 10 | //----------------------------------------------------------------------------- | ||
| 11 | |||
| 12 | #include <stdlib.h> | ||
| 13 | #include <math.h> | ||
| 14 | #include "odesolve.h" | ||
| 15 | |||
| 16 | #define MAXSTP 10000 | ||
| 17 | #define TINY 1.0e-30 | ||
| 18 | #define SAFETY 0.9 | ||
| 19 | #define PGROW -0.2 | ||
| 20 | #define PSHRNK -0.25 | ||
| 21 | #define ERRCON 1.89e-4 // = (5/SAFETY)^(1/PGROW) | ||
| 22 | |||
| 23 | |||
| 24 | //----------------------------------------------------------------------------- | ||
| 25 | // Local declarations | ||
| 26 | //----------------------------------------------------------------------------- | ||
| 27 | int nmax; // max. number of equations | ||
| 28 | double* y; // dependent variable | ||
| 29 | double* yscal; // scaling factors | ||
| 30 | double* yerr; // integration errors | ||
| 31 | double* ytemp; // temporary values of y | ||
| 32 | double* dydx; // derivatives of y | ||
| 33 | double* ak; // derivatives at intermediate points | ||
| 34 | |||
| 35 | |||
| 36 | // function that integrates over an error-controlled stepsize | ||
| 37 | int rkqs(double* x, int n, double htry, double eps, double* hdid, | ||
| 38 | double* hnext, void (*derivs)(double, double*, double*)); | ||
| 39 | |||
| 40 | // function that performs the Runge-Kutta integration step | ||
| 41 | void rkck(double x, int n, double h, void (*derivs)(double, double*, double*)); | ||
| 42 | |||
| 43 | |||
| 44 | //----------------------------------------------------------------------------- | ||
| 45 | // open the ODE solver to solve system of n equations | ||
| 46 | // (return 1 if successful, 0 if not) | ||
| 47 | //----------------------------------------------------------------------------- | ||
| 48 | 37 | int odesolve_open(int n) | |
| 49 | { | ||
| 50 | 37 | int n5 = n*5; | |
| 51 | 37 | nmax = 0; | |
| 52 | 37 | y = (double *) calloc(n, sizeof(double)); | |
| 53 | 37 | yscal = (double *) calloc(n, sizeof(double)); | |
| 54 | 37 | dydx = (double *) calloc(n, sizeof(double)); | |
| 55 | 37 | yerr = (double *) calloc(n, sizeof(double)); | |
| 56 | 37 | ytemp = (double *) calloc(n, sizeof(double)); | |
| 57 | 37 | ak = (double *) calloc(n5, sizeof(double)); | |
| 58 |
6/12✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 37 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 37 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 37 times.
|
37 | if ( !y || !yscal || !dydx || !yerr || !ytemp || !ak ) return 0; |
| 59 | 37 | nmax = n; | |
| 60 | 37 | return 1; | |
| 61 | } | ||
| 62 | |||
| 63 | |||
| 64 | //----------------------------------------------------------------------------- | ||
| 65 | // close the ODE solver | ||
| 66 | //----------------------------------------------------------------------------- | ||
| 67 | 37 | void odesolve_close() | |
| 68 | { | ||
| 69 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | if ( y ) free(y); |
| 70 | 37 | y = NULL; | |
| 71 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | if ( yscal ) free(yscal); |
| 72 | 37 | yscal = NULL; | |
| 73 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | if ( dydx ) free(dydx); |
| 74 | 37 | dydx = NULL; | |
| 75 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | if ( yerr ) free(yerr); |
| 76 | 37 | yerr = NULL; | |
| 77 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | if ( ytemp ) free(ytemp); |
| 78 | 37 | ytemp = NULL; | |
| 79 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | if ( ak ) free(ak); |
| 80 | 37 | ak = NULL; | |
| 81 | 37 | nmax = 0; | |
| 82 | 37 | } | |
| 83 | |||
| 84 | |||
| 85 | 4706940 | int odesolve_integrate(double ystart[], int n, double x1, double x2, | |
| 86 | double eps, double h1, void (*derivs)(double, double*, double*)) | ||
| 87 | //--------------------------------------------------------------- | ||
| 88 | // Driver function for Runge-Kutta integration with adaptive | ||
| 89 | // stepsize control. Integrates starting n values in ystart[] | ||
| 90 | // from x1 to x2 with accuracy eps. h1 is the initial stepsize | ||
| 91 | // guess and derivs is a user-supplied function that computes | ||
| 92 | // derivatives dy/dx of y. On completion, ystart[] contains the | ||
| 93 | // new values of y at the end of the integration interval. | ||
| 94 | //--------------------------------------------------------------- | ||
| 95 | { | ||
| 96 | int i, errcode, nstp; | ||
| 97 | double hdid, hnext; | ||
| 98 | 4706940 | double x = x1; | |
| 99 | 4706940 | double h = h1; | |
| 100 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4706940 times.
|
4706940 | if (nmax < n) return 1; |
| 101 |
2/2✓ Branch 0 taken 7740486 times.
✓ Branch 1 taken 4706940 times.
|
12447426 | for (i=0; i<n; i++) y[i] = ystart[i]; |
| 102 |
1/2✓ Branch 0 taken 4723562 times.
✗ Branch 1 not taken.
|
4723562 | for (nstp=1; nstp<=MAXSTP; nstp++) |
| 103 | { | ||
| 104 | 4723562 | derivs(x,y,dydx); | |
| 105 |
2/2✓ Branch 0 taken 7757118 times.
✓ Branch 1 taken 4723562 times.
|
12480680 | for (i=0; i<n; i++) |
| 106 | 7757118 | yscal[i] = fabs(y[i]) + fabs(dydx[i]*h) + TINY; | |
| 107 |
2/2✓ Branch 0 taken 10184 times.
✓ Branch 1 taken 4713378 times.
|
4723562 | if ((x+h-x2)*(x+h-x1) > 0.0) h = x2 - x; |
| 108 | 4723562 | errcode = rkqs(&x,n,h,eps,&hdid,&hnext,derivs); | |
| 109 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4723562 times.
|
4723562 | if (errcode) break; |
| 110 |
2/2✓ Branch 0 taken 4706940 times.
✓ Branch 1 taken 16622 times.
|
4723562 | if ((x-x2)*(x2-x1) >= 0.0) |
| 111 | { | ||
| 112 |
2/2✓ Branch 0 taken 7740486 times.
✓ Branch 1 taken 4706940 times.
|
12447426 | for (i=0; i<n; i++) ystart[i] = y[i]; |
| 113 | 4706940 | return 0; | |
| 114 | } | ||
| 115 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16622 times.
|
16622 | if (fabs(hnext) <= 0.0) return 2; |
| 116 | 16622 | h = hnext; | |
| 117 | } | ||
| 118 | ✗ | return 3; | |
| 119 | } | ||
| 120 | |||
| 121 | |||
| 122 | 4723562 | int rkqs(double* x, int n, double htry, double eps, double* hdid, | |
| 123 | double* hnext, void (*derivs)(double, double*, double*)) | ||
| 124 | //--------------------------------------------------------------- | ||
| 125 | // Fifth-order Runge-Kutta integration step with monitoring of | ||
| 126 | // local truncation error to assure accuracy and adjust stepsize. | ||
| 127 | // Inputs are current value of x, trial step size (htry), and | ||
| 128 | // accuracy (eps). Outputs are stepsize taken (hdid) and estimated | ||
| 129 | // next stepsize (hnext). Also updated are the values of y[]. | ||
| 130 | //--------------------------------------------------------------- | ||
| 131 | { | ||
| 132 | int i; | ||
| 133 | 4723562 | double err, errmax, h, htemp, xnew, xold = *x; | |
| 134 | |||
| 135 | // --- set initial stepsize | ||
| 136 | 4723562 | h = htry; | |
| 137 | for (;;) | ||
| 138 | { | ||
| 139 | // --- take a Runge-Kutta-Cash-Karp step | ||
| 140 | 4734080 | rkck(xold, n, h, derivs); | |
| 141 | |||
| 142 | // --- compute scaled maximum error | ||
| 143 | 4734080 | errmax = 0.0; | |
| 144 |
2/2✓ Branch 0 taken 7767648 times.
✓ Branch 1 taken 4734080 times.
|
12501728 | for (i=0; i<n; i++) |
| 145 | { | ||
| 146 | 7767648 | err = fabs(yerr[i]/yscal[i]); | |
| 147 |
2/2✓ Branch 0 taken 6701576 times.
✓ Branch 1 taken 1066072 times.
|
7767648 | if (err > errmax) errmax = err; |
| 148 | } | ||
| 149 | 4734080 | errmax /= eps; | |
| 150 | |||
| 151 | // --- error too large; reduce stepsize & repeat | ||
| 152 |
2/2✓ Branch 0 taken 10518 times.
✓ Branch 1 taken 4723562 times.
|
4734080 | if (errmax > 1.0) |
| 153 | { | ||
| 154 | 10518 | htemp = SAFETY*h*pow(errmax,PSHRNK); | |
| 155 |
1/2✓ Branch 0 taken 10518 times.
✗ Branch 1 not taken.
|
10518 | if (h >= 0) |
| 156 | { | ||
| 157 |
2/2✓ Branch 0 taken 10164 times.
✓ Branch 1 taken 354 times.
|
10518 | if (htemp > 0.1*h) h = htemp; |
| 158 | 354 | else h = 0.1*h; | |
| 159 | } | ||
| 160 | else | ||
| 161 | { | ||
| 162 | ✗ | if (htemp < 0.1*h) h = htemp; | |
| 163 | ✗ | else h = 0.1*h; | |
| 164 | } | ||
| 165 | 10518 | xnew = xold + h; | |
| 166 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10518 times.
|
10518 | if (xnew == xold) return 2; |
| 167 | 10518 | continue; | |
| 168 | } | ||
| 169 | |||
| 170 | // --- step succeeded; compute size of next step | ||
| 171 | else | ||
| 172 | { | ||
| 173 |
2/2✓ Branch 0 taken 189032 times.
✓ Branch 1 taken 4534530 times.
|
4723562 | if (errmax > ERRCON) *hnext = SAFETY*h*pow(errmax,PGROW); |
| 174 | 4534530 | else *hnext = 5.0*h; | |
| 175 | 4723562 | *x += (*hdid=h); | |
| 176 |
2/2✓ Branch 0 taken 7757118 times.
✓ Branch 1 taken 4723562 times.
|
12480680 | for (i=0; i<n; i++) y[i] = ytemp[i]; |
| 177 | 4723562 | return 0; | |
| 178 | } | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | |||
| 183 | 4734080 | void rkck(double x, int n, double h, void (*derivs)(double, double*, double*)) | |
| 184 | //---------------------------------------------------------------------- | ||
| 185 | // Uses the Runge-Kutta-Cash-Karp method to advance y[] at x | ||
| 186 | // over stepsize h. | ||
| 187 | //---------------------------------------------------------------------- | ||
| 188 | { | ||
| 189 | 4734080 | double a2=0.2, a3=0.3, a4=0.6, a5=1.0, a6=0.875, | |
| 190 | 4734080 | b21=0.2, b31=3.0/40.0, b32=9.0/40.0, b41=0.3, b42= -0.9, b43=1.2, | |
| 191 | 4734080 | b51= -11.0/54.0, b52=2.5, b53= -70.0/27.0, b54=35.0/27.0, | |
| 192 | 4734080 | b61=1631.0/55296.0, b62=175.0/512.0, b63=575.0/13824.0, | |
| 193 | 4734080 | b64=44275.0/110592.0, b65=253.0/4096.0, c1=37.0/378.0, | |
| 194 | 4734080 | c3=250.0/621.0, c4=125.0/594.0, c6=512.0/1771.0, | |
| 195 | 4734080 | dc5= -277.0/14336.0; | |
| 196 | 4734080 | double dc1=c1-2825.0/27648.0, dc3=c3-18575.0/48384.0, | |
| 197 | 4734080 | dc4=c4-13525.0/55296.0, dc6=c6-0.25; | |
| 198 | int i; | ||
| 199 | 4734080 | int n2 = n*2; | |
| 200 | 4734080 | int n3 = n*3; | |
| 201 | 4734080 | int n4 = n*4; | |
| 202 | 4734080 | double *ak2 = (ak); | |
| 203 | 4734080 | double *ak3 = ((ak)+(n)); | |
| 204 | 4734080 | double *ak4 = ((ak)+(n2)); | |
| 205 | 4734080 | double *ak5 = ((ak)+(n3)); | |
| 206 | 4734080 | double *ak6 = ((ak)+(n4)); | |
| 207 | |||
| 208 |
2/2✓ Branch 0 taken 7767648 times.
✓ Branch 1 taken 4734080 times.
|
12501728 | for (i=0; i<n; i++) |
| 209 | 7767648 | ytemp[i] = y[i] + b21*h*dydx[i]; | |
| 210 | 4734080 | derivs(x+a2*h,ytemp,ak2); | |
| 211 | |||
| 212 |
2/2✓ Branch 0 taken 7767648 times.
✓ Branch 1 taken 4734080 times.
|
12501728 | for (i=0; i<n; i++) |
| 213 | 7767648 | ytemp[i] = y[i] + h*(b31*dydx[i]+b32*ak2[i]); | |
| 214 | 4734080 | derivs(x+a3*h,ytemp,ak3); | |
| 215 | |||
| 216 |
2/2✓ Branch 0 taken 7767648 times.
✓ Branch 1 taken 4734080 times.
|
12501728 | for (i=0; i<n; i++) |
| 217 | 7767648 | ytemp[i] = y[i] + h*(b41*dydx[i]+b42*ak2[i] + b43*ak3[i]); | |
| 218 | 4734080 | derivs(x+a4*h,ytemp,ak4); | |
| 219 | |||
| 220 |
2/2✓ Branch 0 taken 7767648 times.
✓ Branch 1 taken 4734080 times.
|
12501728 | for (i=0; i<n; i++) |
| 221 | 7767648 | ytemp[i] = y[i] + h*(b51*dydx[i]+b52*ak2[i] + b53*ak3[i] + b54*ak4[i]); | |
| 222 | 4734080 | derivs(x+a5*h,ytemp,ak5); | |
| 223 | |||
| 224 |
2/2✓ Branch 0 taken 7767648 times.
✓ Branch 1 taken 4734080 times.
|
12501728 | for (i=0; i<n; i++) |
| 225 | 7767648 | ytemp[i] = y[i] + h*(b61*dydx[i]+b62*ak2[i] + b63*ak3[i] + b64*ak4[i] | |
| 226 | 7767648 | + b65*ak5[i]); | |
| 227 | 4734080 | derivs(x+a6*h,ytemp,ak6); | |
| 228 | |||
| 229 |
2/2✓ Branch 0 taken 7767648 times.
✓ Branch 1 taken 4734080 times.
|
12501728 | for (i=0; i<n; i++) |
| 230 | 7767648 | ytemp[i] = y[i] + h*(c1*dydx[i] + c3*ak3[i] + c4*ak4[i] + c6*ak6[i]); | |
| 231 | |||
| 232 |
2/2✓ Branch 0 taken 7767648 times.
✓ Branch 1 taken 4734080 times.
|
12501728 | for (i=0; i<n; i++) |
| 233 | 7767648 | yerr[i] = h*(dc1*dydx[i] +dc3*ak3[i] + dc4*ak4[i] + dc5*ak5[i] + dc6*ak6[i]); | |
| 234 | 4734080 | } | |
| 235 |