def set_star(self, agasc_id=None, slot=None): """ Set self.ra and dec from either agasc_id *or* slot. This assumes use of star in default agasc miniagasc (no 1.4 or 1.5 or very faint stars) Lookup by "slot" relies on database of starcheck catalogs. This also sets self.agasc_id. """ if agasc_id is not None: star = agasc.get_star(agasc_id, date=self.start) elif slot is not None: sc = mica.starcheck.get_starcheck_catalog_at_date(self.start) stars = sc['cat'][(sc['cat']['slot'] == slot) & ( (sc['cat']['type'] == 'GUI') | (sc['cat']['type'] == 'BOT'))] if not len(stars): raise ValueError( "No GUI or BOT in slot {} at time {} in dwell".format( slot, DateTime(self.start).date)) star = agasc.get_star(stars[0]['id'], date=self.start) else: raise ValueError("Need to supply agasc_id or slot to look up star") # Could also add logic to infer star from loose position and magnitude self.agasc_id = star['AGASC_ID'] self.ra = star['RA_PMCORR'] self.dec = star['DEC_PMCORR']
def test_agasc_1p7(): """ Ensure that AGASC 1.7 is being used. """ # Updated with APASS info star = agasc.get_star(688522864) assert star['RSV3'] == 1 assert star['RSV2'] == 11944 # NOT updated with APASS info star = agasc.get_star(611193056) assert star['RSV3'] == 0 assert star['RSV2'] == -9999
def get_star(id): try: agasc_info = agasc.get_star(id) agasc_list = [(key, agasc_info[key]) for key in agasc_info.dtype.names] return agasc_list except: return []
def _deltas_vs_obc_quat(vals, times, catalog): # Misalign is the identity matrix because this is the OBC quaternion aca_misalign = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) q_att = Quat(q=np.array([ vals['AOATTQT1'], vals['AOATTQT2'], vals['AOATTQT3'], vals['AOATTQT4'] ]).transpose()) Ts = q_att.transform acqs = catalog R2A = 206264.81 dy = {} dz = {} yag = {} zag = {} star_info = {} for slot in range(0, 8): if slot not in acqs['slot']: continue agasc_id = acqs[acqs['slot'] == slot][0]['id'] if agasc_id is None: logger.info("No agasc id for slot {}, skipping".format(slot)) continue try: # This is not perfect for star catalogs for agasc 1.4 and 1.5 star = agasc.get_star(agasc_id, date=times[0], use_supplement=False) except: logger.info("agasc error on slot {}:{}".format( slot, sys.exc_info()[0])) continue ra = star['RA_PMCORR'] dec = star['DEC_PMCORR'] star_pos_eci = radec_to_eci(ra, dec) d_aca = np.dot(np.dot(aca_misalign, Ts.transpose(0, 2, 1)), star_pos_eci).transpose() yag[slot] = np.arctan2(d_aca[:, 1], d_aca[:, 0]) * R2A zag[slot] = np.arctan2(d_aca[:, 2], d_aca[:, 0]) * R2A dy[slot] = vals['AOACYAN{}'.format(slot)] - yag[slot] dz[slot] = vals['AOACZAN{}'.format(slot)] - zag[slot] star_info[slot] = star return dy, dz, star_info, yag, zag
def get_context_data(self, **kwargs): # Call the base implementation first to get a context context = super(StarHistView, self).get_context_data(**kwargs) agasc_id = self.request.GET.get('agasc_id', None) if agasc_id is not None: try: agasc_id = int(agasc_id) except: agasc_id = None start = self.request.GET.get('start', None) stop = self.request.GET.get('stop', None) if start == '': start = None if stop == '': stop = None context['agasc_id'] = agasc_id or '' context['start'] = start or '' context['stop'] = stop or '' if agasc_id: import mica.web.star_hist import agasc from agasc.agasc import IdNotFound try: agasc_info = agasc.get_star(agasc_id) context['star_info'] = [(key, agasc_info[key]) for key in agasc_info.dtype.names] except IdNotFound: context['star_info'] = [] pass acq_table, gui_table = mica.web.star_hist.get_star_stats(agasc_id, start, stop) if len(acq_table): context['acq_table'] = acq_table if len(gui_table): context['gui_table'] = gui_table reports_url = ( "https://cxc.cfa.harvard.edu/mta/ASPECT/agasc/supplement_reports/stars/" + f'{int(agasc_id//1e7):03d}/{agasc_id}/index.html') context['reports_url'] = reports_url return context
def deltas_vs_obc_quat(vals, times, catalog): # Ignore misalign aca_misalign = np.array([[1.0,0,0], [0,1,0],[0,0,1]]) q_att = Quat(np.array([vals['AOATTQT1'], vals['AOATTQT2'], vals['AOATTQT3'], vals['AOATTQT4']]).transpose()) Ts = q_att.transform acqs = catalog[(catalog['type'] == 'BOT') | (catalog['type'] == 'ACQ')] # Compute the multiplicative factor to convert from the AGASC proper motion # field to degrees. The AGASC PM is specified in milliarcsecs / year, so this # is dyear * (degrees / milliarcsec) agasc_equinox = DateTime('2000:001:00:00:00.000') dyear = (DateTime(times[0]) - agasc_equinox) / 365.25 pm_to_degrees = dyear / (3600. * 1000.) R2A = 206264.81 dy = {} dz = {} for slot in range(0, 8): agasc_id = acqs[acqs['slot'] == slot][0]['id'] star = agasc.get_star(agasc_id) ra = star['RA'] dec = star['DEC'] if star['PM_RA'] != -9999: ra = star['RA'] + star['PM_RA'] * pm_to_degrees if star['PM_DEC'] != -9999: dec = star['DEC'] + star['PM_DEC'] * pm_to_degrees star_pos_eci = Ska.quatutil.radec2eci(ra, dec) d_aca = np.dot(np.dot(aca_misalign, Ts.transpose(0, 2, 1)), star_pos_eci).transpose() yag = np.arctan2(d_aca[:, 1], d_aca[:, 0]) * R2A zag = np.arctan2(d_aca[:, 2], d_aca[:, 0]) * R2A dy[slot] = vals['AOACYAN{}'.format(slot)] - yag dz[slot] = vals['AOACZAN{}'.format(slot)] - zag return dy, dz
]))) try: cat = get_catalog(obsid, d.manvr.start) except (ValueError, IndexError) as e: print "Skipping {} {}".format(obsid, e) continue gcat = cat['cat'][(cat['cat']['type'] == 'BOT') | (cat['cat']['type'] == 'GUI')] yag_offs = np.zeros((len(pcad_data['AOKALSTR'].vals), len(gcat))) zag_offs = np.zeros((len(pcad_data['AOKALSTR'].vals), len(gcat))) slot_ok_old = {} slot_ok_new = {} for idx, entry in enumerate(gcat): slot = entry['slot'] #ok = pcad_data['AOACFCT{}'.format(slot)].vals == 'TRAK' star = agasc.get_star(entry['id'], date=d.manvr.start) eci = radec2eci(star['RA_PMCORR'], star['DEC_PMCORR']) d_aca = np.dot(q_atts.transform.transpose(0, 2, 1), eci) yag = np.degrees(np.arctan2(d_aca[:, 1], d_aca[:, 0])) * 3600 zag = np.degrees(np.arctan2(d_aca[:, 2], d_aca[:, 0])) * 3600 yag_offs[:, idx] = yag - pcad_data['AOACYAN{}'.format(entry['slot'])].vals zag_offs[:, idx] = zag - pcad_data['AOACZAN{}'.format(entry['slot'])].vals diff = np.sum(((np.abs(yag_offs) > 5) & (np.abs(yag_offs) < 20)) | ((np.abs(zag_offs) > 5) & (np.abs(zag_offs) < 20)), axis=1) kalstr = pcad_data['AOKALSTR'].vals.astype(int) for e in consecutive(np.flatnonzero(((kalstr - diff) < 3) & (diff != 0))): if len(e) > 8: low_obsids.append(obsid)
def plot_crs_visualization(obsid, plot_dir, crs=None, factor=20, save=False, on_the_fly=False): """ Plot visualization of OBC centroid residuals with respect to ground (obc) aspect solution for science (ER) observations in the yang/zang plain. :param obsid: obsid :param crs: dictionary with keys 'ground' and 'obc'. Dictionary values are dictionaries keyed by slot number containing corresponding CentroidResiduals objects. If ground or obc centroid residuals cannot be computed for a given slot, the value is None. :param on_the_fly: default False, if True then ignore param crs and calculate centroid residuals for the requested obsid """ # catalog cat = get_starcat(obsid) # keep only BOT and GUI entries ok = (cat['type'] == 'BOT') | (cat['type'] == 'GUI') cat = cat[ok] cat['idx'] = cat['slot'] # so that the plot is numbered by slot # attitude att = get_att(obsid) # stars cols = ['RA_PMCORR', 'DEC_PMCORR', 'MAG_ACA', 'MAG_ACA_ERR', 'CLASS', 'ASPQ1', 'ASPQ2', 'ASPQ3', 'VAR', 'POS_ERR'] stars = Table(names=cols) for star in cat: row = [] s = get_star(star['id']) for col in cols: row.append(s[col]) stars.add_row(row) fig = plot_stars(att, cat, stars) cs = ['orange', 'forestgreen', 'steelblue', 'maroon', 'gray'] if on_the_fly: crs = get_crs_per_obsid(obsid) else: if crs is None: raise ValueError('Need to provide crs if on_the_fly is False') if obsid > 40000: # ERs crs_ref = crs['obc'] else: crs_ref = crs['ground'] ax = fig.axes[0] for slot in cat['slot']: ok = cat['slot'] == slot yag = cat['yang'][ok] zag = cat['zang'][ok] yp, zp = yagzag_to_pixels(yag, zag) # 1 px -> factor px; 5 arcsec = 5 * factor arcsec try: """ Minus sign for y-coord to reflect sign flip in the pixel to yag conversion and yag scale going from positive to negative """ yy = yp - crs_ref[slot].dyags * factor zz = zp + crs_ref[slot].dzags * factor ax.plot(yy, zz, alpha=0.3, marker=',', color=cs[slot - 3]) ax.plot([-1000, -1020], [2700, 2700], color='k', lw=3) circle = plt.Circle((yp, zp), 5 * factor, color='darkorange', fill=False) ax.add_artist(circle) except Exception: pass plt.text(-511, 530, "ring radius = 5 arcsec (scaled)", color='darkorange') if save: outroot = os.path.join(plot_dir, f'crs_vis_{obsid}') logger.info(f'Writing plot file {outroot}.png') plt.savefig(outroot + '.png') plt.close() return crs
def kal(dwell, telem, limit=20, catalog=None, nowflags=False): cat = catalog # Track status fids = np.column_stack([(telem['AOACFID{}'.format(slot)].vals == 'FID ') for slot in range(0, 8)]) trak = np.column_stack([(telem['AOACFCT{}'.format(slot)].vals == 'TRAK') for slot in range(0, 8)]) # Flags ir = np.column_stack([(telem['AOACIIR{}'.format(slot)].vals == 'OK ') for slot in range(0, 8)]) sp = np.column_stack([(telem['AOACISP{}'.format(slot)].vals == 'OK ') for slot in range(0, 8)]) dp_date = DateTime('2013:297:11:25:52.000').secs dp = np.column_stack([((telem['AOACIDP{}'.format(slot)].vals == 'OK ') | (telem['AOKALSTR'].times > dp_date)) for slot in range(0, 8)]) if dwell.start > '2015:251': # I'm not sure about the fetch grid if we use fetch interpolate, so just use # a sorted search to see if the MSS flag should apply mss = telem['AOACIMSS'].vals == 'ENAB' mss_times = telem['AOACIMSS'].times mss_at_times = mss[ np.searchsorted(mss_times[1:-1], telem['AOACIMS0'].times) - 1] ms = np.column_stack([((telem['AOACIMS{}'.format(slot)].vals == 'OK ') | ~mss_at_times) for slot in range(0, 8)]) else: ms = np.column_stack([(telem['AOACIMS{}'.format(slot)].vals == 'OK ') for slot in range(0, 8)]) # use rolled-by-4 for ~last 4.1 sample last_trak = np.roll(trak, 4, axis=0) last_trak[0] = True # Calc centroid residuals using CYAN/CZAN q_atts = Quat( normalize( np.column_stack([ telem['AOATTQT1'].vals, telem['AOATTQT2'].vals, telem['AOATTQT3'].vals, telem['AOATTQT4'].vals ]))) # guide and bot slots gcat = cat[(cat['type'] == 'BOT') | (cat['type'] == 'GUI')] # make a couple of structures for the offsets yag_offs = np.zeros((len(telem['AOKALSTR'].vals), 8)) zag_offs = np.zeros((len(telem['AOKALSTR'].vals), 8)) for idx, entry in enumerate(gcat): slot = entry['slot'] #ok = telem['AOACFCT{}'.format(slot)].vals == 'TRAK' star = agasc.get_star(entry['id'], date=dwell.manvr.start) eci = radec2eci(star['RA_PMCORR'], star['DEC_PMCORR']) d_aca = np.dot(q_atts.transform.transpose(0, 2, 1), eci) yag = np.degrees(np.arctan2(d_aca[:, 1], d_aca[:, 0])) * 3600 zag = np.degrees(np.arctan2(d_aca[:, 2], d_aca[:, 0])) * 3600 yag_offs[:, slot] = yag - telem['AOACYAN{}'.format(entry['slot'])].vals zag_offs[:, slot] = zag - telem['AOACZAN{}'.format(entry['slot'])].vals if nowflags: kal = (~fids & trak & last_trak & ir & sp & (np.abs(yag_offs) < limit) & (np.abs(zag_offs) < limit)) else: kal = (~fids & trak & last_trak & ir & sp & dp & ms & (np.abs(yag_offs) < limit) & (np.abs(zag_offs) < limit)) return telem['AOKALSTR'].times, kal