3 * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or (at
8 * your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 /* Runge-Kutta 4th order, Classical */
25 /* Reference: Abramowitz & Stegun, section 25.5. equation 25.5.10
27 Error estimation by step doubling, see eg. Ascher, U.M., Petzold,
28 L.R., Computer methods for ordinary differential and
29 differential-algebraic equations, SIAM, Philadelphia, 1998.
35 #include <gsl/gsl_errno.h>
36 #include <gsl/gsl_odeiv.h>
38 #include "odeiv_util.h"
51 rk4_alloc (size_t dim)
53 rk4_state_t *state = (rk4_state_t *) malloc (sizeof (rk4_state_t));
57 GSL_ERROR_NULL ("failed to allocate space for rk4_state", GSL_ENOMEM);
60 state->k = (double *) malloc (dim * sizeof (double));
65 GSL_ERROR_NULL ("failed to allocate space for k", GSL_ENOMEM);
68 state->k1 = (double *) malloc (dim * sizeof (double));
74 GSL_ERROR_NULL ("failed to allocate space for k1", GSL_ENOMEM);
77 state->y0 = (double *) malloc (dim * sizeof (double));
84 GSL_ERROR_NULL ("failed to allocate space for y0", GSL_ENOMEM);
87 state->ytmp = (double *) malloc (dim * sizeof (double));
95 GSL_ERROR_NULL ("failed to allocate space for ytmp", GSL_ENOMEM);
98 state->y_onestep = (double *) malloc (dim * sizeof (double));
100 if (state->y_onestep == 0)
107 GSL_ERROR_NULL ("failed to allocate space for ytmp", GSL_ENOMEM);
114 rk4_step (double *y, const rk4_state_t *state,
115 const double h, const double t, const size_t dim,
116 const gsl_odeiv_system *sys)
118 /* Makes a Runge-Kutta 4th order advance with step size h. */
120 /* initial values of variables y. */
121 const double *y0 = state->y0;
124 double *ytmp = state->ytmp;
126 /* Runge-Kutta coefficients. Contains values of coefficient k1
129 double *k = state->k;
135 for (i = 0; i < dim; i++)
137 y[i] += h / 6.0 * k[i];
138 ytmp[i] = y0[i] + 0.5 * h * k[i];
143 int s = GSL_ODEIV_FN_EVAL (sys, t + 0.5 * h, ytmp, k);
145 if (s != GSL_SUCCESS)
151 for (i = 0; i < dim; i++)
153 y[i] += h / 3.0 * k[i];
154 ytmp[i] = y0[i] + 0.5 * h * k[i];
159 int s = GSL_ODEIV_FN_EVAL (sys, t + 0.5 * h, ytmp, k);
161 if (s != GSL_SUCCESS)
167 for (i = 0; i < dim; i++)
169 y[i] += h / 3.0 * k[i];
170 ytmp[i] = y0[i] + h * k[i];
175 int s = GSL_ODEIV_FN_EVAL (sys, t + h, ytmp, k);
177 if (s != GSL_SUCCESS)
183 for (i = 0; i < dim; i++)
185 y[i] += h / 6.0 * k[i];
193 rk4_apply (void *vstate,
199 const double dydt_in[],
201 const gsl_odeiv_system * sys)
203 rk4_state_t *state = (rk4_state_t *) vstate;
207 double *const k = state->k;
208 double *const k1 = state->k1;
209 double *const y0 = state->y0;
210 double *const y_onestep = state->y_onestep;
212 DBL_MEMCPY (y0, y, dim);
216 DBL_MEMCPY (k, dydt_in, dim);
220 int s = GSL_ODEIV_FN_EVAL (sys, t, y0, k);
222 if (s != GSL_SUCCESS)
228 /* Error estimation is done by step doubling procedure */
230 /* Save first point derivatives*/
232 DBL_MEMCPY (k1, k, dim);
234 /* First traverse h with one step (save to y_onestep) */
236 DBL_MEMCPY (y_onestep, y, dim);
239 int s = rk4_step (y_onestep, state, h, t, dim, sys);
241 if (s != GSL_SUCCESS)
247 /* Then with two steps with half step length (save to y) */
249 DBL_MEMCPY (k, k1, dim);
252 int s = rk4_step (y, state, h/2.0, t, dim, sys);
254 if (s != GSL_SUCCESS)
256 /* Restore original values */
257 DBL_MEMCPY (y, y0, dim);
262 /* Update before second step */
264 int s = GSL_ODEIV_FN_EVAL (sys, t + h/2.0, y, k);
266 if (s != GSL_SUCCESS)
268 /* Restore original values */
269 DBL_MEMCPY (y, y0, dim);
274 /* Save original y0 to k1 for possible failures */
275 DBL_MEMCPY (k1, y0, dim);
277 /* Update y0 for second step */
278 DBL_MEMCPY (y0, y, dim);
281 int s = rk4_step (y, state, h/2.0, t + h/2.0, dim, sys);
283 if (s != GSL_SUCCESS)
285 /* Restore original values */
286 DBL_MEMCPY (y, k1, dim);
291 /* Derivatives at output */
293 if (dydt_out != NULL) {
294 int s = GSL_ODEIV_FN_EVAL (sys, t + h, y, dydt_out);
296 if (s != GSL_SUCCESS)
298 /* Restore original values */
299 DBL_MEMCPY (y, k1, dim);
306 yerr = C * 0.5 * | y(onestep) - y(twosteps) | / (2^order - 1)
308 constant C is approximately 8.0 to ensure 90% of samples lie within
309 the error (assuming a gaussian distribution with prior p(sigma)=1/sigma.)
313 for (i = 0; i < dim; i++)
315 yerr[i] = 4.0 * (y[i] - y_onestep[i]) / 15.0;
322 rk4_reset (void *vstate, size_t dim)
324 rk4_state_t *state = (rk4_state_t *) vstate;
326 DBL_ZERO_MEMSET (state->k, dim);
327 DBL_ZERO_MEMSET (state->k1, dim);
328 DBL_ZERO_MEMSET (state->y0, dim);
329 DBL_ZERO_MEMSET (state->ytmp, dim);
330 DBL_ZERO_MEMSET (state->y_onestep, dim);
336 rk4_order (void *vstate)
338 rk4_state_t *state = (rk4_state_t *) vstate;
339 state = 0; /* prevent warnings about unused parameters */
344 rk4_free (void *vstate)
346 rk4_state_t *state = (rk4_state_t *) vstate;
351 free (state->y_onestep);
355 static const gsl_odeiv_step_type rk4_type = { "rk4", /* name */
356 1, /* can use dydt_in */
357 1, /* gives exact dydt_out */
365 const gsl_odeiv_step_type *gsl_odeiv_step_rk4 = &rk4_type;