Esempio n. 1
0
 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)
Esempio n. 2
0
 def _fix_comm_times(self, lines, line_times, comm_durations):
     new_lines = []
     new_times = []
     for i, line in enumerate(lines):
         if not "REAL-TIME COMM" in line and not "COMM DURATION" in line:
             new_lines.append(line)
             new_times.append(line_times[i])
     for time in self.events["comm_begins"]["times"]:
         local_time = datetime.strptime(time, "%Y:%j:%H:%M:%S.%f").replace(
             tzinfo=timezone.utc).astimezone(tz=None)
         t = date2secs(time)
         idx = bisect.bisect_right(new_times, t)
         new_times.insert(idx, t)
         new_lines.insert(
             idx, "%s   REAL-TIME COMM BEGINS   %s  EDT" %
             (time, local_time.strftime("%Y:%j:%H:%M:%S")))
     for i, time in enumerate(self.events["comm_ends"]["times"]):
         local_time = datetime.strptime(time, "%Y:%j:%H:%M:%S.%f").replace(
             tzinfo=timezone.utc).astimezone(tz=None)
         t = date2secs(time)
         idx = bisect.bisect_right(new_times, t)
         new_times.insert(idx, t)
         new_lines.insert(
             idx, "%s   REAL-TIME COMM ENDS     %s  EDT" %
             (time, local_time.strftime("%Y:%j:%H:%M:%S")))
         new_times.insert(idx + 1, t)
         new_lines.insert(
             idx + 1, "==> COMM DURATION:  %g mins." % comm_durations[i])
     return new_lines, new_times
Esempio n. 3
0
 def get_updated_dsn_comms(self):
     dsnfile = "/data/acis/dsn_summary.dat"
     if os.path.getsize(dsnfile) == 0:
         mylog.warning("DSN summary file is empty. Ignoring.")
         return
     tstart = date2secs(self.first_time)
     tstop = date2secs(self.last_time)
     bots = []
     eots = []
     new_durations = []
     with open(dsnfile) as f:
         for line in f.readlines()[2:]:
             words = line.strip().split()
             bot = datetime.strptime(
                 "%s:%s:00:00:00" % (words[-4], words[-3].split(".")[0]),
                 "%Y:%j:%H:%M:%S")
             eot = datetime.strptime(
                 "%s:%s:00:00:00" % (words[-2], words[-1].split(".")[0]),
                 "%Y:%j:%H:%M:%S")
             time_bot = date2secs(bot.strftime(
                 "%Y:%j:%H:%M:%S")) + 86400.0 * (float(words[-3]) % 1)
             time_eot = date2secs(eot.strftime(
                 "%Y:%j:%H:%M:%S")) + 86400.0 * (float(words[-1]) % 1)
             new_durations.append((time_eot - time_bot) / 60.0)
             if tstart <= time_bot <= tstop:
                 bots.append(time_bot)
             if tstart <= time_eot <= tstop:
                 eots.append(time_eot)
     self.events["comm_begins"]["times"] = secs2date(bots)
     self.events["comm_ends"]["times"] = secs2date(eots)
     self.lines, self.line_times = self._fix_comm_times(
         self.lines, self.line_times, new_durations)
Esempio n. 4
0
    def get_msid_attrs(self, tstart, tstop, msid, msid_args):
        """Get attributes for computed MSID: ``vals``, ``bads``, ``times``

        :param tstart: start time (CXC secs)
        :param tstop: stop time (CXC secs)
        :param msid: full MSID name e.g. cmd_state_pitch_clean
        :param msid_args: tuple of regex match groups: (state_key, dt)

        :returns: dict of MSID attributes
        """
        from kadi.commands.states import get_states
        from Chandra.Time import date2secs

        state_key = msid_args[0]
        dt = 1.025 * int(msid_args[1])
        states = get_states(tstart, tstop, state_keys=[state_key])

        tstart = date2secs(states['datestart'][0])
        tstops = date2secs(states['datestop'])

        times = np.arange(tstart, tstops[-1], dt)
        vals = states[state_key].view(np.ndarray)

        indexes = np.searchsorted(tstops, times)

        out = {
            'vals': vals[indexes],
            'times': times,
            'bads': np.zeros(len(times), dtype=bool),
            'unit': None
        }

        return out
