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

1from builtins import zip 

2import numpy as np 

3from .baseStacker import BaseStacker 

4from .coordStackers import raDec2AltAz 

5 

6__all__ = ['findTelescopes', 'NFollowStacker'] 

7 

8 

9def findTelescopes(minSize=3.): 

10 """Finds telescopes larger than minSize, from list of large telescopes based on 

11 http://astro.nineplanets.org/bigeyes.html. 

12 

13 Returns 

14 ------- 

15 np.recarray 

16 Array of large telescopes with columns [aperture, name, lat, lon]. 

17 """ 

18 # Aperture Name Location http://astro.nineplanets.org/bigeyes.html 

19 telescopes = [ 

20 [10.4, 'Gran Canarias', 'La Palma'], 

21 [10.0, 'Keck', 'Mauna Kea'], 

22 [10.0, 'Keck II', 'Mauna Kea'], 

23 [9.2, 'SALT', 'South African Astronomical Observatory'], 

24 [9.2, 'Hobby-Eberly', 'Mt. Fowlkes'], 

25 [8.4, 'Large Binocular Telescope', 'Mt. Graham'], 

26 [8.3, 'Subaru', 'Mauna Kea'], 

27 [8.2, 'Antu', 'Cerro Paranal'], 

28 [8.2, 'Kueyen', 'Cerro Paranal'], 

29 [8.2, 'Melipal', 'Cerro Paranal'], 

30 [8.2, 'Yepun', 'Cerro Paranal'], 

31 [8.1, 'Gemini North', 'Mauna Kea'], 

32 [8.1, 'Gemini South', 'Cerro Pachon'], 

33 [6.5, 'MMT', 'Mt. Hopkins'], 

34 [6.5, 'Walter Baade', 'La Serena'], 

35 [6.5, 'Landon Clay', 'La Serena'], 

36 [6.0, 'Bolshoi Teleskop Azimutalnyi', 'Nizhny Arkhyz'], 

37 [6.0, 'LZT', 'British Columbia'], 

38 [5.0, 'Hale', 'Palomar Mountain'], 

39 [4.3, 'Dicovery Channel', 'Lowell Observatory'], 

40 [4.2, 'William Herschel', 'La Palma'], 

41 [4.2, 'SOAR', 'Cerro Pachon'], 

42 [4.2, 'LAMOST', 'Xinglong Station'], 

43 [4.0, 'Victor Blanco', 'Cerro Tololo'], 

44 [4.0, 'Vista', 'Cerro Paranal'], 

45 [3.9, 'Anglo-Australian', 'Coonabarabran'], 

46 [3.8, 'Mayall', 'Kitt Peak'], 

47 [3.8, 'UKIRT', 'Mauna Kea'], 

48 [3.6, '360', 'Cerro La Silla'], 

49 [3.6, 'Canada-France-Hawaii', 'Mauna Kea'], 

50 [3.6, 'Telescopio Nazionale Galileo', 'La Palma'], 

51 [3.5, 'MPI-CAHA', 'Calar Alto'], 

52 [3.5, 'New Technology', 'Cerro La Silla'], 

53 [3.5, 'ARC', 'Apache Point'], 

54 [3.5, 'WIYN', 'Kitt Peak'], 

55 [3.0, 'Shane', 'Mount Hamilton'], 

56 [3.0, 'NASA IRTF', 'Mauna Kea'], 

57 ] 

58 

59 scopes = np.zeros(len(telescopes), dtype = list(zip( 

60 ['aperture', 'name', 'lat', 'lon'], [float, (np.str_, 38), float, float]))) 

61 

62 # name, lat (S negative), lon (W negative) 

63 observatories = [ 

64 ['Cerro Paranal', -24, 38, -70, 24], 

65 ['Nizhny Arkhyz', 43, 39, 41, 26], 

66 ['Cerro La Silla', -29, 15, -70, 44], 

67 ['Lowell Observatory', 35, 12, -111, 40], 

68 ['Apache Point', 32, 47, -105, 49], 

69 ['Mount Hamilton', 37, 21, -121, 38], 

70 ['South African Astronomical Observatory', -32, 23, 20, 49], 

71 ['Cerro Pachon', -30, 20, -70, 59], 

72 ['Coonabarabran', -31, 17, 149, 0o4], 

73 ['Mt. Fowlkes', 30, 40, -104, 1], 

74 ['La Palma', 28, 46, -17, 53], 

75 ['Mt. Graham', 32, 42, -109, 53], 

76 ['Calar Alto', 37, 13, -2, 33], 

77 ['British Columbia', 49, 17, -122, 34], 

78 ['Kitt Peak', 31, 57, -111, 37], 

79 ['La Serena', -30, 10, -70, 48], 

80 ['Palomar Mountain', 33, 21, -116, 52], 

81 ['Xinglong Station', 40, 23, 105, 50], 

82 ['Mt. Hopkins', 31, 41, -110, 53], 

83 ['Cerro Tololo', -30, 10, -70, 49], 

84 ['Mauna Kea', 19, 50, -155, 28] 

85 ] 

