Blame ode-initval2/msbdf.c

Packit 67cb25
/* ode-initval2/msbdf.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 backward differentiation
Packit 67cb25
   formula (BDF) method in Nordsieck form. This stepper uses the
Packit 67cb25
   explicit BDF formula as predictor and implicit BDF formula as
Packit 67cb25
   corrector. A modified Newton iteration method is used to
Packit 67cb25
   solve the system of non-linear equations. Method order varies
Packit 67cb25
   dynamically between 1 and 5.
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
#include <gsl/gsl_linalg.h>
Packit 67cb25
Packit 67cb25
#include "odeiv_util.h"
Packit 67cb25
Packit 67cb25
/* Maximum order of BDF methods */
Packit 67cb25
#define MSBDF_MAX_ORD 5
Packit 67cb25
Packit 67cb25
/* Steps until Jacobian evaluation is forced */
Packit 67cb25
#define MSBDF_JAC_WAIT 50
Packit 67cb25
Packit 67cb25
/* Steps until iteration matrix M evaluation is forced */
Packit 67cb25
#define MSBDF_M_WAIT 20
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 *l;                    /* polynomial coefficients */
Packit 67cb25
  double *hprev;                /* previous step sizes */
Packit 67cb25
  double *hprevbackup;          /* backup of hprev */
Packit 67cb25
  size_t *ordprev;              /* orders of previous calls */
Packit 67cb25
  size_t *ordprevbackup;        /* backup of ordprev */
Packit 67cb25
  double *errlev;               /* desired error level of y */
Packit 67cb25
  gsl_vector *abscor;           /* absolute y values for correction */
Packit 67cb25
  gsl_vector *abscorscaled;     /* scaled abscor for order evaluation */
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
  gsl_matrix *dfdy;             /* Jacobian */
Packit 67cb25
  double *dfdt;                 /* storage for time derivative of f */
Packit 67cb25
  gsl_matrix *M;                /* Newton iteration matrix */
Packit 67cb25
  gsl_permutation *p;           /* permutation for LU decomposition of M */
Packit 67cb25
  gsl_vector *rhs;              /* right hand side equations (-G) */
Packit 67cb25
  long int ni;                  /* stepper call counter */
Packit 67cb25
  size_t ord;                   /* current order of method */
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 ordp1coeffprev;        /* saved order coefficient */
Packit 67cb25
  size_t nJ;                    /* step counter for Jacobian evaluation */
Packit 67cb25
  size_t nM;                    /* step counter for update of M */
Packit 67cb25
  double gammaprev;             /* gamma of previous call */
Packit 67cb25
  double gammaprevbackup;       /* backup of gammaprev */
Packit 67cb25
  size_t failcount;             /* counter for rejected steps */