Esempio n. 5
0
    def calc_model_wrapper(self, model_spec, states, tstart, tstop, state0=None):
        """
        This method sets up the model and runs it. "calc_model" is
        provided by the specific model instances.

        Parameters
        ----------
        model_spec : string
            Path to the JSON file containing the model specification.
        states : NumPy record array
            Commanded states
        tstart : float
            The start time of the model run.
        tstop : float
            The end time of the model run. 
        state0 : initial state dictionary, optional
            This state is used to set the initial temperature.
        """
        if state0 is None:
            start_msid = None
            dh_heater = None
            dh_heater_times = None
        else:
            start_msid = state0[self.msid]
            htrbfn = os.path.join(self.bsdir, 'dahtbon_history.rdb')
            mylog.info('Reading file of dahtrb commands from file %s' % htrbfn)
            htrb = ascii.read(htrbfn, format='rdb')
            dh_heater_times = date2secs(htrb['time'])
            dh_heater = htrb['dahtbon'].astype(bool)
        return self.calc_model(model_spec, states, tstart, tstop, start_msid,
                               dh_heater=dh_heater, dh_heater_times=dh_heater_times)
Esempio n. 6
0
 def append_mask_time(self, new_times, bad=False):
     t0, t1 = DateTime(new_times).secs
     i0, i1 = np.searchsorted(self.times, [t0, t1])
     if i1 > i0:
         self.mask_times_indices.append((i0, i1))
         self.mask_times.append(new_times)
         self.mask_times_bad = np.append(self.mask_times_bad, bad)
     self.mask_time_secs = date2secs(self.mask_times)
Esempio n. 7
0
 def _plot_bands(self, tbegin, tend, plot, events, color, alpha=1.0):
     tc_start = list(self.events[events[0]]["times"])
     tc_end = list(self.events[events[1]]["times"])
     if tc_end[0] < tc_start[0]:
         tc_start.insert(0, self.first_time)
     if tc_start[-1] > tc_end[-1]:
         tc_end.append(self.last_time)
     assert len(tc_start) == len(tc_end)
     tc_start = date2secs(tc_start)
     tc_end = date2secs(tc_end)
     ybot, ytop = plot.ax.get_ylim()
     t = np.linspace(tbegin, tend, 500)
     tplot = cxctime2plotdate(t)
     for tcs, tce in zip(tc_start, tc_end):
         in_evt = (t >= tcs) & (t <= tce)
         plot.ax.fill_between(tplot,
                              ybot,
                              ytop,
                              where=in_evt,
                              color=color,
                              alpha=alpha)
Esempio n. 8
0
    def _add_annotations(self, plot, annotations, tbegin, tend):
        for i, line in enumerate(plot.ax.lines):
            line.set_zorder(100 - i)
        plot_comms = False
        plot_belts = False
        if "cti_runs" in annotations:
            annotations.append("start_cti")
            annotations.append("end_cti")
            annotations.remove("cti_runs")
        for key in annotations:
            if key == "comms":
                plot_comms = True
                continue
            if key == "belts":
                plot_belts = True
                continue
            color = colors[key]
            ls = styles[key]
            for i, t in enumerate(self.events[key]["times"]):
                tt = date2secs(t)
                if tt < tbegin or tt > tend:
                    continue
                plot.add_vline(t, color=color, ls=ls)
                if "state" in self.events[key] and key in offsets:
                    text = self.events[key]["state"][i]
                    if isinstance(text, tuple):
                        text = text[-1]
                    tdt = secs2date(tt + 1800.0)
                    ymin, ymax = plot.ax.get_ylim()
                    y = (1.0 - offsets[key]) * ymin + offsets[key] * ymax
                    plot.add_text(tdt,
                                  y,
                                  text,
                                  fontsize=15,
                                  rotation='vertical',
                                  color=color,
                                  zorder=100)

        if plot_belts:
            self._plot_bands(tbegin,
                             tend,
                             plot, ["radmon_disable", "radmon_enable"],
                             "mediumpurple",
                             alpha=0.333333)

        if plot_comms:
            self._plot_bands(tbegin,
                             tend,
                             plot, ["comm_begins", "comm_ends"],
                             "pink",
                             alpha=1.0)
