Ejemplo n.º 1
0
Archivo: dark_cal.py Proyecto: sot/mica
def _get_dark_cal_id_scalar(date, select='before'):
    dark_cals = get_dark_cal_dirs()
    dark_id = date_to_dark_id(date)

    # Special case if dark_id is exactly an existing dark cal then return that dark
    # cal regardless of the select method.
    if dark_id in dark_cals:
        return dark_id

    dark_cal_ids = list(dark_cals.keys())
    date_secs = CxoTime(date).secs
    dark_cal_secs = CxoTime(np.array([dark_id_to_date(id_) for id_ in dark_cal_ids])).secs

    if select == 'nearest':
        ii = np.argmin(np.abs(dark_cal_secs - date_secs))
    elif select in ('before', 'after'):
        ii = np.searchsorted(dark_cal_secs, date_secs)
        if select == 'before':
            ii -= 1
    else:
        raise ValueError('select arg must be one of "nearest", "before", or "after"')

    if ii < 0:
        earliest = CxoTime(dark_cal_secs[0]).date[:8]
        raise MissingDataError(
            f'No dark cal found before {earliest}'
            f'(requested dark cal on {date})'
        )

    try:
        out_dark_id = dark_cal_ids[ii]
    except IndexError:
        raise MissingDataError('No dark cal found {} {}'.format(select, date))

    return out_dark_id
Ejemplo n.º 2
0
    def get_validation_states(self, datestart, datestop):
        """
        Get states for validation of the thermal model.

        Parameters
        ----------
        datestart : string
            The start date to grab states afterward.
        datestop : string
            The end date to grab states before.
        """
        start = CxoTime(datestart)
        stop = CxoTime(datestop)
        self.logger.info('Getting commanded states between %s - %s' %
                         (start.date, stop.date))

        states = kadi_states.get_states(start,
                                        stop,
                                        state_keys=STATE_KEYS,
                                        merge_identical=True)

        # Set start and end state date/times to match telemetry span.  Extend the
        # state durations by a small amount because of a precision issue converting
        # to date and back to secs.  (The reference tstop could be just over the
        # 0.001 precision of date and thus cause an out-of-bounds error when
        # interpolating state values).
        dt = 0.01 / 86400
        states['tstart'][0] = (start - dt).secs
        states['datestart'][0] = (start - dt).date
        states['tstop'][-1] = (stop + dt).secs
        states['datestop'][-1] = (stop + dt).date

        return states
Ejemplo n.º 3
0
    def __init__(self, date, model_spec, limit, constant_conditions,
                 margin_factor):
        """ Run a Xija model for a given time and state profile.

        :param date: Date used for the dwell balance analysis
        :type date: str
        :param model_spec: Dictionary of model parameters for a single model
        :type model_spec: dict
        :param limit: Thermal Limit
        :type limit: float
        :param constant_conditions: Dictionary of conditions that remain constant for balance analysis, any required
            parameters not included as constant_conditions must be included in the dwell state 1 and state 2 inputs.
            This does not necessarily include initial conditions for primary and pseudo nodes.
        :type constant_conditions: dict
        :param margin_factor: Knockdown/safety factor to reduce predicted available limited dwell time, intended to add
            some conservatism to the ACIS maximum dwell time predictions, which are used to determine the available
            cooling time for models that heat at forward and normal sun attitudes
        :type margin_factor: float


        """

        self.date = CxoTime(date).date
        self.datesecs = CxoTime(date).secs
        self.model_spec = model_spec
        self.limit = limit
        self.constant_conditions = constant_conditions
        self.margin_factor = margin_factor
        self.anchor_offset_time = np.nan
        self.anchor_limited_time = np.nan
        self.results = None
Ejemplo n.º 4
0
def gen_unused_range(tstart, tstop, t_backoff=1725000):
    tstop = CxoTime(tstop).secs - t_backoff
    spans = [{
        'fillcolor': 'black',
        'line': {'width': 0},
        'opacity': 0.25,
        'type': 'rect',
        'x0': datetime.strptime(CxoTime(tstart).date, '%Y:%j:%H:%M:%S.%f'),
        'x1': datetime.strptime(CxoTime(tstop).date, '%Y:%j:%H:%M:%S.%f'),
        'y0': 0,
        'y1': 1,
        'xref': 'x',
        'yref': 'y domain',

    },
        {
            'fillcolor': 'black',
            'line': {'width': 0},
            'opacity': 0.25,
            'type': 'rect',
            'x0': datetime.strptime(CxoTime(tstart).date, '%Y:%j:%H:%M:%S.%f'),
            'x1': datetime.strptime(CxoTime(tstop).date, '%Y:%j:%H:%M:%S.%f'),
            'y0': 0,
            'y1': 1,
            'xref': 'x2',
            'yref': 'y2 domain',

        }
    ]
    return spans
