def make_ra_dec_stars_list(): """ Make a list of stars structured arrays. Each list element has:: (ra, dec, stars) ``stars`` is a structured array from the microagasc that has the brightest 30 candidate guide/acq stars within a 1.0 degree radius of ``ra``, ``dec``. """ npix = healpy.nside2npix(NSIDE) ra_dec_stars_list = [] for ipix in range(0, npix): theta, phi = healpy.pix2ang(NSIDE, ipix) dec = 90 - np.degrees(theta) ra = np.degrees(phi) print ra, dec stars = agasc.get_agasc_cone(ra, dec, 1.0, agasc_file='microagasc.h5') ok = ((stars['CLASS'] == 0) & (stars['MAG_ACA'] < 10.6) & (stars['MAG_ACA'] > 5.8) & (stars['ASPQ1'] == 0) & (stars['COLOR1'] != 0.700)) stars_ok = stars[ok] stars_ok = np.sort(stars_ok, order=['MAG_ACA']) ra_dec_stars_list.append((ra, dec, stars_ok[:30])) pickle.dump(ra_dec_stars_list, open('ra_dec_stars_list.pkl', 'w'), protocol=-1)
def _test_agasc(ra, dec, radius=1.4, agasc_file=None): stars1 = agasc.get_agasc_cone(ra, dec, radius=radius, agasc_file=agasc_file, date='2000:001') stars1.sort('AGASC_ID') stars2 = mp_get_agasc(ra, dec, radius) stars2.sort('AGASC_ID') # First make sure that the common stars are identical agasc_ids = set(stars1['AGASC_ID']).intersection(set(stars2['AGASC_ID'])) for agasc_id in agasc_ids: star1 = stars1[np.searchsorted(stars1['AGASC_ID'], agasc_id)] star2 = stars2[np.searchsorted(stars2['AGASC_ID'], agasc_id)] for colname in AGASC_COLNAMES: if star1[colname].dtype.kind == 'f': assert np.all(np.abs(star1[colname] - star2[colname]) < 1e-4) else: assert star1[colname] == star2[colname] # Second make sure that the non-common stars are all just at the edge # of the faint mag limit, due to precision loss in mp_get_agasc for s1, s2 in ((stars1, stars2), (stars2, stars1)): mm1 = set(s1['AGASC_ID']) - set(s2['AGASC_ID']) for agasc_id in mm1: idx = np.flatnonzero(s1['AGASC_ID'] == agasc_id)[0] star = s1[idx] bad_is_star1 = s1 is stars1 rad = agasc.sphere_dist(ra, dec, star['RA'], star['DEC']) adj_mag = star['MAG_ACA'] - 3.0 * star['MAG_ACA_ERR'] / 100.0 if adj_mag < 11.5 * 0.99: # Allow for loss of precision in output of mp_get_agasc print('Bad star', agasc_id, rad, adj_mag, bad_is_star1) assert False
def check_obs(obsid): try: sc = mica.starcheck.get_starcheck_catalog(obsid) except: return None if sc['obs'] is None: return None if 'cat' not in sc: return None if len(sc['cat']) == 0: return None ra = sc['obs']['point_ra'] if ra is None: return None dec = sc['obs']['point_dec'] roll = sc['obs']['point_roll'] cone_stars = agasc.get_agasc_cone(ra, dec, radius=1.2, date=sc['obs']['mp_starcat_time'], agasc_file='/proj/sot/ska/jeanproj/git/agasc/miniagasc.h5') acqs = sc['cat'][(sc['cat']['type'] == 'BOT') | (sc['cat']['type'] == 'ACQ')] acq_pass = [re.sub('g\d{1}', '', ap) for ap in acqs['pass']] acq_manual = np.array([re.search('X', ap) is not None for ap in acq_pass]) acq_pass = [re.sub('gX', '', ap) for ap in acq_pass] acq_pass = [re.sub('aX', '', ap) for ap in acq_pass] acq_pass = np.array([re.sub('^$', 'a1', ap) for ap in acq_pass]) mini_sausage.set_dither(np.max([sc['obs']['dither_y_amp'], sc['obs']['dither_z_amp'], 8.0])) mini_sausage.set_manvr_error(sc['manvr'][-1]['slew_err_arcsec']) select, all_stars = mini_sausage.select_stars(ra, dec, roll, cone_stars) all_stars['starcheck'] = False for star in acqs: all_stars['starcheck'][all_stars['AGASC_ID'] == star['id']] = True sc_t_ccd, sc_n_acq = aca_required_temp.max_temp(time=sc['obs']['mp_starcat_time'], stars=all_stars[all_stars['starcheck']]) ms_t_ccd, ms_n_acq = aca_required_temp.max_temp(time=sc['obs']['mp_starcat_time'], stars=select) print obsid, "starcheck {}".format(sc_t_ccd), "manual? ", np.any(acq_manual), "mine {}".format(ms_t_ccd) obs = {'obsid': obsid, 'sc_t_ccd': sc_t_ccd, 'sc_had_manual': np.any(acq_manual), 'ms_t_ccd': ms_t_ccd, 'total': len(acqs), 'new': 0} for star in acqs: if star['id'] in select['AGASC_ID']: obs['new'] += 1 for p in [1, 2, 3, 4]: sc_acqs_for_p = acqs[acq_pass == 'a{}'.format(p)] obs['sc_n_{}'.format(p)] = len(sc_acqs_for_p) new_acqs_for_p = select[(select['stage'] == p)] obs['new_n_{}'.format(p)] = 0 for star in sc_acqs_for_p: if star['id'] in new_acqs_for_p['AGASC_ID']: obs['new_n_{}'.format(p)] += 1 obs['extra_n_{}'.format(p)] = len(new_acqs_for_p) - len(sc_acqs_for_p) return obs
def test_basic(): star = agasc.get_star(1180612288) # High-PM star assert np.isclose(star['RA'], 219.9053773) assert np.isclose(star['DEC'], -60.8371572) stars = agasc.get_agasc_cone(star['RA'], star['DEC'], 0.5) stars.sort('MAG_ACA') agasc_ids = [1180612176, 1180612296, 1180612184, 1180612288, 1180612192] mags = [-0.663, -0.576, -0.373, 0.53, 0.667] assert np.allclose(stars['AGASC_ID'][:5], agasc_ids) assert np.allclose(stars['MAG_ACA'][:5], mags)
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']
def make_maps(): npix = healpy.nside2npix(NSIDE) small_ns = {limit: [] for limit in limits} big_ns = {limit: [] for limit in limits} ras = [] decs = [] for ipix in range(0, npix): theta, phi = healpy.pix2ang(NSIDE, ipix) dec = 90 - np.degrees(theta) ra = np.degrees(phi) ras.append(ra) decs.append(dec) print ra, dec star_small = agasc.get_agasc_cone(ra, dec, 0.7) star_big = agasc.get_agasc_cone(ra, dec, 0.9) for limit in limits: stars = star_small ok = ((stars['CLASS'] == 0) & (stars['MAG_ACA'] < limit) & (stars['MAG_ACA'] > 5.8) & (stars['ASPQ1'] == 0) & (stars['COLOR1'] != 0.700)) n = len(stars[ok]) small_ns[limit].append(n) stars = star_big ok = ((stars['CLASS'] == 0) & (stars['MAG_ACA'] < limit) & (stars['MAG_ACA'] > 5.8) & (stars['ASPQ1'] == 0) & (stars['COLOR1'] != 0.700)) n = len(stars[ok]) big_ns[limit].append(n) np.save('ra', np.array(ras)) np.save('dec', np.array(decs)) for limit in limits: np.save('small_{}.npy'.format(limit), np.array(small_ns[limit])) np.save('big_{}.npy'.format(limit), np.array(big_ns[limit]))
def make_plots_for_obsid(obsid, ra, dec, roll, starcat_time, catalog, outdir, red_mag_lim=10.7): """ Make standard starcheck plots for obsid and save as pngs with standard names. Writes out to stars_{obsid}.png and star_view_{obsid}.png in supplied outdir. :param obsid: Obsid used for file names :param ra: RA in degrees :param dec: Dec in degrees :param roll: Roll in degrees :param catalog: list of dicts or other astropy.table compatible structure with conventional starcheck catalog parameters for a set of ACQ/BOT/GUI/FID/MON items. :param outdir: output directory for png plot files :param red_mag_lim: faint limit """ # explicitly float convert these, as we may be receiving this from Perl passing strings ra = float(ra) dec = float(dec) roll = float(roll) # get the agasc field once and then use it for both plots that have stars stars = agasc.get_agasc_cone(ra, dec, radius=1.5, date=starcat_time) # We use the full star list for both the field plot and the main "catalog" plot # and we can save looking up the yang/zang positions twice if we add that content # to the stars in this wrapper yags, zags = radec2yagzag(stars['RA_PMCORR'], stars['DEC_PMCORR'], Quaternion.Quat([ra, dec, roll])) stars['yang'] = yags * 3600 stars['zang'] = zags * 3600 bad_stars = bad_acq_stars(stars) f_plot = plot_stars(attitude=[ra, dec, roll], catalog=None, stars=stars, title=None, starcat_time=starcat_time, bad_stars=bad_stars, red_mag_lim=None) f_plot.savefig(os.path.join(outdir, 'star_view_{}.png'.format(obsid)), dpi=80) plt.close(f_plot) cat_plot = plot_stars(attitude=[ra, dec, roll], catalog=catalog, stars=stars, title="RA=%.6f Dec=%.6f Roll=%.6f" % (ra, dec, roll), starcat_time=starcat_time, bad_stars=bad_stars, red_mag_lim=red_mag_lim) cat_plot.savefig(os.path.join(outdir, 'stars_{}.png'.format(obsid)), dpi=80) plt.close(cat_plot) compass_plot = plot_compass(roll) compass_plot.savefig(os.path.join(outdir, 'compass{}.png'.format(obsid)), dpi=80) plt.close(compass_plot)
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']
def test_proper_motion(): """ Test that the filtering in get_agasc_cone correctly expands the initial search radius and then does final filtering using PM-corrected positions. """ star = agasc.get_star(1180612288) # High-PM star radius = 2.0 / 3600 # 5 arcsec stars = agasc.get_agasc_cone(star['RA'], star['DEC'], radius, date='2000:001') assert len(stars) == 1 stars = agasc.get_agasc_cone(star['RA'], star['DEC'], radius, date='2017:001') assert len(stars) == 0 stars = agasc.get_agasc_cone(star['RA'], star['DEC'], radius, date='2017:001', pm_filter=False) assert len(stars) == 1 stars = agasc.get_agasc_cone(star['RA_PMCORR'], star['DEC_PMCORR'], radius, date='2017:001') assert len(stars) == 1 stars = agasc.get_agasc_cone(star['RA_PMCORR'], star['DEC_PMCORR'], radius, date='2017:001', pm_filter=False) assert len(stars) == 0
def run(self): # Expensive import so do this locally import agasc import Ska.quatutil q_att = self.SC.q_att stars = agasc.get_agasc_cone(q_att.ra, q_att.dec, radius=1.5, date=self.SC.date) stars = Table(stars, names=[name.lower() for name in stars.colnames]) yang, zang = Ska.quatutil.radec2yagzag(stars['ra_pmcorr'], stars['dec_pmcorr'], q_att) stars['yang'] = yang * 3600 # angle in arcsec stars['zang'] = zang * 3600 self.SC.stars = stars logger.debug('Got %d stars for obsid %d', len(self.SC.stars), self.SC.obsid)
def test_agasc_id(radius=0.2, npointings=2, nstar_limit=5, agasc_file=None): ras, decs = random_ra_dec(npointings) for ra, dec in zip(ras, decs): print('ra, dec =', ra, dec) cone_stars = agasc.get_agasc_cone(ra, dec, radius=radius, agasc_file=agasc_file) if len(cone_stars) == 0: return cone_stars.sort('AGASC_ID') for agasc_id in cone_stars['AGASC_ID'][:nstar_limit]: print(' agasc_id =', agasc_id) star1 = agasc.get_star(agasc_id) star2 = mp_get_agascid(agasc_id) for colname in AGASC_COLNAMES: if star1[colname].dtype.kind == 'f': assert np.all(np.allclose(star1[colname], star2[colname])) else: assert star1[colname] == star2[colname]
def get_stars(starcat_time, quaternion, radius=1.5): import agasc from Ska.quatutil import radec2yagzag from chandra_aca.transform import yagzag_to_pixels stars = agasc.get_agasc_cone(quaternion.ra, quaternion.dec, radius=radius, date=starcat_time) 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'], quaternion) 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 return stars
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
def t_ccd_for_attitude(ra, dec, y_offset=0, z_offset=0, start='2014-09-01', stop='2015-12-31', outdir=None): # reset the caches at every new attitude global T_CCD_CACHE T_CCD_CACHE.clear() global CAT_CACHE CAT_CACHE.clear() global RI_CAT_CACHE RI_CAT_CACHE.clear() start = DateTime(start) stop = DateTime(stop) # set the agasc proper motion time to be in the middle of the # requested cycle lts_mid_time = start + (stop - start) / 2 # Get stars in this field cone_stars = agasc.get_agasc_cone(ra, dec, radius=1.5, date=lts_mid_time) if len(cone_stars) == 0: raise ValueError("No stars found in 1.5 degree radius of {} {}".format(ra, dec)) # get mag errs once for the field cone_stars['mag_one_sig_err'], cone_stars['mag_one_sig_err2'] = mini_sausage.get_mag_errs(cone_stars) # get a list of days days = start + np.arange(stop - start) all_rolls = {} temps = {} roll_indep_data = {} # loop over them to see which need data last_good_pitch = None last_good_day = None for day in days.date: day_pitch = Ska.Sun.pitch(ra, dec, time=day) if day_pitch < 46.4 or day_pitch > 170: temps["{}".format(day[0:8])] = { 'day': day[0:8], 'caldate': DateTime(day).caldate[4:9], 'pitch': day_pitch, 'nom_roll': np.nan, 'nom_t_ccd': np.nan, 'best_roll': np.nan, 'best_t_ccd': np.nan, 'nom_id_hash': '', 'best_id_hash': '', 'comment': ''} else: temps["{}".format(day[0:8])] = { 'day': day[0:8], 'caldate': DateTime(day).caldate[4:9], 'pitch': day_pitch} last_good_day = day last_good_pitch = day_pitch if last_good_day is not None: # Run the temperature thing once to see if this might be good for all rolls r_data_check = get_t_ccd_roll( ra, dec, y_offset, z_offset, last_good_pitch, time=last_good_day, cone_stars=cone_stars) # If it is roll independent, write out the star hashes here if r_data_check['roll_indep']: nom_t_ccd, nom_roll, nom_n_acq, nom_stars = r_data_check['nomdata'] best_t_ccd, best_roll, best_n_acq, best_stars = r_data_check['bestdata'] nom_id_hash = hashlib.md5(np.sort(nom_stars['AGASC_ID'])).hexdigest() best_id_hash = hashlib.md5(np.sort(best_stars['AGASC_ID'])).hexdigest() if not os.path.exists(os.path.join(outdir, "{}.html".format(nom_id_hash))): nom_stars.write(os.path.join(outdir, "{}.html".format(nom_id_hash)), format="jsviewer") if not os.path.exists(os.path.join(outdir, "{}.html".format(best_id_hash))): best_stars.write(os.path.join(outdir, "{}.html".format(best_id_hash)), format="jsviewer") for tday in temps: # If this has already been defined/done for this day, continue if 'nom_roll' in temps[tday]: continue # If roll independent copy in the value from that solution if r_data_check['roll_indep']: nom_t_ccd, nom_roll, nom_n_acq, nom_stars = r_data_check['nomdata'] best_t_ccd, best_roll, best_n_acq, best_stars = r_data_check['bestdata'] temps[tday].update({ 'nom_roll': nom_roll, 'nom_t_ccd': nom_t_ccd, 'best_roll': best_roll, 'best_t_ccd': best_t_ccd, 'nom_id_hash': nom_id_hash, 'best_id_hash': best_id_hash, 'comment': r_data_check['comment'], }) continue t_ccd_roll_data = get_t_ccd_roll( ra, dec, y_offset, z_offset, temps[tday]['pitch'], time=temps[tday]['day'], cone_stars=cone_stars) all_day_rolls = t_ccd_roll_data['rolls'] all_rolls.update(all_day_rolls) cone_stars = t_ccd_roll_data['cone_stars'] nom_t_ccd, nom_roll, nom_n_acq, nom_stars = t_ccd_roll_data['nomdata'] best_t_ccd, best_roll, best_n_acq, best_stars = t_ccd_roll_data['bestdata'] nom_id_hash = hashlib.md5(np.sort(nom_stars['AGASC_ID'])).hexdigest() best_id_hash = hashlib.md5(np.sort(best_stars['AGASC_ID'])).hexdigest() if not os.path.exists(os.path.join(outdir, "{}.html".format(nom_id_hash))): nom_stars.write(os.path.join(outdir, "{}.html".format(nom_id_hash)), format="jsviewer") if not os.path.exists(os.path.join(outdir, "{}.html".format(best_id_hash))): best_stars.write(os.path.join(outdir, "{}.html".format(best_id_hash)), format="jsviewer") temps[tday].update({ 'nom_roll': nom_roll, 'nom_t_ccd': nom_t_ccd, 'best_roll': best_roll, 'best_t_ccd': best_t_ccd, 'nom_id_hash': nom_id_hash, 'best_id_hash': best_id_hash, 'comment': t_ccd_roll_data['comment'] }) t_ccd_table = Table(temps.values())['day', 'caldate', 'pitch', 'nom_roll', 'nom_t_ccd', 'best_roll', 'best_t_ccd', 'nom_id_hash', 'best_id_hash', 'comment'] t_ccd_table.sort('day') t_ccd_roll = None if len(all_rolls) > 0: t_ccd_roll = Table(rows=all_rolls.items(), names=('roll', 't_ccd')) t_ccd_roll.sort('roll') return t_ccd_table, t_ccd_roll
# Licensed under a 3-clause BSD style license - see LICENSE.rst import sys from itertools import count import time import numpy as np import agasc def random_ra_dec(nsample): x = np.random.uniform(-0.98, 0.98, size=nsample) ras = 360 * np.random.random(nsample) decs = np.degrees(np.arcsin(x)) return ras, decs radius = 2.0 nsample = 200 ras, decs = random_ra_dec(nsample) print 'get_agasc_cone' t0 = time.time() for ra, dec, cnt in zip(ras, decs, count()): x = agasc.get_agasc_cone(ra, dec, radius=radius, agasc_file='miniagasc.h5') print cnt, len(ras), '\r', sys.stdout.flush() print print time.time() - t0
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 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(). :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) fig = plt.figure(figsize=(5.325, 5.325)) ax = fig.add_subplot(1, 1, 1) plt.subplots_adjust(top=0.95) ax.set_aspect('equal') # plot the box and set the labels plt.xlim(2900, -2900) plt.ylim(-2900, 2900) b1hw = 2560 box1 = plt.Rectangle((b1hw, -b1hw), -2 * b1hw, 2 * b1hw, fill=False) ax.add_patch(box1) b2w = 2600 box2 = plt.Rectangle((b2w, -b1hw), -4 + -2 * b2w, 2 * b1hw, fill=False) ax.add_patch(box2) ax.scatter([-2700, -2700, -2700, -2700, -2700], [2400, 2100, 1800, 1500, 1200], c='orange', edgecolors='none', s=symsize(np.array([10.0, 9.0, 8.0, 7.0, 6.0]))) [l.set_rotation(90) for l in ax.get_yticklabels()] ax.grid(grid) ax.set_ylabel("Zag (arcsec)") ax.set_xlabel("Yag (arcsec)") if quad_bound: pix_range = np.linspace(-510, 510, 50) minus_half_pix = -0.5 * np.ones_like(pix_range) # plot the row = -0.5 line yag, zag = pixels_to_yagzag(minus_half_pix, pix_range) ax.plot(yag, zag, color='magenta', alpha=.4) # plot the col = -0.5 line yag, zag = pixels_to_yagzag(pix_range, minus_half_pix) ax.plot(yag, zag, color='magenta', alpha=.4) # 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) if title is not None: fig.suptitle(title, fontsize='small') return fig
agasc1p7 = str(Path(os.environ['SKA'], 'data', 'agasc', 'agasc1p7.h5')) h5 = tables.open_file(agasc1p7) stars = h5.root.data[:] h5.close() ok = ((stars['CLASS'] == 0) & (stars['MAG_ACA'] < 11.0) & (stars['ASPQ1'] < 50) & # Less than 2.5 arcsec from nearby star (stars['ASPQ1'] > 0) & (stars['ASPQ2'] == 0) # Proper motion less than 0.5 arcsec/yr ) # Candidate acq/guide stars with a near neighbor that made ASPQ1 > 0 nears = stars[ok] radius = 60 / 3600 near_ids = set() for ii, sp in enumerate(nears): near = agasc.get_agasc_cone(sp['RA'], sp['DEC'], radius=radius, date='2000:001', agasc_file=agasc1p7) for id in near['AGASC_ID']: if id != sp['AGASC_ID']: near_ids.add(id) if ii % 100 == 0: print(ii) t = Table([list(near_ids)], names=['near_id']) t.write('near_neighbor_ids_1p7.fits.gz', format='fits')