def matlabPV_FB(feedbackvalue): #get and put timedelay signal matPV = EpicsSignal('LAS:FS4:VIT:matlab:04') org_matPV = matPV.get() #the matlab PV value before FB fbvalns = feedbackvalue * 1e+9 #feedback value in ns fbinput = org_matPV + fbvalns #relative to absolute value matPV.put(fbinput) return
def test_epicssignal_get_in_callback(fake_motor_ioc, cleanup): pvs = fake_motor_ioc.pvs sig = EpicsSignal(write_pv=pvs['setpoint'], read_pv=pvs['readback'], name='motor') cleanup.add(sig) called = [] def generic_sub(sub_type, **kwargs): called.append((sub_type, sig.get(), sig.get_setpoint())) for event_type in (sig.SUB_VALUE, sig.SUB_META, sig.SUB_SETPOINT, sig.SUB_SETPOINT_META): sig.subscribe(generic_sub, event_type=event_type) sig.wait_for_connection() sig.put(1, wait=True) sig.put(2, wait=True) time.sleep(0.5) print(called) # Arbitrary threshold, but if @klauer screwed something up again, this will # blow up assert len(called) < 20 print('total', len(called)) sig.unsubscribe_all()
def test_epicssignal_get_in_callback(cleanup, fake_motor_ioc): pvs = fake_motor_ioc.pvs sig = EpicsSignal(write_pv=pvs['setpoint'], read_pv=pvs['readback'], name='motor') cleanup.add(sig) called = [] def generic_sub(sub_type, **kwargs): called.append((sub_type, sig.get(), sig.get_setpoint())) for event_type in (sig.SUB_VALUE, sig.SUB_META, sig.SUB_SETPOINT, sig.SUB_SETPOINT_META): sig.subscribe(generic_sub, event_type=event_type) sig.wait_for_connection() sig.put(1, wait=True) sig.put(2, wait=True) time.sleep(0.5) print(called) # Arbitrary threshold, but if @klauer screwed something up again, this will # blow up assert len(called) < 20 print('total', len(called))
def test_epicssignal_sub_setpoint(cleanup, fake_motor_ioc): pvs = fake_motor_ioc.pvs pv = EpicsSignal(write_pv=pvs['setpoint'], read_pv=pvs['readback'], name='pv') cleanup.add(pv) setpoint_called = [] setpoint_meta_called = [] def sub_setpoint(old_value, value, **kwargs): setpoint_called.append((old_value, value)) def sub_setpoint_meta(timestamp, **kwargs): setpoint_meta_called.append(timestamp) pv.subscribe(sub_setpoint, event_type=pv.SUB_SETPOINT) pv.subscribe(sub_setpoint_meta, event_type=pv.SUB_SETPOINT_META) pv.wait_for_connection() pv.put(1, wait=True) pv.put(2, wait=True) time.sleep(1.0) assert len(setpoint_called) >= 3 assert len(setpoint_meta_called) >= 3
class Watchman: cbid = None retries = 3 def __init__(self, door_state, voltage_read, voltage_write): self.door_state = EpicsSignalRO(door_state) self.mesh_voltage = EpicsSignal(voltage_read, write_pv=voltage_write) print('Using door pv {}'.format(door_state)) def start(self): """Sets up self.callback to be run when door state changes""" # Make sure we don't start 2 processes self.stop() print('Starting door watcher') self.door_state.subscribe(self.callback) def callback(self, old_value=None, value=None, **kwargs): """To be run every time the door state changes""" print('Door PV changed from {} to {}'.format(old_value, value)) if old_value == 1 and value == 0: print('Zeroing the mesh voltage because door was opened') # Let's retry a few times in case of a network error for i in range(self.retries): try: self.mesh_voltage.put(0) except Exception: pass def stop(self): """Shutdown the watcher""" if self.cbid is not None: print('Stopping door watcher') self.door_state.unsubscribe(self.cbid) self.cbid = None
def test_epicssignal_sub_setpoint(cleanup, fake_motor_ioc): pvs = fake_motor_ioc.pvs pv = EpicsSignal(write_pv=pvs['setpoint'], read_pv=pvs['readback'], name='pv') cleanup.add(pv) setpoint_called = [] setpoint_meta_called = [] def sub_setpoint(old_value, value, **kwargs): setpoint_called.append((old_value, value)) def sub_setpoint_meta(timestamp, **kwargs): setpoint_meta_called.append(timestamp) pv.subscribe(sub_setpoint, event_type=pv.SUB_SETPOINT) pv.subscribe(sub_setpoint_meta, event_type=pv.SUB_SETPOINT_META) pv.wait_for_connection() pv.put(1, wait=True) pv.put(2, wait=True) time.sleep(0.5) assert len(setpoint_called) >= 3 assert len(setpoint_meta_called) >= 3
def test_describe(): sig = EpicsSignal('my_pv') sig._write_pv.enum_strs = ('enum1', 'enum2') sig.wait_for_connection() sig.put(1) desc = sig.describe()['my_pv'] assert desc['dtype'] == 'integer' assert desc['shape'] == [] assert 'precision' in desc assert 'enum_strs' in desc assert 'upper_ctrl_limit' in desc assert 'lower_ctrl_limit' in desc sig.put('foo') desc = sig.describe()['my_pv'] assert desc['dtype'] == 'string' assert desc['shape'] == [] sig.put(3.14) desc = sig.describe()['my_pv'] assert desc['dtype'] == 'number' assert desc['shape'] == [] import numpy as np sig.put(np.array([1,])) desc = sig.describe()['my_pv'] assert desc['dtype'] == 'array' assert desc['shape'] == [1,]
def test_describe(self): epics.PV = FakeEpicsPV sig = EpicsSignal('my_pv') sig._write_pv.enum_strs = ('enum1', 'enum2') sig.wait_for_connection() sig.put(1) desc = sig.describe()['my_pv'] self.assertEquals(desc['dtype'], 'integer') self.assertEquals(desc['shape'], []) self.assertIn('precision', desc) self.assertIn('enum_strs', desc) self.assertIn('upper_ctrl_limit', desc) self.assertIn('lower_ctrl_limit', desc) sig.put('foo') desc = sig.describe()['my_pv'] self.assertEquals(desc['dtype'], 'string') self.assertEquals(desc['shape'], []) sig.put(3.14) desc = sig.describe()['my_pv'] self.assertEquals(desc['dtype'], 'number') self.assertEquals(desc['shape'], []) import numpy as np sig.put(np.array([ 1, ])) desc = sig.describe()['my_pv'] self.assertEquals(desc['dtype'], 'array') self.assertEquals(desc['shape'], [ 1, ])
def test_describe(cleanup, signal_test_ioc): sig = EpicsSignal(signal_test_ioc.pvs['bool_enum'], name='my_pv') cleanup.add(sig) sig.wait_for_connection() sig.put(1) desc = sig.describe()['my_pv'] assert desc['dtype'] == 'integer' assert desc['shape'] == [] # assert 'precision' in desc assert desc['enum_strs'] == ['Off', 'On'] assert 'upper_ctrl_limit' in desc assert 'lower_ctrl_limit' in desc sig = Signal(name='my_pv') sig.put('Off') desc = sig.describe()['my_pv'] assert desc['dtype'] == 'string' assert desc['shape'] == [] sig.put(3.14) desc = sig.describe()['my_pv'] assert desc['dtype'] == 'number' assert desc['shape'] == [] import numpy as np sig.put(np.array([ 1, ])) desc = sig.describe()['my_pv'] assert desc['dtype'] == 'array' assert desc['shape'] == [ 1, ]
def test_describe(self): epics.PV = FakeEpicsPV sig = EpicsSignal('my_pv') sig._write_pv.enum_strs = ('enum1', 'enum2') sig.wait_for_connection() sig.put(1) desc = sig.describe()['my_pv'] self.assertEquals(desc['dtype'], 'integer') self.assertEquals(desc['shape'], []) self.assertIn('precision', desc) self.assertIn('enum_strs', desc) self.assertIn('upper_ctrl_limit', desc) self.assertIn('lower_ctrl_limit', desc) sig.put('foo') desc = sig.describe()['my_pv'] self.assertEquals(desc['dtype'], 'string') self.assertEquals(desc['shape'], []) sig.put(3.14) desc = sig.describe()['my_pv'] self.assertEquals(desc['dtype'], 'number') self.assertEquals(desc['shape'], []) import numpy as np sig.put(np.array([1,])) desc = sig.describe()['my_pv'] self.assertEquals(desc['dtype'], 'array') self.assertEquals(desc['shape'], [1,])
def test_no_connection(cleanup, signal_test_ioc): sig = EpicsSignal('does_not_connect') cleanup.add(sig) with pytest.raises(TimeoutError): sig.wait_for_connection() sig = EpicsSignal('does_not_connect') cleanup.add(sig) with pytest.raises(TimeoutError): sig.put(0.0) with pytest.raises(TimeoutError): sig.get() sig = EpicsSignal(signal_test_ioc.pvs['read_only'], write_pv='does_not_connect') cleanup.add(sig) with pytest.raises(TimeoutError): sig.wait_for_connection()
class TimingChannel(object): def __init__(self, setpoint_PV, readback_PV, name): self.control_PV = EpicsSignal(setpoint_PV) # DG/Vitara PV self.storage_PV = EpicsSignal(readback_PV) # Notepad PV self.name = name def save_t0(self, val=None): """ Set the t0 value directly, or save the current value as t0. """ if not val: # Take current value to be t0 if not provided val = self.control_PV.get() self.storage_PV.put(val) # Save t0 value def restore_t0(self): """ Restore the t0 value from the current saved value for t0. """ val = self.storage_PV.get() self.control_PV.put(val) # write t0 value def mvr(self, relval): """ Move the control PV relative to it's current value. """ currval = self.control_PV.get() self.control_PV.put(currval - relval) def mv(self, val): t0 = self.storage_PV.get() self.control_PV.put(t0 - val) def get_delay(self, verbose=False): delay = self.control_PV.get() - self.storage_PV.get() if delay > 0: print("X-rays arrive {} s before the optical laser".format( abs(delay))) elif delay < 0: print("X-rays arrive {} s after the optical laser".format( abs(delay))) else: # delay is 0 print("X-rays arrive at the same time as the optical laser") if verbose: control_data = (self.name, self.control_PV.pvname, self.control_PV.get()) storage_data = (self.name, self.storage_PV.pvname, self.storage_PV.get()) print("{} Control PV: {}, Control Value: {}".format(*control_data)) print("{} Storage PV: {}, Storage Value: {}".format(*storage_data))
class FuncPositioner(FltMvInterface, SoftPositioner): """ Class for hacking together a positioner-like object. Before you use this, make sure your use case cannot be easily handled by a `PVPositioner` or by a `PseudoPositioner`. This should be fast to set up, but has the following limitations: - Inspection tools will not work properly, in general - typhos, happi, and similar tools will not work - It is not possible to know ahead of time if any control layer signals poked by this device are connected. - Metadata about the control layer will not be provided. - It's not possible to intelligently subscribe to control layer signals. Everything will be periodic polls on background threads. - Session performance may be negatively impacted by slow polling functions. Parameters ---------- name : str, keyword-only The name to use when we refer to this positioner. move : func, keyword-only The function to call to cause the device to move. The signature must be def fn(position) get_pos : func, keyword-only The function to call to check the device's position. The signature must be def fn() set_pos : func, optional, keyword-only If provided, the function to call to change the device's shown position without moving it. The signature must be def fn(position) stop : func, optional, keyword-only If provided, the function to call to stop the motor. The signature must be def fn() done : func, optional, keyword-only If provided, the function to call to check if the device is done moving. The signature must be def fn() -> bool, and it must return True when motion is complete and false otherwise. check_value : func, optional, keyword-only If provided, an extra function to call to check if it is safe to move. The signature must be def fn(position) -> raise ValueError info : func, optional, keyword-only If provided, an extra function to add data to the ipython console pretty-print. The signature must be def fn() -> dict{str: value}. egu : str, optional If provided, the metadata units for the positioner. limits : tuple of floats, optional If provided, we'll raise an exception to reject moves outside of this range. update_rate : float, optional How often to update the position and check for move completion during a move. Defaults to 1 second. timeout : float, optional How long to wait before marking an in-progress move as failed. Defaults to 60 seconds. notepad_pv : str, optional If provided, a PV to put to whenever we move. This can be used to allow other elements in the control system to see what this positioner is doing. """ def __init__(self, *, name, move, get_pos, set_pos=None, stop=None, done=None, check_value=None, info=None, egu='', limits=None, update_rate=1, timeout=60, notepad_pv=None, parent=None, kind=None, **kwargs): self._check_signature('move', move, 1) self._move = move self._check_signature('get_pos', get_pos, 0) self._get_pos = get_pos self._check_signature('set_pos', set_pos, 1) self._set_pos = set_pos self._check_signature('stop', stop, 0) self._stop = stop self._check_signature('done', done, 0) self._done = done self._check_signature('check_value', check_value, 1) self._check = check_value self._info = info self._last_update = 0 self._goal = None self.update_rate = 1 notepad_name = name + '_notepad' if notepad_pv is None: self.notepad_signal = Signal(name=notepad_name) else: self.notepad_signal = EpicsSignal(notepad_pv, name=notepad_name) if parent is None and kind is None: kind = 'hinted' super().__init__(name=name, egu=egu, limits=limits, source='func', timeout=timeout, parent=parent, kind=kind, **kwargs) def _check_signature(self, name, func, nargs): if func is None: return sig = inspect.signature(func) try: sig.bind(*(0, ) * nargs) except TypeError: raise ValueError( f'FuncPositioner recieved {name} with an incorrect. ' f'signature. Must be able to take {nargs} args.') from None def _setup_move(self, position, status): self._run_subs(sub_type=self.SUB_START, timestamp=time.time()) self._goal = position self._started_moving = True self._moving = True self._finished = False self._move(position) self._new_update(status) def _new_update(self, status): schedule_task(self._update_task, args=(status, ), delay=self.update_rate) def _update_task(self, status): self._update_position() if self._check_finished(): self._started_moving = False self._moving = False self._update_position(force=True) try: status.set_finished() except InvalidState: pass else: self._new_update(status) @property def position(self): self._update_position() return self._position def _update_position(self, force=False): if force or time.monotonic() - self._last_update > self.update_rate: self._last_update = time.monotonic() pos = self._get_pos() self.notepad_signal.put(pos) self._set_position(pos) def _check_finished(self): if self._done is None: finished = np.isclose(self._goal, self.position) else: finished = self._done() if finished: self._done_moving() return finished def set_position(self, position): if self._set_pos is None: raise NotImplementedError(f'FuncPositioner {self.name} was not ' 'given a set_pos argument.') else: self._set_pos(position) def stop(self, *args, **kwargs): if self._stop is None: # Often called by bluesky, don't throw an exception self.log.warning(f'Called stop on FuncPositioner {self.name}, ' 'but was not given a stop argument.') else: self._stop() super().stop(*args, **kwargs) def check_value(self, pos): super().check_value(pos) if self._check is not None: self._check(pos) def status_info(self): info = super().status_info() if self._info is not None: info.update(self._info()) return info
class User(): def __init__(self): #switch to trigger instead of full evr self._sync_markers = { 0.5: 0, 1: 1, 5: 2, 10: 3, 30: 4, 60: 5, 120: 6, 360: 7 } self.trigger_mag = Trigger('XCS:R42:EVR:01:TRIG4', name='trigger_mag') self.trigger_pp = Trigger('XCS:USR:EVR:TRIG1', name='trigger_pp') #self.nemptyshots = actions(0, name='nemptyshots') #self.isfire = actions(False, name='isfire') #self.emptyshotspacing = actions(0, name='emptyshotspacing') #self.nshots = actions(0, name='nshots') #self.shotspacing = actions(0, name='shotspacing') #with safe_load('Pirani and Cold Cathode Gauges'): # self.mag_pirani = BaseGauge('XCS:USR:GPI:01', name='mag_pirani') # self.mag_cc = BaseGauge('XCS:USR:GCC:01', name='mag_cc') self.sample_temp = LakeShoreChannel('XCS:USR:TCT:02', name='A') self.mag_temp = LakeShoreChannel('XCS:USR:TCT:02', name='B') self.ttl_high = 2.0 self.ttl_low = 0.8 self._ready_sig = EpicsSignal('XCS:USR:ai1:0', name='User Analog Input channel 0', kind='omitted') self.i0_threshold = 4000 # default threshold is 0 self.i0_avg = AvgSignal(ipm4.wave8.isum, 30, name='ipm4_sum_avg') self.i0_mag_retry = 10 self._gdet_threshold_pv = EpicsSignal('XCS:VARS:J78:GDET_THRES', kind='normal') #self.gdet_avg_count = 30 #self.gdet_mag_retry = 10 #self.gdet = GasDetector('GDET:FEE1', name='gas detector') #self._bykik_pv = Cpt(EpicsSignal('IOC:IN20:EV01:BYKIK_ABTACT', kind = 'normal', string=True, doc='BYKIK: Abort Active') self._req_burst_rate = 'Full' self._test_burst_rate = EpicsSignal('PATT:SYS0:1:TESTBURSTRATE', name='test_burst_rate', kind='normal') self._mps_burst_rate = EpicsSignal('PATT:SYS0:1:MPSBURSTRATE', name='mps_burst_rate') # number of seconds to pause between empty and magnet self.pause_time = 2. self._min_empty_delay = 4 self._beam_owner = EpicsSignal('ECS:SYS0:0:BEAM_OWNER_ID', name='beam_owner', kind='normal') self._att = att self.hutch = 'xcs' self._hutch_id = EpicsSignal('ECS:SYS0:4:HUTCH_ID', name='hutch_id', kind='normal') self.aliases = ['BEAM'] self.gainmodes = '' #use lcls.(tab) to find bykik controls @property def machine_burst_rate(self): if self._beam_owner.get() == self._hutch_id.get(): self._mps_burst_rate.get() else: self._test_burst_rate.get() @machine_burst_rate.setter def machine_burst_rate(self, rate): if self._beam_owner.get() == self._hutch_id.get(): self._mps_burst_rate.put(rate) else: self._test_burst_rate.put(rate) def check_burst_rate(self): if self.machine_burst_rate != self._req_burst_rate: print('Machine burst frequency not set to %s! - fixing...' % self._req_burst_rate) if self._beam_owner.get() == self._hutch_id.get(): set_and_wait( self._mps_burst_rate, self._req_burst_rate ) #ophyd set and wait() - ophyd.utils.epics_pvs.set_and_wait else: set_and_wait(self._test_burst_rate, self._req_burst_rate) print('done.') @property def ready_sig(self): return self._ready_sig.get() def seq_wait(self, timeout=0, sleeptime=1.0): print(f'timeout = {timeout}, sleep = {sleeptime}') sleep(sleeptime) start = time.time() print(f'start time: {start}') while seq.play_status.get() != 0: if timeout > 0 and (time.time() - start >= timeout): raise ValueError('Timed out') def _prepare_burst(self, Nshots, Nbursts=1, freq=120, delay=None, burstMode=False): if Nshots == 1: pp.flipflop() elif Nshots > 1: pp.burst() if Nbursts == 1: seq.play_mode.put(0) elif Nbursts > 1: seq.play_mode.put(1) seq.rep_count.put(Nbursts) elif Nbursts < 0: seq.play_mode.put(2) if burstMode: burst = Nshots + 2 else: burst = 0 if not freq == 120: raise (NotImplementedError('Not implemented yet!')) if Nshots == 1: if delay is None: delay = 3 elif delay < 2: raise ValueError( 'Delay between flip flops of less than two is not allowed') ff_seq = [[84, delay, 0, burst], [86, 0, 0, burst], [85, 2, 0, burst]] elif Nshots > 1: if delay is None: delay = 1 elif delay < 1: raise ValueError( 'Delay between bursts of less than one is not allowed') ff_seq = [[84, delay, 0, burst], [86, 0, 0, burst], [86, 1, 0, burst]] for shotNo in range(Nshots): ff_seq.append([85, 1, 0, burst]) if shotNo == Nshots - 2: ff_seq.append([84, 0, 0, burst]) seq.sequence.put_seq(ff_seq) def _prepNonMagShots(self, nshots): #copy code from old pulsepicker.py file in (blinst) and change where needed or xpp experiment self._prepare_burst(nshots, burstMode=True) def _prepSpacedNonMagShots(self, nshots_per_burst, spacing): nshots = 1 burstDelay = spacing - 2 self.prepare_burst(nshots, Nbursts=nshots_per_burst, delay=burstDelay, burstMode=True) def _takeNonMagShots(self): seq.start() def _prepMagShot(self, isfire, delay=1): pp.flipflop() seq.play_mode.put(0) ff_seq = [[84, delay, 0, 3], [86, 0, 0, 0]] if isfire: ff_seq.append([self.trigger_mag.get_eventcode(), 2, 0, 0]) ff_seq.append([85, 0, 0, 0]) else: ff_seq.append([85, 2, 0, 0]) seq.sequence.put_seq(ff_seq) def _takeMagShot(self): seq.start() def _laserOn(self): """ laser on by goose trigger 88 """ os.system('caput XCS:ECS:IOC:01:EC_11:00 88') os.system('caput ECS:SYS0:11:LEN 1') os.system('caput ECS:SYS0:11:PLYCTL 1') def _laserOff(self): """ laser off by goose trigger 89 """ os.system('caput XCS:ECS:IOC:01:EC_11:00 89') os.system('caput ECS:SYS0:11:LEN 1') os.system('caput ECS:SYS0:11:PLYCTL 1') def _laserNormal(self): """ normal on/off mode """ os.system('caput XCS:ECS:IOC:01:EC_11:00 88') os.system('caput ECS:SYS0:11:LEN 7') os.system('caput ECS:SYS0:11:PLYCTL 1') def takeEmptyShots(self, nshots, shotspacing, use_daq=False, record=None): calibcontrols = { 'nshots': ConfigVal(nshots), 'shotspacing': ConfigVal(shotspacing) } if shotspacing > 0: self._prepSpacedNonMagShots(nshots, shotspacing) else: self._prepNonMagShots(nshots) #configure daq if being used if use_daq: daq.record = record daq.configure(events=0, controls=calibcontrols) try: if use_daq: daq.begin(events=nshots, controls=calibcontrols) seq.start() self.seq_wait() if use_daq: daq.wait() except KeyboardInterrupt: seq.stop() finally: if use_daq: daq.record = None daq.disconnect() def takeMagnetShot(self, nemptyshots, emptyshotspacing=0, isfire=False, record=None): calibcontrols = { 'mag_isfire': ConfigVal(isfire), 'mag_trigger_delay': self.trigger_mag.ns_delay, 'mag_trig_width': self.trigger_mag.width, 'mag_trig_eventcode': self.trigger_mag.eventcode, 'nemptyshots': ConfigVal(nemptyshots), 'emptyshotspacing': ConfigVal(emptyshotspacing) } # check the machine burst rate and set to Full rate if not self.check_burst_rate() # disable BYKIK before taking shots lcls.bykik_disable() # check if emptyshotspacing is valid if 0 < emptyshotspacing < self._min_empty_delay: raise ValueError( "When using spacing between empty shots it must be >= %d" % self._min_empty_delay) spacer = "*********************************" print("\n%s\n* Preparing to take magnet shot *\n%s\n" % (spacer, spacer)) if emptyshotspacing > 0: mag_status = "Taking %d shots, with a spacing between each of %d beam pulses, before firing the magnet\n" % ( nemptyshots, emptyshotspacing) else: mag_status = "Taking %d shots before firing the magnet\n" % nemptyshots mag_status += "Magnet pulse eventcode: %d\n" % self.trigger_mag.get_eventcode( ) mag_status += "Magnet pulse trigger delay: %f\n" % self.trigger_mag.get_delay( ) mag_status += "Magnet pulse trigger width: %f\n" % self.trigger_mag.get_width( ) mag_status += "Magnet to be fired: %s\n" % isfire print(mag_status) try: daq.record = record daq.configure(events=0, controls=calibcontrols) # Pre empty shots if nemptyshots > 0: print("\nPreparing sequencer for pre-firing, non-magnet shots") if emptyshotspacing > 0: self._prepSpacedNonMagShots(nemptyshots, emptyshotspacing) else: self._prepNonMagShots(nemptyshots) time.sleep(self.pause_time) daq.begin(events=nemptyshots, controls=calibcontrols) print("\nTaking %d pre-firing, non-magnet shots\n" % nemptyshots) # pause after changing pulse picker mode time.sleep(self.pause_time) self._takeNonMagShots() print('Taking shots') self.seq_wait() print('seq finished') daq.wait() print('daq finished') else: print("\nSkipping prefiring, non-magnet shots\n") # pause after empty shots time.sleep(self.pause_time) print('sleep finished') # Fire the magnet sequence based on isfire flag if isfire: print("Start magnet firing sequence\n") else: print("Start magnet test 'firing' sequence\n") print("\nPreparing sequencer for magnet shot") if emptyshotspacing > 0: self._prepMagShot(isfire, emptyshotspacing) else: self._prepMagShot(isfire) time.sleep(self.pause_time) # pause after changing pulse picker mode time.sleep(self.pause_time) #checking ipm4?? num_tries = 0 i0_good = False while num_tries < self.i0_mag_retry: i0_val = self.i0_avg.get() if i0_val < self.i0_threshold: print( "\nNot firing magnet due to low beam current (ipm4): %.3f \n" % (i0_val)) backoff_time = 2**num_tries print("Sleeping for %d seconds...\n" % backoff_time) time.sleep(backoff_time) num_tries += 1 else: #ipm4 is good - fire! i0_good = True print("\nInitial intensity(ipm4) looks good: %.3f\n" % i0_val) break if not i0_good: print( "Max number of i0 checks (%d) exceeded! - Abort shot attempt.\n" % self.i0_mag_retry) return False # take the magnet shot daq.begin(events=1, controls=calibcontrols) print("\nTaking magnet shot\n") self._takeMagShot() self.seq_wait() daq.wait() #pause after magnet shots time.sleep(self.pause_time) #post empty shots if nemptyshots > 0: print( "\nPreparing sequencer for post-firing, non-magnet shots") if emptyshotspacing > 0: self._prepSpacedNonMagShots(nemptyshots, emptyshotspacing) else: self._prepNonMagShots(nemptyshots) time.sleep(self.pause_time) daq.begin(events=nemptyshots, controls=calibcontrols) print("\nTaking %d post-firing, non-magnet shots\n" % nemptyshots) # pause after changing pulse picker mode time.sleep(self.pause_time) self._takeNonMagShots() self.seq_wait() daq.wait() else: print("\nSkipping post-firing, non-magnet shots\n") return True except KeyboardInterrupt: seq.stop() daq.stop() return False finally: daq.record = None daq.disconnect() lcls.bykik_enable() def takeMagnetShotMulti(self, nemptyshots, emptyshotspacing=0, isfire=False, record=None, ignore_ready=False): """ Takes magnet shots in a continous fashion waiting for a ready signal from the magnet controller """ latch = False nmagshots = 0 shotgood = True spacer = '##############################' try: while shotgood: if not latch and (self.ready_sig > self.ttl_high or ignore_ready): i0_val = self.i0_avg.get() if i0_val < self.i0_threshold: print( "\nNot firing magnet due to low beam current (ipm4): %.3f \n" % (i0_val)) backoff_time = 1 print("Sleeping for %d second...\n" % backoff_time) time.sleep(backoff_time) continue latch = True print("\n%s\nStarting shot %d\n%s\n" % (spacer, nmagshots, spacer)) start_time = time.time() shotgood = self.takeMagnetShot(nemptyshots, emptyshotspacing, isfire, record) stop_time = time.time() print("\n%s\nCompleted shot %d in %.2f s\n%s\n" % (spacer, nmagshots, (stop_time - start_time), spacer)) nmagshots += 1 if latch and (self.ready_sig < self.ttl_low or ignore_ready): latch = False time.sleep(0.25) except KeyboardInterrupt: print('\nExiting...\n') finally: print('Took %d total magnet shots\n' % nmagshots) def takeRun(self, nEvents, record=None, use_l3t=False): daq.configure(events=120, record=record, use_l3t=use_l3t) daq.begin(events=nEvents) daq.wait() daq.end_run() def ascan(self, motor, start, end, nsteps, nEvents, record=None, use_l3t=False): self.cleanup_RE() currPos = motor.wm() daq.configure(nEvents, record=record, controls=[motor], use_l3t=use_l3t) try: RE(scan([daq], motor, start, end, nsteps)) except Exception: logger.debug('RE Exit', exc_info=True) finally: self.cleanup_RE() motor.mv(currPos) def pv_ascan(self, signal, start, end, nsteps, nEvents, record=None, use_l3t=False): self.cleanup_RE() currPos = signal.get() daq.configure(nEvents, record=record, controls=[signal], use_l3t=use_l3t) try: RE(scan([daq], signal, start, end, nsteps)) except Exception: logger.debug('RE Exit', exc_info=True) finally: self.cleanup_RE() signal.put(currPos) def listscan(self, motor, posList, nEvents, record=None, use_l3t=False): self.cleanup_RE() currPos = motor.wm() daq.configure(nEvents, record=record, controls=[motor], use_l3t=use_l3t) try: RE(list_scan([daq], motor, posList)) except Exception: logger.debug('RE Exit', exc_info=True) finally: self.cleanup_RE() motor.mv(currPos) def list3scan(self, m1, p1, m2, p2, m3, p3, nEvents, record=None, use_l3t=False): self.cleanup_RE() currPos1 = m1.wm() currPos2 = m2.wm() currPos3 = m3.wm() daq.configure(nEvents, record=record, controls=[m1, m2, m3], use_l3t=use_l3t) try: RE(list_scan([daq], m1, p1, m2, p2, m3, p3)) except Exception: logger.debug('RE Exit', exc_info=True) finally: self.cleanup_RE() m1.mv(currPos1) m2.mv(currPos2) m3.mv(currPos3) def dscan(self, motor, start, end, nsteps, nEvents, record=None, use_l3t=False): self.cleanup_RE() daq.configure(nEvents, record=record, controls=[motor], use_l3t=use_l3t) currPos = motor.wm() try: RE(scan([daq], motor, currPos + start, currPos + end, nsteps)) except Exception: logger.debug('RE Exit', exc_info=True) finally: self.cleanup_RE() motor.mv(currPos) def pv_dscan(self, signal, start, end, nsteps, nEvents, record=None, use_l3t=False): self.cleanup_RE() daq.configure(nEvents, record=record, controls=[signal], use_l3t=use_l3t) currPos = signal.get() try: RE(scan([daq], signal, currPos + start, currPos + end, nsteps)) except Exception: logger.debug('RE Exit', exc_info=True) finally: self.cleanup_RE() signal.put(currPos) def a2scan(self, m1, a1, b1, m2, a2, b2, nsteps, nEvents, record=True, use_l3t=False): self.cleanup_RE() daq.configure(nEvents, record=record, controls=[m1, m2], use_l3t=use_l3t) try: RE(scan([daq], m1, a1, b1, m2, a2, b2, nsteps)) except Exception: logger.debug('RE Exit', exc_info=True) finally: self.cleanup_RE() def a3scan(self, m1, a1, b1, m2, a2, b2, m3, a3, b3, nsteps, nEvents, record=True): self.cleanup_RE() daq.configure(nEvents, record=record, controls=[m1, m2, m3]) try: RE(scan([daq], m1, a1, b1, m2, a2, b2, m3, a3, b3, nsteps)) except Exception: logger.debug('RE Exit', exc_info=True) finally: self.cleanup_RE() def delay_scan(self, start, end, sweep_time, record=None, use_l3t=False, duration=None): """Delay scan with the daq.""" self.cleanup_RE() daq.configure(events=None, duration=None, record=record, use_l3t=use_l3t, controls=[lxt_fast]) try: RE( delay_scan(daq, lxt_fast, [start, end], sweep_time, duration=duration)) except Exception: logger.debug('RE Exit', exc_info=True) finally: self.cleanup_RE() def empty_delay_scan(self, start, end, sweep_time, record=None, use_l3t=False, duration=None): """Delay scan without the daq.""" self.cleanup_RE() #daq.configure(events=None, duration=None, record=record, # use_l3t=use_l3t, controls=[lxt_fast]) try: RE( delay_scan(None, lxt_fast, [start, end], sweep_time, duration=duration)) except Exception: logger.debug('RE Exit', exc_info=True) finally: self.cleanup_RE() def cleanup_RE(self): if not RE.state.is_idle: print('Cleaning up RunEngine') print('Stopping previous run') try: RE.stop() except Exception: pass