Ejemplo n.º 5
0
def get_planet_angular_sep(body: str,
                           ra: float,
                           dec: float,
                           time=None,
                           observer_position: str = 'earth') -> float:
    """Get angular separation between planet ``body`` and target ``ra``, ``dec``.

    Valid values for the ``observer_position`` argument are:

    - 'earth' (default, approximate, fastest)
    - 'chandra' (reasonably accurate fast, requires fetching ephemeris)
    - 'chandra-horizons' (most accurate, slow, requires internet access)

    :param body: str
        Body name (lower case planet name)
    :param ra: float
        RA in degrees
    :param dec: float
        Dec in degrees
    :param time: CxoTime-compatible object
        Time or times of observation
    :param observer_position: str
        Observer position ('earth', 'chandra', or 'chandra-horizons')

    :returns: angular separation (deg)
    """
    from agasc import sphere_dist
    if not isinstance(time, CxoTime):
        time = CxoTime(time)

    if observer_position == 'earth':
        eci = get_planet_eci(body, time)
        body_ra, body_dec = eci_to_radec(eci)
    elif observer_position == 'chandra':
        eci = get_planet_chandra(body, time)
        body_ra, body_dec = eci_to_radec(eci)
    elif observer_position == 'chandra-horizons':
        if time.shape == ():
            time = CxoTime([time, time + 1000 * u.s])
            is_scalar = True
        else:
            is_scalar = False
        pos = get_planet_chandra_horizons(body,
                                          time[0],
                                          time[1],
                                          n_times=len(time))
        body_ra = pos['ra']
        body_dec = pos['dec']
        if is_scalar:
            body_ra = body_ra[0]
            body_dec = body_dec[0]
    else:
        raise ValueError(f'{observer_position} is not an allowed value: '
                         f'("earth", "chandra", or "chandra-horizons")')

    sep = sphere_dist(ra, dec, body_ra, body_dec)
    return sep
Ejemplo n.º 6
0
def generate_step_2_plot_dict(plot_data, tstart, tstop, title, units='Celsius'):
    plot_start = datetime.strptime(CxoTime(tstart).date, '%Y:%j:%H:%M:%S.%f')
    plot_stop = datetime.strptime(CxoTime(tstop).date, '%Y:%j:%H:%M:%S.%f')

    plot_object = {
        'data': plot_data,
        'layout':
            {
                'hovermode': "closest",
                'autosize': False,
                'width': width,
                'height': height,
                'margin': {'l': 50, 'r': 50, 't': 50, 'b': 70},
                'title':
                    {
                        'text': title,
                        'font': title_format,
                        'y': 0.95,
                        'x': 0.5,
                        'xanchor': 'center',
                        'yanchor': 'top'
                    },
                'yaxis':
                    {
                        'title':
                        {
                             'text': f'Resulting Temperatures for<br>Dwell #2 Guesses ({units})',
                             'font': label_format
                        },
                        'tickfont': axis_format,
                        'zeroline': False,
                        'linecolor': '#666666',
                        'linewidth': 1,
                        'mirror': True,
                        'anchor': 'x',
                    },

                'xaxis':
                    {
                        'domain': [0, 1],
                        'tickfont': axis_format,
                        'tickformatstops': time_axis_format,
                        'zeroline': False,
                        'linecolor': '#666666',
                        'linewidth': 1,
                        'mirror': True,
                        'range': [plot_start, plot_stop],
                        'showticklabels': True,
                        'tickangle': 30,
                        'anchor': 'y',
                    },

                'showlegend': True,
                'template': 'simple_white',
            },
    }
    return plot_object
Ejemplo n.º 7
0
def get_durations(aca_arr):
    durations = []
    for aca, next_aca in zip(aca_arr[:-1], aca_arr[1:]):
        if isinstance(next_aca, dict):
            dwell_end = next_aca['sched_stop']
        else:
            man_dur = duration(aca.att, next_aca.att)
            dwell_end = CxoTime(next_aca.date) - man_dur * u.s
        durations.append(dwell_end - CxoTime(aca.date))
    return durations
Ejemplo n.º 8
0
def paint_perigee(perigee_passages, states, plots):
    """
    This function draws vertical dashed lines for EEF, Perigee and XEF
    events in the load.EEF and XEF lines are black; Perigee is red.

    You supply the list of perigee passage events which are:
        Radzone Start/Stop time
        Perigee Passage time

        The states you created in main

        The dictionary of plots you created

        The MSID (in this case FP_TEMP) used to access the dictionary
    """
    #
    # Now plot any perigee passages that occur between xmin and xmax
    from cxotime import CxoTime
    for plot in plots.values():
        for eachpassage in perigee_passages:
            # The index [1] item is always the Perigee Passage time. Draw that
            # line in red If this line is between tstart and tstop then it
            # needs to be drawn on the plot. otherwise ignore
            if states['tstop'][-1] >= CxoTime(
                    eachpassage[0]).secs >= states['tstart'][0]:
                # Have to convert this time into the new x axis time scale
                # necessitated by SKA
                xpos = cxctime2plotdate([CxoTime(eachpassage[0]).secs])

                ymin, ymax = plot['ax'].get_ylim()

                # now plot the line.
                plot['ax'].vlines(xpos,
                                  ymin,
                                  ymax,
                                  linestyle=':',
                                  color='red',
                                  linewidth=2.0)

                # Plot the perigee passage time so long as it was specified in
                # the CTI_report file
                if eachpassage[1] != "Not-within-load":
                    perigee_time = cxctime2plotdate(
                        [CxoTime(eachpassage[1]).secs])
                    plot['ax'].vlines(perigee_time,
                                      ymin,
                                      ymax,
                                      linestyle=':',
                                      color='black',
                                      linewidth=2.0)
