From 5563738a39cb6967832c91c4f8addf0c487538f5 Mon Sep 17 00:00:00 2001 From: perrygreenfield Date: Sat, 20 Apr 2024 18:47:31 -0400 Subject: [PATCH] RCAL-775: initial commit of tessel matching code (#1161) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 + CHANGES.rst | 5 + romancal/patch_match/__init__.py | 0 romancal/patch_match/patch_match.py | 255 ++++++++++++++++++ romancal/patch_match/test/patches_subset.asdf | Bin 0 -> 196295 bytes romancal/patch_match/test/test_patch_match.py | 193 +++++++++++++ 6 files changed, 455 insertions(+) create mode 100644 romancal/patch_match/__init__.py create mode 100644 romancal/patch_match/patch_match.py create mode 100644 romancal/patch_match/test/patches_subset.asdf create mode 100644 romancal/patch_match/test/test_patch_match.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4c45ab773..bad5af22c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,3 +1,5 @@ +exclude: ".*\\.asdf$" + repos: - repo: https://github.com/pre-commit/pre-commit-hooks diff --git a/CHANGES.rst b/CHANGES.rst index fbd05f2d2..14a20886e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,11 @@ 0.14.1 (unreleased) ================== +patch_match +----------- + +- Code to determine which patches overlap a given image. [#1161] + tweakreg -------- diff --git a/romancal/patch_match/__init__.py b/romancal/patch_match/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/romancal/patch_match/patch_match.py b/romancal/patch_match/patch_match.py new file mode 100644 index 000000000..1eeac86eb --- /dev/null +++ b/romancal/patch_match/patch_match.py @@ -0,0 +1,255 @@ +""" +This module determines which patch files overlap with the given image. + +Currently this assumes that the sky projected borders of all images are straight. +""" + +import logging +import os +import os.path + +import asdf +import gwcs.wcs as wcs +import numpy as np +import spherical_geometry.polygon as sgp +import spherical_geometry.vector as sgv +from spherical_geometry.vector import normalize_vector + +log = logging.getLogger(__name__) +log.setLevel(logging.DEBUG) + +RAD_TO_ARCSEC = 180.0 / np.pi * 3600.0 + +PATCH_TABLE = None +CANDIDATE_RADIUS = 0.5 # Radius of circle for which patch centers must lie within +# to be tested for intersection (in degrees) + + +def load_patch_table(tablepath=None): + """ + Load the patch table. If no tablepath is supplied the path is obtained + from the environmental variable PATCH_TABLE_PATH + """ + global PATCH_TABLE + if tablepath is None: + try: + tablepath = os.environ["PATCH_TABLE_PATH"] + except KeyError: + log.error("PATCH_TABLE_PATH environmental variable not found") + return + try: + with asdf.open(tablepath) as af: + PATCH_TABLE = af.tree["patches"].copy() + except FileNotFoundError: + raise FileNotFoundError("Specified patch table file path not found") + + +def image_coords_to_vec(image_corners): + """ + This routine can handle the corners in both organizations, whether + a sequence of ra, dec pairs or a list of ra coordinates, followed + by a list of dec coordinates. So long as either form can be converted + to a numpy array it is ok. The spherical geometry routines expect + the latter organization, and the returned value will be of that + organization. + """ + image_corners = np.array(image_corners) + if image_corners.shape == (4, 2): + image_corners = image_corners.transpose() + # Convert all celestial coordinates to cartesion coordinates. + vec_im_corners = np.array(sgv.lonlat_to_vector(image_corners[0], image_corners[1])) + return vec_im_corners + + +def find_patch_matches(image_corners, image_shape=None): + """Find patches that the image overlaps with + + Parameters + ---------- + image_corners : Either a squence of 4 (ra, dec) pairs, or + equivalent 2-d numpy array, or + a GWCS instance. The instance must have either the bounding_box or + pixel_shape attribute defined, or the following image_shape argument + must be supplied + + image_shape : image shape to be used if a GWCS instance is supplied + and does not contain a value for either the bounding_box or + pixel_shape attributes. Default value is None. + + Returns + ------- + A sequence of the indices of all patches that overlap the supplied image + (in the referenced patch table). The indices may be used to obtain all + necessary information about the patches. + """ + + if PATCH_TABLE is None: + raise RuntimeError("No patch table has been loaded") + if isinstance(image_corners, wcs.WCS): + iwcs = image_corners + # Now must find size of correspinding image, with three possible + # sources of that information. + if ( + (not hasattr(iwcs, "bounding_box") or iwcs.bounding_box is None) + and (not hasattr(iwcs, "pixel_shape") or iwcs.pixel_shape is None) + and image_shape is None + ): + raise ValueError( + "Use of a wcs object requires at least one of the bounding_box" + " or pixel_shape attributes be set to the image shape or that the" + "image_shape argument be set" + ) + if image_shape is not None: + pass + else: + # Both bounding_box and pixel_shape are in x, y order contrary to + # numpy convention. + if hasattr(iwcs, "bounding_box") and iwcs.bounding_box is not None: + # Presumes that the bounding_box matches image array boundaries + bbintervals = iwcs.bounding_box.intervals + # This compensates for the half pixel adjustment in the general code. + image_shape = (bbintervals[1].upper + 0.5, bbintervals[0].upper + 0.5) + elif hasattr(iwcs, "pixel_shape") and iwcs.pixel_shape is not None: + image_shape = (iwcs.pixel_shape[1], iwcs.pixel_shape[0]) + # Compute the image corners ra, dec from the wcs + (cxm, cxp), (cym, cyp) = ( + (-0.5, image_shape[1] - 0.5), + (-0.5, image_shape[0] - 0.5), + ) + image_corners = (iwcs(cxp, cyp), iwcs(cxm, cyp), iwcs(cxm, cym), iwcs(cxp, cym)) + ptab = PATCH_TABLE + ra = ptab[:]["ra_center"] + dec = ptab[:]["dec_center"] + # # Convert all celestial coordinates to cartesion coordinates. + vec_centers = np.array(sgv.lonlat_to_vector(ra, dec)).transpose() + # # Organize corners into two ra, dec lists + # imra = np.array([point[0] for point in image_corners]) + # imdec = np.array([point[1] for point in image_corners]) + vec_im_corners = image_coords_to_vec(image_corners) + # Approximate center of image by averaging corner vectors + im_center = normalize_vector(vec_im_corners.mean(axis=1)) + # Compute difference vector between image center and patch centers + diff = vec_centers - im_center + dist = np.sqrt((diff**2).sum(axis=1)) * 180 / np.pi + match = np.where(dist < 0.5) + ncandidates = len(match[0]) + # Now see which of these that are close actually overlap the supplied image. + # (Is it necessary to check that the corners are in a sensible order?) + # All the corner coordinates are returned as arrays. + mra1 = ptab[match]["ra_corn1"] + mra2 = ptab[match]["ra_corn2"] + mra3 = ptab[match]["ra_corn3"] + mra4 = ptab[match]["ra_corn4"] + mdec1 = ptab[match]["dec_corn1"] + mdec2 = ptab[match]["dec_corn2"] + mdec3 = ptab[match]["dec_corn3"] + mdec4 = ptab[match]["dec_corn4"] + mcenters = vec_centers[match] + mra = np.vstack([mra1, mra2, mra3, mra4, mra1]) + mdec = np.vstack([mdec1, mdec2, mdec3, mdec4, mdec1]) + points = np.array(sgv.lonlat_to_vector(mra, mdec)) + # Create polygon for supplied image_corners + pvec_im_corners = np.empty((5, 3)) + pvec_im_corners[:4] = vec_im_corners.transpose() + pvec_im_corners[4] = pvec_im_corners[0] + impoly = sgp.SingleSphericalPolygon(pvec_im_corners, im_center) + realmatch = [] + for i in range(ncandidates): + # print(i) + cellpoints = points[:, :, i].transpose() + cellcenter = mcenters[i] + cellpoly = sgp.SingleSphericalPolygon(cellpoints, cellcenter) + if impoly.intersects_poly(cellpoly): + # print(f"candidate {i} intersects") + realmatch.append(i) + return match[0][realmatch], match[0] + + +def get_cartesian_corners(patch): + """ + Cons] truct a the vertex coordinates for a patch from a patch definition suitable + for plotting the defined region (ra coordinates, dec coordinates). It returns + coordinates in the cartesian system so that it avoids the distortions in plots + due to areas approaching the poles. + """ + dec_corners = np.array( + ( + patch["dec_corn1"], + patch["dec_corn2"], + patch["dec_corn3"], + patch["dec_corn4"], + patch["dec_corn1"], + ) + ) + ra_corners = np.array( + ( + patch["ra_corn1"], + patch["ra_corn2"], + patch["ra_corn3"], + patch["ra_corn4"], + patch["ra_corn1"], + ) + ) + vec_corners = sgv.lonlat_to_vector(ra_corners, dec_corners) + return vec_corners + + +def find_closest_tangent_point(patches, image_corners): + """ + Out of all listed patches, find the closest tangent point to the center + coordinate of the image. + """ + # To deal with the corner case, it is necessary to use spherical_geometry + # to average the the corners properly. + # Convert image corners to unit vectors. + vec_im_corners = image_coords_to_vec(image_corners) + im_center = np.array(normalize_vector(vec_im_corners.mean(axis=1))) + tangent_point_set = set() + patch_tangent_points = [ + (patch["ra_projection_center"], patch["dec_projection_center"]) + for patch in patches + ] + for tangent_point in patch_tangent_points: + tangent_point_set.add(tangent_point) + unique_tangent_points = list(tangent_point_set) + # Compute distance for each tangent point from im_center + dist = [ + ((im_center - np.array(sgv.lonlat_to_vector(*tangent_point))) ** 2).sum() + for tangent_point in unique_tangent_points + ] + sorted_dist_indices = sorted(zip(dist, range(len(dist)))) + sorted_tangent_points = [ + unique_tangent_points[sorted_dist[1]] for sorted_dist in sorted_dist_indices + ] + closest_tangent_point = np.array(sgv.lonlat_to_vector(*sorted_tangent_points[0])) + # Now associate index of sorted_tangent_points with that of all patches + patch_tp_id = [] + for patch_tp in patch_tangent_points: + for i, tp in enumerate(sorted_tangent_points): + if tp == patch_tp: + patch_tp_id.append(i) + return closest_tangent_point, patch_tp_id + + +def veccoords_to_tangent_plane(vertices, tangent_point_vec): + """ + Convert the spherical geometry vectors to tangent plane coordinates + in arcseconds. This algorithm is not precise, but should be good + enough for now (and besides, the goal here is visualizaion, not + ultra-precision). This also breaks down numerically very near the + poles. + """ + # First compute the tangent plane axis vectors. + x_axis = normalize_vector(np.cross([0, 0, 1], tangent_point_vec)) + y_axis = normalize_vector( + np.array([0, 0, 1]) + - np.array(tangent_point_vec) + * np.dot(np.array([0, 0, 1]), np.array(tangent_point_vec)) + ) + avertices = np.vstack(vertices) + x_coords = np.dot(x_axis, avertices) * RAD_TO_ARCSEC + y_coords = np.dot(y_axis, avertices) * RAD_TO_ARCSEC + return x_coords, y_coords + + +load_patch_table() diff --git a/romancal/patch_match/test/patches_subset.asdf b/romancal/patch_match/test/patches_subset.asdf new file mode 100644 index 0000000000000000000000000000000000000000..5ec6950062603ccd64dbe543e75394013de554de GIT binary patch literal 196295 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

wSd>7|2a4|T+F!_3Um6|5bXTcv)=0yoTqZ_ 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

