diff --git a/panel.py b/panel.py deleted file mode 100644 index 8600250..0000000 --- a/panel.py +++ /dev/null @@ -1,224 +0,0 @@ -from collections import deque -import random -import wx -import numpy as np -import epics - -from datetime import datetime - -#from epics.wx import MotorPanel - -from slic.gui.widgets import LabeledMathEntry -from slic.gui.widgets import make_filled_hbox, make_filled_vbox, EXPANDING -from slic.gui.widgets.plotting import PlotPanel - -from bstrd import BS, bsstream - - -# config -nshots = 1000 -mm2fs = 6671.2 # light speed and delay stages -ttThreshold = 5 -iZeroThreshold = 0.5 - -# spectrometer axis in time -timeAx = -1.91*(np.arange(0,2048)-1024) - -# channels -STAGEpv = epics.PV('SLAAR11-LMOT-M452:MOTOR_1.VAL') # global globi -chname_amplitude = "SARES11-SPEC125-M1.edge_amplitude" -chname_jitter = "SARES11-SPEC125-M1.edge_position" -chname_deriv = "SARES11-SPEC125-M1.edge_derivative" -chname_events = "SAR-CVME-TIFALL4:EvtSet" -chname_iZero = "SAROP11-PBPS110:INTENSITY" - -# create channels -ch_amp = BS(chname_amplitude) -ch_jitter = BS(chname_jitter) -ch_events = BS(chname_events) -ch_iZero = BS(chname_iZero) -ch_deriv = BS(chname_deriv) - -iso_format = "%Y-%m-%d %H:%M:%S" - -def goodshots(events, iZero, amps, *arrays): - fel = events[:, 13] - laser = events[:, 18] - darkShot = events[:, 21] - pulsePicking = events[:,200] - iZero = iZero - amplitudes = amps - pumped_shots = np.logical_and.reduce((fel, laser, np.logical_not(darkShot), pulsePicking, iZero > iZeroThreshold, amps > ttThreshold)) -# pumped_shots = np.logical_and.reduce((fel, laser, np.logical_not(darkShot))) - return [a[pumped_shots] for a in arrays] - - -class MainPanel(wx.Panel): - - def __init__(self, parent): - super().__init__(parent) - - self.evts = np.empty((nshots,256)) - self.jitter = np.empty(nshots) - self.amp = np.empty(nshots) - self.iZero = np.empty(nshots) - self.deriv = np.empty((nshots,2048)) - self.edge = np.empty((nshots,2048)) - - self.stagePos = deque(maxlen=1000) - self.jitters = deque(maxlen=1000) - self.jstds = deque(maxlen=1000) - self.amps = deque(maxlen=1000) - self.astds = deque(maxlen=1000) - - self.plot_jitters = plot_jitters = PlotPanel(self, figsize=(2,3)) - self.plot_amps = plot_amps = PlotPanel(self, figsize=(2,3)) - self.plot_edges = plot_edges = PlotPanel(self, figsize=(6,5)) - - plots1 = (plot_edges,) - hb_plot1 = make_filled_hbox(plots1) - - plots2 = (plot_jitters, plot_amps) - hb_plot2 = make_filled_hbox(plots2) - - btn_clearQ = wx.Button(self, label="Clear plots") - btns = (btn_clearQ,) - hb_btns = make_filled_hbox(btns) - - self.chkbx_feedback = chkbx_feedback = wx.CheckBox(self, label="feedback") - chkbxs = (btn_clearQ, chkbx_feedback) - hb_chkbx = make_filled_hbox(chkbxs) - - self.plot_stage = plot_stage = PlotPanel(self, figsize=(6,2)) - self.plot_timeseries_jitters = plot_timeseries_jitters = PlotPanel(self, figsize=(6,2)) - self.plot_timeseries_amps = plot_timeseries_amps = PlotPanel(self, figsize=(6,2)) - plots3 = (plot_timeseries_jitters,) - plots4 = (plot_timeseries_amps,) - plots5 = (plot_stage,) - hb_plot3 = make_filled_hbox(plots3) - hb_plot4 = make_filled_hbox(plots4) - hb_plot5 = make_filled_hbox(plots5) - - widgets = (hb_plot1, hb_plot2, hb_plot3, hb_plot4, hb_plot5, hb_chkbx) - box = make_filled_vbox(widgets, border=1) - self.SetSizerAndFit(box) - - btn_clearQ.Bind(wx.EVT_BUTTON, self.on_click_clearQ) - - self.timer = wx.Timer(self) - self.Bind(wx.EVT_TIMER, self.on_update, self.timer) - self.timer.Start(100) - - - def on_update(self, _event): - - self.time = datetime.now().strftime(iso_format) - - self.evts = np.empty((nshots,256)) - self.jitter = np.empty(nshots) - self.amp = np.empty(nshots) - self.iZero = np.empty(nshots) - self.deriv = np.empty((nshots,2048)) - - for i in range(nshots): - tempa = ch_events.get() - self.evts[i] = tempa - tempb = ch_jitter.get() - self.jitter[i] = tempb - tempc = ch_amp.get() - self.amp[i] = tempc - tempd = ch_iZero.get() - self.iZero[i] = tempd - tempe = ch_deriv.get() - self.deriv[i] = tempe - next(bsstream) - wx.GetApp().Yield() - - self.deriv, self.amp, self.jitter = goodshots(self.evts, self.iZero, self.amp, self.deriv, self.amp, self.jitter) - - if (len(np.asarray(self.jitter)) > 1): - self.jitters.append(np.mean(self.jitter)) - self.jstds.append(np.std(self.jitter)) - self.amps.append(np.mean(self.amp)) - self.astds.append(np.std(self.amp)) - - if (self.chkbx_feedback.IsChecked()) & (np.abs(np.mean(self.jitter)) > 50) & (np.abs(np.mean(self.jitter)) < 1000): - moveTo = STAGEpv.get()*mm2fs - np.mean(self.jitter) - STAGEpv.put(moveTo/mm2fs) - - self.stagePos.append(STAGEpv.get()) - - else: - print("{} Where are my X-rays?".format(self.time)) - self.jitters.append(np.nan) - self.jstds.append(np.nan) - self.amps.append(np.nan) - self.astds.append(np.nan) - self.stagePos.append(np.nan) - - self.draw_plot() - - - def draw_plot(self): - self.plot_jitters.clear() - self.plot_amps.clear() - self.plot_edges.clear() - self.plot_timeseries_jitters.clear() - self.plot_timeseries_amps.clear() - self.plot_stage.clear() - - self.plot_edges.set_xlabel('relative arrival time, fs') - self.plot_edges.set_xlim(-1500,1500) - self.plot_edges.set_ylabel('transmission change, %') - - self.plot_timeseries_jitters.set_xlabel('time ago, a.u.') - self.plot_timeseries_jitters.set_ylabel('arrival time, fs') - - self.plot_timeseries_amps.set_xlabel('time ago, a.u.') - self.plot_timeseries_amps.set_ylabel('edge amplitude, %') - - self.plot_stage.set_xlabel('time ago, a.u.') - self.plot_stage.set_ylabel('m452 position, mm') - - self.plot_edges.set_xlabel('relative arrival time, fs') - self.plot_edges.set_xlim(-1500,1500) - self.plot_edges.set_ylabel('transmission change, %') - - self.plot_jitters.set_xlabel('relative arrival time, fs') - self.plot_jitters.set_ylabel('counts') - - self.plot_amps.set_xlabel('edge amplitudes, %') - self.plot_amps.set_ylabel('counts') - - if (len(self.deriv) > 0): - self.plot_edges.plot(timeAx, self.deriv[random.randrange(0, len(self.deriv))], color='grey') - self.plot_edges.plot(timeAx, self.deriv[random.randrange(0, len(self.deriv))], color='grey') - self.plot_edges.plot(timeAx, self.deriv[random.randrange(0, len(self.deriv))], color='grey') - self.plot_edges.plot(timeAx, self.deriv[random.randrange(0, len(self.deriv))], color='grey') - self.plot_edges.plot(timeAx, self.deriv[random.randrange(0, len(self.deriv))], color='grey') - self.plot_edges.plot(timeAx, np.mean(self.deriv, axis=0), color='orangered') - self.plot_edges.set_title("{}, offset of {}$\,$fs, jitter of {}$\,$fs rms".format(self.time,np.round(np.mean(self.jitter),1), np.round((np.std(self.jitter)),1))) - self.plot_edges.axvline(x=np.mean(self.jitter), color='k', linestyle="--") - self.plot_jitters.hist(self.jitter, facecolor='orangered', edgecolor='black') - self.plot_amps.hist(self.amp, facecolor='orangered', edgecolor='black') - - self.plot_stage.plot(self.stagePos, 'o-') - self.plot_timeseries_jitters.fill_between(np.arange(0, len(self.jitters)), np.asarray(self.jstds)+np.asarray(self.jitters), -np.asarray(self.jstds)+np.asarray(self.jitters), color='gold') - self.plot_timeseries_jitters.plot(np.arange(0, len(self.jitters)), self.jitters, 'o-', color='orangered') - self.plot_timeseries_amps.plot(np.arange(0, len(self.amps)), self.amps, 'o-', color='orangered') - self.plot_timeseries_amps.fill_between(np.arange(0, len(self.amps)), np.asarray(self.astds)+np.asarray(self.amps), -np.asarray(self.astds)+np.asarray(self.amps), color='gold') - - self.plot_edges.draw() - self.plot_jitters.draw() - self.plot_amps.draw() - self.plot_timeseries_jitters.draw() - self.plot_timeseries_amps.draw() - self.plot_stage.draw() - - - def on_click_clearQ(self, _event): - self.jitters.clear() - self.jstds.clear() - self.amps.clear() - self.astds.clear() - self.stagePos.clear() diff --git a/start.py b/start.py deleted file mode 100755 index 0f27cd4..0000000 --- a/start.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python - -import os -import wx - -from slic.gui.persist import Persistence - -from bstrd import bsstream - -from panel import MainPanel - - -def run(*args, **kwargs): - app = wx.App() - wx.Yield = app.Yield - frame = MainFrame(*args, **kwargs) - frame.Show() - app.MainLoop() - app.Yield() #TODO: without this, wxPython segfaults locking a mutex - - -def get_wx_icon(fname="icon.png"): - iname = os.path.dirname(__file__) - iname = os.path.join(iname, fname) - return wx.Icon(iname) - - - -class MainFrame(wx.Frame): - - def __init__(self, title="Coffee 365"): - super().__init__(None, title=title) - self.SetIcon(get_wx_icon()) - - main = MainPanel(self) - - # make sure the window is large enough - sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(main, proportion=1, flag=wx.EXPAND) - self.SetSizerAndFit(sizer) - - self.persist = persist = Persistence(".coffee365", self) - persist.load() - - self.Bind(wx.EVT_CLOSE, self.on_close) - - - def on_close(self, event): - print("bye") - bsstream.stop() - self.persist.save() - event.Skip() # forward the close event - wx.GetApp().Yield() - - - -if __name__ == "__main__": - run() - - -