Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2This file contains coordinate transformations that rely on both 

3palpy and the contents of AstrometryUtils.py (basically, coordinate 

4transformations that need to transform between observed geocentric RA, DEC 

5and ICRS RA, Dec) 

6""" 

7from __future__ import division 

8 

9import numpy as np 

10import palpy 

11from lsst.sims.utils.CodeUtilities import _validate_inputs 

12from lsst.sims.utils import _icrsFromObserved, _observedFromICRS, calcLmstLast 

13 

14__all__ = ["_altAzPaFromRaDec", "altAzPaFromRaDec", 

15 "_raDecFromAltAz", "raDecFromAltAz", 

16 "getRotTelPos", "_getRotTelPos", 

17 "getRotSkyPos", "_getRotSkyPos"] 

18 

19 

20def altAzPaFromRaDec(ra, dec, obs, includeRefraction=True): 

21 """ 

22 Convert RA, Dec, longitude, latitude and MJD into altitude, azimuth 

23 and parallactic angle using PALPY 

24 

25 @param [in] ra is RA in degrees. Can be a numpy array or a single value. 

26 Assumed to be in the International Celestial Reference System. 

27 

28 @param [in] dec is Dec in degrees. Can be a numpy array or a single value. 

29 Assumed to be in the International Celestial Reference System. 

30 

31 @param [in] obs is an ObservationMetaData characterizing 

32 the site of the telescope and the MJD of the observation 

33 

34 @param [in] includeRefraction is a boolean that turns refraction on and off 

35 (default True) 

36 

37 @param [out] altitude in degrees 

38 

39 @param [out] azimuth in degrees 

40 

41 @param [out] parallactic angle in degrees 

42 

43 WARNING: This method does not account for apparent motion due to parallax. 

44 This method is only useful for mapping positions on a theoretical celestial 

45 sphere. 

46 """ 

47 

48 alt, az, pa = _altAzPaFromRaDec(np.radians(ra), np.radians(dec), 

49 obs, includeRefraction=includeRefraction) 

50 

51 return np.degrees(alt), np.degrees(az), np.degrees(pa) 

52 

53 

54def _altAzPaFromRaDec(raRad, decRad, obs, includeRefraction=True): 

55 """ 

56 Convert RA, Dec, longitude, latitude and MJD into altitude, azimuth 

57 and parallactic angle using PALPY 

58 

59 @param [in] raRad is RA in radians. Can be a numpy array or a single value. 

60 Assumed to be in the International Celestial Reference System. 

61 

62 @param [in] decRad is Dec in radians. Can be a numpy array or a single value. 

63 Assumed to be in the International Celestial Reference System. 

64 

65 @param [in] obs is an ObservationMetaData characterizing 

66 the site of the telescope and the MJD of the observation 

67 

68 @param [in] includeRefraction is a boolean that turns refraction on and off 

69 (default True) 

70 

71 @param [out] altitude in radians 

72 

73 @param [out] azimuth in radians 

74 

75 @param [out] parallactic angle in radians 

76 

77 WARNING: This method does not account for apparent motion due to parallax. 

78 This method is only useful for mapping positions on a theoretical focal plan 

79 to positions on the celestial sphere. 

80 """ 

81 

82 are_arrays = _validate_inputs([raRad, decRad], ['ra', 'dec'], 

83 "altAzPaFromRaDec") 

84 

85 raObs, decObs = \ 

86 _observedFromICRS(raRad, decRad, obs_metadata=obs, 

87 epoch=2000.0, includeRefraction=includeRefraction) 

88 

89 lst = calcLmstLast(obs.mjd.UT1, obs.site.longitude_rad) 

90 last = lst[1] 

91 haRad = np.radians(last * 15.0) - raObs 

92 

93 if are_arrays: 

94 az, azd, azdd, \ 

95 alt, altd, altdd, \ 

96 pa, pad, padd = palpy.altazVector( 

97 haRad, decObs, obs.site.latitude_rad) 

98 else: 

99 az, azd, azdd, \ 

100 alt, altd, altdd, \ 

101 pa, pad, padd = palpy.altaz(haRad, decObs, obs.site.latitude_rad) 

102 

103 return alt, az, pa 

104 

105 

106def raDecFromAltAz(alt, az, obs, includeRefraction=True): 

107 """ 

108 Convert altitude and azimuth to RA and Dec 

109 

110 @param [in] alt is the altitude in degrees. Can be a numpy array or a single value. 

111 

112 @param [in] az is the azimuth in degrees. Cant be a numpy array or a single value. 

113 

114 @param [in] obs is an ObservationMetaData characterizing 

