Skip to content

Commit 75a99b2

Browse files
committed
Rewrite conv_func classes to use ABC base for truncation.
Rewrite tests to be neater, easier to read. Add py34 to testing regime.
1 parent c1885ad commit 75a99b2

File tree

9 files changed

+162
-48
lines changed

9 files changed

+162
-48
lines changed

.travis.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ matrix:
33
include:
44
- python: "2.7"
55
env: TOXENV=py27
6+
- python: "3.4"
7+
env: TOXENV=py34
68
- python: "2.7"
79
env: TOXENV=docs
810

@@ -19,4 +21,4 @@ notifications:
1921
on_success: never
2022
on_failure: always
2123

22-
sudo: false
24+
sudo: false

docs/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33

44
# You can set these variables from the command line.
5-
SPHINXOPTS =
5+
SPHINXOPTS = -Wv
66
SPHINXBUILD = sphinx-build
77
PAPER =
88
BUILDDIR = build

docs/source/conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
todo_include_todos = False
6969

7070

71-
autoclass_content = 'both'
71+
autoclass_content = 'class'
7272
# napoleon_use_ivar = True
7373

7474
# Warn when references cannot be resolved:

docs/standalone_notebooks/convolutional_kernel_funcs.ipynb

+25-11
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"import matplotlib.pyplot as plt\n",
2020
"import matplotlib.image as mpimg\n",
2121
"import numpy as np\n",
22-
"%matplotlib inline\n",
22+
"%matplotlib notebook\n",
2323
"# Plot image pixels in cartesian ordering (i.e. y-positive == upwards):\n",
2424
"plt.rcParams['image.origin'] = 'lower'\n",
2525
"# Make plots bigger\n",
@@ -41,12 +41,25 @@
4141
"cell_type": "code",
4242
"execution_count": null,
4343
"metadata": {
44-
"collapsed": true
44+
"collapsed": false
4545
},
4646
"outputs": [],
4747
"source": [
4848
"triangle3 = conv_funcs.Triangle(half_base_width=3.0)\n",
49-
"pillbox = conv_funcs.Pillbox(half_base_width=2.5)"
49+
"pillbox = conv_funcs.Pillbox(half_base_width=2.5)\n",
50+
"sinc = conv_funcs.Sinc(3)"
51+
]
52+
},
53+
{
54+
"cell_type": "code",
55+
"execution_count": null,
56+
"metadata": {
57+
"collapsed": false
58+
},
59+
"outputs": [],
60+
"source": [
61+
"plot_radius = 10.\n",
62+
"x=np.linspace(-plot_radius,plot_radius,101)"
5063
]
5164
},
5265
{
@@ -57,7 +70,7 @@
5770
},
5871
"outputs": [],
5972
"source": [
60-
"x=np.linspace(-4.,4.,81)"
73+
"sinc([-5.])"
6174
]
6275
},
6376
{
@@ -68,29 +81,30 @@
6881
},
6982
"outputs": [],
7083
"source": [
84+
"# plt.plot(x, pillbox(x), color='r')\n",
7185
"plt.plot(x, triangle3(x), color='g')\n",
72-
"plt.plot(x, pillbox(x), color='r')\n",
73-
"plt.ylim(0,1.1)"
86+
"plt.plot(x, sinc(x), color='b')\n",
87+
"plt.ylim(-0.5,1.1)"
7488
]
7589
}
7690
],
7791
"metadata": {
7892
"kernelspec": {
79-
"display_name": "Python 3",
93+
"display_name": "Python 2",
8094
"language": "python",
81-
"name": "python3"
95+
"name": "python2"
8296
},
8397
"language_info": {
8498
"codemirror_mode": {
8599
"name": "ipython",
86-
"version": 3
100+
"version": 2
87101
},
88102
"file_extension": ".py",
89103
"mimetype": "text/x-python",
90104
"name": "python",
91105
"nbconvert_exporter": "python",
92-
"pygments_lexer": "ipython3",
93-
"version": "3.4.3"
106+
"pygments_lexer": "ipython2",
107+
"version": "2.7.6"
94108
}
95109
},
96110
"nbformat": 4,

setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
'click',
1010
'pandas',
1111
'pytest',
12+
'six',
1213
'scipy',
1314
]
1415

src/fastimgproto/gridder/conv_funcs.py

+78-8
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,41 @@
1010
"""
1111
from attr import attrs, attrib
1212
import numpy as np
13+
from six import add_metaclass
14+
from abc import ABCMeta, abstractmethod
1315

1416

15-
@attrs
16-
class Triangle(object):
17+
@add_metaclass(ABCMeta)
18+
class ConvFuncBase(object):
19+
"""
20+
Implements truncation (via __call__), numpy array reshaping.
21+
22+
Always returns 0 outside truncation radius, i.e.::
23+
24+
if np.fabs(x) > trunc:
25+
conv_func(x)==0 # True
26+
27+
Args:
28+
trunc: truncation radius.
29+
"""
30+
31+
def __init__(self, trunc):
32+
self.trunc = trunc
33+
34+
@abstractmethod
35+
def f(self, radius):
36+
"""The convolution function to be evaluated and truncated"""
37+
pass
38+
39+
def __call__(self, radius_in_pix):
40+
radius_in_pix = np.atleast_1d(radius_in_pix)
41+
output = np.zeros_like(radius_in_pix)
42+
inside_trunc_radius = np.fabs(radius_in_pix) < self.trunc
43+
output[inside_trunc_radius] = self.f(radius_in_pix[inside_trunc_radius])
44+
return output
45+
46+
47+
class Triangle(ConvFuncBase):
1748
"""
1849
Linearly declines from 1.0 at origin to 0.0 at **half_base_width**, zero thereafter.
1950
"
@@ -28,17 +59,19 @@ class Triangle(object):
2859
half_base_width (float): Half-base width of the triangle.
2960
3061
"""
31-
half_base_width = attrib()
3262

33-
def __call__(self, radius_in_pix):
63+
def __init__(self, half_base_width):
64+
self.half_base_width = half_base_width
65+
super(Triangle, self).__init__(half_base_width)
66+
67+
def f(self, radius_in_pix):
3468
return np.maximum(
3569
1.0 - np.fabs(radius_in_pix) / self.half_base_width,
3670
np.zeros_like(radius_in_pix)
3771
)
3872

3973

40-
@attrs
41-
class Pillbox(object):
74+
class Pillbox(ConvFuncBase):
4275
"""
4376
Valued 1.0 from origin to **half_base_width**, zero thereafter.
4477
@@ -53,7 +86,44 @@ class Pillbox(object):
5386
Attributes:
5487
half_base_width (float): Half-base width pillbox.
5588
"""
56-
half_base_width = attrib()
5789

58-
def __call__(self, radius_in_pix):
90+
def __init__(self, half_base_width):
91+
self.half_base_width = half_base_width
92+
super(Pillbox, self).__init__(half_base_width)
93+
94+
def f(self, radius_in_pix):
5995
return np.where(np.fabs(radius_in_pix) < self.half_base_width, 1.0, 0.0)
96+
97+
98+
class Sinc(ConvFuncBase):
99+
"""
100+
Sinc function, truncated beyond **trunc** pixels from centre.
101+
102+
103+
Attributes:
104+
trunc (float): Truncation radius
105+
"""
106+
trunc = attrib(default=3.0)
107+
108+
def __init__(self, trunc):
109+
super(Sinc, self).__init__(trunc)
110+
111+
def f(self, radius_in_pix):
112+
return np.sinc(radius_in_pix)
113+
114+
115+
class Sinc(ConvFuncBase):
116+
"""
117+
Sinc function, truncated beyond **trunc** pixels from centre.
118+
119+
120+
Attributes:
121+
trunc (float): Truncation radius
122+
"""
123+
trunc = attrib(default=3.0)
124+
125+
def __init__(self, trunc):
126+
super(Sinc, self).__init__(trunc)
127+
128+
def f(self, radius_in_pix):
129+
return np.sinc(radius_in_pix)

tests/test_gridder/test_conv_funcs.py

+49-22
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,59 @@
22
import numpy as np
33

44

5-
def test_triangle_func():
6-
triangle2 = conv_funcs.Triangle(half_base_width=2.0)
7-
8-
# Test known simple inputs
9-
assert triangle2(0.0) == 1.0
10-
assert triangle2(1.0) == 0.5
11-
assert triangle2(2.0) == 0.0
12-
assert triangle2(2.000001) == 0.0
13-
assert triangle2(100) == 0.0
14-
assert triangle2(-0.1) == triangle2(0.1)
5+
def check_function_results_close(func, input_output_pairs,
6+
symmetric=True,
7+
eps=1e-15):
8+
# test with scalar inputs
9+
for pair in input_output_pairs:
10+
assert np.fabs(func(pair[0]) - pair[1]) < eps
1511

1612
# test with array input
17-
input = np.array([-2., 0.0, 0.5, 1.0, 2.0, 3.0])
18-
output = np.array([0, 1.0, 0.75, 0.5, 0.0, 0.0])
19-
assert (triangle2(input) == output).all()
13+
inputs = input_output_pairs[:, 0]
14+
outputs = input_output_pairs[:, 1]
15+
assert (np.fabs(func(inputs) - outputs) < eps).all()
16+
if symmetric:
17+
inputs *= -1.0
18+
assert (np.fabs(func(inputs) - outputs) < eps).all()
2019

2120

22-
def test_tophat_funct():
23-
tophat3 = conv_funcs.Pillbox(half_base_width=3.0)
21+
def test_triangle_func():
22+
triangle2 = conv_funcs.Triangle(half_base_width=2.0)
2423

25-
input = np.array([-4.2, -2.5, 0.0, 1.5, 2.999, 3.0, 3.1])
26-
output = np.array([0.0, 1.0, 1.0, 1., 1., 0.0, 0.0])
24+
io_pairs = np.array([
25+
[0.0, 1.0],
26+
[1.0, 0.5],
27+
[2.0, 0.0],
28+
[2.000001, 0.0],
29+
[100, 0.0],
30+
[0.1, 0.95],
31+
[0.5, 0.75],
32+
])
2733

28-
# test with array input
29-
assert (tophat3(input) == output).all()
34+
check_function_results_close(triangle2, io_pairs)
3035

31-
# test with scalar input
32-
for idx, val in enumerate(input):
33-
assert tophat3(val) == output[idx]
36+
37+
def test_tophat_func():
38+
tophat3 = conv_funcs.Pillbox(half_base_width=3.0)
39+
io_pairs = np.array([
40+
[0.0, 1.0],
41+
[2.5, 1.0],
42+
[2.999, 1.0],
43+
[3.0, 0.0],
44+
[4.2,0.],
45+
])
46+
check_function_results_close(tophat3, io_pairs)
47+
48+
49+
def test_sinc():
50+
sinc = conv_funcs.Sinc(trunc=3.0)
51+
io_pairs = np.array([
52+
[0.0, 1.0],
53+
[1.0, 0.0],
54+
[0.5, 1. / (0.5 * np.pi)],
55+
[1.5, -1. / (1.5*np.pi)],
56+
[2.0, 0.0],
57+
[2.5, 1. / (2.5*np.pi)],
58+
[3.5, 0.], # Truncated
59+
])
60+
check_function_results_close(sinc, io_pairs)

tests/test_sourcefind/test_detection.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ def test_basic_source_detection():
3636
rms_est=rms)
3737
assert len(sf.islands) == 1
3838
src = sf.islands[0]
39-
print bright_src
40-
print src
39+
# print(bright_src)
40+
# print(src)
4141
assert np.abs(src.peak_x_idx - bright_src.x_mean) <0.5
4242
assert np.abs(src.peak_y_idx - bright_src.y_mean) <0.5
4343
assert np.abs(src.xbar - bright_src.x_mean) <0.1

tox.ini

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
[tox]
2-
envlist = py27, docs
2+
envlist = py27, py34, docs
33

44
[testenv]
55
deps= pytest
66
commands=./runtests.py -sv
77

88
[testenv:docs]
99
changedir=docs
10-
deps=-rrequirements/docs.txt
10+
deps=-rdocs/requirements.txt
1111
#NBSphinx requires pandoc
1212
whitelist_externals =
1313
pandoc

0 commit comments

Comments
 (0)