def testNaNs(self): """ Test how _pupilCoordsFromRaDec handles improper values """ obs = ObservationMetaData(pointingRA=42.0, pointingDec=-28.0, rotSkyPos=111.0, mjd=42356.0) nSamples = 100 rng = np.random.RandomState(42) raList = np.radians(rng.random_sample(nSamples) * 2.0 + 42.0) decList = np.radians(rng.random_sample(nSamples) * 2.0 - 28.0) xControl, yControl = _pupilCoordsFromRaDec(raList, decList, obs_metadata=obs, epoch=2000.0) raList[5] = np.NaN decList[5] = np.NaN raList[15] = np.NaN decList[20] = np.NaN raList[30] = np.radians(42.0) + np.pi xTest, yTest = _pupilCoordsFromRaDec(raList, decList, obs_metadata=obs, epoch=2000.0) for ix, (xc, yc, xt, yt) in \ enumerate(zip(xControl, yControl, xTest, yTest)): if ix != 5 and ix != 15 and ix != 20 and ix != 30: self.assertAlmostEqual(xc, xt, 10) self.assertAlmostEqual(yc, yt, 10) self.assertFalse(np.isnan(xt)) self.assertFalse(np.isnan(yt)) else: np.testing.assert_equal(xt, np.NaN) np.testing.assert_equal(yt, np.NaN)
def testObservedFromPupil(self): """ Test conversion from pupil coordinates to observed coordinates """ mjd = ModifiedJulianDate(TAI=53000.0) solarRA, solarDec = solarRaDec(mjd) # to make sure that we are more than 45 degrees from the Sun as required # for _icrsFromObserved to be at all accurate raCenter = solarRA + 100.0 decCenter = solarDec - 30.0 obs = ObservationMetaData(pointingRA=raCenter, pointingDec=decCenter, boundType='circle', boundLength=0.1, rotSkyPos=23.0, mjd=mjd) nSamples = 1000 rng = np.random.RandomState(4453) ra = (rng.random_sample(nSamples) * 0.1 - 0.2) + np.radians(raCenter) dec = (rng.random_sample(nSamples) * 0.1 - 0.2) + np.radians(decCenter) xp, yp = _pupilCoordsFromRaDec(ra, dec, obs_metadata=obs, epoch=2000.0, includeRefraction=True) raObs, decObs = _observedFromICRS(ra, dec, obs_metadata=obs, epoch=2000.0, includeRefraction=True) raObs_test, decObs_test = _observedFromPupilCoords(xp, yp, obs_metadata=obs, epoch=2000.0, includeRefraction=True) dist = arcsecFromRadians(haversine(raObs, decObs, raObs_test, decObs_test)) self.assertLess(dist.max(), 1.0e-6) # test output in degrees raObs_deg, decObs_deg = observedFromPupilCoords(xp, yp, obs_metadata=obs, epoch=2000.0, includeRefraction=True) np.testing.assert_array_almost_equal(raObs_deg, np.degrees(raObs_test), decimal=16) np.testing.assert_array_almost_equal(decObs_deg, np.degrees(decObs_test), decimal=16) # test one-at-a-time input for ii in range(len(raObs)): rr, dd = _observedFromPupilCoords(xp[ii], yp[ii], obs_metadata=obs, epoch=2000.0, includeRefraction=True) self.assertAlmostEqual(rr, raObs_test[ii], 16) self.assertAlmostEqual(dd, decObs_test[ii], 16) rr, dd = observedFromPupilCoords(xp[ii], yp[ii], obs_metadata=obs, epoch=2000.0, includeRefraction=True) self.assertAlmostEqual(rr, raObs_deg[ii], 16) self.assertAlmostEqual(dd, decObs_deg[ii], 16)
def testpupilCoordsFromRaDec(self): obs = ObservationMetaData(pointingRA=23.5, pointingDec=-115.0, mjd=42351.0, rotSkyPos=127.0) # need to make sure the test points are tightly distributed around the bore site, or # PALPY will throw an error raList = self.rng.random_sample( self.nStars) * np.radians(1.0) + np.radians(23.5) decList = self.rng.random_sample( self.nStars) * np.radians(1.0) + np.radians(-115.0) xpControl, ypControl = utils._pupilCoordsFromRaDec(raList, decList, obs_metadata=obs, epoch=2000.0) xpTest, ypTest = utils.pupilCoordsFromRaDec(np.degrees(raList), np.degrees(decList), obs_metadata=obs, epoch=2000.0) dx = utils.arcsecFromRadians(xpControl - xpTest) np.testing.assert_array_almost_equal(dx, np.zeros(self.nStars), 9) dy = utils.arcsecFromRadians(ypControl - ypTest) np.testing.assert_array_almost_equal(dy, np.zeros(self.nStars), 9)
def testRaDecFromPupil(self): """ Test conversion from pupil coordinates back to Ra, Dec """ mjd = ModifiedJulianDate(TAI=52000.0) solarRA, solarDec = solarRaDec(mjd.TDB) # to make sure that we are more than 45 degrees from the Sun as required # for _icrsFromObserved to be at all accurate raCenter = solarRA + 100.0 decCenter = solarDec - 30.0 obs = ObservationMetaData(pointingRA=raCenter, pointingDec=decCenter, boundType='circle', boundLength=0.1, rotSkyPos=23.0, mjd=mjd) nSamples = 1000 numpy.random.seed(42) ra = (numpy.random.random_sample(nSamples)*0.1-0.2) + numpy.radians(raCenter) dec = (numpy.random.random_sample(nSamples)*0.1-0.2) + numpy.radians(decCenter) xp, yp = _pupilCoordsFromRaDec(ra, dec, obs_metadata=obs, epoch=2000.0) raTest, decTest = _raDecFromPupilCoords(xp, yp, obs_metadata=obs, epoch=2000.0) distance = arcsecFromRadians(haversine(ra, dec, raTest, decTest)) dex = numpy.argmax(distance) worstSolarDistance = distanceToSun(numpy.degrees(ra[dex]), numpy.degrees(dec[dex]), mjd.TDB) msg = "_raDecFromPupilCoords off by %e arcsec at distance to Sun of %e degrees" % \ (distance.max(), worstSolarDistance) self.assertLess(distance.max(), 0.005, msg=msg)
def testRaDecFromPupil(self): """ Test conversion from pupil coordinates back to Ra, Dec """ mjd = ModifiedJulianDate(TAI=52000.0) solarRA, solarDec = solarRaDec(mjd) # to make sure that we are more than 45 degrees from the Sun as required # for _icrsFromObserved to be at all accurate raCenter = solarRA + 100.0 decCenter = solarDec - 30.0 obs = ObservationMetaData(pointingRA=raCenter, pointingDec=decCenter, boundType='circle', boundLength=0.1, rotSkyPos=23.0, mjd=mjd) nSamples = 1000 rng = np.random.RandomState(42) ra = (rng.random_sample(nSamples) * 0.1 - 0.2) + np.radians(raCenter) dec = (rng.random_sample(nSamples) * 0.1 - 0.2) + np.radians(decCenter) xp, yp = _pupilCoordsFromRaDec(ra, dec, obs_metadata=obs, epoch=2000.0) raTest, decTest = _raDecFromPupilCoords(xp, yp, obs_metadata=obs, epoch=2000.0) distance = arcsecFromRadians(haversine(ra, dec, raTest, decTest)) dex = np.argmax(distance) worstSolarDistance = distanceToSun(np.degrees(ra[dex]), np.degrees(dec[dex]), mjd) msg = "_raDecFromPupilCoords off by %e arcsec at distance to Sun of %e degrees" % \ (distance.max(), worstSolarDistance) self.assertLess(distance.max(), 1.0e-6, msg=msg) # now check that passing in the xp, yp values one at a time still gives # the right answer for ix in range(len(ra)): ra_f, dec_f = _raDecFromPupilCoords(xp[ix], yp[ix], obs_metadata=obs, epoch=2000.0) self.assertIsInstance(ra_f, np.float) self.assertIsInstance(dec_f, np.float) dist_f = arcsecFromRadians( haversine(ra_f, dec_f, raTest[ix], decTest[ix])) self.assertLess(dist_f, 1.0e-9)
def testRaDecFromPupil_noRefraction(self): """ Test conversion from pupil coordinates back to Ra, Dec with includeRefraction=False """ mjd = ModifiedJulianDate(TAI=52000.0) solarRA, solarDec = solarRaDec(mjd) # to make sure that we are more than 45 degrees from the Sun as required # for _icrsFromObserved to be at all accurate raCenter = solarRA + 100.0 decCenter = solarDec - 30.0 obs = ObservationMetaData(pointingRA=raCenter, pointingDec=decCenter, boundType='circle', boundLength=0.1, rotSkyPos=23.0, mjd=mjd) nSamples = 1000 rng = np.random.RandomState(42) ra = (rng.random_sample(nSamples) * 0.1 - 0.2) + np.radians(raCenter) dec = (rng.random_sample(nSamples) * 0.1 - 0.2) + np.radians(decCenter) xp, yp = _pupilCoordsFromRaDec(ra, dec, obs_metadata=obs, epoch=2000.0, includeRefraction=False) raTest, decTest = _raDecFromPupilCoords( xp, yp, obs_metadata=obs, epoch=2000.0, includeRefraction=False) distance = arcsecFromRadians(haversine(ra, dec, raTest, decTest)) dex = np.argmax(distance) worstSolarDistance = distanceToSun( np.degrees(ra[dex]), np.degrees(dec[dex]), mjd) msg = "_raDecFromPupilCoords off by %e arcsec at distance to Sun of %e degrees" % \ (distance.max(), worstSolarDistance) self.assertLess(distance.max(), 1.0e-6, msg=msg) # now check that passing in the xp, yp values one at a time still gives # the right answer for ix in range(len(ra)): ra_f, dec_f = _raDecFromPupilCoords(xp[ix], yp[ix], obs_metadata=obs, epoch=2000.0, includeRefraction=False) self.assertIsInstance(ra_f, np.float) self.assertIsInstance(dec_f, np.float) dist_f = arcsecFromRadians(haversine(ra_f, dec_f, raTest[ix], decTest[ix])) self.assertLess(dist_f, 1.0e-9)
def _focalPlaneCoordsFromRaDec(ra, dec, obs_metadata=None, epoch=None, camera=None): """ Get the focal plane coordinates for all objects in the catalog. @param [in] ra is a numpy array in radians. In the International Celestial Reference System. @param [in] dec is a numpy array in radians. In the International Celestial Reference System. @param [in] obs_metadata is an ObservationMetaData object describing the telescope pointing (only if specifying RA and Dec rather than pupil coordinates) @param [in] epoch is the julian epoch of the mean equinox used for coordinate transformations (in years; only if specifying RA and Dec rather than pupil coordinates) @param [in] camera is an afw.cameraGeom camera object @param [out] a 2-D numpy array in which the first row is the x focal plane coordinate and the second row is the y focal plane coordinate (both in millimeters) """ if not isinstance(ra, numpy.ndarray) or not isinstance(dec, numpy.ndarray): raise RuntimeError("You must pass numpy arrays of RA and Dec to focalPlaneCoordsFromRaDec") if len(ra) != len(dec): raise RuntimeError("You specified %d RAs and %d Decs in focalPlaneCoordsFromRaDec" % (len(ra), len(dec))) if epoch is None: raise RuntimeError("You have to specify an epoch to run " + \ "focalPlaneCoordsFromRaDec") if obs_metadata is None: raise RuntimeError("You have to specify an ObservationMetaData to run " + \ "focalPlaneCoordsFromRaDec") if obs_metadata.mjd is None: raise RuntimeError("You need to pass an ObservationMetaData with an " \ + "mjd into focalPlaneCoordsFromRaDec") if obs_metadata.rotSkyPos is None: raise RuntimeError("You need to pass an ObservationMetaData with a " \ + "rotSkyPos into focalPlaneCoordsFromRaDec") xPupil, yPupil = _pupilCoordsFromRaDec(ra, dec, obs_metadata=obs_metadata, epoch=epoch) return focalPlaneCoordsFromPupilCoords(xPupil, yPupil, camera=camera)
def _chipNameFromRaDec(ra, dec, obs_metadata=None, epoch=None, camera=None, allow_multiple_chips=False): """ Return the names of science detectors that see the object specified by either (xPupil, yPupil). Note: this method does not return the name of guide, focus, or wavefront detectors. @param [in] ra in radians (a numpy array). In the International Celestial Reference System. @param [in] dec in radians (a numpy array). In the International Celestial Reference System. @param [in] obs_metadata is an ObservationMetaData characterizing the telescope pointing @param [in] epoch is the epoch in Julian years of the equinox against which RA and Dec are measured @param [in] camera is an afw.cameraGeom camera instance characterizing the camera @param [in] allow_multiple_chips is a boolean (default False) indicating whether or not this method will allow objects to be visible on more than one chip. If it is 'False' and an object appears on more than one chip, an exception will be raised. If it is 'True' and an object falls on more than one chip, it will still only return the first chip in the list of chips returned. THIS BEHAVIOR SHOULD BE FIXED IN A FUTURE TICKET. @param [out] a numpy array of chip names (science detectors only) """ if not isinstance(ra, numpy.ndarray) or not isinstance(dec, numpy.ndarray): raise RuntimeError("You need to pass numpy arrays of RA and Dec to chipName") if len(ra) != len(dec): raise RuntimeError("You passed %d RAs and %d Decs " % (len(ra), len(dec)) + "to chipName.") if epoch is None: raise RuntimeError("You need to pass an epoch into chipName") if obs_metadata is None: raise RuntimeError("You need to pass an ObservationMetaData into chipName") if obs_metadata.mjd is None: raise RuntimeError("You need to pass an ObservationMetaData with an mjd into chipName") if obs_metadata.rotSkyPos is None: raise RuntimeError("You need to pass an ObservationMetaData with a rotSkyPos into chipName") xp, yp = _pupilCoordsFromRaDec(ra, dec, obs_metadata=obs_metadata, epoch=epoch) return chipNameFromPupilCoords(xp, yp, camera=camera, allow_multiple_chips=allow_multiple_chips)
def testpupilCoordsFromRaDec(self): obs = ObservationMetaData(pointingRA=23.5, pointingDec=-115.0, mjd=42351.0, rotSkyPos=127.0) # need to make sure the test points are tightly distributed around the bore site, or # PALPY will throw an error raList = np.random.random_sample(self.nStars)*np.radians(1.0) + np.radians(23.5) decList = np.random.random_sample(self.nStars)*np.radians(1.0) + np.radians(-115.0) xpControl, ypControl = utils._pupilCoordsFromRaDec(raList, decList, obs_metadata=obs, epoch=2000.0) xpTest, ypTest = utils.pupilCoordsFromRaDec(np.degrees(raList), np.degrees(decList), obs_metadata=obs, epoch=2000.0) dx = utils.arcsecFromRadians(xpControl-xpTest) np.testing.assert_array_almost_equal(dx, np.zeros(self.nStars), 9) dy = utils.arcsecFromRadians(ypControl-ypTest) np.testing.assert_array_almost_equal(dy, np.zeros(self.nStars), 9)
def testExceptions(self): """ Test that exceptions are raised when they ought to be """ obs_metadata = ObservationMetaData(pointingRA=25.0, pointingDec=25.0, rotSkyPos=25.0, mjd=52000.0) numpy.random.seed(42) ra = numpy.random.random_sample(10)*numpy.radians(1.0) + numpy.radians(obs_metadata.pointingRA) dec = numpy.random.random_sample(10)*numpy.radians(1.0) + numpy.radians(obs_metadata.pointingDec) raShort = numpy.array([1.0]) decShort = numpy.array([1.0]) #test without epoch self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, obs_metadata=obs_metadata) #test without obs_metadata self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0) #test without pointingRA dummy = ObservationMetaData(pointingDec=obs_metadata.pointingDec, rotSkyPos=obs_metadata.rotSkyPos, mjd=obs_metadata.mjd) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0, obs_metadata=dummy) #test without pointingDec dummy = ObservationMetaData(pointingRA=obs_metadata.pointingRA, rotSkyPos=obs_metadata.rotSkyPos, mjd=obs_metadata.mjd) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0, obs_metadata=dummy) #test without rotSkyPos dummy = ObservationMetaData(pointingRA=obs_metadata.pointingRA, pointingDec=obs_metadata.pointingDec, mjd=obs_metadata.mjd) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0, obs_metadata=dummy) #test without mjd dummy = ObservationMetaData(pointingRA=obs_metadata.pointingRA, pointingDec=obs_metadata.pointingDec, rotSkyPos=obs_metadata.rotSkyPos) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0, obs_metadata=dummy) #test for mismatches dummy = ObservationMetaData(pointingRA=obs_metadata.pointingRA, pointingDec=obs_metadata.pointingDec, rotSkyPos=obs_metadata.rotSkyPos, mjd=obs_metadata.mjd) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, decShort, epoch=2000.0, obs_metadata=dummy) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, raShort, dec, epoch=2000.0, obs_metadata=dummy) #test that it actually runs test = _pupilCoordsFromRaDec(ra, dec, obs_metadata=obs_metadata, epoch=2000.0)
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)
def testExceptions(self): """ Test that exceptions are raised when they ought to be """ obs_metadata = ObservationMetaData(pointingRA=25.0, pointingDec=25.0, rotSkyPos=25.0, mjd=52000.0) rng = np.random.RandomState(42) ra = rng.random_sample(10) * np.radians(1.0) + np.radians(obs_metadata.pointingRA) dec = rng.random_sample(10) * np.radians(1.0) + np.radians(obs_metadata.pointingDec) raShort = np.array([1.0]) decShort = np.array([1.0]) # test without obs_metadata self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0) # test without pointingRA dummy = ObservationMetaData(pointingDec=obs_metadata.pointingDec, rotSkyPos=obs_metadata.rotSkyPos, mjd=obs_metadata.mjd) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0, obs_metadata=dummy) # test without pointingDec dummy = ObservationMetaData(pointingRA=obs_metadata.pointingRA, rotSkyPos=obs_metadata.rotSkyPos, mjd=obs_metadata.mjd) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0, obs_metadata=dummy) # test without rotSkyPos dummy = ObservationMetaData(pointingRA=obs_metadata.pointingRA, pointingDec=obs_metadata.pointingDec, mjd=obs_metadata.mjd) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0, obs_metadata=dummy) # test without mjd dummy = ObservationMetaData(pointingRA=obs_metadata.pointingRA, pointingDec=obs_metadata.pointingDec, rotSkyPos=obs_metadata.rotSkyPos) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0, obs_metadata=dummy) # test for mismatches dummy = ObservationMetaData(pointingRA=obs_metadata.pointingRA, pointingDec=obs_metadata.pointingDec, rotSkyPos=obs_metadata.rotSkyPos, mjd=obs_metadata.mjd) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, decShort, epoch=2000.0, obs_metadata=dummy) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, raShort, dec, epoch=2000.0, obs_metadata=dummy) # test that it actually runs (and that passing in either numpy arrays or floats gives # the same results) xx_arr, yy_arr = _pupilCoordsFromRaDec(ra, dec, obs_metadata=obs_metadata) self.assertIsInstance(xx_arr, np.ndarray) self.assertIsInstance(yy_arr, np.ndarray) for ix in range(len(ra)): xx_f, yy_f = _pupilCoordsFromRaDec(ra[ix], dec[ix], obs_metadata=obs_metadata) self.assertIsInstance(xx_f, np.float) self.assertIsInstance(yy_f, np.float) self.assertAlmostEqual(xx_arr[ix], xx_f, 12) self.assertAlmostEqual(yy_arr[ix], yy_f, 12) self.assertFalse(np.isnan(xx_f)) self.assertFalse(np.isnan(yy_f))
def test_object_extraction_stars(self): """ Test that method to get GalSimCelestialObjects from InstanceCatalogs works """ commands = desc.imsim.metadata_from_file(self.phosim_file) obs_md = desc.imsim.phosim_obs_metadata(commands) phot_params = desc.imsim.photometricParameters(commands) with desc.imsim.fopen(self.phosim_file, mode='rt') as input_: lines = [x for x in input_ if x.startswith('object')] truth_dtype = np.dtype([('uniqueId', str, 200), ('x_pupil', float), ('y_pupil', float), ('sedFilename', str, 200), ('magNorm', float), ('raJ2000', float), ('decJ2000', float), ('pmRA', float), ('pmDec', float), ('parallax', float), ('v_rad', float), ('Av', float), ('Rv', float)]) truth_data = np.genfromtxt(os.path.join(self.data_dir, 'truth_stars.txt'), dtype=truth_dtype, delimiter=';') truth_data.sort() gs_object_arr, gs_object_dict \ = sources_from_list(lines, obs_md, phot_params, self.phosim_file) id_arr = [None] * len(gs_object_arr) for i_obj in range(len(gs_object_arr)): id_arr[i_obj] = gs_object_arr[i_obj].uniqueId id_arr = sorted(id_arr) np.testing.assert_array_equal(truth_data['uniqueId'], id_arr) ######## test that pupil coordinates are correct to within ######## half a milliarcsecond x_pup_test, y_pup_test = _pupilCoordsFromRaDec( truth_data['raJ2000'], truth_data['decJ2000'], pm_ra=truth_data['pmRA'], pm_dec=truth_data['pmDec'], v_rad=truth_data['v_rad'], parallax=truth_data['parallax'], obs_metadata=obs_md) for gs_obj in gs_object_arr: i_obj = np.where(truth_data['uniqueId'] == gs_obj.uniqueId)[0][0] dd = np.sqrt((x_pup_test[i_obj] - gs_obj.xPupilRadians)**2 + (y_pup_test[i_obj] - gs_obj.yPupilRadians)**2) dd = arcsecFromRadians(dd) self.assertLess(dd, 0.0005) ######## test that fluxes are correctly calculated bp_dict = BandpassDict.loadTotalBandpassesFromFiles() imsim_bp = Bandpass() imsim_bp.imsimBandpass() phot_params = PhotometricParameters(nexp=1, exptime=30.0) for gs_obj in gs_object_arr: i_obj = np.where(truth_data['uniqueId'] == gs_obj.uniqueId)[0][0] sed = Sed() full_sed_name = os.path.join(os.environ['SIMS_SED_LIBRARY_DIR'], truth_data['sedFilename'][i_obj]) sed.readSED_flambda(full_sed_name) fnorm = sed.calcFluxNorm(truth_data['magNorm'][i_obj], imsim_bp) sed.multiplyFluxNorm(fnorm) sed.resampleSED(wavelen_match=bp_dict.wavelenMatch) a_x, b_x = sed.setupCCM_ab() sed.addDust(a_x, b_x, A_v=truth_data['Av'][i_obj], R_v=truth_data['Rv'][i_obj]) for bp in ('u', 'g', 'r', 'i', 'z', 'y'): flux = sed.calcADU(bp_dict[bp], phot_params) * phot_params.gain self.assertAlmostEqual(flux / gs_obj.flux(bp), 1.0, 10) ######## test that objects are assigned to the right chip in ######## gs_object_dict unique_id_dict = {} for chip_name in gs_object_dict: local_unique_id_list = [] for gs_object in gs_object_dict[chip_name]: local_unique_id_list.append(gs_object.uniqueId) local_unique_id_list = set(local_unique_id_list) unique_id_dict[chip_name] = local_unique_id_list valid = 0 valid_chip_names = set() for unq, xpup, ypup in zip(truth_data['uniqueId'], truth_data['x_pupil'], truth_data['y_pupil']): chip_name = chipNameFromPupilCoordsLSST(xpup, ypup) if chip_name is not None: self.assertIn(unq, unique_id_dict[chip_name]) valid_chip_names.add(chip_name) valid += 1 self.assertGreater(valid, 10) self.assertGreater(len(valid_chip_names), 5)
def testUtilityMethods(self): """ Generate a catalog using the methods from AstrometryUtils.py and CameraUtils.py. Read that data in, and then recalculate the values 'by hand' to make sure that they are consistent. """ catName = os.path.join(getPackageDir('sims_catUtils'), 'tests', 'scratchSpace', 'AstrometryUtilityCatalog.txt') if os.path.exists(catName): os.unlink(catName) self.cat.write_catalog(catName) dtype = [('id', int), ('raICRS', float), ('decICRS', float), ('parallax', float), ('radial_velocity', float), ('x_pupil', float), ('y_pupil', float), ('chipName', str, 11), ('xPix', float), ('yPix', float), ('xFocalPlane', float), ('yFocalPlane', float)] baselineData = np.genfromtxt(catName, dtype=dtype, delimiter=';') self.assertGreater(len(baselineData), 0) pupilTest = _pupilCoordsFromRaDec(baselineData['raICRS'], baselineData['decICRS'], parallax=baselineData['parallax'], v_rad=baselineData['radial_velocity'], obs_metadata=self.obs_metadata, epoch=2000.0) for (xxtest, yytest, xx, yy) in \ zip(pupilTest[0], pupilTest[1], baselineData['x_pupil'], baselineData['y_pupil']): self.assertAlmostEqual(xxtest, xx, 6) self.assertAlmostEqual(yytest, yy, 6) focalTest = focalPlaneCoordsFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera) focalRa = _focalPlaneCoordsFromRaDec(baselineData['raICRS'], baselineData['decICRS'], parallax=baselineData['parallax'], v_rad=baselineData['radial_velocity'], epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata, camera=self.cat.camera) for (xxtest, yytest, xxra, yyra, xx, yy) in \ zip(focalTest[0], focalTest[1], focalRa[0], focalRa[1], baselineData['xFocalPlane'], baselineData['yFocalPlane']): self.assertAlmostEqual(xxtest, xx, 6) self.assertAlmostEqual(yytest, yy, 6) self.assertAlmostEqual(xxra, xx, 6) self.assertAlmostEqual(yyra, yy, 6) pixTest = pixelCoordsFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera) pixTestRaDec = _pixelCoordsFromRaDec(baselineData['raICRS'], baselineData['decICRS'], parallax=baselineData['parallax'], v_rad=baselineData['radial_velocity'], epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata, camera=self.cat.camera) for (xxtest, yytest, xxra, yyra, xx, yy) in \ zip(pixTest[0], pixTest[1], pixTestRaDec[0], pixTestRaDec[1], baselineData['xPix'], baselineData['yPix']): if not np.isnan(xx) and not np.isnan(yy): self.assertAlmostEqual(xxtest, xx, 5) self.assertAlmostEqual(yytest, yy, 5) self.assertAlmostEqual(xxra, xx, 5) self.assertAlmostEqual(yyra, yy, 5) else: np.testing.assert_equal(xx, np.NaN) np.testing.assert_equal(yy, np.NaN) np.testing.assert_equal(xxra, np.NaN) np.testing.assert_equal(yyra, np.NaN) np.testing.assert_equal(xxtest, np.NaN) np.testing.assert_equal(yytest, np.NaN) nameTest = chipNameFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera) nameRA = _chipNameFromRaDec(baselineData['raICRS'], baselineData['decICRS'], epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata, camera=self.cat.camera) is_none = 0 for (ntest, nra, ncontrol) in zip(nameTest, nameRA, baselineData['chipName']): if ncontrol != 'None': self.assertEqual(ntest, ncontrol) self.assertEqual(nra, ncontrol) else: is_none += 1 self.assertIsNone(ntest) self.assertIsNone(nra) self.assertGreater(is_none, 0) self.assertLess(is_none, len(baselineData)) if os.path.exists(catName): os.unlink(catName)
def testObservedFromPupil_noRefraction(self): """ Test conversion from pupil coordinates to observed coordinates when includeRefraction=False """ mjd = ModifiedJulianDate(TAI=53000.0) solarRA, solarDec = solarRaDec(mjd) # to make sure that we are more than 45 degrees from the Sun as required # for _icrsFromObserved to be at all accurate raCenter = solarRA + 100.0 decCenter = solarDec - 30.0 obs = ObservationMetaData(pointingRA=raCenter, pointingDec=decCenter, boundType='circle', boundLength=0.1, rotSkyPos=23.0, mjd=mjd) nSamples = 1000 rng = np.random.RandomState(4453) ra = (rng.random_sample(nSamples) * 0.1 - 0.2) + np.radians(raCenter) dec = (rng.random_sample(nSamples) * 0.1 - 0.2) + np.radians(decCenter) xp, yp = _pupilCoordsFromRaDec(ra, dec, obs_metadata=obs, epoch=2000.0, includeRefraction=False) raObs, decObs = _observedFromICRS(ra, dec, obs_metadata=obs, epoch=2000.0, includeRefraction=False) raObs_test, decObs_test = _observedFromPupilCoords( xp, yp, obs_metadata=obs, epoch=2000.0, includeRefraction=False) dist = arcsecFromRadians( haversine(raObs, decObs, raObs_test, decObs_test)) self.assertLess(dist.max(), 1.0e-6) # test output in degrees raObs_deg, decObs_deg = observedFromPupilCoords( xp, yp, obs_metadata=obs, epoch=2000.0, includeRefraction=False) np.testing.assert_array_almost_equal(raObs_deg, np.degrees(raObs_test), decimal=16) np.testing.assert_array_almost_equal(decObs_deg, np.degrees(decObs_test), decimal=16) # test one-at-a-time input for ii in range(len(raObs)): rr, dd = _observedFromPupilCoords(xp[ii], yp[ii], obs_metadata=obs, epoch=2000.0, includeRefraction=False) self.assertAlmostEqual(rr, raObs_test[ii], 16) self.assertAlmostEqual(dd, decObs_test[ii], 16) rr, dd = observedFromPupilCoords(xp[ii], yp[ii], obs_metadata=obs, epoch=2000.0, includeRefraction=False) self.assertAlmostEqual(rr, raObs_deg[ii], 16) self.assertAlmostEqual(dd, decObs_deg[ii], 16)
def test_object_extraction_galaxies(self): """ Test that method to get GalSimCelestialObjects from InstanceCatalogs works """ galaxy_phosim_file = os.path.join(self.data_dir, 'phosim_galaxies.txt') commands = desc.imsim.metadata_from_file(galaxy_phosim_file) obs_md = desc.imsim.phosim_obs_metadata(commands) phot_params = desc.imsim.photometricParameters(commands) (gs_object_arr, gs_object_dict) = desc.imsim.sources_from_file( galaxy_phosim_file, obs_md, phot_params) id_arr = np.zeros(len(gs_object_arr), dtype=int) for i_obj in range(len(gs_object_arr)): id_arr[i_obj] = gs_object_arr[i_obj].uniqueId truth_dtype = np.dtype([('uniqueId', int), ('x_pupil', float), ('y_pupil', float), ('sedFilename', str, 200), ('magNorm', float), ('raJ2000', float), ('decJ2000', float), ('redshift', float), ('gamma1', float), ('gamma2', float), ('kappa', float), ('galacticAv', float), ('galacticRv', float), ('internalAv', float), ('internalRv', float), ('minorAxis', float), ('majorAxis', float), ('positionAngle', float), ('sindex', float)]) truth_data = np.genfromtxt(os.path.join(self.data_dir, 'truth_galaxies.txt'), dtype=truth_dtype, delimiter=';') np.testing.assert_array_equal(truth_data['uniqueId'], id_arr) ######## test that galaxy parameters are correctly read in g1 = truth_data['gamma1'] / (1.0 - truth_data['kappa']) g2 = truth_data['gamma2'] / (1.0 - truth_data['kappa']) mu = 1.0 / ((1.0 - truth_data['kappa'])**2 - (truth_data['gamma1']**2 + truth_data['gamma2']**2)) for i_obj, gs_obj in enumerate(gs_object_arr): self.assertAlmostEqual(gs_obj.mu / mu[i_obj], 1.0, 6) self.assertAlmostEqual(gs_obj.g1 / g1[i_obj], 1.0, 6) self.assertAlmostEqual(gs_obj.g2 / g2[i_obj], 1.0, 6) self.assertGreater(np.abs(gs_obj.mu), 0.0) self.assertGreater(np.abs(gs_obj.g1), 0.0) self.assertGreater(np.abs(gs_obj.g2), 0.0) self.assertAlmostEqual(gs_obj.halfLightRadiusRadians, truth_data['majorAxis'][i_obj], 13) self.assertAlmostEqual(gs_obj.minorAxisRadians, truth_data['minorAxis'][i_obj], 13) self.assertAlmostEqual(gs_obj.majorAxisRadians, truth_data['majorAxis'][i_obj], 13) self.assertAlmostEqual(gs_obj.positionAngleRadians, truth_data['positionAngle'][i_obj], 7) self.assertAlmostEqual(gs_obj.sindex, truth_data['sindex'][i_obj], 10) ######## test that pupil coordinates are correct to within ######## half a milliarcsecond x_pup_test, y_pup_test = _pupilCoordsFromRaDec(truth_data['raJ2000'], truth_data['decJ2000'], obs_metadata=obs_md) for i_obj, gs_obj in enumerate(gs_object_arr): self.assertEqual(truth_data['uniqueId'][i_obj], gs_obj.uniqueId) dd = np.sqrt((x_pup_test[i_obj] - gs_obj.xPupilRadians)**2 + (y_pup_test[i_obj] - gs_obj.yPupilRadians)**2) dd = arcsecFromRadians(dd) self.assertLess(dd, 0.0005) ######## test that fluxes are correctly calculated bp_dict = BandpassDict.loadTotalBandpassesFromFiles() imsim_bp = Bandpass() imsim_bp.imsimBandpass() phot_params = PhotometricParameters(nexp=1, exptime=30.0) for i_obj, gs_obj in enumerate(gs_object_arr): sed = Sed() full_sed_name = os.path.join(os.environ['SIMS_SED_LIBRARY_DIR'], truth_data['sedFilename'][i_obj]) sed.readSED_flambda(full_sed_name) fnorm = sed.calcFluxNorm(truth_data['magNorm'][i_obj], imsim_bp) sed.multiplyFluxNorm(fnorm) a_x, b_x = sed.setupCCMab() sed.addCCMDust(a_x, b_x, A_v=truth_data['internalAv'][i_obj], R_v=truth_data['internalRv'][i_obj]) sed.redshiftSED(truth_data['redshift'][i_obj], dimming=True) sed.resampleSED(wavelen_match=bp_dict.wavelenMatch) a_x, b_x = sed.setupCCMab() sed.addCCMDust(a_x, b_x, A_v=truth_data['galacticAv'][i_obj], R_v=truth_data['galacticRv'][i_obj]) for bp in ('u', 'g', 'r', 'i', 'z', 'y'): flux = sed.calcADU(bp_dict[bp], phot_params) * phot_params.gain self.assertAlmostEqual(flux / gs_obj.flux(bp), 1.0, 6) ######## test that objects are assigned to the right chip in ######## gs_object_dict unique_id_dict = {} for chip_name in gs_object_dict: local_unique_id_list = [] for gs_object in gs_object_dict[chip_name]: local_unique_id_list.append(gs_object.uniqueId) local_unique_id_list = set(local_unique_id_list) unique_id_dict[chip_name] = local_unique_id_list valid = 0 valid_chip_names = set() for unq, xpup, ypup in zip(truth_data['uniqueId'], truth_data['x_pupil'], truth_data['y_pupil']): chip_name = chipNameFromPupilCoordsLSST(xpup, ypup)[0] if chip_name is not None: self.assertIn(unq, unique_id_dict[chip_name]) valid_chip_names.add(chip_name) valid += 1 self.assertGreater(valid, 10) self.assertGreater(len(valid_chip_names), 5)
def _chipNameFromRaDecLSST(ra, dec, pm_ra=None, pm_dec=None, parallax=None, v_rad=None, obs_metadata=None, epoch=2000.0, allow_multiple_chips=False, band='r'): """ Return the names of detectors on the LSST camera that see the object specified by (RA, Dec) in radians. @param [in] ra in radians (a numpy array or a float). In the International Celestial Reference System. @param [in] dec in radians (a numpy array or a float). In the International Celestial Reference System. @param [in] pm_ra is proper motion in RA multiplied by cos(Dec) (radians/yr) Can be a numpy array or a number or None (default=None). @param [in] pm_dec is proper motion in dec (radians/yr) Can be a numpy array or a number or None (default=None). @param [in] parallax is parallax in radians Can be a numpy array or a number or None (default=None). @param [in] v_rad is radial velocity (km/s) Can be a numpy array or a number or None (default=None). @param [in] obs_metadata is an ObservationMetaData characterizing the telescope pointing @param [in] epoch is the epoch in Julian years of the equinox against which RA and Dec are measured. Default is 2000. @param [in] allow_multiple_chips is a boolean (default False) indicating whether or not this method will allow objects to be visible on more than one chip. If it is 'False' and an object appears on more than one chip, only the first chip will appear in the list of chipNames but NO WARNING WILL BE EMITTED. If it is 'True' and an object falls on more than one chip, a list of chipNames will appear for that object. @param [in] band is the filter we are simulating (Default=r) @param [out] the name(s) of the chips on which ra, dec fall (will be a numpy array if more than one) """ are_arrays = _validate_inputs([ra, dec], ['ra', 'dec'], "chipNameFromRaDecLSST") if epoch is None: raise RuntimeError("You need to pass an epoch into chipName") if obs_metadata is None: raise RuntimeError( "You need to pass an ObservationMetaData into chipName") if obs_metadata.mjd is None: raise RuntimeError( "You need to pass an ObservationMetaData with an mjd into chipName" ) if obs_metadata.rotSkyPos is None: raise RuntimeError( "You need to pass an ObservationMetaData with a rotSkyPos into chipName" ) xp, yp = _pupilCoordsFromRaDec(ra, dec, pm_ra=pm_ra, pm_dec=pm_dec, parallax=parallax, v_rad=v_rad, obs_metadata=obs_metadata, epoch=epoch) return chipNameFromPupilCoordsLSST( xp, yp, allow_multiple_chips=allow_multiple_chips, band=band)
def _pixelCoordsFromRaDec(ra, dec, obs_metadata=None, epoch=None, chipNames=None, camera=None, includeDistortion=True): """ Get the pixel positions (or nan if not on a chip) for objects based on their RA, and Dec (in radians) @param [in] ra is a numpy array containing the RA of the objects in radians. In the International Celestial Reference System. @param [in] dec is a numpy array containing the Dec of the objects in radians. In the International Celestial Reference System. @param [in] obs_metadata is an ObservationMetaData characterizing the telescope pointing. @param [in] epoch is the epoch in Julian years of the equinox against which RA is measured. @param [in] chipNames a numpy array of chipNames. If it is None, this method will call chipName to find the array. The option exists for the user to specify chipNames, just in case the user has already called chipName for some reason. @param [in] camera is an afwCameraGeom object specifying the attributes of the camera. This is an optional argument to be passed to chipName. @param [in] includeDistortion is a boolean. If True (default), then this method will return the true pixel coordinates with optical distortion included. If False, this method will return TAN_PIXEL coordinates, which are the pixel coordinates with estimated optical distortion removed. See the documentation in afw.cameraGeom for more details. @param [out] a 2-D numpy array in which the first row is the x pixel coordinate and the second row is the y pixel coordinate """ if epoch is None: raise RuntimeError("You need to pass an epoch into pixelCoordsFromRaDec") if obs_metadata is None: raise RuntimeError("You need to pass an ObservationMetaData into pixelCoordsFromRaDec") if obs_metadata.mjd is None: raise RuntimeError("You need to pass an ObservationMetaData with an mjd into " \ + "pixelCoordsFromRaDec") if obs_metadata.rotSkyPos is None: raise RuntimeError("You need to pass an ObservationMetaData with a rotSkyPos into " \ + "pixelCoordsFromRaDec") if not isinstance(ra, numpy.ndarray) or not isinstance(dec, numpy.ndarray): raise RuntimeError("You need to pass numpy arrays of RA and Dec to pixelCoordsFromRaDec") if len(ra) != len(dec): raise RuntimeError("You passed %d RA and %d Dec coordinates " % (len(ra), len(dec)) + "to pixelCoordsFromRaDec") if chipNames is not None: if len(ra) != len(chipNames): raise RuntimeError("You passed %d points but %d chipNames to pixelCoordsFromRaDec" % (len(ra), len(chipNames))) xPupil, yPupil = _pupilCoordsFromRaDec(ra, dec, obs_metadata=obs_metadata, epoch=epoch) return pixelCoordsFromPupilCoords(xPupil, yPupil, chipNames=chipNames, camera=camera, includeDistortion=includeDistortion)
def testUtilityMethods(self): """ Generate a catalog using the methods from AstrometryUtils.py and CameraUtils.py. Read that data in, and then recalculate the values 'by hand' to make sure that they are consistent. """ catName = os.path.join(getPackageDir('sims_catUtils'), 'tests', 'scratchSpace', 'AstrometryUtilityCatalog.txt') if os.path.exists(catName): os.unlink(catName) self.cat.write_catalog(catName) dtype = [('id',int), ('raICRS',float), ('decICRS',float), ('x_pupil',float), ('y_pupil',float), ('chipName',str,11), ('xPix',float), ('yPix',float), ('xFocalPlane',float), ('yFocalPlane',float)] baselineData = numpy.loadtxt(catName, dtype=dtype, delimiter=';') self.assertGreater(len(baselineData), 0) pupilTest = _pupilCoordsFromRaDec(baselineData['raICRS'], baselineData['decICRS'], obs_metadata=self.obs_metadata, epoch=2000.0) for (xxtest, yytest, xx, yy) in \ zip(pupilTest[0], pupilTest[1], baselineData['x_pupil'], baselineData['y_pupil']): self.assertAlmostEqual(xxtest,xx,6) self.assertAlmostEqual(yytest,yy,6) focalTest = focalPlaneCoordsFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera) focalRa = _focalPlaneCoordsFromRaDec(baselineData['raICRS'], baselineData['decICRS'], epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata, camera=self.cat.camera) for (xxtest, yytest, xxra, yyra, xx, yy) in \ zip(focalTest[0], focalTest[1], focalRa[0], focalRa[1], baselineData['xFocalPlane'], baselineData['yFocalPlane']): self.assertAlmostEqual(xxtest,xx,6) self.assertAlmostEqual(yytest,yy,6) self.assertAlmostEqual(xxra,xx,6) self.assertAlmostEqual(yyra,yy,6) pixTest = pixelCoordsFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera) pixTestRaDec = _pixelCoordsFromRaDec(baselineData['raICRS'], baselineData['decICRS'], epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata, camera=self.cat.camera) for (xxtest, yytest, xxra, yyra, xx, yy) in \ zip(pixTest[0], pixTest[1], pixTestRaDec[0], pixTestRaDec[1], baselineData['xPix'], baselineData['yPix']): if not numpy.isnan(xx) and not numpy.isnan(yy): self.assertAlmostEqual(xxtest,xx,5) self.assertAlmostEqual(yytest,yy,5) self.assertAlmostEqual(xxra,xx,5) self.assertAlmostEqual(yyra,yy,5) else: self.assertTrue(numpy.isnan(xx)) self.assertTrue(numpy.isnan(yy)) self.assertTrue(numpy.isnan(xxra)) self.assertTrue(numpy.isnan(yyra)) self.assertTrue(numpy.isnan(xxtest)) self.assertTrue(numpy.isnan(yytest)) nameTest = chipNameFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera) nameRA = _chipNameFromRaDec(baselineData['raICRS'], baselineData['decICRS'], epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata, camera=self.cat.camera) for (ntest, nra, ncontrol) in zip(nameTest, nameRA, baselineData['chipName']): if ncontrol != 'None': self.assertEqual(ntest,ncontrol) self.assertEqual(nra,ncontrol) else: self.assertTrue(ntest is None) self.assertTrue(nra is None) if os.path.exists(catName): os.unlink(catName)
def _pixelCoordsFromRaDec(ra, dec, pm_ra=None, pm_dec=None, parallax=None, v_rad=None, obs_metadata=None, chipName=None, camera=None, epoch=2000.0, includeDistortion=True): """ Get the pixel positions (or nan if not on a chip) for objects based on their RA, and Dec (in radians) @param [in] ra is in radians in the International Celestial Reference System. Can be either a float or a numpy array. @param [in] dec is in radians in the International Celestial Reference System. Can be either a float or a numpy array. @param [in] pm_ra is proper motion in RA multiplied by cos(Dec) (radians/yr) Can be a numpy array or a number or None (default=None). @param [in] pm_dec is proper motion in dec (radians/yr) Can be a numpy array or a number or None (default=None). @param [in] parallax is parallax in radians Can be a numpy array or a number or None (default=None). @param [in] v_rad is radial velocity (km/s) Can be a numpy array or a number or None (default=None). @param [in] obs_metadata is an ObservationMetaData characterizing the telescope pointing. @param [in] epoch is the epoch in Julian years of the equinox against which RA is measured. Default is 2000. @param [in] chipName designates the names of the chips on which the pixel coordinates will be reckoned. Can be either single value, an array, or None. If an array, there must be as many chipNames as there are (RA, Dec) pairs. If a single value, all of the pixel coordinates will be reckoned on the same chip. If None, this method will calculate which chip each(RA, Dec) pair actually falls on, and return pixel coordinates for each (RA, Dec) pair on the appropriate chip. Default is None. @param [in] camera is an afwCameraGeom object specifying the attributes of the camera. This is an optional argument to be passed to chipName. @param [in] includeDistortion is a boolean. If True (default), then this method will return the true pixel coordinates with optical distortion included. If False, this method will return TAN_PIXEL coordinates, which are the pixel coordinates with estimated optical distortion removed. See the documentation in afw.cameraGeom for more details. @param [out] a 2-D numpy array in which the first row is the x pixel coordinate and the second row is the y pixel coordinate """ are_arrays, \ chipNameList = _validate_inputs_and_chipname([ra, dec], ['ra', 'dec'], 'pixelCoordsFromRaDec', chipName) if epoch is None: raise RuntimeError("You need to pass an epoch into pixelCoordsFromRaDec") if obs_metadata is None: raise RuntimeError("You need to pass an ObservationMetaData into pixelCoordsFromRaDec") if obs_metadata.mjd is None: raise RuntimeError("You need to pass an ObservationMetaData with an mjd into " "pixelCoordsFromRaDec") if obs_metadata.rotSkyPos is None: raise RuntimeError("You need to pass an ObservationMetaData with a rotSkyPos into " "pixelCoordsFromRaDec") xPupil, yPupil = _pupilCoordsFromRaDec(ra, dec, pm_ra=pm_ra, pm_dec=pm_dec, parallax=parallax, v_rad=v_rad, obs_metadata=obs_metadata, epoch=epoch) return pixelCoordsFromPupilCoords(xPupil, yPupil, chipName=chipNameList, camera=camera, includeDistortion=includeDistortion)
def _chipNameFromRaDec(ra, dec, pm_ra=None, pm_dec=None, parallax=None, v_rad=None, obs_metadata=None, camera=None, epoch=2000.0, allow_multiple_chips=False): """ Return the names of detectors that see the object specified by (RA, Dec) in radians. @param [in] ra in radians (a numpy array or a float). In the International Celestial Reference System. @param [in] dec in radians (a numpy array or a float). In the International Celestial Reference System. @param [in] pm_ra is proper motion in RA multiplied by cos(Dec) (radians/yr) Can be a numpy array or a number or None (default=None). @param [in] pm_dec is proper motion in dec (radians/yr) Can be a numpy array or a number or None (default=None). @param [in] parallax is parallax in radians Can be a numpy array or a number or None (default=None). @param [in] v_rad is radial velocity (km/s) Can be a numpy array or a number or None (default=None). @param [in] obs_metadata is an ObservationMetaData characterizing the telescope pointing @param [in] epoch is the epoch in Julian years of the equinox against which RA and Dec are measured. Default is 2000. @param [in] camera is an afw.cameraGeom camera instance characterizing the camera @param [in] allow_multiple_chips is a boolean (default False) indicating whether or not this method will allow objects to be visible on more than one chip. If it is 'False' and an object appears on more than one chip, an exception will be raised. If it is 'True' and an object falls on more than one chip, it will still only return the first chip in the list of chips returned. THIS BEHAVIOR SHOULD BE FIXED IN A FUTURE TICKET. @param [out] the name(s) of the chips on which ra, dec fall (will be a numpy array if more than one) """ are_arrays = _validate_inputs([ra, dec], ['ra', 'dec'], "chipNameFromRaDec") if epoch is None: raise RuntimeError("You need to pass an epoch into chipName") if obs_metadata is None: raise RuntimeError("You need to pass an ObservationMetaData into chipName") if obs_metadata.mjd is None: raise RuntimeError("You need to pass an ObservationMetaData with an mjd into chipName") if obs_metadata.rotSkyPos is None: raise RuntimeError("You need to pass an ObservationMetaData with a rotSkyPos into chipName") if not are_arrays: ra = np.array([ra]) dec = np.array([dec]) xp, yp = _pupilCoordsFromRaDec(ra, dec, pm_ra=pm_ra, pm_dec=pm_dec, parallax=parallax, v_rad=v_rad, obs_metadata=obs_metadata, epoch=epoch) ans = chipNameFromPupilCoords(xp, yp, camera=camera, allow_multiple_chips=allow_multiple_chips) if not are_arrays: return ans[0] return ans
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)
def _focalPlaneCoordsFromRaDec(ra, dec, pm_ra=None, pm_dec=None, parallax=None, v_rad=None, obs_metadata=None, epoch=2000.0, camera=None): """ Get the focal plane coordinates for all objects in the catalog. @param [in] ra is in radians in the International Celestial Reference System. Can be either a float or a numpy array. @param [in] dec is in radians in the International Celestial Reference System. Can be either a float or a numpy array. @param [in] pm_ra is proper motion in RA multiplied by cos(Dec) (radians/yr) Can be a numpy array or a number or None (default=None). @param [in] pm_dec is proper motion in dec (radians/yr) Can be a numpy array or a number or None (default=None). @param [in] parallax is parallax in radians Can be a numpy array or a number or None (default=None). @param [in] v_rad is radial velocity (km/s) Can be a numpy array or a number or None (default=None). @param [in] obs_metadata is an ObservationMetaData object describing the telescope pointing (only if specifying RA and Dec rather than pupil coordinates) @param [in] epoch is the julian epoch of the mean equinox used for coordinate transformations (in years; only if specifying RA and Dec rather than pupil coordinates; default is 2000) @param [in] camera is an afw.cameraGeom camera object @param [out] a 2-D numpy array in which the first row is the x focal plane coordinate and the second row is the y focal plane coordinate (both in millimeters) """ _validate_inputs([ra, dec], ['ra', 'dec'], 'focalPlaneCoordsFromRaDec') if epoch is None: raise RuntimeError("You have to specify an epoch to run " "focalPlaneCoordsFromRaDec") if obs_metadata is None: raise RuntimeError("You have to specify an ObservationMetaData to run " "focalPlaneCoordsFromRaDec") if obs_metadata.mjd is None: raise RuntimeError("You need to pass an ObservationMetaData with an " "mjd into focalPlaneCoordsFromRaDec") if obs_metadata.rotSkyPos is None: raise RuntimeError("You need to pass an ObservationMetaData with a " "rotSkyPos into focalPlaneCoordsFromRaDec") xPupil, yPupil = _pupilCoordsFromRaDec(ra, dec, pm_ra=pm_ra, pm_dec=pm_dec, parallax=parallax, v_rad=v_rad, obs_metadata=obs_metadata, epoch=epoch) return focalPlaneCoordsFromPupilCoords(xPupil, yPupil, camera=camera)
def testUtilityMethods(self): """ Generate a catalog using the methods from AstrometryUtils.py and CameraUtils.py. Read that data in, and then recalculate the values 'by hand' to make sure that they are consistent. """ with lsst.utils.tests.getTempFilePath('.txt') as catName: self.cat.write_catalog(catName) dtype = [('id', int), ('raICRS', float), ('decICRS', float), ('parallax', float), ('radial_velocity', float), ('x_pupil', float), ('y_pupil', float), ('chipName', str, 11), ('xPix', float), ('yPix', float), ('xFocalPlane', float), ('yFocalPlane', float)] baselineData = np.genfromtxt(catName, dtype=dtype, delimiter=';') self.assertGreater(len(baselineData), 0) pupilTest = _pupilCoordsFromRaDec(baselineData['raICRS'], baselineData['decICRS'], parallax=baselineData['parallax'], v_rad=baselineData['radial_velocity'], obs_metadata=self.obs_metadata, epoch=2000.0) for (xxtest, yytest, xx, yy) in \ zip(pupilTest[0], pupilTest[1], baselineData['x_pupil'], baselineData['y_pupil']): self.assertAlmostEqual(xxtest, xx, 6) self.assertAlmostEqual(yytest, yy, 6) focalTest = focalPlaneCoordsFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera) focalRa = _focalPlaneCoordsFromRaDec(baselineData['raICRS'], baselineData['decICRS'], parallax=baselineData['parallax'], v_rad=baselineData['radial_velocity'], epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata, camera=self.cat.camera) for (xxtest, yytest, xxra, yyra, xx, yy) in \ zip(focalTest[0], focalTest[1], focalRa[0], focalRa[1], baselineData['xFocalPlane'], baselineData['yFocalPlane']): self.assertAlmostEqual(xxtest, xx, 6) self.assertAlmostEqual(yytest, yy, 6) self.assertAlmostEqual(xxra, xx, 6) self.assertAlmostEqual(yyra, yy, 6) pixTest = pixelCoordsFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera) pixTestRaDec = _pixelCoordsFromRaDec(baselineData['raICRS'], baselineData['decICRS'], parallax=baselineData['parallax'], v_rad=baselineData['radial_velocity'], epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata, camera=self.cat.camera) for (xxtest, yytest, xxra, yyra, xx, yy) in \ zip(pixTest[0], pixTest[1], pixTestRaDec[0], pixTestRaDec[1], baselineData['xPix'], baselineData['yPix']): if not np.isnan(xx) and not np.isnan(yy): self.assertAlmostEqual(xxtest, xx, 5) self.assertAlmostEqual(yytest, yy, 5) self.assertAlmostEqual(xxra, xx, 5) self.assertAlmostEqual(yyra, yy, 5) else: np.testing.assert_equal(xx, np.NaN) np.testing.assert_equal(yy, np.NaN) np.testing.assert_equal(xxra, np.NaN) np.testing.assert_equal(yyra, np.NaN) np.testing.assert_equal(xxtest, np.NaN) np.testing.assert_equal(yytest, np.NaN) nameTest = chipNameFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera) nameRA = _chipNameFromRaDec(baselineData['raICRS'], baselineData['decICRS'], epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata, camera=self.cat.camera) is_none = 0 for (ntest, nra, ncontrol) in zip(nameTest, nameRA, baselineData['chipName']): if ncontrol != 'None': self.assertEqual(ntest, ncontrol) self.assertEqual(nra, ncontrol) else: is_none += 1 self.assertIsNone(ntest) self.assertIsNone(nra) self.assertGreater(is_none, 0) self.assertLess(is_none, len(baselineData))
def _chipNameFromRaDec(ra, dec, pm_ra=None, pm_dec=None, parallax=None, v_rad=None, obs_metadata=None, camera=None, epoch=2000.0, allow_multiple_chips=False): """ Return the names of detectors that see the object specified by (RA, Dec) in radians. @param [in] ra in radians (a numpy array or a float). In the International Celestial Reference System. @param [in] dec in radians (a numpy array or a float). In the International Celestial Reference System. @param [in] pm_ra is proper motion in RA multiplied by cos(Dec) (radians/yr) Can be a numpy array or a number or None (default=None). @param [in] pm_dec is proper motion in dec (radians/yr) Can be a numpy array or a number or None (default=None). @param [in] parallax is parallax in radians Can be a numpy array or a number or None (default=None). @param [in] v_rad is radial velocity (km/s) Can be a numpy array or a number or None (default=None). @param [in] obs_metadata is an ObservationMetaData characterizing the telescope pointing @param [in] epoch is the epoch in Julian years of the equinox against which RA and Dec are measured. Default is 2000. @param [in] camera is an afw.cameraGeom camera instance characterizing the camera @param [in] allow_multiple_chips is a boolean (default False) indicating whether or not this method will allow objects to be visible on more than one chip. If it is 'False' and an object appears on more than one chip, an exception will be raised. If it is 'True' and an object falls on more than one chip, it will still only return the first chip in the list of chips returned. THIS BEHAVIOR SHOULD BE FIXED IN A FUTURE TICKET. @param [out] the name(s) of the chips on which ra, dec fall (will be a numpy array if more than one) """ are_arrays = _validate_inputs([ra, dec], ['ra', 'dec'], "chipNameFromRaDec") if epoch is None: raise RuntimeError("You need to pass an epoch into chipName") if obs_metadata is None: raise RuntimeError( "You need to pass an ObservationMetaData into chipName") if obs_metadata.mjd is None: raise RuntimeError( "You need to pass an ObservationMetaData with an mjd into chipName" ) if obs_metadata.rotSkyPos is None: raise RuntimeError( "You need to pass an ObservationMetaData with a rotSkyPos into chipName" ) if not are_arrays: ra = np.array([ra]) dec = np.array([dec]) xp, yp = _pupilCoordsFromRaDec(ra, dec, pm_ra=pm_ra, pm_dec=pm_dec, parallax=parallax, v_rad=v_rad, obs_metadata=obs_metadata, epoch=epoch) ans = chipNameFromPupilCoords(xp, yp, camera=camera, allow_multiple_chips=allow_multiple_chips) if not are_arrays: return ans[0] return ans
def testCardinalDirections(self): """ This unit test verifies that the following conventions hold: if rotSkyPos = 0, then north is +y the camera and east is +x if rotSkyPos = -90, then north is -x on the camera and east is +y if rotSkyPos = 90, then north is +x on the camera and east is -y if rotSkyPos = 180, then north is -y on the camera and east is -x This is consistent with rotSkyPos = rotTelPos - parallacticAngle parallacticAngle is negative when the pointing is east of the meridian. http://www.petermeadows.com/html/parallactic.html rotTelPos is the angle between up on the telescope and up on the camera, where positive rotTelPos goes from north to west (from an email sent to me by LynneJones) I have verified that OpSim follows the rotSkyPos = rotTelPos - paralacticAngle convention. I have verified that altAzPaFromRaDec follows the convention that objects east of the meridian have a negative parallactic angle. (altAzPaFromRaDec uses PALPY under the hood, so it can probably be taken as correct) It will verify this convention for multiple random pointings. """ epoch = 2000.0 mjd = 42350.0 rng = np.random.RandomState(42) raList = rng.random_sample(10) * 360.0 decList = rng.random_sample(10) * 180.0 - 90.0 for rotSkyPos in np.arange(-90.0, 181.0, 90.0): for ra, dec in zip(raList, decList): obs = ObservationMetaData(pointingRA=ra, pointingDec=dec, mjd=mjd, rotSkyPos=rotSkyPos) ra_obs, dec_obs = _observedFromICRS(np.radians([ra]), np.radians([dec]), obs_metadata=obs, epoch=2000.0, includeRefraction=True) # test points that are displaced just to the (E, W, N, S) of the pointing # in observed geocentric RA, Dec; verify that the pupil coordinates # change as expected raTest_obs = ra_obs[0] + np.array([0.01, -0.01, 0.0, 0.0]) decTest_obs = dec_obs[0] + np.array([0.0, 0.0, 0.01, -0.01]) raTest, decTest = _icrsFromObserved(raTest_obs, decTest_obs, obs_metadata=obs, epoch=2000.0, includeRefraction=True) x, y = _pupilCoordsFromRaDec(raTest, decTest, obs_metadata=obs, epoch=epoch) lon, lat = _nativeLonLatFromRaDec(raTest, decTest, obs) rr = np.abs(np.cos(lat) / np.sin(lat)) if np.abs(rotSkyPos) < 0.01: # rotSkyPos == 0 control_x = np.array([1.0 * rr[0], -1.0 * rr[1], 0.0, 0.0]) control_y = np.array([0.0, 0.0, 1.0 * rr[2], -1.0 * rr[3]]) elif np.abs(rotSkyPos + 90.0) < 0.01: # rotSkyPos == -90 control_x = np.array([0.0, 0.0, -1.0 * rr[2], 1.0 * rr[3]]) control_y = np.array([1.0 * rr[0], -1.0 * rr[1], 0.0, 0.0]) elif np.abs(rotSkyPos - 90.0) < 0.01: # rotSkyPos == 90 control_x = np.array([0.0, 0.0, 1.0 * rr[2], -1.0 * rr[3]]) control_y = np.array([-1.0 * rr[0], +1.0 * rr[1], 0.0, 0.0]) elif np.abs(rotSkyPos - 180.0) < 0.01: # rotSkyPos == 180 control_x = np.array([-1.0 * rr[0], +1.0 * rr[1], 0.0, 0.0]) control_y = np.array([0.0, 0.0, -1.0 * rr[2], 1.0 * rr[3]]) msg = 'failed on rotSkyPos == %e\n' % rotSkyPos msg += 'control_x %s\n' % str(control_x) msg += 'test_x %s\n' % str(x) msg += 'control_y %s\n' % str(control_y) msg += 'test_y %s\n' % str(y) dx = np.array([xx / cc if np.abs(cc) > 1.0e-10 else 1.0 - xx for xx, cc in zip(x, control_x)]) dy = np.array([yy / cc if np.abs(cc) > 1.0e-10 else 1.0 - yy for yy, cc in zip(y, control_y)]) self.assertLess(np.abs(dx-np.ones(4)).max(), 0.001, msg=msg) self.assertLess(np.abs(dy-np.ones(4)).max(), 0.001, msg=msg)
def _pixelCoordsFromRaDecLSST(ra, dec, pm_ra=None, pm_dec=None, parallax=None, v_rad=None, obs_metadata=None, chipName=None, camera=None, epoch=2000.0, includeDistortion=True, band='r'): """ Get the pixel positions on the LSST camera (or nan if not on a chip) for objects based on their RA, and Dec (in radians) @param [in] ra is in radians in the International Celestial Reference System. Can be either a float or a numpy array. @param [in] dec is in radians in the International Celestial Reference System. Can be either a float or a numpy array. @param [in] pm_ra is proper motion in RA multiplied by cos(Dec) (radians/yr) Can be a numpy array or a number or None (default=None). @param [in] pm_dec is proper motion in dec (radians/yr) Can be a numpy array or a number or None (default=None). @param [in] parallax is parallax in radians Can be a numpy array or a number or None (default=None). @param [in] v_rad is radial velocity (km/s) Can be a numpy array or a number or None (default=None). @param [in] obs_metadata is an ObservationMetaData characterizing the telescope pointing. @param [in] epoch is the epoch in Julian years of the equinox against which RA is measured. Default is 2000. @param [in] chipName designates the names of the chips on which the pixel coordinates will be reckoned. Can be either single value, an array, or None. If an array, there must be as many chipNames as there are (RA, Dec) pairs. If a single value, all of the pixel coordinates will be reckoned on the same chip. If None, this method will calculate which chip each(RA, Dec) pair actually falls on, and return pixel coordinates for each (RA, Dec) pair on the appropriate chip. Default is None. @param [in] camera is an afwCameraGeom object specifying the attributes of the camera. This is an optional argument to be passed to chipName. @param [in] includeDistortion is a boolean. If True (default), then this method will return the true pixel coordinates with optical distortion included. If False, this method will return TAN_PIXEL coordinates, which are the pixel coordinates with estimated optical distortion removed. See the documentation in afw.cameraGeom for more details. @param [in] band is the filter we are simulating ('u', 'g', 'r', etc.) Default='r' @param [out] a 2-D numpy array in which the first row is the x pixel coordinate and the second row is the y pixel coordinate """ if epoch is None: raise RuntimeError( "You need to pass an epoch into pixelCoordsFromRaDec") if obs_metadata is None: raise RuntimeError( "You need to pass an ObservationMetaData into pixelCoordsFromRaDec" ) if obs_metadata.mjd is None: raise RuntimeError( "You need to pass an ObservationMetaData with an mjd into " "pixelCoordsFromRaDec") if obs_metadata.rotSkyPos is None: raise RuntimeError( "You need to pass an ObservationMetaData with a rotSkyPos into " "pixelCoordsFromRaDec") xPupil, yPupil = _pupilCoordsFromRaDec(ra, dec, pm_ra=pm_ra, pm_dec=pm_dec, parallax=parallax, v_rad=v_rad, obs_metadata=obs_metadata, epoch=epoch) return pixelCoordsFromPupilCoordsLSST(xPupil, yPupil, chipName=chipName, band=band, includeDistortion=includeDistortion)
def testCardinalDirections(self): """ This unit test verifies that the following conventions hold: if rotSkyPos = 0, then north is +y the camera and east is +x if rotSkyPos = -90, then north is -x on the camera and east is +y if rotSkyPos = 90, then north is +x on the camera and east is -y if rotSkyPos = 180, then north is -y on the camera and east is -x This is consistent with rotSkyPos = rotTelPos - parallacticAngle parallacticAngle is negative when the pointing is east of the meridian. http://www.petermeadows.com/html/parallactic.html rotTelPos is the angle between up on the telescope and up on the camera, where positive rotTelPos goes from north to west (from an email sent to me by LynneJones) I have verified that OpSim follows the rotSkyPos = rotTelPos - paralacticAngle convention. I have verified that altAzPaFromRaDec follows the convention that objects east of the meridian have a negative parallactic angle. (altAzPaFromRaDec uses PALPY under the hood, so it can probably be taken as correct) It will verify this convention for multiple random pointings. """ epoch = 2000.0 mjd = 42350.0 rng = np.random.RandomState(42) raList = rng.random_sample(10) * 360.0 decList = rng.random_sample(10) * 180.0 - 90.0 for rotSkyPos in np.arange(-90.0, 181.0, 90.0): for ra, dec in zip(raList, decList): obs = ObservationMetaData(pointingRA=ra, pointingDec=dec, mjd=mjd, rotSkyPos=rotSkyPos) ra_obs, dec_obs = _observedFromICRS(np.radians([ra]), np.radians([dec]), obs_metadata=obs, epoch=2000.0, includeRefraction=True) # test points that are displaced just to the (E, W, N, S) of the pointing # in observed geocentric RA, Dec; verify that the pupil coordinates # change as expected raTest_obs = ra_obs[0] + np.array([0.01, -0.01, 0.0, 0.0]) decTest_obs = dec_obs[0] + np.array([0.0, 0.0, 0.01, -0.01]) raTest, decTest = _icrsFromObserved(raTest_obs, decTest_obs, obs_metadata=obs, epoch=2000.0, includeRefraction=True) x, y = _pupilCoordsFromRaDec(raTest, decTest, obs_metadata=obs, epoch=epoch) lon, lat = _nativeLonLatFromRaDec(raTest, decTest, obs) rr = np.abs(np.cos(lat) / np.sin(lat)) if np.abs(rotSkyPos) < 0.01: # rotSkyPos == 0 control_x = np.array([1.0 * rr[0], -1.0 * rr[1], 0.0, 0.0]) control_y = np.array([0.0, 0.0, 1.0 * rr[2], -1.0 * rr[3]]) elif np.abs(rotSkyPos + 90.0) < 0.01: # rotSkyPos == -90 control_x = np.array([0.0, 0.0, -1.0 * rr[2], 1.0 * rr[3]]) control_y = np.array([1.0 * rr[0], -1.0 * rr[1], 0.0, 0.0]) elif np.abs(rotSkyPos - 90.0) < 0.01: # rotSkyPos == 90 control_x = np.array([0.0, 0.0, 1.0 * rr[2], -1.0 * rr[3]]) control_y = np.array( [-1.0 * rr[0], +1.0 * rr[1], 0.0, 0.0]) elif np.abs(rotSkyPos - 180.0) < 0.01: # rotSkyPos == 180 control_x = np.array( [-1.0 * rr[0], +1.0 * rr[1], 0.0, 0.0]) control_y = np.array([0.0, 0.0, -1.0 * rr[2], 1.0 * rr[3]]) msg = 'failed on rotSkyPos == %e\n' % rotSkyPos msg += 'control_x %s\n' % str(control_x) msg += 'test_x %s\n' % str(x) msg += 'control_y %s\n' % str(control_y) msg += 'test_y %s\n' % str(y) dx = np.array([ xx / cc if np.abs(cc) > 1.0e-10 else 1.0 - xx for xx, cc in zip(x, control_x) ]) dy = np.array([ yy / cc if np.abs(cc) > 1.0e-10 else 1.0 - yy for yy, cc in zip(y, control_y) ]) self.assertLess(np.abs(dx - np.ones(4)).max(), 0.001, msg=msg) self.assertLess(np.abs(dy - np.ones(4)).max(), 0.001, msg=msg)
def testExceptions(self): """ Test that exceptions are raised when they ought to be """ obs_metadata = ObservationMetaData(pointingRA=25.0, pointingDec=25.0, rotSkyPos=25.0, mjd=52000.0) rng = np.random.RandomState(42) ra = rng.random_sample(10) * np.radians(1.0) + np.radians( obs_metadata.pointingRA) dec = rng.random_sample(10) * np.radians(1.0) + np.radians( obs_metadata.pointingDec) raShort = np.array([1.0]) decShort = np.array([1.0]) # test without obs_metadata self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0) # test without pointingRA dummy = ObservationMetaData(pointingDec=obs_metadata.pointingDec, rotSkyPos=obs_metadata.rotSkyPos, mjd=obs_metadata.mjd) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0, obs_metadata=dummy) # test without pointingDec dummy = ObservationMetaData(pointingRA=obs_metadata.pointingRA, rotSkyPos=obs_metadata.rotSkyPos, mjd=obs_metadata.mjd) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0, obs_metadata=dummy) # test without rotSkyPos dummy = ObservationMetaData(pointingRA=obs_metadata.pointingRA, pointingDec=obs_metadata.pointingDec, mjd=obs_metadata.mjd) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0, obs_metadata=dummy) # test without mjd dummy = ObservationMetaData(pointingRA=obs_metadata.pointingRA, pointingDec=obs_metadata.pointingDec, rotSkyPos=obs_metadata.rotSkyPos) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, dec, epoch=2000.0, obs_metadata=dummy) # test for mismatches dummy = ObservationMetaData(pointingRA=obs_metadata.pointingRA, pointingDec=obs_metadata.pointingDec, rotSkyPos=obs_metadata.rotSkyPos, mjd=obs_metadata.mjd) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, ra, decShort, epoch=2000.0, obs_metadata=dummy) self.assertRaises(RuntimeError, _pupilCoordsFromRaDec, raShort, dec, epoch=2000.0, obs_metadata=dummy) # test that it actually runs (and that passing in either numpy arrays or floats gives # the same results) xx_arr, yy_arr = _pupilCoordsFromRaDec(ra, dec, obs_metadata=obs_metadata) self.assertIsInstance(xx_arr, np.ndarray) self.assertIsInstance(yy_arr, np.ndarray) for ix in range(len(ra)): xx_f, yy_f = _pupilCoordsFromRaDec(ra[ix], dec[ix], obs_metadata=obs_metadata) self.assertIsInstance(xx_f, np.float) self.assertIsInstance(yy_f, np.float) self.assertAlmostEqual(xx_arr[ix], xx_f, 12) self.assertAlmostEqual(yy_arr[ix], yy_f, 12) self.assertFalse(np.isnan(xx_f)) self.assertFalse(np.isnan(yy_f))