def _unstick_GslitsSizeMotors(): """Workaround for issue #425 (and #404).""" pause = 4 logger.info("Workaround for Guard Slit 'motor stuck in moving'.") yield from bps.sleep(pause) # activity pause, empirical logger.info("Sync H&V axes.") yield from bps.mv( guard_slit.h_sync_proc, 1, guard_slit.v_sync_proc, 1, ) # NOTE: These steps did not affect the process outcome. # # write the .STUP field on each motor # for axis in "top bot inb outb".split(): # logger.info("Unstick %s.", axis) # m = getattr(guard_slit, axis) # try: # yield from bps.abs_set(m.status_update, 1, timeout=.1) # yield from bps.sleep(pause) # activity pause, empirical # except FailedStatus: # pass # except Exception as exc: # logger.error("%s: %s", axis, exc) # move each motor *individually* for axis in "top bot inb outb".split(): m = getattr(guard_slit, axis) logger.info("Move %s a little bit.\n", m.name) yield from bps.mvr(m, 0.1) logger.info("Move %s back.\n", m.name) yield from bps.mvr(m, -0.1) logger.info("Workaround Complete.")
def test_mvr_with_timeout(hw): # special-case mv because the group is not configurable # move motors first to ensure that movement is absolute, not relative actual = list(mvr(hw.motor1, 1, hw.motor2, 2, timeout=42)) for msg in actual[:2]: msg.command == 'set' msg.kwargs['timeout'] == 42
def tune_plan(step=0): ''' Tune 2nd crystal pitch from a plan. Argument is a value for the step, so a relative motion. ''' yield from abs_set(dcm_pitch.kill_cmd, 1, wait=True) yield from mvr(dcm_pitch, step) yield from sleep(1.0) yield from abs_set(dcm_pitch.kill_cmd, 1, wait=True)
def tweak_bct(step): dm3_bct = user_ns['dm3_bct'] if step is None: step = 0 if dm3_bct.ampen.get() == 0: yield from mv(dm3_bct.enable_cmd, 1) yield from mv(dm3_bct.kill_cmd, 1) print('Moving from %.4f to %.4f' % (dm3_bct.user_readback.get(), dm3_bct.user_readback.get() + step)) yield from mvr(dm3_bct, step)
def mvrbct(target=None): ''' A workaround to kill the BCT motor, then do a relative movement ''' dm3_bct = user_ns['dm3_bct'] if target is None: target = 0 yield from abs_set(dm3_bct.kill_cmd, 1, wait=True) yield from mvr(dm3_bct, target)
def mvrbender(target=None): ''' A workaround to kill the M2 bender motor, then do a relative movement ''' m2_bender = user_ns['m2_bender'] if target is None: target = 0 yield from abs_set(m2_bender.kill_cmd, 1, wait=True) yield from mvr(m2_bender, target)
def tweak_bct(step): dm3_bct = user_ns['dm3_bct'] if step is None: step = 0 yield from abs_set(dm3_bct.kill_cmd,1, wait=True) print('Moving from %.4f to %.4f' % (dm3_bct.user_readback.get(), dm3_bct.user_readback.get() + step)) yield from mvr(dm3_bct, step) time.sleep(3.0) yield from abs_set(dm3_bct.kill_cmd,1, wait=True)
def energystep(filename = None, start = None, end = None, nsteps = None, delay = 5, dosteps = True): '''A simple energy scan, just step forward in energy and don't measure anything. This is a quick hack for use with a crude resonant reflectivity experiment with IBM folks. filename: name of file, will be appended to DATA for the full path (required) start: starting energy value (required) end: ending energy value (required) nsteps: number of energy steps (required) delay: pause between energy steps, in seconds [5] dosteps: False to see energy values printed to screen without moving mono [True] Writes a data file with columns of energy readback, energy requested, time of epoch, and ISO 8601 timestamp Example: energystep(filename='blahblah', start=18936, end=19036, nsteps=101) ''' BMMuser, dcm = user_ns['BMMuser'], user_ns['dcm'] BMM_log_info("energystep(filename=%s, start=%.1f, end=%.1f, nsteps=%d, delay=%.1f, dosteps=%s)" % (filename, start, end, nsteps, delay, str(dosteps))) datafile = BMMuser.DATA + filename handle = open(datafile, 'w') handle.write('# energy steps from %.1f to %.1f in %d steps\n' % (start, end, nsteps)) handle.write('#----------------------------------------------------\n') handle.write('# energy requested epoch iso8601\n') handle.flush() if dosteps: yield from mv(dcm.energy, start) print(' %.1f %.1f %.6f %s' % (dcm.energy.readback.get(), start, time.time(), now())) handle.write(' %.1f %.1f %.6f %s\n' % (dcm.energy.readback.get(), start, time.time(), now())) handle.flush() yield from sleep(delay) energy = start estep = (end-start) / nsteps while energy <= end: if dosteps: yield from mvr(dcm.energy, estep) print(' %.1f %.1f %.6f %s' % (dcm.energy.readback.get(), energy, time.time(), now())) handle.write(' %.1f %.1f %.6f %s\n' % (dcm.energy.readback.get(), energy, time.time(), now())) handle.flush() energy = energy + estep yield from sleep(delay) handle.flush() handle.close()
def mvrbct(target=None): ''' A workaround to kill the BCT motor, then do a relative movement Since Jan 27 2022, this should not be necessary. ''' dm3_bct = user_ns['dm3_bct'] if target is None: target = 0 if dm3_bct.ampen.get() == 0: yield from mv(dm3_bct.enable_cmd, 1) yield from mv(dm3_bct.kill_cmd, 1) yield from mvr(dm3_bct, target)
def test_mvr(RE, hw): # special-case mv because the group is not configurable # move motors first to ensure that movement is relative, not absolute hw.motor1.set(10) hw.motor2.set(10) actual = [] RE.msg_hook = lambda msg: actual.append(msg) RE(mvr(hw.motor1, 1, hw.motor2, 2)) actual = list(mv(hw.motor1, 1, hw.motor2, 2)) strip_group(actual) for msg in actual[:2]: msg.command == 'set' assert set([msg.obj for msg in actual[:2]]) == set([hw.motor1, hw.motor2]) assert actual[2] == Msg('wait', None)
def test_mvr(RE, hw): # special-case mv because the group is not configurable # move motors first to ensure that movement is relative, not absolute hw.motor1.set(10) hw.motor2.set(10) actual = [] RE.msg_hook = lambda msg: actual.append(msg) RE(mvr(hw.motor1, 1, hw.motor2, 2)) actual = list(mv(hw.motor1, 1, hw.motor2, 2)) strip_group(actual) for msg in actual[:2]: msg.command == 'set' assert set([msg.obj for msg in actual[:2]]) == set([hw.motor1, hw.motor2]) assert actual[2] == Msg('wait', None)
def set_slot(self, n): '''Move to a numbered slot on a sample wheel.''' if type(n) is not int: print( error_msg( 'Slots numbers must be integers between 1 and 24 (argument was %s)' % type(n))) return (yield from null()) if n < 1 or n > 24: print(error_msg('Slots are numbered from 1 to 24')) return (yield from null()) angle = self.angle_from_current(n) yield from mvr(self, angle) report('Arrived at sample wheel slot %d' % n, level='bold')
def to(self, number): '''Rotate to the specified spinner. Turn off all other spinners. Turn on the specified spinner.''' if not self.valid(number): print(error_msg('The fans are numbered from 1 to 8')) yield from null() return yield from self.alloff_plan() distance = number - self.current() if distance > 4: distance = distance - 8 elif distance < -4: distance = 8 + distance angle = -45*distance yield from mvr(self.garot, angle) if self.spin is True: this = getattr(self, f'spinner{number}') yield from mv(this, 1)
def random_step(x: float = 0,y: float = 0, **kwargs): ''' This plan will move the stage randomly by a random number between x/2 and x and y/2 and y, sampling a donut around the original point ''' sys.stdout = kwargs.pop('stdout', sys.stdout) print_to_gui('Executing random move',sys.stdout) if type(x) == str: x = float(x) y = float(y) if not 'motor_x' in kwargs.keys(): motor_x = giantxy.x if not 'motor_y' in kwargs.keys(): motor_y = giantxy.y random_x = 2 * x * (random()-0.5) random_x = random_x * 0.5 + 0.5 * np.sign(random_x) random_y = 2 * y*(random()-0.5) random_y = random_y * 0.5 + 0.5 * np.sign(random_y) yield from mvr(motor_x,random_x,motor_y,random_y)
def kmvr(*args): for m in args[0::2]: if 'Vacuum' in str(type(m)): yield from abs_set(m.kill_cmd, 1, wait=True) yield from mvr(*args)
def center_pin(cam=cam_8): """ Centers a pin in Y Requirements ------------ * Alignment pin mounted. Pin should be aligned in X to within 0.25 of the Mag3 width Parameters ---------- cam: ophyd camera device. Should be cam_7 or cam_8 (default) Examples -------- RE(center_pin()) RE(center_pin(cam_7)) """ if cam not in [cam_7, cam_8]: print('cam must be one of: [cam_7, cam_8]') return -1 # Copy ROI2 geometry (HiMag Mag3 and LoMag Mag1) to ROI4 and use ROI4 centroid plugin cam.roi4.min_xyz.min_x.put(cam.roi2.min_xyz.min_x.get()) cam.roi4.min_xyz.min_y.put(cam.roi2.min_xyz.min_y.get()) cam.roi4.size.x.put(cam.roi2.size.x.get() * 0.25) cam.roi4.size.y.put(cam.roi2.size.y.get()) cam.roi4.min_xyz.min_x.put(cam.roi2.min_xyz.min_x.get() + cam.roi2.size.x.get() / 2 - cam.roi4.size.x.get() / 2) # Invert camera image, so dark pin on light image becomes a peak cam.proc1.scale.put(-1) # High threshold, so AD centroid doesn't interpret background camThresholdOld = cam.stats4.centroid_threshold.get() cam.stats4.centroid_threshold.put(150) # Get centroids at Omega = 0, 90, 180, 270 deg yield from bps.mv(gonio.o, 0) time.sleep(2) c0 = centroid_avg(cam.stats4)[1] yield from bps.mv(gonio.o, 90) time.sleep(2) c90 = centroid_avg(cam.stats4)[1] yield from bps.mv(gonio.o, 180) time.sleep(2) c180 = centroid_avg(cam.stats4)[1] yield from bps.mv(gonio.o, 270) time.sleep(2) c270 = centroid_avg(cam.stats4)[1] # Camera calibration [um/px] if cam == cam_8: camCal = BL_calibration.HiMagCal.get() elif cam == cam_7: camCal = BL_calibration.LoMagCal.get() # Center offset Y offsY = ((c180 - c0)) / 2 * camCal print('Y offset = {:.6g} um'.format(offsY)) # Center offset Z offsZ = ((c270 - c90)) / 2 * camCal print('Z offset = {:.6g} um'.format(offsZ)) # Move pin to center yield from bps.mvr(gonio.py, offsY) yield from bps.mvr(gonio.pz, offsZ) # De-invert image cam.proc1.scale.put(1) # Set thresold to previous value cam.stats4.centroid_threshold.put(camThresholdOld)
def _tweak(self, direction): motor = self._cur_alignment_motor step = self.doubleSpinBox_tweak_motor_step.value() self.RE(bps.mvr(motor, direction * step)) pos = motor.user_readback.get() self.doubleSpinBox_tweak_motor_pos.setValue(pos)
def plan(FBref): # The loop variable, FBi, is changed from within the loop. FBi = 90 while 90 <= FBi <= 100: print(f'FBi: {FBi}') pico_value = (yield from read(pm))["pm"]["value"] outb_value = (yield from read(outb))["outb"]["value"] inb_value = (yield from read(inb))["inb"]["value"] FACTOR = 1000000 # TODO What is this, a unit conversion? BPMpos = (outb_value - inb_value) / (inb_value + outb_value) * FACTOR print(f"inboard signal {inb_value:.6}") print(f"outboard signal {outb_value:.6}") print(f"position {BPMpos:.4} pico {pico_value:.6}") deltaPos = BPMpos - FBref # Check limits. FBi2 = 90 if pico_value - 1 < -550.0: FBi = 101 else: FBi = FBi2 if pico_value - 1 > 400.0: FBi = 101 # check for no beam. if (inb_value < 0.07) and (outb_value < 0.07): FBi = 97 # compare and move as needed: if FBi < 96: if 20000 < deltaPos < 150000: move_by = 0.021 elif -150000 < deltaPos < -25000: move_by = -0.021 elif 150000 < deltaPos < 400000: move_by = 0.063 elif -400000 < deltaPos < -150000: move_by = -0.063 elif deltaPos > 400000: move_by = 0.200 elif deltaPos < -400000: move_by = -0.200 else: move_by = 0 else: move_by = 0 if move_by: yield from mvr(pm, move_by) print(f"moved {move_by} at {datetime.now().isoformat()}") # set feedback frequency: yield from sleep(0.05) # 20 Hz # if beam is lost, pause 10 sec and re-loop if FBi == 97: print( f"lost signal, waiting 10 sec starting at {datetime.now().isoformat()}" ) yield from sleep(10) yield from sleep(1.0) pico_value = (yield from read(pm))["pm"]["value"] print(f"feedback stopped... pico {pico_value}") print(f"inboard signal {inb_value:.6}") print(f"outboard signal {outb_value:.6}") print(f"position {BPMpos:.4}") print(f"Plan exited at {datetime.now().isoformat()}")
def kmvr(*args): for m in args[0::2]: if 'Vacuum' in str(type(m)): yield from mv(m.kill_cmd, 1) yield from mvr(*args)
def xy_fly_scan(self, nshots, nrows=2, y_distance=None, rate=5, record=True, xrays=True): """ Plan for doing a 2D fly scan. Uses the target x motor as the flying axis, running for a specified distance at a specified velocity, taking shots at a specified rate. Parameters ---------- nshots : int The number of shots to take in the x scan. rate : int <default : 5> The rate at which to take shots (120, 30, 10, 5, 1) y_distance : float <default : x.grid.y_spacing> The distance to move the y stage down. nrows : int <default : 2> The number of "rows" to scan the x stage on. record : bool <default : True> Flag to record the data. xrays : bool <default : True> Flag to take an x-ray + optical (True) shot or optical only (False). """ logging.debug("rate: {}".format(rate)) logging.debug("nshots: {}".format(nshots)) logging.debug("nrows: {}".format(nrows)) logging.debug("record: {}".format(record)) logging.debug("xrays: {}".format(xrays)) if not y_distance: y_distance = self.grid.y_spacing logging.debug("y_distance: {}".format(y_distance)) assert rate in [120, 30, 10, 5, 1], "Please choose a rate in {120, 30, 10,5,1}" print("Configuring DAQ...") daq.configure(events=0, record=record) # run infinitely daq.begin_infinite() print("Configuring sequencer...") # Setup the pulse picker for single shots in flip flop mode pp.flipflop(wait=True) # Setup sequencer for requested rate sync_mark = int(self._sync_markers[rate]) seq.sync_marker.put(sync_mark) seq.play_mode.put(1) # Run for n shots seq.rep_count.put(nshots) # Setup sequence self._seq.rate = rate if xrays: s = self._seq.duringSequence(1, 'shortpulse') else: s = self._seq.opticalSequence(1, 'shortpulse') seq.sequence.put_seq(s) # Get starting positions start = self.grid.wm() # Calculate and set velocity vel = self.grid.x_spacing * rate # mm * (1/s) = mm/s self.grid.x.velocity.put(vel) # Estimate distance to move given requested shots and rate dist = (nshots / rate) * vel # (shots/(shots/sec))*mm/s = mm # Close shutter 6 (requested) self._shutters[6].close() time.sleep(5) for i in range(nrows): if i != 0: yield from bps.mvr(self.grid.y, y_distance) # Play the sequencer seq.play_control.put(1) # Start the move yield from bps.mvr(self.grid.x, dist) # Waits for move to complete # Make sure the sequencer stopped seq.play_control.put(0) yield from bps.mv(self.grid.x, start['x']) # Return to start print("Returning to starting position") yield from bps.mv(self.grid.x, start['x']) yield from bps.mv(self.grid.y, start['y']) daq.end_run() self._shutters[6].open()
def stage_left(self): h_step = self.spinBox_hor_step.value() self.RE(bps.mvr(self.sample_stage.x, h_step)) self.show_image()
def stage_down(self): v_step = self.spinBox_ver_step.value() self.RE(bps.mvr(self.sample_stage.y, -v_step)) self.show_image()
def uxi_shot(self, delta=0.3, record=True, lasps=True): """ Returns a BlueSky plan to run a scan for the LV08 experiment. Used for the UXI camera which requires near continuous acquisition for stable camera behavior. The following shots are combined in a single run. Shot sequence: -------------- 1) 10 dark frames # Warm up camera 2) 10 X-ray frames 3) Sample moves in 4) 10 dark frames # Warm up camera 5) 1 X-ray + Optical laser frame 6) 10 dark frames 7) Sample moves out 8) 10 dark frames # Warm up camera 9) 10 X-ray frames Parameters: ----------- delta : float <default: 0.3> The relative distance in mm to move the sample in and out. record : bool <default: True> Flag to record the data (or not). lasps : bool <default: True> Flag to perform pre-and post shot pulse shaping routines. """ logging.debug("Calling User.shot with parameters:") logging.debug("delta: {}".format(delta)) logging.debug("record: {}".format(record)) logging.debug("lasps: {}".format(lasps)) print("Configuring DAQ...") # yield from bps.configure(daq,events=0, record=record) # run infinitely, let sequencer # control number of events daq.begin_infinite(record=record) long_seq = [[0, 240, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] print("Configuring sequencer...") # Setup the pulse picker for single shots in flip flop mode pp.flipflop(wait=True) # Setup sequencer for requested rate sync_mark = int(self._sync_markers[0.5]) seq.sync_marker.put(sync_mark) seq.play_mode.put(1) # Run N times seq.rep_count.put(10) # Setup sequence self._seq.rate = 0.5 # close the shutters specified by the user for shutter in self.shutters: self._shutters[shutter].close() # Shutters are slow; give them time to close time.sleep(5) if lasps: print("Running mecps.pspreshot()...") pspreshot() # Run 10 Pre-laser dark shots (step 1 above) s = self._seq.darkSequence(1, preshot=False) # seq.sequence.put_seq(long_seq) # seq.sequence.put_seq(s) self.scalar_sequence_write(s) print("Taking 10 dark shots...") time.sleep(1) seq.start() self.seq_wait() # yield from bps.trigger_and_read([daq, seq]) # Run 10 Pre-laser x-ray shots (step 2 above) s = self._seq.darkXraySequence(1, preshot=False) # seq.sequence.put_seq(long_seq) # seq.sequence.put_seq(s) self.scalar_sequence_write(s) print("Taking 10 x-ray shots...") time.sleep(1) seq.start() self.seq_wait() #yield from bps.trigger_and_read([daq, seq]) # Move sample in (step 3 above) print("Moving sample in...") yield from bps.mvr(self.target_x, delta) #TODO Check direction # Run 10 Pre-laser dark shots (step 4 above) print("Taking 10 dark shots...") s = self._seq.darkSequence(1, preshot=False) # seq.sequence.put_seq(long_seq) # seq.sequence.put_seq(s) self.scalar_sequence_write(s) time.sleep(1) seq.start() self.seq_wait() # yield from bps.trigger_and_read([daq, seq]) # Run x-ray + optical sequence (step 5 above) print("Taking optical laser shots...") seq.rep_count.put(1) s = self._seq.duringSequence(1, 'longpulse') # seq.sequence.put_seq(long_seq) # seq.sequence.put_seq(s) self.scalar_sequence_write(s) time.sleep(1) seq.start() self.seq_wait() # yield from bps.trigger_and_read([daq, seq]) # Run 10 Post-laser dark shots (step 6 above) print("Taking 10 dark shots...") seq.rep_count.put(10) s = self._seq.darkSequence(1, preshot=False) # seq.sequence.put_seq(long_seq) # seq.sequence.put_seq(s) self.scalar_sequence_write(s) time.sleep(1) seq.start() self.seq_wait() # yield from bps.trigger_and_read([daq, seq]) # Move sample out (step 7 above) print("Moving sample out...") yield from bps.mvr(self.target_x, -delta) #TODO Check direction # Run 10 Pre-x-ray dark shots (step 8 above) print("Taking 10 dark shots...") seq.rep_count.put(10) s = self._seq.darkSequence(1, preshot=False) # seq.sequence.put_seq(long_seq) # seq.sequence.put_seq(s) self.scalar_sequence_write(s) time.sleep(1) seq.start() self.seq_wait() # yield from bps.trigger_and_read([daq, seq]) # Run 10 Pre-laser x-ray shots (step 9 above) print("Taking 10 x-ray shots...") s = self._seq.darkXraySequence(1, preshot=False) # seq.sequence.put_seq(long_seq) # seq.sequence.put_seq(s) self.scalar_sequence_write(s) time.sleep(1) seq.start() self.seq_wait() # yield from bps.trigger_and_read([daq, seq]) daq.end_run() if lasps: print("Running mecps.pspostshot()...") pspostshot() # open the shutters specified by the user for shutter in self.shutters: self._shutters[shutter].open()
def auto_align(self, pitch=2, drop=None): '''Align a sample on a spinner automatically. This performs 5 scans. The first four iterate twice between linear and pitch against the signal in It. This find the flat position. Then the sample is pitched to the requested angle and a fifth scan is done to optimize the linear motor position against the fluorescence signal. The linear scans against It look like a step-down function. The center of this step is found as the centroid of a fitted error function. The xafs_pitch scan should be peaked. Move to the max of the signal. The linear scan against fluorescence ideally looks like a flat-topped peak. Move to the center of mass. At the end, a three-panel figure is drawn showing the last three scans. This is posted to Slack. It also finds its way into the dossier as a record of the quality of the alignment. Arguments ========= pitch : int The angle at which to make the glancing angle measurements. drop : int or None If not None, then this many points will be dropped from the end of linear scan against transmission when fitting the error function. This is an attempt to deal gracefully with leakage through the adhesive at very high energy. ''' BMMuser = user_ns['BMMuser'] if BMMuser.macro_dryrun: report(f'Auto-aligning glancing angle stage, spinner {self.current()}', level='bold', slack=False) print(info_msg(f'\nBMMuser.macro_dryrun is True. Sleeping for %.1f seconds at spinner %d.\n' % (BMMuser.macro_sleep, self.current()))) countdown(BMMuser.macro_sleep) return(yield from null()) report(f'Auto-aligning glancing angle stage, spinner {self.current()}', level='bold', slack=True) BMM_suspenders() ## first pass in transmission yield from self.align_linear(drop=drop) yield from self.align_pitch() ## for realsies X or Y in transmission yield from self.align_linear(drop=drop) self.y_uid = user_ns['db'].v2[-1].metadata['start']['uid'] ## for realsies Y in pitch yield from self.align_pitch() self.pitch_uid = user_ns['db'].v2[-1].metadata['start']['uid'] ## record the flat position if self.orientation == 'parallel': motor = user_ns['xafs_y'] else: motor = user_ns['xafs_x'] self.flat = [motor.position, user_ns['xafs_pitch'].position] ## move to measurement angle and align yield from mvr(user_ns['xafs_pitch'], pitch) yield from linescan(motor, 'xs', -2.3, 2.3, 51, pluck=False) self.f_uid = user_ns['db'].v2[-1].metadata['start']['uid'] tf = user_ns['db'][-1].table() yy = tf[motor.name] signal = (tf[BMMuser.xs1] + tf[BMMuser.xs2] + tf[BMMuser.xs3] + tf[BMMuser.xs4]) / tf['I0'] if BMMuser.element == 'Zr': centroid = yy[signal.idxmax()] else: com = int(center_of_mass(signal)[0])+1 centroid = yy[com] yield from mv(motor, centroid) ## make a pretty picture, post it to slack self.alignment_plot(self.y_uid, self.pitch_uid, self.f_uid) self.alignment_filename = os.path.join(BMMuser.folder, 'snapshots', f'spinner{self.current()}-alignment-{now()}.png') plt.savefig(self.alignment_filename) try: img_to_slack(self.alignment_filename) except: post_to_slack('failed to post image: {self.alignment_filename}') pass BMM_clear_suspenders()
def find_detector_position(start=205, inttime=0.1, verbose=True): RE, xafs_det, dwell_time, xs = user_ns['RE'], user_ns['xafs_det'], user_ns[ 'dwell_time'], user_ns['xs'] RE.msg_hook = None # if step == 0: # step = -5 # if step > 0: # step = -1 * step step = 5 factor = 1 / inttime toomuch = 205000. / factor description = 'optimized' datatable = [] yield from mv(xafs_det, start) yield from mv(dwell_time, inttime) yield from mv(xs.cam.acquire, 1) time.sleep(0.25) ocrs = [ float(xs.channels.channel01.mcarois.mcaroi16.total_rbv.get()), float(xs.channels.channel02.mcarois.mcaroi16.total_rbv.get()), float(xs.channels.channel03.mcarois.mcaroi16.total_rbv.get()), float(xs.channels.channel04.mcarois.mcaroi16.total_rbv.get()) ] datatable.append([xafs_det.position, *ocrs]) if verbose: print( ' xafs_det OCR 1 OCR 2 OCR 3 OCR 4 target predictions' ) print( '=======================================================================================' ) print( f' {xafs_det.position:5.1f} {ocrs[0]:8.1f} {ocrs[1]:8.1f} {ocrs[2]:8.1f} {ocrs[3]:8.1f} {toomuch}' ) while all(y < toomuch for y in ocrs): if xafs_det.position - xafs_det.llm.get() < 10: step = -1 elif xafs_det.position - xafs_det.llm.get() < 30: step = -2 elif xafs_det.position - xafs_det.llm.get() < 80: step = -5 else: step = -10 if xafs_det.position + step < xafs_det.llm.get(): description = 'closest possible' print( whisper( f'the next step would go below the xafs_det soft limit ({xafs_det.llm.get()})' )) break yield from mvr(xafs_det, step) yield from mv(xs.cam.acquire, 1) time.sleep(1.5 * inttime) ocrs = [ float(xs.channels.channel01.mcarois.mcaroi16.total_rbv.get()), float(xs.channels.channel02.mcarois.mcaroi16.total_rbv.get()), float(xs.channels.channel03.mcarois.mcaroi16.total_rbv.get()), float(xs.channels.channel04.mcarois.mcaroi16.total_rbv.get()) ] datatable.append([xafs_det.position, *ocrs]) if verbose: if len(datatable) > 5: predictions = predict_detector_position(datatable, toomuch) print( f' {xafs_det.position:5.1f} {ocrs[0]:8.1f} {ocrs[1]:8.1f} {ocrs[2]:8.1f} {ocrs[3]:8.1f} {toomuch} {predictions[0]} {predictions[1]} {predictions[2]} {predictions[3]}' ) else: print( f' {xafs_det.position:5.1f} {ocrs[0]:8.1f} {ocrs[1]:8.1f} {ocrs[2]:8.1f} {ocrs[3]:8.1f} {toomuch}' ) if verbose: yield from mv(dwell_time, 1.0) #yield from mv(xs.total_points, 1) #yield from count([xs], 1) #yield from sleep(0.25) #xs.table() #xs.plot(add=True) xs.measure_xrf(doplot=False) print(whisper('make a plot with: xs.plot()')) yield from mv(dwell_time, 0.5) RE.msg_hook = BMM_msg_hook print(f'\nfound {description} detector position at ' + go_msg(f'{xafs_det.position:5.1f}')) #yield from resting_state_plan() return xafs_det.position
def kickoff(): st = StatusBase() for i in range(20): yield from mvr(motor, -1) yield from mvr(motor, 1) return st
def tweak(self, val): yield from mvr(self.motor, val)
def __grid_scan(self, x_motor, x_start, x_end, xsteps, y_motor, y_start, y_end, ysteps, z_motor, angle, ndaq, record=True): logging.debug("Setting up the sequencer for %s daq points", ndaq) self.__setup_sequencer(ndaq) # Setup the pulse picker if pp.mode.get() == 3: logging.debug("The pulse picker is already in burst mode") else: logging.debug("Setting up the pulse picker for burst mode") pp.burst(wait=True) # Setup the DAQ daq.record = record daq.configure(events=ndaq) bps.configure(daq, events=ndaq) # For plan introspection # Add sequencer, DAQ to detectors for scan dets = [daq, seq] # Log stuff logging.debug("Returning __grid_scan with the following parameters:") logging.debug("x_start: {}".format(x_start)) logging.debug("x_end: {}".format(x_end)) logging.debug("xsteps: {}".format(xsteps)) logging.debug("y_start: {}".format(y_start)) logging.debug("y_end: {}".format(y_end)) logging.debug("y_steps: {}".format(ysteps)) logging.debug("angle: {}".format(angle)) logging.debug("ndaq: {}".format(ndaq)) logging.debug("record: {}".format(record)) logging.debug("detectors: {}".format(dets)) z_start = z_motor.wm() x_step_size = (x_end - x_start) / (xsteps - 1) logging.debug("X step size: {}".format(x_step_size)) y_step_size = (y_end - y_start) / (ysteps - 1) logging.debug("Y step size: {}".format(y_step_size)) z_step = self.__comp_z(y_step_size, angle) logging.debug("Z step size: {}".format(z_step)) for i in range(ysteps): new_y = y_start + y_step_size * i logging.debug("Moving Y to {}".format(new_y)) yield from bps.mv(y_motor, new_y) if i != 0: # Skip first step; assume focus is fine there logging.debug("Moving Z by {}".format(z_step)) yield from bps.mvr(z_motor, z_step) yield from scan(dets, x_motor, x_start, x_end, xsteps) # Return to original positions yield from bps.mv(x_motor, x_start) yield from bps.mv(y_motor, y_start) yield from bps.mv(z_motor, z_start)
def gonio_axis_align(): """ Center crosshair on pin Requirements ------------ * Alignment pin mounted and centered. Pin should be aligned in X to within 0.25 of the Mag3 width * Governor in SA state * LoMag and HiMag Scale and Offset need to be enabled in Proc1 * XF:17IDC-ES:FMX{Cam:7}Proc1:EnableOffsetScale * XF:17IDC-ES:FMX{Cam:8}Proc1:EnableOffsetScale """ # Invert camera image, so dark pin on light image becomes a peak cam_7.proc1.scale.put(-1) cam_8.proc1.scale.put(-1) # High threshold, so AD centroid doesn't interpret background cam_8ThresholdOld = cam_8.stats4.centroid_threshold.get() cam_8.stats4.centroid_threshold.put(150) cam_7ThresholdOld = cam_7.stats4.centroid_threshold.get() cam_7.stats4.centroid_threshold.put(150) # HiMag # Copy ROI2 geometry (HiMag Mag3) to ROI4 and use ROI4 centroid plugin cam_8.roi4.min_xyz.min_x.put(cam_8.roi2.min_xyz.min_x.get()) cam_8.roi4.min_xyz.min_y.put(cam_8.roi2.min_xyz.min_y.get()) cam_8.roi4.size.x.put(cam_8.roi2.size.x.get() * 0.20) cam_8.roi4.size.y.put(cam_8.roi2.size.y.get()) cam_8.roi4.min_xyz.min_x.put(cam_8.roi2.min_xyz.min_x.get() + cam_8.roi2.size.x.get() / 2 - cam_8.roi4.size.x.get() / 2) # LoMag # Copy ROI2 geometry (LoMag Mag1) to ROI4 and use ROI4 centroid plugin cam_7.roi4.min_xyz.min_x.put(cam_7.roi2.min_xyz.min_x.get()) cam_7.roi4.min_xyz.min_y.put(cam_7.roi2.min_xyz.min_y.get()) cam_7.roi4.size.x.put(cam_7.roi2.size.x.get() * 0.05) cam_7.roi4.size.y.put(cam_7.roi2.size.y.get()) cam_7.roi4.min_xyz.min_x.put(cam_7.roi2.min_xyz.min_x.get() + cam_7.roi2.size.x.get() / 2 - cam_7.roi4.size.x.get() / 2) centerPinYHiMag0 = centroid_avg(cam_8.stats4)[1] centerPinYLoMag0 = centroid_avg(cam_7.stats4)[1] yield from bps.mvr(gonio.o, 180) time.sleep(2) centerPinYHiMag180 = centroid_avg(cam_8.stats4)[1] centerPinYLoMag180 = centroid_avg(cam_7.stats4)[1] centerPinYHiMag = (centerPinYHiMag0 + centerPinYHiMag180) / 2 centerPinYLoMag = (centerPinYLoMag0 + centerPinYLoMag180) / 2 centerPinOffsYHiMag = centerPinYHiMag - cam_8.roi4.size.y.get() / 2 centerPinOffsYLoMag = centerPinYLoMag - cam_7.roi4.size.y.get() / 2 # Correct Mag 3 (cam_8 ROI2) cam_8.roi2.min_xyz.min_y.put(cam_8.roi2.min_xyz.min_y.get() + centerPinOffsYHiMag) # Correct Mag 4 (cam_8 ROI1) cam_8.roi1.min_xyz.min_y.put( cam_8.roi2.min_xyz.min_y.get() + (cam_8.roi2.size.y.get() - cam_8.roi1.size.y.get()) / 2) # Correct Mag 1 (cam_7 ROI2) cam_7.roi2.min_xyz.min_y.put(cam_7.roi2.min_xyz.min_y.get() + centerPinOffsYLoMag) # Correct Mag 2 (cam_7 ROI3) cam_7.roi3.min_xyz.min_y.put( cam_7.roi2.min_xyz.min_y.get() + (cam_7.roi2.size.y.get() - cam_7.roi3.size.y.get()) / 2) # De-invert image cam_7.proc1.scale.put(-1) cam_8.proc1.scale.put(-1) # Set thresold to previous value cam_8.stats4.centroid_threshold.put(cam_8ThresholdOld) cam_7.stats4.centroid_threshold.put(cam_7ThresholdOld) return