sharp_legendre_table: Import Legendre table generating code from libpsht
Includes a Python wrapper. The code is tested and compared with SciPy results through the Python tests.
This commit is contained in:
parent
0787838ab3
commit
a93db0b1aa
9 changed files with 1616 additions and 5 deletions
|
@ -59,6 +59,9 @@ cdef extern from "sharp.h":
|
|||
sharp_alm_info *alm_info, int ntrans, int flags, double *time,
|
||||
unsigned long long *opcnt) nogil
|
||||
|
||||
void sharp_normalized_associated_legendre_table(int m, int lmax, int ntheta,
|
||||
double *theta, int ncols, double *out) nogil
|
||||
|
||||
|
||||
cdef extern from "sharp_geomhelpers.h":
|
||||
void sharp_make_subset_healpix_geom_info(
|
||||
|
@ -76,4 +79,3 @@ cdef extern from "sharp_almhelpers.h":
|
|||
void sharp_make_mmajor_real_packed_alm_info (int lmax, int stride,
|
||||
int nm, const int *ms, sharp_alm_info **alm_info)
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import numpy as np
|
||||
cimport cython
|
||||
|
||||
__all__ = ['legendre_transform', 'legendre_roots', 'sht', 'synthesis', 'adjoint_synthesis',
|
||||
'analysis', 'adjoint_analysis', 'healpix_grid', 'triangular_order', 'rectangular_order',
|
||||
'packed_real_order']
|
||||
'packed_real_order', 'normalized_associated_legendre_table']
|
||||
|
||||
|
||||
def legendre_transform(x, bl, out=None):
|
||||
|
@ -254,3 +255,17 @@ cdef class packed_real_order(alm_info):
|
|||
ms=NULL if ms is None else &ms[0],
|
||||
alm_info=&self.ainfo)
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
@cython.boundscheck(False)
|
||||
def normalized_associated_legendre_table(int lmax, int m, theta):
|
||||
cdef double[::1] theta_ = np.ascontiguousarray(theta, dtype=np.double)
|
||||
out = np.zeros((theta_.shape[0], lmax - m + 1), np.double)
|
||||
cdef double[:, ::1] out_ = out
|
||||
if lmax < m:
|
||||
raise ValueError("lmax < m")
|
||||
with nogil:
|
||||
sharp_normalized_associated_legendre_table(m, lmax, theta_.shape[0], &theta_[0], lmax - m + 1, &out_[0,0])
|
||||
return out
|
||||
|
|
|
@ -56,4 +56,3 @@ def test_legendre_roots():
|
|||
yield check_legendre_roots, 1
|
||||
yield check_legendre_roots, 32
|
||||
yield check_legendre_roots, 33
|
||||
yield check_legendre_roots, 128
|
||||
|
|
35
python/libsharp/tests/test_legendre_table.py
Normal file
35
python/libsharp/tests/test_legendre_table.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
import numpy as np
|
||||
|
||||
from numpy.testing import assert_almost_equal
|
||||
from nose.tools import eq_, ok_
|
||||
|
||||
from libsharp import normalized_associated_legendre_table
|
||||
from scipy.special import sph_harm, p_roots
|
||||
|
||||
def test_compare_legendre_table_with_scipy():
|
||||
def test(theta, m, lmax):
|
||||
Plm = normalized_associated_legendre_table(lmax, m, theta)
|
||||
|
||||
Plm_p = sph_harm(m, np.arange(m, lmax + 1), 0, theta)[None, :]
|
||||
if not np.allclose(Plm_p, Plm):
|
||||
print Plm_p
|
||||
print Plm
|
||||
return ok_, np.allclose(Plm_p, Plm)
|
||||
|
||||
yield test(np.pi/2, 0, 10)
|
||||
yield test(np.pi/4, 0, 10)
|
||||
yield test(3 * np.pi/4, 0, 10)
|
||||
yield test(np.pi/4, 1, 4)
|
||||
yield test(np.pi/4, 2, 4)
|
||||
yield test(np.pi/4, 50, 50)
|
||||
yield test(np.pi/2, 49, 50)
|
||||
|
||||
|
||||
def test_legendre_table_wrapper_logic():
|
||||
# tests the SSE 2 logic in the high-level wrapper by using an odd number of thetas
|
||||
theta = np.asarray([np.pi/2, np.pi/4, 3 * np.pi / 4])
|
||||
m = 3
|
||||
lmax = 10
|
||||
Plm = normalized_associated_legendre_table(lmax, m, theta)
|
||||
assert np.allclose(Plm[1, :], normalized_associated_legendre_table(lmax, m, np.pi/4)[0, :])
|
||||
assert np.allclose(Plm[2, :], normalized_associated_legendre_table(lmax, m, 3 * np.pi/4)[0, :])
|
Loading…
Add table
Add a link
Reference in a new issue