blob: ba72f53fd2d6550c0c07d2612a2c4cf3bae83e52 [file] [log] [blame]
/* integration/qawf.c
*
* Copyright (C) 1996, 1997, 1998, 1999, 2000 Brian Gough
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <config.h>
#include <math.h>
#include <float.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_integration.h>
#include "initialise.c"
#include "append.c"
#include "qelg.c"
int
gsl_integration_qawf (gsl_function * f,
const double a,
const double epsabs,
const size_t limit,
gsl_integration_workspace * workspace,
gsl_integration_workspace * cycle_workspace,
gsl_integration_qawo_table * wf,
double *result, double *abserr)
{
double area, errsum;
double res_ext, err_ext;
double correc, total_error = 0.0, truncation_error;
size_t ktmin = 0;
size_t iteration = 0;
struct extrapolation_table table;
double cycle;
double omega = wf->omega;
const double p = 0.9;
double factor = 1;
double initial_eps, eps;
int error_type = 0;
/* Initialize results */
initialise (workspace, a, a);
*result = 0;
*abserr = 0;
if (limit > workspace->limit)
{
GSL_ERROR ("iteration limit exceeds available workspace", GSL_EINVAL) ;
}
/* Test on accuracy */
if (epsabs <= 0)
{
GSL_ERROR ("absolute tolerance epsabs must be positive", GSL_EBADTOL) ;
}
if (omega == 0.0)
{
if (wf->sine == GSL_INTEG_SINE)
{
/* The function sin(w x) f(x) is always zero for w = 0 */
*result = 0;
*abserr = 0;
return GSL_SUCCESS;
}
else
{
/* The function cos(w x) f(x) is always f(x) for w = 0 */
int status = gsl_integration_qagiu (f, a, epsabs, 0.0,
cycle_workspace->limit,
cycle_workspace,
result, abserr);
return status;
}
}
if (epsabs > GSL_DBL_MIN / (1 - p))
{
eps = epsabs * (1 - p);
}
else
{
eps = epsabs;
}
initial_eps = eps;
area = 0;
errsum = 0;
res_ext = 0;
err_ext = GSL_DBL_MAX;
correc = 0;
cycle = (2 * floor (fabs (omega)) + 1) * M_PI / fabs (omega);
gsl_integration_qawo_table_set_length (wf, cycle);
initialise_table (&table);
for (iteration = 0; iteration < limit; iteration++)
{
double area1, error1, reseps, erreps;
double a1 = a + iteration * cycle;
double b1 = a1 + cycle;
double epsabs1 = eps * factor;
int status = gsl_integration_qawo (f, a1, epsabs1, 0.0, limit,
cycle_workspace, wf,
&area1, &error1);
append_interval (workspace, a1, b1, area1, error1);
factor *= p;
area = area + area1;
errsum = errsum + error1;
/* estimate the truncation error as 50 times the final term */
truncation_error = 50 * fabs (area1);
total_error = errsum + truncation_error;
if (total_error < epsabs && iteration > 4)
{
goto compute_result;
}
if (error1 > correc)
{
correc = error1;
}
if (status)
{
eps = GSL_MAX_DBL (initial_eps, correc * (1.0 - p));
}
if (status && total_error < 10 * correc && iteration > 3)
{
goto compute_result;
}
append_table (&table, area);
if (table.n < 2)
{
continue;
}
qelg (&table, &reseps, &erreps);
ktmin++;
if (ktmin >= 15 && err_ext < 0.001 * total_error)
{
error_type = 4;
}
if (erreps < err_ext)
{
ktmin = 0;
err_ext = erreps;
res_ext = reseps;
if (err_ext + 10 * correc <= epsabs)
break;
if (err_ext <= epsabs && 10 * correc >= epsabs)
break;
}
}
if (iteration == limit)
error_type = 1;
if (err_ext == GSL_DBL_MAX)
goto compute_result;
err_ext = err_ext + 10 * correc;
*result = res_ext;
*abserr = err_ext;
if (error_type == 0)
{
return GSL_SUCCESS ;
}
if (res_ext != 0.0 && area != 0.0)
{
if (err_ext / fabs (res_ext) > errsum / fabs (area))
goto compute_result;
}
else if (err_ext > errsum)
{
goto compute_result;
}
else if (area == 0.0)
{
goto return_error;
}
if (error_type == 4)
{
err_ext = err_ext + truncation_error;
}
goto return_error;
compute_result:
*result = area;
*abserr = total_error;
return_error:
if (error_type > 2)
error_type--;
if (error_type == 0)
{
return GSL_SUCCESS;
}
else if (error_type == 1)
{
GSL_ERROR ("number of iterations was insufficient", GSL_EMAXITER);
}
else if (error_type == 2)
{
GSL_ERROR ("cannot reach tolerance because of roundoff error",
GSL_EROUND);
}
else if (error_type == 3)
{
GSL_ERROR ("bad integrand behavior found in the integration interval",
GSL_ESING);
}
else if (error_type == 4)
{
GSL_ERROR ("roundoff error detected in the extrapolation table",
GSL_EROUND);
}
else if (error_type == 5)
{
GSL_ERROR ("integral is divergent, or slowly convergent",
GSL_EDIVERGE);
}
else
{
GSL_ERROR ("could not integrate function", GSL_EFAILED);
}
}