Ejemplo n.º 9
0
def test_venus_position2():
    # *******************************************************************************
    # Target body name: Venus (299)                     {source: CHANDRA_MERGED}
    # Center body name: Chandra Observatory (spacecraft) (-151) {source: CHANDRA_MERGED}
    # Center-site name: BODYCENTRIC
    # *******************************************************************************
    # Start time      : A.D. 2020-Jan-01 00:00:00.0000 UT
    # Stop  time      : A.D. 2020-Jun-01 00:00:00.0000 UT
    # Step-size       : 21600 minutes
    # *******************************************************************************

    txt = """
        date                   ra         dec
        2020-01-01T00:00     21:08:43.02 -18:22:41.8
        2020-01-16T00:00     22:19:56.31 -12:03:15.4
        2020-01-31T00:00     23:26:25.34 -04:40:18.3
        2020-02-15T00:00     00:29:55.07 +03:09:41.1
        2020-03-01T00:00     01:31:42.96 +10:46:02.6
        2020-03-16T00:00     02:32:52.02 +17:25:28.9
        2020-03-31T00:00     03:32:39.01 +22:40:58.7
        2020-04-15T00:00     04:26:52.03 +26:10:57.3
        2020-04-30T00:00     05:07:55.28 +27:38:30.8
        2020-05-15T00:00     05:22:08.73 +27:05:38.1
        2020-05-30T00:00     04:59:36.37 +24:14:26.9
    """
    dat = ascii.read(txt)
    date = CxoTime(dat['date'])
    sc = SkyCoord(dat['ra'], dat['dec'], unit=(u.hr, u.deg))

    eci = get_planet_chandra('venus', date)
    ra, dec = eci_to_radec(eci)

    dist = sphere_dist(ra, dec, sc.ra.to_value(u.deg), sc.dec.to_value(u.deg)) * 3600
    assert np.all(dist < 4.0)
Ejemplo n.º 10
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
Ejemplo n.º 11
0
def get_planet_eci(body, time=None, pos_observer=None):
    """Get ECI apparent position for solar system ``body`` at ``time``.

    This uses the built-in JPL ephemeris file DE432s and jplephem. The position
    is computed at the supplied ``time`` minus the light-travel time from the
    observer to ``body`` to generate the apparent position on Earth at ``time``.

    Estimated accuracy of planet coordinates (RA, Dec) is as follows, where the
    JPL Horizons positions are used as the "truth". This assumes the observer
    position is Earth (default).

    - Venus: < 12 arcmin with peak around 2 arcmin
    - Mars: < 8 arcmin with peak around 1.5 arcmin
    - Jupiter: < 1 arcmin with peak around 0.5 arcmin
    - Saturn: < 0.5 arcmin with peak around 0.3 arcmin

    :param body: Body name (lower case planet name)
    :param time: Time or times for returned position (default=NOW)
    :param pos_observer: Observer position (default=Earth)
    :returns: Earth-Centered Inertial (ECI) position (km) as (x, y, z)
        or N x (x, y, z)
    """
    time = CxoTime(time)

    pos_planet = get_planet_barycentric(body, time)
    if pos_observer is None:
        pos_observer = get_planet_barycentric('earth', time)

    dist = np.sqrt(np.sum((pos_planet - pos_observer)**2, axis=-1)) * u.km
    light_travel_time = (dist / const.c).to(u.s)

    pos_planet = get_planet_barycentric(body, time - light_travel_time)

    return pos_planet - pos_observer
Ejemplo n.º 12
0
def add_inputs(p, limits, date, dwell_type, roll, chips):
    """
    Add input data to Timbre coposite results.

    :param p: Output data
    :type p: pd.DataFrame
    :param limits: MSID limits used to produce included results
    :type limits: dict, pd.Series
    :param date: Date simulated
    :type date: str
    :param dwell_type: Output data category (i.e. limited or offset)
    :type dwell_type: str
    :param roll: Body roll used to produce included results
    :type roll: int, float
    :param chips: Number of ACIS chips used to produce included results
    :type chips: int

    :returns: Pandas Dataframe of results data with associated simulation input data
    :rtype: pd.DataFrame
    """
    for msid, limit in limits.items():
        p[msid + '_limit'] = np.float(limit)
    p['date'] = date
    p['datesecs'] = CxoTime(date).secs
    p['dwell_type'] = dwell_type
    p['roll'] = roll
    p['chips'] = chips

    p.reset_index(inplace=True)
    p = p.rename(columns={'index': 'pitch'})
    return p
Ejemplo n.º 13
0
Archivo: app.py Proyecto: sot/xija
def get_options():
    parser = argparse.ArgumentParser()
    parser.add_argument("filename", default='test_gui.json', help="Model file")
    parser.add_argument(
        "--days",
        type=float,
        default=15,  # Fix this
        help="Number of days in fit interval (default=90")
    parser.add_argument(
        "--stop",
        default=CxoTime() - 10,  # remove this
        help="Stop time of fit interval (default=model values)")
    parser.add_argument("--maxiter",
                        default=1000,
                        type=int,
                        help="Maximum number of fit iterations (default=1000)")
    parser.add_argument("--fit-method",
                        default="simplex",
                        help="Sherpa fit method (simplex|moncar|levmar)")
    parser.add_argument("--inherit-from",
                        help="Inherit par values from model spec file")
    parser.add_argument("--set-data",
                        action='append',
                        dest='set_data_exprs',
                        default=[],
                        help="Set data value as '<comp_name>=<value>'")
    parser.add_argument("--quiet",
                        default=False,
                        action='store_true',
                        help="Suppress screen output")

    return parser.parse_args()
Ejemplo n.º 14
0
Archivo: app.py Proyecto: sot/xija
 def change_stop(self):
     stop_date = self.stop_text.text()
     try:
         _ = CxoTime(stop_date).secs
         self.start_label.setText("Stop time: {}".format(stop_date))
         self.stop_date = stop_date
     except ValueError:
         raise_error_box("Write Table Error",
                         f"Stop time not valid: {stop_date}")
     self.stop_text.setText("")
