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