Example #1
0
    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']
Example #2
0
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
Example #3
0
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 []
Example #4
0
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
Example #5
0
    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
Example #6
0
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
Example #7
0
         ])))
 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)
Example #8
0
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
Example #9
0
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