115 the site of the telescope and the MJD of the observation 

116 

117 @param [in] includeRefraction is a boolean that turns refraction on and off 

118 (default True) 

119 

120 @param [out] RA in degrees (in the International Celestial Reference System) 

121 

122 @param [out] Dec in degrees (in the International Celestial Reference System) 

123 

124 Note: This method is only accurate to within 0.01 arcsec near azimuth = 0 or pi 

125 """ 

126 

127 ra, dec = _raDecFromAltAz(np.radians(alt), np.radians(az), obs, 

128 includeRefraction=includeRefraction) 

129 

130 return np.degrees(ra), np.degrees(dec) 

131 

132 

133def _raDecFromAltAz(altRad, azRad, obs, includeRefraction=True): 

134 """ 

135 Convert altitude and azimuth to RA and Dec 

136 

137 @param [in] altRad is the altitude in radians. Can be a numpy array or a single value. 

138 

139 @param [in] azRad is the azimuth in radians. Cant be a numpy array or a single value. 

140 

141 @param [in] obs is an ObservationMetaData characterizing 

142 the site of the telescope and the MJD of the observation 

143 

144 @param [in] includeRefraction is a boolean that turns refraction on and off 

145 (default True) 

146 

147 @param [out] RA in radians (in the International Celestial Reference System) 

148 

149 @param [out] Dec in radians (in the International Celestial Reference System) 

150 

151 Note: This method is only accurate to within 0.01 arcsec near azimuth = 0 or pi 

152 """ 

153 

154 with np.errstate(invalid='ignore', divide='ignore'): 

155 are_arrays = _validate_inputs( 

156 [altRad, azRad], ['altRad', 'azRad'], "raDecFromAltAz") 

157 

158 lst = calcLmstLast(obs.mjd.UT1, obs.site.longitude_rad) 

159 last = lst[1] 

160 sinAlt = np.sin(altRad) 

161 cosLat = np.cos(obs.site.latitude_rad) 

162 sinLat = np.sin(obs.site.latitude_rad) 

163 decObs = np.arcsin(sinLat * sinAlt + cosLat * 

164 np.cos(altRad) * np.cos(azRad)) 

165 costheta = (sinAlt - np.sin(decObs) * sinLat) / (np.cos(decObs) * cosLat) 

166 if are_arrays: 

167 haRad0 = np.arccos(costheta) 

168 # Make sure there were no NaNs 

169 nanSpots = np.where(np.isnan(haRad0))[0] 

170 if np.size(nanSpots) > 0: 

171 haRad0[nanSpots] = 0.5 * np.pi * \ 

172 (1.0 - np.sign(costheta[nanSpots])) 

173 else: 

174 haRad0 = np.arccos(costheta) 

175 if np.isnan(haRad0): 

176 if np.sign(costheta) > 0.0: 

177 haRad0 = 0.0 

178 else: 

179 haRad0 = np.pi 

180 

181 haRad = np.where(np.sin(azRad) >= 0.0, -1.0 * haRad0, haRad0) 

182 raObs = np.radians(last * 15.) - haRad 

183 

184 raRad, decRad = _icrsFromObserved(raObs, decObs, 

185 obs_metadata=obs, epoch=2000.0, 

186 includeRefraction=includeRefraction) 

187 

188 return raRad, decRad 

189 

190 

191def getRotSkyPos(ra, dec, obs, rotTel): 

192 """ 

193 @param [in] ra is the RA in degrees. Can be a numpy array or a single value. 

194 (In the International Celestial Reference System) 

195 

196 @param [in] dec is Dec in degrees. Can be a numpy array or a single value. 

197 (In the International Celestial Reference System) 

198 

199 @param [in] obs is an ObservationMetaData characterizing the telescope pointing 

200 and site. 

201 

202 @param [in] rotTel is rotTelPos in degrees 

203 (the angle of the camera rotator). Can be a numpy array or a single value. 

204 If a numpy array, should have the same length as ra and dec. In this case, 

205 each rotTel will be associated with the corresponding ra, dec pair. 

206 

207 @param [out] rotSkyPos in degrees 

208 

209 WARNING: As of 13 April 2015, this method does not agree with OpSim on 

210 the relationship between rotSkyPos and rotTelPos. This is due to a 

211 discrepancy between the time that OpSim uses as the MJD when calculating 

212 rotTelPos and the time that OpSim reports as being the actual expmjd 

213 of the exposure (rotTelPos is calculated at the beginning of the exposure; 

214 expmjd is reckoned at the middle of the exposure). 