Esempio n. 9
0
 def __init__(self, table):
     import numpy.lib.recfunctions as rf
     new_table = OrderedDict()
     if isinstance(table, np.ndarray):
         state_names = list(table.dtype.names)
         if "tstart" not in state_names:
             table = rf.append_fields(table, ["tstart", "tstop"], [
                 date2secs(table["datestart"]),
                 date2secs(table["datestop"])
             ],
                                      usemask=False)
             state_names += ["tstart", "tstop"]
     else:
         state_names = list(table.keys())
         if "tstart" not in state_names:
             table["tstart"] = date2secs(table["datestart"])
             table["tstop"] = date2secs(table["datestop"])
             state_names += ["tstart", "tstop"]
     times = Quantity([table["tstart"], table["tstop"]], "s")
     for k in state_names:
         v = np.asarray(table[k])
         if k == "trans_keys" and v.dtype.char == "O":
             new_table[k] = APStringArray(
                 np.array([",".join(d) for d in v]), times)
         elif v.dtype.char in ['S', 'U', 'O']:
             new_table[k] = APStringArray(v, times)
         else:
             new_table[k] = APQuantity(v,
                                       times,
                                       get_units("states", k),
                                       dtype=v.dtype)
     if "off_nom_roll" not in state_names:
         v = calc_off_nom_rolls(new_table)
         new_table["off_nom_roll"] = APQuantity(v,
                                                times,
                                                "deg",
                                                dtype=v.dtype)
     super(States, self).__init__(table=new_table)
Esempio n. 10
0
 def from_tracelog(cls, filename, tbegin=None, tend=None):
     if tbegin is None:
         tbegin = -1.0e22
     else:
         if isinstance(tbegin, str):
             tbegin = date2secs(tbegin)
     if tend is None:
         tend = 1.0e22
     else:
         if isinstance(tend, str):
             tend = date2secs(tend)
     f = open(filename, "r")
     header = f.readline().split()
     dtype = []
     state_codes = {}
     for msid in header:
         state_code = get_state_codes(msid.lower())
         if msid.lower() != "time":
             state_codes[msid.lower()] = state_code
         if state_code is not None:
             dtype.append((msid.lower(), "|U4"))
         else:
             dtype.append((msid.lower(), '<f8'))
     data = []
     for line in f:
         words = line.split()
         if len(words) == len(header):
             data.append(tuple(words))
     f.close()
     data = np.array(data, dtype=dtype)
     # Convert times in the TIME column to Chandra 1998 time
     data['time'] -= 410227200.
     idxs = np.logical_and(data['time'] >= tbegin, data['time'] <= tend)
     table = dict((k.lower(), data[k][idxs]) for k in data.dtype.names if k != "time")
     times = dict((k.lower(), data["time"][idxs]) for k in header if k != "time")
     derived_msids = ["dpa_a_power", "dpa_b_power", "dea_a_power", "dea_b_power"]
     return cls(table, times, state_codes=state_codes, derived_msids=derived_msids)
