def my_list_grid_scan(detector: tp.Any, *args, acquire_time: float, images_per_set: int, wait_for_step: float = 0., wait_for_shutter: float = 0.5, md: dict = None) -> tp.Generator: """Configure detector and run a list_grid_scan with shutter control and wait for seconds at each step.""" if not md: md = {} def per_step(detectors, step: dict, pos_cache: dict): _motors = step.keys() yield from my_move_per_step(step, pos_cache) yield from bps.sleep(wait_for_step) yield from open_shutter_stub() yield from bps.sleep(wait_for_shutter) yield from bps.trigger_and_read(list(detectors) + list(_motors)) yield from close_shutter_stub() plan = bp.list_grid_scan([detector], *args, per_step=per_step, md=md) motors = list(args[::2]) plan = bpp.subs_wrapper(plan, LiveTable([detector] + motors)) yield from configure_cam_detector(detector, acquire_time, images_per_set) return (yield from plan)
def test_list_grid_scan(RE, hw): expected_data = [] for motor1_pos in [6, 7, 8]: for motor2_pos in [18, 28, 38]: expected_data.append({ 'motor2': motor2_pos, 'motor2_setpoint': motor2_pos, 'det': 1.0, 'motor1': motor1_pos, 'motor1_setpoint': motor1_pos }) scan = bp.list_grid_scan([hw.det], hw.motor1, [6, 7, 8], hw.motor2, [18, 28, 38]) multi_traj_checker(RE, scan, expected_data)
def serp_seq_scan(shift_motor, shift_pts, fly_motor, fly_pts, seq): """ Serpentine scan that triggers the event sequencer on every row. Parameters ---------- shift_motor: Positioner The column axis to shift to the next fly scan row shift_pts: list of floats The positions of the rows to scan down, e.g. [0, 1, 2, 3 ...], np.arange(0, 100, 1000), etc. fly_motor: Positioner The row axis to do fly collection on fly_pts: list of 2 floats The positions to fly between, e.g. [0, 100] seq: Sequencer The sequencer to start on each row. """ if len(fly_pts) != 2: raise ValueError('Expected fly_pts to have exactly 2 points!') is_seq_step = False #is_seq_step = True def per_step(detectors, step, pos_cache): """ Override default per_step to start the sequencer on each row. The first move is not a fly scan move: it moves us into the start position. The second move is, as is the fourth, sixth... """ nonlocal is_seq_step if is_seq_step: yield from trigger(seq) is_seq_step = False else: is_seq_step = True yield from one_nd_step(detectors, step, pos_cache) return (yield from list_grid_scan([], shift_motor, shift_pts, fly_motor, fly_pts, snake_axes=True, per_step=per_step))
def xpdacq_list_grid_scan_with_dark( detectors: list, *args, snake_axes: typing.Union[bool, typing.Iterable[bool], None] = None, per_step: typing.Callable = xpdacq_per_step, md: typing.Union[dict, None] = None): """ Scan over a mesh; each motor is on an independent trajectory. If there is a change in the position of the slow motor, take a dark image. Parameters ---------- detectors: list list of 'readable' objects args: list patterned like (``motor1, position_list1,`` ``motor2, position_list2,`` ``motor3, position_list3,`` ``...,`` ``motorN, position_listN``) The first motor is the "slowest", the outer loop. ``position_list``'s are lists of positions, all lists must have the same length. Motors can be any 'settable' object (motor, temp controller, etc.). snake_axes: boolean or iterable, optional which axes should be snaked, either ``False`` (do not snake any axes), ``True`` (snake all axes) or a list of axes to snake. "Snaking" an axis is defined as following snake-like, winding trajectory instead of a simple left-to-right trajectory.The elements of the list are motors that are listed in `args`. The list must not contain the slowest (first) motor, since it can't be snaked. per_step: callable, optional hook for customizing action of inner loop (messages per step). See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) for details. md: dict, optional metadata """ if args: slow_motor = args[0] per_step = slow_dark_wrapper(per_step, slow_motor) yield from bp.list_grid_scan(detectors, *args, snake_axes=snake_axes, per_step=per_step, md=md)
def test_list_grid_scan_snake_list(RE, hw): expected_data = [] for motor1_pos in [6, 7, 8]: if motor1_pos == 7: motor2_list = [38, 28, 18] else: motor2_list = [18, 28, 38] for motor2_pos in motor2_list: expected_data.append({ 'motor2': motor2_pos, 'motor2_setpoint': motor2_pos, 'det': 1.0, 'motor1': motor1_pos, 'motor1_setpoint': motor1_pos }) scan = bp.list_grid_scan([hw.det], hw.motor1, [6, 7, 8], hw.motor2, [18, 28, 38], snake_axes=[hw.motor2]) multi_traj_checker(RE, scan, expected_data)
def list2scan(self, m1, p1, m2, p3, nEvents, record=None, use_l3t=False, post=False): self.cleanup_RE() currPos1 = m1.wm() currPos2 = m2.wm() daq.configure(nEvents, record=record, controls=[m1,m2], use_l3t=use_l3t) try: RE(list_grid_scan([daq], m1,p1,m2,p3)) except Exception: logger.debug('RE Exit', exc_info=True) finally: self.cleanup_RE() m1.mv(currPos1) m2.mv(currPos2) if post: run = get_run() message = 'grid scan with {name1} from {min1:.3f} to {max1:.3f} in {num1} steps, and {name2} from {min2:.3f} to {max2:.3f} in {num2} steps'.format(name1=m1.name, min1=p1[0],max1=p1[-1], num1=p1.size, name2=m2.name, min2=p2[0],max2=p2[-1],num2=p2.size) self.elog.post(message,run=int(run))
from bluesky.plans import list_grid_scan from ophyd.sim import det4, motor1, motor2 dets = [det4] RE(list_grid_scan(dets, motor1, [1, 1, 2, 3, 5], motor2, [25, 16, 9]))
def test_simple_list_grid_scan(): RE = RunEngine() hardware = yaqc_bluesky.Device(39424) sensor = yaqc_bluesky.Device(39425) lis = [-10, -8, 4, 2, 10] RE(list_grid_scan([sensor], hardware, lis))