Пример #1
0
    def vis_marker_received(self, markerInfo):
        markerId, position, orientation = markerInfo.id, markerInfo.pose.position, markerInfo.pose.orientation
        # if int(markerId) not in self.allowed: return
        # print markerInfo.id
        px, py, pz = tuple([position.x, position.y, position.z])
        # print distFromCamera
        position.z = np.cos(self.angle) * pz - np.sin(self.angle) * py
        position.y = np.sin(self.angle) * pz + np.cos(self.angle) * py
        q = (orientation.x, orientation.y, orientation.z, orientation.w)

        if q in self.cache:
            ori = self.cache[q]
            markerInfo.pose.orientation.x = ori[0]
            markerInfo.pose.orientation.y = ori[1]
            markerInfo.pose.orientation.z = ori[2]
            markerInfo.pose.orientation.w = ori[3]
        else:
            originalQuat = Q.Quat(Q.normalize(list(q)))
            quatOffsetFix = Q.Quat([0, 0, -1 * self.angle])
            fixed = originalQuat * quatOffsetFix
            x, y, z, w = tuple(fixed._get_q())
            markerInfo.pose.orientation.x = x
            markerInfo.pose.orientation.y = y
            markerInfo.pose.orientation.z = z
            markerInfo.pose.orientation.w = w
            self.cache[q] = [x, y, z, w]

        self.markerSeen = markerInfo
Пример #2
0
def calc_earth_vis(p_chandra_eci,
                   chandra_att,
                   planes=make_taco(),
                   p_radiators=make_radiator(),
                   earth_surface_grid=sphere_grid(4)):
    """Calculate the relative Earth visibility for the ACIS radiator given
    the Chandra orbit position ``p_chandra_eci`` and attitude ``chandra_att``.

    The relative visibility is normalized so that 1.0 represents the entire
    radiator seeing the full Earth at 100000 km.

    :param p_chandra_eci: Chandra orbital position [x, y, z] (meters)
    :param chandra_att: Chandra attitude [ra, dec, roll] (deg)

    :returns: relative visibility
    """
    # Calculate position of earth in ECI and Chandra body coords
    # For T = attitude transformation matrix then p_body = T^-1 p_eci
    q_att = Quaternion.Quat(chandra_att)
    p_earth_body = np.dot(q_att.transform.transpose(), -p_chandra_eci)
    p_earth_surfaces = (p_earth_body + earth_surface_grid * Rad_Earth)

    # points that are visible to ACIS radiator
    behind_earth = []
    visible = []
    blocked = []
    illum = 0.

    for p_radiator in p_radiators:
        for p_earth_surface in p_earth_surfaces:
            line = Line(p_radiator, p_earth_surface)
            if nearest_sphere_intersect(line.u, p_earth_body, Rad_Earth,
                                        line.len):
                for plane in planes:
                    if plane_line_intersect(plane, line):
                        # Blocked by SIM structure (aka space taco)
                        blocked.append(p_earth_surface)
                        break
                else:
                    visible.append(p_earth_surface)
                    # calculate projection of radiator normal [0,0,1] onto the vector
                    # from radiator to p_earth_surface.
                    illum += abs(line.u[2]) / line.len**2
                    # Do I need another cos(theta) term for Lambert's law?? YES
            else:
                behind_earth.append(p_earth_surface)

    illum *= 10000.**2 / (len(p_radiators) * len(p_earth_surfaces)) / 0.038
    return visible, blocked, behind_earth, illum
Пример #3
0
def plot(obsid, mp_dir=None):
    sc = get_starcheck_catalog(obsid, mp_dir)
    quat = Quaternion.Quat((sc['obs']['point_ra'], sc['obs']['point_dec'],
                            sc['obs']['point_roll']))
    field = agasc.get_agasc_cone(sc['obs']['point_ra'],
                                 sc['obs']['point_dec'],
                                 radius=1.5,
                                 date=DateTime(
                                     sc['obs']['mp_starcat_time']).date)
    fig = plot_stars(catalog=sc['cat'],
                     attitude=quat,
                     stars=field,
                     title="RA %.2f Dec %.2f" %
                     (sc['obs']['point_ra'], sc['obs']['point_dec']))
    return fig, sc['cat'], sc['obs']
