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

1import math 

2import numpy 

3import copy 

4import json 

5 

6__all__ = ["Target"] 

7 

8class Target(object): 

9 """Class for gathering information for a sky target. 

10 """ 

11 

12 def __init__(self, targetid=0, fieldid=0, band_filter="", 

13 ra_rad=0.0, dec_rad=0.0, ang_rad=0.0, 

14 num_exp=0, exp_times=[]): 

15 """Initialize the class. 

16 

17 Parameters 

18 ---------- 

19 targetid : int 

20 A unique identifier for the given target. 

21 fieldid : int 

22 The ID of the associated OpSim field for the target. 

23 band_filter : str 

24 The single character name of the associated band filter. 

25 ra_rad : float 

26 The right ascension (radians) of the target. 

27 dec_rad : float 

28 The declination (radians) of the target. 

29 ang_rad : float 

30 The sky angle (radians) of the target. 

31 num_exp : int 

32 The number of requested exposures for the target. 

33 exp_times : list[float] 

34 The set of exposure times for the target. Needs to length 

35 of num_exp. 

36 """ 

37 self.targetid = targetid 

38 self.fieldid = fieldid 

39 self.filter = band_filter 

40 self.ra_rad = ra_rad 

41 self.dec_rad = dec_rad 

42 self.ang_rad = ang_rad 

43 self.num_exp = num_exp 

44 self.exp_times = list(exp_times) 

45 self._exp_time = None # total exposure time 

46 

47 # conditions 

48 self.time = 0.0 

49 self.airmass = 0.0 

50 self.sky_brightness = 0.0 

51 self.cloud = 0.0 

52 self.seeing = 0.0 

53 

54 # computed at proposal 

55 self.propid = 0 

56 self.need = 0.0 

57 self.bonus = 0.0 

58 self.value = 0.0 

59 # internal proposal book-keeping 

60 self.goal = 0 

61 self.visits = 0 

62 self.progress = 0.0 

63 

64 self.sequenceid = 0 

65 self.subsequencename = "" 

66 self.groupid = 0 

67 self.groupix = 0 

68 self.is_deep_drilling = False 

69 self.is_dd_firstvisit = False 

70 self.remaining_dd_visits = 0 

71 self.dd_exposures = 0 

72 self.dd_filterchanges = 0 

73 self.dd_exptime = 0.0 

74 

75 # computed at driver 

76 self.alt_rad = 0.0 

77 self.az_rad = 0.0 

78 self.rot_rad = 0.0 

79 self.telalt_rad = 0.0 

80 self.telaz_rad = 0.0 

81 self.telrot_rad = 0.0 

82 self.propboost = 1.0 

83 self.slewtime = 0.0 

84 self.cost = 0.0 

85 self.rank = 0.0 

86 

87 # assembled at driver 

88 self.num_props = 0 

89 self.propid_list = [] 

90 self.need_list = [] 

91 self.bonus_list = [] 

92 self.value_list = [] 

93 self.propboost_list = [] 

94 self.sequenceid_list = [] 

95 self.subsequencename_list = [] 

96 self.groupid_list = [] 

97 self.groupix_list = [] 

98 self.is_deep_drilling_list = [] 

99 self.is_dd_firstvisit_list = [] 

100 self.remaining_dd_visits_list = [] 

101 self.dd_exposures_list = [] 

102 self.dd_filterchanges_list = [] 

103 self.dd_exptime_list = [] 

104 

105 # stamped at observation 

106 self.last_visit_time = 0.0 

107 

108 self.note = '' 

109 

110 def __str__(self): 

111 """str: The string representation of the instance.""" 

112 return ("targetid=%d field=%d filter=%s exp_times=%s ra=%.3f " 

113 "dec=%.3f ang=%.3f alt=%.3f az=%.3f rot=%.3f " 

114 "telalt=%.3f telaz=%.3f telrot=%.3f " 

115 "time=%.1f airmass=%.3f brightness=%.3f " 

116 "cloud=%.2f seeing=%.2f " 

117 "visits=%i progress=%.2f%% " 

118 "seqid=%i ssname=%s groupid=%i groupix=%i " 

119 "firstdd=%s ddvisits=%i " 

120 "need=%.3f bonus=%.3f value=%.3f propboost=%.3f " 

121 "propid=%s need=%s bonus=%s value=%s propboost=%s " 

122 "slewtime=%.3f cost=%.3f rank=%.3f note=%s" % 

123 (self.targetid, self.fieldid, self.filter, 

124 str(self.exp_times), 

125 self.ra, self.dec, self.ang, 

126 self.alt, self.az, self.rot, 

127 self.telalt, self.telaz, self.telrot, 

128 self.time, self.airmass, self.sky_brightness, 

129 self.cloud, self.seeing, 

130 self.visits, 100 * self.progress, 

131 self.sequenceid, self.subsequencename, 

132 self.groupid, self.groupix, 

133 self.is_dd_firstvisit, self.remaining_dd_visits, 

134 self.need, self.bonus, self.value, self.propboost, 

135 self.propid_list, numpy.round(self.need_list, 3), numpy.round(self.bonus_list, 3), 

136 numpy.round(self.value_list, 3), numpy.round(self.propboost_list, 3), 

137 self.slewtime, self.cost, self.rank, self.note)) 