215 """ 

216 

217 rotSky = _getRotSkyPos(np.radians(ra), np.radians(dec), 

218 obs, np.radians(rotTel)) 

219 

220 return np.degrees(rotSky) 

221 

222 

223def _getRotSkyPos(raRad, decRad, obs, rotTelRad): 

224 """ 

225 @param [in] raRad is the RA in radians. Can be a numpy array or a single value. 

226 (In the International Celestial Reference System) 

227 

228 @param [in] decRad is Dec in radians. Can be a numpy array or a single value. 

229 (In the International Celestial Reference System) 

230 

231 @param [in] obs is an ObservationMetaData characterizing the telescope pointing 

232 and site. 

233 

234 @param [in] rotTelRad is rotTelPos in radians 

235 (the angle of the camera rotator). Can be a numpy array or a single value. 

236 If a numpy array, should have the same length as raRad and decRad. In this case, 

237 each rotTelRad will be associated with the corresponding raRad, decRad pair. 

238 

239 @param [out] rotSkyPos in radians 

240 

241 WARNING: As of 13 April 2015, this method does not agree with OpSim on 

242 the relationship between rotSkyPos and rotTelPos. This is due to a 

243 discrepancy between the time that OpSim uses as the MJD when calculating 

244 rotTelPos and the time that OpSim reports as being the actual expmjd 

245 of the exposure (rotTelPos is calculated at the beginning of the exposure; 

246 expmjd is reckoned at the middle of the exposure). 

247 """ 

248 altRad, azRad, paRad = _altAzPaFromRaDec(raRad, decRad, obs) 

249 

250 return (rotTelRad - paRad) % (2. * np.pi) 

251 

252 

253def getRotTelPos(ra, dec, obs, rotSky): 

254 """ 

255 @param [in] ra is RA in degrees. Can be a numpy array or a single value. 

256 (In the International Celestial Reference System) 

257 

258 @param [in] dec is Dec in degrees. Can be a numpy array or a single value. 

259 (In the International Celestial Reference System) 

260 

261 @param [in] obs is an ObservationMetaData characterizing the telescope pointing 

262 and site. 

263 

264 @param [in] rotSky is rotSkyPos in degrees 

265 (the angle of the field of view relative to the South pole given a 

266 rotator angle). Can be a numpy array or a single value. If a numpy array, should 

267 have the same length as ra and dec. In this case, each rotSkyPos 

268 will be associated with the corresponding ra, dec pair. 

269 

270 @param [out] rotTelPos in degrees. 

271 

272 WARNING: As of 13 April 2015, this method does not agree with OpSim on 

273 the relationship between rotSkyPos and rotTelPos. This is due to a 

274 discrepancy between the time that OpSim uses as the MJD when calculating 

275 rotTelPos and the time that OpSim reports as being the actual expmjd 

276 of the exposure (rotTelPos is calculated at the beginning of the exposure; 

277 expmjd is reckoned at the middle of the exposure). 

278 """ 

279 rotTel = _getRotTelPos(np.radians(ra), np.radians(dec), 

280 obs, np.radians(rotSky)) 

281 

282 return np.degrees(rotTel) 

283 

284 

285def _getRotTelPos(raRad, decRad, obs, rotSkyRad): 

286 """ 

287 @param [in] raRad is RA in radians. Can be a numpy array or a single value. 

288 (In the International Celestial Reference System) 

289 

290 @param [in] decRad is Dec in radians. Can be a numpy array or a single value. 

291 (In the International Celestial Reference System) 

292 

293 @param [in] obs is an ObservationMetaData characterizing the telescope pointing 

294 and site. 

295 

296 @param [in] rotSkyRad is rotSkyPos in radians 

297 (the angle of the field of view relative to the South pole given a 

298 rotator angle). Can be a numpy array or a single value. If a numpy array, should 

299 have the same length as raRad and decRad. In this case, each rotSkyPos 

300 will be associated with the corresponding raRad, decRad pair. 

301 

302 @param [out] rotTelPos in radians. 

303 

304 WARNING: As of 13 April 2015, this method does not agree with OpSim on 

305 the relationship between rotSkyPos and rotTelPos. This is due to a 

306 discrepancy between the time that OpSim uses as the MJD when calculating 

307 rotTelPos and the time that OpSim reports as being the actual expmjd 

308 of the exposure (rotTelPos is calculated at the beginning of the exposure; 

309 expmjd is reckoned at the middle of the exposure). 

310 """ 

311 altRad, azRad, paRad = _altAzPaFromRaDec(raRad, decRad, obs) 

312 

313 return (rotSkyRad + paRad) % (2. * np.pi)