Esempio n. 11
0
    def make_dashboard_plots(self, msid, tstart=None, tstop=None, yplotlimits=None,
                             errorplotlimits=None, fig=None, figfile=None,
                             bad_times=None, mask_radzones=False, plot_limits=True, 
                             mask_fmt1=False):
        """
        Make dashboard plots for the particular thermal model.

        Parameters
        ----------
        msid : string
            The MSID name to plot in the dashboard. 
        tstart : string, optional
            The start time of the data for the dashboard plot. If not specified,
            the beginning of the thermal model run is used.
        tstop : string, optional
            The stop time of the data for the dashboard plot. If not specified,
            the end of the thermal model run is used.
        yplotlimits : two-element array_like, optional
            The (min, max) bounds on the temperature to use for the
            temperature vs. time plot. Default: Determine the min/max
            bounds from the telemetry and model prediction and
            decrease/increase by degrees to determine the plot limits.
        errorplotlimits : two-element array_like, optional
            The (min, max) error bounds to use for the error plot.
            Default: [-15, 15]
        fig : :class:`~matplotlib.figure.Figure`, optional
            A Figure instance to plot in. Default: None, one will be
            created if not provided.
        figfile : string, optional
            The file to write the dashboard plot to. One will be created
            if not provided.
        bad_times : list of tuples, optional
            Provide a set of times to exclude from the creation of the
            dashboard plot.
        mask_radzones : boolean, optional
            If True, mask out radzone periods for dashboard plots of the
            focal plane model. Default: False
        plot_limits : boolean, optional
            If True, plot the yellow caution and planning limits on the
            dashboard plots. Default: True
        """
        from xijafit import dashboard as dash
        if fig is None:
            fig = plt.figure(figsize=(20,10))
        if ("msids", msid) not in self.field_list:
            raise RuntimeError("You must include the real data if you want to make a "
                               "dashboard plot! Set get_msids=True when creating the"
                               "thermal model!")
        telem = self["msids", msid]
        pred = self["model", msid]
        mask = np.logical_and(telem.mask, pred.mask)
        if tstart is not None:
            tstart = DateTime(tstart).secs
            mask[telem.times.value < tstart] = False
        if tstop is not None:
            tstop = DateTime(tstop).secs
            mask[telem.times.value > tstop] = False
        if bad_times is not None:
            for (left, right) in bad_times:
                idxs = np.logical_and(telem.times.value >= date2secs(left),
                                      telem.times.value <= date2secs(right))
                mask[idxs] = False
        if msid == "fptemp_11" and mask_radzones:
            rad_zones = events.rad_zones.filter(start=telem.dates[0],
                                                stop=telem.dates[-1])
            for rz in rad_zones:
                idxs = np.logical_and(telem.times.value >= rz.tstart,
                                      telem.times.value <= rz.tstop)
                mask[idxs] = False
        if mask_fmt1:
            which = self["msids", "ccsdstmf"] == "FMT1"
            mask[which] = False
        times = telem.times.value[mask]
        if yplotlimits is None:
            ymin = min(telem.value[mask].min(), pred.value[mask].min())-2
            ymax = min(telem.value[mask].max(), pred.value[mask].max())+2
            yplotlimits = [ymin, ymax]
        if errorplotlimits is None:
            errorplotlimits = [-5, 5]
        mylimits = {"units": "C"}
        if plot_limits:
            if msid == "fptemp_11":
                mylimits["acisi_limit"] = -112.0
                mylimits["aciss_limit"] = -111.0
                mylimits["fp_sens_limit"] = -118.7
            else:
                mylimits["caution_high"] = limits[msid]+margins[msid]
                mylimits["planning_limit"] = limits[msid]
        dash.dashboard(pred.value[mask], telem.value[mask], times, mylimits,
                       msid=msid, modelname=full_name.get(msid, msid),
                       errorplotlimits=errorplotlimits, yplotlimits=yplotlimits,
                       fig=fig, savefig=False)
        if figfile is not None:
            fig.savefig(figfile)
        return fig
Esempio n. 12
0
 def from_mit_file(cls, filename, tbegin=None, tend=None):
     if tbegin is None:
         tbegin = -1.0e22
     else:
         if isinstance(tbegin, str):
             tbegin = date2secs(tbegin)
     if tend is None:
         tend = 1.0e22
     else:
         if isinstance(tend, str):
             tend = date2secs(tend)
     f = open(filename, 'r')
     line = f.readline()
     f.close()
     if "," in line:
         delimiter = ","
     elif "\t" in line:
         delimiter = "\t"
     else:
         delimiter = " "
     if line.startswith("#"):
         year = "#YEAR"
     else:
         year = "YEAR"
     data = Table(ascii.read(filename, guess=False, format='csv',
                             delimiter=delimiter), masked=True)
     mins, hours = np.modf(data["SEC"].data/3600.)
     secs, mins = np.modf(mins*60.)
     secs *= 60.0
     time_arr = ["%04d:%03d:%02d:%02d:%06.3f" % (y, d, h, m, s)
                 for y, d, h, m, s in zip(data[year].data,
                                          data["DOY"].data,
                                          hours, mins, secs)]
     tsecs = date2secs(time_arr)
     idxs = np.logical_and(tsecs >= tbegin, tsecs <= tend)
     table = {}
     times = {}
     masks = {}
     state_codes = {}
     for k in data.keys():
         if k not in [year, "DOY", "SEC"]:
             if k in mit_trans_table:
                 key = mit_trans_table[k]
             else:
                 key = k.lower()
             table[key] = np.array(data[k].data[idxs])
             times[key] = tsecs[idxs]
             if key == "bilevels":
                 masks[key] = np.array(table[key] != "0")
             else:
                 masks[key] = ~data[k].data[idxs].mask
             state_codes[key] = get_state_codes(key)
     # Now we split the bilevel into its components
     bmask = masks["bilevels"]
     bilevels = np.char.strip(table["bilevels"], "b")[bmask]
     for i in range(8):
         key = "1stat%dst" % (7-i)
         table[key] = np.array(["BAD"]*bmask.size)
         table[key][bmask] = np.array([b[i] for b in bilevels])
         times[key] = times["bilevels"]
         masks[key] = bmask
         state_codes[key] = get_state_codes(key)
     return cls(table, times, masks=masks, state_codes=state_codes)