138 

139 @property 

140 def alt(self): 

141 """float: The altitude (degrees) of the target.""" 

142 return math.degrees(self.alt_rad) 

143 

144 @alt.setter 

145 def alt(self, alt): 

146 """ 

147 Set altitude given in degrees 

148 

149 Parameters 

150 ---------- 

151 alt: float (degrees) 

152 """ 

153 self.alt_rad = math.radians(alt) 

154 

155 @property 

156 def ang(self): 

157 """float: The sky angle (degrees) of the target.""" 

158 return math.degrees(self.ang_rad) 

159 

160 @ang.setter 

161 def ang(self, ang): 

162 """ 

163 Set camera rotation angle given in degrees 

164 

165 Parameters 

166 ---------- 

167 ang: float (degrees) 

168 """ 

169 self.ang_rad = math.radians(ang) 

170 

171 @property 

172 def az(self): 

173 """float: The azimuth (degrees) of the target.""" 

174 return math.degrees(self.az_rad) 

175 

176 @az.setter 

177 def az(self, az): 

178 """ 

179 Set camera rotation angle given in degrees 

180 

181 Parameters 

182 ---------- 

183 az: float (degrees) 

184 """ 

185 self.az_rad = math.radians(az) 

186 

187 @property 

188 def dec(self): 

189 """float: The declination (degrees) of the target.""" 

190 return math.degrees(self.dec_rad) 

191 

192 @dec.setter 

193 def dec(self, dec): 

194 """ 

195 Set declination given in degrees 

196 

197 Parameters 

198 ---------- 

199 dec: float (degrees) 

200 """ 

201 self.dec_rad = math.radians(dec) 

202 

203 @property 

204 def ra(self): 

205 """float: The right ascension (degrees) of the target.""" 

206 return math.degrees(self.ra_rad) 

207 

208 @ra.setter 

209 def ra(self, ra): 

210 """ 

211 Set right ascension given in degrees 

212 

213 Parameters 

214 ---------- 

215 ra: float (degrees) 

216 """ 

217 self.ra_rad = math.radians(ra) 

218 

219 @property 

220 def rot(self): 

221 """float: The rotator angle (degrees) of the target.""" 

222 return math.degrees(self.rot_rad) 

223 

224 @rot.setter 

225 def rot(self, rot): 

226 """ 

227 Set camera rotation angle given in degrees 

228 

229 Parameters 

230 ---------- 

231 rot: float (degrees) 

232 """ 

233 self.rot_rad = math.radians(rot) 

234 

235 @property 

236 def telalt(self): 

237 """float: The telescope altitude (degrees) for the target.""" 

238 return math.degrees(self.telalt_rad) 

239 

240 @telalt.setter 

241 def telalt(self, telalt): 

242 """ 

243 Set camera rotation angle given in degrees 

244 

245 Parameters 

246 ---------- 

247 telalt: float (degrees) 

248 """ 

249 self.telalt_rad = math.radians(telalt) 

250 

251 @property 

252 def telaz(self): 

253 """float: The telescope azimuth (degrees) for the target.""" 

254 return math.degrees(self.telaz_rad) 

255 

256 @telaz.setter 

257 def telaz(self, telaz): 

258 """ 

259 Set camera rotation angle given in degrees 

260 

261 Parameters 

262 ---------- 

263 telaz: float (degrees) 

264 """ 

265 self.telaz_rad = math.radians(telaz) 

266 

267 @property 

268 def telrot(self): 

269 """float: The telescope rotator angle (degrees) for the target.""" 

270 return math.degrees(self.telrot_rad) 

271 

272 @telrot.setter 

273 def telrot(self, telrot): 

274 """ 

275 Set camera rotation angle given in degrees 

276 

277 Parameters 

278 ---------- 

279 telrot: float (degrees) 

280 """ 

281 self.telrot_rad = math.radians(telrot) 

282 

283 @property 

284 def exp_time(self): 

285 """ 

286 

287 Returns 

288 ------- 

289 exp_time: float: The total exposure time in seconds. 

290 """ 

291 if self._exp_time is None: 

292 return sum(self.exp_times) 

293 else: 

294 self._exp_time 

295 

296 @exp_time.setter 

297 def exp_time(self, exp_time): 

298 """ 

299 

300 Parameters 

301 ---------- 

302 exp_time: float: The total exposure time in seconds. 

303 

304 Returns 

305 ------- 

306 None 

307 """ 

308 self._exp_time = exp_time 

309 

310 def copy_driver_state(self, target): 

311 """Copy driver state from another target. 

312 

313 Parameters 

314 ---------- 

315 target : :class:`.Target` 

316 An instance of a target from which to get the driver state 

317 information. 

318 """ 

319 self.alt_rad = target.alt_rad 

