Esempio n. 1
0
def test_sun_vec_versus_telemetry():
    """
    Test sun vector values `pitch` and `off_nominal_roll` versus flight telem.  Include
    Load maneuver at 2017:349:20:52:37.719 in DEC1117 with large pitch and
    off_nominal_roll change (from around zero to -17 deg).

    State values are within 1.5 degrees of telemetry.
    """

    state_keys = ['pitch', 'off_nom_roll']
    start, stop = '2017:349:10:00:00', '2017:350:10:00:00'
    cmds = commands.get_cmds(start, stop)
    rk = states.get_states(state_keys=state_keys,
                           cmds=cmds,
                           merge_identical=True)[-20:-1]

    tstart = DateTime(rk['datestart']).secs
    tstop = DateTime(rk['datestop']).secs
    tmid = (tstart + tstop) / 2

    # Pitch from telemetry
    dat = fetch.Msid('pitch', tstart[0] - 100, tstop[-1] + 100)
    dat.interpolate(times=tmid)
    delta = np.abs(dat.vals - rk['pitch'])
    assert np.max(rk['pitch']) - np.min(rk['pitch']) > 75  # Big maneuver
    assert np.all(delta < 1.5)

    # Off nominal roll (not roll from ra,dec,roll) from telemetry
    dat = fetch.Msid('roll', tstart[0] - 100, tstop[-1] + 100)
    dat.interpolate(times=tmid)
    delta = np.abs(dat.vals - rk['off_nom_roll'])
    assert np.max(rk['off_nom_roll']) - np.min(
        rk['off_nom_roll']) > 20  # Large range
    assert np.all(delta < 1.5)
Esempio n. 2
0
def compare_msid(msid, stat):
    """
    Compare ``stat`` data for ``msid``: locally generated vs. flight in /proj/sot/ska.
    """
    # Start with the local version which is generated over a small slice of time
    # (a few days).
    fetch.msid_files.basedir = os.getcwd()
    local = fetch.Msid(msid, opt.start, opt.stop, stat=stat)

    # Now use definitive Ska flight data as reference for comparison.
    # Fetch over an interval which is just slightly longer.
    tstart = local.times[0] - 0.0001
    tstop = local.times[-1] + 0.0001
    fetch.msid_files.basedir = os.path.join(opt.flight_root, 'data',
                                            'eng_archive')
    flight = fetch.Msid(msid, tstart, tstop, stat=stat)

    fails = []

    if len(local) != len(flight):
        fails.append(' length local:{} flight{}'.format(
            len(local), len(flight)))
    else:
        for colname in local.colnames:
            local_value = getattr(local, colname)
            flight_value = getattr(flight, colname)

            # Do not explicitly test bads, this is done implicitly by virtue of
            # the bad filtering already applied.
            if colname == 'bads':
                continue

            # Extend the colname for reporting purposes
            if stat:
                colname = colname + '[{}]'.format(stat)

            # Check dtype equality
            if local_value.dtype != flight_value.dtype:
                fails.append('.{} dtype local:{} flight{}'.format(
                    colname, local.dtype, flight.dtype))
                continue

            # Define comparison operator based on type
            if local_value.dtype.kind in ('i', 'u', 'S', 'U',
                                          'b'):  # int, str, unicode, bool
                compare = lambda x, y: np.all(x == y)
            elif local_value.dtype.kind == 'f':  # float
                compare = np.allclose
            else:
                fails.append('.{} unexpected dtype {}'.format(
                    colname, local_value.dtype))
                continue

            if not compare(local_value, flight_value):
                fails.append('.{} local != flight'.format(colname))

    fails = [msid + fail for fail in fails]
    return fails
Esempio n. 3
0
def collect_bad_data(start, stop, mask):
    """
    find bad data
    input:  start   --- data collection starting time (usually <yyyy>:<jjj>:<hh>:<mm>:<ss>
            stop    --- data collection stopping time
            mask    --- mask to find the data (only two options: '0x7f', '0x0400'
    output: cnt     --- counts of bad data
    """
    #
    #--- get data from ska database
    #
    dat = fetch.Msid('HRC_SS_HK_BAD', start, stop)
    #
    #--- select bad data
    #
    if mask == '0x7f':
        bad = (dat.vals & 0x7f) > 0
    else:
        bad = (dat.vals & 0x0400) > 0
