Blame integration/qmomof.c

Packit 67cb25
/* integration/qmomof.c
Packit 67cb25
 * 
Packit 67cb25
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough
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
#include <config.h>
Packit 67cb25
#include <stdlib.h>
Packit 67cb25
#include <gsl/gsl_integration.h>
Packit 67cb25
#include <gsl/gsl_errno.h>
Packit 67cb25
Packit 67cb25
static void
Packit 67cb25
compute_moments (double par, double * cheb);
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
dgtsl (size_t n, double *c, double *d, double *e, double *b);
Packit 67cb25
Packit 67cb25
gsl_integration_qawo_table *
Packit 67cb25
gsl_integration_qawo_table_alloc (double omega, double L, 
Packit 67cb25
                                  enum gsl_integration_qawo_enum sine,
Packit 67cb25
                                  size_t n)
Packit 67cb25
{
Packit 67cb25
  gsl_integration_qawo_table *t;
Packit 67cb25
  double * chebmo;
Packit 67cb25
Packit 67cb25
  if (n == 0)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_VAL ("table length n must be positive integer",
Packit 67cb25
                        GSL_EDOM, 0);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  t = (gsl_integration_qawo_table *)
Packit 67cb25
    malloc (sizeof (gsl_integration_qawo_table));
Packit 67cb25
Packit 67cb25
  if (t == 0)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_VAL ("failed to allocate space for qawo_table struct",
Packit 67cb25
                        GSL_ENOMEM, 0);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  chebmo = (double *)  malloc (25 * n * sizeof (double));
Packit 67cb25
Packit 67cb25
  if (chebmo == 0)
Packit 67cb25
    {
Packit 67cb25
      free (t);
Packit 67cb25
      GSL_ERROR_VAL ("failed to allocate space for chebmo block",
Packit 67cb25
                        GSL_ENOMEM, 0);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  t->n = n;
Packit 67cb25
  t->sine = sine;
Packit 67cb25
  t->omega = omega;
Packit 67cb25
  t->L = L;
Packit 67cb25
  t->par = 0.5 * omega * L;
Packit 67cb25
  t->chebmo = chebmo;
Packit 67cb25
Packit 67cb25
  /* precompute the moments */