320 self.az_rad = target.az_rad 

321 self.rot_rad = target.rot_rad 

322 self.telalt_rad = target.telalt_rad 

323 self.telaz_rad = target.telaz_rad 

324 self.telrot_rad = target.telrot_rad 

325 self.ang_rad = target.ang_rad 

326 

327 def get_copy(self): 

328 """:class:`.Target`: Get copy of the instance.""" 

329 newtarget = Target() 

330 newtarget.targetid = self.targetid 

331 newtarget.fieldid = self.fieldid 

332 newtarget.filter = self.filter 

333 newtarget.ra_rad = self.ra_rad 

334 newtarget.dec_rad = self.dec_rad 

335 newtarget.ang_rad = self.ang_rad 

336 newtarget.num_exp = self.num_exp 

337 newtarget.exp_times = list(self.exp_times) 

338 newtarget.time = self.time 

339 newtarget.airmass = self.airmass 

340 newtarget.sky_brightness = self.sky_brightness 

341 newtarget.cloud = self.cloud 

342 newtarget.seeing = self.seeing 

343 newtarget.propid = self.propid 

344 newtarget.need = self.need 

345 newtarget.bonus = self.bonus 

346 newtarget.value = self.value 

347 newtarget.goal = self.goal 

348 newtarget.visits = self.visits 

349 newtarget.progress = self.progress 

350 

351 newtarget.sequenceid = self.sequenceid 

352 newtarget.subsequencename = self.subsequencename 

353 newtarget.groupid = self.groupid 

354 newtarget.groupix = self.groupix 

355 newtarget.is_deep_drilling = self.is_deep_drilling 

356 newtarget.is_dd_firstvisit = self.is_dd_firstvisit 

357 newtarget.remaining_dd_visits = self.remaining_dd_visits 

358 newtarget.dd_exposures = self.dd_exposures 

359 newtarget.dd_filterchanges = self.dd_filterchanges 

360 newtarget.dd_exptime = self.dd_exptime 

361 

362 newtarget.alt_rad = self.alt_rad 

363 newtarget.az_rad = self.az_rad 

364 newtarget.rot_rad = self.rot_rad 

365 newtarget.telalt_rad = self.telalt_rad 

366 newtarget.telaz_rad = self.telaz_rad 

367 newtarget.telrot_rad = self.telrot_rad 

368 newtarget.propboost = self.propboost 

369 newtarget.slewtime = self.slewtime 

370 newtarget.cost = self.cost 

371 newtarget.rank = self.rank 

372 newtarget.num_props = self.num_props 

373 newtarget.propid_list = list(self.propid_list) 

374 newtarget.need_list = list(self.need_list) 

375 newtarget.bonus_list = list(self.bonus_list) 

376 newtarget.value_list = list(self.value_list) 

377 newtarget.propboost_list = list(self.propboost_list) 

378 newtarget.sequenceid_list = list(self.sequenceid_list) 

379 newtarget.subsequencename_list = list(self.subsequencename_list) 

380 newtarget.groupid_list = list(self.groupid_list) 

381 newtarget.groupix_list = list(self.groupix_list) 

382 newtarget.is_deep_drilling_list = list(self.is_deep_drilling_list) 

383 newtarget.is_dd_firstvisit_list = list(self.is_dd_firstvisit_list) 

384 newtarget.remaining_dd_visits_list = list(self.remaining_dd_visits_list) 

385 newtarget.dd_exposures_list = list(self.dd_exposures_list) 

386 newtarget.dd_filterchanges_list = list(self.dd_filterchanges_list) 

387 newtarget.dd_exptime_list = list(self.dd_exptime_list) 

388 

389 newtarget.note = self.note 

390 

391 return newtarget 

392 

393 def to_json(self): 

394 """ 

395 Returns a json serialization of variables in this object 

396 """ 

397 return json.dumps(vars(self)) 

398 

399 def from_json(self, jsonstr): 

400 """ 

401 alternate __init__ method that takes a json representation as the only argument 

402 """ 

403 mandatory_fields = ["targetid", "fieldid", "filter", "ra_rad", "dec_rad", "ang_rad", "num_exp", "exp_times"] 

404 

405 jsondict = json.loads(jsonstr) 

406 for f in mandatory_fields: 

407 if f not in jsondict.keys(): 

408 raise KeyError("json blob passed to Target()'s json constructor is missing required attribute: " + f) 

409 

410 

411 for k in jsondict: 

412 setattr(self, k, jsondict[k]) 

413 

414 @classmethod 

415 def from_topic(cls, topic): 

416 """Alternate initializer. 

417 

418 Parameters 

419 ---------- 

420 topic : SALPY_scheduler.targetC 

421 The target topic instance. 

422 

423 Returns 

424 ------- 

425 :class:`.Target` 

426 """ 

427 return cls(topic.targetId, -1, topic.filter, math.radians(topic.ra), 

428 math.radians(topic.decl), math.radians(topic.skyAngle), topic.numExposures, 

429 topic.exposureTimes)