86 

87 # Make a nice little dict to look up the observatory positions 

88 obs = {} 

89 for i, ob in enumerate(observatories): 

90 obs[ob[0]] = [(np.abs(ob[1])+ob[2]/60.)*(ob[1]/np.abs(ob[1])), 

91 (np.abs(ob[3])+ob[4]/60.)*(ob[3]/np.abs(ob[3]))] 

92 

93 for i, telescope in enumerate(telescopes): 

94 scopes['aperture'][i] = telescope[0] 

95 scopes['name'][i] = telescope[1] 

96 scopes['lat'][i], scopes['lon'][i] = obs[telescope[2]] 

97 

98 scopes = scopes[np.where(scopes['aperture'] >= minSize)] 

99 return scopes 

100 

101 

102class NFollowStacker(BaseStacker): 

103 """Add the number of telescopes ('nObservatories') that could follow up any visit 

104 at (any of the) times in timeStep, specifying the minimum telescope size (in meters) and airmass limit. 

105 

106 Parameters 

107 ---------- 

108 minSize: float, opt 

109 The minimum telescope aperture to use, in meters. Default 3.0. 

110 airmassLimit: float, opt 

111 The maximum airmass allowable at the follow-up observatory. Default 2.5. 

112 timeSteps: np.array or list of floats, opt 

113 The timesteps to check for followup opportunities, in hours. Default is np.arange(0.5, 12., 3.0). 

114 mjdCol: str, opt 

115 The exposure MJD column name. Default 'observationStartMJD'. 

116 raCol: str, opt 

117 The RA column name. Default 'fieldRA'. 

118 decCol: str, opt 

119 The Dec column name. Default 'fieldDec'. 

120 raDecDeg: bool, opt 

121 Flag whether RA/Dec are in degrees (True) or radians (False). 

122 """ 

123 colsAdded = ['nObservatories'] 

124 

125 def __init__(self, minSize=3.0, airmassLimit=2.5, timeSteps=np.arange(0.5, 12., 3.0), 

126 mjdCol='observationStartMJD', raCol='fieldRA', decCol='fieldDec', degrees=True): 

127 self.mjdCol = mjdCol 

128 self.raCol = raCol 

129 self.decCol = decCol 

130 self.degrees = degrees 

131 self.colsAddedDtypes = [int] 

132 self.colsReq = [self.mjdCol, self.raCol, self.decCol] 

133 self.units = ['#'] 

134 self.airmassLimit = airmassLimit 

135 self.timeSteps = timeSteps 

136 self.telescopes = findTelescopes(minSize = minSize) 

137 

138 def _run(self, simData, cols_present=False): 

139 if cols_present: 

140 return simData 

141 simData['nObservatories'] = 0 

142 if self.degrees: 

143 ra = np.radians(simData[self.raCol]) 

144 dec = np.radians(simData[self.decCol]) 

145 else: 

146 ra = simData[self.raCol] 

147 dec = simData[self.decCol] 

148 for obs in self.telescopes: 

149 obsGotIt = np.zeros(len(simData[self.raCol]), int) 

150 obsLon = np.radians(obs['lon']) 

151 obsLat = np.radians(obs['lat']) 

152 for step in self.timeSteps: 

153 alt, az = raDec2AltAz(ra, dec, obsLon, obsLat, 

154 simData[self.mjdCol] + step / 24.0, 

155 altonly=True) 

156 airmass = 1. / (np.cos(np.pi / 2. - alt)) 

157 followed = np.where((airmass <= self.airmassLimit) & (airmass >= 1.)) 

158 # If the observatory got an observation, save this into obsGotIt. 

159 # obsGotIt will be 1 if ANY of the times got an observation. 

160 obsGotIt[followed] = 1 

161 # If an observatory got an observation, count it in nObservatories. 

162 simData['nObservatories'] += obsGotIt 

163 return simData