Пример #4
0
def plot_stars(attitude,
               catalog=None,
               stars=None,
               title=None,
               starcat_time=None,
               red_mag_lim=None,
               quad_bound=True,
               grid=True,
               bad_stars=None,
               plot_keepout=False,
               ax=None,
               duration=0):
    """
    Plot a catalog, a star field, or both in a matplotlib figure.
    If supplying a star field, an attitude must also be supplied.

    :param attitude: A Quaternion compatible attitude for the pointing
    :param catalog: Records describing catalog.  Must be astropy table compatible.
        Required fields are ['idx', 'type', 'yang', 'zang', 'halfw']
    :param stars: astropy table compatible set of agasc records of stars
        Required fields are ['RA_PMCORR', 'DEC_PMCORR', 'MAG_ACA', 'MAG_ACA_ERR'].
        If bad_acq_stars will be called (bad_stars is None), additional required fields
        ['CLASS', 'ASPQ1', 'ASPQ2', 'ASPQ3', 'VAR', 'POS_ERR']
        If stars is None, stars will be fetched from the AGASC for the
        supplied attitude.
    :param title: string to be used as suptitle for the figure
    :param starcat_time: DateTime-compatible time.  Used in ACASC fetch for proper
        motion correction.  Not used if stars is not None.
    :param red_mag_lim: faint limit for field star plotting.
    :param quad_bound: boolean, plot inner quadrant boundaries
    :param grid: boolean, plot axis grid
    :param bad_stars: boolean mask on 'stars' of those that don't meet minimum requirements
        to be selected as acq stars.  If None, bad_stars will be set by a call
        to bad_acq_stars().
    :param plot_keepout: plot CCD area to be avoided in star selection (default=False)
    :param ax: matplotlib axes object to use (optional)
    :param duration: duration (starting at ``starcat_time``) for plotting planets
        (secs, default=0)
    :returns: matplotlib figure
    """
    if stars is None:
        quat = Quaternion.Quat(attitude)
        stars = agasc.get_agasc_cone(quat.ra,
                                     quat.dec,
                                     radius=1.5,
                                     date=starcat_time)

    if bad_stars is None:
        bad_stars = bad_acq_stars(stars)

    if ax is None:
        fig = plt.figure(figsize=(5.325, 5.325))
        fig.subplots_adjust(top=0.95)

        # Make an empty plot in row, col space
        ax = fig.add_subplot(1, 1, 1)
    else:
        fig = ax.get_figure()

    ax.set_aspect('equal')
    lim0, lim1 = -580, 590
    plt.xlim(lim0, lim1)  # Matches -2900, 2900 arcsec roughly
    plt.ylim(lim0, lim1)

    # plot the box and set the labels
    b1hw = 512
    box1 = plt.Rectangle((b1hw, -b1hw), -2 * b1hw, 2 * b1hw, fill=False)
    ax.add_patch(box1)
    b2w = 520
    box2 = plt.Rectangle((b2w, -b1hw), -4 + -2 * b2w, 2 * b1hw, fill=False)
    ax.add_patch(box2)

    ax.scatter(np.array([-2700, -2700, -2700, -2700, -2700]) / -5,
               np.array([2400, 2100, 1800, 1500, 1200]) / 5,
               c='orange',
               edgecolors='none',
               s=symsize(np.array([10.0, 9.0, 8.0, 7.0, 6.0])))

    # Manually set ticks and grid to specified yag/zag values
    yz_ticks = [-2000, -1000, 0, 1000, 2000]
    zeros = [0, 0, 0, 0, 0]
    r, c = yagzag_to_pixels(yz_ticks, zeros)
    ax.set_xticks(r)
    ax.set_xticklabels(yz_ticks)
    r, c = yagzag_to_pixels(zeros, yz_ticks)
    ax.set_yticks(c)
    ax.set_yticklabels(yz_ticks)
    ax.grid()

    ax.set_xlabel("Yag (arcsec)")
    ax.set_ylabel("Zag (arcsec)")
    [label.set_rotation(90) for label in ax.get_yticklabels()]

    if quad_bound:
        ax.plot([-511, 511], [0, 0], color='magenta', alpha=0.4)
        ax.plot([0, 0], [-511, 511], color='magenta', alpha=0.4)

    if plot_keepout:
        # Plot grey area showing effective keep-out zones for stars.  Back off on
        # outer limits by one pixel to improve rendered PNG slightly.
        row_pad = 15
        col_pad = 8
        box = plt.Rectangle((-511, -511),
                            1022,
                            1022,
                            edgecolor='none',
                            facecolor='black',
                            alpha=0.2,
                            zorder=-1000)
        ax.add_patch(box)
        box = plt.Rectangle((-512 + row_pad, -512 + col_pad),
                            1024 - row_pad * 2,
                            1024 - col_pad * 2,
                            edgecolor='none',
                            facecolor='white',
                            zorder=-999)
        ax.add_patch(box)

    # Plot stars
    _plot_field_stars(ax,
                      stars,
                      attitude=attitude,
                      bad_stars=bad_stars,
                      red_mag_lim=red_mag_lim)

    # plot starcheck catalog
    if catalog is not None:
        _plot_catalog_items(ax, catalog)

    # Planets
    _plot_planets(ax, attitude, starcat_time, duration, lim0, lim1)

    if title is not None:
        ax.set_title(title, fontsize='small')

    return fig