#
#--- count bad data occarnaces
#
    cnt = count_bad_cases(bad)

    return cnt
Esempio n. 4
0
def are_we_in_comm(verbose=False, cadence=2, fake_comm=False):
    # Always be fetching from MAUDE
    fetch.data_source.set('maude allow_subset=True')

    # These fetches are really fast. Slow the cadence a bit.
    time.sleep(cadence)  # cadence is in seconds here

    # If there VCDU frame values within the last 60 seconds, this will not be empty
    ref_vcdu = fetch.Msid('CVCDUCTR', start=CxoTime.now() - 60 * u.s)

    # Will be True if in comm, False if not.
    in_comm = len(ref_vcdu) > 0

    if fake_comm is True:
        in_comm = True

    if verbose:
        if in_comm:
            print(
                f'({CxoTime.now().strftime("%m/%d/%Y %H:%M:%S")} | VCDU {ref_vcdu.vals[-1]} | #{in_comm_counter}) IN COMM!',
                end='\r')
        elif not in_comm:
            print(
                f'({CxoTime.now().strftime("%m/%d/%Y %H:%M:%S")}) Not in Comm.                                 ',
                end='\r\r\r')

    return in_comm
Esempio n. 5
0
def get_n_kalman(start, stop):
    """
    Get the AOKALSTR data with number of kalman stars reported by OBC
    """
    start = DateTime(start).date
    stop = DateTime(stop).date
    dat = fetch.Msid('aokalstr', start, stop)
    dat.interpolate(1.025)
    return dat
Esempio n. 6
0
    def set_atts(self, source):
        """Get attitude solution quaternions from ``source``.

        One could also just set atts and att_times attributes directly.
        """
        self.att_source = source
        tstart = DateTime(self.start).secs
        tstop = DateTime(self.stop).secs
        # Get attitudes and times
        if source == 'obc':
            telem = fetch.Msidset(['aoattqt*'], tstart, tstop)
            atts = np.vstack([
                telem['aoattqt{}'.format(idx)].vals for idx in [1, 2, 3, 4]
            ]).transpose()
            att_times = telem['aoattqt1'].times
            # Fetch COBSQID at beginning and end of interval, check they match, and define obsid
            if self.obsid is None:
                obsid_start = fetch.Msid('COBSRQID', tstart, tstart + 60)
                obsid_stop = fetch.Msid('COBSRQID', tstop - 60, tstop)
                if len(obsid_start.vals) == 0 or len(obsid_stop.vals) == 0:
                    raise ValueError(
                        "Error getting COBSRQID telem for tstart:{} tstop:{} from fetch_source:{}"
                        .format(tstart, tstop,
                                fetch.data_source.sources()[0]))
                self.obsid = obsid_start.vals[-1]
        elif source == 'ground':
            atts, att_times, asol_recs = asp_l1.get_atts(start=tstart,
                                                         stop=tstop)
            obsids = np.unique(
                np.array([int(rec['OBS_ID']) for rec in asol_recs]))
            if len(obsids) > 1:
                raise ValueError(
                    "Time range covers more than one obsid; Not supported.")
            self.obsid = obsids[0]
        else:
            raise ValueError("att_source must be 'obc' or 'ground'")
        ok = (att_times >= tstart) & (att_times < tstop)
        self.atts = atts[ok, :]  # (N, 4) numpy array
        self.att_times = att_times[ok]
