def _ct_dark_cleanup(oldnumim, gain_bit_dict, gain_state, dark_sh_dict, dark_shutter_state): print('\nReturning to intial conditions (pre-count).') yield from bps.abs_set(fccd.cam.num_images, oldnumim, wait=True) yield from bps.mv(fccd.cam.fcric_gain, gain_state) yield from bps.mv(inout, dark_sh_dict.get(dark_shutter_state)) yield from bps.sleep(fccd.cam.acquire_period.value) print('\tTotal images per trigger are NOW:\t {}'.format( fccd.cam.num_images.setpoint)) print('\tFCCD FCRIC gain value is NOW:\t\t {}\n\n'.format( gain_bit_dict.get(fccd.cam.fcric_gain.value)))
def tablev_scan(): ''' send signal to DO01 to trigger tablev_scan ''' yield from bps.mv(table_trigger, 0) # start tablev_scan yield from bps.sleep(1) # sleep until we see the busy signal go high cnt = 0 while (table_busy.read()[table_busy.name]['value'] < 0.5) and cnt < 100: print('waiting for busy signal...') yield from bps.sleep(2) cnt += 1 # Turn off trigger signal yield from bps.mv(table_trigger, 1)
def test_mv_progress(RE, hw): motor1 = hw.motor1 motor2 = hw.motor2 RE.waiting_hook = ProgressBarManager() assert RE.waiting_hook.delay_draw == 0.2 # moving time > delay_draw motor1.delay = 0.5 motor1.delay = 0.5 RE(mv(motor1, 0, motor2, 0)) # moving time < delay_draw motor1.delay = 0.01 motor1.delay = 0.01 RE(mv(motor1, 0, motor2, 0))
def _setup_mm(mm_mode): if mm_mode == 'Current': monitor_during = [MM.readcurr] yield from bps.mv(MM.readtype, mm_mode) elif mm_mode == 'Voltage': monitor_during = [MM.readvolt] yield from bps.mv(MM.readtype, mm_mode) elif mm_mode == 'none': monitor_during = [] else: raise ValueError(f'you passed mm_mode={mm_mode} ' 'but the value must be one of ' '{"Current", "Voltage"}') return monitor_during
def dark_plan(self, detector): """The plan to take dark.""" # Restage to ensure that dark frames goes into a separate file. yield from bps.unstage(detector) yield from bps.stage(detector) yield from bps.mv(self.shutter, self.shutter_close) # The `group` parameter passed to trigger MUST start with # bluesky-darkframes-trigger. yield from bps.trigger(detector, group='bluesky-darkframes-trigger') yield from bps.wait('bluesky-darkframes-trigger') snapshot = SnapshotDevice(detector) yield from bps.mv(self.shutter, self.shutter_open) # Restage. yield from bps.unstage(detector) yield from bps.stage(detector) return snapshot
def moveE(energy): args_list = [] args_list.append((mono.energy, energy)) if undulator.downstream.tracking is True: target_energy = undulator.downstream.offset + energy current_energy = undulator.downstream.energy.get( ) + undulator.downstream.deadband if current_energy < target_energy: args_list[0] += (undulator.downstream.energy, target_energy + undulator.downstream.backlash) args_list[0] += (undulator.downstream.start_button, 1) args_list.append((undulator.downstream.energy, target_energy)) args_list[-1] += (undulator.downstream.start_button, 1) else: args_list[0] += (undulator.downstream.energy, target_energy) args_list[0] += (undulator.downstream.start_button, 1) stage(mono) for args in args_list: yield from mv(*args)
def level_s_stage(): """level_s_stage level s_stage vx, vy double wafer stage: (-85, 85), (-58, 85) """ # level on y axis yield from bps.mv(s_stage.px, 20, s_stage.py, -46) yield from level_stage_single(lrf, s_stage.vy, s_stage.py, 105, -46) # level on x axis yield from bps.mv(s_stage.px, 28,29, s_stage.py, 0) yield from level_stage_single(lrf, s_stage.vx, s_stage.px, -73,28 ) # level on y axis yield from bps.mv(s_stage.px, 20, s_stage.py, -46) yield from level_stage_single(lrf, s_stage.vy, s_stage.py, 105, -46)
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 fermat_master_plan(*args, exp_time=None, **kwargs): # Synchronize exposure times sclr1.preset_time.put(exp_time) xs.external_trig.put(False) xs.settings.acquire_time.put(exp_time) merlin.cam.acquire_time.put(exp_time) merlin.cam.acquire_period.put(exp_time + 0.005) scan_md = {} get_stock_md(scan_md) scan_md['scan']['merlin'] = { 'merlin_exp_time': exp_time, 'merlin_exp_period': exp_time + 0.005 } plan = bp.rel_spiral_fermat(*args, **kwargs) d = plot_raster_path(plan, args[1].name, args[2].name, probe_size=.001, lw=0.5) num_points = d['path'].get_path().vertices.shape[0] print(f"Number of points: {num_points}") xs.total_points.put(num_points) yield from bps.mv(merlin.total_points, num_points, merlin.hdf5.num_capture, num_points) merlin.hdf5.stage_sigs['num_capture'] = num_points yield from rel_spiral_fermat(*args, **kwargs, md=scan_md)
def batch_parse_and_execute(hhm, sample_stage, batch, plans_dict): tm = trajectory_manager(hhm) for ii in range(batch.rowCount()): experiment = batch.item(ii) print(experiment.item_type) repeat = experiment.repeat print(repeat) for jj in range(experiment.rowCount()): sample = experiment.child(jj) print(' ' + sample.name) print(' ' + str(sample.x)) print(' ' + str(sample.y)) yield from mv(sample_stage.x, sample.x, sample_stage.y, sample.y) for kk in range(sample.rowCount()): scan = sample.child(kk) traj_index = scan.trajectory print(' ' + scan.scan_type) plan = plans_dict[scan.scan_type] kwargs = { 'name': sample.name, 'comment': '', 'delay': 0, 'n_cycles': repeat } tm.init(traj_index + 1) yield from plan(**kwargs)
def resetAll(self): """bluesky plan to reset all to preset values""" yield from bps.mv( self.temperature, 25, self.concentration, 1, self.volume_fraction, 1, self.scattering_length_density, 1, self.magnetic_field, 0, self.stress_field, 0, self.electric_field, 0, self.x_translation, 0, self.rotation_angle, 0, self.magnetic_field_dir, "X", self.stress_field_dir, "X", self.electric_field_dir, "X", self.description, "", self.chemical_formula, "", )
def move_after_scan(thismotor): ''' Call this to pluck a point from a plot and move the plotted motor to that x-value. ''' BMMuser = user_ns['BMMuser'] if BMMuser.motor is None: print(error_msg('\nThere\'s not a current plot on screen.\n')) return (yield from null()) if thismotor is not BMMuser.motor: print( error_msg( '\nThe motor you are asking to move is not the motor in the current plot.\n' )) return (yield from null()) print('Single click the left mouse button on the plot to pluck a point...') cid = BMMuser.fig.canvas.mpl_connect( 'button_press_event', interpret_click) # see derivedplot.py and while BMMuser.x is None: # https://matplotlib.org/users/event_handling.html yield from sleep(0.5) if BMMuser.motor2 is None: yield from mv(thismotor, BMMuser.x) else: print('%.3f %.3f' % (BMMuser.x, BMMuser.y)) #yield from mv(BMMuser.motor, BMMuser.x, BMMuser.motor2, BMMuser.y) cid = BMMuser.fig.canvas.mpl_disconnect(cid) BMMuser.x = BMMuser.y = None
def wafer_edge(motor='x'): '''Fit an error function to the linear scan against It. Plot the result. Move to the centroid of the error function.''' if motor == 'x': motor = user_ns['xafs_linx'] else: motor = user_ns['xafs_liny'] yield from linescan(motor, 'it', -2, 2, 41, pluck=False) close_last_plot() table = user_ns['db'][-1].table() yy = table[motor.name] signal = table['It'] / table['I0'] if float(signal[2]) > list(signal)[-2]: ss = -(signal - signal[2]) else: ss = signal - signal[2] mod = StepModel(form='erf') pars = mod.guess(ss, x=numpy.array(yy)) out = mod.fit(ss, pars, x=numpy.array(yy)) print(whisper(out.fit_report(min_correl=0))) out.plot() target = out.params['center'].value yield from mv(motor, target) yield from resting_state_plan() print( f'Edge found at X={user_ns["xafs_x"].position} and Y={user_ns["xafs_y"].position}' )
def xanes_batch_plan(xypos=[], erange=[], estep=[], acqtime=1.0, waittime=10, peakup_N=2, peakup_E=None): """ Setup a batch XANES scan at multiple points. This scan can also run peakup_fine() between points. xypos <list> A list of points to run XANES scans erange <list> A list of energy points to send to the XANES plan estep <list> A list of energy steps to send to the XANES plan acqtime <float> Acquisition time for each data point. peakup_N <int> Run a peakup every peakup_N scans. Default is no peakup peakup_E <float> The energy to run peakup at. Default is current energy """ # Check positions if (xypos == []): print('You need to enter positions.') return # Check erange and estep if (erange == []): print('You need to enter erange.') return if (estep == []): print('You need to enter estep.') return # Get current energy and use it for peakup if (peakup_E == None): peakup_E = energy.position.energy # Convert keV to eV if (peakup_E < 1000): peakup_E = peakup_E * 1000 # Loop through positions N = len(xypos) for i in range(N): print(f'Moving to:') print(f'\tx = {xypos[i][0]}') print(f'\ty = {xypos[i][1]}') hf_stage.x.move(xypos[i][0]) hf_stage.y.move(xypos[i][1]) if (len(xypos[i]) == 3): print(f'\tz = {xypos[i][2]}') hf_stage.z.move(xypos[i][2]) # Move above edge and peak up if (i % peakup_N == 0): yield from mv(energy, peakup_E) yield from peakup_fine() # Run the energy scan yield from xanes_plan(erange=erange, estep=estep, acqtime=acqtime) # Wait if (i != (N-1)): print(f'Scan complete. Waiting {waittime} seconds...') bps.sleep(waittime)
def plan(): yield from bps.mov(xs.total_points, xnum) # added to "prime" the detector #yield from abs_set(xs.settings.trigger_mode, 'TTL Veto Only') yield from bps.mov(xs.external_trig, True) ystep = 0 for step in np.linspace(ystart, ystop, ynum): yield from abs_set(scanrecord.time_remaining, (ynum - ystep) * ( dwell * xnum + 3.8 ) / 3600.) ystep = ystep + 1 # 'arm' the xs for outputting fly data yield from bps.mov(xs.fly_next, True) # print('h5 armed\t',time.time()) if step == ystart: firststep = True else: firststep = False yield from fly_each_step([], ymotor, step, firststep) # print('return from step\t',time.time()) yield from bps.mov(xs.external_trig, False, ion.count_mode, 1) if shutter is True: yield from mv(shut_b, 'Close')
def fast_shutter_per_step(detectors, motor, step): def move(): grp = _short_uid('set') yield Msg('checkpoint') yield Msg('set', motor, step, group=grp) yield Msg('wait', None, group=grp) yield from move() # Open and close the fast shutter (Mo Foil) between XANES points # Open the shutter yield from mv(Mo_shutter, 0) yield from bps.sleep(1.0) # Step? trigger xspress3 yield from trigger_and_read(list(detectors) + [motor]) # Close the shutter yield from mv(Mo_shutter, 1)
def recover_mirrors(): m2_xu, m2_xd, m2_yu, m2_ydo, m2_ydi = user_ns['m2_xu'], user_ns['m2_xd'], user_ns['m2_yu'], user_ns['m2_ydo'], user_ns['m2_ydi'] m3_xu, m3_xd, m3_yu, m3_ydo, m3_ydi = user_ns['m3_xu'], user_ns['m3_xd'], user_ns['m3_yu'], user_ns['m3_ydo'], user_ns['m3_ydi'] yield from abs_set(m2_yu.home_signal, 1) yield from abs_set(m2_xu.home_signal, 1) yield from abs_set(m3_yu.home_signal, 1) yield from abs_set(m3_xu.home_signal, 1) yield from sleep(1.0) print('Begin homing lateral and vertical motors in M2 and M3:\n') hvalues = (m2_yu.hocpl.get(), m2_ydo.hocpl.get(), m2_ydi.hocpl.get(), m2_xu.hocpl.get(), m2_xd.hocpl.get(), m3_yu.hocpl.get(), m3_ydo.hocpl.get(), m3_ydi.hocpl.get(), m3_xu.hocpl.get(), m3_xd.hocpl.get()) while any(v == 0 for v in hvalues): hvalues = (m2_yu.hocpl.get(), m2_ydo.hocpl.get(), m2_ydi.hocpl.get(), m2_xu.hocpl.get(), m2_xd.hocpl.get(), m3_yu.hocpl.get(), m3_ydo.hocpl.get(), m3_ydi.hocpl.get(), m3_xu.hocpl.get(), m3_xd.hocpl.get()) strings = ['m2_yu', 'm2_ydo', 'm2_ydi', 'm2_xu', 'm2_xd', 'm3_yu', 'm3_ydo', 'm3_ydi', 'm3_xu', 'm3_xd',] for i,v in enumerate(hvalues): strings[i] = go_msg(strings[i]) if hvalues[i] == 1 else error_msg(strings[i]) print(' '.join(strings), end='\r') yield from sleep(1.0) print('\n') yield from mv(m2_yu, MODEDATA['m2_yu']['E'], m2_ydo, MODEDATA['m2_ydo']['E'], m2_ydi, MODEDATA['m2_ydi']['E'], m2_xu, MODEDATA['m2_xu']['E'], m2_xd, MODEDATA['m2_xd']['E'], m3_yu, MODEDATA['m3_yu']['E'], m3_ydo, MODEDATA['m3_ydo']['E'], m3_ydi, MODEDATA['m3_ydi']['E'], m3_xu, MODEDATA['m3_xu']['E'], m3_xd, MODEDATA['m3_xd']['E'])
def dark_plan(detector, dark_frame_cache, max_age, shutter): if (dark_frame_cache.just_started or # first run after instantiation (dark_frame_cache.last_collected is not None and time.monotonic() - dark_frame_cache.last_collected > max_age)): init_shutter_state = shutter.get() yield from bps.mv(shutter, 0) yield from bps.trigger(detector, group='cam') yield from bps.wait('cam') yield from bps.mv(shutter, init_shutter_state) teleport(detector, dark_frame_cache) dark_frame_cache.just_started = False dark_frame_cache.update_done = True else: dark_frame_cache.update_done = False
def tune_usaxs_optics(side=False, md={}): """ tune all the instrument optics currently in configuration This plan is for staff use. Users are advised to use preUSAXStune() instead. """ yield from mode_USAXS() suspender_preinstalled = suspend_BeamInHutch in RE.suspenders if not suspender_preinstalled: yield from bps.install_suspender(suspend_BeamInHutch) yield from tune_mr(md=md) yield from tune_m2rp(md=md) if side: yield from tune_msrp(md=md) yield from tune_asrp(md=md) yield from tune_ar(md=md) yield from tune_a2rp(md=md) if not suspender_preinstalled: yield from bps.remove_suspender(suspend_BeamInHutch) yield from bps.mv( terms.preUSAXStune.num_scans_last_tune, 0, terms.preUSAXStune.epoch_last_tune, time.time(), )
def align_y(self, force=False, drop=None): '''Fit an error function to the xafs_y scan against It. Plot the result. Move to the centroid of the error function.''' xafs_y = user_ns['xafs_y'] db = user_ns['db'] yield from linescan(xafs_y, 'it', -1, 1, 31, pluck=False) close_last_plot() table = db[-1].table() yy = table['xafs_y'] signal = table['It'] / table['I0'] if drop is not None: yy = yy[:-drop] signal = signal[:-drop] if float(signal[2]) > list(signal)[-2]: ss = -(signal - signal[2]) self.inverted = 'inverted ' else: ss = signal - signal[2] self.inverted = '' mod = StepModel(form='erf') pars = mod.guess(ss, x=numpy.array(yy)) out = mod.fit(ss, pars, x=numpy.array(yy)) print(whisper(out.fit_report(min_correl=0))) self.y_plot(yy, out) target = out.params['center'].value yield from mv(xafs_y, target)
def move_then_count( motors: typing.List[ophyd.device.Device], detectors: typing.Optional[typing.List[ophyd.device.Device]] = None, positions: typing.Optional[typing.List[float]] = None, ) -> typing.Generator[bluesky.utils.Msg, None, None]: if not isinstance(motors, (list, tuple)): raise TypeError( f"Parameter 'motors' should be a list or a tuple: type(motors) = {type(motors)}" ) if not isinstance(detectors, (list, tuple)): raise TypeError( f"Parameter 'detectors' should be a list or a tuple: type(detectors) = {type(detectors)}" ) if not isinstance(positions, (list, tuple)): raise TypeError( f"Parameter 'positions' should be a list or a tuple: type(positions) = {type(positions)}" ) if len(motors) != len(positions): raise TypeError( f"The lists of 'motors' and 'positions' should have the same number of elements: " f"len(motors) = {len(motors)}, len(positions) = {len(positions)}") mv_args = [val for tup in zip(motors, positions) for val in tup] yield from bps.mv(*mv_args) yield from count(detectors)
def per_step_plan(detectors, motors, actions, *args, log=None, **kwargs): '''execute one step and return detecors readings Applies the actions to the motors and reads the detectors. Args: detectors: detectors to read from motors: motors to apply the actions to actions: keras-rl requested actions Returns: the detector readings. ''' if log is None: log = logger motors = list(motors) action = list(actions) # There should be a func ml = [] for m, a in zip(motors, action): ml.extend([m, a]) args = tuple(ml) log.debug(f'Executing move (bps.mv) {args}') yield from bps.mv(*args) r = (yield from bps.trigger_and_read(detectors)) log.debug(f'Read {detectors} to {r}') return r
def center(signal_key='xsp3_channel1_rois_roi01_value', motor_key='s_stage_pz'): # first move the stage to the copper yield from copper() # do a z-scan while reading the xps3 num = 10 xsp3.total_points.put(num) yield from bp.rel_scan([xsp3], pz, -3, 3, num=num) # grab the data to find the signal peak, no need to fill data, ROI's are scalars df = db[-1].table() ds = df[signal_key] dz = df[motor_key] # find the location of the signal maximum # need to check out the data type of the xps3 deriv = ds.diff() / dz.diff() left_z = dz[deriv == deriv.max()].item() right_z = dz[deriv == deriv.min()].item() nz = (right_z - left_z) / 2 + left_z print(f'({left_z}, {right_z})--> {nz}') # set the z offset so that the stage is zeroed at the signal max # user_readback=dial+offset curr_offset = pz.user_offset.get() pz.user_offset.set(curr_offset - nz) # move to the home location #yield from home() yield from bps.mv(px, 0, py, 0, pz, 0)
def rel_smooth_sweep_test(mot_x, target): """ rel_smooth_sweep_test is a test method. """ logging.info('driving motor to {:0.4f}'.format(target)) yield from mv(mot_x, target) logging.info('motor arrived at {:0.4f}'.format(target))
def peak_analysis(self, initial_position): if self.peak_detected(): self.tune_ok = True if self.peak_choice == "cen": final_position = self.peaks.cen elif self.peak_choice == "com": final_position = self.peaks.com else: final_position = None self.center = final_position else: self.tune_ok = False final_position = initial_position yield from bps.mv(self.axis, final_position) stream_name = "PeakStats" results = TuningResults(name=stream_name) results.tune_ok.put(self.tune_ok) results.center.put(self.center) results.final_position.put(final_position) results.initial_position.put(initial_position) if self.peaks is None: logger.info("PeakStats object is None.") results.put_results({}) else: results.put_results(self.peaks) self.stats.append(results) t = results.report(print_enable=False) logger.info("%s\n%s", stream_name, str(t))
def calib_dist(self, position: tp.Any, stream: str, output_dir: str = "xpdacq_calib", pyfai_kwargs=None, md=None): """Calibration the distance and add it to the plan.""" yield from bps.mv(self.motor, position) ais = yield from self.calibrate([self.detector], [self.calib_cpt], config_det=False, output_dir=output_dir, pyfai_kwargs=pyfai_kwargs, md=md) self.add_dist(position, stream, ais[0])
def my_move_per_step(step: dict, pos_cache: dict): yield from bps.checkpoint() for motor, pos in step.items(): if pos == pos_cache[motor]: continue yield from bps.mv(motor, pos) pos_cache[motor] = pos
def test_mv_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(mv(hw.motor1, 1, hw.motor2, 2, timeout=42)) for msg in actual[:2]: msg.command == 'set' msg.kwargs['timeout'] == 42
def center_sample_y(): yield from linescan('it', xafs_liny, -1.5, 1.5, 61, pluck=False) table = db[-1].table() diff = -1 * table['It'].diff() inflection = table['xafs_liny'][diff.idxmax()] yield from mv(xafs_liny, inflection) print(bold_msg('Optimal position in y at %.3f' % inflection))
def align_linear(self, force=False, drop=None): '''Fit an error function to the linear scan against It. Plot the result. Move to the centroid of the error function.''' if self.orientation == 'parallel': motor = user_ns['xafs_liny'] else: motor = user_ns['xafs_linx'] yield from linescan(motor, 'it', -2.3, 2.3, 51, pluck=False) close_last_plot() table = user_ns['db'][-1].table() yy = table[motor.name] signal = table['It']/table['I0'] if drop is not None: yy = yy[:-drop] signal = signal[:-drop] if float(signal[2]) > list(signal)[-2] : ss = -(signal - signal[2]) self.inverted = 'inverted ' else: ss = signal - signal[2] self.inverted = '' mod = StepModel(form='erf') pars = mod.guess(ss, x=numpy.array(yy)) out = mod.fit(ss, pars, x=numpy.array(yy)) print(whisper(out.fit_report(min_correl=0))) target = out.params['center'].value yield from mv(motor, target) self.y_plot(yy, out)
def move_and_do_one(bt: Beamtime, sample_ind: tp.Union[int, str], plan_ind: tp.Union[int, str, tp.Generator], wait_time: float = 0., sample_x: str = "sample_x", sample_y: str = "sample_y", x_controller: str = "x_controller", y_controller: str = "y_controller") -> tp.Generator: """Move to the sample and conduct the plan.""" sample = translate_to_sample(bt, sample_ind) plan = translate_to_plan(bt, plan_ind, sample) xc = xpd_configuration[x_controller] yc = xpd_configuration[y_controller] x = float(get_from_sample(sample, sample_x)) y = float(get_from_sample(sample, sample_y)) yield from bps.checkpoint() print("Start moving to sample {} at ({}, {}).".format(sample_ind, x, y)) yield from bps.mv(xc, x, yc, y) print("Finish. ") yield from bps.checkpoint() print("Start sleeping for {} s.".format(wait_time)) yield from bps.sleep(wait_time) print("Wake up.") yield from bps.checkpoint() print("Start plan {} for sample {}".format(plan_ind, sample_ind)) yield from plan print("Finish.")
def test_bluesky_magics(pln, plnargs, magic, line, detectors_factory, RE, hw): # Build a FakeIPython instance to use the magics with. dets = [hw.invariant1] hw.invariant1._ophyd_labels_ = set(['detectors', 'favorite_detectors']) hw.invariant2._ophyd_labels_ = set(['detectors']) ip = FakeIPython({'motor1': hw.motor1, 'motor2': hw.motor2, 'invariant1': hw.invariant1, 'invariant2': hw.invariant2, 'dets': dets} ) sm = BlueskyMagics(ip) detectors = detectors_factory(hw) if detectors: # Test deprecated usage of %ct. with pytest.warns(UserWarning): BlueskyMagics.detectors = detectors # Spy on all msgs processed by RE. msgs = [] def collect(msg): msgs.append(msg) RE.msg_hook = collect BlueskyMagics.RE.msg_hook = collect # Test magics cause the RunEngine to execute the messages we expect. RE(bps.mv(hw.motor1, 10, hw.motor2, 10)) # ensure known initial state msgs.clear() RE(pln(*plnargs(hw))) expected = msgs.copy() RE(bps.mv(hw.motor1, 10, hw.motor2, 10)) # ensure known initial state msgs.clear() if detectors: # Test deprecated usage of %ct. Must catch warning. with pytest.warns(UserWarning): getattr(sm, magic)(line) else: # Normal usage, no warning. getattr(sm, magic)(line) actual = msgs.copy() msgs.clear() compare_msgs(actual, expected) if detectors: with pytest.warns(UserWarning): BlueskyMagics.detectors.clear()
def test_mv(hw): # special-case mv because the group is not configurable # move motors first to ensure that movement is absolute, not relative 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 _ct_dark(detectors, gain_bit_input, gain_bit_dict): yield from bps.mv(fccd.cam.fcric_gain, gain_bit_input) # if _gain_bit_input != 0: # yield from bps.sleep(fccd.cam.acquire_period.value*2.01) # This has to be 2 until we can selectively remove dark images get_fastccd_images() print('\n\nGain bit set to {} for a gain value of {}\n'.format( gain_bit_input, gain_bit_dict.get(gain_bit_input))) # TODO use md csxtools dark correction yield from bp.count(detectors, md={'fccd': { 'image': 'dark', 'gain': gain_bit_dict.get(gain_bit_input)}})
def move(): yield Msg('checkpoint') grp = _short_uid('set') for motor, pos in step.items(): if pos == pos_cache[motor]: # This step does not move this motor. continue yield Msg('set', motor, pos, group=grp) pos_cache[motor] = pos yield Msg('wait', None, group=grp) # this means "take the attenuator out of the beam" yield from mv(attn_shutter, 'Retract')
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 one_1d_step_pseudo_shutter(detectors, motor, step): """ Inner loop of a 1D step scan This is the default function for ``per_step`` param in 1D plans. """ from bluesky.plans import Msg from bluesky.preprocessors import trigger_and_read from bluesky.plan_stubs import mv, _short_uid def move(): grp = _short_uid('set') yield Msg('checkpoint') yield Msg('set', motor, step, group=grp) yield Msg('wait', None, group=grp) yield from mv(attn_shutter, 'Retract') yield from move() ret = (yield from trigger_and_read(list(detectors) + [motor])) yield from mv(attn_shutter, 'Insert') return ret
def one_nd_step_check_beam(detectors, step, pos_cache): from bluesky.plans import Msg from bluesky.preprocessors import trigger_and_read from bluesky.plan_stubs import mv, _short_uid def move(): yield Msg('checkpoint') grp = _short_uid('set') for motor, pos in step.items(): if pos == pos_cache[motor]: # This step does not move this motor. continue yield Msg('set', motor, pos, group=grp) pos_cache[motor] = pos yield Msg('wait', None, group=grp) motors = step.keys() yield from move() ret = (yield from trigger_and_read(list(detectors) + list(motors))) # this means "put the attenuator in the beam" yield from mv(attn_shutter, 'Insert') return ret
def one_nd_step_pseudo_shutter(detectors, step, pos_cache): """ Inner loop of an N-dimensional step scan This is the default function for ``per_step`` param`` in ND plans. Parameters ---------- detectors : iterable devices to read step : dict mapping motors to positions in this step pos_cache : dict mapping motors to their last-set positions """ from bluesky.plans import Msg from bluesky.preprocessors import trigger_and_read from bluesky.plan_stubs import mv, _short_uid def move(): yield Msg('checkpoint') grp = _short_uid('set') for motor, pos in step.items(): if pos == pos_cache[motor]: # This step does not move this motor. continue yield Msg('set', motor, pos, group=grp) pos_cache[motor] = pos yield Msg('wait', None, group=grp) # this means "take the attenuator out of the beam" yield from mv(attn_shutter, 'Retract') motors = step.keys() yield from move() ret = (yield from trigger_and_read(list(detectors) + list(motors))) # this means "put the attenuator in the beam" yield from mv(attn_shutter, 'Insert') return ret
def set_reference_foil(element = None): # Adding reference foil element list with open('/nsls2/xf08id/settings/json/foil_wheel.json') as fp: reference_foils = json.load(fp) elems = [item['element'] for item in reference_foils] if element is None: yield from mv(foil_wheel.wheel1, 0) yield from mv(foil_wheel.wheel2, 0) else: if element in elems: indx = elems.index(element) yield from mv(foil_wheel.wheel2, reference_foils[indx]['fw2']) yield from mv(foil_wheel.wheel1, reference_foils[indx]['fw1']) else: yield from mv(foil_wheel.wheel1, 0) yield from mv(foil_wheel.wheel2, 0)
def set_foil_reference(element = None): # Adding reference foil element list reference_foils = json.loads(open('/nsls2/xf08id/settings/json/foil_wheel.json').read()) elems = [item['element'] for item in reference_foils] ##print(reference_foils[][][]) #reference = {'Ti': {'foilwheel1': 30, 'foilwheel2': 0}, # 'V': {'foilwheel1': 60, 'foilwheel2': 0}, # 'Cr': {'foilwheel1': 90, 'foilwheel2': 0}, # 'Mn': {'foilwheel1': 120, 'foilwheel2': 0}, # 'Fe': {'foilwheel1': 150, 'foilwheel2': 0}, # 'Co': {'foilwheel1': 180, 'foilwheel2': 0}, # 'Ni': {'foilwheel1': 210, 'foilwheel2': 0}, # 'Cu': {'foilwheel1': 240, 'foilwheel2': 0}, # 'Zn': {'foilwheel1': 270, 'foilwheel2': 0}, # 'Pt': {'foilwheel1': 300, 'foilwheel2': 0}, # 'Au': {'foilwheel1': 330, 'foilwheel2': 0}, # 'Se': {'foilwheel2': 60, 'foilwheel1': 0}, # 'Pb': {'foilwheel2': 90, 'foilwheel1': 0}, # 'Nb': {'foilwheel2': 120, 'foilwheel1': 0}, # 'Mo': {'foilwheel2': 150, 'foilwheel1': 0}, # 'Ru': {'foilwheel2': 180, 'foilwheel1': 0}, # 'Rh': {'foilwheel2': 210, 'foilwheel1': 0}, # 'Pd': {'foilwheel2': 240, 'foilwheel1': 0}, # 'Ag': {'foilwheel2': 270, 'foilwheel1': 0}, # 'Sn': {'foilwheel2': 300, 'foilwheel1': 0}, # 'Sb': {'foilwheel2': 330, 'foilwheel1': 0} # } if element is None: yield from mv(foil_wheel.wheel1, 0) yield from mv(foil_wheel.wheel2, 0) else: if element in elems: indx = elems.index(element) yield from mv(foil_wheel.wheel2, reference_foils[indx]['fw2']) yield from mv(foil_wheel.wheel1, reference_foils[indx]['fw1']) else: yield from mv(foil_wheel.wheel1, 0) yield from mv(foil_wheel.wheel2, 0)
def move(): grp = _short_uid('set') yield Msg('checkpoint') yield Msg('set', motor, step, group=grp) yield Msg('wait', None, group=grp) yield from mv(attn_shutter, 'Retract')
def spiral_continuous(detectors, x_motor, y_motor, x_start, y_start, npts, probe_size, overlap=0.8, *, tilt=0.0, per_step=None, md=None): '''Continuously increasing radius spiral scan. centered around (x_start, y_start) which is generic regarding motors and detectors. Parameters ---------- x_motor : object any 'setable' object (motor, etc.) y_motor : object any 'setable' object (motor, etc.) x_start : float x center y_start : float y center npts : integer number of points probe_size : float radius of probe in units of motors overlap : float fraction of probe overlap ---------------------------------------------------------------- Not implemented yet: tilt : float, optional (not yet enabled) Tilt angle in radians, default = 0.0 per_step : callable, optional hook for cutomizing action of inner loop (messages per step) See docstring of bluesky.plans.one_nd_step (the default) for details. ---------------------------------------------------------------- md : dict, optional metadata ''' # #TODO clean up pattern args and _md. Do not remove motors from _md. pattern_args = dict(x_motor=x_motor, y_motor=y_motor, x_start=x_start, y_start=y_start, npts=npts, probe_size=probe_size, overlap=overlap, tilt=tilt) # cyc = plan_patterns.spiral(**pattern_args)# - leftover from spiral. bxs = [] bzs = [] bx_init = x_start bz_init = y_start for i in range(0, npts): R = np.sqrt(i/np.pi) # this is to get the first point to be the center T = 2*i/(R+0.0000001) bx = (overlap*probe_size*R * np.cos(T)) + bx_init bz = (overlap*probe_size*R * np.sin(T)) + bz_init bxs.append(bx) bzs.append(bz) motor_vals = [bxs, bzs] x_range = max(motor_vals[0]) - min(motor_vals[0]) y_range = max(motor_vals[1]) - min(motor_vals[1]) motor_pos = cycler(x_motor, bxs) + cycler(y_motor, bzs) # Before including pattern_args in metadata, replace objects with reprs. pattern_args['x_motor'] = repr(x_motor) pattern_args['y_motor'] = repr(y_motor) _md = {'plan_args': {'detectors': list(map(repr, detectors)), 'x_motor': repr(x_motor), 'y_motor': repr(y_motor), 'x_start': x_start, 'y_start': y_start, 'overlap': overlap, # 'nth': nth, 'tilt': tilt, 'per_step': repr(per_step)}, 'extents': tuple([[x_start - x_range, x_start + x_range], [y_start - y_range, y_start + y_range]]), 'plan_name': 'spiral_continuous', 'plan_pattern': 'spiral_continuous', 'plan_pattern_args': pattern_args, # - leftover from spiral. # 'plan_pattern_module': plan_patterns.__name__, 'hints': {}} try: dimensions = [(x_motor.hints['fields'], 'primary'), (y_motor.hints['fields'], 'primary')] except (AttributeError, KeyError): pass else: _md['hints'].update({'dimensions': dimensions}) _md.update(md or {}) cont_sp_plan = bp.scan_nd(detectors, motor_pos, per_step=per_step, md=_md) reset_plan = bps.mv(x_motor, x_start, y_motor, y_start) def plan_steps(): yield from cont_sp_plan print('Moving back to first point position.') yield from reset_plan try: return (yield from plan_steps()) except Exception: # Catch the exception long enough to clean up. print('Moving back to first point position.') yield from reset_plan raise
def EfixQ(detectors, E_start, E_end, steps, E_shift=0, *, per_step=None, md=None): '''Fixed Q energy scan based on an orientation matrix for CSX-1 mono (pgm.energy) If using higher order harmonic of mono, adjust H K L, not energy. Parameters ---------- E_start : float starting energy [eV] E_stop : float stoping energy [eV] steps : integer number of points E_shift : float shift in energy calibration relative to orientation matrix (i.e, ) per_step : callable, optional hook for cutomizing action of inner loop (messages per step) See docstring of bluesky.plans.one_nd_step (the default) for details. md : dict, optional metadata ''' x_motor = pgm.energy # This is CSX-1's mono motor name for energy x_start = E_start pattern_args = dict(x_motor=x_motor, x_start=E_start, steps=steps, E_shift=E_shift) E_init = x_motor.readback.value tardis.calc.energy = (x_motor.setpoint.value + E_shift)/10000 h_init = tardis.position.h k_init = tardis.position.k l_init = tardis.position.l delta_init = delta.user_readback.value theta_init = theta.user_readback.value gamma_init = gamma.user_readback.value deltas = [] thetas = [] gammas = [] # TODO no plus one, use npts as arugument. E_vals = np.linspace(E_start, E_end, steps+1) x_range = max(E_vals) - min(E_vals) for E_val in E_vals: tardis.calc.energy = (E_val + E_shift)/10000 angles = tardis.forward([h_init, k_init, l_init]) deltas.append(angles.delta) thetas.append(angles.theta) gammas.append(angles.gamma) motor_pos = (cycler(delta, deltas) + cycler(theta, thetas) + cycler(gamma, gammas) + cycler(x_motor, E_vals)) # TODO decide to include diffractometer motors below? # Before including pattern_args in metadata, replace objects with reprs. pattern_args['x_motor'] = repr(x_motor) _md = {'plan_args': {'detectors': list(map(repr, detectors)), 'x_motor': repr(x_motor), 'x_start': x_start, 'x_range': x_range, 'per_step': repr(per_step)}, 'extents': tuple([[x_start - x_range, x_start + x_range]]), 'plan_name': 'EfixQ', 'plan_pattern': 'scan', 'plan_pattern_args': pattern_args, # this is broken TODO do we need this # 'plan_pattern_module': plan_patterns.__name__, 'hints': {}} try: dimensions = [(x_motor.hints['fields'], 'primary')] # print(dimensions) except (AttributeError, KeyError): pass else: _md['hints'].update({'dimensions': dimensions}) _md.update(md or {}) # this works without subs, Escan_plan = scan_nd(detectors, motor_pos, per_step=per_step, md=_md) reset_plan = bps.mv(x_motor, E_init, delta, delta_init, theta, theta_init, gamma, gamma_init) # yield from print('Starting an Escan fix Q at ({:.4f}, {:.4f}, {:.4f})'.format(h_init,k_init,l_init)) def plan_steps(): print('Starting fixed Q energy scan for ' '({:.4f}, {:.4f}, {:.4f}\n\n)'.format( tardis.h.position, tardis.k.position, tardis.l.position)) yield from Escan_plan print('\nMoving back to motor positions immediately before scan\n') yield from reset_plan yield from bps.sleep(1) tardis.calc.energy = (pgm.energy.readback.value + E_shift)/10000 print('Returned to Q at ({:.4f}, {:.4f}, {:.4f})'.format( tardis.h.position, tardis.k.position, tardis.l.position)) try: return (yield from plan_steps()) except Exception: print('\nMoving back to motor positions immediately before scan\n') yield from reset_plan yield from bps.sleep(1) tardis.calc.energy = (pgm.energy.readback.value + E_shift)/10000 print('Returned to Q at ({:.4f}, {:.4f}, {:.4f})'.format( tardis.h.position, tardis.k.position, tardis.l.position)) raise
def EfixQapprox(detectors, E_start, E_end, npts, E_shift=0, *, per_step=None, md=None): '''Approximate fixed Q energy scan based on delta, theta positions for CSX-1 mono (pgm.energy) Parameters ---------- E_start : float starting energy [eV] E_stop : float stoping energy [eV] npts : integer number of points E_shift : float shift in energy calibration relative to orientation matrix (i.e, ) - not used currently per_step : callable, optional hook for cutomizing action of inner loop (messages per step) See docstring of bluesky.plans.one_nd_step (the default) for details. md : dict, optional metadata ''' x_motor = pgm.energy # This is CSX-1's mono motor name for energy x_start = E_start pattern_args = dict(x_motor=x_motor, x_start=E_start, npts=npts) deltas = [] thetas = [] deltaCALC = 0 thetaCALC = 0 E_init = x_motor.readback.value lam_init = 12398/E_init delta_init = delta.user_readback.value theta_init = theta.user_readback.value dsp = lam_init/(2*np.sin(np.radians(delta_init/2))) theta_offset = delta_init/2 - theta_init E_vals = np.linspace(E_start, E_end, npts) # lam_vals = np.linspace(12398/E_start, 12398/E_end, npts) x_range = max(E_vals) - min(E_vals) for lam_val in lam_vals: deltaCALC = np.degrees(np.arcsin(lam_val/2/dsp))*2 thetaCALC = deltaCALC/2 - theta_offset deltas.append(deltaCALC) thetas.append(thetaCALC) motor_pos = (cycler(delta, deltas) + cycler(theta, thetas) + cycler(x_motor, E_vals)) # TODO decide to include diffractometer motors below? # Before including pattern_args in metadata, replace objects with reprs. pattern_args['x_motor'] = repr(x_motor) _md = {'plan_args': {'detectors': list(map(repr, detectors)), 'x_motor': repr(x_motor), 'x_start': x_start, 'x_range': x_range, 'per_step': repr(per_step)}, 'extents': tuple([[x_start - x_range, x_start + x_range]]), 'plan_name': 'EfixQapprox', 'plan_pattern': 'scan', 'plan_pattern_args': pattern_args, # this is broken TODO do we need this? # 'plan_pattern_module': plan_patterns.__name__, 'hints': {}} try: dimensions = [(x_motor.hints['fields'], 'primary')] # print(dimensions) except (AttributeError, KeyError): pass else: _md['hints'].update({'dimensions': dimensions}) _md.update(md or {}) # this works without subs, Escan_plan = scan_nd(detectors, motor_pos, per_step=per_step, md=_md) reset_plan = bps.mv(x_motor, E_init, delta, delta_init, theta, theta_init) # Check for suitable syntax.. # yield from print('Starting an Escan fix Q at ({:.4f}, {:.4f}, {:.4f})'.format(h_init,k_init,l_init)) def plan_steps(): yield from Escan_plan print('/nMoving back to motor positions immediately before scan/n') yield from reset_plan try: return (yield from plan_steps()) except Exception: print('/nMoving back to motor positions immediately before scan/n') yield from reset_plan raise
def ct_dark(numim=None, detectors=None, gain_std=0): """Collect dark images for fccd and add metadata tag for dark and gain. The pre-count shutter & gain states preserved. Parameters ----------- numim: int Number of images to be measured. If different from current setting, the number of images will revert back to the original after the scan is complete. detectors: list List of detectors to be recorded. Default = [fccd] gain_std: int List of detectors to be recorded. Default = 0 (which is 'Auto' or x8, the most sensitive gain) Returns ------- """ if detectors is None: detectors = [fccd] try: # TODO figureout kwargs and self to mkae up to line 44 a # single definition oldnumim = fccd.cam.num_images.value # Printing info print( '\nStarting procedure to acquire darks ' '{:3.3}Hz or {:3.3f}s.\n'.format( 1/fccd.cam.acquire_time.value, fccd.cam.acquire_time.value)) print('\tCurrent number of images = {}.\n'.format( fccd.cam.num_images.value)) yield from bps.sleep(.3) if numim is not None: print('\tSetting to {} images.\n'.format(numim)) yield from bps.abs_set(fccd.cam.num_images, numim, wait=True) dark_shutter_state = inout.status.value dark_sh_dict = {'Inserted': 'In', 'Not Inserted': 'Out'} gain_state = fccd.cam.fcric_gain.value gain_bit_dict = {0: 'auto', 1: 'x2', 2: 'x1'} yield from bps.mv(inout, 'In') # This has to be 2 until we can selectively remove dark images # get_fastccd_images() yield from bps.sleep(fccd.cam.acquire_period.value*2.01) # SET TO 1 TO ARM FOR NEXT EVENT so that the FastCCD1 is # already bkg subt yield from bps.mv(fccd.fccd1.capture_bgnd, 1) # take darks yield from _ct_dark(detectors, gain_std, gain_bit_dict) # Putting things back yield from _ct_dark_cleanup(oldnumim, gain_bit_dict, gain_state, dark_sh_dict, dark_shutter_state) except Exception: yield from _ct_dark_cleanup(oldnumim, gain_bit_dict, gain_state, dark_sh_dict, dark_shutter_state) raise except KeyboardInterrupt: yield from _ct_dark_cleanup(oldnumim, gain_bit_dict, gain_state, dark_sh_dict, dark_shutter_state) raise