Ejemplo n.º 15
0
Archivo: dark_cal.py Proyecto: sot/mica
def get_dark_cal_ids(dark_cals_dir=MICA_FILES['dark_cals_dir'].abs):
    """
    Get an ordered dict dates as keys and dark cal identifiers (YYYYDOY) as values.

    :param dark_cals_dir: directory containing dark cals.
    :returns: ordered dict of absolute directory paths
    """
    dark_cal_ids = sorted([fn for fn in os.listdir(dark_cals_dir)
                           if re.match(r'[12]\d{6}$', fn)])
    dates = [CxoTime(d[:4] + ':' + d[4:]).date for d in dark_cal_ids]
    return OrderedDict(zip(dates, dark_cal_ids))
Ejemplo n.º 16
0
def gen_range_annotations(tstart, tstop, yloc1, yloc2, t_backoff=1725000):
    tstart = CxoTime(tstart).secs
    tstop = CxoTime(tstop).secs
    tmid = tstop - t_backoff

    ttext = (tstop + tmid) / 2.
    arrow1 = {
        'x': datetime.strptime(CxoTime(tmid).date, '%Y:%j:%H:%M:%S.%f'),
        'y': yloc1,
        'text': '',
        'showarrow': True,
        'arrowhead': 2,
        'arrowwidth': 3,
        'arrowcolor': 'rgb(100,100,100)',
        'xref': "x2",
        'yref': "y2",
        'ax': datetime.strptime(CxoTime(ttext).date, '%Y:%j:%H:%M:%S.%f'),
        'ay': yloc1,
        'axref': 'x2',
        'ayref': 'y2',
        'xanchor': "center",
        'yanchor': "bottom",
        'font': label_format
    }
    arrow2 = {
        'x': datetime.strptime(CxoTime(tstop).date, '%Y:%j:%H:%M:%S.%f'),
        'y': yloc1,
        'text': '',
        'showarrow': True,
        'arrowhead': 2,
        'arrowwidth': 3,
        'arrowcolor': 'rgb(100,100,100)',
        'xref': "x2",
        'yref': "y2",
        'ax': datetime.strptime(CxoTime(ttext).date, '%Y:%j:%H:%M:%S.%f'),
        'ay': yloc1,
        'axref': 'x2',
        'ayref': 'y2',
        'xanchor': "center",
        'yanchor': "bottom",
        'font': label_format
    }
    text = {
        'x': datetime.strptime(CxoTime(ttext).date, '%Y:%j:%H:%M:%S.%f'),
        'y': yloc2,
        'text': 'Data Range used for evaluation',
        'showarrow': False,
        'xref': "x2",
        'yref': "y2",
        'xanchor': "center",
        'yanchor': "bottom",
        'font': label_format
    }
    annotations = [arrow1, arrow2, text]

    return annotations
Ejemplo n.º 17
0
def get_planet_chandra(body, time=None):
    """Get position for solar system ``body`` at ``time`` relative to Chandra.

    This uses the built-in JPL ephemeris file DE432s and jplephem, along with
    the CXC predictive Chandra orbital ephemeris (from the OFLS). The position
    is computed at the supplied ``time`` minus the light-travel time from
    Chandra to ``body`` to generate the apparent position from Chandra at
    ``time``.

    Estimated accuracy of planet coordinates (RA, Dec) from Chandra is as
    follows, where the JPL Horizons positions are used as the "truth".

    - Venus: < 4 arcsec with a peak around 3.5
    - Mars: < 3 arcsec with a peak around 2.0
    - Jupiter: < 0.8 arcsec
    - Saturn: < 0.5 arcsec

    :param body: Body name
    :param time: Time or times for returned position (default=NOW)
    :returns: position relative to Chandra (km) as (x, y, z) or N x (x, y, z)
    """
    from cheta import fetch

    time = CxoTime(time)

    # Get position of Chandra relative to Earth
    try:
        dat = fetch.MSIDset(
            ['orbitephem0_x', 'orbitephem0_y', 'orbitephem0_z'],
            np.min(time) - 500 * u.s,
            np.max(time) + 500 * u.s)
    except ValueError:
        raise NoEphemerisError('Chandra ephemeris not available')

    if len(dat['orbitephem0_x'].vals) == 0:
        raise NoEphemerisError('Chandra ephemeris not available')

    times = np.atleast_1d(time.secs)
    dat.interpolate(times=times)

    pos_earth = get_planet_barycentric('earth', time)

    # Chandra position in km
    chandra_eci = np.zeros_like(pos_earth)
    chandra_eci[..., 0] = dat['orbitephem0_x'].vals.reshape(time.shape) / 1000
    chandra_eci[..., 1] = dat['orbitephem0_y'].vals.reshape(time.shape) / 1000
    chandra_eci[..., 2] = dat['orbitephem0_z'].vals.reshape(time.shape) / 1000
    planet_chandra = get_planet_eci(body,
                                    time,
                                    pos_observer=pos_earth + chandra_eci)

    return planet_chandra
Ejemplo n.º 18
0
def gen_limit_annotation(xloc, yloc, limit, units):
    text_dict = {
        'x': datetime.strptime(CxoTime(xloc).date, '%Y:%j:%H:%M:%S.%f'),
        'y': yloc,
        'text': f'Limit = {limit} {units}',
        'showarrow': False,
        'xref': "x2",
        'yref': "y2",
        'xanchor': "center",
        'yanchor': "bottom",
        'font': label_format
    }
    return [text_dict, ]
