def testObservedFromICRS(self): obs = ObservationMetaData(pointingRA=35.0, pointingDec=-45.0, mjd=43572.0) for pmRaList in [self.pm_raList, None]: for pmDecList in [self.pm_decList, None]: for pxList in [self.pxList, None]: for vRadList in [self.v_radList, None]: for includeRefraction in [True, False]: raRad, decRad = utils._observedFromICRS(self.raList, self.decList, pm_ra=pmRaList, pm_dec=pmDecList, parallax=pxList, v_rad=vRadList, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) raDeg, decDeg = utils.observedFromICRS(np.degrees(self.raList), np.degrees(self.decList), pm_ra=utils.arcsecFromRadians(pmRaList), pm_dec=utils.arcsecFromRadians(pmDecList), parallax=utils.arcsecFromRadians(pxList), v_rad=vRadList, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) dRa = utils.arcsecFromRadians(raRad-np.radians(raDeg)) np.testing.assert_array_almost_equal(dRa, np.zeros(self.nStars), 9) dDec = utils.arcsecFromRadians(decRad-np.radians(decDeg)) np.testing.assert_array_almost_equal(dDec, np.zeros(self.nStars), 9)
def testObservedFromICRS(self): obs = ObservationMetaData(pointingRA=35.0, pointingDec=-45.0, mjd=43572.0) for pmRaList in [self.pm_raList, None]: for pmDecList in [self.pm_decList, None]: for pxList in [self.pxList, None]: for vRadList in [self.v_radList, None]: for includeRefraction in [True, False]: raRad, decRad = utils._observedFromICRS( self.raList, self.decList, pm_ra=pmRaList, pm_dec=pmDecList, parallax=pxList, v_rad=vRadList, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) raDeg, decDeg = utils.observedFromICRS( np.degrees(self.raList), np.degrees(self.decList), pm_ra=utils.arcsecFromRadians(pmRaList), pm_dec=utils.arcsecFromRadians(pmDecList), parallax=utils.arcsecFromRadians(pxList), v_rad=vRadList, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) dRa = utils.arcsecFromRadians(raRad - np.radians(raDeg)) np.testing.assert_array_almost_equal( dRa, np.zeros(self.nStars), 9) dDec = utils.arcsecFromRadians(decRad - np.radians(decDeg)) np.testing.assert_array_almost_equal( dDec, np.zeros(self.nStars), 9)
def test_stellar_observed_degrees(self): """ Test ability to go all the way to observed RA, Dec from PhoSim (this is necessary for the ImSim software that DESC is working on) """ db = testStarsDBObj(driver='sqlite', database=self.db_name) cat = StarTestCatalog(db, obs_metadata=self.obs) with lsst.utils.tests.getTempFilePath('.txt') as cat_name: cat.write_catalog(cat_name) dtype = np.dtype([('raICRS', float), ('decICRS', float), ('raPhoSim', float), ('decPhoSim', float), ('raJ2000', float), ('decJ2000', float), ('pmRA', float), ('pmDec', float), ('parallax', float), ('vRad', float)]) data = np.genfromtxt(cat_name, dtype=dtype) self.assertGreater(len(data), 100) (ra_obs, dec_obs) = observedFromICRS(np.degrees(data['raJ2000']), np.degrees(data['decJ2000']), obs_metadata=self.obs, pm_ra=arcsecFromRadians(data['pmRA']), pm_dec=arcsecFromRadians(data['pmDec']), parallax=arcsecFromRadians(data['parallax']), v_rad=data['vRad'], includeRefraction=True, epoch=2000.0) (ra_appGeo, dec_appGeo) = PhoSimAstrometryBase.appGeoFromPhoSim(data['raPhoSim'], data['decPhoSim'], self.obs) (ra_obs_2, dec_obs_2) = observedFromAppGeo(ra_appGeo, dec_appGeo, obs_metadata=self.obs, includeRefraction=True) dd = 3600.0*angularSeparation(ra_obs, dec_obs, ra_obs_2, dec_obs_2) self.assertLess(dd.max(), 1.0e-5)
def test_against_catalog(self): """ Compare deprecession results to a catalog that was validated with PhoSim. """ obs = ObservationMetaData(pointingRA=53.00913847303155535, pointingDec=-27.43894880881512321, rotSkyPos=256.75075318193080420, mjd=59580.13955500000156462, site=Site(name="LSST", pressure=0.0, humidity=0.0)) dtype = np.dtype([('id', int), ('ra', float), ('dec', float), ('ra_deprecessed', float), ('dec_deprecessed', float), ('x_dm', float), ('y_dm', float), ('x_focal', float), ('y_focal', float), ('x_cam', float), ('y_cam', float)]) data = np.genfromtxt(os.path.join(getPackageDir('sims_catUtils'), 'tests', 'testData', 'pixel_prediction_catalog.txt'), dtype=dtype) ra_obs, dec_obs = observedFromICRS(data['ra'], data['dec'], obs_metadata=obs, includeRefraction=False, epoch=2000.0) phosim_mixin = PhoSimAstrometryBase() ra_dep, dec_dep = phosim_mixin._dePrecess(np.radians(ra_obs), np.radians(dec_obs), obs) dd = 3600.0 * angularSeparation( data['ra_deprecessed'], data['dec_deprecessed'], np.degrees(ra_dep), np.degrees(dec_dep)) self.assertLess(dd.max(), 1.0e-5)
def test_stellar_observed_degrees(self): """ Test ability to go all the way to observed RA, Dec from PhoSim (this is necessary for the ImSim software that DESC is working on) """ db = testStarsDBObj(driver='sqlite', database=self.db_name) cat = StarTestCatalog(db, obs_metadata=self.obs) with lsst.utils.tests.getTempFilePath('.txt') as cat_name: cat.write_catalog(cat_name) dtype = np.dtype([('raICRS', float), ('decICRS', float), ('raPhoSim', float), ('decPhoSim', float), ('raJ2000', float), ('decJ2000', float), ('pmRA', float), ('pmDec', float), ('parallax', float), ('vRad', float)]) data = np.genfromtxt(cat_name, dtype=dtype) self.assertGreater(len(data), 100) (ra_obs, dec_obs) = observedFromICRS( np.degrees(data['raJ2000']), np.degrees(data['decJ2000']), obs_metadata=self.obs, pm_ra=arcsecFromRadians(data['pmRA']), pm_dec=arcsecFromRadians(data['pmDec']), parallax=arcsecFromRadians(data['parallax']), v_rad=data['vRad'], includeRefraction=True, epoch=2000.0) (ra_appGeo, dec_appGeo) = PhoSimAstrometryBase.appGeoFromPhoSim( data['raPhoSim'], data['decPhoSim'], self.obs) (ra_obs_2, dec_obs_2) = observedFromAppGeo(ra_appGeo, dec_appGeo, obs_metadata=self.obs, includeRefraction=True) dd = 3600.0 * angularSeparation(ra_obs, dec_obs, ra_obs_2, dec_obs_2) self.assertLess(dd.max(), 1.0e-5)
def test_against_catalog(self): """ Compare deprecession results to a catalog that was validated with PhoSim. """ obs = ObservationMetaData(pointingRA=53.00913847303155535, pointingDec=-27.43894880881512321, rotSkyPos=256.75075318193080420, mjd=59580.13955500000156462, site=Site(name="LSST", pressure=0.0, humidity=0.0)) dtype = np.dtype([('id', int), ('ra', float), ('dec', float), ('ra_deprecessed', float), ('dec_deprecessed', float), ('x_dm', float), ('y_dm', float), ('x_focal', float), ('y_focal', float), ('x_cam', float), ('y_cam', float)]) data = np.genfromtxt(os.path.join(getPackageDir('sims_catUtils'), 'tests', 'testData', 'pixel_prediction_catalog.txt'), dtype=dtype) ra_obs, dec_obs = observedFromICRS(data['ra'], data['dec'], obs_metadata=obs, includeRefraction=False, epoch=2000.0) phosim_mixin = PhoSimAstrometryBase() ra_dep, dec_dep = phosim_mixin._dePrecess(np.radians(ra_obs), np.radians(dec_obs), obs) dd = 3600.0*angularSeparation(data['ra_deprecessed'], data['dec_deprecessed'], np.degrees(ra_dep), np.degrees(dec_dep)) self.assertLess(dd.max(), 1.0e-5)
def testRaDec(self): """ Test that raDecFromNativeLonLat does invert nativeLonLatFromRaDec """ np.random.seed(42) nSamples = 100 rrList = np.random.random_sample(nSamples)*50.0 # because raDecFromNativeLonLat is only good # out to a zenith distance of ~ 70 degrees thetaList = np.random.random_sample(nSamples)*2.0*np.pi rrPointingList = np.random.random_sample(10)*50.0 thetaPointingList = np.random.random_sample(10)*2.0*np.pi mjdList = np.random.random_sample(nSamples)*10000.0 + 43000.0 for rrp, thetap, mjd in \ zip(rrPointingList, thetaPointingList, mjdList): site = Site(name='LSST') raZenith, decZenith = raDecFromAltAz(180.0, 0.0, ObservationMetaData(mjd=mjd, site=site)) rp = raZenith + rrp*np.cos(thetap) dp = decZenith + rrp*np.sin(thetap) obs = ObservationMetaData(pointingRA=rp, pointingDec=dp, mjd=mjd, site=site) raList_icrs = (raZenith + rrList*np.cos(thetaList)) % 360.0 decList_icrs = decZenith + rrList*np.sin(thetaList) raList_obs, decList_obs = observedFromICRS(raList_icrs, decList_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=True) # calculate the distance between the ICRS position and the observed # geocentric position dd_icrs_obs_list = arcsecFromRadians(haversine(np.radians(raList_icrs), np.radians(decList_icrs), np.radians(raList_obs), np.radians(decList_obs))) for rr, dd, dd_icrs_obs in zip(raList_icrs, decList_icrs, dd_icrs_obs_list): lon, lat = nativeLonLatFromRaDec(rr, dd, obs) r1, d1 = raDecFromNativeLonLat(lon, lat, obs) # the distance between the input RA, Dec and the round-trip output # RA, Dec distance = arcsecFromRadians(haversine(np.radians(r1), np.radians(d1), np.radians(rr), np.radians(dd))) rr_obs, dec_obs = observedFromICRS(np.array([rr]), np.array([dd]), obs_metadata=obs, epoch=2000.0, includeRefraction=True) # verify that the round trip through nativeLonLat only changed # RA, Dec by less than an arcsecond self.assertLess(distance, 1.0) # verify that any difference in the round trip is much less # than the distance between the ICRS and the observed geocentric # RA, Dec self.assertLess(distance, dd_icrs_obs*0.01)
def testNativeLongLatComplicated(self): """ Test that nativeLongLatFromRaDec works by considering stars and pointings at non-intuitive locations. """ np.random.seed(42) nPointings = 10 raPointingList_icrs = np.random.random_sample(nPointings)*360.0 decPointingList_icrs = np.random.random_sample(nPointings)*180.0 - 90.0 mjdList = np.random.random_sample(nPointings)*10000.0 + 43000.0 nStars = 10 for raPointing_icrs, decPointing_icrs, mjd in \ zip(raPointingList_icrs, decPointingList_icrs, mjdList): obs = ObservationMetaData(pointingRA=raPointing_icrs, pointingDec=decPointing_icrs, mjd=mjd) raList_icrs = np.random.random_sample(nStars)*360.0 decList_icrs = np.random.random_sample(nStars)*180.0 - 90.0 raList_obs, decList_obs = observedFromICRS(raList_icrs, decList_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=True) obsTemp = ObservationMetaData(mjd=mjd) ra_temp, dec_temp = observedFromICRS(np.array([raPointing_icrs]), np.array([decPointing_icrs]), obs_metadata=obsTemp, epoch=2000.0, includeRefraction=True) raPointing_obs = ra_temp[0] decPointing_obs = dec_temp[0] for ra_obs, dec_obs, ra_icrs, dec_icrs in \ zip(raList_obs, decList_obs, raList_icrs, decList_icrs): raRad = np.radians(ra_obs) decRad = np.radians(dec_obs) sinRa = np.sin(raRad) cosRa = np.cos(raRad) sinDec = np.sin(decRad) cosDec = np.cos(decRad) # the three dimensional position of the star controlPosition = np.array([-cosDec*sinRa, cosDec*cosRa, sinDec]) # calculate the rotation matrices needed to transform the # x, y, and z axes into the local x, y, and z axes # (i.e. the axes with z lined up with raPointing_obs, decPointing_obs) alpha = 0.5*np.pi - np.radians(decPointing_obs) ca = np.cos(alpha) sa = np.sin(alpha) rotX = np.array([[1.0, 0.0, 0.0], [0.0, ca, sa], [0.0, -sa, ca]]) cb = np.cos(np.radians(raPointing_obs)) sb = np.sin(np.radians(raPointing_obs)) rotZ = np.array([[cb, -sb, 0.0], [sb, cb, 0.0], [0.0, 0.0, 1.0]]) # rotate the coordinate axes into the local basis xAxis = np.dot(rotZ, np.dot(rotX, np.array([1.0, 0.0, 0.0]))) yAxis = np.dot(rotZ, np.dot(rotX, np.array([0.0, 1.0, 0.0]))) zAxis = np.dot(rotZ, np.dot(rotX, np.array([0.0, 0.0, 1.0]))) # calculate the local longitude and latitude of the star lon, lat = nativeLonLatFromRaDec(ra_icrs, dec_icrs, obs) cosLon = np.cos(np.radians(lon)) sinLon = np.sin(np.radians(lon)) cosLat = np.cos(np.radians(lat)) sinLat = np.sin(np.radians(lat)) # the x, y, z position of the star in the local coordinate basis transformedPosition = np.array([-cosLat*sinLon, cosLat*cosLon, sinLat]) # convert that position back into the un-rotated bases testPosition = transformedPosition[0]*xAxis + \ transformedPosition[1]*yAxis + \ transformedPosition[2]*zAxis # assert that testPosition and controlPosition should be equal distance = np.sqrt(np.power(controlPosition-testPosition, 2).sum()) self.assertLess(distance, 1.0e-12)
def test_pixel_positions(self): """ Test that CatSim pixel positions are close to PhoSim pixel positions. This is complicated by the fact that PhoSim uses the camera team definition of pixel space, which differs from the DM definition of pixel space as follows: Camera +y = DM +x Camera +x = DM -y Camera +z = DM +z This has been verified both by consulting documentation -- the documentation for afwCameraGeom says that +x is along the serial readout direction; LCA-13381 indicates that, in the Camera team's definition, the serial readout is along +y -- and phenomenologically by comparing the relationship between pixelCoordsFromPupilCoords() to visual inspection of PhoSim-generated FITS images. """ self.assertGreater(len(self.data), 10) for ix in range(len(self.data)): in_name = self.data['chipName'][ix] chip_name = in_name[0] + ':' + in_name[1] + ',' + in_name[2] chip_name += ' ' + in_name[3] + ':' + in_name[4] + ',' + in_name[5] corner_pixels = getCornerPixels(chip_name, lsst_camera()) x_center_dm = 0.25 * (corner_pixels[0][0] + corner_pixels[1][0] + corner_pixels[2][0] + corner_pixels[3][0]) y_center_dm = 0.25 * (corner_pixels[0][1] + corner_pixels[1][1] + corner_pixels[2][1] + corner_pixels[3][1]) obs = ObservationMetaData(pointingRA=self.data['pointingRA'][ix], pointingDec=self.data['pointingDec'][ix], rotSkyPos=self.data['rotSkyPos'][ix], mjd=59580.0) xpix, ypix = pixelCoordsFromRaDecLSST(self.data['objRA'][ix], self.data['objDec'][ix], obs_metadata=obs) raObs, decObs = observedFromICRS(self.data['objRA'][ix], self.data['objDec'][ix], obs_metadata=obs, epoch=2000.0) # find displacement from center of DM coordinates of the # objects as placed by PhoSim d_y_phosim = y_center_dm - self.data['xpix'][ix] d_x_phosim = self.data['ypix'][ix] - x_center_dm # displacement from center of DM coordinates as calculated # by DM d_x_dm = xpix - x_center_dm d_y_dm = ypix - y_center_dm d_pix = np.sqrt((d_x_dm - d_x_phosim)**2 + (d_y_dm - d_y_phosim)**2) # demand that the difference between the two displacements is less # than 0.05 of the total displacement from the center of the object # as calculated by DM msg = 'dx %e; dy %e' % (d_x_dm, d_y_dm) self.assertLess(d_pix, 0.05 * np.sqrt(d_x_dm**2 + d_y_dm**2), msg=msg)
def test_with_proper_motion(self): """ Test that calculating pupil coordinates in the presence of proper motion, parallax, and radial velocity is equivalent to observedFromICRS -> icrsFromObserved -> pupilCoordsFromRaDec (mostly to make surethat pupilCoordsFromRaDec is correctly calling observedFromICRS with non-zero proper motion, etc.) """ rng = np.random.RandomState(38442) is_valid = False while not is_valid: mjd_tai = 59580.0 + 10000.0 * rng.random_sample() obs = ObservationMetaData(mjd=mjd_tai) ra, dec = raDecFromAltAz(78.0, 112.0, obs) dd = distanceToSun(ra, dec, obs.mjd) if dd > 45.0: is_valid = True n_obj = 1000 rr = rng.random_sample(n_obj) * 2.0 theta = rng.random_sample(n_obj) * 2.0 * np.pi ra_list = ra + rr * np.cos(theta) dec_list = dec + rr * np.sin(theta) obs = ObservationMetaData(pointingRA=ra, pointingDec=dec, mjd=mjd_tai, rotSkyPos=19.0) pm_ra_list = rng.random_sample(n_obj) * 100.0 - 50.0 pm_dec_list = rng.random_sample(n_obj) * 100.0 - 50.0 px_list = rng.random_sample(n_obj) + 0.05 v_rad_list = rng.random_sample(n_obj) * 600.0 - 300.0 for includeRefraction in (True, False): ra_obs, dec_obs = observedFromICRS( ra_list, dec_list, pm_ra=pm_ra_list, pm_dec=pm_dec_list, parallax=px_list, v_rad=v_rad_list, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) ra_icrs, dec_icrs = icrsFromObserved( ra_obs, dec_obs, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) xp_control, yp_control = pupilCoordsFromRaDec( ra_icrs, dec_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) xp_test, yp_test = pupilCoordsFromRaDec( ra_list, dec_list, pm_ra=pm_ra_list, pm_dec=pm_dec_list, parallax=px_list, v_rad=v_rad_list, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) distance = arcsecFromRadians( np.sqrt( np.power(xp_test - xp_control, 2) + np.power(yp_test - yp_control, 2))) self.assertLess(distance.max(), 0.006) # now test it in radians xp_rad, yp_rad = _pupilCoordsFromRaDec( np.radians(ra_list), np.radians(dec_list), pm_ra=radiansFromArcsec(pm_ra_list), pm_dec=radiansFromArcsec(pm_dec_list), parallax=radiansFromArcsec(px_list), v_rad=v_rad_list, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) np.testing.assert_array_equal(xp_rad, xp_test) np.testing.assert_array_equal(yp_rad, yp_test) # now test it with proper motion = 0 ra_obs, dec_obs = observedFromICRS( ra_list, dec_list, parallax=px_list, v_rad=v_rad_list, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) ra_icrs, dec_icrs = icrsFromObserved( ra_obs, dec_obs, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) xp_control, yp_control = pupilCoordsFromRaDec( ra_icrs, dec_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) xp_test, yp_test = pupilCoordsFromRaDec( ra_list, dec_list, parallax=px_list, v_rad=v_rad_list, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) distance = arcsecFromRadians( np.sqrt( np.power(xp_test - xp_control, 2) + np.power(yp_test - yp_control, 2))) self.assertLess(distance.max(), 1.0e-6)
obs_metadata_list = OpSimDB.getObservationMetaData((88.0, -40.0), 5.0, fovRadius=radiusDegrees, makeCircBounds=True) obs_metadata = obs_metadata_list[0] #generate some random RA and Dec to find chips for nsamples = 10 numpy.random.seed(32) rr = numpy.radians(2.0) * numpy.random.sample(nsamples) theta = 2.0 * numpy.pi * numpy.random.sample(nsamples) ra = numpy.degrees( numpy.radians(obs_metadata.pointingRA) + rr * numpy.cos(theta)) dec = numpy.degrees( numpy.radians(obs_metadata.pointingDec) + rr * numpy.sin(theta)) #need to correct coordinates for precession, nutation, and aberration ra, dec = observedFromICRS(ra, dec, obs_metadata=obs_metadata, epoch=epoch) xx, yy = pupilCoordsFromRaDec(ra, dec, obs_metadata=obs_metadata, epoch=epoch) chipNames = chipNameFromRaDec(ra, dec, epoch=epoch, camera=camera, obs_metadata=obs_metadata) for (rr, dd, x, y, nn) in zip(ra, dec, xx, yy, chipNames): print(rr, dd, arcsecFromRadians(x), arcsecFromRadians(y), nn)
det_name_m = det_name.replace(':', '').replace(',', '').replace( ' ', '_') dm_xpix_in, dm_ypix_in = camera_wrapper.dmPixFromCameraPix( cam_xpix_in, cam_ypix_in, det_name) ra_icrs, dec_icrs = raDecFromPixelCoords(dm_xpix_in, dm_ypix_in, det_name, camera=lsst_camera(), obs_metadata=obs) ra_obs, dec_obs = observedFromICRS(ra_icrs, dec_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=False) (ra_deprecessed, dec_deprecessed) = de_precessor._dePrecess( np.radians(ra_obs), np.radians(dec_obs), obs) x_f, y_f = focalPlaneCoordsFromRaDec(ra_icrs, dec_icrs, obs_metadata=obs, camera=lsst_camera()) for ra, dec, camxx, camyy, r_icrs, d_icrs, dmxx, dmyy, xxf, yyf in \ zip(ra_deprecessed, dec_deprecessed, cam_xpix_in, cam_ypix_in, ra_icrs, dec_icrs, dm_xpix_in, dm_ypix_in, x_f, y_f):
def test_with_proper_motion(self): """ Test that calculating pupil coordinates in the presence of proper motion, parallax, and radial velocity is equivalent to observedFromICRS -> icrsFromObserved -> pupilCoordsFromRaDec (mostly to make surethat pupilCoordsFromRaDec is correctly calling observedFromICRS with non-zero proper motion, etc.) """ rng = np.random.RandomState(38442) is_valid = False while not is_valid: mjd_tai = 59580.0 + 10000.0*rng.random_sample() obs = ObservationMetaData(mjd=mjd_tai) ra, dec = raDecFromAltAz(78.0, 112.0, obs) dd = distanceToSun(ra, dec, obs.mjd) if dd > 45.0: is_valid = True n_obj = 1000 rr = rng.random_sample(n_obj)*2.0 theta = rng.random_sample(n_obj)*2.0*np.pi ra_list = ra + rr*np.cos(theta) dec_list = dec + rr*np.sin(theta) obs = ObservationMetaData(pointingRA=ra, pointingDec=dec, mjd=mjd_tai, rotSkyPos=19.0) pm_ra_list = rng.random_sample(n_obj)*100.0 - 50.0 pm_dec_list = rng.random_sample(n_obj)*100.0 - 50.0 px_list = rng.random_sample(n_obj) + 0.05 v_rad_list = rng.random_sample(n_obj)*600.0 - 300.0 for includeRefraction in (True, False): ra_obs, dec_obs = observedFromICRS(ra_list, dec_list, pm_ra=pm_ra_list, pm_dec=pm_dec_list, parallax=px_list, v_rad=v_rad_list, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) ra_icrs, dec_icrs = icrsFromObserved(ra_obs, dec_obs, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) xp_control, yp_control = pupilCoordsFromRaDec(ra_icrs, dec_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) xp_test, yp_test = pupilCoordsFromRaDec(ra_list, dec_list, pm_ra=pm_ra_list, pm_dec=pm_dec_list, parallax=px_list, v_rad=v_rad_list, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) distance = arcsecFromRadians(np.sqrt(np.power(xp_test-xp_control, 2) + np.power(yp_test-yp_control, 2))) self.assertLess(distance.max(), 0.006) # now test it in radians xp_rad, yp_rad = _pupilCoordsFromRaDec(np.radians(ra_list), np.radians(dec_list), pm_ra=radiansFromArcsec(pm_ra_list), pm_dec=radiansFromArcsec(pm_dec_list), parallax=radiansFromArcsec(px_list), v_rad=v_rad_list, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) np.testing.assert_array_equal(xp_rad, xp_test) np.testing.assert_array_equal(yp_rad, yp_test) # now test it with proper motion = 0 ra_obs, dec_obs = observedFromICRS(ra_list, dec_list, parallax=px_list, v_rad=v_rad_list, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) ra_icrs, dec_icrs = icrsFromObserved(ra_obs, dec_obs, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) xp_control, yp_control = pupilCoordsFromRaDec(ra_icrs, dec_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) xp_test, yp_test = pupilCoordsFromRaDec(ra_list, dec_list, parallax=px_list, v_rad=v_rad_list, obs_metadata=obs, epoch=2000.0, includeRefraction=includeRefraction) distance = arcsecFromRadians(np.sqrt(np.power(xp_test-xp_control, 2) + np.power(yp_test-yp_control, 2))) self.assertLess(distance.max(), 1.0e-6)
from lsst.obs.lsstSim import LsstSimMapper mapper = LsstSimMapper() camera = mapper.camera epoch = 2000.0 #generate an ObservationMetaData object based on an actual OpSim pointing obshistid = 88625744 radiusDegrees = 3.0 OpSimDB = OpSim3_61DBObject() obs_metadata = OpSimDB.getObservationMetaData(obshistid, radiusDegrees, makeCircBounds=True) #generate some random RA and Dec to find chips for nsamples = 10 numpy.random.seed(32) rr = numpy.radians(2.0)*numpy.random.sample(nsamples) theta = 2.0*numpy.pi*numpy.random.sample(nsamples) ra = numpy.degrees(numpy.radians(obs_metadata.pointingRA) + rr*numpy.cos(theta)) dec = numpy.degrees(numpy.radians(obs_metadata.pointingDec) + rr*numpy.sin(theta)) #need to correct coordinates for precession, nutation, and aberration ra, dec = observedFromICRS(ra, dec, obs_metadata=obs_metadata, epoch=epoch) xx, yy = pupilCoordsFromRaDec(ra, dec, obs_metadata=obs_metadata, epoch=epoch) chipNames = chipNameFromRaDec(ra, dec, epoch=epoch, camera=camera, obs_metadata=obs_metadata) for (rr,dd,x,y,nn) in zip(ra,dec,xx,yy,chipNames): print rr,dd,arcsecFromRadians(x),arcsecFromRadians(y),nn
def test_pixel_positions(self): """ Test that CatSim pixel positions are close to PhoSim pixel positions. This is complicated by the fact that PhoSim uses the camera team definition of pixel space, which differs from the DM definition of pixel space as follows: Camera +y = DM +x Camera +x = DM -y Camera +z = DM +z This has been verified both by consulting documentation -- the documentation for afwCameraGeom says that +x is along the serial readout direction; LCA-13381 indicates that, in the Camera team's definition, the serial readout is along +y -- and phenomenologically by comparing the relationship between pixelCoordsFromPupilCoords() to visual inspection of PhoSim-generated FITS images. """ self.assertGreater(len(self.data), 10) for ix in range(len(self.data)): in_name = self.data['chipName'][ix] chip_name = in_name[0]+':'+in_name[1]+','+in_name[2] chip_name += ' '+in_name[3]+':'+in_name[4]+','+in_name[5] corner_pixels = getCornerPixels(chip_name, lsst_camera()) x_center_dm = 0.25*(corner_pixels[0][0] + corner_pixels[1][0] + corner_pixels[2][0] + corner_pixels[3][0]) y_center_dm = 0.25*(corner_pixels[0][1] + corner_pixels[1][1] + corner_pixels[2][1] + corner_pixels[3][1]) obs = ObservationMetaData(pointingRA=self.data['pointingRA'][ix], pointingDec=self.data['pointingDec'][ix], rotSkyPos=self.data['rotSkyPos'][ix], mjd=59580.0) xpix, ypix = pixelCoordsFromRaDecLSST(self.data['objRA'][ix], self.data['objDec'][ix], obs_metadata=obs) raObs, decObs = observedFromICRS(self.data['objRA'][ix], self.data['objDec'][ix], obs_metadata=obs, epoch=2000.0) # find displacement from center of DM coordinates of the # objects as placed by PhoSim d_y_phosim = y_center_dm - self.data['xpix'][ix] d_x_phosim = self.data['ypix'][ix] - x_center_dm # displacement from center of DM coordinates as calculated # by DM d_x_dm = xpix - x_center_dm d_y_dm = ypix - y_center_dm d_pix = np.sqrt((d_x_dm - d_x_phosim)**2 + (d_y_dm - d_y_phosim)**2) # demand that the difference between the two displacements is less # than 0.05 of the total displacement from the center of the object # as calculated by DM msg = 'dx %e; dy %e' % (d_x_dm, d_y_dm) self.assertLess(d_pix, 0.05*np.sqrt(d_x_dm**2+d_y_dm**2), msg=msg)
def test_naive_focal_plane_position(self): """ Test deprecession of PhoSim coordinates by comparing the focal plane position predicted by CatSim from ICRS with the focal plane position predicted by CatSim from deprecessed coordinates. """ phosim_mixin = PhoSimAstrometryBase() mjd = 59587.2 # create site with no atmosphere so that we can avoid # refraction site = Site(name="LSST", pressure=0.0, humidity=0.0) obs = ObservationMetaData(mjd=mjd, site=site) ra, dec = raDecFromAltAz(31.0, 112.0, obs) d_sun = distanceToSun(ra, dec, obs.mjd) self.assertGreater(d_sun, 45.0) obs = ObservationMetaData(pointingRA=ra, pointingDec=dec, rotSkyPos=27.3, mjd=mjd, site=site) ra_icrs = np.arange(obs.pointingRA - 2.0, obs.pointingRA + 2.0, 0.05) dec_icrs = np.arange(obs.pointingDec - 2.0, obs.pointingDec + 2.0, 0.05) coord_grid = np.meshgrid(ra_icrs, dec_icrs) ra_icrs = coord_grid[0].flatten() dec_icrs = coord_grid[1].flatten() (xpup_icrs, ypup_icrs) = pupilCoordsFromRaDec(ra_icrs, dec_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=False) (x_focal_icrs, y_focal_icrs) = focalPlaneCoordsFromPupilCoords(xpup_icrs, ypup_icrs, camera=lsst_camera()) ra_obs, dec_obs = observedFromICRS(ra_icrs, dec_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=False) ra_obs_rad = np.radians(ra_obs) dec_obs_rad = np.radians(dec_obs) (ra_deprecessed_rad, dec_deprecessed_rad) = phosim_mixin._dePrecess( ra_obs_rad, dec_obs_rad, obs) (xpup_deprecessed, ypup_deprecessed) = _naivePupilCoordsFromObserved( ra_deprecessed_rad, dec_deprecessed_rad, obs._pointingRA, obs._pointingDec, obs._rotSkyPos) (x_focal_deprecessed, y_focal_deprecessed) = focalPlaneCoordsFromPupilCoords( xpup_deprecessed, ypup_deprecessed, camera=lsst_camera()) dd = np.sqrt((x_focal_icrs - x_focal_deprecessed)**2 + (y_focal_icrs - y_focal_deprecessed)**2) self.assertLess(dd.max(), 1.0e-8)
def test_naive_focal_plane_position(self): """ Test deprecession of PhoSim coordinates by comparing the focal plane position predicted by CatSim from ICRS with the focal plane position predicted by CatSim from deprecessed coordinates. """ phosim_mixin = PhoSimAstrometryBase() mjd = 59587.2 # create site with no atmosphere so that we can avoid # refraction site = Site(name="LSST", pressure=0.0, humidity=0.0) obs = ObservationMetaData(mjd=mjd, site=site) ra, dec = raDecFromAltAz(31.0, 112.0, obs) d_sun = distanceToSun(ra, dec, obs.mjd) self.assertGreater(d_sun, 45.0) obs = ObservationMetaData(pointingRA=ra, pointingDec=dec, rotSkyPos=27.3, mjd=mjd, site=site) ra_icrs = np.arange(obs.pointingRA-2.0, obs.pointingRA+2.0, 0.05) dec_icrs = np.arange(obs.pointingDec-2.0, obs.pointingDec+2.0, 0.05) coord_grid = np.meshgrid(ra_icrs, dec_icrs) ra_icrs = coord_grid[0].flatten() dec_icrs = coord_grid[1].flatten() (xpup_icrs, ypup_icrs) = pupilCoordsFromRaDec(ra_icrs, dec_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=False) (x_focal_icrs, y_focal_icrs) = focalPlaneCoordsFromPupilCoords(xpup_icrs, ypup_icrs, camera=lsst_camera()) ra_obs, dec_obs = observedFromICRS(ra_icrs, dec_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=False) ra_obs_rad = np.radians(ra_obs) dec_obs_rad = np.radians(dec_obs) (ra_deprecessed_rad, dec_deprecessed_rad) = phosim_mixin._dePrecess(ra_obs_rad, dec_obs_rad, obs) (xpup_deprecessed, ypup_deprecessed) = _naivePupilCoordsFromObserved(ra_deprecessed_rad, dec_deprecessed_rad, obs._pointingRA, obs._pointingDec, obs._rotSkyPos) (x_focal_deprecessed, y_focal_deprecessed) = focalPlaneCoordsFromPupilCoords(xpup_deprecessed, ypup_deprecessed, camera=lsst_camera()) dd = np.sqrt((x_focal_icrs-x_focal_deprecessed)**2 +(y_focal_icrs-y_focal_deprecessed)**2) self.assertLess(dd.max(), 5.0e-8)
def testRaDec(self): """ Test that raDecFromNativeLonLat does invert nativeLonLatFromRaDec """ rng = np.random.RandomState(42) nSamples = 100 # because raDecFromNativeLonLat is only good rrList = rng.random_sample(nSamples) * 50.0 # out to a zenith distance of ~ 70 degrees thetaList = rng.random_sample(nSamples) * 2.0 * np.pi rrPointingList = rng.random_sample(10) * 50.0 thetaPointingList = rng.random_sample(10) * 2.0 * np.pi mjdList = rng.random_sample(nSamples) * 10000.0 + 43000.0 for rrp, thetap, mjd in \ zip(rrPointingList, thetaPointingList, mjdList): site = Site(name='LSST') raZenith, decZenith = raDecFromAltAz( 180.0, 0.0, ObservationMetaData(mjd=mjd, site=site)) rp = raZenith + rrp * np.cos(thetap) dp = decZenith + rrp * np.sin(thetap) obs = ObservationMetaData(pointingRA=rp, pointingDec=dp, mjd=mjd, site=site) raList_icrs = (raZenith + rrList * np.cos(thetaList)) % 360.0 decList_icrs = decZenith + rrList * np.sin(thetaList) raList_obs, decList_obs = observedFromICRS(raList_icrs, decList_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=True) # calculate the distance between the ICRS position and the observed # geocentric position dd_icrs_obs_list = arcsecFromRadians( haversine(np.radians(raList_icrs), np.radians(decList_icrs), np.radians(raList_obs), np.radians(decList_obs))) for rr, dd, dd_icrs_obs in zip(raList_icrs, decList_icrs, dd_icrs_obs_list): lon, lat = nativeLonLatFromRaDec(rr, dd, obs) r1, d1 = raDecFromNativeLonLat(lon, lat, obs) # the distance between the input RA, Dec and the round-trip output # RA, Dec distance = arcsecFromRadians( haversine(np.radians(r1), np.radians(d1), np.radians(rr), np.radians(dd))) rr_obs, dec_obs = observedFromICRS(rr, dd, obs_metadata=obs, epoch=2000.0, includeRefraction=True) # verify that the round trip through nativeLonLat only changed # RA, Dec by less than an arcsecond self.assertLess(distance, 1.0) # verify that any difference in the round trip is much less # than the distance between the ICRS and the observed geocentric # RA, Dec self.assertLess(distance, dd_icrs_obs * 0.01)
def testNativeLongLatComplicated(self): """ Test that nativeLongLatFromRaDec works by considering stars and pointings at non-intuitive locations. """ rng = np.random.RandomState(42) nPointings = 10 raPointingList_icrs = rng.random_sample(nPointings) * 360.0 decPointingList_icrs = rng.random_sample(nPointings) * 180.0 - 90.0 mjdList = rng.random_sample(nPointings) * 10000.0 + 43000.0 nStars = 10 for raPointing_icrs, decPointing_icrs, mjd in \ zip(raPointingList_icrs, decPointingList_icrs, mjdList): obs = ObservationMetaData(pointingRA=raPointing_icrs, pointingDec=decPointing_icrs, mjd=mjd) raList_icrs = rng.random_sample(nStars) * 360.0 decList_icrs = rng.random_sample(nStars) * 180.0 - 90.0 raList_obs, decList_obs = observedFromICRS(raList_icrs, decList_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=True) obsTemp = ObservationMetaData(mjd=mjd) raPointing_obs, decPointing_obs = observedFromICRS( raPointing_icrs, decPointing_icrs, obs_metadata=obsTemp, epoch=2000.0, includeRefraction=True) for ra_obs, dec_obs, ra_icrs, dec_icrs in \ zip(raList_obs, decList_obs, raList_icrs, decList_icrs): raRad = np.radians(ra_obs) decRad = np.radians(dec_obs) sinRa = np.sin(raRad) cosRa = np.cos(raRad) sinDec = np.sin(decRad) cosDec = np.cos(decRad) # the three dimensional position of the star controlPosition = np.array( [-cosDec * sinRa, cosDec * cosRa, sinDec]) # calculate the rotation matrices needed to transform the # x, y, and z axes into the local x, y, and z axes # (i.e. the axes with z lined up with raPointing_obs, decPointing_obs) alpha = 0.5 * np.pi - np.radians(decPointing_obs) ca = np.cos(alpha) sa = np.sin(alpha) rotX = np.array([[1.0, 0.0, 0.0], [0.0, ca, sa], [0.0, -sa, ca]]) cb = np.cos(np.radians(raPointing_obs)) sb = np.sin(np.radians(raPointing_obs)) rotZ = np.array([[cb, -sb, 0.0], [sb, cb, 0.0], [0.0, 0.0, 1.0]]) # rotate the coordinate axes into the local basis xAxis = np.dot(rotZ, np.dot(rotX, np.array([1.0, 0.0, 0.0]))) yAxis = np.dot(rotZ, np.dot(rotX, np.array([0.0, 1.0, 0.0]))) zAxis = np.dot(rotZ, np.dot(rotX, np.array([0.0, 0.0, 1.0]))) # calculate the local longitude and latitude of the star lon, lat = nativeLonLatFromRaDec(ra_icrs, dec_icrs, obs) cosLon = np.cos(np.radians(lon)) sinLon = np.sin(np.radians(lon)) cosLat = np.cos(np.radians(lat)) sinLat = np.sin(np.radians(lat)) # the x, y, z position of the star in the local coordinate # basis transformedPosition = np.array( [-cosLat * sinLon, cosLat * cosLon, sinLat]) # convert that position back into the un-rotated bases testPosition = transformedPosition[0] * xAxis + \ transformedPosition[1] * yAxis + \ transformedPosition[2] * zAxis # assert that testPosition and controlPosition should be equal distance = np.sqrt( np.power(controlPosition - testPosition, 2).sum()) self.assertLess(distance, 1.0e-12)