def test_tan_sip_wcs(self): """ Test that getTanSipWcs works by fitting a TAN WCS and a TAN-SIP WCS to the a detector with distortions and verifying that the TAN-SIP WCS better approximates the truth. """ arcsec_per_radian = 180.0*3600.0/np.pi tanWcs = self.wcs.getTanWcs() tanSipWcs = self.wcs.getTanSipWcs() tanWcsRa = [] tanWcsDec = [] tanSipWcsRa = [] tanSipWcsDec = [] xPixList = [] yPixList = [] for xx in np.arange(0.0, 4001.0, 1000.0): for yy in np.arange(0.0, 4001.0, 1000.0): xPixList.append(xx) yPixList.append(yy) pt = afwGeom.Point2D(xx ,yy) skyPt = tanWcs.pixelToSky(pt).getPosition() tanWcsRa.append(skyPt.getX()) tanWcsDec.append(skyPt.getY()) skyPt = tanSipWcs.pixelToSky(pt).getPosition() tanSipWcsRa.append(skyPt.getX()) tanSipWcsDec.append(skyPt.getY()) tanWcsRa = np.radians(np.array(tanWcsRa)) tanWcsDec = np.radians(np.array(tanWcsDec)) tanSipWcsRa = np.radians(np.array(tanSipWcsRa)) tanSipWcsDec = np.radians(np.array(tanSipWcsDec)) xPixList = np.array(xPixList) yPixList = np.array(yPixList) raTest, decTest = \ self.wcs._camera.raDecFromPixelCoords(xPixList, yPixList, [self.wcs._chip_name]*len(xPixList)) for rrTest, ddTest, rrTan, ddTan, rrSip, ddSip in \ zip(raTest, decTest, tanWcsRa, tanWcsDec, tanSipWcsRa, tanSipWcsDec): pp = CelestialCoord(rrTest*galsim.radians, ddTest*galsim.radians) distTan = \ pp.distanceTo(CelestialCoord(rrTan*galsim.radians, ddTan*galsim.radians))/galsim.arcsec distSip = \ pp.distanceTo(CelestialCoord(rrSip*galsim.radians, ddSip*galsim.radians))/galsim.arcsec msg = 'error in TAN WCS %e arcsec; error in TAN-SIP WCS %e arcsec' % (distTan, distSip) self.assertLess(distSip, 0.001, msg=msg) self.assertGreater(distTan-distSip, 1.0e-10, msg=msg)
def test_pupil_coordinates_from_floats(self): """ Test that the method which converts floats into pupil coordinates agrees with the method that converts CelestialCoords into pupil coordinates """ start = time.clock() raPointing = 113.0 decPointing = -25.6 rot = 82.1 pointing = CelestialCoord(raPointing*galsim.degrees, decPointing*galsim.degrees) camera = LsstCamera(pointing, rot*galsim.degrees) arcsec_per_radian = 180.0*3600.0/np.pi rng = np.random.RandomState(33) raList = (rng.random_sample(100)-0.5)*20.0+raPointing decList = (rng.random_sample(100)-0.5)*20.0+decPointing pointingList = [] for rr, dd in zip(raList, decList): pointingList.append(CelestialCoord(rr*galsim.degrees, dd*galsim.degrees)) control_x, control_y = camera.pupilCoordsFromPoint(pointingList) test_x, test_y = camera.pupilCoordsFromFloat(np.radians(raList), np.radians(decList)) np.testing.assert_array_almost_equal((test_x - control_x)*arcsec_per_radian, np.zeros(len(test_x)), 10) np.testing.assert_array_almost_equal((test_y - control_y)*arcsec_per_radian, np.zeros(len(test_y)), 10) print 'time to run %s = %e sec' % (funcname(), time.clock()-start)
def test_rotation_angle_pixel_coordinate_convention(self): """ Test the convention on how rotation angle affects the orientation of north on the focal plane (in pixel coordinates) by calculating the pixel coordinates of positions slightly displaced from the center of the camera. """ start = time.clock() ra = 30.0 dec = 0.0 delta = 0.001 pointing = CelestialCoord(ra*galsim.degrees, dec*galsim.degrees) north = CelestialCoord(ra*galsim.degrees, (dec+delta)*galsim.degrees) east = CelestialCoord((ra+delta)*galsim.degrees, dec*galsim.degrees) camera = LsstCamera(pointing, 0.0*galsim.degrees) x_0, y_0, name = camera.pixelCoordsFromPoint(pointing) x_n, y_n, name = camera.pixelCoordsFromPoint(north) x_e, y_e, name = camera.pixelCoordsFromPoint(east) self.assertGreater(x_n-x_0, 10.0) self.assertAlmostEqual(y_n-y_0, 0.0, 7) self.assertAlmostEqual(x_e-x_0, 0.0, 7) self.assertGreater(y_e-y_0, 10.0) camera = LsstCamera(pointing, 90.0*galsim.degrees) x_0, y_0, name = camera.pixelCoordsFromPoint(pointing) x_n, y_n, name = camera.pixelCoordsFromPoint(north) x_e, y_e, name = camera.pixelCoordsFromPoint(east) self.assertAlmostEqual(x_n-x_0, 0.0, 7) self.assertGreater(y_n-y_0, 10.0) self.assertLess(x_e-x_0, -10.0) self.assertAlmostEqual(y_e-y_0, 0.0, 7) camera = LsstCamera(pointing, -90.0*galsim.degrees) x_0, y_0, name = camera.pixelCoordsFromPoint(pointing) x_n, y_n, name = camera.pixelCoordsFromPoint(north) x_e, y_e, name = camera.pixelCoordsFromPoint(east) self.assertAlmostEqual(x_n-x_0, 0.0, 7) self.assertLess(y_n-y_0, -10.0) self.assertGreater(x_e-x_0, 10.0) self.assertAlmostEqual(y_e-y_0, 0.0, 7) camera = LsstCamera(pointing, 180.0*galsim.degrees) x_0, y_0, name = camera.pixelCoordsFromPoint(pointing) x_n, y_n, name = camera.pixelCoordsFromPoint(north) x_e, y_e, name = camera.pixelCoordsFromPoint(east) self.assertLess(x_n-x_0, -10.0) self.assertAlmostEqual(y_n-y_0, 0.0, 7) self.assertAlmostEqual(x_e-x_0, 0.0, 7) self.assertLess(y_e-y_0, -10.0) print 'time to run %s = %e sec' % (funcname(), time.clock()-start)
def test_rotation_angle_pupil_coordinate_convention(self): """ Test the convention on how rotation angle affects the orientation of north on the focal plane (in pupil coordinates) by calculating the puipil coordinates of positions slightly displaced from the center of the camera. """ ra = 30.0 dec = 0.0 delta = 0.001 pointing = CelestialCoord(ra * galsim.degrees, dec * galsim.degrees) north = CelestialCoord(ra * galsim.degrees, (dec + delta) * galsim.degrees) east = CelestialCoord((ra + delta) * galsim.degrees, dec * galsim.degrees) camera = LsstCamera(pointing, 0.0 * galsim.degrees) x_0, y_0 = camera.pupilCoordsFromPoint(pointing) x_n, y_n = camera.pupilCoordsFromPoint(north) x_e, y_e = camera.pupilCoordsFromPoint(east) self.assertAlmostEqual(0.0, np.degrees(x_0), 7) self.assertAlmostEqual(0.0, np.degrees(y_0), 7) self.assertAlmostEqual(0.0, np.degrees(x_n), 7) self.assertGreater(np.degrees(y_n), 1.0e-4) self.assertLess(np.degrees(x_e), -1.0e-4) self.assertAlmostEqual(np.degrees(y_e), 0.0, 7) camera = LsstCamera(pointing, 90.0 * galsim.degrees) x_n, y_n = camera.pupilCoordsFromPoint(north) x_e, y_e = camera.pupilCoordsFromPoint(east) self.assertLess(np.degrees(x_n), -1.0e-4) self.assertAlmostEqual(np.degrees(y_n), 0.0, 7) self.assertAlmostEqual(np.degrees(x_e), 0.0, 7) self.assertLess(np.degrees(y_e), -1.0e-4) camera = LsstCamera(pointing, -90.0 * galsim.degrees) x_n, y_n = camera.pupilCoordsFromPoint(north) x_e, y_e = camera.pupilCoordsFromPoint(east) self.assertGreater(np.degrees(x_n), 1.0e-4) self.assertAlmostEqual(np.degrees(y_n), 0.0, 7) self.assertAlmostEqual(np.degrees(x_e), 0.0, 7) self.assertGreater(np.degrees(y_e), 1.0e-4) camera = LsstCamera(pointing, 180.0 * galsim.degrees) x_n, y_n = camera.pupilCoordsFromPoint(north) x_e, y_e = camera.pupilCoordsFromPoint(east) self.assertAlmostEqual(np.degrees(x_n), 0, 7) self.assertLess(np.degrees(y_n), -1.0e-4) self.assertGreater(np.degrees(x_e), 1.0e-4) self.assertAlmostEqual(np.degrees(y_e), 0.0, 7)
def test_tan_wcs(self): """ Test method to return a Tan WCS by generating a bunch of pixel coordinates in the undistorted TAN-PIXELS coordinate system. Then, use sims_coordUtils to convert those pixel coordinates into RA and Dec. Compare these to the RA and Dec returned by the WCS. Demand agreement to witin 0.001 arcseconds. Note: if you use a bigger camera, it is possible to have disagreements of order a few milliarcseconds. """ start = time.clock() xPixList = [] yPixList = [] tanWcs = self.wcs.getTanWcs() wcsRa = [] wcsDec = [] for xx in np.arange(0.0, 4001.0, 1000.0): for yy in np.arange(0.0, 4001.0, 1000.0): xPixList.append(xx) yPixList.append(yy) pt = afwGeom.Point2D(xx ,yy) skyPt = tanWcs.pixelToSky(pt).getPosition() wcsRa.append(skyPt.getX()) wcsDec.append(skyPt.getY()) wcsRa = np.radians(np.array(wcsRa)) wcsDec = np.radians(np.array(wcsDec)) xPixList = np.array(xPixList) yPixList = np.array(yPixList) raTest, decTest = \ self.wcs._camera.raDecFromTanPixelCoords(xPixList, yPixList, [self.wcs._chip_name]*len(xPixList)) for rr1, dd1, rr2, dd2 in zip(raTest, decTest, wcsRa, wcsDec): pp = CelestialCoord(rr1*galsim.radians, dd1*galsim.radians) dist = \ pp.distanceTo(CelestialCoord(rr2*galsim.radians, dd2*galsim.radians))/galsim.arcsec msg = 'error in tanWcs was %e arcsec' % dist self.assertLess(dist, 0.001, msg=msg) print 'time to run %s = %e sec' % (funcname(), time.clock()-start)
def test_eq(self): """ Test that __eq__ works for LsstWCS """ start = time.clock() wcs1 = LsstWCS(self.pointing, self.rotation, self.chip_name) self.assertEqual(self.wcs, wcs1) new_origin = galsim.PositionI(9, 9) wcs1 = wcs1._newOrigin(new_origin) self.assertNotEqual(self.wcs, wcs1) other_pointing = CelestialCoord(1.9*galsim.degrees, -34.0*galsim.degrees) wcs2 = LsstWCS(other_pointing, self.rotation, self.chip_name) self.assertNotEqual(self.wcs, wcs2) wcs3 = LsstWCS(self.pointing, 112.0*galsim.degrees, self.chip_name) self.assertNotEqual(self.wcs, wcs3) wcs4 = LsstWCS(self.pointing, self.rotation, 'R:2,2 S:2,2') self.assertNotEqual(self.wcs, wcs4) print 'time to run %s = %e sec' % (funcname(), time.clock()-start)
def test_attribute_exceptions(self): """ Test that exceptions are raised when you try to re-assign LsstWCS attributes """ with self.assertRaises(AttributeError) as context: self.wcs.pointing = CelestialCoord(22.0*galsim.degrees, -17.0*galsim.degrees) with self.assertRaises(AttributeError) as context: self.wcs.rotation_angle = 23.0*galsim.degrees with self.assertRaises(AttributeError) as context: self.wcs.chip_name = 'R:4,4 S:1,1'
def setUpClass(cls): if not have_lsst_stack: # skip doesn't apply to setUpClass. cf. https://github.com/nose-devs/nose/issues/946 return # these are taken from the header of the # galsim_afwCameraGeom_data.txt file generated by # GalSim/devel/external/generate_galsim_lsst_camera_validation.py cls.raPointing = 112.064181578541 cls.decPointing = -33.015167519966 cls.rotation = 27.0 pointing = CelestialCoord(cls.raPointing*galsim.degrees, cls.decPointing*galsim.degrees) cls.camera = LsstCamera(pointing, cls.rotation*galsim.degrees)
def test_copy(self): """ Test that copy() works """ pointing = CelestialCoord(64.82*galsim.degrees, -16.73*galsim.degrees) rotation = 116.8*galsim.degrees chip_name = 'R:1,2 S:2,2' wcs0 = LsstWCS(pointing, rotation, chip_name) wcs0 = wcs0._newOrigin(galsim.PositionI(112, 4)) wcs1 = wcs0.copy() self.assertEqual(wcs0, wcs1) wcs0 = wcs0._newOrigin(galsim.PositionI(66, 77)) self.assertNotEqual(wcs0, wcs1)
def test_constructor(self): """ Just make sure that the constructor for LsstWCS runs, and that it throws an error when you specify a nonsense chip. """ pointing = CelestialCoord(112.0*galsim.degrees, -39.0*galsim.degrees) rotation = 23.1*galsim.degrees wcs1 = LsstWCS(pointing, rotation, 'R:1,1 S:2,2') with self.assertRaises(RuntimeError) as context: wcs2 = LsstWCS(pointing, rotation, 'R:1,1 S:3,3') self.assertEqual(context.exception.args[0], "R:1,1 S:3,3 is not a valid chip_name for an LsstWCS")
def test_attribute_exceptions(self): """ Test that exceptions are raised when you try to re-assign LsstWCS attributes """ start = time.clock() with self.assertRaises(AttributeError) as context: self.wcs.pointing = CelestialCoord(22.0*galsim.degrees, -17.0*galsim.degrees) with self.assertRaises(AttributeError) as context: self.wcs.rotation_angle = 23.0*galsim.degrees with self.assertRaises(AttributeError) as context: self.wcs.chip_name = 'R:4,4 S:1,1' print 'time to run %s = %e sec' % (funcname(), time.clock()-start)
def test_copy(self): """ Test that copy() works """ start = time.clock() pointing = CelestialCoord(64.82*galsim.degrees, -16.73*galsim.degrees) rotation = 116.8*galsim.degrees chip_name = 'R:1,2 S:2,2' wcs0 = LsstWCS(pointing, rotation, chip_name) wcs0 = wcs0._newOrigin(galsim.PositionI(112, 4)) wcs1 = wcs0.copy() self.assertEqual(wcs0, wcs1) wcs0 = wcs0._newOrigin(galsim.PositionI(66, 77)) self.assertNotEqual(wcs0, wcs1) print 'time to run %s = %e sec' % (funcname(), time.clock()-start)
def test_pupil_coordinates(self): """ Test the conversion between (RA, Dec) and pupil coordinates. Results are checked against the routine provided by PALPY. """ start = time.clock() def palpyPupilCoords(star, pointing): """ This is just a copy of the PALPY method Ds2tp, which I am taking to be the ground truth for projection from a sphere onto the tangent plane inputs ------------ star is a CelestialCoord corresponding to the point being projected pointing is a CelestialCoord corresponding to the pointing of the 'telescope' outputs ------------ The x and y coordinates in the focal plane (radians) """ ra = star.ra/galsim.radians dec = star.dec/galsim.radians ra_pointing = pointing.ra/galsim.radians dec_pointing = pointing.dec/galsim.radians cdec = np.cos(dec) sdec = np.sin(dec) cdecz = np.cos(dec_pointing) sdecz = np.sin(dec_pointing) cradif = np.cos(ra - ra_pointing) sradif = np.sin(ra - ra_pointing) denom = sdec * sdecz + cdec * cdecz * cradif xx = cdec * sradif/denom yy = (sdec * cdecz - cdec * sdecz * cradif)/denom return xx, yy rng = np.random.RandomState(42) n_pointings = 10 ra_pointing_list = rng.random_sample(n_pointings)*2.0*np.pi dec_pointing_list = 0.5*(rng.random_sample(n_pointings)-0.5)*np.pi rotation_angle_list = rng.random_sample(n_pointings)*2.0*np.pi radians_to_arcsec = 3600.0*np.degrees(1.0) for ra, dec, rotation in zip(ra_pointing_list, dec_pointing_list, rotation_angle_list): pointing = CelestialCoord(ra*galsim.radians, dec*galsim.radians) camera = LsstCamera(pointing, rotation*galsim.radians) dra_list = (rng.random_sample(100)-0.5)*0.5 ddec_list = (rng.random_sample(100)-0.5)*0.5 star_list = np.array([CelestialCoord((ra+dra)*galsim.radians, (dec+ddec)*galsim.radians) for dra, ddec in zip(dra_list, ddec_list)]) xTest, yTest = camera.pupilCoordsFromPoint(star_list) xControl = [] yControl = [] for star in star_list: xx, yy = palpyPupilCoords(star, pointing) xx *= -1.0 xControl.append(xx*np.cos(rotation) - yy*np.sin(rotation)) yControl.append(yy*np.cos(rotation) + xx*np.sin(rotation)) xControl = np.array(xControl) yControl = np.array(yControl) np.testing.assert_array_almost_equal((xTest*radians_to_arcsec) - (xControl*radians_to_arcsec), np.zeros(len(xControl)), 7) np.testing.assert_array_almost_equal((yTest*radians_to_arcsec) - (yControl*radians_to_arcsec), np.zeros(len(yControl)), 7) print 'time to run %s = %e sec' % (funcname(), time.clock()-start)