Blame ode-initval2/driver.c

Packit 67cb25
/* ode-initval2/driver.c
Packit 67cb25
 * 
Packit 67cb25
 * Copyright (C) 2009, 2010 Tuomo Keskitalo
Packit 67cb25
 * 
Packit 67cb25
 * This program is free software; you can redistribute it and/or modify
Packit 67cb25
 * it under the terms of the GNU General Public License as published by
Packit 67cb25
 * the Free Software Foundation; either version 3 of the License, or (at
Packit 67cb25
 * your option) any later version.
Packit 67cb25
 * 
Packit 67cb25
 * This program is distributed in the hope that it will be useful, but
Packit 67cb25
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 67cb25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 67cb25
 * General Public License for more details.
Packit 67cb25
 * 
Packit 67cb25
 * You should have received a copy of the GNU General Public License
Packit 67cb25
 * along with this program; if not, write to the Free Software
Packit 67cb25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 67cb25
 */
Packit 67cb25
Packit 67cb25
/* Driver routine for odeiv2. This is a wrapper for low level GSL
Packit 67cb25
   functions that allows a simple interface to step, control and
Packit 67cb25
   evolve layers.
Packit 67cb25
 */
Packit 67cb25
Packit 67cb25
#include <config.h>
Packit 67cb25
#include <math.h>
Packit 67cb25
#include <gsl/gsl_errno.h>
Packit 67cb25
#include <gsl/gsl_odeiv2.h>
Packit 67cb25
#include <gsl/gsl_machine.h>
Packit 67cb25
Packit 67cb25
static gsl_odeiv2_driver *
Packit 67cb25
driver_alloc (const gsl_odeiv2_system * sys, const double hstart,
Packit 67cb25
              const gsl_odeiv2_step_type * T)