Пример #5
0
def _plot_field_stars(ax, stars, attitude, red_mag_lim=None, bad_stars=None):
    """
    Plot plot field stars in yang and zang on the supplied
    axes object in place.

    :param ax: matplotlib axes
    :param stars: astropy.table compatible set of records of agasc entries of stars
    :param attitude: Quaternion-compatible attitude
    :param red_mag_lim: faint limit
    :param bad_stars: boolean mask of stars to be plotted in red
    """
    stars = Table(stars)
    quat = Quaternion.Quat(attitude)

    if bad_stars is None:
        bad_stars = np.zeros(len(stars), dtype=bool)

    if 'yang' not in stars.colnames or 'zang' not in stars.colnames:
        # Add star Y angle and Z angle in arcsec to the stars table.
        # radec2yagzag returns degrees.
        yags, zags = radec2yagzag(stars['RA_PMCORR'], stars['DEC_PMCORR'],
                                  quat)
        stars['yang'] = yags * 3600
        stars['zang'] = zags * 3600

    # Update table to include row/col values corresponding to yag/zag
    rows, cols = yagzag_to_pixels(stars['yang'], stars['zang'], allow_bad=True)
    stars['row'] = rows
    stars['col'] = cols

    # Initialize array of colors for the stars, default is black.  Use 'object'
    # type to not worry in advance about string length and also for Py2/3 compat.
    colors = np.zeros(len(stars), dtype='object')
    colors[:] = 'black'

    colors[bad_stars] = BAD_STAR_COLOR

    if red_mag_lim:
        # Mark stars with the FAINT_STAR_COLOR if they have MAG_ACA
        # that is fainter than red_mag_lim but brighter than red_mag_lim
        # plus a rough mag error.  The rough mag error calculation is
        # based on the SAUSAGE acq stage 1 check, which uses nsigma of
        # 3.0, a mag low limit of 1.5, and a random error of 0.26.
        nsigma = 3.0
        mag_error_low_limit = 1.5
        randerr = 0.26
        caterr = stars['MAG_ACA_ERR'] / 100.
        error = nsigma * np.sqrt(randerr**2 + caterr**2)
        error = error.clip(mag_error_low_limit)
        # Faint and bad stars will keep their BAD_STAR_COLOR
        # Only use the faint mask on stars that are not bad
        colors[(stars['MAG_ACA'] >= red_mag_lim)
               & (stars['MAG_ACA'] < red_mag_lim + error)
               & ~bad_stars] = FAINT_STAR_COLOR
        # Don't plot those for which MAG_ACA is fainter than red_mag_lim + error
        # This overrides any that may be 'bad'
        colors[stars['MAG_ACA'] >= red_mag_lim + error] = 'none'

    size = symsize(stars['MAG_ACA'])
    # scatter() does not take an array of alphas, and rgba is
    # awkward for color='none', so plot these in a loop.
    for color, alpha in [(FAINT_STAR_COLOR, FAINT_STAR_ALPHA),
                         (BAD_STAR_COLOR, BAD_STAR_ALPHA), ('black', 1.0)]:
        colormatch = colors == color
        ax.scatter(stars[colormatch]['row'],
                   stars[colormatch]['col'],
                   c=color,
                   s=size[colormatch],
                   edgecolor='none',
                   alpha=alpha)
