Blame ode-initval2/msadams.c

Packit 67cb25
/* ode-initval2/msadams.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
/* A variable-coefficient linear multistep Adams method in Nordsieck
Packit 67cb25
   form. This stepper uses explicit Adams-Bashforth (predictor) and
Packit 67cb25
   implicit Adams-Moulton (corrector) methods in P(EC)^m functional
Packit 67cb25
   iteration mode. Method order varies dynamically between 1 and 12.
Packit 67cb25
Packit 67cb25
   References:
Packit 67cb25
Packit 67cb25
   Byrne, G. D., and Hindmarsh, A. C., A Polyalgorithm for the
Packit 67cb25
   Numerical Solution of Ordinary Differential Equations,
Packit 67cb25
   ACM Trans. Math. Software, 1 (1975), pp. 71-96.
Packit 67cb25
Packit 67cb25
   Brown, P. N., Byrne, G. D., and Hindmarsh, A. C., VODE: A
Packit 67cb25
   Variable-coefficient ODE Solver, SIAM J. Sci. Stat. Comput. 10,
Packit 67cb25
   (1989), pp. 1038-1051.
Packit 67cb25
Packit 67cb25
   Hindmarsh, A. C., Brown, P. N., Grant, K. E., Lee, S. L., Serban,
Packit 67cb25
   R., Shumaker, D. E., and Woodward, C. S., SUNDIALS: Suite of
Packit 67cb25
   Nonlinear and Differential/Algebraic Equation Solvers, ACM
Packit 67cb25
   Trans. Math. Software 31 (2005), pp. 363-396.
Packit 67cb25
Packit 67cb25
   Note: The algorithms have been adapted for GSL ode-initval2
Packit 67cb25
   framework.
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
#include <config.h>
Packit 67cb25
#include <stdlib.h>
Packit 67cb25
#include <string.h>
Packit 67cb25
#include <gsl/gsl_math.h>
Packit 67cb25
#include <gsl/gsl_errno.h>
Packit 67cb25
#include <gsl/gsl_odeiv2.h>
Packit 67cb25
#include <gsl/gsl_blas.h>
Packit 67cb25
Packit 67cb25
#include "odeiv_util.h"
Packit 67cb25
Packit 67cb25
/* Maximum order of Adams methods */
Packit 67cb25
#define MSADAMS_MAX_ORD 12
Packit 67cb25
Packit 67cb25
typedef struct
Packit 67cb25
{
Packit 67cb25
  /* Nordsieck history matrix. Includes concatenated
Packit 67cb25
     Nordsieck vectors [y_n, h*y_n', (h^2/2!)*y_n'', ...,
Packit 67cb25
     (h^ord/ord!)*d^(ord)(y_n)]. Nordsieck vector number i is located
Packit 67cb25
     at z[i*dim] (i=0..ord).
Packit 67cb25
   */
Packit 67cb25
  double *z;
Packit 67cb25
Packit 67cb25
  double *zbackup;              /* backup of Nordsieck matrix */
Packit 67cb25
  double *ytmp;                 /* work area */
Packit 67cb25
  double *ytmp2;                /* work area */
Packit 67cb25
  double *pc;                   /* product term coefficients */
Packit 67cb25
  double *l;                    /* polynomial coefficients */
Packit 67cb25
  double *hprev;                /* previous step sizes */
Packit 67cb25
  double *hprevbackup;          /* backup of hprev */
Packit 67cb25
  double *errlev;               /* desired error level of y */
Packit 67cb25
  gsl_vector *abscor;           /* absolute y values for correction */
Packit 67cb25
  gsl_vector *relcor;           /* relative y values for correction */
Packit 67cb25
  gsl_vector *svec;             /* saved abscor & work area */
Packit 67cb25
  gsl_vector *tempvec;          /* work area */
Packit 67cb25
  const gsl_odeiv2_driver *driver;      /* pointer to gsl_odeiv2_driver object */
Packit 67cb25
Packit 67cb25
  long int ni;                  /* stepper call counter */
Packit 67cb25
  size_t ord;                   /* current order of method */
Packit 67cb25
  size_t ordprev;               /* order of previous call */
Packit 67cb25
  size_t ordprevbackup;         /* backup of ordprev */
Packit 67cb25
  double tprev;                 /* t point of previous call */
Packit 67cb25
  size_t ordwait;               /* counter for order change */
Packit 67cb25
  size_t ordwaitbackup;         /* backup of ordwait */
Packit 67cb25
  size_t failord;               /* order of convergence failure */
Packit 67cb25
  double failt;                 /* t point of convergence failure */
Packit 67cb25
  double ordm1coeff;            /* saved order-1 coefficiet */
Packit 67cb25
  double ordp1coeffprev;        /* saved order+1 coefficient */
Packit 67cb25
  size_t failcount;             /* counter for rejected steps */
Packit 67cb25
}
Packit 67cb25
msadams_state_t;
Packit 67cb25
Packit 67cb25
/* Introduce msadams_reset for use in msadams_alloc and _apply */
Packit 67cb25
Packit 67cb25
static int msadams_reset (void *, size_t);
Packit 67cb25
Packit 67cb25
static void *
Packit 67cb25
msadams_alloc (size_t dim)
Packit 67cb25
{
Packit 67cb25
  msadams_state_t *state =
Packit 67cb25
    (msadams_state_t *) malloc (sizeof (msadams_state_t));
Packit 67cb25
Packit 67cb25
  if (state == 0)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for msadams_state",
Packit 67cb25
                      GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->z =
Packit 67cb25
    (double *) malloc ((MSADAMS_MAX_ORD + 1) * dim * sizeof (double));
Packit 67cb25
Packit 67cb25
  if (state->z == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for z", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->zbackup =
Packit 67cb25
    (double *) malloc ((MSADAMS_MAX_ORD + 1) * dim * sizeof (double));
Packit 67cb25
Packit 67cb25
  if (state->zbackup == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state->z);
Packit 67cb25
      free (state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for zbackup", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->ytmp = (double *) malloc (dim * sizeof (double));
Packit 67cb25
Packit 67cb25
  if (state->ytmp == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state->zbackup);
Packit 67cb25
      free (state->z);
Packit 67cb25
      free (state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for ytmp", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->ytmp2 = (double *) malloc (dim * sizeof (double));
Packit 67cb25
Packit 67cb25
  if (state->ytmp2 == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state->ytmp);
Packit 67cb25
      free (state->zbackup);
Packit 67cb25
      free (state->z);
Packit 67cb25
      free (state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for ytmp2", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->pc = (double *) malloc ((MSADAMS_MAX_ORD + 1) * sizeof (double));
Packit 67cb25
Packit 67cb25
  if (state->pc == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state->ytmp2);
Packit 67cb25
      free (state->ytmp);
Packit 67cb25
      free (state->zbackup);
Packit 67cb25
      free (state->z);
Packit 67cb25
      free (state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for pc", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->l = (double *) malloc ((MSADAMS_MAX_ORD + 1) * sizeof (double));
Packit 67cb25
Packit 67cb25
  if (state->l == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state->pc);
Packit 67cb25
      free (state->ytmp);
Packit 67cb25
      free (state->zbackup);
Packit 67cb25
      free (state->z);
Packit 67cb25
      free (state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for l", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->hprev = (double *) malloc (MSADAMS_MAX_ORD * sizeof (double));
Packit 67cb25
Packit 67cb25
  if (state->hprev == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state->l);
Packit 67cb25
      free (state->pc);
Packit 67cb25
      free (state->ytmp2);
Packit 67cb25
      free (state->ytmp);
Packit 67cb25
      free (state->zbackup);
Packit 67cb25
      free (state->z);
Packit 67cb25
      free (state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for hprev", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->hprevbackup = (double *) malloc (MSADAMS_MAX_ORD * sizeof (double));
Packit 67cb25
Packit 67cb25
  if (state->hprevbackup == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
Packit 67cb25
      free (state->pc);
Packit 67cb25
      free (state->ytmp2);
Packit 67cb25
      free (state->ytmp);
Packit 67cb25
      free (state->zbackup);
Packit 67cb25
      free (state->z);
Packit 67cb25
      free (state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for hprevbackup", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->errlev = (double *) malloc (dim * sizeof (double));
Packit 67cb25
Packit 67cb25
  if (state->errlev == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
Packit 67cb25
      free (state->pc);
Packit 67cb25
      free (state->ytmp2);
Packit 67cb25
      free (state->ytmp);
Packit 67cb25
      free (state->zbackup);
Packit 67cb25
      free (state->z);
Packit 67cb25
      free (state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for errlev", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->abscor = gsl_vector_alloc (dim);
Packit 67cb25
Packit 67cb25
  if (state->abscor == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state->errlev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
Packit 67cb25
      free (state->pc);
Packit 67cb25
      free (state->ytmp2);
Packit 67cb25
      free (state->ytmp);
Packit 67cb25
      free (state->zbackup);
Packit 67cb25
      free (state->z);
Packit 67cb25
      free (state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for abscor", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->relcor = gsl_vector_alloc (dim);
Packit 67cb25
Packit 67cb25
  if (state->relcor == 0)
Packit 67cb25
    {
Packit 67cb25
      gsl_vector_free (state->abscor);
Packit 67cb25
      free (state->errlev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
Packit 67cb25
      free (state->pc);
Packit 67cb25
      free (state->ytmp2);
Packit 67cb25
      free (state->ytmp);
Packit 67cb25
      free (state->zbackup);
Packit 67cb25
      free (state->z);
Packit 67cb25
      free (state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for relcor", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->svec = gsl_vector_alloc (dim);
Packit 67cb25
Packit 67cb25
  if (state->svec == 0)
Packit 67cb25
    {
Packit 67cb25
      gsl_vector_free (state->relcor);
Packit 67cb25
      gsl_vector_free (state->abscor);
Packit 67cb25
      free (state->errlev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
Packit 67cb25
      free (state->pc);
Packit 67cb25
      free (state->ytmp2);
Packit 67cb25
      free (state->ytmp);
Packit 67cb25
      free (state->zbackup);
Packit 67cb25
      free (state->z);
Packit 67cb25
      free (state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for svec", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->tempvec = gsl_vector_alloc (dim);
Packit 67cb25
Packit 67cb25
  if (state->tempvec == 0)
Packit 67cb25
    {
Packit 67cb25
      gsl_vector_free (state->svec);
Packit 67cb25
      gsl_vector_free (state->relcor);
Packit 67cb25
      gsl_vector_free (state->abscor);
Packit 67cb25
      free (state->errlev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
Packit 67cb25
      free (state->pc);
Packit 67cb25
      free (state->ytmp2);
Packit 67cb25
      free (state->ytmp);
Packit 67cb25
      free (state->zbackup);
Packit 67cb25
      free (state->z);
Packit 67cb25
      free (state);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for tempvec", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  msadams_reset ((void *) state, dim);
Packit 67cb25
Packit 67cb25
  state->driver = NULL;
Packit 67cb25
Packit 67cb25
  return state;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
msadams_failurehandler (void *vstate, const size_t dim, const double t)
Packit 67cb25
{
Packit 67cb25
  /* Internal failure handler routine for msadams. Adjusted strategy
Packit 67cb25
     for GSL: Decrease order if this is the second time a failure
Packit 67cb25
     has occurred at this order and point.
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  msadams_state_t *state = (msadams_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  const size_t ord = state->ord;
Packit 67cb25
Packit 67cb25
  if (ord > 1 && (ord - state->ordprev == 0) &&
Packit 67cb25
      ord == state->failord && t == state->failt)
Packit 67cb25
    {
Packit 67cb25
      state->ord--;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Save information about failure */
Packit 67cb25
Packit 67cb25
  state->failord = ord;
Packit 67cb25
  state->failt = t;
Packit 67cb25
  state->ni++;
Packit 67cb25
Packit 67cb25
  /* Force reinitialization if failure took place at lowest
Packit 67cb25
     order 
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  if (ord == 1)
Packit 67cb25
    {
Packit 67cb25
      msadams_reset (vstate, dim);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
msadams_calccoeffs (const size_t ord, const size_t ordwait,
Packit 67cb25
                    const double h, const double hprev[],
Packit 67cb25
                    double pc[], double l[],
Packit 67cb25
                    double *errcoeff, double *ordm1coeff,
Packit 67cb25
                    double *ordp1coeff, double *ordp2coeff)
Packit 67cb25
{
Packit 67cb25
Packit 67cb25
  /* Calculates coefficients (l) of polynomial Lambda, error and
Packit 67cb25
     auxiliary order change evaluation coefficients.
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  if (ord == 1)
Packit 67cb25
    {
Packit 67cb25
      l[0] = 1.0;
Packit 67cb25
      l[1] = 1.0;
Packit 67cb25
      *errcoeff = 0.5;
Packit 67cb25
      *ordp1coeff = 1.0;
Packit 67cb25
      *ordp2coeff = 12.0;
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      size_t i, j;
Packit 67cb25
      double hsum = h;
Packit 67cb25
      double st1 = 0.0;         /* sum term coefficients */
Packit 67cb25
      double st2 = 0.0;
Packit 67cb25
Packit 67cb25
      /* Calculate coefficients (pc) of product terms */
Packit 67cb25
Packit 67cb25
      DBL_ZERO_MEMSET (pc, MSADAMS_MAX_ORD + 1);
Packit 67cb25
Packit 67cb25
      pc[0] = 1.0;
Packit 67cb25
Packit 67cb25
      for (i = 1; i < ord; i++)
Packit 67cb25
        {
Packit 67cb25
          /* Calculate auxiliary coefficient used in evaluation of
Packit 67cb25
             change of order
Packit 67cb25
           */
Packit 67cb25
Packit 67cb25
          if (i == ord - 1 && ordwait == 1)
Packit 67cb25
            {
Packit 67cb25
              int s = 1;
Packit 67cb25
Packit 67cb25
              *ordm1coeff = 0.0;
Packit 67cb25
Packit 67cb25
              for (j = 0; j < ord - 1; j++)
Packit 67cb25
                {
Packit 67cb25
                  *ordm1coeff += s * pc[j] / (j + 2);
Packit 67cb25
                  s = -s;
Packit 67cb25
                }
Packit 67cb25
Packit 67cb25
              *ordm1coeff = pc[ord - 2] / (ord * (*ordm1coeff));
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          for (j = i; j > 0; j--)
Packit 67cb25
            {
Packit 67cb25
              pc[j] += pc[j - 1] * h / hsum;
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          hsum += hprev[i - 1];
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* Calculate sum term 1 for error estimation */
Packit 67cb25
Packit 67cb25
      {
Packit 67cb25
        int s = 1;
Packit 67cb25
Packit 67cb25
        for (i = 0; i < ord; i++)
Packit 67cb25
          {
Packit 67cb25
            st1 += s * pc[i] / (i + 1.0);
Packit 67cb25
            s = -s;
Packit 67cb25
          }
Packit 67cb25
      }
Packit 67cb25
Packit 67cb25
      /* Calculate sum term 2 for error estimation */
Packit 67cb25
Packit 67cb25
      {
Packit 67cb25
        int s = 1;
Packit 67cb25
Packit 67cb25
        for (i = 0; i < ord; i++)
Packit 67cb25
          {
Packit 67cb25
            st2 += s * pc[i] / (i + 2.0);
Packit 67cb25
            s = -s;
Packit 67cb25
          }
Packit 67cb25
      }
Packit 67cb25
Packit 67cb25
      /* Calculate the actual polynomial coefficients (l) */
Packit 67cb25
Packit 67cb25
      DBL_ZERO_MEMSET (l, MSADAMS_MAX_ORD + 1);
Packit 67cb25
Packit 67cb25
      l[0] = 1.0;
Packit 67cb25
Packit 67cb25
      for (i = 1; i < ord + 1; i++)
Packit 67cb25
        {
Packit 67cb25
          l[i] = pc[i - 1] / (i * st1);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
      {
Packit 67cb25
        size_t di;
Packit 67cb25
Packit 67cb25
        printf ("-- calccoeffs l: ");
Packit 67cb25
        for (di = 0; di < ord + 1; di++)
Packit 67cb25
          {
Packit 67cb25
            printf ("%.5e ", l[di]);
Packit 67cb25
          }
Packit 67cb25
        printf ("\n");
Packit 67cb25
Packit 67cb25
        printf ("-- calccoeffs pc: ");
Packit 67cb25
        for (di = 0; di < ord; di++)
Packit 67cb25
          {
Packit 67cb25
            printf ("%.5e ", pc[di]);
Packit 67cb25
          }
Packit 67cb25
        printf ("\n");
Packit 67cb25
Packit 67cb25
        printf ("-- calccoeffs st1=%.5e, st2=%.5e\n", st1, st2);
Packit 67cb25
      }
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
      /* Calculate error coefficient */
Packit 67cb25
Packit 67cb25
      *errcoeff = (h / hsum) * (st2 / st1);
Packit 67cb25
Packit 67cb25
      /* Calculate auxiliary coefficients used in evaluation of change
Packit 67cb25
         of order
Packit 67cb25
       */
Packit 67cb25
Packit 67cb25
      if (ordwait < 2)
Packit 67cb25
        {
Packit 67cb25
          int s = 1;
Packit 67cb25
Packit 67cb25
          *ordp1coeff = hsum / (h * l[ord]);
Packit 67cb25
Packit 67cb25
          *ordp2coeff = 0.0;
Packit 67cb25
Packit 67cb25
          for (i = ord; i > 0; i--)
Packit 67cb25
            {
Packit 67cb25
              pc[i] += pc[i - 1] * (h / hsum);
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          for (i = 0; i < ord + 1; i++)
Packit 67cb25
            {
Packit 67cb25
              *ordp2coeff += s * pc[i] / (i + 2);
Packit 67cb25
              s = -s;
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          *ordp2coeff = (ord + 1) * st1 / (*ordp2coeff);
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
  printf ("-- calccoeffs ordm1coeff=%.5e ", *ordm1coeff);
Packit 67cb25
  printf ("ordp1coeff=%.5e ", *ordp1coeff);
Packit 67cb25
  printf ("ordp2coeff=%.5e ", *ordp2coeff);
Packit 67cb25
  printf ("errcoeff=%.5e\n", *errcoeff);
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
msadams_corrector (void *vstate, const gsl_odeiv2_system * sys,
Packit 67cb25
                   const double t, const double h, const size_t dim,
Packit 67cb25
                   const double z[], const double errlev[],
Packit 67cb25
                   const double l[], const double errcoeff,
Packit 67cb25
                   gsl_vector * abscor, gsl_vector * relcor,
Packit 67cb25
                   double ytmp[], double ytmp2[])
Packit 67cb25
{
Packit 67cb25
  /* Calculates the correction step (abscor). Non-linear equation
Packit 67cb25
     system is solved by functional iteration.
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  size_t mi, i;
Packit 67cb25
  const size_t max_iter = 3;    /* Maximum number of iterations */
Packit 67cb25
  double convrate = 1.0;        /* convergence rate */
Packit 67cb25
  double stepnorm = 0.0;        /* norm of correction step */
Packit 67cb25
  double stepnormprev = 0.0;
Packit 67cb25
Packit 67cb25
  /* Evaluate at predicted values */
Packit 67cb25
Packit 67cb25
  {
Packit 67cb25
    int s = GSL_ODEIV_FN_EVAL (sys, t + h, z, ytmp);
Packit 67cb25
Packit 67cb25
    if (s == GSL_EBADFUNC)
Packit 67cb25
      {
Packit 67cb25
        return s;
Packit 67cb25
      }
Packit 67cb25
Packit 67cb25
    if (s != GSL_SUCCESS)
Packit 67cb25
      {
Packit 67cb25
        msadams_failurehandler (vstate, dim, t);
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
        printf ("-- FAIL at user function evaluation\n");
Packit 67cb25
#endif
Packit 67cb25
        return s;
Packit 67cb25
      }
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  /* Calculate correction step (abscor) */
Packit 67cb25
Packit 67cb25
  gsl_vector_set_zero (abscor);
Packit 67cb25
Packit 67cb25
  for (mi = 0; mi < max_iter; mi++)
Packit 67cb25
    {
Packit 67cb25
      const double safety = 0.3;
Packit 67cb25
      const double safety2 = 0.1;
Packit 67cb25
Packit 67cb25
      /* Calculate new y values to ytmp2 */
Packit 67cb25
Packit 67cb25
      for (i = 0; i < dim; i++)
Packit 67cb25
        {
Packit 67cb25
          ytmp[i] *= h;
Packit 67cb25
          ytmp[i] -= z[1 * dim + i];
Packit 67cb25
          ytmp[i] /= l[1];
Packit 67cb25
          ytmp2[i] = z[0 * dim + i] + ytmp[i];
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
      {
Packit 67cb25
        size_t di;
Packit 67cb25
        printf ("-- dstep: ");
Packit 67cb25
        for (di = 0; di < dim; di++)
Packit 67cb25
          {
Packit 67cb25
            printf ("%.5e ", ytmp[di]);
Packit 67cb25
          }
Packit 67cb25
        printf ("\n");
Packit 67cb25
      }
Packit 67cb25
#endif
Packit 67cb25
      /* Convergence test. Norms used are root-mean-square norms. */
Packit 67cb25
Packit 67cb25
      for (i = 0; i < dim; i++)
Packit 67cb25
        {
Packit 67cb25
          gsl_vector_set (relcor, i,
Packit 67cb25
                          (ytmp[i] - gsl_vector_get (abscor, i)) / errlev[i]);
Packit 67cb25
          gsl_vector_set (abscor, i, ytmp[i]);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      stepnorm = gsl_blas_dnrm2 (relcor) / sqrt (dim);
Packit 67cb25
Packit 67cb25
      if (mi > 0)
Packit 67cb25
        {
Packit 67cb25
          convrate = GSL_MAX_DBL (safety * convrate, stepnorm / stepnormprev);
Packit 67cb25
        }
Packit 67cb25
      else
Packit 67cb25
        {
Packit 67cb25
          convrate = 1.0;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      {
Packit 67cb25
        const double convtest =
Packit 67cb25
          GSL_MIN_DBL (convrate, 1.0) * stepnorm * errcoeff / safety2;
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
        printf
Packit 67cb25
          ("-- func iter loop %d, errcoeff=%.5e, stepnorm =%.5e, convrate = %.5e, convtest = %.5e\n",
Packit 67cb25
           (int) mi, errcoeff, stepnorm, convrate, convtest);
Packit 67cb25
#endif
Packit 67cb25
        if (convtest <= 1.0)
Packit 67cb25
          {
Packit 67cb25
            break;
Packit 67cb25
          }
Packit 67cb25
      }
Packit 67cb25
Packit 67cb25
      /* Check for divergence during iteration */
Packit 67cb25
      {
Packit 67cb25
        const double div_const = 2.0;
Packit 67cb25
        
Packit 67cb25
        if (mi > 1 && stepnorm > div_const * stepnormprev)
Packit 67cb25
          {
Packit 67cb25
            msadams_failurehandler (vstate, dim, t);
Packit 67cb25
            
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
            printf ("-- FAIL, diverging functional iteration\n");
Packit 67cb25
#endif
Packit 67cb25
            return GSL_FAILURE;
Packit 67cb25
          }
Packit 67cb25
      }
Packit 67cb25
Packit 67cb25
      /* Evaluate at new y */
Packit 67cb25
Packit 67cb25
      {
Packit 67cb25
        int s = GSL_ODEIV_FN_EVAL (sys, t + h, ytmp2, ytmp);
Packit 67cb25
Packit 67cb25
        if (s == GSL_EBADFUNC)
Packit 67cb25
          {
Packit 67cb25
            return s;
Packit 67cb25
          }
Packit 67cb25
Packit 67cb25
        if (s != GSL_SUCCESS)
Packit 67cb25
          {
Packit 67cb25
            msadams_failurehandler (vstate, dim, t);
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
            printf ("-- FAIL at user function evaluation\n");
Packit 67cb25
#endif
Packit 67cb25
            return s;
Packit 67cb25
          }
Packit 67cb25
      }
Packit 67cb25
Packit 67cb25
      stepnormprev = stepnorm;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
  printf ("-- functional iteration exit at mi=%d\n", (int) mi);
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
  /* Handle convergence failure */
Packit 67cb25
Packit 67cb25
  if (mi == max_iter)
Packit 67cb25
    {
Packit 67cb25
      msadams_failurehandler (vstate, dim, t);
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
      printf ("-- FAIL, max_iter reached\n");
Packit 67cb25
#endif
Packit 67cb25
      return GSL_FAILURE;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
msadams_eval_order (gsl_vector * abscor, gsl_vector * tempvec,
Packit 67cb25
                    gsl_vector * svec, const double errcoeff,
Packit 67cb25
                    const size_t dim, const double errlev[],
Packit 67cb25
                    const double ordm1coeff, const double ordp1coeff,
Packit 67cb25
                    const double ordp1coeffprev, const double ordp2coeff,
Packit 67cb25
                    const double hprev[],
Packit 67cb25
                    const double h, const double z[],
Packit 67cb25
                    size_t * ord, size_t * ordwait)
Packit 67cb25
{
Packit 67cb25
  /* Evaluates and executes change in method order (current, current-1
Packit 67cb25
     or current+1). Order which maximizes the step length is selected.
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  size_t i;
Packit 67cb25
Packit 67cb25
  /* step size estimates at current order, order-1 and order+1 */
Packit 67cb25
  double ordest = 0.0;
Packit 67cb25
  double ordm1est = 0.0;
Packit 67cb25
  double ordp1est = 0.0;
Packit 67cb25
Packit 67cb25
  const double safety = 1e-6;
Packit 67cb25
  const double bias = 6.0;
Packit 67cb25
  const double bias2 = 10.0;
Packit 67cb25
Packit 67cb25
  /* Relative step length estimate for current order */
Packit 67cb25
Packit 67cb25
  ordest = 1.0 / (pow (bias * gsl_blas_dnrm2 (abscor) / sqrt (dim)
Packit 67cb25
                       * errcoeff, 1.0 / (*ord + 1)) + safety);
Packit 67cb25
Packit 67cb25
  /* Relative step length estimate for order ord - 1 */
Packit 67cb25
Packit 67cb25
  if (*ord > 1)
Packit 67cb25
    {
Packit 67cb25
      for (i = 0; i < dim; i++)
Packit 67cb25
        {
Packit 67cb25
          gsl_vector_set (tempvec, i, z[*ord * dim + i] / errlev[i]);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      ordm1est = 1.0 / (pow (bias * gsl_blas_dnrm2 (tempvec) / sqrt (dim)
Packit 67cb25
                             / ordm1coeff, 1.0 / (*ord)) + safety);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      ordm1est = 0.0;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Relative step length estimate for order ord + 1 */
Packit 67cb25
Packit 67cb25
  if (*ord < MSADAMS_MAX_ORD)
Packit 67cb25
    {
Packit 67cb25
      const double c = -ordp1coeff / ordp1coeffprev *
Packit 67cb25
        pow (h / hprev[1], *ord + 1);
Packit 67cb25
Packit 67cb25
      for (i = 0; i < dim; i++)
Packit 67cb25
        {
Packit 67cb25
          gsl_vector_set (svec, i, gsl_vector_get (svec, i) * c +
Packit 67cb25
                          gsl_vector_get (abscor, i));
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      ordp1est = 1.0 / (pow (bias2 * gsl_blas_dnrm2 (svec) / sqrt (dim)
Packit 67cb25
                             / ordp2coeff, 1.0 / (*ord + 2)) + safety);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      ordp1est = 0.0;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
  printf
Packit 67cb25
    ("-- eval_order ord=%d, ordest=%.5e, ordm1est=%.5e, ordp1est=%.5e\n",
Packit 67cb25
     (int) *ord, ordest, ordm1est, ordp1est);
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
  /* Choose order that maximises step size and increases step
Packit 67cb25
     size markedly compared to current step 
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  {
Packit 67cb25
    const double min_incr = 1.5;
Packit 67cb25
Packit 67cb25
    if (ordm1est > ordest && ordm1est > ordp1est && ordm1est > min_incr)
Packit 67cb25
      {
Packit 67cb25
        *ord -= 1;
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
        printf ("-- eval_order order DECREASED to %d\n", (int) *ord);
Packit 67cb25
#endif
Packit 67cb25
      }
Packit 67cb25
    
Packit 67cb25
    else if (ordp1est > ordest && ordp1est > ordm1est && ordp1est > min_incr)
Packit 67cb25
      {
Packit 67cb25
        *ord += 1;
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
        printf ("-- eval_order order INCREASED to %d\n", (int) *ord);
Packit 67cb25
#endif
Packit 67cb25
      }
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  *ordwait = *ord + 2;
Packit 67cb25
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
msadams_apply (void *vstate, size_t dim, double t, double h,
Packit 67cb25
               double y[], double yerr[],
Packit 67cb25
               const double dydt_in[], double dydt_out[],
Packit 67cb25
               const gsl_odeiv2_system * sys)
Packit 67cb25
{
Packit 67cb25
  /* Conducts a step by Adams linear multistep methods. */
Packit 67cb25
Packit 67cb25
  msadams_state_t *state = (msadams_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  double *const z = state->z;
Packit 67cb25
  double *const zbackup = state->zbackup;
Packit 67cb25
  double *const ytmp = state->ytmp;
Packit 67cb25
  double *const ytmp2 = state->ytmp2;
Packit 67cb25
  double *const pc = state->pc;
Packit 67cb25
  double *const l = state->l;
Packit 67cb25
  double *const hprev = state->hprev;
Packit 67cb25
  double *const hprevbackup = state->hprevbackup;
Packit 67cb25
  double *const errlev = state->errlev;
Packit 67cb25
  gsl_vector *const abscor = state->abscor;
Packit 67cb25
  gsl_vector *const relcor = state->relcor;
Packit 67cb25
  gsl_vector *const svec = state->svec;
Packit 67cb25
  gsl_vector *const tempvec = state->tempvec;
Packit 67cb25
Packit 67cb25
  size_t ord = state->ord;
Packit 67cb25
  double ordm1coeff = 0.0;
Packit 67cb25
  double ordp1coeff = 0.0;
Packit 67cb25
  double ordp2coeff = 0.0;
Packit 67cb25
  double errcoeff = 0.0;        /* error coefficient */
Packit 67cb25
Packit 67cb25
  int deltaord;
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
  {
Packit 67cb25
    size_t di;
Packit 67cb25
Packit 67cb25
    printf ("msadams_apply: t=%.5e, ord=%d, h=%.5e, y:", t, (int) ord, h);
Packit 67cb25
Packit 67cb25
    for (di = 0; di < dim; di++)
Packit 67cb25
      {
Packit 67cb25
        printf ("%.5e ", y[di]);
Packit 67cb25
      }
Packit 67cb25
    printf ("\n");
Packit 67cb25
  }
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
  /* Check if t is the same as on previous stepper call (or last
Packit 67cb25
     failed call). This means that calculation of previous step failed
Packit 67cb25
     or the step was rejected, and therefore previous state will be
Packit 67cb25
     restored or the method will be reset.
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  if (state->ni > 0 && (t == state->tprev || t == state->failt))
Packit 67cb25
    {
Packit 67cb25
      if (state->ni == 1)
Packit 67cb25
        {
Packit 67cb25
          /* No step has been accepted yet, reset method */
Packit 67cb25
Packit 67cb25
          msadams_reset (vstate, dim);
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
          printf ("-- first step was REJECTED, msadams_reset called\n");
Packit 67cb25
#endif
Packit 67cb25
        }
Packit 67cb25
      else
Packit 67cb25
        {
Packit 67cb25
          /* A succesful step has been saved, restore previous state. */
Packit 67cb25
Packit 67cb25
          /* If previous step suggests order increase, but the step was
Packit 67cb25
             rejected, then do not increase order.
Packit 67cb25
           */
Packit 67cb25
Packit 67cb25
          if (ord > state->ordprev)
Packit 67cb25
            {
Packit 67cb25
              state->ord = state->ordprev;
Packit 67cb25
              ord = state->ord;
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          /* Restore previous state */
Packit 67cb25
Packit 67cb25
          DBL_MEMCPY (z, zbackup, (MSADAMS_MAX_ORD + 1) * dim);
Packit 67cb25
          DBL_MEMCPY (hprev, hprevbackup, MSADAMS_MAX_ORD);
Packit 67cb25
          state->ordprev = state->ordprevbackup;
Packit 67cb25
          state->ordwait = state->ordwaitbackup;
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
          printf ("-- previous step was REJECTED, state restored\n");
Packit 67cb25
#endif
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      state->failcount++;
Packit 67cb25
Packit 67cb25
      {
Packit 67cb25
        const size_t max_failcount = 3;
Packit 67cb25
        
Packit 67cb25
        /* If step is repeatedly rejected, then reset method */
Packit 67cb25
Packit 67cb25
        if (state->failcount > max_failcount && state->ni > 1)
Packit 67cb25
          {
Packit 67cb25
            msadams_reset (vstate, dim);
Packit 67cb25
            ord = state->ord;
Packit 67cb25
            
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
            printf ("-- max_failcount reached, msadams_reset called\n");
Packit 67cb25
#endif
Packit 67cb25
          }
Packit 67cb25
Packit 67cb25
        /* Attempt to decrease order twice is indicative of system stiffness.
Packit 67cb25
           Reset method to enable fast recovery. */
Packit 67cb25
Packit 67cb25
        else if ((int)state->ordprev - (int)ord >= 2)
Packit 67cb25
          {
Packit 67cb25
            msadams_reset (vstate, dim);
Packit 67cb25
            ord = state->ord;
Packit 67cb25
          
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
            printf ("-- order decreased by two, msadams_reset called\n");
Packit 67cb25
#endif
Packit 67cb25
          } 
Packit 67cb25
      }
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      /* The previous step was accepted. Backup current state. */
Packit 67cb25
Packit 67cb25
      DBL_MEMCPY (zbackup, z, (MSADAMS_MAX_ORD + 1) * dim);
Packit 67cb25
      DBL_MEMCPY (hprevbackup, hprev, MSADAMS_MAX_ORD);
Packit 67cb25
      state->ordprevbackup = state->ordprev;
Packit 67cb25
      state->ordwaitbackup = state->ordwait;
Packit 67cb25
Packit 67cb25
      state->failcount = 0;
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
      if (state->ni > 0)
Packit 67cb25
        {
Packit 67cb25
          printf ("-- previous step was ACCEPTED, state saved\n");
Packit 67cb25
        }
Packit 67cb25
#endif
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
  printf ("-- ord=%d, ni=%ld, ordwait=%d\n", (int) ord, state->ni,
Packit 67cb25
          (int) state->ordwait);
Packit 67cb25
  printf ("-- ordprev: %d\n", (int) state->ordprev);
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
  /* Get desired error levels via gsl_odeiv2_control object through driver
Packit 67cb25
     object, which is a requirement for this stepper.
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  if (state->driver == NULL)
Packit 67cb25
    {
Packit 67cb25
      return GSL_EFAULT;
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      size_t i;
Packit 67cb25
Packit 67cb25
      for (i = 0; i < dim; i++)
Packit 67cb25
        {
Packit 67cb25
          if (dydt_in != NULL)
Packit 67cb25
            {
Packit 67cb25
              gsl_odeiv2_control_errlevel (state->driver->c, y[i],
Packit 67cb25
                                           dydt_in[i], h, i, &errlev[i]);
Packit 67cb25
            }
Packit 67cb25
          else
Packit 67cb25
            {
Packit 67cb25
              gsl_odeiv2_control_errlevel (state->driver->c, y[i],
Packit 67cb25
                                           0.0, h, i, &errlev[i]);
Packit 67cb25
            }
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
  {
Packit 67cb25
    size_t di;
Packit 67cb25
    printf ("-- errlev: ");
Packit 67cb25
    for (di = 0; di < dim; di++)
Packit 67cb25
      {
Packit 67cb25
        printf ("%.5e ", errlev[di]);
Packit 67cb25
      }
Packit 67cb25
    printf ("\n");
Packit 67cb25
  }
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
  /* On first call initialize Nordsieck matrix */
Packit 67cb25
Packit 67cb25
  if (state->ni == 0)
Packit 67cb25
    {
Packit 67cb25
      size_t i;
Packit 67cb25
Packit 67cb25
      DBL_ZERO_MEMSET (z, (MSADAMS_MAX_ORD + 1) * dim);
Packit 67cb25
Packit 67cb25
      if (dydt_in != NULL)
Packit 67cb25
        {
Packit 67cb25
          DBL_MEMCPY (ytmp, dydt_in, dim);
Packit 67cb25
        }
Packit 67cb25
      else
Packit 67cb25
        {
Packit 67cb25
          int s = GSL_ODEIV_FN_EVAL (sys, t, y, ytmp);
Packit 67cb25
Packit 67cb25
          if (s != GSL_SUCCESS)
Packit 67cb25
            {
Packit 67cb25
              return s;
Packit 67cb25
            }
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      DBL_MEMCPY (&z[0 * dim], y, dim);
Packit 67cb25
      DBL_MEMCPY (&z[1 * dim], ytmp, dim);
Packit 67cb25
Packit 67cb25
      for (i = 0; i < dim; i++)
Packit 67cb25
        {
Packit 67cb25
          z[1 * dim + i] *= h;
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Sanity check  */
Packit 67cb25
Packit 67cb25
  deltaord = ord - state->ordprev;
Packit 67cb25
Packit 67cb25
  if (deltaord > 1 || deltaord < -1)
Packit 67cb25
    {
Packit 67cb25
      printf ("-- order change %d\n", deltaord);
Packit 67cb25
      GSL_ERROR_NULL ("msadams_apply too large order change", GSL_ESANITY);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Modify Nordsieck matrix if order or step length has been changed */
Packit 67cb25
Packit 67cb25
  /* If order increased by 1, initialize new Nordsieck vector */
Packit 67cb25
Packit 67cb25
  if (deltaord == 1)
Packit 67cb25
    {
Packit 67cb25
      DBL_ZERO_MEMSET (&z[ord * dim], dim);
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
      printf ("-- order increase detected, Nordsieck modified\n");
Packit 67cb25
#endif
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* If order decreased by 1, adjust Nordsieck matrix */
Packit 67cb25
Packit 67cb25
  if (deltaord == -1)
Packit 67cb25
    {
Packit 67cb25
      double hsum = 0.0;
Packit 67cb25
      size_t i, j;
Packit 67cb25
Packit 67cb25
      /* Calculate coefficients used in adjustment to l */
Packit 67cb25
Packit 67cb25
      DBL_ZERO_MEMSET (l, MSADAMS_MAX_ORD + 1);
Packit 67cb25
Packit 67cb25
      l[1] = 1.0;
Packit 67cb25
Packit 67cb25
      for (i = 1; i < ord; i++)
Packit 67cb25
        {
Packit 67cb25
          hsum += hprev[i - 1];
Packit 67cb25
Packit 67cb25
          for (j = i + 1; j > 0; j--)
Packit 67cb25
            {
Packit 67cb25
              l[j] *= hsum / hprev[0];
Packit 67cb25
              l[j] += l[j - 1];
Packit 67cb25
            }
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      for (i = 1; i < ord; i++)
Packit 67cb25
        {
Packit 67cb25
          l[i + 1] = (ord + 1) * l[i] / (i + 1);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* Scale Nordsieck matrix */
Packit 67cb25
Packit 67cb25
      for (i = 2; i < ord + 1; i++)
Packit 67cb25
        for (j = 0; j < dim; j++)
Packit 67cb25
          {
Packit 67cb25
            z[i * dim + j] += -l[i] * z[(ord + 1) * dim + j];
Packit 67cb25
          }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
      printf ("-- order decrease detected, Nordsieck modified\n");
Packit 67cb25
#endif
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Scale Nordsieck vectors if step size has been changed */
Packit 67cb25
Packit 67cb25
  if (state->ni > 0 && h != hprev[0])
Packit 67cb25
    {
Packit 67cb25
      size_t i, j;
Packit 67cb25
      const double hrel = h / hprev[0];
Packit 67cb25
      double coeff = hrel;
Packit 67cb25
Packit 67cb25
      for (i = 1; i < ord + 1; i++)
Packit 67cb25
        {
Packit 67cb25
          for (j = 0; j < dim; j++)
Packit 67cb25
            {
Packit 67cb25
              z[i * dim + j] *= coeff;
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          coeff *= hrel;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
      printf ("-- h != hprev, Nordsieck modified\n");
Packit 67cb25
#endif
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Calculate polynomial coefficients (l), error coefficient and
Packit 67cb25
     auxiliary coefficients
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  msadams_calccoeffs (ord, state->ordwait, h, hprev, pc, l, &errcoeff,
Packit 67cb25
                      &ordm1coeff, &ordp1coeff, &ordp2coeff);
Packit 67cb25
Packit 67cb25
  /* Carry out the prediction step */
Packit 67cb25
Packit 67cb25
  {
Packit 67cb25
    size_t i, j, k;
Packit 67cb25
Packit 67cb25
    for (i = 1; i < ord + 1; i++)
Packit 67cb25
      for (j = ord; j > i - 1; j--)
Packit 67cb25
        for (k = 0; k < dim; k++)
Packit 67cb25
          {
Packit 67cb25
            z[(j - 1) * dim + k] += z[j * dim + k];
Packit 67cb25
          }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
    {
Packit 67cb25
      size_t di;
Packit 67cb25
      printf ("-- predicted y: ");
Packit 67cb25
      for (di = 0; di < dim; di++)
Packit 67cb25
        {
Packit 67cb25
          printf ("%.5e ", z[di]);
Packit 67cb25
        }
Packit 67cb25
      printf ("\n");
Packit 67cb25
    }
Packit 67cb25
#endif
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  /* Calculate correction step to abscor */
Packit 67cb25
  {
Packit 67cb25
    int s;
Packit 67cb25
    s = msadams_corrector (vstate, sys, t, h, dim, z, errlev, l, errcoeff,
Packit 67cb25
                           abscor, relcor, ytmp, ytmp2);
Packit 67cb25
    if (s != GSL_SUCCESS)
Packit 67cb25
      {
Packit 67cb25
        return s;
Packit 67cb25
      }
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  {
Packit 67cb25
    /* Add accepted final correction step to Nordsieck matrix */
Packit 67cb25
Packit 67cb25
    size_t i, j;
Packit 67cb25
Packit 67cb25
    for (i = 0; i < ord + 1; i++)
Packit 67cb25
      for (j = 0; j < dim; j++)
Packit 67cb25
        {
Packit 67cb25
          z[i * dim + j] += l[i] * gsl_vector_get (abscor, j);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
    {
Packit 67cb25
      size_t di;
Packit 67cb25
      printf ("-- corrected y: ");
Packit 67cb25
      for (di = 0; di < dim; di++)
Packit 67cb25
        {
Packit 67cb25
          printf ("%.5e ", z[di]);
Packit 67cb25
        }
Packit 67cb25
      printf ("\n");
Packit 67cb25
    }
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
    /* Derivatives at output */
Packit 67cb25
Packit 67cb25
    if (dydt_out != NULL)
Packit 67cb25
      {
Packit 67cb25
        int s = GSL_ODEIV_FN_EVAL (sys, t + h, z, dydt_out);
Packit 67cb25
Packit 67cb25
        if (s == GSL_EBADFUNC)
Packit 67cb25
          {
Packit 67cb25
            return s;
Packit 67cb25
          }
Packit 67cb25
Packit 67cb25
        if (s != GSL_SUCCESS)
Packit 67cb25
          {
Packit 67cb25
            msadams_failurehandler (vstate, dim, t);
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
            printf ("-- FAIL at user function evaluation\n");
Packit 67cb25
#endif
Packit 67cb25
            return s;
Packit 67cb25
          }
Packit 67cb25
      }
Packit 67cb25
Packit 67cb25
    /* Calculate error estimate */
Packit 67cb25
Packit 67cb25
    for (i = 0; i < dim; i++)
Packit 67cb25
      {
Packit 67cb25
        yerr[i] = fabs (gsl_vector_get (abscor, i)) * errcoeff;
Packit 67cb25
      }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
    {
Packit 67cb25
      size_t di;
Packit 67cb25
      printf ("-- yerr: ");
Packit 67cb25
      for (di = 0; di < dim; di++)
Packit 67cb25
        {
Packit 67cb25
          printf ("%.5e ", yerr[di]);
Packit 67cb25
        }
Packit 67cb25
      printf ("\n");
Packit 67cb25
    }
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
    /* Save y values */
Packit 67cb25
Packit 67cb25
    for (i = 0; i < dim; i++)
Packit 67cb25
      {
Packit 67cb25
        y[i] = z[0 * dim + i];
Packit 67cb25
      }
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  /* Scale abscor with errlev for later use in norm calculations */
Packit 67cb25
  {
Packit 67cb25
    size_t i;
Packit 67cb25
Packit 67cb25
    for (i = 0; i < dim; i++)
Packit 67cb25
      {
Packit 67cb25
        gsl_vector_set (abscor, i, gsl_vector_get (abscor, i) / errlev[i]);
Packit 67cb25
      }
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  /* Save items needed for evaluation of order increase on next
Packit 67cb25
     call, if needed
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  if (state->ordwait == 1 && ord < MSADAMS_MAX_ORD)
Packit 67cb25
    {
Packit 67cb25
      size_t i;
Packit 67cb25
Packit 67cb25
      state->ordp1coeffprev = ordp1coeff;
Packit 67cb25
      state->ordm1coeff = ordm1coeff;
Packit 67cb25
Packit 67cb25
      for (i = 0; i < dim; i++)
Packit 67cb25
        {
Packit 67cb25
          gsl_vector_set (svec, i, gsl_vector_get (abscor, i));
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Consider and execute order change for next step */
Packit 67cb25
Packit 67cb25
  if (state->ordwait == 0)
Packit 67cb25
    {
Packit 67cb25
      msadams_eval_order (abscor, tempvec, svec, errcoeff, dim, errlev,
Packit 67cb25
                          state->ordm1coeff, ordp1coeff,
Packit 67cb25
                          state->ordp1coeffprev, ordp2coeff,
Packit 67cb25
                          hprev, h, z, &(state->ord), &(state->ordwait));
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Save information about current step in state and update counters */
Packit 67cb25
  {
Packit 67cb25
    size_t i;
Packit 67cb25
Packit 67cb25
    state->ordprev = ord;
Packit 67cb25
Packit 67cb25
    for (i = MSADAMS_MAX_ORD - 1; i > 0; i--)
Packit 67cb25
      {
Packit 67cb25
        hprev[i] = hprev[i - 1];
Packit 67cb25
      }
Packit 67cb25
    hprev[0] = h;
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
    {
Packit 67cb25
      size_t di;
Packit 67cb25
      printf ("-- hprev: ");
Packit 67cb25
      for (di = 0; di < MSADAMS_MAX_ORD; di++)
Packit 67cb25
        {
Packit 67cb25
          printf ("%.5e ", hprev[di]);
Packit 67cb25
        }
Packit 67cb25
      printf ("\n");
Packit 67cb25
    }
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
    state->tprev = t;
Packit 67cb25
    state->ordwait--;
Packit 67cb25
    state->ni++;
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
msadams_set_driver (void *vstate, const gsl_odeiv2_driver * d)
Packit 67cb25
{
Packit 67cb25
  msadams_state_t *state = (msadams_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  state->driver = d;
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
msadams_reset (void *vstate, size_t dim)
Packit 67cb25
{
Packit 67cb25
  msadams_state_t *state = (msadams_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  state->ni = 0;
Packit 67cb25
  state->ord = 1;
Packit 67cb25
  state->ordprev = 1;
Packit 67cb25
  state->ordprevbackup = 1;
Packit 67cb25
  state->ordwait = 2;
Packit 67cb25
  state->ordwaitbackup = 2;
Packit 67cb25
  state->failord = 0;
Packit 67cb25
  state->failt = GSL_NAN;
Packit 67cb25
  state->failcount = 0;
Packit 67cb25
Packit 67cb25
  DBL_ZERO_MEMSET (state->hprev, MSADAMS_MAX_ORD);
Packit 67cb25
  DBL_ZERO_MEMSET (state->z, (MSADAMS_MAX_ORD + 1) * dim);
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
  printf ("-- msadams_reset called\n");
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static unsigned int
Packit 67cb25
msadams_order (void *vstate)
Packit 67cb25
{
Packit 67cb25
  msadams_state_t *state = (msadams_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  return state->ord;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static void
Packit 67cb25
msadams_free (void *vstate)
Packit 67cb25
{
Packit 67cb25
  msadams_state_t *state = (msadams_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  gsl_vector_free (state->tempvec);
Packit 67cb25
  gsl_vector_free (state->svec);
Packit 67cb25
  gsl_vector_free (state->relcor);
Packit 67cb25
  gsl_vector_free (state->abscor);
Packit 67cb25
  free (state->errlev);
Packit 67cb25
  free (state->hprevbackup);
Packit 67cb25
  free (state->hprev);
Packit 67cb25
  free (state->l);
Packit 67cb25
  free (state->pc);
Packit 67cb25
  free (state->ytmp2);
Packit 67cb25
  free (state->ytmp);
Packit 67cb25
  free (state->zbackup);
Packit 67cb25
  free (state->z);
Packit 67cb25
  free (state);
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static const gsl_odeiv2_step_type msadams_type = {
Packit 67cb25
  "msadams",                    /* name */
Packit 67cb25
  1,                            /* can use dydt_in? */
Packit 67cb25
  1,                            /* gives exact dydt_out? */
Packit 67cb25
  &msadams_alloc,
Packit 67cb25
  &msadams_apply,
Packit 67cb25
  &msadams_set_driver,
Packit 67cb25
  &msadams_reset,
Packit 67cb25
  &msadams_order,
Packit 67cb25
  &msadams_free
Packit 67cb25
};
Packit 67cb25
Packit 67cb25
const gsl_odeiv2_step_type *gsl_odeiv2_step_msadams = &msadams_type;