|
Packit |
67cb25 |
/* specfunc/legendre_source.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 2009-2013 Patrick Alken
|
|
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 |
/* define various macros for functions below */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#define CONCAT2x(a,b) a ## _ ## b
|
|
Packit |
67cb25 |
#define CONCAT3x(a,b,c) a ## _ ## b ## _ ## c
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#if defined(LEGENDRE)
|
|
Packit |
67cb25 |
#define FUNCTION(dir,name) CONCAT2x(dir,name)
|
|
Packit |
67cb25 |
#define OUTPUT result_array
|
|
Packit |
67cb25 |
#define OUTPUT_ARG double result_array[]
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#elif defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
#define FUNCTION(dir,name) CONCAT3x(dir,deriv,name)
|
|
Packit |
67cb25 |
#define OUTPUT result_array, result_deriv_array
|
|
Packit |
67cb25 |
#define OUTPUT_ARG double result_array[], double result_deriv_array[]
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#elif defined(LEGENDRE_DERIV_ALT)
|
|
Packit |
67cb25 |
#define FUNCTION(dir,name) CONCAT3x(dir,deriv_alt,name)
|
|
Packit |
67cb25 |
#define OUTPUT result_array, result_deriv_array
|
|
Packit |
67cb25 |
#define OUTPUT_ARG double result_array[], double result_deriv_array[]
|
|
Packit |
67cb25 |
#define LEGENDRE_DERIV
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#elif defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
#define FUNCTION(dir,name) CONCAT3x(dir,deriv2,name)
|
|
Packit |
67cb25 |
#define OUTPUT result_array, result_deriv_array, result_deriv2_array
|
|
Packit |
67cb25 |
#define OUTPUT_ARG double result_array[], double result_deriv_array[], double result_deriv2_array[]
|
|
Packit |
67cb25 |
#define LEGENDRE_DERIV
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#elif defined(LEGENDRE_DERIV2_ALT)
|
|
Packit |
67cb25 |
#define FUNCTION(dir,name) CONCAT3x(dir,deriv2_alt,name)
|
|
Packit |
67cb25 |
#define OUTPUT result_array, result_deriv_array, result_deriv2_array
|
|
Packit |
67cb25 |
#define OUTPUT_ARG double result_array[], double result_deriv_array[], double result_deriv2_array[]
|
|
Packit |
67cb25 |
#define LEGENDRE_DERIV
|
|
Packit |
67cb25 |
#define LEGENDRE_DERIV2
|
|
Packit |
67cb25 |
#define LEGENDRE_DERIV_ALT
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int FUNCTION (legendre, array_schmidt_e)
|
|
Packit |
67cb25 |
(const size_t lmax, const double x, const double csphase, OUTPUT_ARG);
|
|
Packit |
67cb25 |
static int FUNCTION(legendre, array_none_e)
|
|
Packit |
67cb25 |
(const size_t lmax, const double x, const double csphase, OUTPUT_ARG);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_sf_legendre_array()
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: norm - normlization type
|
|
Packit |
67cb25 |
lmax - maximum degree
|
|
Packit |
67cb25 |
x - input argument
|
|
Packit |
67cb25 |
result_array - (output) normalized P_{lm}
|
|
Packit |
67cb25 |
result_deriv_array - (output) normalized P'_{lm}
|
|
Packit |
67cb25 |
result_deriv2_array - (output) normalized P''_{lm}
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
FUNCTION (gsl_sf_legendre, array)
|
|
Packit |
67cb25 |
(const gsl_sf_legendre_t norm, const size_t lmax, const double x,
|
|
Packit |
67cb25 |
OUTPUT_ARG)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int s = FUNCTION (gsl_sf_legendre, array_e)(norm, lmax, x, 1.0, OUTPUT);
|
|
Packit |
67cb25 |
return s;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_sf_legendre_array_e()
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: norm - normlization type
|
|
Packit |
67cb25 |
lmax - maximum degree
|
|
Packit |
67cb25 |
x - input argument
|
|
Packit |
67cb25 |
csphase - Condon-Shortley phase
|
|
Packit |
67cb25 |
result_array - (output) normalized P_{lm}
|
|
Packit |
67cb25 |
result_deriv_array - (output) normalized P'_{lm}
|
|
Packit |
67cb25 |
result_deriv2_array - (output) normalized P''_{lm}
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
FUNCTION (gsl_sf_legendre, array_e)
|
|
Packit |
67cb25 |
(const gsl_sf_legendre_t norm, const size_t lmax, const double x,
|
|
Packit |
67cb25 |
const double csphase, OUTPUT_ARG)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int s;
|
|
Packit |
67cb25 |
const size_t nlm = gsl_sf_legendre_nlm(lmax);
|
|
Packit |
67cb25 |
#if !defined(LEGENDRE_DERIV_ALT)
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV) || defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
const double u = sqrt((1.0 - x) * (1.0 + x));
|
|
Packit |
67cb25 |
const double uinv = 1.0 / u;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
const double uinv2 = uinv * uinv;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
double fac1 = 0.0, fac2 = 0.0; /* normalization factors */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (norm == GSL_SF_LEGENDRE_NONE)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* compute P_{lm}(x) */
|
|
Packit |
67cb25 |
s = FUNCTION(legendre,array_none_e)(lmax, x, csphase, OUTPUT);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* compute S_{lm}(x) */
|
|
Packit |
67cb25 |
s = FUNCTION(legendre,array_schmidt_e)(lmax, x, csphase, OUTPUT);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#if !defined(LEGENDRE_DERIV_ALT)
|
|
Packit |
67cb25 |
/* scale derivative arrays to recover P'(x) and P''(x) */
|
|
Packit |
67cb25 |
for (i = 0; i < nlm; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
double dp = result_deriv_array[i];
|
|
Packit |
67cb25 |
double d2p = result_deriv2_array[i];
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result_deriv2_array[i] = (d2p - x * uinv * dp) * uinv2;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[i] *= -uinv;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* apply scaling for requested normalization */
|
|
Packit |
67cb25 |
if (norm == GSL_SF_LEGENDRE_SCHMIDT || norm == GSL_SF_LEGENDRE_NONE)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return s;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (norm == GSL_SF_LEGENDRE_SPHARM)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
fac1 = 1.0 / sqrt(4.0 * M_PI);
|
|
Packit |
67cb25 |
fac2 = 1.0 / sqrt(8.0 * M_PI);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (norm == GSL_SF_LEGENDRE_FULL)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
fac1 = 1.0 / sqrt(2.0);
|
|
Packit |
67cb25 |
fac2 = 1.0 / sqrt(4.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* common code for different normalizations
|
|
Packit |
67cb25 |
* P_{l0} = fac1 * sqrt(2l + 1) * S_{l0}
|
|
Packit |
67cb25 |
* P_{lm} = fac2 * sqrt(2l + 1) * S_{lm}, m > 0
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t l, m;
|
|
Packit |
67cb25 |
size_t twoellp1 = 1; /* 2l + 1 */
|
|
Packit |
67cb25 |
double *sqrts = &(result_array[nlm]);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (l = 0; l <= lmax; ++l)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
result_array[gsl_sf_legendre_array_index(l, 0)] *=
|
|
Packit |
67cb25 |
sqrts[twoellp1] * fac1;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[gsl_sf_legendre_array_index(l, 0)] *=
|
|
Packit |
67cb25 |
sqrts[twoellp1] * fac1;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[gsl_sf_legendre_array_index(l, 0)] *=
|
|
Packit |
67cb25 |
sqrts[twoellp1] * fac1;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (m = 1; m <= l; ++m)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
result_array[gsl_sf_legendre_array_index(l, m)] *=
|
|
Packit |
67cb25 |
sqrts[twoellp1] * fac2;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[gsl_sf_legendre_array_index(l, m)] *=
|
|
Packit |
67cb25 |
sqrts[twoellp1] * fac2;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[gsl_sf_legendre_array_index(l, m)] *=
|
|
Packit |
67cb25 |
sqrts[twoellp1] * fac2;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
twoellp1 += 2;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return s;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
legendre,array_schmidt_e()
|
|
Packit |
67cb25 |
This routine computes Schmidt semi-normalized associated
|
|
Packit |
67cb25 |
Legendre polynomials and their first and second derivatives.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: lmax - maximum order
|
|
Packit |
67cb25 |
x - legendre argument in [-1,1]
|
|
Packit |
67cb25 |
csphase - -1.0 to include CS phase (-1)^m,
|
|
Packit |
67cb25 |
1.0 to not include
|
|
Packit |
67cb25 |
result_array - (output) where to store P_{lm}(x) values
|
|
Packit |
67cb25 |
result_deriv_array - (output) where to store
|
|
Packit |
67cb25 |
d/dtheta P_{lm}(x) values
|
|
Packit |
67cb25 |
result_deriv2_array - (output) where to store
|
|
Packit |
67cb25 |
d^2/dtheta^2 P_{lm}(x) values
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
FUNCTION(legendre, array_schmidt_e)
|
|
Packit |
67cb25 |
(const size_t lmax, const double x, const double csphase, OUTPUT_ARG)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (x > 1.0 || x < -1.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("x is outside [-1,1]", GSL_EDOM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV) || defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
else if (fabs(x) == 1.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("x cannot equal 1 or -1 for derivative computation", GSL_EDOM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
else if (csphase != 1.0 && csphase != -1.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("csphase has invalid value", GSL_EDOM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const double eps = 1.0e-280;
|
|
Packit |
67cb25 |
const double u = sqrt((1.0 - x) * (1.0 + x)); /* sin(theta) */
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
const double uinv = 1.0 / u;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
const double uinv2 = 1.0 / u / u;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV) || defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
const double xbyu = x * uinv; /* x / u */
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
size_t l, m;
|
|
Packit |
67cb25 |
size_t k, idxmm;
|
|
Packit |
67cb25 |
double plm, /* eps * S(l,m) / u^m */
|
|
Packit |
67cb25 |
pmm; /* eps * S(m,m) / u^m */
|
|
Packit |
67cb25 |
double rescalem;
|
|
Packit |
67cb25 |
double pm1, /* S(l-1,m) */
|
|
Packit |
67cb25 |
pm2; /* S(l-2,m) */
|
|
Packit |
67cb25 |
size_t nlm = gsl_sf_legendre_nlm(lmax);
|
|
Packit |
67cb25 |
double *sqrts = &(result_array[nlm]);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* precompute square root factors for recurrence */
|
|
Packit |
67cb25 |
legendre_sqrts(lmax, sqrts);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initial values S(0,0) and S(1,0) */
|
|
Packit |
67cb25 |
pm2 = 1.0; /* S(0,0) */
|
|
Packit |
67cb25 |
pm1 = x; /* S(1,0) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result_array[0] = pm2;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[0] = 0.0;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[0] = 0.0;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (lmax == 0)
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result_array[1] = pm1;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[1] = -u;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[1] = -x;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Compute S(l,0) for l=2..lmax, no scaling required */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
k = 1; /* idx(1,0) */
|
|
Packit |
67cb25 |
for (l = 2; l <= lmax; ++l)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double linv = 1.0 / (double)l;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
k += l; /* idx(l,m) = idx(l-1,m) + l */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
plm = (2.0 - linv) * x * pm1 - (1.0 - linv) * pm2;
|
|
Packit |
67cb25 |
result_array[k] = plm;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[k] = uinv * l * (x * plm - pm1);
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[k] = -(double) l * (l + 1.0) * plm -
|
|
Packit |
67cb25 |
xbyu * result_deriv_array[k];
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
pm2 = pm1;
|
|
Packit |
67cb25 |
pm1 = plm;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Compute S(m,m), S(m+1,m) and S(l,m) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* pi_m = Prod_{i=2}^m sqrt[ (2m - 1) / (2m) ]
|
|
Packit |
67cb25 |
* but pi_1 = 1.0, so initialize to sqrt(2) so that
|
|
Packit |
67cb25 |
* the first m = 1 iteration of the loop will reset it
|
|
Packit |
67cb25 |
* to 1.0. Starting with m = 2 it will begin accumulating
|
|
Packit |
67cb25 |
* the correct terms.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* pmm = S(m,m) * eps / u^m = pi_m
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
pmm = sqrt(2.0) * eps;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
rescalem = 1.0 / eps;
|
|
Packit |
67cb25 |
idxmm = 0; /* tracks idx(m,m), initialize to idx(0,0) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (m = 1; m < lmax; ++m)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* rescalem = u^m / eps */
|
|
Packit |
67cb25 |
rescalem *= u;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* compute:
|
|
Packit |
67cb25 |
* S(m,m) = u * sqrt((2m - 1) / (2m)) S(m-1,m-1) = u^m * pi_m
|
|
Packit |
67cb25 |
* d_t S(m,m) = m * x / u * S(m,m)
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
idxmm += m + 1; /* idx(m,m) = idx(m-1,m-1) + m + 1 */
|
|
Packit |
67cb25 |
pmm *= csphase * sqrts[2 * m - 1] / sqrts[2 * m]; /* S(m,m) * eps / u^m */
|
|
Packit |
67cb25 |
result_array[idxmm] = pmm * rescalem;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[idxmm] = m * xbyu * result_array[idxmm];
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[idxmm] =
|
|
Packit |
67cb25 |
m * (uinv2 * m - (m + 1.0)) * result_array[idxmm] -
|
|
Packit |
67cb25 |
xbyu * result_deriv_array[idxmm];
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
pm2 = pmm;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* compute:
|
|
Packit |
67cb25 |
* S(m+1,m) = sqrt(2 * m + 1) * x * S(m,m)
|
|
Packit |
67cb25 |
* d_t S(m+1,m) = 1/u * ((m+1)*x*S(m+1,m) - sqrt(2*m+1)*S(m,m))
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
k = idxmm + m + 1; /* idx(m+1,m) = idx(m,m) + m + 1 */
|
|
Packit |
67cb25 |
pm1 = x * sqrts[2 * m + 1] * pm2;
|
|
Packit |
67cb25 |
result_array[k] = pm1 * rescalem;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[k] =
|
|
Packit |
67cb25 |
uinv * ((m + 1.0) * x * result_array[k] -
|
|
Packit |
67cb25 |
sqrts[2 * m + 1] * result_array[idxmm]);
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[k] =
|
|
Packit |
67cb25 |
(m * m * uinv2 - (m + 1.0) * (m + 2.0)) * result_array[k] -
|
|
Packit |
67cb25 |
xbyu * result_deriv_array[k];
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute S(l,m) for l=m+2...lmax */
|
|
Packit |
67cb25 |
for (l = m + 2; l <= lmax; ++l)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
k += l; /* idx(l,m) = idx(l-1,m) + l */
|
|
Packit |
67cb25 |
plm =
|
|
Packit |
67cb25 |
(2*l - 1) / sqrts[l + m] / sqrts[l - m] * x * pm1 -
|
|
Packit |
67cb25 |
sqrts[l - m - 1] * sqrts[l + m - 1] /
|
|
Packit |
67cb25 |
sqrts[l + m] / sqrts[l - m] * pm2;
|
|
Packit |
67cb25 |
result_array[k] = plm * rescalem;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[k] =
|
|
Packit |
67cb25 |
uinv * (l * x * result_array[k] -
|
|
Packit |
67cb25 |
sqrts[l + m] * sqrts[l - m] * result_array[k - l]);
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[k] =
|
|
Packit |
67cb25 |
(m * m * uinv2 - l * (l + 1.0)) * result_array[k] -
|
|
Packit |
67cb25 |
xbyu * result_deriv_array[k];
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
pm2 = pm1;
|
|
Packit |
67cb25 |
pm1 = plm;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* for (m = 1; m < lmax; ++m) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute S(lmax,lmax) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
rescalem *= u;
|
|
Packit |
67cb25 |
idxmm += m + 1; /* idx(lmax,lmax) */
|
|
Packit |
67cb25 |
pmm *= csphase * sqrts[2 * lmax - 1] / sqrts[2 * lmax];
|
|
Packit |
67cb25 |
result_array[idxmm] = pmm * rescalem;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[idxmm] = lmax * xbyu * result_array[idxmm];
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[idxmm] =
|
|
Packit |
67cb25 |
lmax * (uinv2 * lmax - (lmax + 1.0)) * result_array[idxmm] -
|
|
Packit |
67cb25 |
xbyu * result_deriv_array[idxmm];
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
legendre_array_none_e()
|
|
Packit |
67cb25 |
This routine computes unnormalized associated Legendre polynomials
|
|
Packit |
67cb25 |
and their derivatives.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: lmax - maximum order
|
|
Packit |
67cb25 |
x - legendre argument in [-1,1]
|
|
Packit |
67cb25 |
csphase - -1.0 to include CS phase (-1)^m,
|
|
Packit |
67cb25 |
1.0 to not include
|
|
Packit |
67cb25 |
result_array - (output) where to store P_{lm}(x) values
|
|
Packit |
67cb25 |
result_deriv_array - (output) where to store
|
|
Packit |
67cb25 |
d/dtheta P_{lm}(x) values
|
|
Packit |
67cb25 |
result_deriv2_array - (output) where to store
|
|
Packit |
67cb25 |
d^2/dtheta^2 P_{lm}(x) values
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
FUNCTION(legendre, array_none_e)
|
|
Packit |
67cb25 |
(const size_t lmax, const double x, const double csphase, OUTPUT_ARG)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (x > 1.0 || x < -1.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("x is outside [-1,1]", GSL_EDOM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV) || defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
else if (fabs(x) == 1.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("x cannot equal 1 or -1 for derivative computation", GSL_EDOM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
else if (csphase != 1.0 && csphase != -1.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("csphase has invalid value", GSL_EDOM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const double u = sqrt((1.0 - x) * (1.0 + x)); /* sin(theta) */
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
const double uinv = 1.0 / u;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
const double uinv2 = 1.0 / u / u;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV) || defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
const double xbyu = x * uinv; /* x / u */
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
size_t l, m;
|
|
Packit |
67cb25 |
size_t k, idxmm;
|
|
Packit |
67cb25 |
double plm, pmm;
|
|
Packit |
67cb25 |
double pm1, /* P(l-1,m) */
|
|
Packit |
67cb25 |
pm2; /* P(l-2,m) */
|
|
Packit |
67cb25 |
double twomm1; /* 2*m - 1 */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initial values P(0,0) and P(1,0) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
pm2 = 1.0; /* P(0,0) */
|
|
Packit |
67cb25 |
pm1 = x; /* P(1,0) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result_array[0] = pm2;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[0] = 0.0;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[0] = 0.0;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (lmax == 0)
|
|
Packit |
67cb25 |
return 0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result_array[1] = pm1;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[1] = -u;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[1] = -x;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Compute P(l,0) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
k = 1;
|
|
Packit |
67cb25 |
for (l = 2; l <= lmax; ++l)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
k += l;
|
|
Packit |
67cb25 |
plm = ((2*l - 1) * x * pm1 - (l - 1) * pm2) / (double) l;
|
|
Packit |
67cb25 |
result_array[k] = plm;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[k] = -(double)l * (pm1 - x * plm) * uinv;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[k] = -(double) l * (l + 1.0) * plm -
|
|
Packit |
67cb25 |
xbyu * result_deriv_array[k];
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
pm2 = pm1;
|
|
Packit |
67cb25 |
pm1 = plm;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Compute P(m,m), P(m+1,m) and P(l,m) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
pmm = 1.0;
|
|
Packit |
67cb25 |
twomm1 = -1.0; /* 2 * m - 1 */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
idxmm = 0; /* tracks idx(m,m), initialize to idx(0,0) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (m = 1; m <= lmax - 1; ++m)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* compute
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* P(m,m) = u * (2m - 1) P(m-1,m-1)
|
|
Packit |
67cb25 |
* and
|
|
Packit |
67cb25 |
* dP(m,m)/dtheta = m * x * P(m,m) / u
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
idxmm += m + 1;
|
|
Packit |
67cb25 |
twomm1 += 2.0;
|
|
Packit |
67cb25 |
pmm *= csphase * u * twomm1;
|
|
Packit |
67cb25 |
result_array[idxmm] = pmm;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[idxmm] = m * xbyu * pmm;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[idxmm] =
|
|
Packit |
67cb25 |
m * (uinv2 * m - (m + 1.0)) * result_array[idxmm] -
|
|
Packit |
67cb25 |
xbyu * result_deriv_array[idxmm];
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
pm2 = pmm;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* compute
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* P(m+1,m) = (2 * m + 1) * x * P(m,m)
|
|
Packit |
67cb25 |
* and
|
|
Packit |
67cb25 |
* dP(m+1,m)/dt = -[(2*m + 1) * P(m,m) - (m+1) * x * P(m+1,m)]/u
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
k = idxmm + m + 1;
|
|
Packit |
67cb25 |
pm1 = x * pmm * (2*m + 1);
|
|
Packit |
67cb25 |
result_array[k] = pm1;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[k] = -uinv * ((2*m + 1) * pmm - (m + 1) * x * pm1);
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[k] =
|
|
Packit |
67cb25 |
(m * m * uinv2 - (m + 1.0) * (m + 2.0)) * result_array[k] -
|
|
Packit |
67cb25 |
xbyu * result_deriv_array[k];
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute P(l,m) */
|
|
Packit |
67cb25 |
for (l = m + 2; l <= lmax; ++l)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
k += l;
|
|
Packit |
67cb25 |
plm = ((2*l - 1) * x * pm1 - (l + m - 1) * pm2) /
|
|
Packit |
67cb25 |
(double) (l - m);
|
|
Packit |
67cb25 |
result_array[k] = plm;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[k] = -uinv * ((l + m) * pm1 - l * x * plm);
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[k] =
|
|
Packit |
67cb25 |
(m * m * uinv2 - l * (l + 1.0)) * result_array[k] -
|
|
Packit |
67cb25 |
xbyu * result_deriv_array[k];
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
pm2 = pm1;
|
|
Packit |
67cb25 |
pm1 = plm;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* for (m = 1; m <= lmax - 1; ++m) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute P(lmax,lmax) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
idxmm += m + 1;
|
|
Packit |
67cb25 |
twomm1 += 2.0;
|
|
Packit |
67cb25 |
pmm *= csphase * u * twomm1;
|
|
Packit |
67cb25 |
result_array[idxmm] = pmm;
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV)
|
|
Packit |
67cb25 |
result_deriv_array[idxmm] = lmax * x * pmm * uinv;
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
#if defined(LEGENDRE_DERIV2)
|
|
Packit |
67cb25 |
result_deriv2_array[idxmm] =
|
|
Packit |
67cb25 |
lmax * (uinv2 * lmax - (lmax + 1.0)) * result_array[idxmm] -
|
|
Packit |
67cb25 |
xbyu * result_deriv_array[idxmm];
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* legendre_array_none_e() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#undef FUNCTION
|
|
Packit |
67cb25 |
#undef CONCAT2x
|
|
Packit |
67cb25 |
#undef CONCAT3x
|
|
Packit |
67cb25 |
#undef OUTPUT
|
|
Packit |
67cb25 |
#undef OUTPUT_ARG
|
|
Packit |
67cb25 |
#undef LEGENDRE_DERIV
|
|
Packit |
67cb25 |
#undef LEGENDRE_DERIV2
|
|
Packit |
67cb25 |
#undef LEGENDRE_DERIV_ALT
|