Пример #6
0
        # Else there were no None's in the Q's so Calculate pitch and roll
        # Calculate the pitch and roll values from the specified Maneuver Quaternions
        #
        # First create an array of the 4 quaternions
        man_quat_array = np.array(
            [float(args.q1),
             float(args.q2),
             float(args.q3),
             float(args.q4)])
        # Be sure the q's are normalized
        normd_q_list = qt.normalize(man_quat_array)

        # Create the Quat instance
        # Give it a try; if fail then set pitch and roll to 0.0
        try:
            man_quat = qt.Quat(normd_q_list)
            # Worked ok so now calculate the pitch and roll
            pitch = Ska.Sun.pitch(man_quat.ra, man_quat.dec,
                                  str(args.event_time))
            nom_roll = Ska.Sun.nominal_roll(man_quat.ra, man_quat.dec,
                                            str(args.event_time))
        except ValueError:
            pitch = 0.0
            nom_roll = 0.0
            print "WARNING: The Quaternion set you gave me is not normalized. Can't use it. I've set the resultant pitch and roll to 0.0.\n BE SURE you do not run a model until you've entered reasonable values."

    # Append the header to the file
    eventfile.write(
        "#*******************************************************************************"
    )
    eventfile.write("\n# Type: " + args.event_type)
Пример #7
0
def main():
    global opt
    opt, args = get_options()
    tstart = DateTime(opt.tstart).secs
    tstop = DateTime(opt.tstop).secs

    # Get orbital ephemeris in requested time range
    print('Fetching ephemeris')
    ephem_x = fetch.MSID('orbitephem0_x', opt.tstart, opt.tstop)
    ephem_y = fetch.MSID('orbitephem0_y', opt.tstart, opt.tstop)
    ephem_z = fetch.MSID('orbitephem0_z', opt.tstart, opt.tstop)
    ephem_times = ephem_x.times.copy()

    # Get spacecraft attitude in requested time range at the same sampling as ephemeris
    print('Fetching attitude telemetry between {0} and {1}'.format(
        opt.tstart, opt.tstop))
    qatts = fetch.MSIDset(['aoattqt1', 'aoattqt2', 'aoattqt3', 'aoattqt4'],
                          opt.tstart, opt.tstop)
    #cols, atts = fetch(start=ephem.Time[0], stop=ephem.Time[-1], dt=dt, time_format='secs',
    #             colspecs=)
    # atts = np.rec.fromrecords(atts, names=cols)
    q1s = qatts['aoattqt1'].vals[::opt.sample]
    q2s = qatts['aoattqt2'].vals[::opt.sample]
    q3s = qatts['aoattqt3'].vals[::opt.sample]
    q4s = qatts['aoattqt4'].vals[::opt.sample]
    q_times = qatts['aoattqt1'].times[::opt.sample]

    ephem_x_vals = Ska.Numpy.interpolate(ephem_x.vals, ephem_times, q_times)
    ephem_y_vals = Ska.Numpy.interpolate(ephem_y.vals, ephem_times, q_times)
    ephem_z_vals = Ska.Numpy.interpolate(ephem_z.vals, ephem_times, q_times)

    chandra_ecis = np.array([ephem_x_vals, ephem_y_vals,
                             ephem_z_vals]).copy().transpose()

    if opt.movie:
        if len(atts) > 250:
            print "Error: movie option will produce more than 250 images.  Change code if needed."
            sys.exit(0)
        if not os.path.exists(opt.out):
            os.makedirs(opt.out)

    # Divy up calculations amongst the n-processors
    i0s = range(0, len(q1s), len(q1s) // opt.nproc + 1)
    i1s = i0s[1:] + [len(q1s)]

    t0 = time.time()
    # Calculate illumination in a separate process over each sub-interval
    queues = []
    procs = []
    for iproc, i0, i1 in zip(itertools.count(), i0s, i1s):
        queue = Queue()
        proc = Process(target=calc_vis_values,
                       args=(queue, iproc, q_times[i0:i1], chandra_ecis[i0:i1],
                             q1s[i0:i1], q2s[i0:i1], q3s[i0:i1], q4s[i0:i1]))
        proc.start()
        procs.append(proc)
        queues.append(queue)

    # Join the results from each processor at the end
    outvals = []
    for proc, queue in zip(procs, queues):
        outvals.extend(queue.get())
        proc.join()
    print
    print 'calc_esa:', time.time() - t0

    t0 = time.time()
    esa_directs = np.ndarray(len(q_times))
    esa_refls = np.ndarray(len(q_times))
    for i, t, q1, q2, q3, q4, x, y, z in zip(itertools.count(), q_times, q1s,
                                             q2s, q3s, q4s, ephem_x_vals,
                                             ephem_y_vals, ephem_z_vals):
        direct, refl, total = Chandra.acis_esa.earth_solid_angle(
            Quaternion.Quat([q1, q2, q3, q4]), np.array([x, y, z]))

        esa_directs[i] = direct
        esa_refls[i] = refl

    print 'calc_esa:', time.time() - t0
    # Plot illumination versus date
    fig = plt.figure(1, figsize=(6, 4))
    plt.clf()
    illum = np.rec.fromrecords(
        outvals,
        names=['time', 'direct', 'reflect', 'alt', 'q1', 'q2', 'q3', 'q4'])
    ticklocs, fig, ax = plot_cxctime(illum.time, illum.direct + illum.reflect,
                                     '-b')
    #    plot_cxctime(illum.time, illum.reflect, '-r')
    #    plot_cxctime(illum.time, illum.direct, '-r')
    #    plot_cxctime(q_times, esa_directs, '-c')
    #    plot_cxctime(q_times, esa_refls, '-m')
    plot_cxctime(q_times, esa_directs + esa_refls, '-r')
    ax.set_title('ACIS radiator illumination')
    ax.set_ylabel('Illumination (steradians)')
    filename = opt.out + '.png'
    fig.savefig(filename)
    print 'Create image file', filename

    # Write results to FITS table
    filename = opt.out + '.fits'
    Ska.Table.write_fits_table(opt.out + '.fits', illum)
    print 'Created FITS table', filename

    if opt.movie:
        print 'To make a movie run the following command:'
        print 'convert -delay 30 %s/*.png -loop 0 %s.gif' % (opt.out, opt.out)
Пример #8
0
def get_xray_data(obsids):

    for obsid in obsids:

        obsdir = "%s/auto/obs%05d" % (projdir, obsid)
        if not os.path.exists(obsdir):
            os.makedirs(obsdir)

        src_file = os.path.join(obsdir, 'picked_src.dat')
        obs_info = sqlaca.fetchone(
            "select * from observations where obsid = %d" % obsid)
        if obs_info is None:
            continue
        if not os.path.exists(src_file):
            src = find_obsid_src(obsid, obs_info)
            if src is None:
                continue
            else:
                src.write(src_file, format='ascii.tab')
        else:
            src = Table.read(src_file, format='ascii.tab')

        # cut-out region with a point source for this obsid
        point = '%s/point_source.fits' % obsdir
        #print point
        if (not os.path.exists(point) or ((os.stat(point).st_mtime < MTIME)
                                          and obs_info['instrume'] == 'HRC')
                or REDO):
            extract_point(obs_info, src, obsdir, point)
        obsid_src = point

        # periscope tilt telemetry
        if not os.path.exists(os.path.join(obsdir, 'tilt.pkl')) or REDO:
            obs = obs_info
            msids = [
                'OOBAGRD3', 'OOBAGRD6', 'OHRTHR42', 'OHRTHR43', 'OOBTHR39',
                'OHRTHR24', '4RT702T', 'OHRTHR24', 'AACBPPT', 'AACH1T',
                'AACCCDPT', 'AACBPRT'
            ]
            telem = fetch.MSIDset(msids, obs['tstart'] - 1000,
                                  obs['tstop'] + 1000)
            telemtime = telem['OOBAGRD3'].times
            tilt = dict(telem)
            tilt.update(
                dict(time=telemtime,
                     tilt_axial=telem['OOBAGRD3'].vals,
                     tilt_diam=telem['OOBAGRD6'].vals))
            tilt_pick = open(os.path.join(obsdir, 'tilt.pkl'), 'w')
            cPickle.dump(tilt, tilt_pick)
            tilt_pick.close()
            #print os.path.join(obsdir, 'tilt.pkl')

        # position data
        if (not os.path.exists(os.path.join(obsdir, 'released_pos.pkl'))
                or (os.stat(os.path.join(obsdir, 'released_pos.pkl')).st_mtime
                    < os.stat(point).st_mtime) or REDO):
            obs = obs_info
            print "making released_pos.pkl for {}".format(obs['obsid'])
            print obs
            evts = Table.read(obsid_src)
            q = Quaternion.Quat(
                [obs['ra_nom'], obs['dec_nom'], obs['roll_nom']])

            # only use the first aspect interval of obsid 14457
            if obsid == 14457:
                evts = evts[evts['time'] < 490232479.878]
            y, z = Ska.quatutil.radec2yagzag(evts['RA'], evts['DEC'], q)
            pos = dict(time=np.array(evts['time']),
                       yag=np.array(y * 3600),
                       zag=np.array(z * 3600))
            pos_pick = open(os.path.join(obsdir, 'released_pos.pkl'), 'w')
            cPickle.dump(pos, pos_pick)
            pos_pick.close()

        GRADIENTS = dict(OOBAGRD3=dict(
            yag=6.98145650e-04,
            zag=9.51578351e-05,
        ),
                         OOBAGRD6=dict(
                             yag=-1.67009240e-03,
                             zag=-2.79084775e-03,
                         ))

        # position data
        if (not os.path.exists(os.path.join(obsdir, 'pos.pkl'))
                or (os.stat(os.path.join(obsdir, 'pos.pkl')).st_mtime <
                    os.stat(point).st_mtime) or REDO):
            obs = obs_info
            print "making pos.pkl for {}".format(obs['obsid'])
            evts = Table.read(obsid_src)
            q = Quaternion.Quat(
                [obs['ra_nom'], obs['dec_nom'], obs['roll_nom']])

            # only use the first aspect interval of obsid 14457
            if obsid == 14457:
                evts = evts[evts['time'] < 490232479.878]
            y, z = Ska.quatutil.radec2yagzag(evts['RA'], evts['DEC'], q)
            # retrieve gradient telemetry
            tstart = evts['time'][0]
            tstop = evts['time'][-1]
            gradients = fetch.MSIDset(GRADIENTS.keys(), tstart - 100,
                                      tstop + 100)
            for msid in gradients:
                # filter bad telemetry in place
                filter_bad_telem(gradients[msid])
                times = gradients[msid].times
                evt_idx = np.searchsorted(times, evts['time'])
                # find a mean gradient, because this calibration is relative to mean
                mean_gradient = np.mean(gradients[msid].vals[evt_idx])
                # and smooth the telemetry to deal with slow changes and large step sizes..
                smooth_gradient = smooth(gradients[msid].vals)
                y += (smooth_gradient[evt_idx] -
                      mean_gradient) * GRADIENTS[msid]['yag']
                z += (smooth_gradient[evt_idx] -
                      mean_gradient) * GRADIENTS[msid]['zag']

            pos = dict(time=np.array(evts['time']),
                       yag=np.array(y * 3600),
                       zag=np.array(z * 3600))

            pos_pick = open(os.path.join(obsdir, 'pos.pkl'), 'w')
            cPickle.dump(pos, pos_pick)
            pos_pick.close()

    pos_files = glob("auto/obs*/released_pos.pkl")
    print "Retrieved sources for {} observations".format(len(pos_files))