astropy/photutils — pull request #6 by kbarbary (2012-06-20 20:20:49+00:00)
Title: Cython function for subpixel sampling in circular apertures

This PR implements a cython function to speed up the subpixel sampling for circular apertures. It works in a way similar to how the `circular_exact` function works. The speed-up is due to the fact that pixels are only sub-sampled when they are close to the boundary of the aperture. The speed gain can be extremely large for big apertures.

Here are some speed results (the label `subpixels` is the result from this branch):
```
===============================================================================
Big data, single big aperture (milliseconds)
subpixels
function label 1 5 10 exact
-------------------------------------------------------------------------------
circ subpixels 0.723 0.735 0.878 3.842
circ master 0.531 10.906 61.313 3.498
-------------------------------------------------------------------------------

===============================================================================
Small data, multiple small apertures (milliseconds)
subpixels
function label 1 5 10 exact
-------------------------------------------------------------------------------
circ subpixels 130.604 143.837 167.115 198.097
circ master 125.222 178.188 315.610 199.858
-------------------------------------------------------------------------------

===============================================================================
Big data, multiple small apertures, multiple per object (milliseconds)
subpixels
function label 1 5 10 exact
-------------------------------------------------------------------------------
circ subpixels 600.661 658.523 770.303 1468.716
circ master 636.463 1852.837 6287.717 1482.852
-------------------------------------------------------------------------------

===============================================================================
Big data, multiple small apertures (milliseconds)
subpixels
function label 1 5 10 exact
-------------------------------------------------------------------------------
circ subpixels 132.910 137.661 149.065 196.845
circ master 126.189 174.993 325.919 199.184
-------------------------------------------------------------------------------

===============================================================================
Big data, multiple big apertures (milliseconds)
subpixels
function label 1 5 10 exact
-------------------------------------------------------------------------------
circ subpixels 61.718 67.104 79.542 362.409
circ master 45.385 1017.251 4548.554 351.035
-------------------------------------------------------------------------------
```

This is not yet ready for merging. First, I want to get some feedback on how the various `encloses` methods of an aperture interact with the main `aperture_photometry` function, which is getting messy. Before this PR, we had an `encloses` method for all apertures, and also an `encloses_exact` method for apertures that provide it. However, with this PR, we now additionally have an `encloses_subpixels` method for those apertures that provide it. In the main function we have to put another try/except clause around the `encloses_subpixels` call... if it fails, then we do the subpixel sampling the old way: calculate a big meshgrid of (x, y) positions, then use the `encloses` method on them. The problem will get worse if we

One possible solution for cleaning this up would be to have a single `encloses` method for each aperture class. It would look something like this:

def encloses(x_grid, y_grid, method=None, subpixels=None):

where `method` could be one of `exact`, `subpixel`. None would default to just checking if each pixel is in the aperture. Each aperture class could then handle `method` as it sees fit.

The major downside of this is that it raises the bar for what encloses() has to do for a minimally implemented Aperture class. If it didn't use a cython function, it would have to create the (x,y) meshgrid.
However, I see this as a fairly limited use case. I don't think a ton of novice users will be implementing their own aperture classes, if we have circles, ellipses and polygons included already.

Does this make sense? Thoughts?