diff options
| author | sienkiew <sienkiew@stsci.edu> | 2014-03-25 10:53:08 -0400 | 
|---|---|---|
| committer | sienkiew <sienkiew@stsci.edu> | 2014-03-25 10:53:08 -0400 | 
| commit | 5d00dcb1a0123389d9759698a5c42828e17af9bc (patch) | |
| tree | ecef07881ea7b6b661ee5f59847b00dafecf3409 /stsci/sphere/test | |
| parent | 64be292044c4428b5908acf5cc2dda6693ed1afb (diff) | |
| download | stsci.sphere-5d00dcb1a0123389d9759698a5c42828e17af9bc.tar.gz | |
mod for d2to1 install
git-svn-id: http://svn.stsci.edu/svn/ssb/stsci_python/stsci.sphere/trunk@30670 fe389314-cf27-0410-b35b-8c050e845b92
Former-commit-id: 91667828b7e01b5aae55679093564473a976e8a9
Diffstat (limited to 'stsci/sphere/test')
| -rw-r--r-- | stsci/sphere/test/__init__.py | 1 | ||||
| -rw-r--r-- | stsci/sphere/test/benchmarks.py | 39 | ||||
| -rw-r--r-- | stsci/sphere/test/data/1904-66_TAN.fits.gz | bin | 0 -> 113196 bytes | |||
| -rw-r--r-- | stsci/sphere/test/data/2chipA.fits.gz | bin | 0 -> 227579 bytes | |||
| -rw-r--r-- | stsci/sphere/test/data/2chipB.fits.gz | bin | 0 -> 227493 bytes | |||
| -rw-r--r-- | stsci/sphere/test/data/2chipC.fits.gz | bin | 0 -> 183594 bytes | |||
| -rw-r--r-- | stsci/sphere/test/test.py | 277 | ||||
| -rw-r--r-- | stsci/sphere/test/test_intersection.py | 189 | ||||
| -rw-r--r-- | stsci/sphere/test/test_shared.py | 12 | ||||
| -rw-r--r-- | stsci/sphere/test/test_skyline.py | 225 | ||||
| -rw-r--r-- | stsci/sphere/test/test_union.py | 215 | ||||
| -rw-r--r-- | stsci/sphere/test/test_util.py | 14 | 
12 files changed, 972 insertions, 0 deletions
| diff --git a/stsci/sphere/test/__init__.py b/stsci/sphere/test/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/stsci/sphere/test/__init__.py @@ -0,0 +1 @@ + diff --git a/stsci/sphere/test/benchmarks.py b/stsci/sphere/test/benchmarks.py new file mode 100644 index 0000000..91ef8db --- /dev/null +++ b/stsci/sphere/test/benchmarks.py @@ -0,0 +1,39 @@ +import os +import sys +import time + +import numpy as np +from sphere import * +from test_util import * +from test_shared import resolve_imagename + +def point_in_poly_lots(): +    image_name = resolve_imagename(ROOT_DIR,'1904-66_TAN.fits') +     +    poly1 = SphericalPolygon.from_wcs(image_name, 64, crval=[0, 87]) +    poly2 = SphericalPolygon.from_wcs(image_name, 64, crval=[20, 89]) +    poly3 = SphericalPolygon.from_wcs(image_name, 64, crval=[180, 89]) + +    points = get_point_set(density=25) + +    count = 0 +    for point in points: +        if poly1.contains_point(point) or poly2.contains_point(point) or \ +               poly3.contains_point(point): +            count += 1 + +    assert count == 5 +    assert poly1.intersects_poly(poly2) +    assert not poly1.intersects_poly(poly3) +    assert not poly2.intersects_poly(poly3) + +if __name__ == '__main__': +    for benchmark in [point_in_poly_lots]: +        t = time.time() +        sys.stdout.write(benchmark.__name__) +        sys.stdout.write('...') +        sys.stdout.flush() +        benchmark() +        sys.stdout.write(' %.03fs\n' % (time.time() - t)) +        sys.stdout.flush() + diff --git a/stsci/sphere/test/data/1904-66_TAN.fits.gz b/stsci/sphere/test/data/1904-66_TAN.fits.gzBinary files differ new file mode 100644 index 0000000..34ff168 --- /dev/null +++ b/stsci/sphere/test/data/1904-66_TAN.fits.gz diff --git a/stsci/sphere/test/data/2chipA.fits.gz b/stsci/sphere/test/data/2chipA.fits.gzBinary files differ new file mode 100644 index 0000000..27a68ab --- /dev/null +++ b/stsci/sphere/test/data/2chipA.fits.gz diff --git a/stsci/sphere/test/data/2chipB.fits.gz b/stsci/sphere/test/data/2chipB.fits.gzBinary files differ new file mode 100644 index 0000000..209d5f9 --- /dev/null +++ b/stsci/sphere/test/data/2chipB.fits.gz diff --git a/stsci/sphere/test/data/2chipC.fits.gz b/stsci/sphere/test/data/2chipC.fits.gzBinary files differ new file mode 100644 index 0000000..10af627 --- /dev/null +++ b/stsci/sphere/test/data/2chipC.fits.gz diff --git a/stsci/sphere/test/test.py b/stsci/sphere/test/test.py new file mode 100644 index 0000000..b551090 --- /dev/null +++ b/stsci/sphere/test/test.py @@ -0,0 +1,277 @@ +from __future__ import absolute_import + +import os +import random + +import numpy as np +from numpy.testing import assert_almost_equal, assert_array_less + +from .. import graph +from .. import great_circle_arc +from .. import polygon +from .. import vector + +from .test_util import * +from .test_shared import resolve_imagename + +graph.DEBUG = True + + +def test_normalize_vector(): +    x, y, z = np.ogrid[-100:100:11,-100:100:11,-100:100:11] +    xn, yn, zn = vector.normalize_vector(x.flatten(), y.flatten(), z.flatten()) +    l = np.sqrt(xn ** 2 + yn ** 2 + zn ** 2) +    assert_almost_equal(l, 1.0) + + +def test_radec_to_vector(): +    npx, npy, npz = vector.radec_to_vector(np.arange(-360, 360, 1), 90) +    assert_almost_equal(npx, 0.0) +    assert_almost_equal(npy, 0.0) +    assert_almost_equal(npz, 1.0) + +    spx, spy, spz = vector.radec_to_vector(np.arange(-360, 360, 1), -90) +    assert_almost_equal(spx, 0.0) +    assert_almost_equal(spy, 0.0) +    assert_almost_equal(spz, -1.0) + +    eqx, eqy, eqz = vector.radec_to_vector(np.arange(-360, 360, 1), 0) +    assert_almost_equal(eqz, 0.0) + + +def test_vector_to_radec(): +    ra, dec = vector.vector_to_radec(0, 0, 1) +    assert_almost_equal(dec, 90) + +    ra, dec = vector.vector_to_radec(0, 0, -1) +    assert_almost_equal(dec, -90) + +    ra, dec = vector.vector_to_radec(1, 1, 0) +    assert_almost_equal(ra, 45.0) +    assert_almost_equal(dec, 0.0) + + +def test_intersects_poly_simple(): +    ra1 = [-10, 10, 10, -10, -10] +    dec1 = [30, 30, 0, 0, 30] +    poly1 = polygon.SphericalPolygon.from_radec(ra1, dec1) + +    ra2 = [-5, 15, 15, -5, -5] +    dec2 = [20, 20, -10, -10, 20] +    poly2 = polygon.SphericalPolygon.from_radec(ra2, dec2) + +    assert poly1.intersects_poly(poly2) + +    # Make sure it isn't order-dependent +    ra1 = ra1[::-1] +    dec1 = dec1[::-1] +    poly1 = polygon.SphericalPolygon.from_radec(ra1, dec1) + +    ra2 = ra2[::-1] +    dec2 = dec2[::-1] +    poly2 = polygon.SphericalPolygon.from_radec(ra2, dec2) + +    assert poly1.intersects_poly(poly2) + + +def test_intersects_poly_fully_contained(): +    ra1 = [-10, 10, 10, -10, -10] +    dec1 = [30, 30, 0, 0, 30] +    poly1 = polygon.SphericalPolygon.from_radec(ra1, dec1) + +    ra2 = [-5, 5, 5, -5, -5] +    dec2 = [20, 20, 10, 10, 20] +    poly2 = polygon.SphericalPolygon.from_radec(ra2, dec2) + +    assert poly1.intersects_poly(poly2) + +    # Make sure it isn't order-dependent +    ra1 = ra1[::-1] +    dec1 = dec1[::-1] +    poly1 = polygon.SphericalPolygon.from_radec(ra1, dec1) + +    ra2 = ra2[::-1] +    dec2 = dec2[::-1] +    poly2 = polygon.SphericalPolygon.from_radec(ra2, dec2) + +    assert poly1.intersects_poly(poly2) + + +def test_hard_intersects_poly(): +    ra1 = [-10, 10, 10, -10, -10] +    dec1 = [30, 30, 0, 0, 30] +    poly1 = polygon.SphericalPolygon.from_radec(ra1, dec1) + +    ra2 = [-20, 20, 20, -20, -20] +    dec2 = [20, 20, 10, 10, 20] +    poly2 = polygon.SphericalPolygon.from_radec(ra2, dec2) + +    assert poly1.intersects_poly(poly2) + +    # Make sure it isn't order-dependent +    ra1 = ra1[::-1] +    dec1 = dec1[::-1] +    poly1 = polygon.SphericalPolygon.from_radec(ra1, dec1) + +    ra2 = ra2[::-1] +    dec2 = dec2[::-1] +    poly2 = polygon.SphericalPolygon.from_radec(ra2, dec2) + +    assert poly1.intersects_poly(poly2) + + +def test_not_intersects_poly(): +    ra1 = [-10, 10, 10, -10, -10] +    dec1 = [30, 30, 5, 5, 30] +    poly1 = polygon.SphericalPolygon.from_radec(ra1, dec1) + +    ra2 = [-20, 20, 20, -20, -20] +    dec2 = [-20, -20, -10, -10, -20] +    poly2 = polygon.SphericalPolygon.from_radec(ra2, dec2) + +    assert not poly1.intersects_poly(poly2) + +    # Make sure it isn't order-dependent +    ra1 = ra1[::-1] +    dec1 = dec1[::-1] +    poly1 = polygon.SphericalPolygon.from_radec(ra1, dec1) + +    ra2 = ra2[::-1] +    dec2 = dec2[::-1] +    poly2 = polygon.SphericalPolygon.from_radec(ra2, dec2) + +    assert not poly1.intersects_poly(poly2) + + +def test_point_in_poly(): +    point = np.asarray([-0.27475449, 0.47588873, -0.83548781]) +    points = np.asarray([[ 0.04821217, -0.29877206, 0.95310589], +                         [ 0.04451801, -0.47274119, 0.88007608], +                         [-0.14916503, -0.46369786, 0.87334649], +                         [-0.16101648, -0.29210164, 0.94273555], +                         [ 0.04821217, -0.29877206, 0.95310589]]) +    inside = np.asarray([-0.03416009, -0.36858623, 0.9289657]) +    poly = polygon.SphericalPolygon(points, inside) +    assert not poly.contains_point(point) + + +def test_point_in_poly_lots(): +    import pyfits +    fits = pyfits.open(resolve_imagename(ROOT_DIR, '1904-66_TAN.fits')) +    header = fits[0].header + +    poly1 = polygon.SphericalPolygon.from_wcs( +        header, 1, crval=[0, 87]) +    poly2 = polygon.SphericalPolygon.from_wcs( +        header, 1, crval=[20, 89]) +    poly3 = polygon.SphericalPolygon.from_wcs( +        header, 1, crval=[180, 89]) + +    points = get_point_set() +    count = 0 +    for point in points: +        if poly1.contains_point(point) or poly2.contains_point(point) or \ +               poly3.contains_point(point): +            count += 1 + +    assert count == 5 +    assert poly1.intersects_poly(poly2) +    assert not poly1.intersects_poly(poly3) +    assert not poly2.intersects_poly(poly3) + + +def test_great_circle_arc_intersection(): +    A = [-10, -10] +    B = [10, 10] + +    C = [-25, 10] +    D = [15, -10] + +    E = [-20, 40] +    F = [20, 40] + +    correct = [0.99912414, -0.02936109, -0.02981403] + +    A = vector.radec_to_vector(*A) +    B = vector.radec_to_vector(*B) +    C = vector.radec_to_vector(*C) +    D = vector.radec_to_vector(*D) +    E = vector.radec_to_vector(*E) +    F = vector.radec_to_vector(*F) + +    assert great_circle_arc.intersects(A, B, C, D) +    r = great_circle_arc.intersection(A, B, C, D) +    assert r.shape == (3,) +    assert_almost_equal(r, correct) + +    assert np.all(great_circle_arc.intersects([A], [B], [C], [D])) +    r = great_circle_arc.intersection([A], [B], [C], [D]) +    assert r.shape == (1, 3) +    assert_almost_equal(r, [correct]) + +    assert np.all(great_circle_arc.intersects([A], [B], C, D)) +    r = great_circle_arc.intersection([A], [B], C, D) +    assert r.shape == (1, 3) +    assert_almost_equal(r, [correct]) + +    assert not np.all(great_circle_arc.intersects([A, E], [B, F], [C], [D])) +    r = great_circle_arc.intersection([A, E], [B, F], [C], [D]) +    assert r.shape == (2, 3) +    assert_almost_equal(r[0], correct) +    assert np.all(np.isnan(r[1])) + +    # Test parallel arcs +    r = great_circle_arc.intersection(A, B, A, B) +    assert np.all(np.isnan(r)) + + +def test_great_circle_arc_length(): +    A = [90, 0] +    B = [-90, 0] +    A = vector.radec_to_vector(*A) +    B = vector.radec_to_vector(*B) +    assert great_circle_arc.length(A, B) == 180.0 + +    A = [135, 0] +    B = [-90, 0] +    A = vector.radec_to_vector(*A) +    B = vector.radec_to_vector(*B) +    assert great_circle_arc.length(A, B) == 135.0 + +    A = [0, 0] +    B = [0, 90] +    A = vector.radec_to_vector(*A) +    B = vector.radec_to_vector(*B) +    assert great_circle_arc.length(A, B) == 90.0 + + +def test_great_circle_arc_angle(): +    A = [1, 0, 0] +    B = [0, 1, 0] +    C = [0, 0, 1] +    assert great_circle_arc.angle(A, B, C) == 90.0 + +    # TODO: More angle tests + + +def test_cone(): +    random.seed(0) +    for i in range(50): +        ra = random.randrange(-180, 180) +        dec = random.randrange(20, 90) +        cone = polygon.SphericalPolygon.from_cone(ra, dec, 8, steps=64) + + +def test_area(): +    triangles = [ +        ([[90, 0], [0, -45], [0, 45], [90, 0]], np.pi * 0.5), +        ([[90, 0], [0, -22.5], [0, 22.5], [90, 0]], np.pi * 0.25), +        ([[90, 0], [0, -11.25], [0, 11.25], [90, 0]], np.pi * 0.125) +        ] + +    for tri, area in triangles: +        tri = np.array(tri) +        x, y, z = vector.radec_to_vector(tri[:,1], tri[:,0]) +        points = np.dstack((x, y, z))[0] +        poly = polygon.SphericalPolygon(points) +        calc_area = poly.area() diff --git a/stsci/sphere/test/test_intersection.py b/stsci/sphere/test/test_intersection.py new file mode 100644 index 0000000..6dacb3d --- /dev/null +++ b/stsci/sphere/test/test_intersection.py @@ -0,0 +1,189 @@ +from __future__ import print_function, absolute_import + +# STDLIB +import functools +import itertools +import math +import os +import random +import sys + +# THIRD-PARTY +import numpy as np +from numpy.testing import assert_array_almost_equal + +# LOCAL +from .. import polygon +from .test_shared import resolve_imagename + +GRAPH_MODE = False +ROOT_DIR = os.path.join(os.path.dirname(__file__), 'data') + + +class intersection_test: +    def __init__(self, lon_0, lat_0, proj='ortho'): +        self._lon_0 = lon_0 +        self._lat_0 = lat_0 +        self._proj = proj + +    def __call__(self, func): +        @functools.wraps(func) +        def run(*args, **kwargs): +            if GRAPH_MODE: +                from mpl_toolkits.basemap import Basemap +                from matplotlib import pyplot as plt + +            polys = func(*args, **kwargs) + +            intersections = [] +            num_permutations = math.factorial(len(polys)) +            step_size = int(max(float(num_permutations) / 20.0, 1.0)) + +            areas = [x.area() for x in polys] + +            if GRAPH_MODE: +                print("%d permutations" % num_permutations) +            for method in ('parallel', 'serial'): +                for i, permutation in enumerate( +                    itertools.islice( +                        itertools.permutations(polys), +                        None, None, step_size)): +                    filename = '%s_%s_intersection_%04d.svg' % ( +                        func.__name__, method, i) +                    print(filename) + +                    intersection = polygon.SphericalPolygon.multi_intersection( +                        permutation, method=method) +                    intersections.append(intersection) +                    intersection_area = intersection.area() +                    if GRAPH_MODE: +                        fig = plt.figure() +                        m = Basemap(projection=self._proj, +                                    lon_0=self._lon_0, +                                    lat_0=self._lat_0) +                        m.drawparallels(np.arange(-90., 90., 20.)) +                        m.drawmeridians(np.arange(0., 420., 20.)) +                        m.drawmapboundary(fill_color='white') + +                        intersection.draw(m, color='red', linewidth=3) +                        for poly in permutation: +                            poly.draw(m, color='blue', alpha=0.5) +                        plt.savefig(filename) +                        fig.clear() + +                    assert np.all(intersection_area * 0.9 <= areas) + +            lengths = np.array([len(x._points) for x in intersections]) +            assert np.all(lengths == [lengths[0]]) +            areas = np.array([x.area() for x in intersections]) +            assert_array_almost_equal(areas, areas[0], decimal=1) + +        return run + + +@intersection_test(0, 90) +def test1(): +    import pyfits +    import os + +    fits = pyfits.open(resolve_imagename(ROOT_DIR,'1904-66_TAN.fits')) +    header = fits[0].header + +    poly1 = polygon.SphericalPolygon.from_wcs( +        header, 1, crval=[0, 87]) +    poly2 = polygon.SphericalPolygon.from_wcs( +        header, 1, crval=[20, 89]) + +    return [poly1, poly2] + + +@intersection_test(0, 90) +def test2(): +    poly1 = polygon.SphericalPolygon.from_cone(0, 60, 8, steps=16) +    poly2 = polygon.SphericalPolygon.from_cone(0, 68, 8, steps=16) +    poly3 = polygon.SphericalPolygon.from_cone(12, 66, 8, steps=16) +    return [poly1, poly2, poly3] + + +@intersection_test(0, 90) +def test3(): +    import pyfits +    fits = pyfits.open(resolve_imagename(ROOT_DIR, '1904-66_TAN.fits')) +    header = fits[0].header + +    poly1 = polygon.SphericalPolygon.from_wcs( +        header, 1, crval=[0, 87]) +    poly3 = polygon.SphericalPolygon.from_wcs( +        header, 1, crval=[175, 89]) + +    return [poly1, poly3] + + +def test4(): +    import pyfits +    import pywcs + +    A = pyfits.open(os.path.join(ROOT_DIR, '2chipA.fits.gz')) +    B = pyfits.open(os.path.join(ROOT_DIR, '2chipB.fits.gz')) + +    wcs = pywcs.WCS(A[1].header, fobj=A) +    chipA1 = polygon.SphericalPolygon.from_wcs(wcs) +    wcs = pywcs.WCS(A[4].header, fobj=A) +    chipA2 = polygon.SphericalPolygon.from_wcs(wcs) +    wcs = pywcs.WCS(B[1].header, fobj=B) +    chipB1 = polygon.SphericalPolygon.from_wcs(wcs) +    wcs = pywcs.WCS(B[4].header, fobj=B) +    chipB2 = polygon.SphericalPolygon.from_wcs(wcs) + +    Apoly = chipA1.union(chipA2) +    Bpoly = chipB1.union(chipB2) + +    X = Apoly.intersection(Bpoly) + + +def test5(): +    import pyfits +    import pywcs + +    A = pyfits.open(os.path.join(ROOT_DIR, '2chipA.fits.gz')) +    B = pyfits.open(os.path.join(ROOT_DIR, '2chipB.fits.gz')) + +    wcs = pywcs.WCS(A[1].header, fobj=A) +    chipA1 = polygon.SphericalPolygon.from_wcs(wcs) +    wcs = pywcs.WCS(A[4].header, fobj=A) +    chipA2 = polygon.SphericalPolygon.from_wcs(wcs) +    wcs = pywcs.WCS(B[1].header, fobj=B) +    chipB1 = polygon.SphericalPolygon.from_wcs(wcs) +    wcs = pywcs.WCS(B[4].header, fobj=B) +    chipB2 = polygon.SphericalPolygon.from_wcs(wcs) + +    Apoly = chipA1.union(chipA2) +    Bpoly = chipB1.union(chipB2) + +    Apoly.overlap(chipB1) + + +@intersection_test(0, 90) +def test6(): +    import pyfits +    fits = pyfits.open(resolve_imagename(ROOT_DIR, '1904-66_TAN.fits')) +    header = fits[0].header + +    poly1 = polygon.SphericalPolygon.from_wcs( +        header, 1) +    poly2 = polygon.SphericalPolygon.from_wcs( +        header, 1) + +    return [poly1, poly2] + + +if __name__ == '__main__': +    if '--profile' not in sys.argv: +        GRAPH_MODE = True +        from mpl_toolkits.basemap import Basemap +        from matplotlib import pyplot as plt + +    functions = [(k, v) for k, v in globals().items() if k.startswith('test')] +    functions.sort() +    for k, v in functions: +        v() diff --git a/stsci/sphere/test/test_shared.py b/stsci/sphere/test/test_shared.py new file mode 100644 index 0000000..0853d3a --- /dev/null +++ b/stsci/sphere/test/test_shared.py @@ -0,0 +1,12 @@ +import os + +def resolve_imagename(ROOT_DIR, base_name): +    """Resolve image name for tests.""" + +    image_name = os.path.join(ROOT_DIR, base_name) + +    # Is it zipped? +    if not os.path.exists(image_name): +        image_name = image_name.replace('.fits', '.fits.gz') + +    return image_name diff --git a/stsci/sphere/test/test_skyline.py b/stsci/sphere/test/test_skyline.py new file mode 100644 index 0000000..929f0ba --- /dev/null +++ b/stsci/sphere/test/test_skyline.py @@ -0,0 +1,225 @@ +""" +SkyLine tests. + +:Author: Pey Lian Lim + +:Organization: Space Telescope Science Institute + +Examples +-------- +>>> cd path/to/project +>>> nosetests + +""" +from __future__ import absolute_import + +from copy import copy +from numpy.testing import assert_almost_equal + +from ..vector import vector_to_radec +from ..polygon import SphericalPolygon +from ..skyline import SkyLine + +from .test_util import ROOT_DIR +from .test_shared import resolve_imagename + + +#---------------------------------------# +# Load footprints used by all the tests # +#---------------------------------------# +f_2chipA  = resolve_imagename(ROOT_DIR, '2chipA.fits') # ACS/WFC #1 +im_2chipA = SkyLine(f_2chipA) +f_2chipB  = resolve_imagename(ROOT_DIR, '2chipB.fits') # ACS/WFC #2 +im_2chipB = SkyLine(f_2chipB) +f_2chipC  = resolve_imagename(ROOT_DIR, '2chipC.fits') # WFC3/UVIS +im_2chipC = SkyLine(f_2chipC) +f_66_tan  = resolve_imagename(ROOT_DIR, '1904-66_TAN.fits') +im_66_tan = SkyLine(f_66_tan, extname='primary') + + +#----- SHARED FUNCTIONS ----- + +def same_members(mem1, mem2): +    assert len(mem1) == len(mem2) + +    for m in mem1: +        assert m in mem2 + +    for m in mem2: +        assert m in mem1 + +def subset_members(mem_child, mem_parent): +    assert len(mem_parent) > len(mem_child) + +    for m in mem_child: +        assert m in mem_parent + +def subset_polygon(p_child, p_parent): +    """Overlap not working. Do this instead until fixed.""" +    assert p_parent.area() >= p_child.area() +    assert p_parent.contains_point(p_child.inside) + +def no_polygon(p_child, p_parent): +    """Overlap not working. Do this instead until fixed.""" +    assert not p_parent.contains_point(p_child.inside) + + +#----- MEMBERSHIP ----- + +def do_member_overlap(im): +    for m in im.members: +        assert_almost_equal(m.polygon.overlap(im), 1.0) + +def test_membership(): +    do_member_overlap(im_2chipA) +    do_member_overlap(im_2chipB) +    do_member_overlap(im_66_tan) + +    assert len(im_2chipA.members) == 1 +    assert im_2chipA.members[0].fname == f_2chipA +    assert im_2chipA.members[0].ext == (1,4) + + +#----- COPY ----- + +def test_copy(): +    a_copy = copy(im_2chipA) +    assert a_copy is not im_2chipA + + +#----- SPHERICAL POLYGON RELATED ----- + +def test_sphericalpolygon(): +    assert im_2chipA.contains_point(im_2chipA.inside) +     +    assert im_2chipA.intersects_poly(im_2chipB.polygon) +     +    assert im_2chipA.intersects_arc(im_2chipA.inside, im_2chipB.inside) +     +    assert im_2chipA.overlap(im_2chipB) < im_2chipA.overlap(im_2chipA) +     +    assert_almost_equal(im_2chipA.area(), im_2chipB.area()) + +    ra_A, dec_A = im_2chipA.to_radec() +    for i in xrange(len(im_2chipA.points)): +        p = im_2chipA.points[i] +        ra, dec = vector_to_radec(p[0], p[1], p[2], degrees=True) +        assert_almost_equal(ra_A[i], ra) +        assert_almost_equal(dec_A[i], dec) + + +#----- WCS ----- + +def test_wcs(): +    wcs = im_2chipA.to_wcs() +    new_p = SphericalPolygon.from_wcs(wcs) +    subset_polygon(im_2chipA, new_p) + + +#----- UNION ----- + +def do_add_image(im1, im2): +    u1 = im1.add_image(im2) +    u2 = im2.add_image(im1) + +    assert u1.same_points_as(u2) +    same_members(u1.members, u2.members) + +    all_mems = im1.members + im2.members +    same_members(u1.members, all_mems) + +    subset_polygon(im1, u1) +    subset_polygon(im2, u1) + +def test_add_image(): +    # Dithered +    do_add_image(im_2chipA, im_2chipB) + +    # Not related +    do_add_image(im_2chipA, im_66_tan) + + +#----- INTERSECTION ----- + +def do_intersect_image(im1, im2): +    i1 = im1.find_intersection(im2) +    i2 = im2.find_intersection(im1) + +    assert i1.same_points_as(i2) +    same_members(i1.members, i2.members) + +    if len(i1.points) > 0: +        subset_members(im1.members, i1.members) +        subset_members(im2.members, i1.members) +     +        subset_polygon(i1, im1) +        subset_polygon(i1, im2) + +def test_find_intersection():    +    # Dithered +    do_intersect_image(im_2chipA, im_2chipB) + +    # Not related +    do_intersect_image(im_2chipA, im_66_tan) + + +#----- SKYLINE OVERLAP ----- + +def test_max_overlap(): +    max_s, max_a = im_2chipA.find_max_overlap([im_2chipB, im_2chipC, im_66_tan]) +    assert max_s is im_2chipB +    assert_almost_equal(max_a, im_2chipA.intersection(im_2chipB).area()) + +    max_s, max_a = im_2chipA.find_max_overlap([im_2chipB, im_2chipA]) +    assert max_s is im_2chipA +    assert_almost_equal(max_a, im_2chipA.area()) + +def test_max_overlap_pair(): +    assert SkyLine.max_overlap_pair( +        [im_2chipB, im_2chipC, im_2chipA, im_66_tan]) == (im_2chipB, im_2chipA) + +    assert SkyLine.max_overlap_pair([im_2chipC, im_2chipA, im_66_tan]) is None + + +#----- INTENDED USE CASE ----- + +def test_science_1(): +    mos, inc, exc = SkyLine.mosaic([im_2chipA, im_2chipB, im_2chipC, im_66_tan]) + +    assert inc == [f_2chipA, f_2chipB] +    assert exc == [f_2chipC, f_66_tan] + +    subset_polygon(im_2chipA, mos) +    subset_polygon(im_2chipB, mos) + +    no_polygon(im_2chipC, mos) +    no_polygon(im_66_tan, mos) + +def test_science_2(): +    """Like `test_science_1` but different input order.""" +    mos, inc, exc = SkyLine.mosaic([im_2chipB, im_66_tan, im_2chipC, im_2chipA]) + +    assert inc == [f_2chipB, f_2chipA] +    assert exc == [f_66_tan, f_2chipC] + +    subset_polygon(im_2chipA, mos) +    subset_polygon(im_2chipB, mos) + +    no_polygon(im_2chipC, mos) +    no_polygon(im_66_tan, mos) + + +#----- UNSTABLE ----- + +def DISABLED_unstable_overlap(): +    i1 = im_2chipA.find_intersection(im_2chipB) +    i2 = im_2chipB.find_intersection(im_2chipA) +     +    u1 = im_2chipA.add_image(im_2chipB) +    u2 = im_2chipB.add_image(im_2chipA) + +    # failed here before - known bug +    # failure not always the same due to hash mapping +    assert_almost_equal(i1.overlap(u1), 1.0) +    assert_almost_equal(i1.overlap(i2), 1.0) +    assert_almost_equal(u1.overlap(u2), 1.0) diff --git a/stsci/sphere/test/test_union.py b/stsci/sphere/test/test_union.py new file mode 100644 index 0000000..4b649f6 --- /dev/null +++ b/stsci/sphere/test/test_union.py @@ -0,0 +1,215 @@ +from __future__ import print_function, absolute_import + +# STDLIB +import functools +import itertools +import math +import os +import random +import sys + +# THIRD-PARTY +import numpy as np +from numpy.testing import assert_array_almost_equal + +# LOCAL +from .. import polygon +from .test_shared import resolve_imagename + +GRAPH_MODE = False +ROOT_DIR = os.path.join(os.path.dirname(__file__), 'data') + + +class union_test: +    def __init__(self, lon_0, lat_0, proj='ortho'): +        self._lon_0 = lon_0 +        self._lat_0 = lat_0 +        self._proj = proj + +    def __call__(self, func): +        @functools.wraps(func) +        def run(*args, **kwargs): +            if GRAPH_MODE: +                from mpl_toolkits.basemap import Basemap +                from matplotlib import pyplot as plt + +            polys = func(*args, **kwargs) + +            unions = [] +            num_permutations = math.factorial(len(polys)) +            step_size = int(max(float(num_permutations) / 20.0, 1.0)) +            if GRAPH_MODE: +                print("%d permutations" % num_permutations) + +            areas = [x.area() for x in polys] + +            for i, permutation in enumerate( +                    itertools.islice( +                    itertools.permutations(polys), +                    None, None, step_size)): +                filename = '%s_union_%04d.svg' % ( +                    func.__name__, i) +                print(filename) + +                union = polygon.SphericalPolygon.multi_union( +                    permutation) +                unions.append(union) +                union_area = union.area() +                print(union._points) +                print(permutation[0]._points) + +                if GRAPH_MODE: +                    fig = plt.figure() +                    m = Basemap(projection=self._proj, +                                lon_0=self._lon_0, +                                lat_0=self._lat_0) +                    m.drawmapboundary(fill_color='white') +                    m.drawparallels(np.arange(-90., 90., 20.)) +                    m.drawmeridians(np.arange(0., 420., 20.)) + +                    union.draw(m, color='red', linewidth=3) +                    for poly in permutation: +                        poly.draw(m, color='blue', alpha=0.5) +                    plt.savefig(filename) +                    fig.clear() + +                print(union_area, areas) +                assert np.all(union_area * 1.1 >= areas) + +            lengths = np.array([len(x._points) for x in unions]) +            assert np.all(lengths == [lengths[0]]) +            areas = np.array([x.area() for x in unions]) +            assert_array_almost_equal(areas, areas[0], 1) + +        return run + + +@union_test(0, 90) +def test1(): +    import pyfits +    fits = pyfits.open(resolve_imagename(ROOT_DIR, '1904-66_TAN.fits')) +    header = fits[0].header + +    poly1 = polygon.SphericalPolygon.from_wcs( +        header, 1, crval=[0, 87]) +    poly2 = polygon.SphericalPolygon.from_wcs( +        header, 1, crval=[20, 89]) +    poly3 = polygon.SphericalPolygon.from_wcs( +        header, 1, crval=[175, 89]) +    poly4 = polygon.SphericalPolygon.from_cone( +        90, 70, 10, steps=50) + +    return [poly1, poly2, poly3, poly4] + + +@union_test(0, 90) +def test2(): +    poly1 = polygon.SphericalPolygon.from_cone(0, 60, 7, steps=16) +    poly2 = polygon.SphericalPolygon.from_cone(0, 72, 7, steps=16) +    poly3 = polygon.SphericalPolygon.from_cone(20, 60, 7, steps=16) +    poly4 = polygon.SphericalPolygon.from_cone(20, 72, 7, steps=16) +    poly5 = polygon.SphericalPolygon.from_cone(35, 55, 7, steps=16) +    poly6 = polygon.SphericalPolygon.from_cone(60, 60, 3, steps=16) +    return [poly1, poly2, poly3, poly4, poly5, poly6] + + +@union_test(0, 90) +def test3(): +    random.seed(0) +    polys = [] +    for i in range(10): +        polys.append(polygon.SphericalPolygon.from_cone( +            random.randrange(-180, 180), +            random.randrange(20, 90), +            random.randrange(5, 16), +            steps=16)) +    return polys + + +@union_test(0, 15) +def test4(): +    random.seed(64) +    polys = [] +    for i in range(10): +        polys.append(polygon.SphericalPolygon.from_cone( +            random.randrange(-30, 30), +            random.randrange(-15, 60), +            random.randrange(5, 16), +            steps=16)) +    return polys + + +def test5(): +    import pyfits +    import pywcs + +    A = pyfits.open(os.path.join(ROOT_DIR, '2chipA.fits.gz')) + +    wcs = pywcs.WCS(A[1].header, fobj=A) +    chipA1 = polygon.SphericalPolygon.from_wcs(wcs) +    wcs = pywcs.WCS(A[4].header, fobj=A) +    chipA2 = polygon.SphericalPolygon.from_wcs(wcs) + +    null_union = chipA1.union(chipA2) + + +def test6(): +    import pyfits +    import pywcs + +    A = pyfits.open(os.path.join(ROOT_DIR, '2chipC.fits.gz')) + +    wcs = pywcs.WCS(A[1].header, fobj=A) +    chipA1 = polygon.SphericalPolygon.from_wcs(wcs) +    wcs = pywcs.WCS(A[4].header, fobj=A) +    chipA2 = polygon.SphericalPolygon.from_wcs(wcs) + +    null_union = chipA1.union(chipA2) + + +@union_test(0, 90) +def test7(): +    import pyfits +    import pywcs + +    A = pyfits.open(os.path.join(ROOT_DIR, '2chipA.fits.gz')) + +    wcs = pywcs.WCS(A[1].header, fobj=A) +    chipA1 = polygon.SphericalPolygon.from_wcs(wcs) +    wcs = pywcs.WCS(A[4].header, fobj=A) +    chipA2 = polygon.SphericalPolygon.from_wcs(wcs) + +    B = pyfits.open(os.path.join(ROOT_DIR, '2chipB.fits.gz')) + +    wcs = pywcs.WCS(B[1].header, fobj=B) +    chipB1 = polygon.SphericalPolygon.from_wcs(wcs) +    wcs = pywcs.WCS(B[4].header, fobj=B) +    chipB2 = polygon.SphericalPolygon.from_wcs(wcs) + +    return [chipA1, chipA2, chipB1, chipB2] + + +@union_test(0, 90) +def test8(): +    import pyfits +    fits = pyfits.open(resolve_imagename(ROOT_DIR, '1904-66_TAN.fits')) +    header = fits[0].header + +    poly1 = polygon.SphericalPolygon.from_wcs( +        header, 1) +    poly2 = polygon.SphericalPolygon.from_wcs( +        header, 1) + +    return [poly1, poly2] + + +if __name__ == '__main__': +    if '--profile' not in sys.argv: +        GRAPH_MODE = True +        from mpl_toolkits.basemap import Basemap +        from matplotlib import pyplot as plt + +    functions = [(k, v) for k, v in globals().items() if k.startswith('test')] +    functions.sort() +    for k, v in functions: +        v() diff --git a/stsci/sphere/test/test_util.py b/stsci/sphere/test/test_util.py new file mode 100644 index 0000000..6dc0393 --- /dev/null +++ b/stsci/sphere/test/test_util.py @@ -0,0 +1,14 @@ +import os + +import numpy as np +from .. import vector + +ROOT_DIR = os.path.join(os.path.dirname(__file__), 'data') + +def get_point_set(density=25): +    points = [] +    for i in np.linspace(-85, 85, density, True): +        for j in np.linspace(-180, 180, np.cos(np.deg2rad(i)) * density): +            points.append([j, i]) +    points = np.asarray(points) +    return np.dstack(vector.radec_to_vector(points[:,0], points[:,1]))[0] | 
