1 /* ode-initval/evolve.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.
25 #include <gsl/gsl_math.h>
26 #include <gsl/gsl_errno.h>
27 #include <gsl/gsl_odeiv.h>
29 #include "odeiv_util.h"
32 gsl_odeiv_evolve_alloc (size_t dim)
35 (gsl_odeiv_evolve *) malloc (sizeof (gsl_odeiv_evolve));
39 GSL_ERROR_NULL ("failed to allocate space for evolve struct",
43 e->y0 = (double *) malloc (dim * sizeof (double));
48 GSL_ERROR_NULL ("failed to allocate space for y0", GSL_ENOMEM);
51 e->yerr = (double *) malloc (dim * sizeof (double));
57 GSL_ERROR_NULL ("failed to allocate space for yerr", GSL_ENOMEM);
60 e->dydt_in = (double *) malloc (dim * sizeof (double));
67 GSL_ERROR_NULL ("failed to allocate space for dydt_in", GSL_ENOMEM);
70 e->dydt_out = (double *) malloc (dim * sizeof (double));
78 GSL_ERROR_NULL ("failed to allocate space for dydt_out", GSL_ENOMEM);
90 gsl_odeiv_evolve_reset (gsl_odeiv_evolve * e)
99 gsl_odeiv_evolve_free (gsl_odeiv_evolve * e)
108 /* Evolution framework method.
110 * Uses an adaptive step control object
113 gsl_odeiv_evolve_apply (gsl_odeiv_evolve * e,
114 gsl_odeiv_control * con,
115 gsl_odeiv_step * step,
116 const gsl_odeiv_system * dydt,
117 double *t, double t1, double *h, double y[])
119 const double t0 = *t;
123 double dt = t1 - t0; /* remaining time, possibly less than h */
125 if (e->dimension != step->dimension)
127 GSL_ERROR ("step dimension must match evolution size", GSL_EINVAL);
130 if ((dt < 0.0 && h0 > 0.0) || (dt > 0.0 && h0 < 0.0))
132 GSL_ERROR ("step direction must match interval direction", GSL_EINVAL);
135 /* No need to copy if we cannot control the step size. */
139 DBL_MEMCPY (e->y0, y, e->dimension);
142 /* Calculate initial dydt once if the method can benefit. */
144 if (step->type->can_use_dydt_in)
146 int status = GSL_ODEIV_FN_EVAL (dydt, t0, y, e->dydt_in);
156 if ((dt >= 0.0 && h0 > dt) || (dt < 0.0 && h0 < dt))
166 if (step->type->can_use_dydt_in)
169 gsl_odeiv_step_apply (step, t0, h0, y, e->yerr, e->dydt_in,
175 gsl_odeiv_step_apply (step, t0, h0, y, e->yerr, NULL, e->dydt_out,
179 /* Check for stepper internal failure */
181 if (step_status != GSL_SUCCESS)
183 *h = h0; /* notify user of step-size which caused the failure */
201 /* Check error and attempt to adjust the step. */
205 const int hadjust_status
206 = gsl_odeiv_control_hadjust (con, step, y, e->yerr, e->dydt_out, &h0);
208 if (hadjust_status == GSL_ODEIV_HADJ_DEC)
210 /* Check that the reported status is correct (i.e. an actual
211 decrease in h0 occured) and the suggested h0 will change
212 the time by at least 1 ulp */
214 double t_curr = GSL_COERCE_DBL(*t);
215 double t_next = GSL_COERCE_DBL((*t) + h0);
217 if (fabs(h0) < fabs(h_old) && t_next != t_curr)
219 /* Step was decreased. Undo step, and try again with new h0. */
220 DBL_MEMCPY (y, e->y0, dydt->dimension);
226 h0 = h_old; /* keep current step size */
231 *h = h0; /* suggest step size for next time-step */