blob: 73c085cefdca764bbb4c010557720c34da77e74c [file] [log] [blame]
/* integration/qc25f.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.
*/
struct fn_fourier_params
{
gsl_function *function;
double omega;
};
static double fn_sin (double t, void *params);
static double fn_cos (double t, void *params);
static void
qc25f (gsl_function * f, double a, double b,
gsl_integration_qawo_table * wf, size_t level,
double *result, double *abserr, double *resabs, double *resasc);
static void
qc25f (gsl_function * f, double a, double b,
gsl_integration_qawo_table * wf, size_t level,
double *result, double *abserr, double *resabs, double *resasc)
{
const double center = 0.5 * (a + b);
const double half_length = 0.5 * (b - a);
const double omega = wf->omega ;
const double par = omega * half_length;
if (fabs (par) < 2)
{
gsl_function weighted_function;
struct fn_fourier_params fn_params;
fn_params.function = f;
fn_params.omega = omega;
if (wf->sine == GSL_INTEG_SINE)
{
weighted_function.function = &fn_sin;
}
else
{
weighted_function.function = &fn_cos;
}
weighted_function.params = &fn_params;
gsl_integration_qk15 (&weighted_function, a, b, result, abserr,
resabs, resasc);
return;
}
else
{
double *moment;
double cheb12[13], cheb24[25];
double result_abs, res12_cos, res12_sin, res24_cos, res24_sin;
double est_cos, est_sin;
double c, s;
size_t i;
gsl_integration_qcheb (f, a, b, cheb12, cheb24);
if (level >= wf->n)
{
/* table overflow should not happen, check before calling */
GSL_ERROR_VOID("table overflow in internal function", GSL_ESANITY);
}
/* obtain moments from the table */
moment = wf->chebmo + 25 * level;
res12_cos = cheb12[12] * moment[12];
res12_sin = 0 ;
for (i = 0; i < 6; i++)
{
size_t k = 10 - 2 * i;
res12_cos += cheb12[k] * moment[k];
res12_sin += cheb12[k + 1] * moment[k + 1];
}
res24_cos = cheb24[24] * moment[24];
res24_sin = 0 ;
result_abs = fabs(cheb24[24]) ;
for (i = 0; i < 12; i++)
{
size_t k = 22 - 2 * i;
res24_cos += cheb24[k] * moment[k];
res24_sin += cheb24[k + 1] * moment[k + 1];
result_abs += fabs(cheb24[k]) + fabs(cheb24[k+1]);
}
est_cos = fabs(res24_cos - res12_cos);
est_sin = fabs(res24_sin - res12_sin);
c = half_length * cos(center * omega);
s = half_length * sin(center * omega);
if (wf->sine == GSL_INTEG_SINE)
{
*result = c * res24_sin + s * res24_cos;
*abserr = fabs(c * est_sin) + fabs(s * est_cos);
}
else
{
*result = c * res24_cos - s * res24_sin;
*abserr = fabs(c * est_cos) + fabs(s * est_sin);
}
*resabs = result_abs * half_length;
*resasc = GSL_DBL_MAX;
return;
}
}
static double
fn_sin (double x, void *params)
{
struct fn_fourier_params *p = (struct fn_fourier_params *) params;
gsl_function *f = p->function;
double w = p->omega;
double wx = w * x;
double sinwx = sin(wx) ;
return GSL_FN_EVAL (f, x) * sinwx;
}
static double
fn_cos (double x, void *params)
{
struct fn_fourier_params *p = (struct fn_fourier_params *) params;
gsl_function *f = p->function;
double w = p->omega;
double wx = w * x;
double coswx = cos(wx) ;
return GSL_FN_EVAL (f, x) * coswx ;
}