def get_fitting_data(self, start, stop): tstart = date2secs(start) tstop = date2secs(stop) times = self._eng_match_times(tstart, tstop, 328.0) msids = [self.msid] + [ data_map[input] for input in self.inputs if input not in pwr_states ] msids += ['solarephem0_{}'.format(ax) for ax in "xyz"] data = fetch.MSIDset(msids, start, stop, stat='5min', filter_bad=True) data.interpolate(times=times) msid_vals = Ska.Numpy.smooth(data[self.msid].vals, 10) sun_eci = np.array([ data['solarephem0_x'].vals, data['solarephem0_y'].vals, data['solarephem0_z'].vals ]) d_sun = np.sqrt((sun_eci**2).sum(axis=0)) states = self.get_cmd_states(data.datestart, data.datestop, times) combined_dict = { 'msid_times': times, 'msid_vals': msid_vals, 'd_sun': d_sun } for input in self.inputs: if input in data_map: combined_dict[input] = data[data_map[input]].vals elif input in states.dtype.names: combined_dict[input] = states[input] return pd.DataFrame(combined_dict)
def _get_ephemeris(self, tstart, tstop, times): msids = ['orbitephem0_{}'.format(axis) for axis in "xyz"] msids += ['solarephem0_{}'.format(axis) for axis in "xyz"] ephem = {} if self.ephem_file is None: e = fetch.MSIDset(msids, tstart - 2000.0, tstop + 2000.0) for msid in msids: ephem[msid] = Ska.Numpy.interpolate(e[msid].vals, e[msid].times, times) else: e = ascii.read(self.ephem_file) msids = ['orbitephem0_{}'.format(axis) for axis in "xyz"] idxs = np.logical_and(e["times"] >= tstart - 2000.0, e["times"] <= tstop + 2000.0) for msid in msids: ephem[msid] = Ska.Numpy.interpolate(e[msid][idxs], e["times"][idxs], times) return ephem
def from_database(cls, msids, tstart, tstop=None, filter_bad=False, stat='5min', interpolate=None, interpolate_times=None): tstart = get_time(tstart) tstop = get_time(tstop) msids = ensure_list(msids) msids, derived_msids = check_depends(msids) msids = [msid.lower() for msid in msids] data = fetch.MSIDset(msids, tstart, stop=tstop, filter_bad=filter_bad, stat=stat) table = {} times = {} state_codes = {} masks = {} if interpolate is not None: if interpolate_times is None: # Get the nominal tstart / tstop range max_fetch_tstart = max(msid.times[0] for msid in data.values()) min_fetch_tstop = min(msid.times[-1] for msid in data.values()) dt = 328.0 start = DateTime(tstart).secs if tstart else data.tstart stop = DateTime(tstop).secs if tstop else data.tstop start = max(start, max_fetch_tstart) stop = min(stop, min_fetch_tstop) interpolate_times = np.arange((stop - start) // dt + 1) * dt + start else: interpolate_times = DateTime(interpolate_times).secs for k, msid in data.items(): if interpolate is not None: indexes = Ska.Numpy.interpolate(np.arange(len(msid.times)), msid.times, interpolate_times, method=interpolate, sorted=True) times[k.lower()] = interpolate_times else: indexes = slice(None, None, None) times[k.lower()] = data[k].times if msid.state_codes: state_codes[k] = dict((k, v) for v, k in msid.state_codes) table[k.lower()] = msid.vals[indexes] if msid.bads is not None: masks[k.lower()] = (~msid.bads)[indexes] return cls(table, times, state_codes=state_codes, masks=masks, derived_msids=derived_msids)
def get_fitting_data(self, start, stop): msids = [self.msid] + [ data_map[input] for input in self.inputs if input not in acis_states ] data = fetch.MSIDset(msids, start, stop, stat='5min', filter_bad=True) data.interpolate(times=data["DP_PITCH"].times) states = self.get_cmd_states(data.datestart, data.datestop, data[self.msid].times) combined_dict = { 'msid_times': data[self.msid].times, 'msid_vals': data[self.msid].vals, 'phase': make_phase(data[self.msid].times) } for input in self.inputs: if input in data_map: combined_dict[input] = data[data_map[input]].vals elif input in states.dtype.names: combined_dict[input] = states[input] return combined_dict
def calc_perigee_map(start='2010:114:20:00:00', stop='2010:117:16:00:00', ngrid=50): # Get orbital ephemeris in requested time range print('Fetching ephemeris') objs = ('orbit', 'lunar', 'solar') axes = ('x', 'y', 'z') msids = [ '{0}ephem0_{1}'.format(obj, axis) for obj in objs for axis in axes ] ephems = fetch.MSIDset(msids, start, stop) times = ephems[msids[0]].times.copy() n_ephem = len(ephems[msids[0]].vals) if any(len(ephems[msid].vals) != n_ephem for msid in msids): raise ValueError('Unexpected mismatch in ephemeris telemetry sampling') ephem_xyzs = {} for obj in ('orbit', 'lunar', 'solar'): msids = ('{0}ephem0_{1}'.format(obj, axis) for axis in axes) ephem_xyzs[obj] = np.array([ephems[msid].vals for msid in msids]) illum_maps = [] illum_idxs = [] antisun, xs, ys = get_antisun_grid(ngrid) antisun_pitches, phis = antisun.img2polar(xs, ys) for i_ephem, ephem_xyz in enumerate(ephem_xyzs['orbit'].transpose()): # Calculate a grid of attitude vectors centered on the anti-sun line and extending # from sun-pitch=180 (center) to sun-pitch=45 (edge). orbit_r = np.sqrt(np.sum(ephem_xyzs['orbit'][:, i_ephem]**2)) if orbit_r > 50000e3: continue sun_eci = ephem_xyzs['solar'][:, i_ephem] - ephem_xyzs['orbit'][:, i_ephem] att_vecs = antisun.img2eci(xs, ys, sun_eci) ras, decs = Ska.quatutil.eci2radec(att_vecs) illum_map = np.zeros((ngrid, ngrid), dtype=np.float32) print(i_ephem, n_ephem, ephem_xyz) for iy in range(ngrid): for ix in range(ngrid): i_vec = iy * ngrid + ix if antisun_pitches[i_vec] < 135: ra, dec = ras[i_vec], decs[i_vec] roll = Ska.Sun.nominal_roll(ra, dec, times[i_ephem]) _, att_illums, _ = acis_taco.calc_earth_vis( ephem_xyz, [ra, dec, roll], max_reflect=5) illum = sum(att_illums) else: illum = 0.0 illum_map[iy, ix] = illum illum_idxs.append(i_ephem) illum_maps.append(illum_map) # debug_here() return dict( illums=np.array(illum_maps), illum_idxs=np.array(illum_idxs), times=times, antisun=antisun, ephem_xyzs=ephem_xyzs, )
def make_thermal_plots( counter=None, fig_save_directory='/proj/web-icxc/htdocs/hrcops/hrcmonitor/plots/'): # Fetch all MSIDs msids_daily = fetch.Msidset(monitor_temperature_msids, start='2001:001', stat='daily', filter_bad=True) msids_5min = fetch.MSIDset(monitor_temperature_msids, start='2001:001', stat='5min', filter_bad=True) ave_table = Table( ) # Instantiate an empty AstroPy table that we can later sort daybin = 100 # The number of days over which we'll compute the rolling average all_names = [] all_means = [] all_stds = [] for msid in monitor_temperature_msids: mean = np.mean(msids_daily[msid].means[-daybin:]).round(2) std = np.std(msids_daily[msid].stds[-daybin:]).round(2) all_names.append(msid) all_means.append(mean) all_stds.append(std) ave_table["MSID"] = all_names ave_table["{} Day Average".format(daybin)] = all_means ave_table["Standard Deviation"] = all_stds ave_table.sort("{} Day Average".format(daybin)) ordered_msidlist = ave_table["MSID"] window = 365 # days, i.e. a year # Because this funtion will cut off the first 364 datapoints if your window is 365 days time_corrector = window - 1 all_trends = {} for msid in ordered_msidlist: moving_aves = compute_yearly_average(msids_daily[msid].means, window) moving_stds = compute_yearly_average(msids_daily[msid].stds, window) all_trends["{}_trend".format(msid)] = moving_aves all_trends["{}_stds".format(msid)] = moving_stds # Make Figure 1 # Make this True to ensure the file size is small. Otherwise you're plotting thousands of vector points. rasterized = True fig, ax = plt.subplots(figsize=(16, 8)) n_lines = len(ordered_msidlist) color_idx = np.linspace(0, 1, n_lines) for i, msid in zip(color_idx, ordered_msidlist): print('Plotting daily thermals for {}'.format(msid), end='\r', flush=True) # Clear the command line manually sys.stdout.write("\033[K") ax.plot_date(convert_chandra_time(msids_daily[msid].times), msids_daily[msid].means, '.', alpha=1.0, markersize=2.5, label='{}'.format(msid), color=plt.cm.RdYlBu_r(i), rasterized=rasterized) # Draw a large point line where the current data point is with fetch.data_source('maude'): latest_datapoint = fetch.Msid(msid, start='2020:340') ax.plot_date(convert_chandra_time(latest_datapoint.times)[-1], latest_datapoint.vals[-1], markersize=8, color=plt.cm.RdYlBu_r(i), rasterized=rasterized, zorder=4) ax.set_ylabel("Temperature (C)", fontsize=10) ax.set_xlabel("Date", fontsize=10) plt.xticks(fontsize=10) plt.yticks(fontsize=10) ax.set_ylim(0, 40) # ax.set_xlim(dt.date(2018, 10, 6), dt.date(2018, 10, 30)) if counter is not None: ax.set_title( 'HRC Thermistor MSIDs (Daily Means) | Updated as of {} EST'.format( dt.datetime.now().strftime("%Y-%b-%d %H:%M:%S")), color='slategray', size=10) else: ax.set_title( "HRC Thermistor Temperatures (Daily Averages) Over the Mission Lifetime", color='slategray', size=6) # ax.legend() # ax.set_ylim(10, 40) ax.legend(prop={'size': 13}, loc='center left', bbox_to_anchor=(1, 0.5)) # ax.legend(loc=2, prop={'size': 13}) ax.axvline(dt.datetime.now(pytz.utc), color='gray', alpha=0.5) ax.text(dt.datetime.now(pytz.utc), ax.get_ylim()[1] + 0.3, 'Now', fontsize=10, color='slategray') fig.savefig(fig_save_directory + 'thermals.png', dpi=300, bbox_inches='tight') fig.savefig(fig_save_directory + 'thermals.pdf', dpi=300, bbox_inches='tight') plt.close() # Make Figure 2 fetch.data_source.set('cxc') fig, ax = plt.subplots(figsize=(17, 8)) n_lines = len(ordered_msidlist) color_idx = np.linspace(0, 1, n_lines) for i, msid in zip(color_idx, ordered_msidlist): print('Plotting thermal trends for {}'.format(msid), end='\r', flush=True) # Clear the command line manually sys.stdout.write("\033[K") times = convert_chandra_time(msids_daily[msid].times) # ax.plot(all_trends["{}_trend".format(msidname)], lw=3.0, label=msidname, color=plt.cm.coolwarm(i)) ax.plot_date(times[time_corrector:], all_trends["{}_trend".format(msid)], '-', label='{}'.format(msid), lw=3.0, color=plt.cm.RdYlBu_r(i), rasterized=rasterized) ax.fill_between(times[time_corrector:], all_trends["{}_trend".format(msid)] + all_trends["{}_stds".format(msid)], all_trends["{}_trend".format(msid)] - all_trends["{}_stds".format(msid)], facecolor='gray', alpha=0.4) # Draw a large point line where the current data point is with fetch.data_source('maude'): latest_datapoint = fetch.Msid(msid, start='2020:340') ax.plot_date(convert_chandra_time(latest_datapoint.times)[-1], latest_datapoint.vals[-1], markersize=8, color=plt.cm.RdYlBu_r(i), rasterized=rasterized, zorder=4) ax.legend(prop={'size': 13}, loc='center left', bbox_to_anchor=(1, 0.5)) # plt.legend(title='title', bbox_to_anchor=(1.05, 1), loc='upper left') if counter is not None: ax.set_title( 'Moving Average Thermal Trends | Updated as of {} EST'.format( dt.datetime.now().strftime("%Y-%b-%d %H:%M:%S")), color='slategray', size=10) else: ax.set_title( "HRC Thermistor Temperatures (Moving Averages) Over the Mission Lifetime", color='slategray', size=6) ax.set_ylabel("Temperature (C)", fontsize=10) ax.set_xlabel("Date", fontsize=10) plt.xticks(fontsize=10) plt.yticks(fontsize=10) ax.axvline(dt.datetime.now(pytz.utc), color='gray', alpha=0.5) ax.text(dt.datetime.now(pytz.utc), ax.get_ylim()[1] + 0.3, 'Now', fontsize=10, color='slategray') ax.set_xlim(dt.datetime(2001, 1, 1), dt.datetime(2022, 1, 1)) fig.savefig(fig_save_directory + 'thermal_trends.png', dpi=300, bbox_inches='tight') fig.savefig(fig_save_directory + 'thermal_trends.pdf', dpi=300, bbox_inches='tight') plt.close()
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)