Esempio n. 13
0
 def _populate_event_times(self):
     lines = []
     line_times = []
     time = self.first_time
     comm_durations = []
     with open(self.load_file, "r") as f:
         for i, line in enumerate(f.readlines()):
             words = line.strip().split()
             if len(words) > 0:
                 event = None
                 state = None
                 if line.startswith(self.load_year) or \
                     line.startswith(self.next_year):
                     time = words[0]
                 if "MP_OBSID" in line:
                     event = "obsid_change"
                     state = words[-1]
                 if "SIMTRANS" in line:
                     event = "sim_trans"
                     state = (int(words[-2]), words[-1].strip("()"))
                 if "HETGIN" in line:
                     event = "hetg_in"
                 if "HETGRE" in line:
                     event = "hetg_out"
                 if "LETGIN" in line:
                     event = "letg_in"
                 if "LETGRE" in line:
                     event = "letg_out"
                 if "CSELFMT" in line and "COMMAND_HW" in line:
                     event = "fmt_change"
                     state = int(words[-1][-1])
                 if "EPERIGEE" in line and "ORBPOINT" in line:
                     event = "perigee"
                 if "APOGEE" in line and "ORBPOINT" in line:
                     event = "apogee"
                 if "COMM BEGINS" in line:
                     event = "comm_begins"
                 if "COMM ENDS" in line:
                     event = "comm_ends"
                 if "EEF1000" in line and "ORBPOINT" in line:
                     event = "enter_belts"
                 if "XEF1000" in line and "ORBPOINT" in line:
                     event = "exit_belts"
                 if "OORMPDS" in line and "COMMAND_SW" in line:
                     event = "radmon_disable"
                 if "OORMPEN" in line and "COMMAND_SW" in line:
                     event = "radmon_enable"
                 if event is not None:
                     if event not in self.events:
                         self.events[event] = {"times": []}
                     if event == "comm_ends":
                         time = secs2date(date2secs(words[0]) - 1800.0)
                     self.events[event]["times"].append(time)
                     if state is not None:
                         if "state" not in self.events[event]:
                             self.events[event]["state"] = []
                         self.events[event]["state"].append(state)
                 if "REAL-TIME COMM" in line:
                     continue
                 if "COMM DURATION" in line:
                     comm_durations.append(float(words[-2]) - 30.0)
                     continue
                 if line.startswith(self.load_year) or \
                     line.startswith(self.next_year) or \
                     "WSPOW COMMAND LOADS" in line or \
                     "CHANDRA STATUS ARRAY" in line or \
                     "ACIS integration time" in line or \
                     "requested time" in line or \
                     "ObsID change" in line or \
                     "THERE IS A Z-SIM" in line or \
                     "==> DITHER" in line:
                     lines.append(line)
                     line_times.append(time)
     line_times = date2secs(line_times)
     if len(self.events["comm_begins"]) > 0:
         lines, line_times = self._fix_comm_times(lines, line_times,
                                                  comm_durations)
     return lines, line_times
Esempio n. 14
0
 def reset_mask_times(self):
     self.mask_times = self.bad_times.copy()
     self.mask_times_indices = self.bad_times_indices.copy()
     self.mask_time_secs = date2secs(self.mask_times)
     self.mask_times_bad = np.ones(self.mask_time_secs.shape[0],
                                   dtype='bool')
Esempio n. 15
0
def find_text_time(time, hours=1.0):
    return secs2date(date2secs(time)+hours*3600.0)
Esempio n. 16
0
 def test_date2secs(self):
     vals = DateTime(['2012:001', '2000:001'])
     self.assertTrue(np.all(date2secs(vals.date) == vals.secs))
Esempio n. 17
0
 def test_date2secs(self):
     vals = DateTime(['2012:001', '2000:001'])
     self.assertTrue(np.all(date2secs(vals.date) == vals.secs))