Ejemplo n.º 19
0
def format_shapes(state_data):
    shape_data = []

    s = zip(state_data['state_times'], state_data['state_keys'])
    for t1, s1 in s:
        t2, s2 = next(s)

        t3, s3 = next(s)  # Ignore
        t4, s4 = next(s)  # Ignore

        shape_data.extend([
            {
                'fillcolor': 'black',
                'line': {'width': 0},
                'opacity': 0.05,
                'type': 'rect',
                'x0': datetime.strptime(CxoTime(t1).date, '%Y:%j:%H:%M:%S.%f'),
                'x1': datetime.strptime(CxoTime(t2).date, '%Y:%j:%H:%M:%S.%f'),
                'y0': 0,
                'y1': 1,
                'xref': 'x2',
                'yref': 'y2 domain',

            },
            {
                'fillcolor': 'black',
                'line': {'width': 0},
                'opacity': 0.05,
                'type': 'rect',
                'x0': datetime.strptime(CxoTime(t1).date, '%Y:%j:%H:%M:%S.%f'),
                'x1': datetime.strptime(CxoTime(t2).date, '%Y:%j:%H:%M:%S.%f'),
                'y0': 0,
                'y1': 1,
                'xref': 'x',
                'yref': 'y domain',

            }
        ])
    return shape_data
Ejemplo n.º 20
0
def format_step_2_plot_data(model_data, limit, tstart, tstop):
    plot_start = datetime.strptime(CxoTime(tstart).date, '%Y:%j:%H:%M:%S.%f')
    plot_stop = datetime.strptime(CxoTime(tstop).date, '%Y:%j:%H:%M:%S.%f')

    seq_colors = px.colors.n_colors(hex_to_rgba_str(colors[3], 1),
                                    hex_to_rgba_str(colors[0], 1),
                                    len(model_data),
                                    colortype='rgb')
    plot_data = []

    for (t, results), c in zip(model_data.items(), seq_colors):
        model_results = results['model_results']['aacccdpt']

        plot_data.append({
            'type': 'scattergl',
            'x': format_dates(model_results.times),
            'y': model_results.mvals,
            'name': f't_dwell2 = {t:.1f}',
            'line': {'color': c, 'width': 2, 'shape': 'hv'},
            'mode': 'lines',
            'showlegend': True,
            'xaxis': 'x',
            'yaxis': 'y',
        })

    plot_data.append({
        'type': 'scattergl',
        'x': [plot_start, plot_stop],
        'y': [limit, limit],
        'name': 'Limit',
        'line': {'color': 'black', 'width': 2, 'shape': 'hv', 'dash': 'dash'},
        'mode': 'lines',
        'showlegend': False,
        'xaxis': 'x',
        'yaxis': 'y',
    })

    return plot_data
Ejemplo n.º 21
0
Archivo: app.py Proyecto: sot/xija
 def add_filter(self, filter_type):
     err_msg = ''
     if filter_type == "ignore":
         vals = [self.start_text.text(), self.stop_text.text()]
     elif filter_type == "bad_time":
         vals = [self.bt_start_text.text(), self.bt_stop_text.text()]
     try:
         if vals[0] == "*":
             vals[0] = self.model.datestart
         if vals[1] == "*":
             vals[1] = self.model.datestop
         lim = CxoTime(vals).date
         t0, t1 = CxoTime(lim).secs
         if t0 > t1:
             err_msg = "Filter stop is earlier than filter start!"
     except (IndexError, ValueError):
         if len(vals) == 2:
             err_msg = f"Invalid input for filter: {vals[0]} {vals[1]}"
         else:
             err_msg = "Filter requires two arguments, " \
                       "the start time and the stop time."
     if len(err_msg) > 0:
         raise_error_box("Filters Error", err_msg)
     else:
         if filter_type == "ignore":
             self.model.append_mask_time([lim[0], lim[1]])
             bad = False
             self.mw.plots_box.add_fill(t0, t1)
         elif filter_type == "bad_time":
             self.model.append_bad_time([lim[0], lim[1]])
             bad = True
         self.mw.plots_box.add_fill(t0, t1, bad=bad)
     self.start_text.setText('')
     self.stop_text.setText('')
     self.bt_start_text.setText('')
     self.bt_stop_text.setText('')