Packit 67cb25
{
Packit 67cb25
  /* Allocates and initializes an ODE driver system. Step and evolve
Packit 67cb25
     objects are allocated here, but control object is allocated in
Packit 67cb25
     another function.
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  gsl_odeiv2_driver *state;
Packit 67cb25
Packit 67cb25
  if (sys == NULL)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("gsl_odeiv2_system must be defined", GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state = (gsl_odeiv2_driver *) calloc (1, sizeof (gsl_odeiv2_driver));
Packit 67cb25
Packit 67cb25
  if (state == NULL)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for driver state",
Packit 67cb25
                      GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  {
Packit 67cb25
    const size_t dim = sys->dimension;
Packit 67cb25
Packit 67cb25
    if (dim == 0)
Packit 67cb25
      {
Packit 67cb25
        gsl_odeiv2_driver_free(state);
Packit 67cb25
        GSL_ERROR_NULL
Packit 67cb25
          ("gsl_odeiv2_system dimension must be a positive integer",
Packit 67cb25
           GSL_EINVAL);
Packit 67cb25
      }
Packit 67cb25
Packit 67cb25
    state->sys = sys;
Packit 67cb25
Packit 67cb25
    state->s = gsl_odeiv2_step_alloc (T, dim);
Packit 67cb25
Packit 67cb25
    if (state->s == NULL)
Packit 67cb25
      {
Packit 67cb25
        gsl_odeiv2_driver_free(state);
Packit 67cb25
        GSL_ERROR_NULL ("failed to allocate step object", GSL_ENOMEM);
Packit 67cb25
      }
Packit 67cb25
Packit 67cb25
    state->e = gsl_odeiv2_evolve_alloc (dim);
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  if (state->e == NULL)
Packit 67cb25
    {
Packit 67cb25
      gsl_odeiv2_driver_free(state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate evolve object", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  if (hstart > 0.0 || hstart < 0.0)
Packit 67cb25
    {
Packit 67cb25
      state->h = hstart;
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      gsl_odeiv2_driver_free(state);
Packit 67cb25
      GSL_ERROR_NULL ("invalid hstart", GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->h = hstart;
Packit 67cb25
  state->hmin = 0.0;
Packit 67cb25
  state->hmax = GSL_DBL_MAX;
Packit 67cb25
  state->nmax = 0;
Packit 67cb25
  state->n = 0;
Packit 67cb25
  state->c = NULL;
Packit 67cb25
Packit 67cb25
  return state;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_odeiv2_driver_set_hmin (gsl_odeiv2_driver * d, const double hmin)
Packit 67cb25
{
Packit 67cb25
  /* Sets minimum allowed step size fabs(hmin) for driver. It is
Packit 67cb25
     required that hmin <= fabs(h) <= hmax. */
Packit 67cb25
Packit 67cb25
  if ((fabs (hmin) > fabs (d->h)) || (fabs (hmin) > d->hmax))
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("hmin <= fabs(h) <= hmax required", GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  d->hmin = fabs (hmin);
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_odeiv2_driver_set_hmax (gsl_odeiv2_driver * d, const double hmax)
Packit 67cb25
{
Packit 67cb25
  /* Sets maximum allowed step size fabs(hmax) for driver. It is
Packit 67cb25
     required that hmin <= fabs(h) <= hmax. */
Packit 67cb25
Packit 67cb25
  if ((fabs (hmax) < fabs (d->h)) || (fabs (hmax) < d->hmin))
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("hmin <= fabs(h) <= hmax required", GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  if (hmax > 0.0 || hmax < 0.0)
Packit 67cb25
    {
Packit 67cb25
      d->hmax = fabs (hmax);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("invalid hmax", GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_odeiv2_driver_set_nmax (gsl_odeiv2_driver * d,
Packit 67cb25
                            const unsigned long int nmax)
Packit 67cb25
{
Packit 67cb25
  /* Sets maximum number of allowed steps (nmax) for driver */
Packit 67cb25
Packit 67cb25
  d->nmax = nmax;
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
gsl_odeiv2_driver *
Packit 67cb25
gsl_odeiv2_driver_alloc_y_new (const gsl_odeiv2_system * sys,
Packit 67cb25
                               const gsl_odeiv2_step_type * T,
Packit 67cb25
                               const double hstart,
Packit 67cb25
                               const double epsabs, const double epsrel)
Packit 67cb25
{
Packit 67cb25
  /* Initializes an ODE driver system with control object of type y_new. */
Packit 67cb25
Packit 67cb25
  gsl_odeiv2_driver *state = driver_alloc (sys, hstart, T);
Packit 67cb25
Packit 67cb25
  if (state == NULL)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate driver object", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  if (epsabs >= 0.0 && epsrel >= 0.0)
Packit 67cb25
    {
Packit 67cb25
      state->c = gsl_odeiv2_control_y_new (epsabs, epsrel);
Packit 67cb25
Packit 67cb25
      if (state->c == NULL)
Packit 67cb25
        {
Packit 67cb25
          gsl_odeiv2_driver_free (state);
Packit 67cb25
          GSL_ERROR_NULL ("failed to allocate control object", GSL_ENOMEM);
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      gsl_odeiv2_driver_free (state);
Packit 67cb25
      GSL_ERROR_NULL ("epsabs and epsrel must be positive", GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Distribute pointer to driver object */
Packit 67cb25
Packit 67cb25
  gsl_odeiv2_step_set_driver (state->s, state);
Packit 67cb25
  gsl_odeiv2_evolve_set_driver (state->e, state);
Packit 67cb25
  gsl_odeiv2_control_set_driver (state->c, state);
Packit 67cb25
Packit 67cb25
  return state;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
gsl_odeiv2_driver *
Packit 67cb25
gsl_odeiv2_driver_alloc_yp_new (const gsl_odeiv2_system * sys,
Packit 67cb25
                                const gsl_odeiv2_step_type * T,
Packit 67cb25
                                const double hstart,
Packit 67cb25
                                const double epsabs, const double epsrel)
Packit 67cb25
{
Packit 67cb25
  /* Initializes an ODE driver system with control object of type yp_new. */
Packit 67cb25
Packit 67cb25
  gsl_odeiv2_driver *state = driver_alloc (sys, hstart, T);
Packit 67cb25
Packit 67cb25
  if (state == NULL)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate driver object", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  if (epsabs >= 0.0 && epsrel >= 0.0)
Packit 67cb25
    {
Packit 67cb25
      state->c = gsl_odeiv2_control_yp_new (epsabs, epsrel);
Packit 67cb25
Packit 67cb25
      if (state->c == NULL)
Packit 67cb25
        {
Packit 67cb25
          gsl_odeiv2_driver_free (state);
Packit 67cb25
          GSL_ERROR_NULL ("failed to allocate control object", GSL_ENOMEM);
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      gsl_odeiv2_driver_free (state);
Packit 67cb25
      GSL_ERROR_NULL ("epsabs and epsrel must be positive", GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Distribute pointer to driver object */
Packit 67cb25
Packit 67cb25
  gsl_odeiv2_step_set_driver (state->s, state);
Packit 67cb25
  gsl_odeiv2_evolve_set_driver (state->e, state);
Packit 67cb25
  gsl_odeiv2_control_set_driver (state->c, state);
Packit 67cb25
Packit 67cb25
  return state;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
gsl_odeiv2_driver *
Packit 67cb25
gsl_odeiv2_driver_alloc_standard_new (const gsl_odeiv2_system * sys,
Packit 67cb25
                                      const gsl_odeiv2_step_type * T,
Packit 67cb25
                                      const double hstart,
Packit 67cb25
                                      const double epsabs,
Packit 67cb25
                                      const double epsrel, const double a_y,
Packit 67cb25
                                      const double a_dydt)
Packit 67cb25
{
Packit 67cb25
  /* Initializes an ODE driver system with control object of type
Packit 67cb25
     standard_new. 
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  gsl_odeiv2_driver *state = driver_alloc (sys, hstart, T);
Packit 67cb25
Packit 67cb25
  if (state == NULL)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate driver object", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  if (epsabs >= 0.0 && epsrel >= 0.0)
Packit 67cb25
    {
Packit 67cb25
      state->c =
Packit 67cb25
        gsl_odeiv2_control_standard_new (epsabs, epsrel, a_y, a_dydt);
Packit 67cb25
Packit 67cb25
      if (state->c == NULL)
Packit 67cb25
        {
Packit 67cb25
          gsl_odeiv2_driver_free (state);
Packit 67cb25
          GSL_ERROR_NULL ("failed to allocate control object", GSL_ENOMEM);
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      gsl_odeiv2_driver_free (state);
Packit 67cb25
      GSL_ERROR_NULL ("epsabs and epsrel must be positive", GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Distribute pointer to driver object */
Packit 67cb25
Packit 67cb25
  gsl_odeiv2_step_set_driver (state->s, state);
Packit 67cb25
  gsl_odeiv2_evolve_set_driver (state->e, state);
Packit 67cb25
  gsl_odeiv2_control_set_driver (state->c, state);
Packit 67cb25
Packit 67cb25
  return state;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
gsl_odeiv2_driver *
Packit 67cb25
gsl_odeiv2_driver_alloc_scaled_new (const gsl_odeiv2_system * sys,
Packit 67cb25
                                    const gsl_odeiv2_step_type * T,
Packit 67cb25
                                    const double hstart,
Packit 67cb25
                                    const double epsabs, const double epsrel,
Packit 67cb25
                                    const double a_y, const double a_dydt,
Packit 67cb25
                                    const double scale_abs[])
Packit 67cb25
{
Packit 67cb25
  /* Initializes an ODE driver system with control object of type
Packit 67cb25
     scaled_new. 
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  gsl_odeiv2_driver *state = driver_alloc (sys, hstart, T);
Packit 67cb25
Packit 67cb25
  if (state == NULL)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate driver object", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  if (epsabs >= 0.0 && epsrel >= 0.0)
Packit 67cb25
    {
Packit 67cb25
      state->c = gsl_odeiv2_control_scaled_new (epsabs, epsrel, a_y, a_dydt,
Packit 67cb25
                                                scale_abs, sys->dimension);
Packit 67cb25
Packit 67cb25
      if (state->c == NULL)
Packit 67cb25
        {
Packit 67cb25
          gsl_odeiv2_driver_free (state);
Packit 67cb25
          GSL_ERROR_NULL ("failed to allocate control object", GSL_ENOMEM);
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      gsl_odeiv2_driver_free (state);
Packit 67cb25
      GSL_ERROR_NULL ("epsabs and epsrel must be positive", GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Distribute pointer to driver object */
Packit 67cb25
Packit 67cb25
  gsl_odeiv2_step_set_driver (state->s, state);
Packit 67cb25
  gsl_odeiv2_evolve_set_driver (state->e, state);
Packit 67cb25
  gsl_odeiv2_control_set_driver (state->c, state);
Packit 67cb25
Packit 67cb25
  return state;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_odeiv2_driver_apply (gsl_odeiv2_driver * d, double *t,
Packit 67cb25
                         const double t1, double y[])
Packit 67cb25
{
Packit 67cb25
  /* Main driver function that evolves the system from t to t1. In
Packit 67cb25
     beginning vector y contains the values of dependent variables at
Packit 67cb25
     t. This function returns values at t=t1 in y. In case of
Packit 67cb25
     unrecoverable error, y and t contains the values after the last
Packit 67cb25
     successful step.
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  int sign = 0;
Packit 67cb25
  d->n = 0;
Packit 67cb25
Packit 67cb25
  /* Determine integration direction sign */
Packit 67cb25
Packit 67cb25
  if (d->h > 0.0)
Packit 67cb25
    {
Packit 67cb25
      sign = 1;
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      sign = -1;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Check that t, t1 and step direction are sensible */
Packit 67cb25
Packit 67cb25
  if (sign * (t1 - *t) < 0.0)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL
Packit 67cb25
        ("integration limits and/or step direction not consistent",
Packit 67cb25
         GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Evolution loop */
Packit 67cb25
Packit 67cb25
  while (sign * (t1 - *t) > 0.0)
Packit 67cb25
    {
Packit 67cb25
      int s = gsl_odeiv2_evolve_apply (d->e, d->c, d->s, d->sys,
Packit 67cb25
                                       t, t1, &(d->h), y);
Packit 67cb25
Packit 67cb25
      if (s != GSL_SUCCESS)
Packit 67cb25
        {
Packit 67cb25
          return s;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* Check for maximum allowed steps */
Packit 67cb25
Packit 67cb25
      if ((d->nmax > 0) && (d->n > d->nmax))
Packit 67cb25
        {
Packit 67cb25
          return GSL_EMAXITER;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* Set step size if maximum size is exceeded */
Packit 67cb25
Packit 67cb25
      if (fabs (d->h) > d->hmax)
Packit 67cb25
        {
Packit 67cb25
          d->h = sign * d->hmax;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* Check for too small step size */
Packit 67cb25
Packit 67cb25
      if (fabs (d->h) < d->hmin)
Packit 67cb25
        {
Packit 67cb25
          return GSL_ENOPROG;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      d->n++;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_odeiv2_driver_apply_fixed_step (gsl_odeiv2_driver * d, double *t,
Packit 67cb25
                                    const double h, const unsigned long int n,
Packit 67cb25
                                    double y[])
Packit 67cb25
{
Packit 67cb25
  /* Alternative driver function that evolves the system from t using
Packit 67cb25
   * n steps of size h. In the beginning vector y contains the values
Packit 67cb25
   * of dependent variables at t. This function returns values at t =
Packit 67cb25
   * t + n * h in y. In case of an unrecoverable error, y and t
Packit 67cb25
   * contains the values after the last successful step.
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  unsigned long int i;
Packit 67cb25
  d->n = 0;
Packit 67cb25
Packit 67cb25
  /* Evolution loop */
Packit 67cb25
Packit 67cb25
  for (i = 0; i < n; i++)
Packit 67cb25
    {
Packit 67cb25
      int s = gsl_odeiv2_evolve_apply_fixed_step (d->e, d->c, d->s, d->sys,
Packit 67cb25
                                                  t, h, y);
Packit 67cb25
Packit 67cb25
      if (s != GSL_SUCCESS)
Packit 67cb25
        {
Packit 67cb25
          return s;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      d->n++;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_odeiv2_driver_reset (gsl_odeiv2_driver * d)
Packit 67cb25
{
Packit 67cb25
  /* Reset the driver. Resets evolve and step objects. */
Packit 67cb25
Packit 67cb25
  {
Packit 67cb25
    int s = gsl_odeiv2_evolve_reset (d->e);
Packit 67cb25
Packit 67cb25
    if (s != GSL_SUCCESS)
Packit 67cb25
      {
Packit 67cb25
        return s;
Packit 67cb25
      }
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  {
Packit 67cb25
    int s = gsl_odeiv2_step_reset (d->s);
Packit 67cb25
Packit 67cb25
    if (s != GSL_SUCCESS)
Packit 67cb25
      {
Packit 67cb25
        return s;
Packit 67cb25
      }
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_odeiv2_driver_reset_hstart (gsl_odeiv2_driver * d, const double hstart)
Packit 67cb25
{
Packit 67cb25
  /* Resets current driver and sets initial step size to hstart */
Packit 67cb25
Packit 67cb25
  gsl_odeiv2_driver_reset (d);
Packit 67cb25
Packit 67cb25
  if ((d->hmin > fabs (hstart)) || (fabs (hstart) > d->hmax))
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("hmin <= fabs(h) <= hmax required", GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  if (hstart > 0.0 || hstart < 0.0)
Packit 67cb25
    {
Packit 67cb25
      d->h = hstart;
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("invalid hstart", GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
void
Packit 67cb25
gsl_odeiv2_driver_free (gsl_odeiv2_driver * state)
Packit 67cb25
{
Packit 67cb25
  if (state->c)
Packit 67cb25
    gsl_odeiv2_control_free (state->c);
Packit 67cb25
Packit 67cb25
  if (state->e)
Packit 67cb25
    gsl_odeiv2_evolve_free (state->e);
Packit 67cb25
Packit 67cb25
  if (state->s)
Packit 67cb25
    gsl_odeiv2_step_free (state->s);
Packit 67cb25
Packit 67cb25
  free (state);
Packit 67cb25
}