NqI!g(rJ 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 VZW$RFZkeSDa`H;tva+(={{utNsMY`g literal 0 HcmV?d00001 diff --git a/romancal/patch_match/test/test_patch_match.py b/romancal/patch_match/test/test_patch_match.py new file mode 100644 index 000000000..916115552 --- /dev/null +++ b/romancal/patch_match/test/test_patch_match.py @@ -0,0 +1,193 @@ +""" +Unit tests for patch_match. + +These tests depend very strongly on the contents of the referenced table of patches. +Changes to the contents of this table will require changes to the tests for +any unit tests that depend on specific matches to patches in the table. + +Any changes to the matching algorithm should be completely separate from any +changes to the table contents. + +The tests include the following cases to validate the matches +1) Simple case at ra, dec, pa = 0, 0, 0 +2) 1) translated to ra, de, pa = 180, 40, 0 +3) Same as 2) but with pa = 45 and 60. +4) Same as 3) (pa=45 case) but with the lower corner just above, below, to the right + and to the left of a 4 patch corner + (assuming non-overlapping patchs within a common tangent point). + This requires identifying the ra, dec of such a corner in the table. +5) A test of a WCS provided example. + +Most of these tests check to see if the matches are what are expected, by index of +the table (the table format is expected to include the index of the entry as one +of its columns so that subsets of the table selected to reduce the filesize still +retain the same index obtained.) +""" + +import inspect +import os +import os.path + +import astropy.coordinates as coord +import astropy.modeling.models as amm +import astropy.units as u +import gwcs.coordinate_frames as cf +import gwcs.wcs as wcs +import numpy as np +import pytest +import spherical_geometry.vector as sgv + +import romancal.patch_match.patch_match as pm + +mpath = inspect.stack()[0][1] +pm.load_patch_table(os.path.join(os.path.split(mpath)[0], "patches_subset.asdf")) +rotate = sgv.rotate_around +absindex = 925050 +patchtable = pm.PATCH_TABLE +crecord = patchtable[np.where(patchtable[:]["index"] == absindex)] +cra = crecord["ra_corn3"] +if len(cra) == 1: + cra = cra[0] +cdec = crecord["dec_corn3"] +if len(cdec) == 1: + cdec = cdec[0] +cpa = 45.0 +csize = 0.001 +e = 0.0011 # epsilon offset in degrees + + +def mk_im_corners(ra, dec, pa, size): + """ + Generate 4 image corners of a square with the center at the supplied + side size, ra, dec, and position angle (all in degrees). + """ + # Generate 4 unit vectors at ra, dec = (0 , 0) + center = sgv.lonlat_to_vector(0.0, 0.0) + radecvec = sgv.lonlat_to_vector(ra, dec) + zaxis = (0.0, 0.0, 1.0) + yaxis = (0.0, 1.0, 0.0) + pp = rotate(*(rotate(*(center + yaxis + (-size / 2,))) + zaxis + (+size / 2,))) + pm = rotate(*(rotate(*(center + yaxis + (+size / 2,))) + zaxis + (+size / 2,))) + mp = rotate(*(rotate(*(center + yaxis + (-size / 2,))) + zaxis + (-size / 2,))) + mm = rotate(*(rotate(*(center + yaxis + (+size / 2,))) + zaxis + (-size / 2,))) + rect = [pp, mp, mm, pm] + + # Now move to requested ra and dec + trect = [ + rotate(*(rotate(*(vec + yaxis + (-dec,))) + zaxis + (ra,))) for vec in rect + ] + # Rotate to desired position angle + rrect = [rotate(*(vec + radecvec + (pa,))) for vec in trect] + frect = [sgv.vector_to_lonlat(*vec) for vec in rrect] + # Reorganize by ra, dec arrays + radecrect = np.array(frect).transpose() + return radecrect + + +def mk_gwcs(ra=cra, dec=cdec, pa=cpa, bounding_box=None, pixel_shape=None): + """ + Construct a GWCS model for testing the patch matching when provided a WCS + This just implements a basic tangent projection with specified ra, dec, and + position angle + """ + transform = (amm.Shift(-2048) & amm.Shift(-2048)) | ( + amm.Scale(0.11 / 3600.0) & amm.Scale(0.11 / 3600.0) + | amm.Rotation2D(pa) + | amm.Pix2Sky_TAN() + | amm.RotateNative2Celestial(cra, cdec, 180.0) + ) + detector_frame = cf.Frame2D( + name="detector", axes_names=("x", "y"), unit=(u.pix, u.pix) + ) + sky_frame = cf.CelestialFrame( + reference_frame=coord.ICRS(), name="icrs", unit=(u.deg, u.deg) + ) + wcsobj = wcs.WCS([(detector_frame, transform), (sky_frame, None)]) + if pixel_shape is not None: + wcsobj.pixel_shape = pixel_shape + if bounding_box is not None: + wcsobj.bounding_box = bounding_box + return wcsobj + + +@pytest.mark.parametrize( + "pars, expected", + [ + ((cra, cdec + e, cpa, csize), (925051, 925151)), + ((cra, cdec - e, cpa, csize), (925050, 925150)), + ((cra + e, cdec, cpa, csize), (925150, 925151)), + ((cra - e, cdec, cpa, csize), (925050, 925051)), + ((cra, cdec, cpa, csize), (925050, 925051, 925150, 925151)), + ( + (cra, cdec, cpa, 0.5), + ( + 924750, + 924751, + 924849, + 924850, + 924851, + 924852, + 924948, + 924949, + 924950, + 924951, + 924952, + 924953, + 925047, + 925048, + 925049, + 925050, + 925051, + 925052, + 925053, + 925054, + 925147, + 925148, + 925149, + 925150, + 925151, + 925152, + 925153, + 925154, + 925248, + 925249, + 925250, + 925251, + 925252, + 925253, + 925349, + 925350, + 925351, + 925352, + 925450, + 925451, + ), + ), + ], +) +def test_corners(pars, expected): + corners = mk_im_corners(*pars) + matches, close = pm.find_patch_matches(corners) + # map matches to absolute index + mmatches = tuple([patchtable[match]["index"] for match in matches]) + assert tuple(mmatches) == expected + + +def test_wcs_corners(): + imshape = (4096, 4096) + wcsobj = mk_gwcs() + matches, close = pm.find_patch_matches(wcsobj, image_shape=imshape) + mmatches = tuple([patchtable[match]["index"] for match in matches]) + assert tuple(mmatches) == (925050, 925051, 925150, 925151) + wcsobj.pixel_shape = imshape + matches, close = pm.find_patch_matches(wcsobj) + mmatches = tuple([patchtable[match]["index"] for match in matches]) + assert tuple(mmatches) == (925050, 925051, 925150, 925151) + wcsobj.pixel_shape = None + wcsobj.bounding_box = ((-0.5, 4096 - 0.5), (-0.5, 4096 - 0.5)) + matches, close = pm.find_patch_matches(wcsobj) + mmatches = tuple([patchtable[match]["index"] for match in matches]) + assert tuple(mmatches) == (925050, 925051, 925150, 925151) + wcsobj.bounding_box = None + with pytest.raises(ValueError): + matches, close = pm.find_patch_matches(wcsobj)