Packit 67cb25
Packit 67cb25
  { 
Packit 67cb25
    size_t i;
Packit 67cb25
    double scale = 1.0;
Packit 67cb25
Packit 67cb25
    for (i = 0 ; i < t->n; i++)
Packit 67cb25
      {
Packit 67cb25
        compute_moments (t->par * scale, t->chebmo + 25*i);
Packit 67cb25
        scale *= 0.5;
Packit 67cb25
      }
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  return t;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_integration_qawo_table_set (gsl_integration_qawo_table * t,
Packit 67cb25
                                    double omega, double L,
Packit 67cb25
                                    enum gsl_integration_qawo_enum sine)
Packit 67cb25
{
Packit 67cb25
  t->omega = omega;
Packit 67cb25
  t->sine = sine;
Packit 67cb25
  t->L = L;
Packit 67cb25
  t->par = 0.5 * omega * L;
Packit 67cb25
Packit 67cb25
  /* recompute the moments */
Packit 67cb25
Packit 67cb25
  { 
Packit 67cb25
    size_t i;
Packit 67cb25
    double scale = 1.0;
Packit 67cb25
Packit 67cb25
    for (i = 0 ; i < t->n; i++)
Packit 67cb25
      {
Packit 67cb25
        compute_moments (t->par * scale, t->chebmo + 25*i);
Packit 67cb25
        scale *= 0.5;
Packit 67cb25
      }
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_integration_qawo_table_set_length (gsl_integration_qawo_table * t,
Packit 67cb25
                                           double L)
Packit 67cb25
{
Packit 67cb25
  /* return immediately if the length is the same as the old length */
Packit 67cb25
Packit 67cb25
  if (L == t->L)
Packit 67cb25
    return GSL_SUCCESS;
Packit 67cb25
Packit 67cb25
  /* otherwise reset the table and compute the new parameters */
Packit 67cb25
Packit 67cb25
  t->L = L;
Packit 67cb25
  t->par = 0.5 * t->omega * L;
Packit 67cb25
Packit 67cb25
  /* recompute the moments */
Packit 67cb25
Packit 67cb25
  { 
Packit 67cb25
    size_t i;
Packit 67cb25
    double scale = 1.0;
Packit 67cb25
Packit 67cb25
    for (i = 0 ; i < t->n; i++)
Packit 67cb25
      {
Packit 67cb25
        compute_moments (t->par * scale, t->chebmo + 25*i);
Packit 67cb25
        scale *= 0.5;
Packit 67cb25
      }
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
Packit 67cb25
void
Packit 67cb25
gsl_integration_qawo_table_free (gsl_integration_qawo_table * t)
Packit 67cb25
{
Packit 67cb25
  RETURN_IF_NULL (t);
Packit 67cb25
  free (t->chebmo);
Packit 67cb25
  free (t);
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static void
Packit 67cb25
compute_moments (double par, double *chebmo)
Packit 67cb25
{
Packit 67cb25
  double v[28], d[25], d1[25], d2[25];
Packit 67cb25
Packit 67cb25
  const size_t noeq = 25;
Packit 67cb25
  
Packit 67cb25
  const double par2 = par * par;
Packit 67cb25
  const double par4 = par2 * par2;
Packit 67cb25
  const double par22 = par2 + 2.0;
Packit 67cb25
Packit 67cb25
  const double sinpar = sin (par);
Packit 67cb25
  const double cospar = cos (par);
Packit 67cb25
Packit 67cb25
  size_t i;
Packit 67cb25
Packit 67cb25
  /* compute the chebyschev moments with respect to cosine */
Packit 67cb25
Packit 67cb25
  double ac = 8 * cospar;
Packit 67cb25
  double as = 24 * par * sinpar;
Packit 67cb25
Packit 67cb25
  v[0] = 2 * sinpar / par;
Packit 67cb25
  v[1] = (8 * cospar + (2 * par2 - 8) * sinpar / par) / par2;
Packit 67cb25
  v[2] = (32 * (par2 - 12) * cospar
Packit 67cb25
          + (2 * ((par2 - 80) * par2 + 192) * sinpar) / par) / par4;
Packit 67cb25
Packit 67cb25
  if (fabs (par) <= 24)
Packit 67cb25
    {
Packit 67cb25
      /* compute the moments as the solution of a boundary value
Packit 67cb25
         problem using the asyptotic expansion as an endpoint */
Packit 67cb25
      
Packit 67cb25
      double an2, ass, asap;
Packit 67cb25
      double an = 6;
Packit 67cb25
      size_t k;
Packit 67cb25
Packit 67cb25
      for (k = 0; k < noeq - 1; k++)
Packit 67cb25
        {
Packit 67cb25
          an2 = an * an;
Packit 67cb25
          d[k] = -2 * (an2 - 4) * (par22 - 2 * an2);
Packit 67cb25
          d2[k] = (an - 1) * (an - 2) * par2;
Packit 67cb25
          d1[k + 1] = (an + 3) * (an + 4) * par2;
Packit 67cb25
          v[k + 3] = as - (an2 - 4) * ac;
Packit 67cb25
          an = an + 2.0;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      an2 = an * an;
Packit 67cb25
Packit 67cb25
      d[noeq - 1] = -2 * (an2 - 4) * (par22 - 2 * an2);
Packit 67cb25
      v[noeq + 2] = as - (an2 - 4) * ac;
Packit 67cb25
      v[3] = v[3] - 56 * par2 * v[2];
Packit 67cb25
Packit 67cb25
      ass = par * sinpar;
Packit 67cb25
      asap = (((((210 * par2 - 1) * cospar - (105 * par2 - 63) * ass) / an2
Packit 67cb25
                - (1 - 15 * par2) * cospar + 15 * ass) / an2 
Packit 67cb25
               - cospar + 3 * ass) / an2 
Packit 67cb25
              - cospar) / an2;
Packit 67cb25
      v[noeq + 2] = v[noeq + 2] - 2 * asap * par2 * (an - 1) * (an - 2);
Packit 67cb25
Packit 67cb25
      dgtsl (noeq, d1, d, d2, v + 3);
Packit 67cb25
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      /* compute the moments by forward recursion */
Packit 67cb25
      size_t k;
Packit 67cb25
      double an = 4;
Packit 67cb25
Packit 67cb25
      for (k = 3; k < 13; k++)
Packit 67cb25
        {
Packit 67cb25
          double an2 = an * an;
Packit 67cb25
          v[k] = ((an2 - 4) * (2 * (par22 - 2 * an2) * v[k - 1] - ac)
Packit 67cb25
                  + as - par2 * (an + 1) * (an + 2) * v[k - 2]) 
Packit 67cb25
            / (par2 * (an - 1) * (an - 2));
Packit 67cb25
          an = an + 2.0;
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
Packit 67cb25
  for (i = 0; i < 13; i++)
Packit 67cb25
    {
Packit 67cb25
      chebmo[2 * i] = v[i];
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* compute the chebyschev moments with respect to sine */
Packit 67cb25
Packit 67cb25
  v[0] = 2 * (sinpar - par * cospar) / par2;
Packit 67cb25
  v[1] = (18 - 48 / par2) * sinpar / par2 + (-2 + 48 / par2) * cospar / par;
Packit 67cb25
Packit 67cb25
  ac = -24 * par * cospar;
Packit 67cb25
  as = -8 * sinpar;
Packit 67cb25
Packit 67cb25
  if (fabs (par) <= 24)
Packit 67cb25
    {
Packit 67cb25
      /* compute the moments as the solution of a boundary value
Packit 67cb25
         problem using the asyptotic expansion as an endpoint */
Packit 67cb25
Packit 67cb25
      size_t k;
Packit 67cb25
      double an2, ass, asap;
Packit 67cb25
      double an = 5;
Packit 67cb25
Packit 67cb25
      for (k = 0; k < noeq - 1; k++)
Packit 67cb25
        {
Packit 67cb25
          an2 = an * an;
Packit 67cb25
          d[k] = -2 * (an2 - 4) * (par22 - 2 * an2);
Packit 67cb25
          d2[k] = (an - 1) * (an - 2) * par2;
Packit 67cb25
          d1[k + 1] = (an + 3) * (an + 4) * par2;
Packit 67cb25
          v[k + 2] = ac + (an2 - 4) * as;
Packit 67cb25
          an = an + 2.0;
Packit 67cb25
        }
Packit 67cb25
      
Packit 67cb25
      an2 = an * an;
Packit 67cb25
Packit 67cb25
      d[noeq - 1] = -2 * (an2 - 4) * (par22 - 2 * an2);
Packit 67cb25
      v[noeq + 1] = ac + (an2 - 4) * as;
Packit 67cb25
      v[2] = v[2] - 42 * par2 * v[1];
Packit 67cb25
Packit 67cb25
      ass = par * cospar;
Packit 67cb25
      asap = (((((105 * par2 - 63) * ass - (210 * par2 - 1) * sinpar) / an2
Packit 67cb25
                + (15 * par2 - 1) * sinpar
Packit 67cb25
                - 15 * ass) / an2 - sinpar - 3 * ass) / an2 - sinpar) / an2;
Packit 67cb25
      v[noeq + 1] = v[noeq + 1] - 2 * asap * par2 * (an - 1) * (an - 2);
Packit 67cb25
Packit 67cb25
      dgtsl (noeq, d1, d, d2, v + 2);
Packit 67cb25
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      /* compute the moments by forward recursion */
Packit 67cb25
      size_t k;
Packit 67cb25
      double an = 3;
Packit 67cb25
      for (k = 2; k < 12; k++)
Packit 67cb25
        {
Packit 67cb25
          double an2 = an * an;
Packit 67cb25
          v[k] = ((an2 - 4) * (2 * (par22 - 2 * an2) * v[k - 1] + as)
Packit 67cb25
                  + ac - par2 * (an + 1) * (an + 2) * v[k - 2]) 
Packit 67cb25
            / (par2 * (an - 1) * (an - 2));
Packit 67cb25
          an = an + 2.0;
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  for (i = 0; i < 12; i++)
Packit 67cb25
    {
Packit 67cb25
      chebmo[2 * i + 1] = v[i];
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
dgtsl (size_t n, double *c, double *d, double *e, double *b)
Packit 67cb25
{
Packit 67cb25
  /* solves a tridiagonal matrix A x = b 
Packit 67cb25
     
Packit 67cb25
     c[1 .. n - 1]   subdiagonal of the matrix A
Packit 67cb25
     d[0 .. n - 1]   diagonal of the matrix A
Packit 67cb25
     e[0 .. n - 2]   superdiagonal of the matrix A
Packit 67cb25
Packit 67cb25
     b[0 .. n - 1]   right hand side, replaced by the solution vector x */
Packit 67cb25
Packit 67cb25
  size_t k;
Packit 67cb25
Packit 67cb25
  c[0] = d[0];
Packit 67cb25
Packit 67cb25
  if (n == 0)
Packit 67cb25
    {
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  if (n == 1)
Packit 67cb25
    {
Packit 67cb25
      b[0] = b[0] / d[0] ;
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  d[0] = e[0];
Packit 67cb25
  e[0] = 0;
Packit 67cb25
  e[n - 1] = 0;
Packit 67cb25
Packit 67cb25
  for (k = 0; k < n - 1; k++)
Packit 67cb25
    {
Packit 67cb25
      size_t k1 = k + 1;
Packit 67cb25
Packit 67cb25
      if (fabs (c[k1]) >= fabs (c[k]))
Packit 67cb25
        {
Packit 67cb25
          {
Packit 67cb25
            double t = c[k1];
Packit 67cb25
            c[k1] = c[k];
Packit 67cb25
            c[k] = t;
Packit 67cb25
          };
Packit 67cb25
          {
Packit 67cb25
            double t = d[k1];
Packit 67cb25
            d[k1] = d[k];
Packit 67cb25
            d[k] = t;
Packit 67cb25
          };
Packit 67cb25
          {
Packit 67cb25
            double t = e[k1];
Packit 67cb25
            e[k1] = e[k];
Packit 67cb25
            e[k] = t;
Packit 67cb25
          };
Packit 67cb25
          {
Packit 67cb25
            double t = b[k1];
Packit 67cb25
            b[k1] = b[k];
Packit 67cb25
            b[k] = t;
Packit 67cb25
          };
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      if (c[k] == 0)
Packit 67cb25
        {
Packit 67cb25
          return GSL_FAILURE ;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      {
Packit 67cb25
        double t = -c[k1] / c[k];
Packit 67cb25
Packit 67cb25
        c[k1] = d[k1] + t * d[k];
Packit 67cb25
        d[k1] = e[k1] + t * e[k];
Packit 67cb25
        e[k1] = 0;
Packit 67cb25
        b[k1] = b[k1] + t * b[k];
Packit 67cb25
      }
Packit 67cb25
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  if (c[n - 1] == 0)
Packit 67cb25
    {
Packit 67cb25
      return GSL_FAILURE;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
Packit 67cb25
  b[n - 1] = b[n - 1] / c[n - 1];
Packit 67cb25
Packit 67cb25
  b[n - 2] = (b[n - 2] - d[n - 2] * b[n - 1]) / c[n - 2];
Packit 67cb25
Packit 67cb25
  for (k = n ; k > 2; k--)
Packit 67cb25
    {
Packit 67cb25
      size_t kb = k - 3;
Packit 67cb25
      b[kb] = (b[kb] - d[kb] * b[kb + 1] - e[kb] * b[kb + 2]) / c[kb];
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}