def test_waveform_callback_with_count_arg(self): values = [] # NOTE: do not use get_pv() here, as `count` is incompatible with # the cache wf = PV(pvnames.char_arr_pv, count=32) def onChanges(pvname=None, value=None, char_value=None, **kw): write('PV %s %s, %s Changed!\n' % (pvname, repr(value), char_value)) values.append(value) wf.add_callback(onChanges) write('Added a callback. Now wait for changes...\n') t0 = time.time() while time.time() - t0 < 3: time.sleep(1.e-4) if len(values) > 0: break self.failUnless(len(values) > 0) self.assertEquals(len(values[0]), 32) wf.clear_callbacks()
def start_processes(counter_pv, data_pv, logger, *args): """ This is a main thread that starts thread reacting to the callback, starts the consuming process, and sets a callback on the frame counter PV change. The function then awaits for the data in the exit queue that indicates that all frames have been processed. The functin cancells the callback on exit. Parameters ---------- counter_pv : str a PV string for the area detector frame counter data_pv : str a PV string for the area detector frame data logger : Logger a Logger instance, typically synchronized with the consuming process logger *args : list a list of arguments specific to the client process Returns ------- None """ data_thread = CAThread(target = deliver_data, args=(data_pv, logger,)) data_thread.start() start_process(globals.process_dataq, logger, *args) cntr = PV(counter_pv) cntr.add_callback(on_change, index = 1) globals.exitq.get() cntr.clear_callbacks()
def run_test_sofb(): """Test SOFB IOC frequency.""" def print_time(pvname, value, **kwargs): _ = pvname nonlocal times, values # times.append(time.time()) times.append(kwargs['timestamp']) values.append(value[0]) print(datetime.datetime.fromtimestamp(times[-1]).isoformat(), value[0]) times = [] values = [] pv = PV('SI-Glob:AP-SOFB:SlowOrbX-Mon') pv.wait_for_connection() pv.add_callback(print_time) total = 30 time.sleep(total) # times = values print(f'frequency: {len(times)/total:.2f} Hz') print(f'average time: {np.mean(np.diff(times))*1000:.2f} ms') print(f'std time: {np.std(np.diff(times))*1000:.2f} ms') print(f'min time: {np.min(np.diff(times))*1000:.2f} ms') print(f'max time: {np.max(np.diff(times))*1000:.2f} ms') np.savetxt('si_sofb.txt', times) pv.clear_callbacks()
class PVIntegrator: """PVIntegrator""" def __init__(self,pv = "IBC1H04CRCUR2",name=None,outpv=None): self.output_name = outpv if self.output_name != None : self.output_pv = PV(self.output_name) #else : # self.output_pv = None self.total = 0.0 self.name = name self.total_time = 0.000000001 if name is None: self.name = pv self.pv_name = pv self.process_var = PV(self.pv_name) def Reset(self): self.total = 0.0 self.total_time = 0.000000001 def PVChangeCallback(self,pvname=None, value=None, char_value=None, **kws): value = float(char_value) self.total = self.total + 2.0*value # 2.0 s readout self.total_time = self.total_time + 2.0 def AddCallback(self): self.process_var.add_callback(self.PVChangeCallback) def ClearCallback(self): self.process_var.clear_callbacks() def Dump(self): print str("{:^10} total charge = {} mC").format(self.pv_name, self.total*0.001) print str("{:^10} average current = {} uA").format("", self.total/self.total_time) def Print(self): self.ClearCallback() print str("{:^10} total charge = {} mC").format(self.pv_name, self.total*0.001) print str("{:^10} average current = {} uA").format("", self.total/self.total_time) def GetJSONObject(self): self.ClearCallback() trip_dict = {'total': float(self.total)} trip_dict.update({'PV': self.pv_name}) return {self.name: trip_dict } def PrintJSON(self): print "writing json"
def run(self, data, store, signal, context, **kwargs): """ The main run method of the PvTriggerTask task. Args: data (MultiTaskData): The data object that has been passed from the predecessor task. store (DataStoreDocument): The persistent data store object that allows the task to store data for access across the current workflow run. signal (TaskSignal): The signal object for tasks. It wraps the construction and sending of signals into easy to use methods. context (TaskContext): The context in which the tasks runs. """ params = self.params.eval(data, store) skipped_initial = False if params.skip_initial_callback else True polling_event_number = 0 queue = deque() # set up the internal callback pv = PV(params.pv_name, callback=partial(self._pv_callback, queue=queue)) while True: if params.event_trigger_time is not None: time.sleep(params.event_trigger_time) # check every stop_polling_rate events the stop signal polling_event_number += 1 if polling_event_number > params.stop_polling_rate: polling_event_number = 0 if signal.is_stopped: break # get all the events from the queue and call the callback function while len(queue) > 0: event = queue.pop() if skipped_initial: if self._callback is not None: self._callback(data, store, signal, context, **event) else: skipped_initial = True pv.clear_callbacks() return Action(data)
def test_get_callback(self): write("Callback test: changing PV must be updated\n") global NEWVALS mypv = PV(pvnames.updating_pv1) NEWVALS = [] def onChanges(pvname=None, value=None, char_value=None, **kw): write( 'PV %s %s, %s Changed!\n' % (pvname, repr(value), char_value)) NEWVALS.append( repr(value)) mypv.add_callback(onChanges) write('Added a callback. Now wait for changes...\n') t0 = time.time() while time.time() - t0 < 3: time.sleep(1.e-4) write(' saw %i changes.\n' % len(NEWVALS)) self.failUnless(len(NEWVALS) > 3) mypv.clear_callbacks()
class PVTracker: def __init__(self, pvname = "hcCOINRunAccumulatedCharge",name=None): self.pv_name = pvname self.name = name self.process_var = PV(pvname) self.value = self.process_var.get() def PVChangeCallback(self,pvname=None, value=None, char_value=None, **kws): self.value = value def AddCallback(self): self.process_var.add_callback(self.PVChangeCallback) def ClearCallback(self): self.process_var.clear_callbacks() def Dump(self): print str("{} value = {} ").format(self.name, self.value)
def test_get_callback(self): write("Callback test: changing PV must be updated\n") global NEWVALS mypv = PV(pvnames.updating_pv1) NEWVALS = [] def onChanges(pvname=None, value=None, char_value=None, **kw): write( 'PV %s %s, %s Changed!\n' % (pvname, repr(value), char_value)) NEWVALS.append( repr(value)) mypv.add_callback(onChanges) write('Added a callback. Now wait for changes...\n') t0 = time.time() while time.time() - t0 < 3: time.sleep(1.e-4) write(' saw %i changes.\n' % len(NEWVALS)) self.failUnless(len(NEWVALS) > 3) mypv.clear_callbacks()
def test_waveform_callback_with_count_arg(self): values = [] wf = PV(pvnames.char_arr_pv, count=32) def onChanges(pvname=None, value=None, char_value=None, **kw): write( 'PV %s %s, %s Changed!\n' % (pvname, repr(value), char_value)) values.append( value) wf.add_callback(onChanges) write('Added a callback. Now wait for changes...\n') t0 = time.time() while time.time() - t0 < 3: time.sleep(1.e-4) if len(values)>0: break self.failUnless(len(values) > 0) self.assertEquals(len(values[0]),32) wf.clear_callbacks()
def main(argv=None): global dbd global simulate global fp global shut_open global current global T_stop dSi111 = SRXenergy.d111 dbragg = SRXenergy.dBragg #parse command line options usage = "usage: %prog [options]\nData files are written to /data/<year>/<month>/<day>/" parser = OptionParser(usage) parser.add_option("--wait", action="store", type="float", dest="stall", help="wait at each step [seconds]") parser.add_option("--config", action="store", type="string", dest="fname", help="name of config file") parser.add_option("--simulate", action="store_true", dest="sim", default=False, help="simulate motor moves and bursting") parser.add_option("--checkbeam", action="store_true", dest="checkbeam", default=False, help="only acquire when beam is on") parser.add_option("--acqtime", action="store", type="float", dest="acqt", help="image integration time [sec]") parser.add_option("--acqnum", action="store", type="int", dest="acqn", help="images to collect") (options, args) = parser.parse_args() #open log file D0 = time.localtime()[0] D1 = time.localtime()[1] D2 = time.localtime()[2] D3 = time.localtime()[3] D4 = time.localtime()[4] cd = os.getcwd() fstr = '/nfs/xf05id1/data/' if sys.argv[0][0] == '.': out_filename=fstr+repr(D0)+'/'+repr(D1)+'/'+repr(D2)+'/'+'log_'+repr(D0)+'_'+repr(D1)+'_'+repr(D2)+'_'+repr(D3)+'_'+repr(D4)+'_'+\ string.split(string.strip(sys.argv[0],'./'),'/')[0]+'.txt' else: out_filename=fstr+repr(D0)+'/'+repr(D1)+'/'+repr(D2)+'/'+'log_'+repr(D0)+'_'+repr(D1)+'_'+repr(D2)+'_'+repr(D3)+'_'+repr(D4)+'_'+\ string.split(string.strip(sys.argv[0],'./'),'/')[5]+'.txt' try: os.chdir(fstr + repr(D0)) except OSError: try: os.mkdir(fstr + repr(D0)) except Exception: print 'cannot create directory: ' + fstr + repr(D0) sys.exit() try: os.chdir(fstr + repr(D0) + '/' + repr(D1)) except OSError: try: os.mkdir(fstr + repr(D0) + '/' + repr(D1)) except Exception: print 'cannot create directory: ' + fstr + repr(D0) + '/' + repr( D1) sys.exit() try: os.chdir(fstr + repr(D0) + '/' + repr(D1) + '/' + repr(D2)) except OSError: try: os.mkdir(fstr + repr(D0) + '/' + repr(D1) + '/' + repr(D2)) except Exception: print 'cannot create directory: ' + fstr + repr(D0) + '/' + repr( D1) + '/' + repr(D2) sys.exit() try: fp = open(out_filename, 'a') except Exception: print 'cannot open file: ' + out_filename sys.exit() try: os.chdir(fstr + repr(D0) + '/' + repr(D1) + '/' + repr(D2) + '/' + 'HDF5') except OSError: try: os.mkdir(fstr + repr(D0) + '/' + repr(D1) + '/' + repr(D2) + '/' + 'HDF5') except Exception: print 'cannot create directory: ' + fstr + repr(D0) + '/' + repr( D1) + '/' + repr(D2) + '/' + 'HDF5' sys.exit() # H5path=fstr+repr(D0)+'/'+repr(D1)+'/'+repr(D2)+'/HDF5' H5path = '/epics/data/2015-3/300226-2' # H5path='/epics/data/2015-3/in-house' os.chdir(cd) fp.write('#') fp.write(', '.join(sys.argv)) fp.write('\n') #open list of scan points try: fconfig = open(options.fname) except Exception: print "cannot open file containing scan points. Error opening: " + options.fname sys.exit() fstr = '#a default string' pN = 0 angle = list() ivu = list() t2gap = list() while fstr.rsplit().__len__() > 0: if (fstr[0] is not '#'): pN = pN + 1 angle.append(fstr.rsplit()[0]) ivu.append(fstr.rsplit()[1]) t2gap.append(fstr.rsplit()[2]) fstr = fconfig.readline() fconfig.close() #initialize PVs and callbacks detstr = 'XF:05IDA{IM:1}' bmot = PV('XF:05IDA-OP:1{Mono:HDCM-Ax:P}Mtr.VAL', connection_timeout=4) bmot_cur = PV('XF:05IDA-OP:1{Mono:HDCM-Ax:P}Mtr.RBV', connection_timeout=4) bmot_stop = PV('XF:05IDA-OP:1{Mono:HDCM-Ax:P}Mtr.STOP', connection_timeout=4) umot = PV('SR:C5-ID:G1{IVU21:1-Mtr:2}Inp:Pos', connection_timeout=4) umot_cur = PV('SR:C5-ID:G1{IVU21:1-LEnc}Gap', connection_timeout=4) umot_go = PV('SR:C5-ID:G1{IVU21:1-Mtr:2}Sw:Go', connection_timeout=4) gmot = PV('XF:05IDA-OP:1{Mono:HDCM-Ax:X2}Mtr.VAL', connection_timeout=4) gmot_cur = PV('XF:05IDA-OP:1{Mono:HDCM-Ax:X2}Mtr.RBV', connection_timeout=4) gmot_stop = PV('XF:05IDA-OP:1{Mono:HDCM-Ax:X2}Mtr.STOP', connection_timeout=4) shut_status = PV('SR:C05-EPS{PLC:1}Shutter:Sum-Sts', connection_timeout=4) beam_current = PV('SR:C03-BI{DCCT:1}I:Total-I', connection_timeout=4) bragg_temp = PV('XF:05IDA-OP:1{Mono:HDCM-Ax:P}T-I', connection_timeout=4) norm0 = PV('XF:05IDD-BI:1{BPM:01}.S20', connection_timeout=4) norm1 = PV('XF:05IDD-BI:1{BPM:01}.S21', connection_timeout=4) norm2 = PV('XF:05IDD-BI:1{BPM:01}.S22', connection_timeout=4) norm3 = PV('XF:05IDD-BI:1{BPM:01}.S23', connection_timeout=4) wb = srxslit.nsls2slit(tb='XF:05IDA-OP:1{Slt:1-Ax:T}', bb='XF:05IDA-OP:1{Slt:1-Ax:B}', ib='XF:05IDA-OP:1{Slt:1-Ax:I}', ob='XF:05IDA-OP:1{Slt:1-Ax:O}') pb = srxslit.nsls2slit(ib='XF:05IDA-OP:1{Slt:2-Ax:I}', ob='XF:05IDA-OP:1{Slt:2-Ax:O}') ssa = srxslit.nsls2slit(tb='XF:05IDB-OP:1{Slt:SSA-Ax:T}', bb='XF:05IDB-OP:1{Slt:SSA-Ax:B}', ob='XF:05IDB-OP:1{Slt:SSA-Ax:O}', ib='XF:05IDB-OP:1{Slt:SSA-Ax:I}') x3acq = PV('XSPRESS3-EXAMPLE:Acquire', connection_timeout=4) x3erase = PV('XSPRESS3-EXAMPLE:ERASE', connection_timeout=4) x3acqtime = PV('XSPRESS3-EXAMPLE:AcquireTime', connection_timeout=4) x3acqnum = PV('XSPRESS3-EXAMPLE:NumImages', connection_timeout=4) x3tmode = PV('XSPRESS3-EXAMPLE:TriggerMode', connection_timeout=4) x3h5path = PV('XSPRESS3-EXAMPLE:HDF5:FilePath', connection_timeout=4) x3h5fname = PV('XSPRESS3-EXAMPLE:HDF5:FileName', connection_timeout=4) x3h5fnum = PV('XSPRESS3-EXAMPLE:HDF5:FileNumber', connection_timeout=4) x3h5vdim = PV('XSPRESS3-EXAMPLE:HDF5:NumExtraDims', connection_timeout=4) x3h5size = PV('XSPRESS3-EXAMPLE:HDF5:ExtraDimSizeN', connection_timeout=4) x3h5d1 = PV('XSPRESS3-EXAMPLE:HDF5:ExtraDimSizeX', connection_timeout=4) x3h5d2 = PV('XSPRESS3-EXAMPLE:HDF5:ExtraDimSizeY', connection_timeout=4) x3h5writerbv = PV('XSPRESS3-EXAMPLE:HDF5:WriteFile_RBV', connection_timeout=2) #report ROIs for channels and counts at each point x3ch1roi0min = PV('XSPRESS3-EXAMPLE:C1_MCA_ROI1_LLM', connection_timeout=4) x3ch1roi0max = PV('XSPRESS3-EXAMPLE:C1_MCA_ROI1_HLM', connection_timeout=4) x3ch1roi0ct = PV('XSPRESS3-EXAMPLE:C1_ROI1:Value_RBV', connection_timeout=4) x3ch1roi1min = PV('XSPRESS3-EXAMPLE:C1_MCA_ROI2_LLM', connection_timeout=4) x3ch1roi1max = PV('XSPRESS3-EXAMPLE:C1_MCA_ROI2_HLM', connection_timeout=4) x3ch1roi1ct = PV('XSPRESS3-EXAMPLE:C1_ROI2:Value_RBV', connection_timeout=4) x3ch1roi2min = PV('XSPRESS3-EXAMPLE:C1_MCA_ROI3_LLM', connection_timeout=4) x3ch1roi2max = PV('XSPRESS3-EXAMPLE:C1_MCA_ROI3_HLM', connection_timeout=4) x3ch1roi2ct = PV('XSPRESS3-EXAMPLE:C1_ROI3:Value_RBV', connection_timeout=4) x3ch2roi0min = PV('XSPRESS3-EXAMPLE:C2_MCA_ROI1_LLM', connection_timeout=4) x3ch2roi0max = PV('XSPRESS3-EXAMPLE:C2_MCA_ROI1_HLM', connection_timeout=4) x3ch2roi0ct = PV('XSPRESS3-EXAMPLE:C2_ROI1:Value_RBV', connection_timeout=4) x3ch2roi1min = PV('XSPRESS3-EXAMPLE:C2_MCA_ROI2_LLM', connection_timeout=4) x3ch2roi1max = PV('XSPRESS3-EXAMPLE:C2_MCA_ROI2_HLM', connection_timeout=4) x3ch2roi1ct = PV('XSPRESS3-EXAMPLE:C2_ROI2:Value_RBV', connection_timeout=4) x3ch2roi2min = PV('XSPRESS3-EXAMPLE:C2_MCA_ROI3_LLM', connection_timeout=4) x3ch2roi2max = PV('XSPRESS3-EXAMPLE:C2_MCA_ROI3_HLM', connection_timeout=4) x3ch2roi2ct = PV('XSPRESS3-EXAMPLE:C2_ROI3:Value_RBV', connection_timeout=4) x3ch3roi0min = PV('XSPRESS3-EXAMPLE:C3_MCA_ROI1_LLM', connection_timeout=4) x3ch3roi0max = PV('XSPRESS3-EXAMPLE:C3_MCA_ROI1_HLM', connection_timeout=4) x3ch3roi0ct = PV('XSPRESS3-EXAMPLE:C3_ROI1:Value_RBV', connection_timeout=4) x3ch3roi1min = PV('XSPRESS3-EXAMPLE:C3_MCA_ROI2_LLM', connection_timeout=4) x3ch3roi1max = PV('XSPRESS3-EXAMPLE:C3_MCA_ROI2_HLM', connection_timeout=4) x3ch3roi1ct = PV('XSPRESS3-EXAMPLE:C3_ROI2:Value_RBV', connection_timeout=4) x3ch3roi2min = PV('XSPRESS3-EXAMPLE:C3_MCA_ROI3_LLM', connection_timeout=4) x3ch3roi2max = PV('XSPRESS3-EXAMPLE:C3_MCA_ROI3_HLM', connection_timeout=4) x3ch3roi2ct = PV('XSPRESS3-EXAMPLE:C3_ROI3:Value_RBV', connection_timeout=4) #claim ROI 4 for our own use. we will integrate over all 4096 channels. x3ch1roi3min = PV('XSPRESS3-EXAMPLE:C1_MCA_ROI4_LLM', connection_timeout=4) x3ch1roi3max = PV('XSPRESS3-EXAMPLE:C1_MCA_ROI4_HLM', connection_timeout=4) x3ch1roi3ct = PV('XSPRESS3-EXAMPLE:C1_ROI4:Value_RBV', connection_timeout=4) x3ch2roi3min = PV('XSPRESS3-EXAMPLE:C2_MCA_ROI4_LLM', connection_timeout=4) x3ch2roi3max = PV('XSPRESS3-EXAMPLE:C2_MCA_ROI4_HLM', connection_timeout=4) x3ch2roi3ct = PV('XSPRESS3-EXAMPLE:C2_ROI4:Value_RBV', connection_timeout=4) x3ch3roi3min = PV('XSPRESS3-EXAMPLE:C3_MCA_ROI4_LLM', connection_timeout=4) x3ch3roi3max = PV('XSPRESS3-EXAMPLE:C3_MCA_ROI4_HLM', connection_timeout=4) x3ch3roi3ct = PV('XSPRESS3-EXAMPLE:C3_ROI4:Value_RBV', connection_timeout=4) dett = PV('XF:05IDD-ES:1{EVR:1-Out:FP3}Src:Scale-SP', connection_timeout=4) deti = PV('XF:05IDA{IM:1}Per-SP', connection_timeout=4) detinit = PV('XF:05IDA{IM:1}Cmd:Init', connection_timeout=4) det0 = PV(detstr + 'Cur:I0-I', connection_timeout=4) det1 = PV(detstr + 'Cur:I1-I', connection_timeout=4) det2 = PV(detstr + 'Cur:I2-I', connection_timeout=4) det3 = PV(detstr + 'Cur:I3-I', connection_timeout=4) bmot.info bmot_cur.info bmot_stop.info umot.info umot_cur.info umot_go.info gmot.info gmot_cur.info gmot_stop.info det0.info det1.info det2.info det3.info bragg_temp.info bmot_cur.add_callback(cbfx) bmot_cur.run_callbacks() umot_cur.add_callback(cbfy) umot_cur.run_callbacks() gmot_cur.add_callback(cbfz) gmot_cur.run_callbacks() shut_status.add_callback(cbf_shut) beam_current.add_callback(cbf_curr) shut_status.run_callbacks() beam_current.run_callbacks() bragg_temp.add_callback(cbf_temp) bragg_temp.run_callbacks() x3h5path.put(H5path) x3h5fname.put( repr(D0) + '_' + repr(D1) + '_' + repr(D2) + '_' + repr(D3) + '_' + repr(D4) + '_') x3h5fnum.put(0) x3acqtime.put(options.acqt) x3acqnum.put(options.acqn) x3tmode.put(1) x3ch1roi3min.put(0) x3ch2roi3min.put(0) x3ch3roi3min.put(0) x3ch1roi3max.put(4096) x3ch2roi3max.put(4096) x3ch3roi3max.put(4096) #h5 set up x3h5vdim.put(1) x3h5size.put(options.acqn) x3h5d1.put(pN) x3h5d2.put(0) roits = x3ch3roi3ct.timestamp dett.put(3) #overhead on triggering F460 deti.put(float(options.acqn) * options.acqt * .9) detinit.put(1) #check command line options if options.stall == None: twait = 0. else: twait = options.stall str = '#NSLS-II SRX' + time.asctime() fp.write(str) fp.write('\n') str = '# Start time is ' + time.asctime() print str fp.write(str) fp.write('\n') if options.sim is True: str = " -----simulating motor moves and bursts-----" print str fp.write(str) fp.write('\n') else: x3h5capture.put(1) dett.put(4) while x3h5capture.get() == 0: time.sleep(0.5) time.sleep(2) while x3h5writerbv.get() == 0: x3h5capture.put(0) print "File write is not confirmed. Waiting for confirmation..." time.sleep(30) x3h5capture.put(1) time.sleep(2) dett.put(3) str='# bragg: %(br)6.4f ; undulator: %(un)6.4f ; gap: %(cg)f ; ROI1 %(roi1i)d:%(roi1a)d ; ROI2 %(roi2i)d:%(roi2a)d ; ROI3 %(roi3i)d:%(roi3a)d'%\ {"br":bmot_cur.get(),"un":umot_cur.get(), "cg":gmot_cur.get(),'roi1i':x3ch1roi0min.get(), 'roi1a':x3ch1roi0max.get(), 'roi2i':x3ch1roi1min.get(), 'roi2a':x3ch1roi1max.get(), 'roi3i':x3ch1roi2min.get(), 'roi3a':x3ch1roi2max.get()} print str fp.write(str) fp.write('\n') str = "# --------------------" print str fp.write(str) fp.write('\n') str = "# bragg u-gap c-gap energy I0-1 I0-2 I0-3 I0-4 time ROI-1 ROI-2 ROI-3 ROI-4 intensity" print str fp.write(str) fp.write('\n') LN = 0 oldsig = det0.get() t0 = time.time() sig0 = 0. sig1 = 0. sig2 = 0. sig3 = 0. nsig0 = 0. nsig1 = 0. nsig2 = 0. nsig3 = 0. for x in range(0, pN): tar[0][1] = 1 tar[0][0] = float(angle[x]) tar[1][1] = 1 tar[1][0] = float(ivu[x]) tar[2][1] = 1 tar[2][0] = float(t2gap[x]) #if tar[0][0] is the original position, raise "in position" flag if indeadband(float(tar[0][0]), float(bmot_cur.get()), dbd) == 1: tar[0][1] = 0 if indeadband(float(tar[1][0]), float(umot_cur.get()), dbd) == 1: tar[1][1] = 0 if indeadband(float(tar[2][0]), float(gmot_cur.get()), dbd) == 1: tar[2][1] = 0 if options.sim is False: bmot.put(tar[0][0]) umot.put(tar[1][0]) gmot.put(tar[2][0]) time.sleep(1) umot_go.put(0) else: tar[0][1] = 0 tar[1][1] = 0 tar[2][1] = 0 while (tar[0][1] == 1) or (tar[1][1] == 1) or (tar[2][1] == 1): time.sleep(0.05) if LN > 400: umot_go.put(0) LN = 0 else: LN = LN + 1 if options.sim is False: time.sleep(twait) while (options.checkbeam and (shut_open == False or beam_current == False)) or T_stop == True: print "Stopped. Waiting for scan conditions to return to normal." if shut_open == False: print "\t->shutter is closed" elif beam_current == False: print "\t->Ring current is below threshold" elif T_stop == True: print "\t->HDCM pitch motor is too hot" else: print "\t->why not have a nice cup of tea or hit ctrl-C?" time.sleep(60.) x3erase.put(1) dett.put(4) nsig0 = norm0.get() nsig1 = norm1.get() nsig2 = norm2.get() nsig3 = norm3.get() #?? # sig0=sig1=sig2=sig3=3 sig0 = sig1 = sig2 = sig3 = 0 for i in range(0, options.acqn): x3acq.put(1) while (x3ch3roi3ct.get() == 0.0 or x3ch3roi3ct.timestamp == roits): time.sleep(0.02) sig0 = sig0 + x3ch1roi0ct.get() + x3ch2roi0ct.get( ) + x3ch3roi0ct.get() sig1 = sig1 + x3ch1roi1ct.get() + x3ch2roi1ct.get( ) + x3ch3roi1ct.get() sig2 = sig2 + x3ch1roi2ct.get() + x3ch2roi2ct.get( ) + x3ch3roi2ct.get() sig3 = sig3 + x3ch1roi3ct.get() + x3ch2roi3ct.get( ) + x3ch3roi3ct.get() # sig0=sig0+x3ch2roi0ct.get()+x3ch3roi0ct.get() # sig1=sig1+x3ch2roi1ct.get()+x3ch3roi1ct.get() # sig2=sig2+x3ch2roi2ct.get()+x3ch3roi2ct.get() # sig3=sig3+x3ch2roi3ct.get()+x3ch3roi3ct.get() roits = x3ch3roi3ct.timestamp signal0 = float(det1.get()) while (signal0 == 0.0): signal0 = float(det1.get()) # while(signal0 == oldsig): # signal0=det0.get() # oldsig=signal0 dett.put(3) else: while (options.checkbeam and (shut_open == False or beam_current == False)): print "Stopped. Waiting for beam to return." time.sleep(60.) signal0 = 0. nsig1 = 0 nsig2 = 0 nsig3 = 0 tn = time.time() - t0 if options.sim is False: # str=' %(B)8.4f %(U)8.4f %(G)8.3f %(E)8.2f %(C0)10.7e %(C1)10.7e %(C2)10.7e %(C3)10.7e %(T)d %(ROI1)d %(ROI2)d %(ROI3)d %(ROI4)d %(T1)10.7e'%{"B":float(bmot_cur.get()), "U":float(umot_cur.get()), "G":float(gmot_cur.get()), "C0":nsig0, "C1":nsig1, "C2":nsig2, "C3":nsig3, "ROI1":sig0,'T':tn,"ROI2":sig1,"ROI3":sig2,"ROI4":sig3,"T1":signal0,"E":12398.4 / (2 * 3.13029665951 * math.sin((bmot_cur.get()+0.323658778534)/180.*np.pi))} str = ' %(B)8.4f %(U)8.4f %(G)8.3f %(E)8.2f %(C0)10.7e %(C1)10.7e %(C2)10.7e %(C3)10.7e %(T)d %(ROI1)d %(ROI2)d %(ROI3)d %(ROI4)d %(T1)10.7e' % { "B": float(bmot_cur.get()), "U": float(umot_cur.get()), "G": float(gmot_cur.get()), "C0": nsig0, "C1": nsig1, "C2": nsig2, "C3": nsig3, "ROI1": sig0, 'T': tn, "ROI2": sig1, "ROI3": sig2, "ROI4": sig3, "T1": signal0, "E": 12398.4 / (2 * dSi111 * math.sin( (bmot_cur.get() + dbragg) / 180. * np.pi)) } print str fp.write(str) fp.write('\n') else: str = ' B= %(B)8.4f U= %(U)8.4f G= %(G)8.3f : %(C0)10.7e %(C1)10.7e %(C2)10.7e %(C3)10.7e %(ROI)d %(T)d' % { "B": tar[0][0], "U": tar[1][0], "G": tar[2][0], "C0": signal0, "C1": nsig1, "C2": nsig2, "C3": nsig3, "ROI": x3ch1roi0ct.get(), 'T': time.time() } print str fp.write(str) fp.write('\n') str = '#End time is ' + time.asctime() print str fp.write(str) fp.write('\n') fp.close() bmot_cur.clear_callbacks() umot_cur.clear_callbacks() gmot_cur.clear_callbacks() shut_status.clear_callbacks() beam_current.clear_callbacks() bragg_temp.clear_callbacks() return 0
class _RunListener: '''Run listener for a single run type. Helper class for RunDaemon. ''' def __init__(self, run_type): '''Initialize the listener for run_type.''' self.run_type = run_type.upper() self.name = 'listener for {} runs'.format(self.run_type) print('Creating ' + self.name) self.reset() #print('hc{}RunNumber'.format(self.run_type)) self.pv_run_number = PV('hc{}RunNumber'.format(self.run_type)) self.pv_is_running = PV('hc{}RunInProgress'.format(self.run_type)) def reset(self): '''Reset/initialize the listener.''' self.tasks = {'run_start': [], 'run_stop': []} self.coda_running = False self.run_number = -1 def on_event(self, event, callback): '''Append callback task to the listener.''' if event in self.tasks: self.tasks[event].append(callback) else: raise EventTypeError(event, [e for e in self.tasks]) def interrupt(self): '''Interrupt the listener by issue a run_stop event if CODA is running.''' self.pv_is_running.clear_callbacks() if self.coda_running: self._run_stop() def listen(self): '''Start listening for events.''' self.pv_is_running.add_callback(self._listener) def _listener(self, pvname=None, value=None, char_value=None, **kwargs): '''Event listener, dispatches events.''' run_in_progress = int(char_value) self.run_number = self.pv_run_number.get() ## Bail and print warning if we could not get a valid run number if self.run_number is None: print('WARNING({}): Unable to load run number from EPICS'.format( self.name)) print('WARNING({}): Skipping this callback...'.format(self.name)) return self.run_number = int(self.run_number) if run_in_progress and not self.coda_running: self._run_start() elif not run_in_progress and self.coda_running: self._run_stop() def _run_start(self): '''Handle run_start event.''' print('New {} run started: {}'.format(self.run_type, self.run_number)) self.coda_running = True for task in self.tasks['run_start']: task(self.run_number) def _run_stop(self): '''Handle run_stop event.''' print('End of {} run: {}'.format(self.run_type, self.run_number)) self.coda_running = False for task in self.tasks['run_stop']: task(self.run_number)
class XltEpics(Assembly): def __init__(self, pvname="SLAAR02-LTIM-PDLY", name="lxt_epics"): super().__init__(name=name) self.pvname = pvname self.settings_collection.append(self, force=True) self.status_indicators_collection.append(self, force=True) self._append( PvEnum, self.pvname + ":SHOTDELAY", name="oscillator_pulse_offset", is_setting=True, is_status=True, ) self._append( PvEnum, self.pvname + ":SHOTMOFFS_ENA", name="modulo_offset_mode", is_setting=True, is_status=True, ) self._append( PvRecord, self.pvname + ":DELAY_Z_OFFS", name="_offset", is_setting=True, is_status=False, ) self._append( AdjustableVirtual, [self._offset], lambda offset: offset * 1e-12, lambda offset: offset / 1e-12, name="offset", is_setting=False, is_status=True, ) self._append( PvRecord, self.pvname + ":DELAY", name="_set_user_delay_value", is_setting=False, is_status=False, ) self._append( PvRecord, self.pvname + ":P_RATIO", name="rep_len", is_setting=True, is_status=True, ) self._append( PvRecord, "SIN-TIMAST-TMA:Evt-22-Freq-SP", name="laser_frequency", is_setting=True, is_status=True, ) self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2") self.alias.append( Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA") ) self.waiting_for_change = PV(self.pvname + ":WAITING") def get_current_dial_value(self): return self._delay_dial_rb.get() * 1e-6 def get_current_value(self): return self.get_current_dial_value() - self.offset.get_current_value() def change_user_and_wait(self, value, check_interval=0.03): if np.abs(value) > 0.1: raise Exception("Very large value! This value is counted in seconds!") if not self.waiting_for_change.get(): raise Exception("lxt is still moving!") self.is_moving = False self.is_stopped = False def set_is_stopped(**kwargs): old_status = self.is_moving new_status = not bool(kwargs["value"]) if (not new_status) and old_status: self.is_stopped = True self.is_moving = new_status self.waiting_for_change.add_callback(callback=set_is_stopped) self._set_user_delay_value.set_target_value(value / 1e-12) while not self.is_stopped: time.sleep(check_interval) self.waiting_for_change.clear_callbacks() def set_target_value(self, value, hold=False): return Changer( target=value, parent=self, changer=self.change_user_and_wait, hold=hold, stopper=None, ) def reset_current_value_to(self, value): self.offset.set_target_value((self.get_current_dial_value() - value)).wait()
class TripCounter: """Trip Counter""" def __init__(self,pv = "IBC1H04CRCUR2",th=7.6,name=None): self.name = name if name is None: self.name = pv self.trip_count = 0 self.currently_tripped = False self.trip_threshold = th self.pv_name = pv self.process_var = PV(self.pv_name) self.trips = [] self.latest_trip = None def Reset(self): self.trip_count = 0 self.currently_tripped = False self.trips = [] self.latest_trip = None def PVChangeCallback(self,pvname=None, value=None, char_value=None, **kws): """Call back for epics PV.""" #self.trip_count #self.trip_threshold #self.currently_tripped value = float(char_value) #print 'PV :', pvname, char_value, time.ctime(), " thresh ", self.trip_threshold if (value < self.trip_threshold) and not self.currently_tripped: self.latest_trip = Trip(len(self.trips)) print 'PV tripped!', pvname, char_value, time.strftime('%X %x %Z') self.trip_count = self.trip_count +1 print self.trip_count self.currently_tripped = True if self.currently_tripped and (value > self.trip_threshold): print 'PV restored', pvname, char_value, time.strftime('%X %x %Z') self.currently_tripped = False if not (self.latest_trip == None) : self.latest_trip.stop() self.trips.append(self.latest_trip) #if self.currently_tripped: # print 'PV still tripped', pvname, char_value, time.ctime() def AddCallback(self): self.process_var.add_callback(self.PVChangeCallback) def ClearCallback(self): self.process_var.clear_callbacks() def Dump(self): print(self.pv_name, "counts ", self.trip_count ) def Print(self): self.ClearCallback() print(self.pv_name, "counts ", self.trip_count ) def GetJSONObject(self): self.ClearCallback() all_trips = [] for num,atrip in enumerate(self.trips): all_trips.append(atrip.GetJSONObject()) trip_dict = {'trips': len(self.trips)} trip_dict.update({'PV': self.pv_name}) trip_dict.update({'trip_events': all_trips}) return {self.name: trip_dict } def PrintJSON(self): print "printing "
def main(argv=None): global dbd global simulate global fp global xmot_cur #deadband in motor units dbd = .001 #parse command line options usage = "usage: %prog [options]\nData files are written to /data/<year>/<month>/<day>/" parser = OptionParser(usage) parser.add_option("--motname", action="store", type="string", dest="motname", help="motor to scan") parser.add_option("--detname", action="store", type="string", dest="detname", help="detector to trigger") parser.add_option("--xstart", action="store", type="float", dest="xo", help="starting X position") parser.add_option("--xnumstep", action="store", type="int", dest="Nx", help="number of steps in X") parser.add_option("--xstepsize", action="store", type="float", dest="dx", help="step size in X") parser.add_option( "--deadband", action="store", type="float", dest="dbd", help="software deadband for motion, default is 0.001 motor units") parser.add_option("--wait", action="store", type="float", dest="stall", help="wait at each step [seconds]") parser.add_option("--simulate", action="store_true", dest="sim", default=False, help="simulate motor moves and bursting") parser.add_option("--acqtime", action="store", type="float", dest="acqt", help="SDD acquisition time at each step [seconds]") (options, args) = parser.parse_args() #open log file D0 = time.localtime()[0] D1 = time.localtime()[1] D2 = time.localtime()[2] D3 = time.localtime()[3] D4 = time.localtime()[4] cd = os.getcwd() fstr = '/nfs/xf05id1/data/' if sys.argv[0][0] == '.': out_filename=fstr+repr(D0)+'/'+repr(D1)+'/'+repr(D2)+'/'+'log_'+repr(D3)+'_'+repr(D4)+'_'+\ string.split(string.strip(sys.argv[0],'./'),'/')[0]+'.txt' else: out_filename=fstr+repr(D0)+'/'+repr(D1)+'/'+repr(D2)+'/'+'log_'+repr(D3)+'_'+repr(D4)+'_'+\ string.split(string.strip(sys.argv[0],'./'),'/')[5]+'.txt' try: os.chdir(fstr + repr(D0)) except OSError: try: os.mkdir(fstr + repr(D0)) except Exception: print 'cannot create directory: ' + fstr + repr(D0) sys.exit() try: os.chdir(fstr + repr(D0) + '/' + repr(D1)) except OSError: try: os.mkdir(fstr + repr(D0) + '/' + repr(D1)) except Exception: print 'cannot create directory: ' + fstr + repr(D0) + '/' + repr( D1) sys.exit() try: os.chdir(fstr + repr(D0) + '/' + repr(D1) + '/' + repr(D2)) except OSError: try: os.mkdir(fstr + repr(D0) + '/' + repr(D1) + '/' + repr(D2)) except Exception: print 'cannot create directory: ' + fstr + repr(D0) + '/' + repr( D1) + '/' + repr(D2) sys.exit() H5path = '/epics/data/201507' try: fp = open(out_filename, 'a') except Exception: print 'cannot open file: ' + out_filename sys.exit() os.chdir(cd) fp.write(', '.join(sys.argv)) fp.write('\n') #initialize PVs and callbacks if options.motname == None: # xmotstr='XF:03IDA-OP{Mon:1-Ax:P}' xmotstr = '' print "must provide motor pv base, e.g., 'XF:28IDA-OP:1{Slt:MB1-Ax:T}'" sys.exit() else: xmotstr = options.motname if options.detname == None: # detstr='XF:03IDA-BI{FS:1-CAM:1}' detstr = '' print "must provide detector pv base, e.g., 'XF:28IDA-BI{URL:01}'" sys.exit() else: detstr = options.detname if xmotstr.rsplit('{')[1].rsplit('}')[0] == 'IVU21:1-Mtr:2': undpv = True else: undpv = False if options.dbd is not None: dbd = options.dbd #transmission if undpv is False: xmot = PV(xmotstr + 'Mtr.VAL', connection_timeout=2) xmot_cur = PV(xmotstr + 'Mtr.RBV', connection_timeout=2) xmot_stop = PV(xmotstr + 'Mtr.STOP', connection_timeout=2) else: xmot = PV(xmotstr + 'Inp:Pos', connection_timeout=2) xmot_cur = PV(xmotstr.rsplit('{')[0] + '{IVU21:1-LEnc}Gap', connection_timeout=2) xmot_stop = PV(xmotstr + 'Sw:Go', connection_timeout=2) # det_acq = PV(detstr+'Cur:I0-I') if 'IM' in detstr: det0_acq = PV(detstr, connection_timeout=4) det1_acq = PV(detstr.replace('I0-I', 'I1-I'), connection_timeout=4) else: det0_acq = PV(detstr, connection_timeout=2) det1_acq = None x3acq = PV('XSPRESS3-EXAMPLE:Acquire', connection_timeout=2) x3erase = PV('XSPRESS3-EXAMPLE:ERASE', connection_timeout=2) x3acqtime = PV('XSPRESS3-EXAMPLE:AcquireTime', connection_timeout=2) x3acqnum = PV('XSPRESS3-EXAMPLE:NumImages', connection_timeout=2) x3tmode = PV('XSPRESS3-EXAMPLE:TriggerMode', connection_timeout=2) x3h5path = PV('XSPRESS3-EXAMPLE:HDF5:FilePath', connection_timeout=2) x3h5fname = PV('XSPRESS3-EXAMPLE:HDF5:FileName', connection_timeout=2) x3h5fnum = PV('XSPRESS3-EXAMPLE:HDF5:FileNumber', connection_timeout=2) x3h5capture = PV('XSPRESS3-EXAMPLE:HDF5:Capture', connection_timeout=2) x3ch1roi0min = PV('XSPRESS3-EXAMPLE:C1_MCA_ROI1_LLM', connection_timeout=2) x3ch1roi0max = PV('XSPRESS3-EXAMPLE:C1_MCA_ROI1_HLM', connection_timeout=2) x3ch1roi0ct = PV('XSPRESS3-EXAMPLE:C1_ROI1:Value_RBV', connection_timeout=2) xmot_cur.get(as_string=True) xmot_cur.add_callback(cbfx) xmot_cur.run_callbacks() det0_acq.info if det1_acq is not None: det1_acq.info #check command line options if options.xo == None: xo = xmot_cur.get(timeout=3) else: xo = options.xo if options.dx == None: dx = 0.00000001 else: dx = options.dx if options.Nx == None: Nx = 0 else: Nx = options.Nx if options.stall == None: twait = 0. else: twait = options.stall x3h5path.put(H5path) x3h5fname.put(repr(D3) + '_' + repr(D4) + '_') x3h5fnum.put(0) x3acqtime.put(options.acqt) x3acqnum.put(1) x3tmode.put(1) str = 'Start time is ' + time.asctime() print str fp.write(str) fp.write('\n') if options.sim is True: str = " -----simulating motor moves and bursts-----" print str fp.write(str) fp.write('\n') str="Current position [mm]: %(XC)7.3f" %\ {"XC":xmot_cur.get(timeout=3)} print str fp.write(str) fp.write('\n') str="Starting scan at: %(XO)7.3f"%\ {"XO":xo} print str fp.write(str) fp.write('\n') time.sleep(2) #number of rows and columns completed by scan Ncol = 0 LN = 0 #scan direction for x dir = 1 #intensity ROIint = -1 count = 0 #nested loops for scanning z,x,y for x in frange(0, Nx * dx, dx): tar[0][1] = 1 tar[0][0] = x + xo #if tar[0][0] is the original position, raise "in position" flag if indeadband(float(tar[0][0]), float(xmot_cur.get()), dbd) == 1: tar[0][1] = 0 if options.sim is False: xmot.put(tar[0][0]) if undpv == True: time.sleep(0.5) xmot_stop.put(0) else: tar[0][1] = 0 while (tar[0][1] == 1): if LN > 1000: LN = 0 xmot.put(tar[0][0]) LN = LN + 1 xmot.info if xmot.severity == 2: str = "\t scan stopped at " + xmot_cur.get() print str fp.write(str) fp.write('\n') raw_input( "clear motor error and press enter (or ctrl-C to halt)" ) xmot.put(tar[0][0]) time.sleep(twait) if options.sim is False: time.sleep(twait) x3h5capture.put(1) x3erase.put(1) x3acq.put(1) signal = [0., 0.] signal[0] = float(det0_acq.get()) while (signal[0] == 0.): time.sleep(0.01) signal[0] = float(det0_acq.get()) if det1_acq is not None: signal[1] = float(det1_acq.get()) while (signal[1] == 0.): time.sleep(0.01) signal[1] = float(det1_acq.get()) time.sleep(options.acqt) else: print "bang" signal = 0. if options.sim is False: sigstr = '%(one)10.7e %(two)10.7e' % { 'one': signal[0], 'two': signal[1] } str = ' [%(X)04d] at (X= %(XC)9.4f ): signal is %(RI)s ' % { "X": Ncol, "XC": xmot_cur.get(), "RI": sigstr } print str fp.write(str) fp.write('\n') else: str = ' [%(X)04d] at (X= %(XC)8.3f )' % { "X": Ncol, "XC": tar[0][0] } print str fp.write(str) fp.write('\n') Ncol = Ncol + 1 #return to starting positions if options.sim is False: xmot.put(xo) time.sleep(0.01) if undpv == True: time.sleep(0.5) xmot_stop.put(0) str = 'End time is ' + time.asctime() print str fp.write(str) fp.write('\n') fp.close() xmot_cur.clear_callbacks() return 0
class Feed: """ This class reads frames in a real time using pyepics, and delivers to consuming process. """ def __init__(self): """ Constructor This constructor creates the following queues: process_dataq : a queue used to pass data to the consuming process exitq : a queue used to signal awaiting process the end of processing, so the resources can be closed thread_dataq : this queue delivers counter number on change from call back thread Other fields are initialized. """ self.process_dataq = Queue() self.exitq = tqueue.Queue() self.thread_dataq = tqueue.Queue() self.sizex = 0 self.sizey = 0 self.no_frames = 0 self.sequence = None self.sequence_index = 0 self.callback_pv = None self.counter_pv = None self.offset = 0 self.ctr = None self.file_name = [] def deliver_data(self, data_pv, frame_type_pv, logger): """ This function receives data, processes it, and delivers to consuming process. This function is invoked at the beginning of the feed as a distinct thread. It reads data from a thread_dataq inside a loop that delivers current counter value on change. If the counter is not a consecutive number to the previous reading a 'missing' string is enqueued into process_dataq in place of the data to mark the missing frames. For every received frame data, it reads a data type from PV, and the two elements are delivered to a consuming process via process_dataq as Data instance. If a sequence is defined, then the data type for this frame determined from sequence is compared with the data type read from PV. If they are different, a warning log is recorded. On the loop exit an 'all_data' string is enqueud into the inter-process queue, and 'exit' string is enqueued into the inter-thread queue, to notify the main thread of the exit event. Parameters ---------- data_pv : str a PV string for the area detector data frame_type_pv : str a PV string for the area detector data type logger : Logger a Logger instance, typically synchronized with the consuming process logger Returns ------- None """ def build_type_map(): types = {} types[0] = 'data' types[1] = 'data_dark' types[2] = 'data_white' # types[3] = 'data' # it'd double correlation, but leave data for now return types def verify_sequence(logger, data_type): while frame_index > self.sequence[self.sequence_index][1]: self.sequence_index += 1 planned_data_type = self.sequence[self.sequence_index][0] if planned_data_type != data_type: logger.warning('The data type for frame number ' + str( frame_index) + ' is ' + data_type + ' but was planned ' + planned_data_type) types = build_type_map() self.done = False frame_index = 0 while not self.done: try: callback_item = self.thread_dataq.get(timeout=1) if isinstance(callback_item, (int, long, float)): # came from on_change function current_counter = callback_item if self.callback_pv is None: file_name = None else: if len(self.file_name) > 0: file_name = self.file_name.pop(0) else: print('race conditions') else: self.file_name.append(callback_item) continue except tqueue.Empty: continue if self.no_frames < 0 or current_counter < self.no_frames + 1: try: data = np.array(caget(data_pv)) data_type = types[caget(frame_type_pv)] if data is None: self.finish() done = True logger.error('reading image times out, possibly the detector exposure time is too small') else: delta = current_counter - self.ctr self.ctr = current_counter data.resize(self.sizex, self.sizey) if delta > 1: for i in range(1, delta): self.process_dataq.put(adapter.pack_data(None, "missing")) frame_index += delta packed_data = self.get_packed_data(data, data_type, file_name) self.process_dataq.put(packed_data) if self.sequence is not None: verify_sequence(logger, data_type) except: self.finish() self.done = True logger.error('reading image raises exception, possibly the detector exposure time is too small') else: self.done = True self.finish() def get_packed_data(self, data, data_type, file_name): return adapter.pack_data(data, data_type) def acq_done(self, pvname=None, **kws): """ A callback method that activates when a frame counter of area detector changes. This method reads the counter value and enqueues it into inter-thread queue that will be dequeued by the 'deliver_data' function. If it is a first read, the function adjusts counter data in the self object. Parameters ---------- pvname : str a PV string for the area detector frame counter Returns ------- None """ # if the callback is not on the counter pv, keep track of counter if kws['value'] == 0: self.thread_dataq.put(self.ctr + 1) def on_change(self, pvname=None, **kws): """ A callback method that activates when a frame counter of area detector changes. This method reads the counter value and enqueues it into inter-thread queue that will be dequeued by the 'deliver_data' function. If it is a first read, the function adjusts counter data in the self object. Parameters ---------- pvname : str a PV string for the area detector frame counter Returns ------- None """ file_name = kws['value'][:-1] file_name = ''.join(chr(i) for i in file_name) self.thread_dataq.put(file_name) def on_ctr_change(self, pvname=None, **kws): """ A callback method that activates when a frame counter of area detector changes. This method reads the counter value and enqueues it into inter-thread queue that will be dequeued by the 'deliver_data' function. If it is a first read, the function adjusts counter data in the self object. Parameters ---------- pvname : str a PV string for the area detector frame counter Returns ------- None """ current_ctr = kws['value'] # on first callback adjust the values if self.ctr is None: self.offset = current_ctr self.ctr = 0 else: current_ctr -= self.offset if current_ctr > 1: self.thread_dataq.put(current_ctr) else: self.ctr = current_ctr def start_processes(self, acquire_pv, counter_pv_name, data_pv, frame_type_pv, logger, reportq, *args, **kwargs): """ This function starts processes and callbacks. This is a main thread that starts thread reacting to the callback, starts the consuming process, and sets a callback on the frame counter PV change. The function then awaits for the data in the exit queue that indicates that all frames have been processed. The functin cancells the callback on exit. Parameters ---------- counter_pv : str a PV string for the area detector frame counter data_pv : str a PV string for the area detector frame data frame_type_pv : str a PV string for the area detector data type logger : Logger a Logger instance, typically synchronized with the consuming process logger *args : list a list of arguments specific to the client process Returns ------- None """ data_thread = CAThread(target=self.deliver_data, args=(data_pv, frame_type_pv, logger,)) data_thread.start() p = Process(target=handler.handle_data, args=(self.process_dataq, reportq, args, kwargs,)) p.start() self.counter_pv = PV(counter_pv_name) self.counter_pv.add_callback(self.on_ctr_change, index=1) self.acq_pv = PV(acquire_pv) self.acq_pv.add_callback(self.acq_done, index=2) try: callback_pv_name = kwargs['callback_pv'] self.callback_pv = PV(callback_pv_name) self.callback_pv.add_callback(self.on_change, as_string=True, index=3) except KeyError: pass def get_pvs(self, detector): """ This function takes defined strings from configuration file and constructs PV variables that are accessed during processing. Parameters ---------- detector : str a string defining the first prefix in area detector, it has to match the area detector configuration Returns ------- acquire_pv : str a PV string representing acquireing state counter_ pv : str a PV string representing frame counter data_pv : str a PV string representing acquired data sizex_pv : str a PV string representing x size of acquired data sizey_pv : str a PV string representing y size of acquired data frame_type_pv : str a PV string for the area detector data type """ acquire_pv = detector + ':cam1:Acquire' counter_pv = detector + ':cam1:ArrayCounter_RBV' data_pv = detector + ':image1:ArrayData' sizex_pv = detector + ':image1:ArraySize0_RBV' sizey_pv = detector + ':image1:ArraySize1_RBV' frame_type_pv = detector + ':cam1:FrameType' return acquire_pv, counter_pv, data_pv, sizex_pv, sizey_pv, frame_type_pv def feed_data(self, logger, reportq, *args, **kwargs): # no_frames, detector, logger, sequence=None, *args): """ This function is called by a client to start the process. After all initial settings are completed, the method awaits for the area detector to start acquireing by polling the PV. When the area detective is active it starts processing. Parameters ---------- no_frames : int number of frames to feed, indefinately if -1 detector : str detector name logger : Logger a Logger instance, recommended to use the same logger for feed and consuming process sequence : list or int if int, the number is used to set number of frames to process, if list, take the number of frames from the list, and verify the sequence of data is correct during processing *args : list a list of process specific arguments Returns ------- None """ acquire_pv, counter_pv, data_pv, sizex_pv, sizey_pv, frame_type_pv = self.get_pvs(kwargs['detector']) self.no_frames = args[2] test = True while test: self.sizex = caget(sizex_pv) self.sizey = caget(sizey_pv) ack = caget(acquire_pv) if ack == 1: test = False self.start_processes(acquire_pv, counter_pv, data_pv, frame_type_pv, logger, reportq, *args, **kwargs) else: time.sleep(.005) return caget(acquire_pv) def finish(self): self.process_dataq.put(adapter.pack_data(None, const.DATA_STATUS_END)) self.done = True try: self.counter_pv.clear_callbacks() self.acq_pv.clear_callbacks() if not self.callback_pv is None: self.callback_pv.clear_callbacks() except: pass
class Feed: """ This class reads frames in a real time using pyepics, and delivers to consuming process. """ def __init__(self): """ Constructor This constructor creates the following queues: process_dataq : a queue used to pass data to the consuming process exitq : a queue used to signal awaiting process the end of processing, so the resources can be closed thread_dataq : this queue delivers counter number on change from call back thread Other fields are initialized. """ self.process_dataq = Queue() self.exitq = tqueue.Queue() self.thread_dataq = tqueue.Queue() self.sizex = 0 self.sizey = 0 self.no_frames = 0 self.ctr = 0 self.sequence = None self.sequence_index = 0 self.cntr_pv = None def deliver_data(self, data_pv, frame_type_pv, logger): """ This function receives data, processes it, and delivers to consuming process. This function is invoked at the beginning of the feed as a distinct thread. It reads data from a thread_dataq inside a loop that delivers current counter value on change. If the counter is not a consecutive number to the previous reading a 'missing' string is enqueued into process_dataq in place of the data to mark the missing frames. For every received frame data, it reads a data type from PV, and the two elements are delivered to a consuming process via process_dataq as Data instance. If a sequence is defined, then the data type for this frame determined from sequence is compared with the data type read from PV. If they are different, a warning log is recorded. On the loop exit an 'all_data' string is enqueud into the inter-process queue, and 'exit' string is enqueued into the inter-thread queue, to notify the main thread of the exit event. Parameters ---------- data_pv : str a PV string for the area detector data frame_type_pv : str a PV string for the area detector data type logger : Logger a Logger instance, typically synchronized with the consuming process logger Returns ------- None """ def build_type_map(): types = {} types[0] = 'data' types[1] = 'data_dark' types[2] = 'data_white' types[3] = 'data' # it'd double correlation, but leave data for now return types def verify_sequence(logger, data_type): while frame_index > self.sequence[self.sequence_index][1]: self.sequence_index += 1 planned_data_type = self.sequence[self.sequence_index][0] if planned_data_type != data_type: logger.warning('The data type for frame number ' + str(frame_index) + ' is ' + data_type + ' but was planned ' + planned_data_type) # def finish(): # self.process_dataq.put(pack_data(None, "end")) # self.exitq.put('exit') types = build_type_map() done = False frame_index = 0 while not done: current_counter = self.thread_dataq.get() if self.no_frames < 0 or current_counter < self.no_frames: try: data = np.array(caget(data_pv)) data_type = types[caget(frame_type_pv)] if data is None: self.finish() done = True logger.error('reading image times out, possibly the detector exposure time is too small') else: delta = current_counter - self.ctr self.ctr = current_counter data.resize(self.sizex, self.sizey) if delta > 1: for i in range (1, delta): self.process_dataq.put(adapter.pack_data(None, "missing")) frame_index += delta packed_data = self.get_packed_data(data, data_type) self.process_dataq.put(packed_data) if self.sequence is not None: verify_sequence(logger, data_type) except: self.finish() done = True logger.error('reading image raises exception, possibly the detector exposure time is too small') else: done = True self.finish() def get_packed_data(self, data, data_type): return adapter.pack_data(data, data_type) def on_change(self, pvname=None, **kws): """ A callback method that activates when a frame counter of area detector changes. This method reads the counter value and enqueues it into inter-thread queue that will be dequeued by the 'deliver_data' function. If it is a first read, the function adjusts counter data in the self object. Parameters ---------- pvname : str a PV string for the area detector frame counter Returns ------- None """ current_ctr = kws['value'] #on first callback adjust the values if self.ctr == 0: self.ctr = current_ctr if self.no_frames >= 0: self.no_frames += current_ctr self.thread_dataq.put(current_ctr) def start_processes(self, counter_pv, data_pv, frame_type_pv, logger, *args): """ This function starts processes and callbacks. This is a main thread that starts thread reacting to the callback, starts the consuming process, and sets a callback on the frame counter PV change. The function then awaits for the data in the exit queue that indicates that all frames have been processed. The functin cancells the callback on exit. Parameters ---------- counter_pv : str a PV string for the area detector frame counter data_pv : str a PV string for the area detector frame data frame_type_pv : str a PV string for the area detector data type logger : Logger a Logger instance, typically synchronized with the consuming process logger *args : list a list of arguments specific to the client process Returns ------- None """ data_thread = CAThread(target = self.deliver_data, args=(data_pv, frame_type_pv, logger,)) data_thread.start() adapter.start_process(self.process_dataq, logger, *args) self.cntr_pv = PV(counter_pv) self.cntr_pv.add_callback(self.on_change, index = 1) # self.exitq.get() # print 'got Exit in exitq stopping callback' # self.cntr.clear_callbacks() def get_pvs(self, detector, detector_basic, detector_image): """ This function takes defined strings from configuration file and constructs PV variables that are accessed during processing. Parameters ---------- detector : str a string defining the first prefix in area detector, it has to match the area detector configuration detector_basic : str a string defining the second prefix in area detector, defining the basic parameters, it has to match the area detector configuration detector_image : str a string defining the second prefix in area detector, defining the image parameters, it has to match the area detector configuration Returns ------- acquire_pv : str a PV string representing acquireing state counter_ pv : str a PV string representing frame counter data_pv : str a PV string representing acquired data sizex_pv : str a PV string representing x size of acquired data sizey_pv : str a PV string representing y size of acquired data frame_type_pv : str a PV string for the area detector data type """ acquire_pv = detector + ':' + detector_basic + ':' + 'Acquire' counter_pv = detector + ':' + detector_basic + ':' + 'NumImagesCounter_RBV' data_pv = detector + ':' + detector_image + ':' + 'ArrayData' sizex_pv = detector + ':' + detector_image + ':' + 'ArraySize0_RBV' sizey_pv = detector + ':' + detector_image + ':' + 'ArraySize1_RBV' frame_type_pv = detector + ':' + detector_basic + ':' + 'FrameType' return acquire_pv, counter_pv, data_pv, sizex_pv, sizey_pv, frame_type_pv def feed_data(self, no_frames, detector, detector_basic, detector_image, logger, sequence=None, *args): """ This function is called by an client to start the process. It parses configuration and gets needed process variables. It stores necessary values in the self object. After all initial settings are completed, the method awaits for the area detector to start acquireing by polling the PV. When the area detective is active it starts processing. Parameters ---------- config : str a configuration file logger : Logger a Logger instance, recommended to use the same logger for feed and consuming process sequence : list or int if int, the number is used to set number of frames to process, if list, take the number of frames from the list, and verify the sequence of data is correct during processing *args : list a list of process specific arguments Returns ------- None """ acquire_pv, counter_pv, data_pv, sizex_pv, sizey_pv, frame_type_pv = self.get_pvs(detector, detector_basic, detector_image) self.no_frames = no_frames # if sequence is None: # self.no_frames = no_frames # elif type(sequence) is int: # self.no_frames = sequence # else: # self.sequence = sequence # self.no_frames = sequence[len(sequence)-1][1] + 1 test = True while test: self.sizex = caget (sizex_pv) self.sizey = caget (sizey_pv) ack = caget(acquire_pv) if ack == 1: test = False self.start_processes(counter_pv, data_pv, frame_type_pv, logger, *args) return caget(acquire_pv) def finish(self): self.process_dataq.put(adapter.pack_data(None, "end")) self.cntr_pv.clear_callbacks()
class Feed: """ This class reads frames in a real time using pyepics, and delivers to consuming process. """ def __init__(self): """ Constructor This constructor creates the following queues: process_dataq : a queue used to pass data to the consuming process exitq : a queue used to signal awaiting process the end of processing, so the resources can be closed thread_dataq : this queue delivers counter number on change from call back thread Other fields are initialized. """ self.process_dataq = Queue() self.exitq = tqueue.Queue() self.thread_dataq = tqueue.Queue() self.sizex = 0 self.sizey = 0 self.no_frames = 0 self.ctr = 0 self.sequence = None self.sequence_index = 0 self.cntr_pv = None def deliver_data(self, data_pv, frame_type_pv, logger): """ This function receives data, processes it, and delivers to consuming process. This function is invoked at the beginning of the feed as a distinct thread. It reads data from a thread_dataq inside a loop that delivers current counter value on change. If the counter is not a consecutive number to the previous reading a 'missing' string is enqueued into process_dataq in place of the data to mark the missing frames. For every received frame data, it reads a data type from PV, and the two elements are delivered to a consuming process via process_dataq as Data instance. If a sequence is defined, then the data type for this frame determined from sequence is compared with the data type read from PV. If they are different, a warning log is recorded. On the loop exit an 'all_data' string is enqueud into the inter-process queue, and 'exit' string is enqueued into the inter-thread queue, to notify the main thread of the exit event. Parameters ---------- data_pv : str a PV string for the area detector data frame_type_pv : str a PV string for the area detector data type logger : Logger a Logger instance, typically synchronized with the consuming process logger Returns ------- None """ def build_type_map(): types = {} types[0] = 'data' types[1] = 'data_dark' types[2] = 'data_white' types[ 3] = 'data' # it'd double correlation, but leave data for now return types def verify_sequence(logger, data_type): while frame_index > self.sequence[self.sequence_index][1]: self.sequence_index += 1 planned_data_type = self.sequence[self.sequence_index][0] if planned_data_type != data_type: logger.warning('The data type for frame number ' + str(frame_index) + ' is ' + data_type + ' but was planned ' + planned_data_type) # def finish(): # self.process_dataq.put(pack_data(None, "end")) # self.exitq.put('exit') types = build_type_map() done = False frame_index = 0 while not done: current_counter = self.thread_dataq.get() if self.no_frames < 0 or current_counter < self.no_frames: try: data = np.array(caget(data_pv)) data_type = types[caget(frame_type_pv)] if data is None: self.finish() done = True logger.error( 'reading image times out, possibly the detector exposure time is too small' ) else: delta = current_counter - self.ctr self.ctr = current_counter data.resize(self.sizex, self.sizey) if delta > 1: for i in range(1, delta): self.process_dataq.put( adapter.pack_data(None, "missing")) frame_index += delta packed_data = self.get_packed_data(data, data_type) self.process_dataq.put(packed_data) if self.sequence is not None: verify_sequence(logger, data_type) except: self.finish() done = True logger.error( 'reading image raises exception, possibly the detector exposure time is too small' ) else: done = True self.finish() def get_packed_data(self, data, data_type): return adapter.pack_data(data, data_type) def on_change(self, pvname=None, **kws): """ A callback method that activates when a frame counter of area detector changes. This method reads the counter value and enqueues it into inter-thread queue that will be dequeued by the 'deliver_data' function. If it is a first read, the function adjusts counter data in the self object. Parameters ---------- pvname : str a PV string for the area detector frame counter Returns ------- None """ current_ctr = kws['value'] #on first callback adjust the values if self.ctr == 0: self.ctr = current_ctr if self.no_frames >= 0: self.no_frames += current_ctr self.thread_dataq.put(current_ctr) def start_processes(self, counter_pv, data_pv, frame_type_pv, logger, *args): """ This function starts processes and callbacks. This is a main thread that starts thread reacting to the callback, starts the consuming process, and sets a callback on the frame counter PV change. The function then awaits for the data in the exit queue that indicates that all frames have been processed. The functin cancells the callback on exit. Parameters ---------- counter_pv : str a PV string for the area detector frame counter data_pv : str a PV string for the area detector frame data frame_type_pv : str a PV string for the area detector data type logger : Logger a Logger instance, typically synchronized with the consuming process logger *args : list a list of arguments specific to the client process Returns ------- None """ data_thread = CAThread(target=self.deliver_data, args=( data_pv, frame_type_pv, logger, )) data_thread.start() adapter.start_process(self.process_dataq, logger, *args) self.cntr_pv = PV(counter_pv) self.cntr_pv.add_callback(self.on_change, index=1) # self.exitq.get() # print 'got Exit in exitq stopping callback' # self.cntr.clear_callbacks() def get_pvs(self, detector, detector_basic, detector_image): """ This function takes defined strings from configuration file and constructs PV variables that are accessed during processing. Parameters ---------- detector : str a string defining the first prefix in area detector, it has to match the area detector configuration detector_basic : str a string defining the second prefix in area detector, defining the basic parameters, it has to match the area detector configuration detector_image : str a string defining the second prefix in area detector, defining the image parameters, it has to match the area detector configuration Returns ------- acquire_pv : str a PV string representing acquireing state counter_ pv : str a PV string representing frame counter data_pv : str a PV string representing acquired data sizex_pv : str a PV string representing x size of acquired data sizey_pv : str a PV string representing y size of acquired data frame_type_pv : str a PV string for the area detector data type """ acquire_pv = detector + ':' + detector_basic + ':' + 'Acquire' counter_pv = detector + ':' + detector_basic + ':' + 'NumImagesCounter_RBV' data_pv = detector + ':' + detector_image + ':' + 'ArrayData' sizex_pv = detector + ':' + detector_image + ':' + 'ArraySize0_RBV' sizey_pv = detector + ':' + detector_image + ':' + 'ArraySize1_RBV' frame_type_pv = detector + ':' + detector_basic + ':' + 'FrameType' return acquire_pv, counter_pv, data_pv, sizex_pv, sizey_pv, frame_type_pv def feed_data(self, no_frames, detector, detector_basic, detector_image, logger, sequence=None, *args): """ This function is called by an client to start the process. It parses configuration and gets needed process variables. It stores necessary values in the self object. After all initial settings are completed, the method awaits for the area detector to start acquireing by polling the PV. When the area detective is active it starts processing. Parameters ---------- config : str a configuration file logger : Logger a Logger instance, recommended to use the same logger for feed and consuming process sequence : list or int if int, the number is used to set number of frames to process, if list, take the number of frames from the list, and verify the sequence of data is correct during processing *args : list a list of process specific arguments Returns ------- None """ acquire_pv, counter_pv, data_pv, sizex_pv, sizey_pv, frame_type_pv = self.get_pvs( detector, detector_basic, detector_image) self.no_frames = no_frames # if sequence is None: # self.no_frames = no_frames # elif type(sequence) is int: # self.no_frames = sequence # else: # self.sequence = sequence # self.no_frames = sequence[len(sequence)-1][1] + 1 test = True while test: self.sizex = caget(sizex_pv) self.sizey = caget(sizey_pv) ack = caget(acquire_pv) if ack == 1: test = False self.start_processes(counter_pv, data_pv, frame_type_pv, logger, *args) return caget(acquire_pv) def finish(self): self.process_dataq.put(adapter.pack_data(None, "end")) self.cntr_pv.clear_callbacks()
def main(argv=None): global simulate global fp global shut_open global current global x3h5capture global xmot_cur global ymot_cur global shut_status global beam_current #parse command line options usage = "usage: %prog [options]\nData files are written to /data/<year>/<month>/<day>/" parser = OptionParser(usage) parser.add_option("--detname", action="store", type="string", dest="detname", help="detector PV base") parser.add_option("--xstart", action="store", type="float", dest="xo", help="starting X position") parser.add_option("--xnumstep", action="store", type="int", dest="Nx", help="number of steps in X") parser.add_option("--xstepsize", action="store", type="float", dest="dx", help="step size in X") parser.add_option("--ystart", action="store", type="float", dest="yo", help="starting Y position") parser.add_option("--ynumstep", action="store", type="int", dest="Ny", help="number of steps in Y") parser.add_option("--ystepsize", action="store", type="float", dest="dy", help="step size in Y") parser.add_option("--wait", action="store", type="float", dest="stall", help="wait at each step [seconds]") parser.add_option("--simulate", action="store_true", dest="sim", default=False, help="simulate motor moves") parser.add_option("--checkbeam", action="store_true", dest="checkbeam", default=False, help="only acquire when beam is on") parser.add_option("--checkcryo", action="store_true", dest="checkcryo", default=False, help="only acquire when cryo status is ok") parser.add_option("--acqtime", action="store", type="float", dest="acqt", default=1, help="image integration time [sec]") parser.add_option("--acqnum", action="store", type="int", dest="acqn", default=1, help="frames per scan point") (options,args) = parser.parse_args() #open log file D0=time.localtime()[0] D1=time.localtime()[1] D2=time.localtime()[2] D3=time.localtime()[3] D4=time.localtime()[4] cd=os.getcwd() filedir = '/nfs/xf05id1/data/' if sys.argv[0][0]=='.': out_filename=filedir+repr(D0)+'/'+repr(D1)+'/'+repr(D2)+'/'+'log_'+repr(D1)+'_'+repr(D2)+'_'+repr(D3)+'_'+repr(D4)+'_'+\ string.split(string.strip(sys.argv[0],'./'),'/')[0]+'.txt' else: out_filename=filedir+repr(D0)+'/'+repr(D1)+'/'+repr(D2)+'/'+'log_'+repr(D1)+'_'+repr(D2)+'_'+repr(D3)+'_'+repr(D4)+'_'+\ string.split(string.strip(sys.argv[0],'./'),'/')[5]+'.txt' try: os.chdir(filedir+repr(D0)) except OSError: try: os.mkdir(filedir+repr(D0)) except Exception: print 'cannot create directory: '+'/data/'+repr(D0) sys.exit() try: os.chdir(filedir+repr(D0)+'/'+repr(D1)) except OSError: try: os.mkdir(filedir+repr(D0)+'/'+repr(D1)) except Exception: print 'cannot create directory: '+'/data/'+repr(D0)+'/'+repr(D1) sys.exit() try: os.chdir(filedir+repr(D0)+'/'+repr(D1)+'/'+repr(D2)) except OSError: try: os.mkdir(filedir+repr(D0)+'/'+repr(D1)+'/'+repr(D2)) except Exception: print 'cannot create directory: '+filedir+repr(D0)+'/'+repr(D1)+'/'+repr(D2) sys.exit() try: fp=open(out_filename,'a') except Exception: print 'cannot open file: '+out_filename sys.exit() os.chdir(cd) fp.write('#'+', '.join(sys.argv)) fp.write('\n') H5path='/epics/data/2015-3/in-house' #H5path='/epics/data/2015-2/testing' #initialize PVs and callbacks if options.detname == None: detstr='' print "must provide detector pv base, e.g., 'XF:28IDA-BI{URL:01}'" sys.exit() else: detstr=options.detname ##### original script for Aerotech stages # xmotname='XF:05IDD-ES:1{Stg:Smpl1-Ax:X}' # ymotname='XF:05IDD-ES:1{Stg:Smpl1-Ax:Y}' # xmot=PV(xmotname+'Mtr.VAL') # xmot_cur=PV(xmotname+'Mtr.RBV') # ymot=PV(ymotname+'Mtr.VAL') # ymot_cur=PV(ymotname+'Mtr.RBV') ###### #####modified for nPoint Stages # xmot=PV('NPOINT:CH1:SET_POSITION.A',connection_timeout=2) # xmot_cur=PV('NPOINT:CH1:GET_POSITION',connection_timeout=2) # ymot=PV('NPOINT:CH2:SET_POSITION.A',connection_timeout=2) # ymot_cur=PV('NPOINT:CH2:GET_POSITION',connection_timeout=2) #####modified for HR coarse Stages; X=Attocube ECS505 X, Y=Attocube ECS505 Z xmot=PV('XF:05IDD-ES:1{Stg:Ecs50}:ACT0:CMD:TARGET',connection_timeout=2) xmot_cur=PV('XF:05IDD-ES:1{Stg:Ecs50}:ACT0:POSITION',connection_timeout=2) ymot=PV('XF:05IDD-ES:1{Stg:Ecs50}:ACT1:CMD:TARGET',connection_timeout=2) ymot_cur=PV('XF:05IDD-ES:1{Stg:Ecs50}:ACT1:POSITION',connection_timeout=2) ##### shut_status=PV('SR:C05-EPS{PLC:1}Shutter:Sum-Sts',connection_timeout=2) beam_current=PV('SR:C03-BI{DCCT:1}I:Total-I',connection_timeout=2) bmot_cur=PV('XF:05IDA-OP:1{Mono:HDCM-Ax:P}Mtr.RBV',connection_timeout=2) #transmission #check command line options if options.yo == None: print "must provide a starting point in the vertical" sys.exit() else: yo = options.yo if options.xo == None: print "must provide a starting point in the horizontal" sys.exit() else: xo = options.xo if options.dx == None: dx = 0.00000001 else: dx = options.dx if options.dy == None: dy = 0.00000001 else: dy = options.dy if options.Nx == None: Nx = 0 else: Nx = options.Nx if options.Ny == None: Ny = 0 else: Ny = options.Ny if options.stall == None: twait = 0. else: twait = options.stall diode0=PV(detstr+'Cur:I0-I',connection_timeout=4) diode1=PV(detstr+'Cur:I1-I',connection_timeout=4) diode2=PV(detstr+'Cur:I2-I',connection_timeout=4) diode3=PV(detstr+'Cur:I3-I',connection_timeout=4) diode0.connect() diode1.connect() diode2.connect() diode3.connect() dett=PV('XF:05IDD-ES:1{EVR:1-Out:FP3}Src:Scale-SP',connection_timeout=2) deti=PV('XF:05IDA{IM:1}Per-SP',connection_timeout=4) detinit=PV('XF:05IDA{IM:1}Cmd:Init',connection_timeout=4) wb=srxslit.nsls2slit(tb='XF:05IDA-OP:1{Slt:1-Ax:T}',bb='XF:05IDA-OP:1{Slt:1-Ax:B}',ib='XF:05IDA-OP:1{Slt:1-Ax:I}',ob='XF:05IDA-OP:1{Slt:1-Ax:O}') pb=srxslit.nsls2slit(ib='XF:05IDA-OP:1{Slt:2-Ax:I}',ob='XF:05IDA-OP:1{Slt:2-Ax:O}') ssa=srxslit.nsls2slit(tb='XF:05IDB-OP:1{Slt:SSA-Ax:T}', bb='XF:05IDB-OP:1{Slt:SSA-Ax:B}', ob='XF:05IDB-OP:1{Slt:SSA-Ax:O}',ib='XF:05IDB-OP:1{Slt:SSA-Ax:I}') x3acq=PV('XSPRESS3-EXAMPLE:Acquire',connection_timeout=2) x3erase=PV('XSPRESS3-EXAMPLE:ERASE',connection_timeout=2) x3acqtime=PV('XSPRESS3-EXAMPLE:AcquireTime',connection_timeout=2) x3acqnum=PV('XSPRESS3-EXAMPLE:NumImages',connection_timeout=2) x3tmode=PV('XSPRESS3-EXAMPLE:TriggerMode',connection_timeout=2) x3h5path=PV('XSPRESS3-EXAMPLE:HDF5:FilePath',connection_timeout=2) x3h5fname=PV('XSPRESS3-EXAMPLE:HDF5:FileName',connection_timeout=2) x3h5fnum=PV('XSPRESS3-EXAMPLE:HDF5:FileNumber',connection_timeout=2) x3h5vdim=PV('XSPRESS3-EXAMPLE:HDF5:NumExtraDims',connection_timeout=2) x3h5size=PV('XSPRESS3-EXAMPLE:HDF5:ExtraDimSizeN',connection_timeout=2) x3h5d1=PV('XSPRESS3-EXAMPLE:HDF5:ExtraDimSizeX',connection_timeout=2) x3h5d2=PV('XSPRESS3-EXAMPLE:HDF5:ExtraDimSizeY',connection_timeout=2) #report ROIs for channels and counts at each point x3ch1roi0min=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI1_LLM',connection_timeout=2) x3ch1roi0max=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI1_HLM',connection_timeout=2) x3ch1roi0ct=PV('XSPRESS3-EXAMPLE:C1_ROI1:Value_RBV',connection_timeout=2) x3ch1roi1min=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI2_LLM',connection_timeout=2) x3ch1roi1max=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI2_HLM',connection_timeout=2) x3ch1roi1ct=PV('XSPRESS3-EXAMPLE:C1_ROI2:Value_RBV',connection_timeout=2) x3ch1roi2min=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI3_LLM',connection_timeout=2) x3ch1roi2max=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI3_HLM',connection_timeout=2) x3ch1roi2ct=PV('XSPRESS3-EXAMPLE:C1_ROI3:Value_RBV',connection_timeout=2) x3ch2roi0min=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI1_LLM',connection_timeout=2) x3ch2roi0max=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI1_HLM',connection_timeout=2) x3ch2roi0ct=PV('XSPRESS3-EXAMPLE:C2_ROI1:Value_RBV',connection_timeout=2) x3ch2roi1min=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI2_LLM',connection_timeout=2) x3ch2roi1max=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI2_HLM',connection_timeout=2) x3ch2roi1ct=PV('XSPRESS3-EXAMPLE:C2_ROI2:Value_RBV',connection_timeout=2) x3ch2roi2min=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI3_LLM',connection_timeout=2) x3ch2roi2max=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI3_HLM',connection_timeout=2) x3ch2roi2ct=PV('XSPRESS3-EXAMPLE:C2_ROI3:Value_RBV',connection_timeout=2) x3ch3roi0min=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI1_LLM',connection_timeout=2) x3ch3roi0max=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI1_HLM',connection_timeout=2) x3ch3roi0ct=PV('XSPRESS3-EXAMPLE:C3_ROI1:Value_RBV',connection_timeout=2) x3ch3roi1min=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI2_LLM',connection_timeout=2) x3ch3roi1max=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI2_HLM',connection_timeout=2) x3ch3roi1ct=PV('XSPRESS3-EXAMPLE:C3_ROI2:Value_RBV',connection_timeout=2) x3ch3roi2min=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI3_LLM',connection_timeout=2) x3ch3roi2max=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI3_HLM',connection_timeout=2) x3ch3roi2ct=PV('XSPRESS3-EXAMPLE:C3_ROI3:Value_RBV',connection_timeout=2) #claim ROI 4 for our own use. we will integrate over all 4096 channels. x3ch1roi3min=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI4_LLM',connection_timeout=2) x3ch1roi3max=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI4_HLM',connection_timeout=2) x3ch1roi3ct=PV('XSPRESS3-EXAMPLE:C1_ROI4:Value_RBV',connection_timeout=2) x3ch2roi3min=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI4_LLM',connection_timeout=2) x3ch2roi3max=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI4_HLM',connection_timeout=2) x3ch2roi3ct=PV('XSPRESS3-EXAMPLE:C2_ROI4:Value_RBV',connection_timeout=2) x3ch3roi3min=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI4_LLM',connection_timeout=2) x3ch3roi3max=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI4_HLM',connection_timeout=2) x3ch3roi3ct=PV('XSPRESS3-EXAMPLE:C3_ROI4:Value_RBV',connection_timeout=2) # xmot_cur.get() xmot_cur.connect() # ymot_cur.get() ymot_cur.connect() norm0=PV('XF:05IDD-BI:1{BPM:01}.S20',connection_timeout=2) norm1=PV('XF:05IDD-BI:1{BPM:01}.S21',connection_timeout=2) norm2=PV('XF:05IDD-BI:1{BPM:01}.S22',connection_timeout=2) norm3=PV('XF:05IDD-BI:1{BPM:01}.S23',connection_timeout=2) xmot_cur.add_callback(cbfx) ymot_cur.add_callback(cbfy) shut_status.add_callback(cbf_shut) beam_current.add_callback(cbf_curr) xmot_cur.run_callbacks() ymot_cur.run_callbacks() shut_status.run_callbacks() beam_current.run_callbacks() x3h5path.put(H5path) x3h5fname.put(repr(D0)+'_'+repr(D1)+'_'+repr(D2)+'_'+repr(D3)+'_'+repr(D4)+'_') x3h5fnum.put(0) x3acqtime.put(options.acqt) x3acqnum.put(options.acqn) x3tmode.put(1) x3ch1roi3min.put(0) x3ch2roi3min.put(0) x3ch3roi3min.put(0) x3ch1roi3max.put(4096) x3ch2roi3max.put(4096) x3ch3roi3max.put(4096) #h5 set up x3h5vdim.put(2) x3h5size.put(options.acqn) x3h5d1.put(options.Nx+1) x3h5d2.put(options.Ny+1) dett.put(3) #overhead on triggering F460 deti.put(float(options.acqn)*options.acqt*1.) detinit.put(1) #ring buffer and PV for tracking ion chamber value ic_hist=collections.deque(maxlen=50) ic_hist.append(0.) v19st=PV('XF:05IDA-UT{Cryo:1-IV:19}Pos-I',connection_timeout=4) v19st.connect() str='#NSLS-II SRX'+time.asctime() fp.write(str) fp.write('\n') str='#Start time is '+time.asctime() print str fp.write(str) fp.write('\n') str='# x: %(hs)6.4f ; y: %(vs)6.4f ; ROI1 %(roi1i)d:%(roi1a)d ; ROI2 %(roi2i)d:%(roi2a)d ; ROI3 %(roi3i)d:%(roi3a)d'%\ {"hs":xmot_cur.get(),"vs":ymot_cur.get(), 'roi1i':x3ch1roi0min.get(), 'roi1a':x3ch1roi0max.get(), 'roi2i':x3ch1roi1min.get(), 'roi2a':x3ch1roi1max.get(), 'roi3i':x3ch1roi2min.get(), 'roi3a':x3ch1roi2max.get()} print str fp.write(str) fp.write('\n') roits=x3ch3roi3ct.timestamp str='# SSA HCEN: %(WBHC)f ; SSA HSIZE: %(WBHS)f ; SSA VCEN: %(WBVC)f ; SSA VSIZE: %(WBVS)f'%\ {"WBHC":ssa.hcen(), "WBHS":ssa.hsize(), "WBVC":ssa.vcen(), "WBVS":ssa.vsize()} print str fp.write(str) fp.write('\n') str='# Bragg: %(B)6.4f ; Energy: %(E)6.4f ; WB HCEN: %(WBHC)f ; WB HSIZE: %(WBHS)f ; WB VCEN: %(WBVC)f ; WB VSIZE: %(WBVS)f'%\ {"B":bmot_cur.get(), "E": 12398. / (2 * 3.12964794061 * math.sin((bmot_cur.get()+0.323341791985)/180.*3.1416)), "WBHC":wb.hcen(), "WBHS":wb.hsize(), "WBVC":wb.vcen(), "WBVS":wb.vsize()} print str fp.write(str) fp.write('\n') str="# -------------------------------------------------------------------- " print str fp.write(str) fp.write('\n') str='#[point #]\tX pos\t\tY pos\tch 1\t\tch 2\t\tch 3\t\tch 4\tdBPM1\t\tdBPM2\t\tdBPM3\t\tdBPM4\t\troi0\t\troi1\t\troi2\t\troi3\t\ttime' print str fp.write(str) fp.write('\n') if options.sim is True: str=" -----simulating motor moves and bursts-----" print str fp.write(str) fp.write('\n') else: x3h5capture.put(1) dett.put(4) time.sleep(2) thisisstupid=0 while x3h5capture.get() == 0: time.sleep(0.5) thisisstupid+=1 if (thisisstupid%20==0): print "waiting for xspress3" dett.put(3) ic_hist.append(diode1.get()) #number of rows and columns completed by scan Ncol=Nrow=0 LN=0 #diode readback is now limiting factor for scan speed oldsig=0. #when the cryocooler kicks in, the beam is unusable for ~3200sec # cryo=PV('XF:05IDA-OP:1{Mono:HDCM}T:LN2Out-I') # ct=cryo.get() # while( ct is None): # time.sleep(0.1) # ct=cryo.get() # print "waiting for cryocooler to respond" t0=time.time() cryocounter=0 shut_toggle=False #nested loops for scanning z,x,y for y in np.linspace(yo,yo+((Ny)*dy),Ny+1): tar[1][0]=y tar[1][1]=1 if options.sim is False: ymot.put(tar[1][0]) if indeadband(float(tar[1][0]),float(ymot_cur.get()),dbd)==1: tar[1][1] = 0 if Nrow%2==0: xs=0.+xo xe=((Nx+1)*dx)+xo-dx xi=dx else: xs=((Nx)*dx)+xo xe=0.+xo xi=-dx for x in np.linspace(xs,xe,Nx+1): tar[0][0]=x tar[0][1]=1 if indeadband(float(tar[0][0]),float(xmot_cur.get()),dbd)==1: tar[0][1]=0 if options.sim is False: xmot.put(tar[0][0]) while ((tar[0][1] == 1) or (tar[1][1] == 1)): time.sleep(0.01) signal0=signal1=signal2=signal3=0. nsig0=nsig1=nsig2=nsig3=0. sig0=sig1=sig2=sig3=0. # while ( options.checkbeam and (cryo.get() < (ct - 0.1)) ): # print "Stopped. Detected possible cryocooler activation." # time.sleep(1) # cryocounter=cryocounter+1 #if the above is true for five cycles, the cryocooler was on, wait another 10min # if ( options.checkbeam and cryocounter > 300 ): # print "Detected cryocooler activation, waiting 10min" # time.sleep(600) # cryocounter=0 #this is my averge IC current tavg=np.asarray(ic_hist).mean() #check the filling valve status and set flag high if it is open while ( options.checkcryo and (v19st.get() > 0.)): print "Stopped. Crycooler valve V19 is open." cryocounter=1 time.sleep(1) #while the ion chamber is reading less than 80% of previous history, sleep while (cryocounter==1): #trigger the 460 and store the ion chamber value dett.put(4) time.sleep(5+options.acqt) oldsig=diode1.get() dett.put(3) #if the reading is less than 80% of historical value or the valve is open, sleep #remember that the reading is negative-going if (oldsig > (-1.*0.8*tavg)) and (v19st.get > 0.): print "Beam current has not returned" time.sleep(30) else: cryocounter=0 while ( options.checkbeam and (shut_open == False or beam_current == False)): print "Stopped. Waiting for scan conditions to return to normal." if shut_open==False: shut_toggle=True time.sleep(10.) if shut_toggle==True: print "Entering optics conditioning period. Waiting 5min" time.sleep(300) shut_toggle=False if options.sim is False: x3erase.put(1) dett.put(4) while nsig0==0.: nsig0=float(norm0.get()) while nsig1==0.: nsig1=float(norm1.get()) while nsig2==0.: nsig2=float(norm2.get()) while nsig3==0.: nsig3=float(norm3.get()) sig0=0 sig1=0 sig2=0 sig3=0 for i in range(0,options.acqn): x3acq.put(1) while ( x3ch3roi3ct.get()==0.0 or x3ch3roi3ct.timestamp==roits): time.sleep(0.02) sig0=sig0+x3ch1roi0ct.get()+x3ch2roi0ct.get()+x3ch3roi0ct.get() sig1=sig1+x3ch1roi1ct.get()+x3ch2roi1ct.get()+x3ch3roi1ct.get() sig2=sig2+x3ch1roi2ct.get()+x3ch2roi2ct.get()+x3ch3roi2ct.get() sig3=sig3+x3ch1roi3ct.get()+x3ch2roi3ct.get()+x3ch3roi3ct.get() roits=x3ch3roi3ct.timestamp signal0=diode0.get() if signal0==oldsig: time.sleep(0.02) signal0=diode0.get() oldsig=signal0 signal1=diode1.get() signal2=diode2.get() signal3=diode3.get() dett.put(3) #populate a ring buffer with every 100th ion chamber reading #we will use the average of this buffer to determine recovery #from a cryocooler activation if(Nx%100 ==0): ic_hist.append(signal1) time.sleep(twait) tn=time.time()-t0 if options.sim is False: str='%(X)06d %(XC)9.4f %(YC)9.4f %(d1)10.7e %(d2)10.7e %(d3)10.7e %(d4)10.7e %(n0)10.7e %(n1)10.7e %(n2)10.7e %(n3)10.7e %(s0)10.7e %(s1)10.7e %(s2)10.7e %(s3)10.7e %(time)9.2f'%{ 'X':Ncol, 'XC':xmot_cur.get(),"YC":ymot_cur.get(), "d1":float(signal0), "d2":float(signal1), "d3":float(signal2),"d4":float(signal3), 'n0':nsig0, 'n1':nsig1, 'n2':nsig2, 'n3':nsig3, "s0":sig0,"s1":sig1,"s2":sig2,"s3":sig3, "time":tn} print str fp.write(str) fp.write('\n') else: str='%(X)06d %(XC)8.4f %(YC)8.4f %(d1)10.7e %(d2)10.7e %(d3)10.7e %(d4)10.7e'%{"X":int(Ncol),"XC":tar[0][0], "YC":tar[1][0], "d1":float(signal0), "d2":float(signal1), "d3":float(signal2),"d4":float(signal3)} print str fp.write(str) fp.write('\n') Ncol=Ncol+1 Nrow=Nrow+1 str='#End time is '+time.asctime() print str fp.write(str) fp.write('\n') fp.close() xmot_cur.clear_callbacks() ymot_cur.clear_callbacks() shut_status.clear_callbacks() beam_current.clear_callbacks() return 0
class XAFSviewerFrame(wx.Frame): def __init__(self, parent=None, *args, **kwds): kwds["style"] = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER | wx.TAB_TRAVERSAL wx.Frame.__init__(self, parent, wx.NewId(), '', wx.DefaultPosition, wx.Size(-1, -1), **kwds) self.SetTitle(" WXMPlot Plotting Demo") self.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, False)) menu = wx.Menu() ID_EXIT = wx.NewId() ID_TIMER = wx.NewId() menu.Append(ID_EXIT, "E&xit", "Terminate the program") menuBar = wx.MenuBar() menuBar.Append(menu, "&File") self.SetMenuBar(menuBar) wx.EVT_MENU(self, ID_EXIT, self.OnExit) self.Bind(wx.EVT_CLOSE, self.OnExit) self.plotframe = None framesizer = wx.BoxSizer(wx.VERTICAL) panel = wx.Panel(self, -1, size=(-1, -1)) panelsizer = wx.BoxSizer(wx.VERTICAL) panelsizer.Add(wx.StaticText(panel, -1, 'XAFS Spectra viewer '), 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT | wx.EXPAND, 10) b40 = wx.Button(panel, -1, 'Start Timed Plot', size=(-1, -1)) #b40.Bind(wx.EVT_BUTTON,self.onStartTimer) panelsizer.Add(b40, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5) panel.SetSizer(panelsizer) panelsizer.Fit(panel) framesizer.Add(panel, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.EXPAND, 2) self.SetSizer(framesizer) framesizer.Fit(self) #----------- added by LWW ----------------------------- self.ShowPlotFrame(do_raise=False, clear=False) self.plotYdata = [] self.plotXdata = [] # ----------epics PVs----------------------- self.i0 = PV('BL10C:scaler1_calc2.VAL') self.it = PV('BL10C:scaler1_calc3.VAL') self.iF = PV('BL10C:scaler1_calc4.VAL') self.trans = PV('BL10C:scaler1_calc8.VAL') self.motorPos = PV('mobiis:m2.RBV') self.scanStart = PV('BL10C:scan2.EXSC.VAL', callback=self.scanStartCALLBACK) while self.motorPos.get() is None: print self.motorPos.get() self.countDonePV = PV('BL10C:scaler1.CNT', callback=self.countDoneCALLBACK) self.time0 = time.time() self.datrange = None #----------- end of add by LWW ----------------------- #wx.EVT_TIMER(self, ID_TIMER, self.onTimer) #self.timer = wx.Timer(self, ID_TIMER) self.Refresh() # --------------epics callback method--------------------- def scanStartCALLBACK(self, **kwargs): if kwargs['value'] is 1: # 0:Done, 1: scanning self.ShowPlotFrame(do_raise=True, clear=True) print 'New Scan Started!!!' else: print 'scan stopped!!!' return def countDoneCALLBACK(self, **kwargs): if kwargs['value'] is 1: # 0:Done, 1:Counting return ## self._flag = True self.plotYdata.append(self.trans.get()) self.plotXdata.append(self.motorPos.get()) ## self._flag = False print 'X:%s, Y:%s' % (len(self.plotXdata), len(self.plotYdata)) # Todo: we need new scan start sequence. # new list, graph clear, data save..., # print 'timer ', self.count, time.time() ## self.count += 1 #self.ShowPlotFrame(do_raise=False, clear=False) ## n = self.count if len(self.plotXdata) < 2: return # Todo: implementation of scan finish sequence. ''' if n >= self.npts: self.timer.Stop() self.timer_results() elif n <= 3: ''' if len(self.plotXdata) <= 3: self.plotframe.plot(self.plotXdata, self.plotYdata, linewidth=0.5, marker='o', markersize=6, xlabel='energy[eV]', ylabel='[count]') # , grid=False) else: xx = np.array(self.plotXdata) yy = np.array(self.plotYdata) self.plotframe.update_line(0, xx, yy, update_limits=len(xx) < 10, draw=True) etime = time.time() - self.time0 s = " %i / %i points in %8.4f s" % (len(self.plotXdata), len(self.plotYdata), etime) self.plotframe.write_message(s) if self.datrange is None: self.datrange = [min(self.plotXdata), max(self.plotXdata), min(self.plotYdata), max(self.plotYdata)] dr = [min(self.plotXdata), max(self.plotXdata), min(self.plotYdata), max(self.plotYdata)] lims = self.plotframe.panel.get_viewlimits() if dr[0] < lims[0] or dr[1] > lims[1] or dr[2] < lims[2] or dr[3] > lims[3]: self.datrange = dr ## if len(self.plotXdata) < len(self.x): ## nmax = min(int(n*1.6), len(self.x)-1) ## self.datrange[1] = self.x[nmax] self.plotframe.panel.set_xylims(self.datrange) def ShowPlotFrame(self, do_raise=True, clear=True): """make sure plot frame is enabled, and visible""" if self.plotframe is None: self.plotframe = PlotFrame(self, axissize=[0.08, 0.06, 0.91, 0.92]) # self.has_plot = False try: self.plotframe.Show() except wx.PyDeadObjectError: self.plotframe = PlotFrame(self, axissize=[0.08, 0.06, 0.91, 0.92]) self.plotframe.Show() if do_raise: self.plotframe.Raise() if clear: self.plotframe.panel.clear() self.plotframe.reset_config() self.plotYdata = [] self.plotXdata = [] ''' def onStartTimer(self,event=None): self.count = 0 self.up_count = 0 self.n_update = 1 self.datrange = None self.time0 = time.time() ### LWW self.start_mem= self.report_memory() self.timer.Start(10) # self.timer.Start(500) def timer_results(self): if (self.count < 2): return etime = time.time() - self.time0 tpp = etime/max(1,self.count) s = "drew %i points in %8.3f s: time/point= %8.4f s" % (self.count,etime,tpp) self.plotframe.write_message(s) self.time0 = 0 self.count = 0 self.datrange = None ''' ''' def onTimer(self, event): # print 'timer ', self.count, time.time() self.count += 1 self.ShowPlotFrame(do_raise=False, clear=False) n = self.count if n < 2: return if n >= self.npts: self.timer.Stop() self.timer_results() elif n <= 3: self.plotframe.plot(self.x[:n], self.y1[:n])# , grid=False) else: self.plotframe.update_line(0, self.x[:n], self.y1[:n], update_limits=n<10, draw=True) etime = time.time() - self.time0 s = " %i / %i points in %8.4f s" % (n,self.npts,etime) self.plotframe.write_message(s) if self.datrange is None: self.datrange = [min(self.x[:n]), max(self.x[:n]), min(self.y1[:n]),max(self.y1[:n])] dr = [min(self.x[:n]), max(self.x[:n]), min(self.y1[:n]), max(self.y1[:n])] lims = self.plotframe.panel.get_viewlimits() if dr[0] < lims[0] or dr[1] > lims[1] or dr[2] < lims[2] or dr[3] > lims[3]: self.datrange = dr if n < len(self.x): nmax = min(int(n*1.6), len(self.x)-1) self.datrange[1] = self.x[nmax] self.plotframe.panel.set_xylims(self.datrange) ''' def OnAbout(self, event): dlg = wx.MessageDialog(self, "This program shows MCA Spectra\n" "message dialog.", "About MPlot test", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def OnExit(self, event): # 1st. disconnect PV(s) self.countDonePV.clear_callbacks() self.i0.disconnect() self.it.disconnect() self.iF.disconnect() self.trans.disconnect() self.motorPos.disconnect() try: if self.plotframe is not None: self.plotframe.onExit() except: pass self.Destroy()