Skip to content

Commit 0a0cad3

Browse files
author
Dag Sverre Seljebotn
committed
Python wrapper with test for Legendre transform
1 parent 351180b commit 0a0cad3

11 files changed

Lines changed: 165 additions & 0 deletions

File tree

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
*.o
2+
*.so
23
#*
34
*~
5+
*.pyc
6+
*.pyo
47

58
/auto
69
/autom4te.cache
@@ -9,3 +12,5 @@
912
/config/config.auto
1013
/configure
1114
/sharp_oracle.inc
15+
16+
/python/libsharp/libsharp.c

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,10 @@ perftest: compile_all
6161

6262
genclean:
6363
rm libsharp/sharp_legendre.c || exit 0
64+
65+
pytest:
66+
rm python/libsharp/libsharp.so || exit 0
67+
cd python && LIBSHARP_INCLUDE=$(INCDIR) LIBSHARP_LIB=$(LIBDIR) python setup.py build_ext --inplace
68+
cd python && nosetests libsharp
69+
70+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# work around broken setuptools monkey patching
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build_ext = "yes, it's there!"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# work around broken setuptools monkey patching

python/fake_pyrex/README

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This directory is here to fool setuptools into building .pyx files
2+
even if Pyrex is not installed. See ../setup.py.

python/libsharp/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .libsharp import *

python/libsharp/libsharp.pyx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import numpy as np
2+
3+
cdef extern from "sharp.h":
4+
ctypedef long ptrdiff_t
5+
6+
void sharp_legendre_transform_s(float *bl, float *recfac, ptrdiff_t lmax, float *x,
7+
float *out, ptrdiff_t nx)
8+
void sharp_legendre_transform(double *bl, double *recfac, ptrdiff_t lmax, double *x,
9+
double *out, ptrdiff_t nx)
10+
void sharp_legendre_transform_recfac(double *r, ptrdiff_t lmax)
11+
void sharp_legendre_transform_recfac_s(float *r, ptrdiff_t lmax)
12+
13+
14+
def legendre_transform(x, bl, out=None):
15+
if out is None:
16+
out = np.empty_like(x)
17+
if x.dtype == np.float64:
18+
if bl.dtype != np.float64:
19+
bl = bl.astype(np.float64)
20+
return _legendre_transform(x, bl, out=out)
21+
elif x.dtype == np.float32:
22+
if bl.dtype != np.float32:
23+
bl = bl.astype(np.float32)
24+
return _legendre_transform_s(x, bl, out=out)
25+
else:
26+
raise ValueError("unsupported dtype")
27+
28+
29+
def _legendre_transform(double[::1] x, double[::1] bl, double[::1] out):
30+
if out.shape[0] != x.shape[0]:
31+
raise ValueError('x and out must have same shape')
32+
sharp_legendre_transform(&bl[0], NULL, bl.shape[0] - 1, &x[0], &out[0], x.shape[0])
33+
return np.asarray(out)
34+
35+
36+
def _legendre_transform_s(float[::1] x, float[::1] bl, float[::1] out):
37+
if out.shape[0] != x.shape[0]:
38+
raise ValueError('x and out must have same shape')
39+
sharp_legendre_transform_s(&bl[0], NULL, bl.shape[0] - 1, &x[0], &out[0], x.shape[0])
40+
return np.asarray(out)
41+

python/libsharp/tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# empty
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import numpy as np
2+
from scipy.special import legendre
3+
import libsharp
4+
5+
6+
def test_legendre_transform():
7+
lmax = 20
8+
ntheta = 19
9+
10+
l = np.arange(lmax + 1)
11+
bl = np.exp(-l*(l+1))
12+
bl *= (2 * l + 1)
13+
14+
theta = np.linspace(0, np.pi, ntheta, endpoint=True)
15+
x = np.cos(theta)
16+
17+
# Compute truth using scipy.special.legendre
18+
P = np.zeros((ntheta, lmax + 1))
19+
for l in range(lmax + 1):
20+
P[:, l] = legendre(l)(x)
21+
y0 = np.dot(P, bl)
22+
23+
# double-precision
24+
y = libsharp.legendre_transform(x, bl)
25+
assert np.max(np.abs(y - y) / np.abs(y)) < 1e-12
26+
27+
# single-precision
28+
y32 = libsharp.legendre_transform(x.astype(np.float32), bl)
29+
assert np.max(np.abs(y32 - y) / np.abs(y32)) < 1e-4

0 commit comments

Comments
 (0)