Package astLib :: Module astCoords
[hide private]
[frames] | no frames]

Source Code for Module astLib.astCoords

  1  # -*- coding: utf-8 -*- 
  2  """module for coordinate manipulation (conversions, calculations etc.) 
  3   
  4  (c) 2007-2011 Matt Hilton  
  5   
  6  U{http://astlib.sourceforge.net} 
  7   
  8  """ 
  9   
 10  import sys 
 11  import math 
 12  import numpy 
 13  from PyWCSTools import wcscon 
 14   
 15  #--------------------------------------------------------------------------------------------------- 
16 -def hms2decimal(RAString, delimiter):
17 """Converts a delimited string of Hours:Minutes:Seconds format into decimal degrees. 18 19 @type RAString: string 20 @param RAString: coordinate string in H:M:S format 21 @type delimiter: string 22 @param delimiter: delimiter character in RAString 23 @rtype: float 24 @return: coordinate in decimal degrees 25 26 """ 27 # is it in HH:MM:SS format? 28 if delimiter=="": 29 RABits=str(RAString).split() 30 else: 31 RABits=str(RAString).split(delimiter) 32 if len(RABits)>1: 33 RAHDecimal=float(RABits[0]) 34 if len(RABits)>1: 35 RAHDecimal=RAHDecimal+(float(RABits[1])/60.0) 36 if len(RABits)>2: 37 RAHDecimal=RAHDecimal+(float(RABits[2])/3600.0) 38 RADeg=(RAHDecimal/24.0)*360.0 39 else: 40 RADeg=float(RAString) 41 42 return RADeg
43 44 #---------------------------------------------------------------------------------------------------
45 -def dms2decimal(decString, delimiter):
46 """Converts a delimited string of Degrees:Minutes:Seconds format into decimal degrees. 47 48 @type decString: string 49 @param decString: coordinate string in D:M:S format 50 @type delimiter: string 51 @param delimiter: delimiter character in decString 52 @rtype: float 53 @return: coordinate in decimal degrees 54 55 """ 56 # is it in DD:MM:SS format? 57 if delimiter=="": 58 decBits=str(decString).split() 59 else: 60 decBits=str(decString).split(delimiter) 61 if len(decBits)>1: 62 decDeg=float(decBits[0]) 63 if decBits[0].find("-")!=-1: 64 if len(decBits)>1: 65 decDeg=decDeg-(float(decBits[1])/60.0) 66 if len(decBits)>2: 67 decDeg=decDeg-(float(decBits[2])/3600.0) 68 else: 69 if len(decBits)>1: 70 decDeg=decDeg+(float(decBits[1])/60.0) 71 if len(decBits)>2: 72 decDeg=decDeg+(float(decBits[2])/3600.0) 73 else: 74 decDeg=float(decString) 75 76 return decDeg
77 78 #---------------------------------------------------------------------------------------------------
79 -def decimal2hms(RADeg, delimiter):
80 """Converts decimal degrees to string in Hours:Minutes:Seconds format with user specified 81 delimiter. 82 83 @type RADeg: float 84 @param RADeg: coordinate in decimal degrees 85 @type delimiter: string 86 @param delimiter: delimiter character in returned string 87 @rtype: string 88 @return: coordinate string in H:M:S format 89 90 91 """ 92 hours=(RADeg/360.0)*24 93 if hours<10 and hours>=1: 94 sHours="0"+str(hours)[0] 95 elif hours>=10: 96 sHours=str(hours)[:2] 97 elif hours<1: 98 sHours="00" 99 100 if str(hours).find(".")==-1: 101 mins=float(hours)*60.0 102 else: 103 mins=float(str(hours)[str(hours).index("."):])*60.0 104 if mins<10 and mins>=1: 105 sMins="0"+str(mins)[:1] 106 elif mins>=10: 107 sMins=str(mins)[:2] 108 elif mins<1: 109 sMins="00" 110 111 secs=(hours-(float(sHours)+float(sMins)/60.0))*3600.0 112 if secs<10 and secs>0.001: 113 sSecs="0"+str(secs)[:str(secs).find(".")+4] 114 elif secs<0.0001: 115 sSecs="00.001" 116 else: 117 sSecs=str(secs)[:str(secs).find(".")+4] 118 if len(sSecs)<5: 119 sSecs=sSecs+"00" # So all to 3dp 120 121 if float(sSecs) == 60.000: 122 sSecs="00.00" 123 sMins=str(int(sMins)+1) 124 if int(sMins) == 60: 125 sMins="00" 126 sDeg=str(int(sDeg)+1) 127 128 return sHours+delimiter+sMins+delimiter+sSecs
129 130 #---------------------------------------------------------------------------------------------------
131 -def decimal2dms(decDeg, delimiter):
132 """Converts decimal degrees to string in Degrees:Minutes:Seconds format with user specified 133 delimiter. 134 135 @type decDeg: float 136 @param decDeg: coordinate in decimal degrees 137 @type delimiter: string 138 @param delimiter: delimiter character in returned string 139 @rtype: string 140 @return: coordinate string in D:M:S format 141 142 """ 143 # Positive 144 if decDeg>0: 145 if decDeg<10 and decDeg>=1: 146 sDeg="0"+str(decDeg)[0] 147 elif decDeg>=10: 148 sDeg=str(decDeg)[:2] 149 elif decDeg<1: 150 sDeg="00" 151 152 if str(decDeg).find(".")==-1: 153 mins=float(decDeg)*60.0 154 else: 155 mins=float(str(decDeg)[str(decDeg).index("."):])*60 156 if mins<10 and mins>=1: 157 sMins="0"+str(mins)[:1] 158 elif mins>=10: 159 sMins=str(mins)[:2] 160 elif mins<1: 161 sMins="00" 162 163 secs=(decDeg-(float(sDeg)+float(sMins)/60.0))*3600.0 164 if secs<10 and secs>0: 165 sSecs="0"+str(secs)[:str(secs).find(".")+3] 166 elif secs<0.001: 167 sSecs="00.00" 168 else: 169 sSecs=str(secs)[:str(secs).find(".")+3] 170 if len(sSecs)<5: 171 sSecs=sSecs+"0" # So all to 2dp 172 173 if float(sSecs) == 60.00: 174 sSecs="00.00" 175 sMins=str(int(sMins)+1) 176 if int(sMins) == 60: 177 sMins="00" 178 sDeg=str(int(sDeg)+1) 179 180 return "+"+sDeg+delimiter+sMins+delimiter+sSecs 181 182 else: 183 if decDeg>-10 and decDeg<=-1: 184 sDeg="-0"+str(decDeg)[1] 185 elif decDeg<=-10: 186 sDeg=str(decDeg)[:3] 187 elif decDeg>-1: 188 sDeg="-00" 189 190 if str(decDeg).find(".")==-1: 191 mins=float(decDeg)*-60.0 192 else: 193 mins=float(str(decDeg)[str(decDeg).index("."):])*60 194 if mins<10 and mins>=1: 195 sMins="0"+str(mins)[:1] 196 elif mins>=10: 197 sMins=str(mins)[:2] 198 elif mins<1: 199 sMins="00" 200 201 secs=(decDeg-(float(sDeg)-float(sMins)/60.0))*3600.0 202 if secs>-10 and secs<0: 203 sSecs="0"+str(secs)[1:str(secs).find(".")+3] # so don't get minus sign 204 elif secs>-0.001: 205 sSecs="00.00" 206 else: 207 sSecs=str(secs)[1:str(secs).find(".")+3] 208 if len(sSecs)<5: 209 sSecs=sSecs+"0" # So all to 2dp 210 211 if float(sSecs) == 60.00: 212 sSecs="00.00" 213 sMins=str(int(sMins)+1) 214 if int(sMins) == 60: 215 sMins="00" 216 sDeg=str(int(sDeg)-1) 217 218 return sDeg+delimiter+sMins+delimiter+sSecs
219 220 #---------------------------------------------------------------------------------------------------
221 -def calcAngSepDeg(RADeg1, decDeg1, RADeg2, decDeg2):
222 """Calculates the angular separation of two positions on the sky (specified in decimal 223 degrees) in decimal degrees, assuming a tangent plane projection (so separation has to be 224 <90 deg). Note that RADeg2, decDeg2 can be numpy arrays. 225 226 @type RADeg1: float 227 @param RADeg1: R.A. in decimal degrees for position 1 228 @type decDeg1: float 229 @param decDeg1: dec. in decimal degrees for position 1 230 @type RADeg2: float or numpy array 231 @param RADeg2: R.A. in decimal degrees for position 2 232 @type decDeg2: float or numpy array 233 @param decDeg2: dec. in decimal degrees for position 2 234 @rtype: float or numpy array, depending upon type of RADeg2, decDeg2 235 @return: angular separation in decimal degrees 236 237 """ 238 cRA=numpy.radians(RADeg1) 239 cDec=numpy.radians(decDeg1) 240 241 gRA=numpy.radians(RADeg2) 242 gDec=numpy.radians(decDeg2) 243 244 dRA=cRA-gRA 245 dDec=gDec-cDec 246 cosC=(numpy.sin(gDec)*numpy.sin(cDec))+(numpy.cos(gDec)*numpy.cos(cDec)*numpy.cos(gRA-cRA)) 247 x=(numpy.cos(cDec)*numpy.sin(gRA-cRA))/cosC 248 y=((numpy.cos(gDec)*numpy.sin(cDec))-(numpy.sin(gDec)*numpy.cos(cDec)*numpy.cos(gRA-cRA)))/cosC 249 r=numpy.degrees(numpy.sqrt(x*x+y*y)) 250 251 return r
252 253 #---------------------------------------------------------------------------------------------------
254 -def convertCoords(inputSystem, outputSystem, coordX, coordY, epoch):
255 """Converts specified coordinates (given in decimal degrees) between J2000, B1950, and 256 Galactic. 257 258 @type inputSystem: string 259 @param inputSystem: system of the input coordinates (either "J2000", "B1950" or "GALACTIC") 260 @type outputSystem: string 261 @param outputSystem: system of the returned coordinates (either "J2000", "B1950" or 262 "GALACTIC") 263 @type coordX: float 264 @param coordX: longitude coordinate in decimal degrees, e.g. R. A. 265 @type coordY: float 266 @param coordY: latitude coordinate in decimal degrees, e.g. dec. 267 @type epoch: float 268 @param epoch: epoch of the input coordinates 269 @rtype: list 270 @return: coordinates in decimal degrees in requested output system 271 272 """ 273 274 if inputSystem=="J2000" or inputSystem=="B1950" or inputSystem=="GALACTIC": 275 if outputSystem=="J2000" or outputSystem=="B1950" or outputSystem=="GALACTIC": 276 277 outCoords=wcscon.wcscon(wcscon.wcscsys(inputSystem), 278 wcscon.wcscsys(outputSystem), 0, 0, coordX, coordY, epoch) 279 280 return outCoords 281 282 raise Exception, "inputSystem and outputSystem must be 'J2000', 'B1950' or 'GALACTIC'" 283 284 #---------------------------------------------------------------------------------------------------
285 -def calcRADecSearchBox(RADeg, decDeg, radiusSkyDeg):
286 """Calculates minimum and maximum RA, dec coords needed to define a box enclosing a circle of 287 radius radiusSkyDeg around the given RADeg, decDeg coordinates. Useful for freeform queries 288 of e.g. SDSS, UKIDSS etc.. Uses L{calcAngSepDeg}, so has the same limitations. 289 290 @type RADeg: float 291 @param RADeg: RA coordinate of centre of search region 292 @type decDeg: float 293 @param decDeg: dec coordinate of centre of search region 294 @type radiusSkyDeg: float 295 @param radiusSkyDeg: radius in degrees on the sky used to define search region 296 @rtype: list 297 @return: [RAMin, RAMax, decMin, decMax] - coordinates in decimal degrees defining search box 298 299 """ 300 301 tolerance=1e-5 # in degrees on sky 302 targetHalfSizeSkyDeg=radiusSkyDeg 303 funcCalls=["calcAngSepDeg(RADeg, decDeg, guess, decDeg)", 304 "calcAngSepDeg(RADeg, decDeg, guess, decDeg)", 305 "calcAngSepDeg(RADeg, decDeg, RADeg, guess)", 306 "calcAngSepDeg(RADeg, decDeg, RADeg, guess)"] 307 coords=[RADeg, RADeg, decDeg, decDeg] 308 signs=[1.0, -1.0, 1.0, -1.0] 309 results=[] 310 for f, c, sign in zip(funcCalls, coords, signs): 311 # Initial guess range 312 maxGuess=sign*targetHalfSizeSkyDeg*2.0 313 minGuess=sign*targetHalfSizeSkyDeg/10.0 314 guessStep=(maxGuess-minGuess)/10.0 315 guesses=numpy.arange(minGuess+c, maxGuess+c, guessStep) 316 for i in range(20): 317 minSizeDiff=1e6 318 bestGuess=None 319 for guess in guesses: 320 sizeDiff=abs(eval(f)-targetHalfSizeSkyDeg) 321 if sizeDiff < minSizeDiff: 322 minSizeDiff=sizeDiff 323 bestGuess=guess 324 if minSizeDiff < tolerance: 325 break 326 else: 327 guessRange=abs((maxGuess-minGuess)) 328 maxGuess=bestGuess+guessRange/4.0 329 minGuess=bestGuess-guessRange/4.0 330 guessStep=(maxGuess-minGuess)/10.0 331 guesses=numpy.arange(minGuess, maxGuess, guessStep) 332 results.append(bestGuess) 333 RAMax=results[0] 334 RAMin=results[1] 335 decMax=results[2] 336 decMin=results[3] 337 338 return [RAMin, RAMax, decMin, decMax]
339