def run_cmds(cmds, or_list_file=None, ofls_characteristics_file=None, initial_state=None): obsreqs = parse_cm.read_or_list(or_list_file) if or_list_file else None if ofls_characteristics_file: odb_si_align = parse_cm.read_characteristics(ofls_characteristics_file, item="ODB_SI_ALIGN") characteristics = {"odb_si_align": odb_si_align} else: characteristics = None sc = Spacecraft(cmds, obsreqs, characteristics, initial_state) sc.run() return sc
def get_ccd_temps(oflsdir, outdir='out', json_obsids=sys.stdin, model_spec=None, char_file=None, orlist=None, verbose=1, **kwargs): """ Using the cmds and cmd_states sybase databases, available telemetry, and the pitches determined from the planning products, calculate xija ACA model temperatures for the given week. :param oflsdir: products directory :param outdir: output directory for plots :param json_obsids: file-like object or string containing JSON of starcheck Obsid objects :param model_spec: xija ACA model specification :param verbose: Verbosity (0=quiet, 1=normal, 2=debug) :returns: JSON dictionary of labeled dwell intervals with max temperatures """ if not os.path.exists(outdir): os.mkdir(outdir) config_logging(outdir, verbose) # Store info relevant to processing for use in outputs proc = {'run_user': os.environ['USER'], 'run_time': time.ctime(), 'errors': []} logger.info('##############################' '#######################################') logger.info('# %s run at %s by %s' % (TASK_NAME, proc['run_time'], proc['run_user'])) logger.info('# {} version = {}'.format(TASK_NAME, VERSION)) logger.info('###############################' '######################################\n') # load more general starcheck characteristics to get red/yellow limits char = yaml.load(open(char_file)) # save spec file in out directory shutil.copy(model_spec, outdir) # json_obsids can be either a string or a file-like object. Try those options in order. try: sc_obsids = json.loads(json_obsids) except TypeError: sc_obsids = json.load(json_obsids) tnow = DateTime().secs # Get tstart, tstop, commands from backstop file in opt.oflsdir bs_cmds = get_bs_cmds(oflsdir) tstart = bs_cmds[0]['time'] tstop = bs_cmds[-1]['time'] proc['datestart'] = DateTime(tstart).date proc['datestop'] = DateTime(tstop).date # Get temperature telemetry for 30 days prior to min(tstart, NOW) tlm = get_telem_values(min(tstart, tnow), ['aacccdpt', 'pitch'], days=30) states = get_week_states(tstart, tstop, bs_cmds, tlm) # if the last obsid interval extends over the end of states # extend the state / predictions if ((states[-1]['obsid'] == sc_obsids[-1]['obsid']) & (sc_obsids[-1]['obs_tstop'] > states[-1]['tstop'])): tstop = sc_obsids[-1]['obs_tstop'] states[-1]['tstop'] = sc_obsids[-1]['obs_tstop'] states[-1]['datestop'] = DateTime(sc_obsids[-1]['obs_tstop']).date if tstart > DateTime(MODEL_VALID_FROM).secs: times, ccd_temp = make_week_predict(model_spec, states, tstop) else: times, ccd_temp = mock_telem_predict(states) make_check_plots(outdir, states, times, ccd_temp, tstart, tstop, char=char) intervals = get_obs_intervals(sc_obsids) obsreqs = None if orlist is None else {obs['obsid']: obs for obs in read_or_list(orlist)} obstemps = get_interval_data(intervals, times, ccd_temp, obsreqs) return json.dumps(obstemps, sort_keys=True, indent=4, cls=NumpyAwareJSONEncoder)
def make_pcad_attitude_check_report(backstop_file, or_list_file=None, mm_file=None, simtrans_file=None, simfocus_file=None, ofls_characteristics_file=None, out=None, dynamic_offsets_file=None, ): """ Make a report for checking PCAD attitudes """ all_ok = True lines = [] # output report lines mm = read_maneuver_summary(mm_file) q = [mm[0][key] for key in ['q1_0', 'q2_0', 'q3_0', 'q4_0']] bs = read_backstop(backstop_file) simfa_time, simfa = recent_sim_history(DateTime(bs[0]['date']).secs, simfocus_file) simpos_time, simpos = recent_sim_history(DateTime(bs[0]['date']).secs, simtrans_file) initial_state = {'q_att': q, 'simpos': simpos, 'simfa_pos': simfa} or_list = None if or_list_file is None else read_or_list(or_list_file) if or_list is None: lines.append('ERROR: No OR list provided, cannot check attitudes') all_ok = False # If dynamical offsets file is available then load was planned using # Matlab tools 2016_210 later, which implements the "Cycle 18 aimpoint # transition plan". This code injects new OR list attributes for the # dynamical offset. if dynamic_offsets_file is not None and or_list is not None: # Existing OFLS characteristics file is not relevant for post 2016_210. # Products are planned using the Matlab tools SI align which matches the # baseline mission align matrix from pre-November 2015. ofls_characteristics_file = None lines.append('INFO: using dynamic offsets file {}'.format(dynamic_offsets_file)) or_map = {or_['obsid']: or_ for or_ in or_list} doffs = Table.read(dynamic_offsets_file, format='ascii.basic', guess=False) for doff in doffs: obsid = doff['obsid'] if obsid in or_map: or_map[obsid]['aca_offset_y'] = doff['aca_offset_y'] / 3600. or_map[obsid]['aca_offset_z'] = doff['aca_offset_z'] / 3600. # Check that obsids in dynamic offsets table are all in OR list if not set(doffs['obsid']).issubset(set(or_map)): all_ok = False obsid_mismatch = set(doffs['obsid']) - set(or_map) lines.append('WARNING: Obsid in dynamic offsets table but missing in OR list {}' .format(list(obsid_mismatch))) # Run the commands and populate attributes in `sc`, the spacecraft state. # In particular sc.checks is a dict of checks by obsid. # Any state value (e.g. obsid or q_att) has a corresponding plural that # gives the history of updates as a dict with a `value` and `date` key. sc = hopper.run_cmds(backstop_file, or_list, ofls_characteristics_file, initial_state=initial_state) # Iterate through obsids in order obsids = [obj['value'] for obj in sc.obsids] for obsid in obsids: if obsid not in sc.checks: continue checks = sc.checks[obsid] for check in checks: if check['name'] == 'CheckObsreqTargetFromPcad': ok = check['ok'] all_ok &= ok if check.get('skip'): message = 'SKIPPED: {}'.format(check['message']) else: message = 'OK' if ok else check['message'] line = '{:5d}: {}'.format(obsid, message) lines.append(line) if out is not None: with open(out, 'w') as fh: fh.writelines("\n".join(lines)) return all_ok
def make_pcad_attitude_check_report(backstop_file, or_list_file=None, attitude_file=None, simtrans_file=None, simfocus_file=None, ofls_characteristics_file=None, out=None, dynamic_offsets_file=None, ): """ Make a report for checking PCAD attitudes """ all_ok = True lines = [] # output report lines bs = read_backstop(backstop_file) # Get initial state attitude and sim position from history att_time, q1, q2, q3, q4 = recent_attitude_history(DateTime(bs[0]['date']).secs, attitude_file) q = Quaternion.normalize([q1, q2, q3, q4]) simfa_time, simfa = recent_sim_history(DateTime(bs[0]['date']).secs, simfocus_file) simpos_time, simpos = recent_sim_history(DateTime(bs[0]['date']).secs, simtrans_file) initial_state = {'q1': q[0], 'q2': q[1], 'q3': q[2], 'q4': q[3], 'simpos': simpos, 'simfa_pos': simfa} or_list = None if or_list_file is None else read_or_list(or_list_file) if or_list is None: lines.append('ERROR: No OR list provided, cannot check attitudes') all_ok = False # If dynamical offsets file is available then load was planned using # Matlab tools 2016_210 later, which implements the "Cycle 18 aimpoint # transition plan". This code injects new OR list attributes for the # dynamical offset. if dynamic_offsets_file is not None and or_list is not None: # Existing OFLS characteristics file is not relevant for post 2016_210. # Products are planned using the Matlab tools SI align which matches the # baseline mission align matrix from pre-November 2015. ofls_characteristics_file = None lines.append('INFO: using dynamic offsets file {}'.format(dynamic_offsets_file)) or_map = {or_['obsid']: or_ for or_ in or_list} doffs = Table.read(dynamic_offsets_file, format='ascii.basic', guess=False) for doff in doffs: obsid = doff['obsid'] if obsid in or_map: or_map[obsid]['aca_offset_y'] = doff['aca_offset_y'] / 3600. or_map[obsid]['aca_offset_z'] = doff['aca_offset_z'] / 3600. # Check that obsids in dynamic offsets table are all in OR list if not set(doffs['obsid']).issubset(set(or_map)): all_ok = False obsid_mismatch = set(doffs['obsid']) - set(or_map) lines.append('WARNING: Obsid in dynamic offsets table but missing in OR list {}' .format(list(obsid_mismatch))) # Run the commands and populate attributes in `sc`, the spacecraft state. # In particular sc.checks is a dict of checks by obsid. # Any state value (e.g. obsid or q_att) has a corresponding plural that # gives the history of updates as a dict with a `value` and `date` key. sc = hopper.run_cmds(backstop_file, or_list, ofls_characteristics_file, initial_state=initial_state, starcheck=True) # Iterate through checks by obsid to print status checks = sc.get_checks_by_obsid() for obsid in sc.obsids: for check in checks[obsid]: if check.name == 'attitude_consistent_with_obsreq': ok = check.success all_ok &= ok if check.not_applicable: message = 'SKIPPED: {}'.format(":".join(check.infos)) else: message = 'OK' if ok else "ERROR: {}".format(":".join(check.errors)) line = '{:5d}: {}'.format(obsid, message) lines.append(line) if out is not None: with open(out, 'w') as fh: fh.writelines("\n".join(lines)) return all_ok