def __init__(self, msids, start, stop): super(MSIDset, self).__init__() self.tstart = DateTime(start).secs self.tstop = DateTime(stop).secs self.datestart = DateTime(self.tstart).date self.datestop = DateTime(self.tstop).date slot_datas = {} slots = set(slot_for_msid(confirm_msid(msid)) for msid in msids) for slot in slots: # get the 8x8 data tstop = self.tstop + 33.0 # Major frame of padding slot_data = aca_l0.get_slot_data( self.tstart, tstop, slot, imgsize=[8], columns=ACA_DTYPE_NAMES) # Find samples where the time stamp changes by a value other than 4.1 secs # (which is the value for 8x8 readouts). In that case there must have been a # break in L0 decom, typically due to a change to 4x4 or 6x6 data. # t[0] = 1.0 # t[1] = 5.1 <= This record could be bad, as indicated by the gap afterward # t[2, 3] = 17.4, 21.5 # To form the time diffs first add `tstop` to the end so that if 8x8 data # does not extend through `tstop` then the last record gets chopped. dt = np.diff(np.concatenate([slot_data['TIME'], [tstop]])) bad = np.abs(dt - 4.1) > 1e-3 slot_data[bad] = ma.masked # Chop off the padding i_stop = np.searchsorted(slot_data['TIME'], self.tstop, side='right') slot_data = slot_data[:i_stop] # explicitly unmask useful columns slot_data['TIME'].mask = ma.nomask slot_data['IMGSIZE'].mask = ma.nomask slot_data['FILENAME'].mask = ma.nomask slot_datas[slot] = slot_data # make a shared time ndarray that is the union of the time sets in the # slots. The ACA L0 telemetry has the same timestamps across slots, # so the only differences here are caused by different times in # non-TRAK across the slots (usually SRCH differences at the beginning # of the observation) shared_time = np.unique(np.concatenate([ slot_datas[slot]['TIME'].data for slot in slots])) for msid in msids: hdr3_msid = confirm_msid(msid) slot = slot_for_msid(hdr3_msid) full_data = ma.zeros(len(shared_time), dtype=slot_datas[slot].dtype) full_data.mask = ma.masked fd_idx = search_both_sorted(shared_time, slot_datas[slot]['TIME']) full_data[fd_idx] = slot_datas[slot] # make a data dictionary to feed to the MSID constructor slot_data = {'vals': HDR3_DEF[hdr3_msid]['value'](full_data), 'desc': HDR3_DEF[hdr3_msid]['desc'], 'longdesc': HDR3_DEF[hdr3_msid]['longdesc'], 'times': shared_time, 'hdr3_msid': hdr3_msid} self[msid] = MSID(msid, start, stop, slot_data)
def get_slot_image_data(start, stop, slot): slot_data = aca_l0.get_slot_data( start, stop, imgsize=[4, 6, 8], slot=slot, columns=['TIME', 'BGDAVG', 'IMGFUNC1', 'QUALITY', 'IMGSIZE']) return Table(slot_data)
def plot_bgd(e, edir): """ Make a plot of BGDAVG over an event and save to `edir`. Presently plots over range from 100 seconds before high threshold crossing to 300 seconds after high threshold crossing. :param e: dictionary with times of background event :param edir: directory for plots """ slots = [int(s) for s in e['slots_for_sum'].split(',')] plt.figure(figsize=(4, 4.5)) max_bgd = 0 for slot in slots: l0_telem = aca_l0.get_slot_data(e['cross_time'] - 100, e['cross_time'] + 300, imgsize=[4, 6, 8], slot=slot) if len(l0_telem['TIME']) == 0: raise ValueError ok = (l0_telem['QUALITY'] == 0) & (l0_telem['IMGFUNC1'] == 1) if np.count_nonzero(ok) > 0: plot_cxctime(l0_telem['TIME'][ok], l0_telem['BGDAVG'][ok], '.', label=f'slot {slot}') max_bgd = max([max_bgd, np.max(l0_telem['BGDAVG'][ok])]) plt.title("Hi BGD obsid {}\n start {}".format( e['obsid'], DateTime(e['event_tstart']).date), fontsize='small') plt.legend(numpoints=1, fontsize='x-small') plt.tight_layout() plt.margins(.05) plt.ylim([-20, 1100]) plt.grid() filename = "bgdavg_{}.png".format(e['event_datestart']) plt.savefig(os.path.join(edir, filename)) plt.close() return filename, max_bgd
def test_get_slot_data_8x8(): """ Do a validation test of get_l0_images: - Get 20 mins of image data for slot 6 of obsid 8008 (very nice clean stars) - Do first moment centroids in row and col - Compare to aspect pipeline FM centroids for same slot data This is a deep test that all the signs are right. If not then everything breaks badly because the star image doesn't move in sync with row0, col0. """ start = '2007:002:06:00:00' stop = '2007:002:06:20:00' slot_data = aca_l0.get_slot_data(start, stop, slot=6, centered_8x8=True) files = asp_l1.get_files(8008, content=['ACACENT']) acen = Table.read(files[0]) # Pick FM centroids for slot 6 ok = (acen['alg'] == 1) & (acen['slot'] == 6) acen = acen[ok] # Row and col centroids times = slot_data['TIME'] # Easy way to do FM centroids with mgrid rw, cw = np.mgrid[0:8, 0:8] img_raw = slot_data['IMGRAW'] # np.round(slot_data['IMGRAW']).astype(int) norm = np.sum(img_raw, axis=(1, 2)) rcs = np.sum(img_raw * rw, axis=(1, 2)) / norm + slot_data['IMGROW0'] - 1 ccs = np.sum(img_raw * cw, axis=(1, 2)) / norm + slot_data['IMGCOL0'] - 1 rcen = interpolate(acen['cent_i'], acen['time'], times) ccen = interpolate(acen['cent_j'], acen['time'], times) assert np.all(np.abs(rcen - rcs) < 0.05) assert np.all(np.abs(ccen - ccs) < 0.05)
def make_images(start, stop, outdir='out', max_images=200): """ Make pixel plots of the a time range and write out to a directory. :param start: start of time range (Chandra.Time compatible) :param stop: end of time range (Chandra.Time compatible) :param outdir: output directory :param max_images: stop making image files if more more than this number have been made """ start = DateTime(start) stop = DateTime(stop) slotdata = {} for slot in range(8): slotdata[slot] = Table( aca_l0.get_slot_data(start.secs - 20, stop.secs + 20, slot=slot).data) slotdata[slot]['SLOT'] = slot # Get a list of all the unique times in the set times = np.unique( np.concatenate([slotdata[slot]['TIME'].data for slot in range(8)])) times = times[(times >= (start.secs - 4.5)) & (times <= (stop.secs + 4.5))] SIZE = 96 rows = [] for time in times: row = {'rowsecs': time, 'rowdate': DateTime(time).date, 'slots': []} slot_imgs = [] for slot in range(8): # Find last complete row at or before this time last_idx = np.flatnonzero(slotdata[slot]['TIME'] <= time)[-1] dat = slotdata[slot][last_idx] imgraw = dat['IMGRAW'].reshape(8, 8) sz = dat['IMGSIZE'] if sz < 8: imgraw = imgraw[:sz, :sz] imgraw = np.clip(imgraw, a_min=10, a_max=None) if np.all(imgraw == 10) or dat['IMGFUNC1'] != 1: pixvals = np.zeros((sz, sz)) np.fill_diagonal(pixvals, 255) else: # Log scale the images but use a fixed low end at 4 logimg = np.log(imgraw) pixvals = 255 * (logimg - 4) / (np.max(logimg) - 4) # Scale the image because the browser isn't great at it pixvals = np.kron(pixvals, np.ones( (int(SIZE / sz), int(SIZE / sz)))) # Set a border for stale data img = (255 * np.ones( (108, 108)) if dat['TIME'] < row['rowsecs'] else np.zeros( (108, 108))) img[6:102, 6:102] = pixvals slot_imgs.append(img) # bgcolor = 'gray' if dat['TIME'] < row['rowsecs'] else 'white' row['slots'].append({ 'stale': (dat['TIME'] < row['rowsecs']), 'slot': slot, 'time': dat['TIME'], 'rowsecs': row['rowsecs'], 'bgdavg': dat['BGDAVG'], 'imgfunc1': dat['IMGFUNC1'], }) im = Image.fromarray(np.hstack(slot_imgs)).convert('RGB') imgfilename = "piximg_{}.png".format(row['rowsecs']) im.save(os.path.join(outdir, imgfilename), "PNG") row['img'] = imgfilename rows.append(row) if len(rows) > max_images: break return rows