Ejemplo n.º 22
0
Archivo: dark_cal.py Proyecto: sot/mica
def date_to_dark_id(date):
    """
    Convert ``date`` to the corresponding YYYYDOY format for a dark cal identifiers.

    :param date: any CxoTime compatible format
    :returns: dark id (YYYYDOY)
    """
    time = CxoTime(date)
    date_str = time.date
    if not time.shape:
        return date_str[:4] + date_str[5:8]
    date_str = np.atleast_1d(date_str)
    chars = date_str.view((str, 1)).reshape(-1, date_str.dtype.itemsize // 4)
    result = np.hstack([chars[:, :4], chars[:, 5:8]])
    result = np.frombuffer(result.tobytes(), dtype=(str, 7))
    return result.reshape(time.shape)
Ejemplo n.º 23
0
def test_venus_position1():
    """Obsid 18695 starcat at 2017:010:05:07:20.875, approx obs star 0510z"""

    # Output from JPL Horizons for Venus from Chandra
    date = CxoTime('2017-01-10T05:10')
    sc = SkyCoord('22:36:02.59', '-09:39:07.2', unit=(u.hr, u.deg))
    q_att = [-0.54137601, 0.17071483, -0.10344611, 0.81674192]

    eci = get_planet_chandra('venus', date)
    ra, dec = eci_to_radec(eci)
    yag, zag = radec_to_yagzag(ra, dec, q_att)
    # Confirm yag value is on "left side" of CCD, opposite all stars in 18695
    assert np.isclose(yag, 210.20, rtol=0, atol=0.01)
    assert np.isclose(zag, 69.45, rtol=0, atol=0.01)

    dist = sphere_dist(ra, dec, sc.ra.to_value(u.deg), sc.dec.to_value(u.deg)) * 3600
    assert np.all(dist < 4.0)
Ejemplo n.º 24
0
def gen_shading_annotation(xloc, yloc, dwell1_text, dwell2_text):
    text1 = f'Lightly Shaded Vertical Bands = Dwell State #1 ({dwell1_text})'
    text2 = f'Unshaded Vertical Bands = Dwell State #2 ({dwell2_text})'
    text = f'{text1}<br>{text2}'

    text_dict = {
        'x': datetime.strptime(CxoTime(xloc).date, '%Y:%j:%H:%M:%S.%f'),
        'y': yloc,
        'text': text,
        'showarrow': False,
        'xref': "x2",
        'yref': "y2",
        'xanchor': "right",
        'yanchor': "bottom",
        'font': label_format,
        'align': 'right'
    }
    return [text_dict, ]
Ejemplo n.º 25
0
    def _get_bs_cmds(self):
        """
        Internal method used to obtain commands from the backstop
        file and store them.
        """
        if os.path.isdir(self.backstop_file):
            # Returns a list but requires exactly 1 match
            backstop_file = get_globfiles(
                os.path.join(self.backstop_file, 'CR[0-9]*.backstop'))[0]
            self.backstop_file = backstop_file

        self.logger.info('Using backstop file %s' % self.backstop_file)

        # Read the backstop commands and add a `time` column
        bs_cmds = kadi.commands.get_cmds_from_backstop(self.backstop_file)
        bs_cmds['time'] = CxoTime(bs_cmds['date']).secs

        self.bs_cmds = bs_cmds
        self.tstart = bs_cmds[0]['time']
        self.tstop = bs_cmds[-1]['time']
Ejemplo n.º 26
0
def get_planet_barycentric(body, time=None):
    """Get barycentric position for solar system ``body`` at ``time``.

    This uses the built-in JPL ephemeris file DE432s and jplephem.

    :param body: Body name (lower case planet name)
    :param time: Time or times for returned position (default=NOW)
    :returns: barycentric position (km) as (x, y, z) or N x (x, y, z)
    """
    kernel = KERNEL.val
    if body not in BODY_NAME_TO_KERNEL_SPEC:
        raise ValueError(f'{body} is not an allowed value '
                         f'{tuple(BODY_NAME_TO_KERNEL_SPEC)}')

    spk_pairs = BODY_NAME_TO_KERNEL_SPEC[body]
    time = CxoTime(time)
    time_jd = time.jd
    pos = kernel[spk_pairs[0]].compute(time_jd)
    for spk_pair in spk_pairs[1:]:
        pos += kernel[spk_pair].compute(time_jd)

    return pos.transpose()  # SPK returns (3, N) but we need (N, 3)
Ejemplo n.º 27
0
Archivo: app.py Proyecto: sot/xija
 def save_ascii_table(self):
     from astropy.table import Table, Column
     dlg = QtWidgets.QFileDialog()
     dlg.setNameFilters(
         ["DAT files (*.dat)", "TXT files (*.txt)", "All files (*)"])
     dlg.selectNameFilter("DAT files (*.dat)")
     dlg.setAcceptMode(dlg.AcceptSave)
     dlg.exec_()
     filename = str(dlg.selectedFiles()[0])
     if filename != '':
         try:
             checked = []
             for i, box in enumerate(self.check_boxes):
                 if box.isChecked():
                     checked.append(i)
             t = Table()
             ts = CxoTime([self.start_date, self.stop_date]).secs
             ts[-1] += 1.0  # a buffer to make sure we grab the last point
             istart, istop = np.searchsorted(self.ftd.times, ts)
             c = Column(self.ftd.dates[istart:istop],
                        name="date",
                        format="{0}")
             t.add_column(c)
             for i, key in enumerate(self.ftd):
                 if i in checked:
                     c = Column(self.ftd[i][istart:istop],
                                name=key,
                                format=self.ftd.formats[i])
                     t.add_column(c)
             t.write(filename, overwrite=True, format='ascii.ecsv')
             self.last_filename = filename
         except IOError as ioerr:
             msg = QtWidgets.QMessageBox()
             msg.setStandardButtons(QtWidgets.QMessageBox.Ok)
             msg.setText("There was a problem writing the file:")
             msg.setDetailedText("Cannot write {}. {}".format(
                 filename, ioerr.strerror))
             msg.exec_()
Ejemplo n.º 28
0
def _plot_planets(ax, att, date0, duration, lim0, lim1):
    """
    :param ax: plt.Axes
        Matplotlib axes object to use
    :param att: Quat
        Attitude quaternion
    :param date0: CxoTime-compatible
        Date of obs start
    :param duration: float
        Duration of plot (secs)
    :param lim0: float
        Lower limit on x, y axis (row)
    :param lim1: float
        Upper limit on x, y axis (col)

    :returns: boolean
        True if planets were plotted
    """
    if not isinstance(att, Quat):
        att = Quat(att)

    date0 = CxoTime(date0)
    n_times = int(duration / 1000) + 1
    dates = date0 + np.linspace(0, duration, n_times) * u.s

    planets = ('venus', 'mars', 'jupiter', 'saturn')
    has_planet = False

    for planet in planets:
        # First check if planet is within 2 deg of aimpoint using Earth as the
        # reference point (without fetching Chandra ephemeris). These values are
        # accurate to better than 0.25 deg.
        sep = get_planet_angular_sep(planet,
                                     ra=att.ra,
                                     dec=att.dec,
                                     time=date0 +
                                     ([0, 0.5, 1] * u.s) * duration,
                                     observer_position='earth')
        if np.all(sep > 2.0):
            continue

        # Compute ACA row, col for planet each ksec (approx) over the duration.
        # This uses get_planet_chandra which is accurate to 4 arcsec for Venus
        # and < 1 arcsec for Jupiter, Saturn.
        try:
            eci = get_planet_chandra(planet, dates)
            from_earth = False
        except NoEphemerisError:
            # Get the position from Earth using built-in DE432
            eci = get_planet_eci(planet, dates)
            from_earth = True

        ra, dec = eci_to_radec(eci)
        yag, zag = radec_to_yagzag(ra, dec, att)
        row, col = yagzag_to_pixels(yag, zag, allow_bad=True)

        # Only plot planet within the image limits
        ok = (row >= lim0) & (row <= lim1) & (col >= lim0) & (col <= lim1)
        if np.any(ok):
            has_planet = True
            row = row[ok]
            col = col[ok]
            # Plot with green at beginning, red at ending
            ax.plot(row, col, '.', color='m', alpha=0.5)
            ax.plot(row[0], col[0], '.', color='g')
            label = planet.capitalize()
            if from_earth:
                err = GET_PLANET_ECI_ERRORS[planet].to(u.arcsec)
                label += f' (from Earth, errors to {err})'

            ax.plot(row[-1], col[-1], '.', color='r', label=label)

    if has_planet:
        ax.legend(loc='upper left',
                  fontsize='small',
                  facecolor='y',
                  edgecolor='k')
Ejemplo n.º 29
0
    def processRTS(self, RTS_load, SCS_NUM, NUM_HOURS, RTS_start_date):
        """
        This method opens the specified RTS, reads each line and creates an
        array which contains the values in the line plus time stamps the line.
        

        inputs:      RTS_load : Name of the LTCTI RTS file (e.g. 1_4_CTI)
                     SCS_NUM  : The SCS number this RTS file was run in (e.g. 135)
                    NUM_HOURS : a string in the FOT request format:  ddd:hh:mm:ss
               RTS_start_date : Start of the LTCTI in DOY format

        ACIS LTCTI RTS files contain comma separated lines, and each line entry
         can have 2,3 or 4 columns.
        
        Samples are:  /CMD, OORMPEN
                      ACIS,WSVIDALLDN, DELTA=00:00:01.000
                      /CMD, 2S2STHV, 2S2STHV2=0, DELTA=00:00:01.000
        
          Any line that does not start with 'ACIS' is logged in the array but not used by ACIS
          Ops other than to extract and use a DELTA if any.
              
        The important point about using the DELTA's is that if one exists, you MUST apply
        The delta time to the ongoing time stamp before you save the time for that line. 
        
        For example, suppose the time stamp is 2018:001:00:00:00.00 and you are 
        processing this line:
        
            ACIS,WSPOW0CF3F,DELTA=00:00:01.000
        
        The time stamp for that command is the present time stamp plus the DELTA in that line or:
        
            2018:001:00:00:01.00
        
        another way of saying it is that the DELTA is the delay between the previous command and
        the one you are processing.
        
        If there is no DELTA use the present time stamp value
        
        """
        # Compile the regex match criteria for the lines in the CTI RTS files
        delta_match = re.compile('DELTA=')
        equal_match = re.compile('=')
        cmd_statement_match = re.compile('/CMD')
        acis_statement_match = re.compile('ACIS')

        # Convert the RTS start date into seconds. We will use this
        # to calculate the time of each command in the RTS
        present_date = RTS_start_date
        present_time = CxoTime(RTS_start_date).secs

        # Calculate the duration of the CTI run, in seconds, as if it was NOT interrupted
        # by a Return To Science....i.e. it ran to completion and was
        # followed by the Perigee passage
        cti_duration_secs = self.convert_RTS_DELTA_to_secs(NUM_HOURS)

        # Convert the RTS start date to seconds.
        present_time = CxoTime(RTS_start_date).secs

        # Create an empty array with the RTS_dtype
        RTS_cmds = np.array([], dtype=self.RTS_dtype)

        # Form the full path to the appropriate RTS file
        rts_file_path = os.path.join(self.RTS_file_loc, self.RTS_name + '.RTS')
        # Open the specified RTS file for this Long Term CTI run
        rts_load = open(rts_file_path, 'r')

        # Process each command in the RTS
        # You want to fill out the RTS_dtype to the degree that you can
        #
        # So for each line in the RTS file.....
        for eachline in rts_load:
            # Ignore the line if it is a comment or a blank line
            if (eachline[0] != '!') and (eachline[0:2] != '\n'):

                # Split and join the lines while eliminating all whitespace that
                # occasionally occurs with the list items
                split_line = ''.join(eachline.split())

                # Now split the line on commas
                split_line = split_line.split(',')

                # /CMD or ACIS STATEMENT
                # Find out what the statement value is (/CMD or ACIS)
                if any(filter(cmd_statement_match.match, split_line)):
                    # It's a /CMD line so set the statement to /CMD
                    statement = '/CMD'
                elif any(filter(acis_statement_match.match, split_line)):
                    # It's an ACIS line so set the statement to ACIS
                    statement = 'ACIS'
                else:
                    # It's neither a /CMD or ACIS line so set the statement to None
                    statement = None

                # MNEMONIC
                if statement is not None:
                    # Find the position in the list of the statment
                    # It's usually the first line but don't make assumptions
                    statement_pos = split_line.index(statement)
                    # The Mnemonic comes immediately after the statement
                    mnemonic = split_line[statement_pos + 1]

                # Grab all list items that have an equal sign
                equal_items_list = list(filter(equal_match.findall,
                                               split_line))

                # Is there a DELTA= in any list item?
                d_match = list(filter(delta_match.findall, equal_items_list))

                # If so, extract the time string in the DELTA entry, convert
                # it to seconds, and add those number of seconts to the present_time
                if d_match:
                    # You have a match convert and save the value..........
                    delta_string = d_match[0].split('=')
                    # Check to see if the Time String is &NUM_HOURS&, If it is,
                    # then use cti_duration_secs
                    if delta_string[-1] == '&NUM_HOURS&':
                        dt = cti_duration_secs
                    else:
                        # Otherwise use the value represented by the string
                        dt = self.convert_RTS_DELTA_to_secs('000:' +
                                                            delta_string[-1])

                    # In either case, advance the prewsent time by dt
                    present_time += dt
                    # Get the index of the DELTA item in the equal_items_list
                    # and remove that item from the list
                    equal_items_list.remove(d_match[0])
                else:
                    dt = 0.0

                # Whether you had a delta or not, convert the present time to a date
                present_date = CxoTime(present_time).date

                # Now if equal_items_list is not empty, after you removed the DELTA
                # line, then the RTS line had a
                # substitution parameter and a supbstitution parameter value. The
                # format of the line is "substitution_parameter=value'.
                if equal_items_list:
                    # There is a substitution value in there so set the
                    # variables appropriately.
                    sub_split = equal_items_list[0].split('=')
                    substitution_parameter = sub_split[0]
                    substitution_parametr_value = sub_split[1]
                else:
                    # The list was empty so there was no substitution parameter
                    # so therefore set the two variables to None
                    substitution_parameter = None
                    substitution_parametr_value = None

                # Now you have all the information necessary to put an entry into the array
                RTS_cmds = np.r_[RTS_cmds,
                                 np.array([(present_date, present_time,
                                            statement, mnemonic,
                                            substitution_parameter,
                                            substitution_parametr_value, dt,
                                            SCS_NUM)],
                                          dtype=self.RTS_dtype)]

        # Done with the RTS file - close it
        rts_load.close()

        # Return the RTS_cmds array
        return RTS_cmds
Ejemplo n.º 30
0
def process_obsids(obsids, update=True, retry=False):
    report_root = REPORT_ROOT

    for obsid in obsids:
        strobs = "%05d" % obsid
        chunk_dir = strobs[0:2]
        topdir = os.path.join(report_root, chunk_dir)
        outdir = os.path.join(topdir, strobs)
        if os.path.exists(outdir) and not update:
            logger.info("Skipping {}, output dir exists.".format(obsid))
            continue
        if not retry and os.path.exists(os.path.join(outdir, "proc_err")):
            logger.warning("Skipping {}, previous processing error.".format(obsid))
            continue
        if not os.path.exists(outdir):
            os.makedirs("{}".format(outdir))
        # Delete files from old failure if reprocessing
        for failfile in ['proc_err', 'trace.txt']:
            if os.path.exists(os.path.join(outdir, failfile)):
                os.unlink(os.path.join(outdir, failfile))
        try:
            main(obsid)
        except:
            import traceback
            etype, emess, trace = sys.exc_info()
            logger.warning("Failed report on {}".format(obsid))
            # Make an empty file to record the error status
            f = open(os.path.join(outdir, 'proc_err'), 'w')
            f.close()
            # Write out the traceback too
            trace_file = open(os.path.join(outdir, 'trace.txt'), 'w')
            traceback.print_tb(trace, file=trace_file)
            trace_file.close()
            # Write out a notes jason file
            notes = {'report_version': REPORT_VERSION,
                     'obsid': obsid,
                     'checked_date': CxoTime.now().date,
                     'last_sched': "{}".format(str(emess)),
                     'vv_version': None,
                     'vv_revision': None,
                     'aspect_1_id': None,
                     'ocat_status': None,
                     'long_term': None,
                     'short_term': None,
                     'starcheck': None}
            f = open(os.path.join(outdir, 'notes.json'), 'w')
            f.write(json.dumps(notes,
                               sort_keys=True,
                               indent=4))
            f.close()
            # Make a stub html page
            proc_date = CxoTime.now().date
            jinja_env = jinja2.Environment(
                loader=jinja2.PackageLoader('mica.report'))
            jinja_env.line_comment_prefix = '##'
            jinja_env.line_statement_prefix = '#'
            template = jinja_env.get_template('proc_error.html')
            page = template.render(obsid=obsid,
                                   proc_date=proc_date,
                                   version=version)
            full_report_file = os.path.join(outdir, 'index.html')
            logger.info("Writing out error stub report to {}".format(full_report_file))
            f = open(full_report_file, 'w')
            f.write(page)
            f.close()

            # Save the bad state in the database
            save_state_in_db(obsid, notes)