|
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 |
º1coeff, &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;
|