|
Packit |
67cb25 |
/* specfunc/bessel_sequence.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
|
|
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 |
/* Author: G. Jungman */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include <config.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_math.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_errno.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_sf_bessel.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#define DYDX_p(p,u,x) (-(p)/(x) + (((nu)*(nu))/((x)*(x))-1.0)*(u))
|
|
Packit |
67cb25 |
#define DYDX_u(p,u,x) (p)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
rk_step(double nu, double x, double dx, double * Jp, double * J)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double p_0 = *Jp;
|
|
Packit |
67cb25 |
double u_0 = *J;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double p_1 = dx * DYDX_p(p_0, u_0, x);
|
|
Packit |
67cb25 |
double u_1 = dx * DYDX_u(p_0, u_0, x);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double p_2 = dx * DYDX_p(p_0 + 0.5*p_1, u_0 + 0.5*u_1, x + 0.5*dx);
|
|
Packit |
67cb25 |
double u_2 = dx * DYDX_u(p_0 + 0.5*p_1, u_0 + 0.5*u_1, x + 0.5*dx);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double p_3 = dx * DYDX_p(p_0 + 0.5*p_2, u_0 + 0.5*u_2, x + 0.5*dx);
|
|
Packit |
67cb25 |
double u_3 = dx * DYDX_u(p_0 + 0.5*p_2, u_0 + 0.5*u_2, x + 0.5*dx);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double p_4 = dx * DYDX_p(p_0 + p_3, u_0 + u_3, x + dx);
|
|
Packit |
67cb25 |
double u_4 = dx * DYDX_u(p_0 + p_3, u_0 + u_3, x + dx);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*Jp = p_0 + p_1/6.0 + p_2/3.0 + p_3/3.0 + p_4/6.0;
|
|
Packit |
67cb25 |
*J = u_0 + u_1/6.0 + u_2/3.0 + u_3/3.0 + u_4/6.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_sequence_Jnu_e(double nu, gsl_mode_t mode, size_t size, double * v)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* CHECK_POINTER(v) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(nu < 0.0) {
|
|
Packit |
67cb25 |
GSL_ERROR ("domain error", GSL_EDOM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if(size == 0) {
|
|
Packit |
67cb25 |
GSL_ERROR ("error", GSL_EINVAL);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
const gsl_prec_t goal = GSL_MODE_PREC(mode);
|
|
Packit |
67cb25 |
const double dx_array[] = { 0.001, 0.03, 0.1 }; /* double, single, approx */
|
|
Packit |
67cb25 |
const double dx_nominal = dx_array[goal];
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
const int cnu = (int) ceil(nu);
|
|
Packit |
67cb25 |
const double nu13 = pow(nu,1.0/3.0);
|
|
Packit |
67cb25 |
const double smalls[] = { 0.01, 0.02, 0.4, 0.7, 1.3, 2.0, 2.5, 3.2, 3.5, 4.5, 6.0 };
|
|
Packit |
67cb25 |
const double x_small = ( nu >= 10.0 ? nu - nu13 : smalls[cnu] );
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_sf_result J0, J1;
|
|
Packit |
67cb25 |
double Jp, J;
|
|
Packit |
67cb25 |
double x;
|
|
Packit |
67cb25 |
size_t i = 0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Calculate the first point. */
|
|
Packit |
67cb25 |
x = v[0];
|
|
Packit |
67cb25 |
gsl_sf_bessel_Jnu_e(nu, x, &J0;;
|
|
Packit |
67cb25 |
v[0] = J0.val;
|
|
Packit |
67cb25 |
++i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Step over the idiot case where the
|
|
Packit |
67cb25 |
* first point was actually zero.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
if(x == 0.0) {
|
|
Packit |
67cb25 |
if(v[1] <= x) {
|
|
Packit |
67cb25 |
/* Strict ordering failure. */
|
|
Packit |
67cb25 |
GSL_ERROR ("error", GSL_EFAILED);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
x = v[1];
|
|
Packit |
67cb25 |
gsl_sf_bessel_Jnu_e(nu, x, &J0;;
|
|
Packit |
67cb25 |
v[1] = J0.val;
|
|
Packit |
67cb25 |
++i;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Calculate directly as long as the argument
|
|
Packit |
67cb25 |
* is small. This is necessary because the
|
|
Packit |
67cb25 |
* integration is not very good there.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
while(v[i] < x_small && i < size) {
|
|
Packit |
67cb25 |
if(v[i] <= x) {
|
|
Packit |
67cb25 |
/* Strict ordering failure. */
|
|
Packit |
67cb25 |
GSL_ERROR ("error", GSL_EFAILED);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
x = v[i];
|
|
Packit |
67cb25 |
gsl_sf_bessel_Jnu_e(nu, x, &J0;;
|
|
Packit |
67cb25 |
v[i] = J0.val;
|
|
Packit |
67cb25 |
++i;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* At this point we are ready to integrate.
|
|
Packit |
67cb25 |
* The value of x is the last calculated
|
|
Packit |
67cb25 |
* point, which has the value J0; v[i] is
|
|
Packit |
67cb25 |
* the next point we need to calculate. We
|
|
Packit |
67cb25 |
* calculate nu+1 at x as well to get
|
|
Packit |
67cb25 |
* the derivative, then we go forward.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
gsl_sf_bessel_Jnu_e(nu+1.0, x, &J1;;
|
|
Packit |
67cb25 |
J = J0.val;
|
|
Packit |
67cb25 |
Jp = -J1.val + nu/x * J0.val;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
while(i < size) {
|
|
Packit |
67cb25 |
const double dv = v[i] - x;
|
|
Packit |
67cb25 |
const int Nd = (int) ceil(dv/dx_nominal);
|
|
Packit |
67cb25 |
const double dx = dv / Nd;
|
|
Packit |
67cb25 |
double xj;
|
|
Packit |
67cb25 |
int j;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(v[i] <= x) {
|
|
Packit |
67cb25 |
/* Strict ordering failure. */
|
|
Packit |
67cb25 |
GSL_ERROR ("error", GSL_EFAILED);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Integrate over interval up to next sample point.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
for(j=0, xj=x; j
|
|
Packit |
67cb25 |
rk_step(nu, xj, dx, &Jp, &J);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Go to next interval. */
|
|
Packit |
67cb25 |
x = v[i];
|
|
Packit |
67cb25 |
v[i] = J;
|
|
Packit |
67cb25 |
++i;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|