Esempio n. 7
0
def fix_stats_h5(msid, tstart, tstop, interval):
    dt = {'5min': 328, 'daily': 86400}[interval]

    ft['msid'] = msid
    ft['interval'] = interval
    datestart = DateTime(tstart).date
    with _set_msid_files_basedir(datestart):
        stats_file = msid_files['stats'].abs
    logger.info('Updating stats file {}'.format(stats_file))

    index0 = int(tstart // dt)
    index1 = int(tstop // dt) + 1
    indexes = np.arange(index0, index1 + 1, dtype=np.int32)
    times = indexes * dt
    logger.info('Indexes = {}:{}'.format(index0, index1))

    logger.info('Fetching {} data between {} to {}'.format(
        msid,
        DateTime(times[0] - 500).date,
        DateTime(times[-1] + 500).date))
    dat = fetch.Msid(msid, times[0] - 500, times[-1] + 500)

    # Check within each stat interval?
    if len(dat.times) == 0:
        logger.info('Skipping: No values within interval {} to {}'.format(
            DateTime(times[0] - 500).date,
            DateTime(times[-1] + 500).date))
        return

    rows = np.searchsorted(dat.times, times)
    vals_stats = calc_stats_vals(dat, rows, indexes, interval)

    try:
        h5 = tables.openFile(stats_file, 'a')
        table = h5.root.data
        row0, row1 = np.searchsorted(table.col('index'), [index0, index1])
        for row_idx, vals_stat in itertools.izip(range(row0, row1),
                                                 vals_stats):
            if row1 - row0 < 50 or row_idx == row0 or row_idx == row1 - 1:
                logger.info('Row index = {}'.format(row_idx))
                logger.info('  ORIGINAL: %s', table[row_idx])
                logger.info('  UPDATED : %s', vals_stat)
            if opt.run:
                table[row_idx] = tuple(vals_stat)
    finally:
        h5.close()

    logger.info('')
Esempio n. 8
0
def plot_aokalstr(e, edir):
    """
    Plot AOKALSTR over the event with times in the supplied dictionary.

    :param e: dictionary with times of background event
    :param edir: directory for plots
    """
    plt.figure(figsize=(4, 3))
    aokalstr = fetch.Msid('AOKALSTR', e['event_tstart'] - 100,
                          e['event_tstop'] + 100)
    aokalstr.plot()
    plt.ylim([0, 9])
    plt.grid()
    plt.title('AOKALSTR')
    filename = "aokalstr_{}.png".format(e['event_datestart'])
    plt.savefig(os.path.join(edir, filename))
    plt.close()
    return filename
Esempio n. 9
0
def get_telem(dwell):
    subformat = fetch.Msid('COTLRDSF', dwell.start, dwell.stop)
    msids = [
        'AOACASEQ', 'AOPCADMD', 'AOKALSTR', 'COTLRDSF', 'COBSRQID', 'AOATTQT1',
        'AOATTQT2', 'AOATTQT3', 'AOATTQT4', 'CORADMEN', '3TSCPOS', '3TSCMOVE'
    ]
    # don't bother getting the residuals if the dwell has PCAD subformat
    if not np.any(subformat.vals == 'PCAD'):
        res_msids = [
            'AORESY0', 'AORESY1_1', 'AORESY2_1', 'AORESY3', 'AORESY4',
            'AORESY5_1', 'AORESY6_1', 'AORESY7', 'AORESZ0', 'AORESZ1_1',
            'AORESZ2_1', 'AORESZ3', 'AORESZ4', 'AORESZ5_1', 'AORESZ6_1',
            'AORESZ7'
        ]
        msids = msids + res_msids
    slot_cols = [
        'AOACFID', 'AOACMAG', 'AOACYAN', 'AOACZAN', 'AOACFCT', 'AOIMAGE',
        'AOACIDP', 'AOACIIR', 'AOACIMS', 'AOACISP'
    ]
    slots = range(0, 8)
    slot_msids = [
        "{}{}".format(field, slot) for field in slot_cols for slot in slots
    ]
    msids = msids + slot_msids
    if dwell.start > '2015:251':
        pcad_data = fetch.Msidset(msids + ['AOACIMSS'],
                                  start=dwell.start,
                                  stop=dwell.stop)
    else:
        pcad_data = fetch.Msidset(msids, start=dwell.start, stop=dwell.stop)

    if 'AORESY0' in pcad_data:
        for slot in [1, 2, 5, 6]:
            pcad_data['AORESY{}'.format(slot)] = pcad_data['AORESY{}_1'.format(
                slot)]
            pcad_data['AORESZ{}'.format(slot)] = pcad_data['AORESZ{}_1'.format(
                slot)]

    return pcad_data
Esempio n. 10
0
def get_observed_metrics(obsid, metrics_file=None):
    """
    Fetch manvr angle, one shot updates and aberration corrections,
    calculate centroid residuals and observed OBC roll error with
    respect to the ground (obc) solution for science (ER) observations
    as a function of time. Calculate also 50th and 95th percentile of
    the roll error, and log the preceding and next obsid.

    :param obsid: obsid

    """
    # One shot
    manvrs = events.manvrs.filter(obsid=obsid)
    if len(manvrs) == 0:
        raise NoManvrError(f"No manvr for obsid={obsid}")
    manvr = manvrs[0]
    one_shot = manvr.one_shot
    one_shot_pitch = manvr.one_shot_pitch
    one_shot_yaw = manvr.one_shot_yaw

    # Manvr angle
    manvr_angle = manvr.angle

    # Next obsid
    manvr_next = manvr.get_next()
    if manvr_next:
        obsid_next = manvr_next.get_obsid()
    else:
        obsid_next = -9999

    # Preceding obsid
    manvr_preceding = manvr.get_previous()
    if manvr_preceding:
        obsid_preceding = manvr_preceding.get_obsid()
    else:
        obsid_preceding = -9999

    # Attitude errors
    att_errors = get_observed_att_errors(obsid, on_the_fly=True)
    att_flag = att_errors['flag']

    if att_flag > 1:
        return ({'obsid': obsid,
                 'obsid_preceding': obsid_preceding,
                 'obsid_next': obsid_next,
                 'att_flag': att_flag,
                 'dwell': True},
                None)

    if att_errors is None:
        return ({'obsid': obsid,
                 'obsid_preceding': obsid_preceding,
                 'obsid_next': obsid_next,
                 'att_flag': att_flag,
                 'dwell': False},
                None)

    # dr statistics
    drs = att_errors['dr']
    dr50 = float(np.percentile(np.abs(drs), 50))
    dr95 = float(np.percentile(np.abs(drs), 95))
    mean_date = DateTime(0.5 * (att_errors['time'][0] + att_errors['time'][-1])).date

    # Centroid residuals
    crs = att_errors['crs']

    # Roll error at end of preceding observation
    preceding_roll_err = get_ending_roll_err(obsid_preceding, metrics_file=metrics_file)

    # Aberration correction
    aber_flag = 0
    path_ = get_mp_dir(obsid)[0]
    if path_ is None:
        logger.info(f'No mp_dir for {obsid}. Skipping aber correction')
        aber_y = -9999
        aber_z = -9999
        aber_flag = 1
    else:
        mp_dir = f"/data/mpcrit1/mplogs/{path_}"
        manerr = glob(f'{mp_dir}/*ManErr.txt')

        if len(manerr) == 0:
            logger.info(f'No ManErr file for {obsid}. Skipping aber correction')
            aber_y = -9999
            aber_z = -9999
            aber_flag = 2
        else:
            dat = ascii.read(manerr[0], header_start=2, data_start=3)
            ok = dat['obsid'] == obsid

            if np.sum(ok) > 1:
                logger.info(f'More than one entry per {obsid}. Skipping aber correction')
                aber_y = -9999
                aber_z = -9999
                aber_flag = 3
            else:
                aber_y = dat['aber-Y'][ok][0]
                aber_z = dat['aber-Z'][ok][0]

    if aber_flag == 0:
        one_shot_aber_corrected = np.sqrt((one_shot_pitch - aber_y)**2
                                          + (one_shot_yaw - aber_z)**2)
    else:
        one_shot_aber_corrected = -9999

    out_obsid = {'obsid': obsid,
                 'mean_date': mean_date,
                 'dr50': dr50,
                 'dr95': dr95,
                 'one_shot': one_shot,
                 'one_shot_pitch': one_shot_pitch,
                 'one_shot_yaw': one_shot_yaw,
                 'manvr_angle': manvr_angle,
                 'obsid_preceding': obsid_preceding,
                 'ending_roll_err': att_errors['dr'][-1],
                 'preceding_roll_err': preceding_roll_err,
                 'aber_y': aber_y,
                 'aber_z': aber_z,
                 'aber_flag': aber_flag,
                 'one_shot_aber_corrected': one_shot_aber_corrected,
                 'obsid_next': obsid_next,
                 'att_errors': att_errors,
                 'att_flag': att_flag,
                 'dwell': True}

    out_slot = {'obsid': obsid, 'slots': {k: {} for k in range(8)}}

    cat = crs['cat']
    d = events.dwells.filter(obsid=obsid)[0]
    logger.info(f'Dwell at {d.start}')

    for slot in range(8):
        ok = cat['slot'] == slot
        out = {}
        if len(cat[ok]) > 0:
            out['id'] = cat['id'][ok][0]
            out['type'] = cat['type'][ok][0]
            out['mag'] = cat['mag'][ok][0]
            out['yang'] = cat['yang'][ok][0]
            out['zang'] = cat['zang'][ok][0]
            out['slot'] = slot

            if att_flag == 0:
                # Ground solution exists
                val = crs['ground'][slot]
            else:
                # Use obc solution
                val = crs['obc'][slot]

            if len(val.dyags) > 0 and len(val.dzags) > 0:
                out['std_dy'] = np.std(val.dyags)
                out['std_dz'] = np.std(val.dzags)
                out['rms_dy'] = np.sqrt(np.mean(val.dyags ** 2))
                out['rms_dz'] = np.sqrt(np.mean(val.dzags ** 2))
                out['median_dy'] = np.median(val.dyags)
                out['median_dz'] = np.median(val.dzags)
                drs = np.sqrt((val.dyags ** 2) + (val.dzags ** 2))
                for dist in ['1.5', '3.0', '5.0']:
                    out[f'f_within_{dist}'] = np.count_nonzero(drs < float(dist)) / len(drs)
            else:
                for metric in ['std_dy', 'std_dz', 'rms_dy', 'rms_dz', 'median_dy', 'median_dz']:
                    out[metric] = -9999
                for metric in ['f_within_5.0', 'f_within_3.0', 'f_within_1.5']:
                    out[metric] = 0

            mags = fetch.Msid(f'aoacmag{slot}', start=d.start, stop=d.stop)
            out['median_mag'] = np.median(mags.vals)

            out_slot['slots'][slot] = out

    return out_obsid, out_slot
Esempio n. 11
0
from kadi import events
from mica.quaternion import Quat, normalize
from mica.starcheck import get_starcheck_catalog
import os
import time
import re
from Chandra.Time import DateTime
import Ska.DBI
from Ska.Shell import bash
from astropy.table import Table
import numpy as np
from Ska.engarchive import fetch

kalstr_obsids = []
for year in range(2008, 2017):
    dat = fetch.Msid('AOKALSTR', '{}:001'.format(year), '{}:001'.format(year+1))
    lowkals = dat.logical_intervals('<=', '2 ')
    lowkals = lowkals[lowkals['duration'] < 120]  # too-long intervals are spurious
    bad = lowkals['duration'] > 60
    lowkals = lowkals[bad]
    for interval in lowkals:
        ds = events.dwells.filter(start=interval['tstart'], stop=interval['tstop'])
        kalstr_obsids.extend([d.get_obsid() for d in ds])

kalstr_obsids = np.unique(kalstr_obsids)
kalstr_obsids = kalstr_obsids[kalstr_obsids != 0]
Esempio n. 12
0
def main():

    fetch.data_source.set('maude allow_subset=True')

    args = get_args()
    fake_comm = args.fake_comm
    chatty = args.report_errors  # Will be True if user set --report_errors

    if fake_comm:
        bot_slack_channel = '#bot-testing'
    elif not fake_comm:
        bot_slack_channel = bot_slack_channel = '#comm_passes'

    # Initial settings
    recently_in_comm = False
    in_comm_counter = 0

    # Loop infinitely :)
    while True:

        try:
            in_comm = are_we_in_comm(verbose=False,
                                     cadence=2,
                                     fake_comm=fake_comm)

            if not in_comm:
                if recently_in_comm:
                    # We might have just had a loss in telemetry. Try again after waiting for a minute
                    time.sleep(60)
                    in_comm = are_we_in_comm(verbose=False, cadence=2)
                    if in_comm:
                        continue

                    # Assuming the end of comm is real, then comm has recently ended and we need to report that.
                    telem = grab_critical_telemetry(start=CxoTime.now() -
                                                    1800 * u.s)
                    message = f"It appears that COMM has ended as of `{CxoTime.now().strftime('%m/%d/%Y %H:%M:%S')}` \n\n HRC was *{telem['HRC observing status']}* \n Last telemetry was in `{telem['Format']}` \n\n *HRC-I* was {telem['HRC-I Status']} \n *HRC-S* was {telem['HRC-S Status']} \n\n *Shields were {telem['Shield State']}* with a count rate of `{telem['Shield Rate']} cps` \n\n *HRC-I* Voltage Steps were (Top/Bottom) = `{telem['HRC-I Voltage Steps'][0]}/{telem['HRC-I Voltage Steps'][1]}` \n *HRC-S* Voltage Steps were (Top/Bottom) = `{telem['HRC-S Voltage Steps'][0]}/{telem['HRC-S Voltage Steps'][1]}`  \n\n *Bus Current* was `{telem['Bus Current (DN)']} DN` (`{telem['Bus Current (A)']} A`)  \n\n *FEA Temperature* was `{telem['FEA Temp']} C`"
                    send_slack_message(message, channel=bot_slack_channel)

                recently_in_comm = False
                in_comm_counter = 0
                print(
                    f'({CxoTime.now().strftime("%m/%d/%Y %H:%M:%S")}) Not in Comm.                                 ',
                    end='\r\r\r')

            if in_comm:
                if fake_comm:
                    # two days to make sure we grab previous comm
                    start_time = CxoTime.now() - 2 * u.d
                elif not fake_comm:
                    start_time = CxoTime.now(
                    ) - 300 * u.s  # 300 sec to make the grab really small

                if in_comm_counter == 0:
                    # Then start the clock on the comm pass
                    comm_start_timestamp = CxoTime.now()

                recently_in_comm = True
                in_comm_counter += 1

                time.sleep(5)  # Wait a few seconds for MAUDE to refresh
                latest_vcdu = fetch.Msid('CVCDUCTR', start=start_time).vals[-1]

                print(
                    f'({CxoTime.now().strftime("%m/%d/%Y %H:%M:%S")} | VCDU {latest_vcdu} | #{in_comm_counter}) In Comm.',
                    end='\r')

                if in_comm_counter == 5:
                    # Now we've waited ~half a minute or so for MAUDE to update
                    telem = grab_critical_telemetry(start=CxoTime.now() -
                                                    8 * u.h)

                    # Craft a message string using this latest elemetry
                    message = f"We are now *IN COMM* as of `{CxoTime.now().strftime('%m/%d/%Y %H:%M:%S')}` (_Chandra_ time). \n\n HRC is *{telem['HRC observing status']}*  \n Telemetry Format = `{telem['Format']}` \n\n *HRC-I* is {telem['HRC-I Status']} \n *HRC-S* is {telem['HRC-S Status']} \n\n *Shields are {telem['Shield State']}* with a count rate of `{telem['Shield Rate']} cps` \n\n *HRC-I* Voltage Steps (Top/Bottom) = `{telem['HRC-I Voltage Steps'][0]}/{telem['HRC-I Voltage Steps'][1]}` \n *HRC-S* Voltage Steps (Top/Bottom) = `{telem['HRC-S Voltage Steps'][0]}/{telem['HRC-S Voltage Steps'][1]}`  \n \n *Total Event* Rate = `{telem['TE Rate']} cps`   \n *Valid Event* Rate = `{telem['VE Rate']} cps`  \n \n *Bus Current* is `{telem['Bus Current (DN)']} DN` (`{telem['Bus Current (A)']} A`) \n \n *FEA Temperature* is `{telem['FEA Temp']} C`"
                    # Send the message using our slack bot
                    send_slack_message(message, channel=bot_slack_channel)
                    # do a first audit of the telemetry upon announcement

                if in_comm_counter == 10:
                    # Now we've waited a minute. Let's audit the telemetry and send amessage.
                    audit_telemetry(start=comm_start_timestamp,
                                    channel=bot_slack_channel)

        except Exception as e:
            # MAUDE queries fail regularly as TM is streaming in (mismatched array sizes as data is being populated), 404s, etc.
            # The solution is almost always to simply try again. Therefore this script just presses on in the event of an Exception.

            if chatty:
                # Then we want a verbose error message, because we're obviously in testing mode
                print(
                    f'({CxoTime.now().strftime("%m/%d/%Y %H:%M:%S")}) ERROR: {e}'
                )
                print("Heres the traceback:")
                print(traceback.format_exc())
                print("Pressing on...")
            elif not chatty:
                # Then we're likely in operational mode. Ignore the errors on the command line.
                print(
                    f'({CxoTime.now().strftime("%m/%d/%Y %H:%M:%S")}) ERROR encountered! Use --report_errors to display them.                             ',
                    end='\r\r\r')
            if in_comm_counter > 0:
                # Reset the comm counter to make the error "not count"
                in_comm_counter -= 1
            continue
Esempio n. 13
0
def calc_stats(obsid):
    obspar = mica.archive.obspar.get_obspar(obsid)
    if not obspar:
        raise ValueError("No obspar for {}".format(obsid))
    manvr = None
    dwell = None
    try:
        manvrs = events.manvrs.filter(obsid=obsid, n_dwell__gt=0)
        dwells = events.dwells.filter(obsid=obsid)
        if dwells.count() == 1 and manvrs.count() == 0:
            # If there is more than one dwell for the manvr but they have
            # different obsids (unusual) so don't throw an overlapping interval kadi error
            # just get the maneuver to the attitude with this dwell
            dwell = dwells[0]
            manvr = dwell.manvr
        elif dwells.count() == 0:
            # If there's just nothing, that doesn't need an error here
            # and gets caught outside the try/except
            pass
        else:
            # Else just take the first matches from each
            manvr = manvrs[0]
            dwell = dwells[0]
    except ValueError:
        multi_manvr = events.manvrs.filter(start=obspar['tstart'] - 100000,
                                           stop=obspar['tstart'] + 100000)
        multi = multi_manvr.select_overlapping(events.obsids(obsid=obsid))
        deltas = [np.abs(m.tstart - obspar['tstart']) for m in multi]
        manvr = multi[np.argmin(deltas)]
        dwell = manvr.dwell_set.first()

    if not manvr or not dwell:
        raise ValueError("No manvr or dwell for {}".format(obsid))
    if not manvr.get_next():
        raise ValueError("No *next* manvr so can't calculate dwell")
    if not manvr.guide_start:
        raise ValueError("No guide transition for {}".format(obsid))
    if not manvr.kalman_start:
        raise ValueError("No Kalman transition for {}".format(obsid))

    logger.info("Found obsid manvr at {}".format(manvr.start))
    logger.info("Found dwell at {}".format(dwell.start))
    starcheck = get_starcheck_catalog_at_date(manvr.guide_start)
    if starcheck is None or 'cat' not in starcheck or not len(
            starcheck['cat']):
        raise ValueError('No starcheck catalog found for {}'.format(
            manvr.get_obsid()))
    starcat_time = DateTime(starcheck['cat']['mp_starcat_time'][0]).secs
    starcat_dtime = starcat_time - DateTime(manvr.start).secs
    # If it looks like the wrong starcheck by time, give up
    if abs(starcat_dtime) > 300:
        raise ValueError(
            "Starcheck cat time delta is {}".format(starcat_dtime))
    if abs(starcat_dtime) > 30:
        logger.warning("Starcheck cat time delta of {} is > 30 sec".format(
            abs(starcat_dtime)))
    # The NPNT dwell should end when the next maneuver starts, but explicitly confirm via pcadmd
    pcadmd = fetch.Msid('AOPCADMD', manvr.kalman_start,
                        manvr.get_next().tstart + 20)
    next_nman_start = pcadmd.times[pcadmd.vals != 'NPNT'][0]
    vals, star_info = get_data(start=manvr.kalman_start,
                               stop=next_nman_start,
                               obsid=obsid,
                               starcheck=starcheck)
    gui_stats = calc_gui_stats(vals, star_info)
    obsid_info = {
        'obsid': obsid,
        'obi': obspar['obi_num'],
        'kalman_datestart': manvr.kalman_start,
        'kalman_tstart': DateTime(manvr.kalman_start).secs,
        'npnt_tstop': DateTime(next_nman_start).secs,
        'npnt_datestop': DateTime(next_nman_start).date,
        'revision': STAT_VERSION
    }
    catalog = Table(starcheck['cat'])
    catalog.sort('idx')
    guide_catalog = catalog[(catalog['type'] == 'GUI') |
                            (catalog['type'] == 'BOT')]
    aacccdpt = fetch_sci.MSID('AACCCDPT', manvr.kalman_start,
                              manvr.get_next().start)
    warm_threshold = 100.0
    tccd_mean = np.mean(aacccdpt.vals)
    tccd_max = np.max(aacccdpt.vals)
    warm_frac = dark_model.get_warm_fracs(warm_threshold, manvr.start,
                                          tccd_mean)
    temps = {
        'tccd_mean': tccd_mean,
        'n100_warm_frac': warm_frac,
        'tccd_max': tccd_max
    }
    return obsid_info, gui_stats, star_info, guide_catalog, temps