1 /* ode-initval/rk2imp.c
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 2, Gaussian implicit. Also known as the implicit
23 /* Author: G. Jungman */
25 /* Error estimation by step doubling, see eg. Ascher, U.M., Petzold,
26 L.R., Computer methods for ordinary differential and
27 differential-algebraic equations, SIAM, Philadelphia, 1998.
28 The method is also described in eg. this reference.
34 #include <gsl/gsl_math.h>
35 #include <gsl/gsl_errno.h>
36 #include <gsl/gsl_odeiv.h>
38 #include "odeiv_util.h"
51 rk2imp_alloc (size_t dim)
53 rk2imp_state_t *state = (rk2imp_state_t *) malloc (sizeof (rk2imp_state_t));
57 GSL_ERROR_NULL ("failed to allocate space for rk2imp_state",
61 state->Y1 = (double *) malloc (dim * sizeof (double));
66 GSL_ERROR_NULL ("failed to allocate space for Y1", GSL_ENOMEM);
69 state->ytmp = (double *) malloc (dim * sizeof (double));
75 GSL_ERROR_NULL ("failed to allocate space for ytmp", GSL_ENOMEM);
78 state->y0 = (double *) malloc (dim * sizeof (double));
85 GSL_ERROR_NULL ("failed to allocate space for y0", GSL_ENOMEM);
88 state->y_onestep = (double *) malloc (dim * sizeof (double));
90 if (state->y_onestep == 0)
96 GSL_ERROR_NULL ("failed to allocate space for y_onestep", GSL_ENOMEM);
99 state->y0_orig = (double *) malloc (dim * sizeof (double));
101 if (state->y0_orig == 0)
103 free (state->y_onestep);
108 GSL_ERROR_NULL ("failed to allocate space for y0_orig", GSL_ENOMEM);
115 rk2imp_step (double *y, rk2imp_state_t *state,
116 const double h, const double t,
117 const size_t dim, const gsl_odeiv_system *sys)
119 /* Makes a Runge-Kutta 2nd order implicit advance with step size h.
120 y0 is initial values of variables y.
122 The implicit matrix equations to solve are:
124 Y1 = y0 + h/2 * f(t + h/2, Y1)
126 y = y0 + h * f(t + h/2, Y1)
129 const double *y0 = state->y0;
130 double *Y1 = state->Y1;
131 double *ytmp = state->ytmp;
136 /* iterative solution of Y1 = y0 + h/2 * f(t + h/2, Y1)
137 Y1 should include initial values at call.
139 Note: This method does not check for convergence of the
143 for (nu = 0; nu < max_iter; nu++)
145 for (i = 0; i < dim; i++)
147 ytmp[i] = y0[i] + 0.5 * h * Y1[i];
151 int s = GSL_ODEIV_FN_EVAL (sys, t + 0.5 * h, ytmp, Y1);
153 if (s != GSL_SUCCESS)
162 for (i = 0; i < dim; i++)
164 y[i] = y0[i] + h * Y1[i];
171 rk2imp_apply (void *vstate,
177 const double dydt_in[],
178 double dydt_out[], const gsl_odeiv_system * sys)
180 rk2imp_state_t *state = (rk2imp_state_t *) vstate;
184 double *Y1 = state->Y1;
185 double *y0 = state->y0;
186 double *y_onestep = state->y_onestep;
187 double *y0_orig = state->y0_orig;
189 /* Error estimation is done by step doubling procedure */
191 /* initialization step */
193 DBL_MEMCPY (y0, y, dim);
195 /* Save initial values for possible failures */
196 DBL_MEMCPY (y0_orig, y, dim);
200 DBL_MEMCPY (Y1, dydt_in, dim);
205 int s = GSL_ODEIV_FN_EVAL (sys, t, y, Y1);
207 if (s != GSL_SUCCESS)
213 /* First traverse h with one step (save to y_onestep) */
215 DBL_MEMCPY (y_onestep, y, dim);
218 int s = rk2imp_step (y_onestep, state, h, t, dim, sys);
220 if (s != GSL_SUCCESS)
226 /* Then with two steps with half step length (save to y) */
229 int s = rk2imp_step (y, state, h / 2.0, t, dim, sys);
231 if (s != GSL_SUCCESS)
233 /* Restore original y vector */
234 DBL_MEMCPY (y, y0_orig, dim);
240 DBL_MEMCPY (y0, y, dim);
243 int s = GSL_ODEIV_FN_EVAL (sys, t + h / 2.0, y, Y1);
245 if (s != GSL_SUCCESS)
247 /* Restore original y vector */
248 DBL_MEMCPY (y, y0_orig, dim);
255 int s = rk2imp_step (y, state, h / 2.0, t + h / 2.0, dim, sys);
257 if (s != GSL_SUCCESS)
259 /* Restore original y vector */
260 DBL_MEMCPY (y, y0_orig, dim);
266 /* Derivatives at output */
268 if (dydt_out != NULL)
270 int s = GSL_ODEIV_FN_EVAL (sys, t + h, y, dydt_out);
272 if (s != GSL_SUCCESS)
274 /* Restore original y vector */
275 DBL_MEMCPY (y, y0_orig, dim);
281 /* Error estimation */
283 for (i = 0; i < dim; i++)
285 yerr[i] = 4.0 * (y[i] - y_onestep[i]) / 3.0;
292 rk2imp_reset (void *vstate, size_t dim)
294 rk2imp_state_t *state = (rk2imp_state_t *) vstate;
296 DBL_ZERO_MEMSET (state->Y1, dim);
297 DBL_ZERO_MEMSET (state->ytmp, dim);
298 DBL_ZERO_MEMSET (state->y0, dim);
299 DBL_ZERO_MEMSET (state->y_onestep, dim);
300 DBL_ZERO_MEMSET (state->y0_orig, dim);
306 rk2imp_order (void *vstate)
308 rk2imp_state_t *state = (rk2imp_state_t *) vstate;
309 state = 0; /* prevent warnings about unused parameters */
314 rk2imp_free (void *vstate)
316 rk2imp_state_t *state = (rk2imp_state_t *) vstate;
321 free (state->y_onestep);
322 free (state->y0_orig);
326 static const gsl_odeiv_step_type rk2imp_type = { "rk2imp", /* name */
327 1, /* can use dydt_in */
328 1, /* gives exact dydt_out */
336 const gsl_odeiv_step_type *gsl_odeiv_step_rk2imp = &rk2imp_type;