Packit 67cb25
}
Packit 67cb25
msbdf_state_t;
Packit 67cb25
Packit 67cb25
/* Introduce msbdf_reset for use in msbdf_alloc and _apply */
Packit 67cb25
Packit 67cb25
static int msbdf_reset (void *, size_t);
Packit 67cb25
Packit 67cb25
static void *
Packit 67cb25
msbdf_alloc (size_t dim)
Packit 67cb25
{
Packit 67cb25
  msbdf_state_t *state = (msbdf_state_t *) malloc (sizeof (msbdf_state_t));
Packit 67cb25
Packit 67cb25
  if (state == 0)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for msbdf_state", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->z = (double *) malloc ((MSBDF_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 ((MSBDF_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->l = (double *) malloc ((MSBDF_MAX_ORD + 1) * sizeof (double));
Packit 67cb25
Packit 67cb25
  if (state->l == 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 l", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->hprev = (double *) malloc (MSBDF_MAX_ORD * sizeof (double));
Packit 67cb25
Packit 67cb25
  if (state->hprev == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state->l);
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 (MSBDF_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->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->ordprev = (size_t *) malloc (MSBDF_MAX_ORD * sizeof (size_t));
Packit 67cb25
Packit 67cb25
  if (state->ordprev == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
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 ordprev", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->ordprevbackup = (size_t *) malloc (MSBDF_MAX_ORD * sizeof (size_t));
Packit 67cb25
Packit 67cb25
  if (state->ordprevbackup == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state->ordprev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
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 ordprevbackup",
Packit 67cb25
                      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->ordprevbackup);
Packit 67cb25
      free (state->ordprev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
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->ordprevbackup);
Packit 67cb25
      free (state->ordprev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
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->ordprevbackup);
Packit 67cb25
      free (state->ordprev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
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->ordprevbackup);
Packit 67cb25
      free (state->ordprev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
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->ordprevbackup);
Packit 67cb25
      free (state->ordprev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
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
  state->dfdy = gsl_matrix_alloc (dim, dim);
Packit 67cb25
Packit 67cb25
  if (state->dfdy == 0)
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->ordprevbackup);
Packit 67cb25
      free (state->ordprev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
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 dfdy", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->dfdt = (double *) malloc (dim * sizeof (double));
Packit 67cb25
Packit 67cb25
  if (state->dfdt == 0)
Packit 67cb25
    {
Packit 67cb25
      gsl_matrix_free (state->dfdy);
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->ordprevbackup);
Packit 67cb25
      free (state->ordprev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
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 dfdt", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->M = gsl_matrix_alloc (dim, dim);
Packit 67cb25
Packit 67cb25
  if (state->M == 0)
Packit 67cb25
    {
Packit 67cb25
      free (state->dfdt);
Packit 67cb25
      gsl_matrix_free (state->dfdy);
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->ordprevbackup);
Packit 67cb25
      free (state->ordprev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
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 M", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->p = gsl_permutation_alloc (dim);
Packit 67cb25
Packit 67cb25
  if (state->p == 0)
Packit 67cb25
    {
Packit 67cb25
      gsl_matrix_free (state->M);
Packit 67cb25
      free (state->dfdt);
Packit 67cb25
      gsl_matrix_free (state->dfdy);
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->ordprevbackup);
Packit 67cb25
      free (state->ordprev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
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 p", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->rhs = gsl_vector_alloc (dim);
Packit 67cb25
Packit 67cb25
  if (state->rhs == 0)
Packit 67cb25
    {
Packit 67cb25
      gsl_permutation_free (state->p);
Packit 67cb25
      gsl_matrix_free (state->M);
Packit 67cb25
      free (state->dfdt);
Packit 67cb25
      gsl_matrix_free (state->dfdy);
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->ordprevbackup);
Packit 67cb25
      free (state->ordprev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
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 rhs", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->abscorscaled = gsl_vector_alloc (dim);
Packit 67cb25
Packit 67cb25
  if (state->abscorscaled == 0)
Packit 67cb25
    {
Packit 67cb25
      gsl_vector_free (state->rhs); 
Packit 67cb25
      gsl_permutation_free (state->p);
Packit 67cb25
      gsl_matrix_free (state->M);
Packit 67cb25
      free (state->dfdt);
Packit 67cb25
      gsl_matrix_free (state->dfdy);
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->ordprevbackup);
Packit 67cb25
      free (state->ordprev);
Packit 67cb25
      free (state->hprevbackup);
Packit 67cb25
      free (state->hprev);
Packit 67cb25
      free (state->l);
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 abscorscaled", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  msbdf_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
msbdf_failurehandler (void *vstate, const size_t dim, const double t)
Packit 67cb25
{
Packit 67cb25
  /* Internal failure handler routine for msbdf. 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
  msbdf_state_t *state = (msbdf_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  const size_t ord = state->ord;
Packit 67cb25
Packit 67cb25
  if (ord > 1 && (ord - state->ordprev[0] == 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
      msbdf_reset (vstate, dim);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
msbdf_calccoeffs (const size_t ord, const size_t ordwait,
Packit 67cb25
                  const double h, const double hprev[],
Packit 67cb25
                  double l[],
Packit 67cb25
                  double *errcoeff, double *ordm1coeff,
Packit 67cb25
                  double *ordp1coeff, double *ordp2coeff, double *gamma)
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 = 2.0;
Packit 67cb25
Packit 67cb25
      {
Packit 67cb25
        const double hsum = h + hprev[0];
Packit 67cb25
        
Packit 67cb25
        const double a5 = -1.5;
Packit 67cb25
        const double a6 = -1.0 - h / hsum;
Packit 67cb25
        const double c2 = 2.0 / (1.0 - a6 + a5);
Packit 67cb25
        
Packit 67cb25
        *ordp2coeff = fabs (c2 * (h / hsum) * 3.0 * a5);
Packit 67cb25
      }
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      size_t i, j;
Packit 67cb25
      double hsum = h;
Packit 67cb25
      double coeff1 = -1.0;
Packit 67cb25
      double x;
Packit 67cb25
Packit 67cb25
      /* Calculate the actual polynomial coefficients (l) */
Packit 67cb25
Packit 67cb25
      DBL_ZERO_MEMSET (l, MSBDF_MAX_ORD + 1);
Packit 67cb25
Packit 67cb25
      l[0] = 1.0;
Packit 67cb25
      l[1] = 1.0;
Packit 67cb25
Packit 67cb25
      for (i = 2; i < ord; i++)
Packit 67cb25
        {
Packit 67cb25
          hsum += hprev[i - 2];
Packit 67cb25
          coeff1 += -1.0 / i;
Packit 67cb25
Packit 67cb25
          for (j = i; j > 0; j--)
Packit 67cb25
            {
Packit 67cb25
              l[j] += h / hsum * l[j - 1];
Packit 67cb25
            }
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      coeff1 += -1.0 / ord;
Packit 67cb25
Packit 67cb25
      x = -l[1] - coeff1;
Packit 67cb25
Packit 67cb25
      for (i = ord; i > 0; i--)
Packit 67cb25
        {
Packit 67cb25
          l[i] += l[i - 1] * x;
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
#endif
Packit 67cb25
Packit 67cb25
      hsum += hprev[ord - 2];
Packit 67cb25
Packit 67cb25
      {
Packit 67cb25
        const double coeff2 = -l[1] - h / hsum;
Packit 67cb25
        const double a1 = 1.0 - coeff2 + coeff1;
Packit 67cb25
        const double a2 = 1.0 + ord * a1;
Packit 67cb25
Packit 67cb25
        /* Calculate error coefficient */
Packit 67cb25
Packit 67cb25
        *errcoeff = fabs (a1 / (coeff1 * a2));
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
            const double a3 = coeff1 + 1.0 / ord;
Packit 67cb25
            const double a4 = coeff2 + h / hsum;
Packit 67cb25
            const double c1 = a3 / (1.0 - a4 + a3);
Packit 67cb25
Packit 67cb25
            *ordm1coeff = fabs (c1 / (x / l[ord]));
Packit 67cb25
Packit 67cb25
            *ordp1coeff = fabs (a2 / (l[ord] * (h / hsum) / x));
Packit 67cb25
Packit 67cb25
            hsum += hprev[ord - 1];
Packit 67cb25
Packit 67cb25
            {
Packit 67cb25
              const double a5 = coeff1 - 1.0 / (ord + 1.0);
Packit 67cb25
              const double a6 = coeff2 - h / hsum;
Packit 67cb25
              const double c2 = a2 / (1.0 - a6 + a5);
Packit 67cb25
Packit 67cb25
              *ordp2coeff = fabs (c2 * (h / hsum) * (ord + 2) * a5);
Packit 67cb25
            }
Packit 67cb25
          }
Packit 67cb25
      }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  *gamma = h / l[1];
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
msbdf_update (void *vstate, const size_t dim, gsl_matrix * dfdy, double *dfdt,
Packit 67cb25
              const double t, const double *y, const gsl_odeiv2_system * sys,
Packit 67cb25
              gsl_matrix * M, gsl_permutation * p,
Packit 67cb25
              const size_t iter, size_t * nJ, size_t * nM,
Packit 67cb25
              const double tprev, const double failt,
Packit 67cb25
              const double gamma, const double gammaprev, const double hratio)
Packit 67cb25
{
Packit 67cb25
  /* Evaluates Jacobian dfdy and updates iteration matrix M
Packit 67cb25
     if criteria for update is met.
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  /* Jacobian is evaluated
Packit 67cb25
     - at first step
Packit 67cb25
     - if MSBDF_JAC_WAIT steps have been made without re-evaluation
Packit 67cb25
     - in case of a convergence failure if
Packit 67cb25
     --- change in gamma is small, or 
Packit 67cb25
     --- convergence failure resulted in step size decrease
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  const double c = 0.2;
Packit 67cb25
  const double gammarel = fabs (gamma / gammaprev - 1.0);
Packit 67cb25
Packit 67cb25
  if (*nJ == 0 || *nJ > MSBDF_JAC_WAIT ||
Packit 67cb25
      (t == failt && (gammarel < c || hratio < 1.0)))
Packit 67cb25
    {
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
      printf ("-- evaluate jacobian\n");
Packit 67cb25
#endif
Packit 67cb25
      int s = GSL_ODEIV_JA_EVAL (sys, t, y, dfdy->data, dfdt);
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
          msbdf_failurehandler (vstate, dim, t);
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
          printf ("-- FAIL at jacobian function evaluation\n");
Packit 67cb25
#endif
Packit 67cb25
          return s;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* Reset counter */
Packit 67cb25
Packit 67cb25
      *nJ = 0;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Iteration matrix M (and it's LU decomposition) is generated
Packit 67cb25
     - at first step
Packit 67cb25
     - if MSBDF_M_WAIT steps have been made without an update
Packit 67cb25
     - if change in gamma is significant (e.g. change in step size)
Packit 67cb25
     - if previous step was rejected
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  if (*nM == 0 || *nM > MSBDF_M_WAIT || gammarel >= c ||
Packit 67cb25
      t == tprev || t == failt)
Packit 67cb25
    {
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
      printf ("-- update M, gamma=%.5e\n", gamma);
Packit 67cb25
#endif
Packit 67cb25
      size_t i;
Packit 67cb25
      gsl_matrix_memcpy (M, dfdy);
Packit 67cb25
      gsl_matrix_scale (M, -gamma);
Packit 67cb25
Packit 67cb25
      for (i = 0; i < dim; i++)
Packit 67cb25
        {
Packit 67cb25
          gsl_matrix_set (M, i, i, gsl_matrix_get (M, i, i) + 1.0);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      {
Packit 67cb25
        int signum;
Packit 67cb25
        int s = gsl_linalg_LU_decomp (M, p, &signum);
Packit 67cb25
        
Packit 67cb25
        if (s != GSL_SUCCESS)
Packit 67cb25
          {
Packit 67cb25
            return GSL_FAILURE;
Packit 67cb25
          }
Packit 67cb25
      }
Packit 67cb25
Packit 67cb25
      /* Reset counter */
Packit 67cb25
Packit 67cb25
      *nM = 0;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
msbdf_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
                 gsl_matrix * dfdy, double dfdt[], gsl_matrix * M,
Packit 67cb25
                 gsl_permutation * p, gsl_vector * rhs,
Packit 67cb25
                 size_t * nJ, size_t * nM,
Packit 67cb25
                 const double tprev, const double failt,
Packit 67cb25
                 const double gamma, const double gammaprev,
Packit 67cb25
                 const double hprev0)
Packit 67cb25
{
Packit 67cb25
  /* Calculates the correction step (abscor). Equation
Packit 67cb25
     system M = I - gamma * dfdy = -G is solved by Newton 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;    /* previous norm value */
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
        msbdf_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
      /* Generate or update Jacobian and/or iteration matrix M if needed */
Packit 67cb25
Packit 67cb25
      if (mi == 0)
Packit 67cb25
        {
Packit 67cb25
          int s = msbdf_update (vstate, dim, dfdy, dfdt, t + h, z,
Packit 67cb25
                                sys, M, p, mi,
Packit 67cb25
                                nJ, nM, tprev, failt,
Packit 67cb25
                                gamma, gammaprev,
Packit 67cb25
                                h / hprev0);
Packit 67cb25
Packit 67cb25
          if (s != GSL_SUCCESS)
Packit 67cb25
            {
Packit 67cb25
              return s;
Packit 67cb25
            }
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* Evaluate the right hand side (-G) */
Packit 67cb25
Packit 67cb25
      for (i = 0; i < dim; i++)
Packit 67cb25
        {
Packit 67cb25
          const double r = -1.0 * gsl_vector_get (abscor, i) -
Packit 67cb25
            z[1 * dim + i] / l[1] + gamma * ytmp[i];
Packit 67cb25
Packit 67cb25
          gsl_vector_set (rhs, i, r);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* Solve system of equations */
Packit 67cb25
Packit 67cb25
      {
Packit 67cb25
        int s = gsl_linalg_LU_solve (M, p, rhs, relcor);
Packit 67cb25
        
Packit 67cb25
        if (s != GSL_SUCCESS)
Packit 67cb25
          {
Packit 67cb25
            msbdf_failurehandler (vstate, dim, t);
Packit 67cb25
            
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
            printf ("-- FAIL at LU_solve\n");
Packit 67cb25
#endif
Packit 67cb25
            return GSL_FAILURE;
Packit 67cb25
          }
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 ", gsl_vector_get (relcor, di));
Packit 67cb25
          }
Packit 67cb25
        printf ("\n");
Packit 67cb25
      }
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
      /* Add iteration results */
Packit 67cb25
Packit 67cb25
      for (i = 0; i < dim; i++)
Packit 67cb25
        {
Packit 67cb25
          const double r =
Packit 67cb25
            gsl_vector_get (abscor, i) + gsl_vector_get (relcor, i);
Packit 67cb25
Packit 67cb25
          gsl_vector_set (abscor, i, r);
Packit 67cb25
Packit 67cb25
          ytmp2[i] = z[i] + r;
Packit 67cb25
Packit 67cb25
          gsl_vector_set (relcor, i, gsl_vector_get (relcor, i) / errlev[i]);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
      {
Packit 67cb25
        size_t di;
Packit 67cb25
        printf ("-- abscor: ");
Packit 67cb25
        for (di = 0; di < dim; di++)
Packit 67cb25
          {
Packit 67cb25
            printf ("%.5e ", gsl_vector_get (abscor, di));
Packit 67cb25
          }
Packit 67cb25
        printf ("\n");
Packit 67cb25
      }
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
      /* Convergence test. Norms used are root-mean-square norms. */
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
          ("-- newt 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
      {
Packit 67cb25
        const double div_const = 2.0;
Packit 67cb25
Packit 67cb25
        if (mi > 1 && stepnorm > div_const * stepnormprev)
Packit 67cb25
          {
Packit 67cb25
            msbdf_failurehandler (vstate, dim, t);
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
            printf ("-- FAIL, diverging Newton 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
            msbdf_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 ("-- Newton 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
      msbdf_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
msbdf_eval_order (gsl_vector * abscorscaled, 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)
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
  const double min_incr = 1.5;
Packit 67cb25
Packit 67cb25
  /* Relative step length estimate for current order */
Packit 67cb25
Packit 67cb25
  ordest = 1.0 / (pow (bias * gsl_blas_dnrm2 (abscorscaled) / 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 < MSBDF_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 (abscorscaled, 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
  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
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
msbdf_check_no_order_decrease (size_t const ordprev[])
Packit 67cb25
{
Packit 67cb25
  /* Checks if order has not been decreased according to order history
Packit 67cb25
     array. Used in stability enhancement.
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  size_t i;
Packit 67cb25
Packit 67cb25
  for (i = 0; i < MSBDF_MAX_ORD - 1; i++)
Packit 67cb25
    {
Packit 67cb25
      if (ordprev[i + 1] > ordprev[i])
Packit 67cb25
        {
Packit 67cb25
          return 0;
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return 1;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
msbdf_check_step_size_decrease (double const hprev[])
Packit 67cb25
{
Packit 67cb25
  /* Checks if step size has decreased markedly according to
Packit 67cb25
     step size history array. Used in stability enhancement.
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  size_t i;
Packit 67cb25
  double max = fabs (hprev[0]);
Packit 67cb25
  const double min = fabs (hprev[0]);
Packit 67cb25
  const double decrease_limit = 0.5;
Packit 67cb25
Packit 67cb25
  for (i = 1; i < MSBDF_MAX_ORD; i++)
Packit 67cb25
    {
Packit 67cb25
      const double h = fabs (hprev[i]);
Packit 67cb25
Packit 67cb25
      if (h > min && h > max)
Packit 67cb25
        {
Packit 67cb25
          max = h;
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  if (min / max < decrease_limit)
Packit 67cb25
    {
Packit 67cb25
      return 1;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return 0;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
msbdf_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
  /* Carries out a step by BDF linear multistep methods. */
Packit 67cb25
Packit 67cb25
  msbdf_state_t *state = (msbdf_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 l = state->l;
Packit 67cb25
  double *const hprev = state->hprev;
Packit 67cb25
  double *const hprevbackup = state->hprevbackup;
Packit 67cb25
  size_t *const ordprev = state->ordprev;
Packit 67cb25
  size_t *const ordprevbackup = state->ordprevbackup;
Packit 67cb25
  double *const errlev = state->errlev;
Packit 67cb25
  gsl_vector *const abscor = state->abscor;
Packit 67cb25
  gsl_vector *const abscorscaled = state->abscorscaled;
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;      /* order for this step */
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
  double gamma = 0.0;           /* gamma coefficient */
Packit 67cb25
Packit 67cb25
  const size_t max_failcount = 3;
Packit 67cb25
  size_t i;
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
  {
Packit 67cb25
    size_t di;
Packit 67cb25
Packit 67cb25
    printf ("msbdf_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
          msbdf_reset (vstate, dim);
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
          printf ("-- first step was REJECTED, msbdf_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 > ordprev[0])
Packit 67cb25
            {
Packit 67cb25
              state->ord = ordprev[0];
Packit 67cb25
              ord = state->ord;
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          /* Restore previous state */
Packit 67cb25
Packit 67cb25
          DBL_MEMCPY (z, zbackup, (MSBDF_MAX_ORD + 1) * dim);
Packit 67cb25
          DBL_MEMCPY (hprev, hprevbackup, MSBDF_MAX_ORD);
Packit 67cb25
Packit 67cb25
          for (i = 0; i < MSBDF_MAX_ORD; i++)
Packit 67cb25
            {
Packit 67cb25
              ordprev[i] = ordprevbackup[i];
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          state->ordwait = state->ordwaitbackup;
Packit 67cb25
          state->gammaprev = state->gammaprevbackup;
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
      /* If step is repeatedly rejected, then reset method */
Packit 67cb25
Packit 67cb25
      state->failcount++;
Packit 67cb25
Packit 67cb25
      if (state->failcount > max_failcount && state->ni > 1)
Packit 67cb25
        {
Packit 67cb25
          msbdf_reset (vstate, dim);
Packit 67cb25
          ord = state->ord;
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
          printf ("-- max_failcount reached, msbdf_reset called\n");
Packit 67cb25
#endif
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, (MSBDF_MAX_ORD + 1) * dim);
Packit 67cb25
      DBL_MEMCPY (hprevbackup, hprev, MSBDF_MAX_ORD);
Packit 67cb25
Packit 67cb25
      for (i = 0; i < MSBDF_MAX_ORD; i++)
Packit 67cb25
        {
Packit 67cb25
          ordprevbackup[i] = ordprev[i];
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      state->ordwaitbackup = state->ordwait;
Packit 67cb25
      state->gammaprevbackup = state->gammaprev;
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
Packit 67cb25
  size_t di;
Packit 67cb25
  printf ("-- ordprev: ");
Packit 67cb25
Packit 67cb25
  for (di = 0; di < MSBDF_MAX_ORD; di++)
Packit 67cb25
    {
Packit 67cb25
      printf ("%d ", (int) ordprev[di]);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  printf ("\n");
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, (MSBDF_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
  /* Stability enhancement heuristic for msbdf: If order > 1 and order
Packit 67cb25
     has not been changed, check for decrease in step size, that is
Packit 67cb25
     not accompanied by a decrease in method order. This condition may
Packit 67cb25
     be indication of BDF method stability problems, a change in ODE
Packit 67cb25
     system, or convergence problems in Newton iteration. In all
Packit 67cb25
     cases, the strategy is to decrease method order.
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
  printf ("-- check_no_order_decrease %d, check_step_size_decrease %d\n",
Packit 67cb25
          msbdf_check_no_order_decrease (ordprev),
Packit 67cb25
          msbdf_check_step_size_decrease (hprev));
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
  if (ord > 1 &&
Packit 67cb25
      ord - ordprev[0] == 0 &&
Packit 67cb25
      msbdf_check_no_order_decrease (ordprev) &&
Packit 67cb25
      msbdf_check_step_size_decrease (hprev))
Packit 67cb25
    {
Packit 67cb25
      state->ord--;
Packit 67cb25
      state->ordwait = ord + 2;
Packit 67cb25
      ord = state->ord;
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
      printf ("-- stability enhancement decreased order to %d\n", (int) ord);
Packit 67cb25
#endif
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Sanity check */
Packit 67cb25
Packit 67cb25
  { 
Packit 67cb25
    const int deltaord = ord - ordprev[0];
Packit 67cb25
Packit 67cb25
  if (deltaord > 1 || deltaord < -1)
Packit 67cb25
    {
Packit 67cb25
      printf ("-- order change %d\n", deltaord);
Packit 67cb25
      GSL_ERROR_NULL ("msbdf_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, adjust Nordsieck matrix */
Packit 67cb25
Packit 67cb25
  if (deltaord == 1)
Packit 67cb25
    {
Packit 67cb25
      if (ord > 2)
Packit 67cb25
        {
Packit 67cb25
          size_t i, j;
Packit 67cb25
          double hsum = h;
Packit 67cb25
          double coeff1 = -1.0;
Packit 67cb25
          double coeff2 = 1.0;
Packit 67cb25
          double hrelprev = 1.0;
Packit 67cb25
          double hrelprod = 1.0;
Packit 67cb25
          double hrel = 0.0;
Packit 67cb25
Packit 67cb25
          /* Calculate coefficients used in adjustment to l */
Packit 67cb25
Packit 67cb25
          DBL_ZERO_MEMSET (l, MSBDF_MAX_ORD + 1);
Packit 67cb25
Packit 67cb25
          l[2] = 1.0;
Packit 67cb25
Packit 67cb25
          for (i = 1; i < ord - 1; i++)
Packit 67cb25
            {
Packit 67cb25
              hsum += hprev[i];
Packit 67cb25
              hrel = hsum / h;
Packit 67cb25
              hrelprod *= hrel;
Packit 67cb25
              coeff1 -= 1.0 / (i + 1);
Packit 67cb25
              coeff2 += 1.0 / hrel;
Packit 67cb25
Packit 67cb25
              for (j = i + 2; j > 1; j--)
Packit 67cb25
                {
Packit 67cb25
                  l[j] *= hrelprev;
Packit 67cb25
                  l[j] += l[j - 1];
Packit 67cb25
                }
Packit 67cb25
Packit 67cb25
              hrelprev = hrel;
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          /* Scale Nordsieck matrix */
Packit 67cb25
Packit 67cb25
          {
Packit 67cb25
            const double c = (-coeff1 - coeff2) / hrelprod;
Packit 67cb25
Packit 67cb25
            for (i = 0; i < dim; i++)
Packit 67cb25
              {
Packit 67cb25
                z[ord * dim + i] = c * gsl_vector_get (abscor, i);
Packit 67cb25
              }
Packit 67cb25
          }
Packit 67cb25
          for (i = 2; i < ord; i++)
Packit 67cb25
            for (j = 0; j < dim; j++)
Packit 67cb25
              {
Packit 67cb25
                z[i * dim + j] += l[i] * z[ord * dim + j];
Packit 67cb25
              }
Packit 67cb25
        }
Packit 67cb25
      else
Packit 67cb25
        {
Packit 67cb25
          /* zero new vector for order incease from 1 to 2 */
Packit 67cb25
Packit 67cb25
          DBL_ZERO_MEMSET (&z[ord * dim], dim);
Packit 67cb25
        }
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
      size_t i, j;
Packit 67cb25
      double hsum = 0.0;
Packit 67cb25
Packit 67cb25
      /* Calculate coefficients used in adjustment to l */
Packit 67cb25
Packit 67cb25
      DBL_ZERO_MEMSET (l, MSBDF_MAX_ORD + 1);
Packit 67cb25
Packit 67cb25
      l[2] = 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 + 2; j > 1; j--)
Packit 67cb25
            {
Packit 67cb25
              l[j] *= hsum / h;
Packit 67cb25
              l[j] += l[j - 1];
Packit 67cb25
            }
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
  msbdf_calccoeffs (ord, state->ordwait, h, hprev, l, &errcoeff,
Packit 67cb25
                    &ordm1coeff, &ordp1coeff, &ordp2coeff, &gamma);
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 = msbdf_corrector (vstate, sys, t, h, dim, z, errlev, l, errcoeff,
Packit 67cb25
                         abscor, relcor, ytmp, ytmp2,
Packit 67cb25
                         state->dfdy, state->dfdt, state->M,
Packit 67cb25
                         state->p, state->rhs,
Packit 67cb25
                         &(state->nJ), &(state->nM),
Packit 67cb25
                         state->tprev, state->failt, gamma,
Packit 67cb25
                         state->gammaprev, hprev[0]);
Packit 67cb25
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 ("---- 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 ("-- 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
            msbdf_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
     in order evaluation in msbdf_eval_order
Packit 67cb25
   */
Packit 67cb25
  {
Packit 67cb25
    size_t i;
Packit 67cb25
Packit 67cb25
    for (i = 0; i < dim; i++)
Packit 67cb25
      {
Packit 67cb25
        gsl_vector_set (abscorscaled, i, 
Packit 67cb25
                        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 < MSBDF_MAX_ORD)
Packit 67cb25
    {
Packit 67cb25
      size_t i;
Packit 67cb25
Packit 67cb25
      state->ordp1coeffprev = ordp1coeff;
Packit 67cb25
Packit 67cb25
      for (i = 0; i < dim; i++)
Packit 67cb25
        {
Packit 67cb25
          gsl_vector_set (svec, i, gsl_vector_get (abscorscaled, i));
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Consider and execute order change for next step if order is unchanged. */
Packit 67cb25
Packit 67cb25
  if (state->ordwait == 0) 
Packit 67cb25
  { 
Packit 67cb25
    if (ord - ordprev[0] == 0)
Packit 67cb25
      {
Packit 67cb25
        msbdf_eval_order (abscorscaled, tempvec, svec, errcoeff, dim, errlev,
Packit 67cb25
                          ordm1coeff, ordp1coeff,
Packit 67cb25
                          state->ordp1coeffprev, ordp2coeff,
Packit 67cb25
                          hprev, h, z, &(state->ord));
Packit 67cb25
Packit 67cb25
        state->ordwait = state->ord + 2;
Packit 67cb25
      }
Packit 67cb25
    else
Packit 67cb25
      {
Packit 67cb25
        /* Postpone order evaluation if order has been modified elsewhere */
Packit 67cb25
    
Packit 67cb25
        state->ordwait = 2;
Packit 67cb25
      }
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
    for (i = MSBDF_MAX_ORD - 1; i > 0; i--)
Packit 67cb25
      {
Packit 67cb25
        hprev[i] = hprev[i - 1];
Packit 67cb25
        ordprev[i] = ordprev[i - 1];
Packit 67cb25
      }
Packit 67cb25
  }
Packit 67cb25
  
Packit 67cb25
  hprev[0] = h;
Packit 67cb25
  ordprev[0] = ord;
Packit 67cb25
  
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
  {
Packit 67cb25
    size_t di;
Packit 67cb25
    printf ("-- hprev: ");
Packit 67cb25
    for (di = 0; di < MSBDF_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
  state->gammaprev = gamma;
Packit 67cb25
  
Packit 67cb25
  state->nJ++;
Packit 67cb25
  state->nM++;
Packit 67cb25
  
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
  printf ("-- nJ=%d, nM=%d\n", (int) state->nJ, (int) state->nM);
Packit 67cb25
#endif
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
msbdf_set_driver (void *vstate, const gsl_odeiv2_driver * d)
Packit 67cb25
{
Packit 67cb25
  msbdf_state_t *state = (msbdf_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
msbdf_reset (void *vstate, size_t dim)
Packit 67cb25
{
Packit 67cb25
  msbdf_state_t *state = (msbdf_state_t *) vstate;
Packit 67cb25
  size_t i;
Packit 67cb25
Packit 67cb25
  state->ni = 0;
Packit 67cb25
  state->ord = 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->tprev = GSL_NAN;  
Packit 67cb25
  state->gammaprev = 1.0;
Packit 67cb25
  state->gammaprevbackup = 1.0;
Packit 67cb25
  state->nJ = 0;
Packit 67cb25
  state->nM = 0;
Packit 67cb25
  state->failcount = 0;
Packit 67cb25
  state->ordp1coeffprev = 0.0;
Packit 67cb25
Packit 67cb25
  DBL_ZERO_MEMSET (state->hprev, MSBDF_MAX_ORD);
Packit 67cb25
  DBL_ZERO_MEMSET (state->hprevbackup, MSBDF_MAX_ORD);
Packit 67cb25
  DBL_ZERO_MEMSET (state->z, (MSBDF_MAX_ORD + 1) * dim);
Packit 67cb25
  DBL_ZERO_MEMSET (state->zbackup, (MSBDF_MAX_ORD + 1) * dim);
Packit 67cb25
Packit 67cb25
  for (i = 0; i < MSBDF_MAX_ORD; i++)
Packit 67cb25
    {
Packit 67cb25
      state->ordprev[i] = 1;
Packit 67cb25
      state->ordprevbackup[i] = 1;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
#ifdef DEBUG
Packit 67cb25
  printf ("-- msbdf_reset called\n");
Packit 67cb25
#endif
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static unsigned int
Packit 67cb25
msbdf_order (void *vstate)
Packit 67cb25
{
Packit 67cb25
  msbdf_state_t *state = (msbdf_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  return state->ord;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static void
Packit 67cb25
msbdf_free (void *vstate)
Packit 67cb25
{
Packit 67cb25
  msbdf_state_t *state = (msbdf_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  gsl_vector_free (state->rhs);
Packit 67cb25
  gsl_permutation_free (state->p);
Packit 67cb25
  gsl_matrix_free (state->M);
Packit 67cb25
  free (state->dfdt);
Packit 67cb25
  gsl_matrix_free (state->dfdy);
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
  gsl_vector_free (state->abscorscaled);
Packit 67cb25
  free (state->errlev);
Packit 67cb25
  free (state->ordprevbackup);
Packit 67cb25
  free (state->ordprev);
Packit 67cb25
  free (state->hprevbackup);
Packit 67cb25
  free (state->hprev);
Packit 67cb25
  free (state->l);
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 msbdf_type = {
Packit 67cb25
  "msbdf",                      /* name */
Packit 67cb25
  1,                            /* can use dydt_in? */
Packit 67cb25
  1,                            /* gives exact dydt_out? */
Packit 67cb25
  &msbdf_alloc,
Packit 67cb25
  &msbdf_apply,
Packit 67cb25
  &msbdf_set_driver,
Packit 67cb25
  &msbdf_reset,
Packit 67cb25
  &msbdf_order,
Packit 67cb25
  &msbdf_free
Packit 67cb25
};
Packit 67cb25
Packit 67cb25
const gsl_odeiv2_step_type *gsl_odeiv2_step_msbdf = &msbdf_type;