def MED(init_gas, other_gas, minT, maxT, num_steps, num_steady, num_trans, num_loops=2): """ 1. Start flowing the initial gas. 2. Scan the temperature from minT to maxT in `num_steps` evenly-spaced steps. 3. Hold temperature at maxT and take `num_steady` images. 4. Repeat (2) and (3) `num_loops` times. 5. Switch the gas to `other_gas` and take `num_trans` acquisitions. 6. Switch it back and take another `num_trans` acquisitions. Example ------- Set the gasses. They can be in any other, nothing to do with the order they are used in the plan. >>> gas.gas_list = ['O2', 'CO2'] Optionally, preview the plan. >>> print_summary(MED('O2', 'C02', 200, 300, 21, 20, 60)) Execute it. >>> RE(MED('O2', 'C02', 200, 300, 21, 20, 60)) """ # Step 1 yield from abs_set(gas, init_gas) # Steps 2 and 3 in a loop. for _ in range(num_loops): yield from subs_wrapper(scan([pe1, gas.current_gas], eurotherm, minT, maxT, num_steps), LiveTable([eurotherm, gas.current_gas])) yield from subs_wrapper(count([pe1], num_steady), LiveTable([])) # Step 4 yield from abs_set(gas, other_gas) yield from subs_wrapper(count([pe1], num_steady), LiveTable([])) # Step 6 yield from abs_set(gas, init_gas) yield from subs_wrapper(count([pe1], num_steady), LiveTable([]))
def count_with_calib(detectors: list, num: int = 1, delay: float = None, *, calibration_md: dict = None, md: dict = None) -> typing.Generator: """ Take one or more readings from detectors with shutter control and calibration metadata injection. Parameters ---------- detectors : list list of 'readable' objects num : integer, optional number of readings to take; default is 1 If None, capture data until canceled delay : iterable or scalar, optional Time delay in seconds between successive readings; default is 0. calibration_md : The calibration data in a dictionary. If not applied, the function is a normal `bluesky.plans.count`. md : dict, optional metadata Notes ----- If ``delay`` is an iterable, it must have at least ``num - 1`` entries or the plan will raise a ``ValueError`` during iteration. """ if md is None: md = dict() if calibration_md is not None: md["calibration_md"] = calibration_md def _per_shot(_detectors): yield from open_shutter_stub() yield from bps.one_shot(_detectors) yield from close_shutter_stub() return prev_state = glbl["auto_load_calib"] glbl["auto_load_calib"] = False try: plan = bp.count(detectors, num, delay, md=md, per_shot=_per_shot) bpp.subs_wrapper(plan, LiveTable(detectors)) sts = yield from plan except Exception as error: glbl["auto_load_calib"] = prev_state raise error glbl["auto_load_calib"] = prev_state return sts
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 simple_ct(dets, exposure, *, md=None): """A minimal wrapper around count that adjusts exposure time.""" md = md or {} # setting up area_detector (ad, ) = (d for d in dets if hasattr(d, "cam")) (num_frame, acq_time, computed_exposure) = yield from configure_area_det(ad, exposure) sp = { "time_per_frame": acq_time, "num_frames": num_frame, "requested_exposure": exposure, "computed_exposure": computed_exposure, "type": "ct", "uid": str(uuid.uuid4()), "plan_name": "ct", } # update md _md = {"sp": sp, **{f"sp_{k}": v for k, v in sp.items()}} _md.update(md) plan = bp.count(dets, md=_md) plan = bpp.subs_wrapper(plan, LiveTable([])) return (yield from plan)
def learner_callback_plan(dets, motors, learner, goal, **kwargs): queue = Queue() callback = AdaptiveCallback(learner, goal, queue) return (yield from bpp.subs_wrapper(intra_plan_learner(dets, motors, queue, **kwargs), callback))
def escan(start, stop, num, md=None): """ Scan the mono_energy while reading the scaler. Parameters ---------- start : number stop : number num : integer number of data points (i.e. number of strides + 1) md : dictionary, optional """ dets = [sclr] motor = mono.energy cols = ['I0', 'fbratio', 'It', 'If_tot'] x = 'mono_energy' fig, axes = plt.subplots(2, sharex=True) plan = bp.scan(dets, motor, start, stop, num, md=md) plan2 = bpp.subs_wrapper(plan, [ LiveTable(cols), LivePlot('If_tot', x, ax=axes[0]), LivePlot('I0', x, ax=axes[1]) ]) yield from plan2
def cryo_test(numpt=5, delay_time=2, preamp_acqtime=0.5): det = [ current_preamp, cryo_v19, cryo_lt19, cryo_pt1, hdcm_Si111_1stXtalrtd, hdcm_Si111_2ndXtal_rtd, hdcm_1stXtal_ThermStab_rtd, hdcm_ln2out_rtd, hdcm_water_rtd, dBPM_h, dBPM_v, dBPM_t, dBPM_i, dBPM_o, dBPM_b ] current_preamp.exp_time.put(preamp_acqtime) livecallbacks = [] livetableitem = [ current_preamp.ch0, current_preamp.ch2, cryo_v19, cryo_lt19, cryo_pt1, hdcm_Si111_1stXtalrtd, hdcm_Si111_2ndXtal_rtd, hdcm_1stXtal_ThermStab_rtd, hdcm_ln2out_rtd, hdcm_water_rtd, dBPM_h, dBPM_v, dBPM_t, dBPM_i, dBPM_o, dBPM_b ] livecallbacks.append(LiveTable(livetableitem)) for det_item in livetableitem: liveploty = det_item liveplotfig = plt.figure(det_item.name) livecallbacks.append(LivePlot(liveploty, fig=liveplotfig)) yield from subs_wrapper(count(det, num=numpt, delay=delay_time), livecallbacks)
def take_dark(): """a plan for taking a single dark frame""" print("INFO: closing shutter...") yield from close_shutter_stub() print("INFO: taking dark frame....") # upto this stage, area_det has been configured to so exposure time is # correct area_det = xpd_configuration["area_det"] acq_time = area_det.cam.acquire_time.get() if hasattr(area_det, 'images_per_set'): num_frame = area_det.images_per_set.get() else: num_frame = 1 computed_exposure = acq_time * num_frame # update md _md = { "sp_time_per_frame": acq_time, "sp_num_frames": num_frame, "sp_computed_exposure": computed_exposure, "sp_type": "ct", "sp_plan_name": "dark_{}".format(computed_exposure), "dark_frame": True, } c = bp.count([area_det], md=_md) yield from bpp.subs_wrapper(c, {"stop": [_update_dark_dict_list]}) # TODO: remove this, since it kinda depends on what happens next? print("opening shutter...")
def take_dark(): """a plan for taking a single dark frame""" print("INFO: closing shutter...") yield from bps.abs_set(xpd_configuration.get("shutter"), XPD_SHUTTER_CONF["close"], wait=True) print("INFO: taking dark frame....") # upto this stage, area_det has been configured to so exposure time is # correct area_det = xpd_configuration["area_det"] acq_time = area_det.cam.acquire_time.get() num_frame = area_det.images_per_set.get() computed_exposure = acq_time * num_frame # update md _md = { "sp_time_per_frame": acq_time, "sp_num_frames": num_frame, "sp_computed_exposure": computed_exposure, "sp_type": "ct", "sp_plan_name": "dark_{}".format(computed_exposure), "dark_frame": True, } c = bp.count([area_det], md=_md) yield from bpp.subs_wrapper(c, {"stop": [_update_dark_dict_list]}) print("opening shutter...")
def my_plan(): motor = hw.motor det = hw.det motor.delay = 1 plan = bp.scan([det], motor, -5, 5, 25) plan = subs_wrapper(bp.scan([det], motor, -5, 5, 25), LivePlot(det.name, motor.name)) return (yield from plan)
def ct(sample, exposure): """ Capture how many exposures are needed to get a total exposure of the given value, and sum those into one file before saving. """ pe1c.images_per_set.put(1) pe1c.number_of_sets.put(1) plan = subs_wrapper(count([pe1c], num=1), LiveTable([])) # plan = robot_wrapper(plan, sample) yield from plan
def tomo_xrf_proj_realmotor(xcen, zcen, hstepsize, hnumstep, ycen, ystepsize, ynumstep, dets=[]): ''' collect an XRF 'projection' map at the current angle zcen should be defined as the position when the sample is in focus at zero degree; if it is not given, the program should take the current z position ''' theta = tomo_stage.theta.position #horizontal axes x_motor = tomo_stage.finex_top z_motor = tomo_stage.finez_top #vertical axis y_motor = tomo_stage.finey_top #stepsize setup xstepsize = hstepsize * numpy.cos(numpy.deg2rad(theta)) zstepsize = hstepsize * numpy.sin(numpy.deg2rad(theta)) #start and end point setup xstart = xcen - xstepsize * hnumstep / 2 xstop = xcen + xstepsize * hnumstep / 2 zstart = zcen - zstepsize * hnumstep / 2 zstop = zcen + zstepsize * hnumstep / 2 ystart = ycen - ystepsize * ynumstep / 2 ystop = ycen + ystepsize * ynumstep / 2 xlist = numpy.linspace(xstart, xstop, hnumstep + 1) #some theta dependent function zlist = numpy.linspace(zstart, zstop, hnumstep + 1) ylist = numpy.linspace(ystart, ystop, ynumstep + 1) xz_cycler = cycler(x_motor, xlist) + cycler(z_motor, zlist) yxz_cycler = cycler(y_motor, ylist) * xz_cycler # The scan_nd plan expects a list of detectors and a cycler. plan = scan_nd(dets, yxz_cycler) # Optionally, add subscritpions. #TO-DO: need to figure out how to add LiveRaster with the new x/z axis plan = subs_wrapper(plan, [LiveTable([x_motor, y_motor, z_motor])]) # LiveMesh(...)] scaninfo = yield from plan return scaninfo
def count_dets(_dets, _full_md): _count_plan = bp.count(_dets, md=_full_md) _count_plan = bpp.subs_wrapper(_count_plan, LiveTable(_dets)) _count_plan = bpp.finalize_wrapper( _count_plan, bps.abs_set(xpd_configuration['shutter'], XPD_SHUTTER_CONF['close'], wait=True)) yield from bps.abs_set(xpd_configuration['shutter'], XPD_SHUTTER_CONF['open'], wait=True) yield from _count_plan
def tseries(sample, exposure, num): """ Capture how ever many exposures are needed to get a total exposure of the given value, and divide those into files of 'num' exposures each, summed. """ if pe1c.cam.acquire_time.get() != 0.1: raise RuntimeError("We expect pe1c.cam.acquire_time to be 0.1") pe1c.images_per_set.put(num) pe1c.number_of_sets.put(exposure // num) plan = subs_wrapper(count([pe1c], num=1), LiveTable([])) i # plan = robot_wrapper(plan, sample) yield from plan
def cls_plan(): current_settings = {} for key, val in kwargs.items(): current_settings[key] = getattr(self, key) setattr(self, key, val) try: plan = self._gen() plan = bpp.subs_wrapper(plan, subs) plan = bpp.stage_wrapper(plan, flyers) plan = bpp.fly_during_wrapper(plan, flyers) return (yield from plan) finally: for key, val in current_settings.items(): setattr(self, key, val)
def ct(dets, exposure): """ Take one reading from area detector with given exposure time Parameters ---------- dets : list list of 'readable' objects. default to area detector linked to xpdAcq. exposure : float total time of exposrue in seconds Notes ----- area detector being triggered will always be the one configured in global state. To find out which these are, please using following commands: >>> xpd_configuration['area_det'] to see which device is being linked """ pe1c, = dets md = {} # setting up area_detector (num_frame, acq_time, computed_exposure) = yield from _configure_area_det( exposure ) area_det = xpd_configuration["area_det"] # update md _md = ChainMap( md, { "sp_time_per_frame": acq_time, "sp_num_frames": num_frame, "sp_requested_exposure": exposure, "sp_computed_exposure": computed_exposure, "sp_type": "ct", "sp_uid": str(uuid.uuid4()), "sp_plan_name": "ct", }, ) plan = bp.count([area_det], md=_md) plan = bpp.subs_wrapper(plan, LiveTable([])) yield from plan
def check_tth(): '''Align the spectrometer rotation angle''' yield from bps.mv(geo.det_mode, 1) yield from bps.mv(abs2, 6) yield from mabt(0, 0, 0) tmp1 = geo.tth.position print('resetting tth') yield from bps.mv(sh, -1) yield from bps.mv(shutter, 1) # open shutter local_peaks = PeakStats(tth.user_readback.name, quadem.current3.mean_value.name) #yield from bp.rel_scan([quadem],tth,-0.1,0.1,21) yield from bpp.subs_wrapper(bp.rel_scan([quadem], tth, -0.1, 0.1, 21), local_peaks) tmp2 = local_peaks.cen #get the height for roi2 of quadem with a max intens yield from bps.mv(tth, tmp2) yield from set_tth(tmp1) yield from bps.mv(shutter, 0) # close shutter
def check_astth(detector=lambda_det): '''Align the detector arm rotation angle''' yield from bps.mv(geo.det_mode, 1) yield from bps.mv(abs2, 6) yield from mabt(0.0, 0.0, 0) tmp1 = geo.astth.position yield from bps.mvr(sh, -1) print('setting astth') yield from bps.mv(shutter, 1) # open shutter # yield from bp.rel_scan([detector],astth,-0.1,0.1,21) # tmp2=peaks.cen['%s_stats2_total'%detector.name] local_peaks = PeakStats(astth.user_readback.name, '%s_stats2_total' % detector.name) yield from bpp.subs_wrapper(bp.rel_scan([detector], astth, -0.1, 0.1, 21), local_peaks) tmp2 = local_peaks.cen #get the height for roi2 of detector.name with max intens yield from bps.mv(astth, tmp2) yield from bps.mv(shutter, 0) # close shutter yield from set_astth(tmp1)
def test_interrupted_with_callbacks(RE, int_meth, stop_num, msg_num): docs = defaultdict(list) def collector_cb(name, doc): nonlocal docs docs[name].append(doc) RE.msg_hook = MsgCollector() with pytest.raises(RunEngineInterrupted): RE(subs_wrapper(run_wrapper(pause()), {"all": collector_cb})) getattr(RE, int_meth)() assert len(docs["start"]) == 1 assert len(docs["event"]) == 0 assert len(docs["descriptor"]) == 0 assert len(docs["stop"]) == stop_num assert len(RE.msg_hook.msgs) == msg_num
def check_ih(): '''Align the Align the spectrometer stage height ''' yield from bps.mv(geo.det_mode, 1) #move lamda detector in ? yield from bps.mv(abs2, 6) #move the second absorber in yield from mabt(0, 0, 0) # don't understand???, yield from bps.mv(sh, -1) # move the Sample vertical translation to -1 yield from bps.mv(shutter, 1) # open shutter print('resetting ih') #yield from bp.rel_scan([quadem],ih,-0.15,0.15,16) #scan the quadem detector against XtalDfl-height #tmp=peaks.cen['quadem_current3_mean_value'] #get the height for roi2 of quadem with a max intensity local_peaks = PeakStats(ih.user_readback.name, quadem.current3.mean_value.name) yield from bpp.subs_wrapper(bp.rel_scan([quadem], ih, -0.15, 0.15, 16), local_peaks) tmp = local_peaks.cen #get the height for roi2 of quadem with a max intens yield from bps.mv(ih, tmp) #move the XtalDfl to this height yield from set_ih(0) #set this height as 0 yield from bps.mv(shutter, 0) # close shutter
def config_det_and_count(motors: List[object], sample_md: dict, exposure: float): """ Take one reading from area detector with given exposure time and motors. Save the motor reading results in the start document. Parameters ---------- motors : List[float] A list of readable motors. sample_md The metadata of the sample. exposure The exposure time in seconds. Yields ------- Message to configure the detector and run the scan. """ # setting up area_detector _md = {} num_frame, acq_time, computed_exposure = yield from _configure_area_det(exposure) area_det = xpd_configuration["area_det"] # update md _md.update(**sample_md) plan_md = { "sp_time_per_frame": acq_time, "sp_num_frames": num_frame, "sp_requested_exposure": exposure, "sp_computed_exposure": computed_exposure, "sp_type": "cryostat", "sp_uid": str(uuid.uuid4()), "sp_plan_name": "cryostat" } _md.update(**plan_md) motor_md = {motor.name: dict(motor.read()) for motor in motors} _md.update(**motor_md) # yield plan dets = [area_det] + motors plan = count(dets, md=_md) plan = subs_wrapper(plan, LiveTable([])) yield from plan
def check_sh_coarse(value=0, detector=lambda_det): ''' Aligh the sample height ''' yield from bps.mv(geo.det_mode, 1) yield from bps.mv(abs2, 6) yield from mabt(value, value, 0) tmp1 = geo.sh.position #Msg('reset_settle_time', sh.settle_time, 2) print('Start the height scan before GID') # yield from bp.rel_scan([detector],sh,-1,1,21,per_step=shutter_flash_scan) # tmp2=peaks.cen['%s_stats2_total'%detector.name] local_peaks = PeakStats(sh.user_readback.name, '%s_stats2_total' % detector.name) yield from bpp.subs_wrapper( bp.rel_scan([detector], sh, -1, 1, 21, per_step=shutter_flash_scan), local_peaks) tmp2 = local_peaks.cen #get the height for roi2 of detector.name with max intens ) yield from bps.mv(sh, tmp2) yield from set_sh(tmp1) Msg('reset_settle_time', sh.settle_time, 0)
def dummy_edge_scan(sample_name, edge, md=None): from bluesky.examples import det, motor, det2 if md is None: md = {} local_md = {'plan_name': 'edge_ascan'} md = ChainMap(md, local_md) e_scan_params = EDGE_MAP[edge] # TODO configure the vortex sample_props = SAMPLE_MAP[sample_name] # sample_props = list(sample_manager.find(sample_name))[0] local_md.update(sample_props) lp_list = [] for n in ['det', 'det2']: fig = plt.figure(edge + ': ' + n) lp = bs.callbacks.LivePlot(n, 'motor', fig=fig) lp_list.append(lp) yield from bpp.subs_wrapper(bp.relative_scan([det, det2], motor, -5, 5, 15, md=md), lp_list)
def test_subs(): def cb(name, doc): pass def plan(*args, **kwargs): # check that args to plan are passed through yield from [Msg('null', None, *args, **kwargs)] processed_plan = list(subs_wrapper(plan('test_arg', test_kwarg='val'), {'all': cb})) expected = [Msg('subscribe', None, cb, 'all'), Msg('null', None, 'test_arg', test_kwarg='val'), Msg('unsubscribe', token=None)] assert processed_plan == expected processed_plan = list(subs_decorator({'all': cb})(plan)('test_arg', test_kwarg='val')) assert processed_plan == expected
def test_evil_table_names(RE): from ophyd import Signal sigs = [ Signal(value=0, name="a:b"), Signal(value=0, name="a,b"), Signal(value=0, name="a'b"), Signal(value=0, name="🐍"), ] table = LiveTable([s.name for s in sigs], min_width=5, extra_pad=2, separator_lines=False) with _print_redirect() as fout: print() # get a blank line in camptured output RE(bpp.subs_wrapper(bp.count(sigs, num=2), table)) reference = """ +------------+--------------+--------+--------+--------+--------+ | seq_num | time | a:b | a,b | a'b | 🐍 | +------------+--------------+--------+--------+--------+--------+ | 1 | 12:47:09.7 | 0 | 0 | 0 | 0 | | 2 | 12:47:09.7 | 0 | 0 | 0 | 0 | +------------+--------------+--------+--------+--------+--------+""" _compare_tables(fout, reference)
def check_sh_fine(value=0.05, detector=lambda_det): yield from bps.mv(geo.det_mode, 1) yield from bps.mv(abs2, 5) yield from mabt(value, value, 0) tmp1 = geo.sh.position print('Start the height scan before GID') # Msg('reset_settle_time', sh.settle_time, value) # yield from bp.rel_scan([detector],sh,-0.1,0.1,21,per_step=shutter_flash_scan) # tmp2=peaks.cen['%s_stats2_total'%detector.name] local_peaks = PeakStats(sh.user_readback.name, '%s_stats2_total' % detector.name) yield from bpp.subs_wrapper( bp.rel_scan([detector], sh, -0.15, 0.15, 16, per_step=shutter_flash_scan), local_peaks) print("at #1") tmp2 = local_peaks.cen #get the height for roi2 of detector.name with max intens print("at #2") yield from bps.mv(sh, tmp2) yield from set_sh(tmp1) Msg('reset_settle_time', sh.settle_time, 0)
def edge_ascan(sample_name, edge, md=None): '''Run a multi-edge nexafs scan for single sample and edge Parameters ---------- sample_name : str Base sample name sample_position : float Postion of sample on manipulator arm edge : str Key into EDGE_MAP ''' if md is None: md = {} local_md = {'plan_name': 'edge_ascan'} local_md['edge'] = edge md = ChainMap(md, local_md) e_scan_params = EDGE_MAP[edge] # TODO configure the vortex det_settings = DET_SETTINGS[edge] sample_props = SAMPLE_MAP[sample_name] # sample_props = list(sample_manager.find(name=sample_name)) local_md.update(sample_props) # init_group = 'ME_INIT_' + str(uuid.uuid4()) yield from bps.abs_set(ioxas_x, sample_props['pos'], wait=True) # yield from bps.mov(appes_x, sample_props['pos_x']) # yield from bps.mov(appes_y, sample_props['pos_y']) yield from bps.abs_set(feedback, 0, wait=True) yield from bps.abs_set(pgm_energy, e_scan_params['start'], wait=True) yield from bps.abs_set(epu1table, e_scan_params['epu_table'], wait=True) yield from bps.abs_set(epu1offset, e_scan_params['epu1offset'], wait=True) yield from bps.sleep(15) yield from bps.abs_set(m1b1_fp, 100) yield from bps.abs_set(feedback, 1, wait=True) yield from bps.sleep(5) yield from bps.abs_set(feedback, 0, wait=True) yield from bps.abs_set(vortex_x, det_settings['vortex_pos'], wait=True) yield from bps.abs_set(sample_sclr_gain, det_settings['samplegain'], wait=True) yield from bps.abs_set(sample_sclr_decade, det_settings['sampledecade'], wait=True) yield from bps.abs_set(aumesh_sclr_gain, det_settings['aumeshgain'], wait=True) yield from bps.abs_set(aumesh_sclr_decade, det_settings['aumeshdecade'], wait=True) yield from bps.abs_set(sclr_time, det_settings['sclr_time'], wait=True) # yield from open_all_valves(all_valves) # yield from bp.wait(init_group) # TODO make this an ohypd obj!!!!!! #caput('XF:23IDA-PPS:2{PSh}Cmd:Opn-Cmd',1) # yield from bp.sleep(2) # TODO make this an ohypd obj!!!!!! # TODO ask stuart #caput('XF:23IDA-OP:2{Mir:1A-Ax:FPit}Mtr_POS_SP',50) yield from bps.sleep(5) # yield from bps.configure(vortex, VORTEX_SETTINGS[edge]) # yield from bps.sleep(2) yield from bps.abs_set(vortex.mca.rois.roi4.lo_chan, det_settings['vortex_low'], wait=True) yield from bps.abs_set(vortex.mca.rois.roi4.hi_chan, det_settings['vortex_high'], wait=True) yield from bps.abs_set(vortex.mca.preset_real_time, det_settings['vortex_time'], wait=True) # lp_list = [] # for n in ['sclr_ch4', 'vortex_mca_rois_roi4_count']: # fig = plt.figure(edge + ': ' + n) # lp = bs.callbacks.LivePlot(n, 'pgm_energy_readback', fig=fig) # lp_list.append(lp) # class norm_plot(bs.callbacks.LivePlot): # def event(self,doc): # try: # doc.data['norm_intensity'] = doc.data['sclr_ch4']/doc.data['sclr_ch3'] # except KeyError: # pass # super().event(doc) # for n in ['sclr_ch4']: # fig = plt.figure(edge + ': ' + n) # lp = bs.callbacks.LivePlot(n, 'pgm_energy_readback', fig=fig) # lp = norm_plot('norm_intensity', 'pgm_energy_readback', fig=fig) # lp_list.append(lp) dets = [sclr, vortex, norm_ch4, ring_curr] for channel in ['mca.rois.roi2.count','mca.rois.roi3.count','mca.rois.roi4.count']: getattr(vortex, channel).kind = 'hinted' for channel in ['mca.rois.roi2.count','mca.rois.roi3.count']: getattr(vortex, channel).kind = 'normal' for channel in ['channels.chan3','channels.chan4']: getattr(sclr, channel).kind = 'hinted' for channel in ['channels.chan2']: getattr(sclr, channel).kind = 'normal' scan_kwargs = {'start': e_scan_params['stop'], 'stop': e_scan_params['start'], 'velocity': e_scan_params['velocity'], 'deadband': e_scan_params['deadband'], 'md': md} ret = [] for j in range(e_scan_params['scan_count']): tmp_pos = sample_props['pos'] + (j-((e_scan_params['scan_count']-1)/2))*e_scan_params['intervals'] # yield from bps.mov(appes_y, tmp_pos) yield from bps.mov(ioxas_x, tmp_pos) yield from bps.abs_set(pgm_energy, e_scan_params['stop'], wait=True) yield from open_all_valves(all_valves) res = yield from bpp.subs_wrapper(E_ramp(dets, **scan_kwargs), {'stop': save_csv}) yield from bps.abs_set(valve_diag3_close, 1, wait=True) yield from bps.abs_set(valve_mir3_close, 1, wait=True) yield from bps.sleep(5) if res is None: res = [] ret.extend(res) if not ret: return ret # hdr = db[ret[0]] # redo_count = how_many_more_times_to_take_data(hdr) # for j in range(redo_count): # res = yield from bpp.subs_wrapper(ascan(*scan_args, md=md), lp) # ret.extend(res) # new_count_time = compute_new_count_time(hdr, old_count_time) # if new_count_time != old_count_time: # yield from bps.configure(vortex, {'count_time': new_count_time}) # res = yield from bpp.subs_wrapper(ascan(*scan_args, md=md), lp) # ret.extend(res) return ret
def custom_subs(plan): yield from subs_wrapper(plan, my_sub)
def xanes_plan(erange=[], estep=[], harmonic=1, correct_c2_x=True, correct_c1_r=False, detune=None, acqtime=1., roinum=1, delaytime=0.00, struck=True, fluor=True, samplename='', filename='', shutter=True, align=False, align_at=None, per_step=None): ''' erange (list of floats): energy ranges for XANES in eV, e.g. erange = [7112-50, 7112-20, 7112+50, 7112+120] estep (list of floats): energy step size for each energy range in eV, e.g. estep = [2, 1, 5] harmonic (odd integer): when set to 1, use the highest harmonic achievable automatically. when set to an odd integer, force the XANES scan to use that harmonic correct_c2_x (boolean or float): when True, automatically correct the c2x when False, c2x will not be moved during the XANES scan correct_c1_r (False or float): when False, c1r will not be moved during a XANES scan when set to a float, c1r will be set to that value before a XANES scan but will remain the same during the whole scan detune: add this value to the gap of the undulator to reduce flux [mm] acqtime (float): acqusition time to be set for both xspress3 and preamplifier roinum: select the roi to be used to calculate the XANES spectrum delaytime: reduce acquisition time of F460 by this value [sec] struck: Use the SRS and Struck scaler for the ion chamber and diode. Set to False to use the F460. fluorescence: indicate the presence of fluorescence data [bool] samplename (string): sample name to be saved in the scan metadata filename (string): filename to be added to the scan id as the text output filename shutter: instruct the scan to control the B shutter [bool] align: control the tuning of the DCM pointing before each XANES scan [bool] align_at: energy at which to align, default is the first energy point ''' ept = numpy.array([]) det = [] filename = filename last_time_pt = time.time() ringbuf = collections.deque(maxlen=10) c2pitch_kill = EpicsSignal("XF:05IDA-OP:1{Mono:HDCM-Ax:P2}Cmd:Kill-Cmd") xs.external_trig.put(False) #make sure user provided correct input if erange is []: raise AttributeError( "An energy range must be provided in a list by means of the 'erange' keyword." ) if estep is []: raise AttributeError( "A list of energy steps must be provided by means of the 'esteps' keyword." ) if (not isinstance(erange, list)) or (not isinstance(estep, list)): raise TypeError("The keywords 'estep' and 'erange' must be lists.") if len(erange) - len(estep) is not 1: raise ValueError("The 'erange' and 'estep' lists are inconsistent;"\ +'c.f., erange = [7000, 7100, 7150, 7500], estep = [2, 0.5, 5] ') if type(roinum) is not list: roinum = [roinum] if detune is not None: yield from abs_set(energy.detune, detune) #record relevant meta data in the Start document, defined in 90-usersetup.py metadata_record() #add user meta data RE.md['sample'] = {'name': samplename} RE.md['scaninfo'] = { 'type': 'XANES', 'ROI': roinum, 'raster': False, 'dwell': acqtime } RE.md['scan_input'] = str(np.around(erange, 2)) + ', ' + str( np.around(estep, 2)) #convert erange and estep to numpy array erange = numpy.array(erange) estep = numpy.array(estep) #calculation for the energy points for i in range(len(estep)): ept = numpy.append(ept, numpy.arange(erange[i], erange[i + 1], estep[i])) ept = numpy.append(ept, numpy.array(erange[-1])) # Debugging # Convert energy to bragg angle egap = np.array(()) ebragg = np.array(()) exgap = np.array(()) for i in ept: # Convert from eV to keV # if (i > 4500): # i = i / 1000 # Convert keV to bragg angle #b, _, _ = energy.energy_to_positions(i, 5, 0) eg, eb, ex = energy.forward(i) egap = np.append(egap, eg) ebragg = np.append(ebragg, eb) exgap = np.append(exgap, ex) # print(ebragg) #register the detectors det = [ring_current] if struck == True: det.append(sclr1) else: det.append(current_preamp) if fluor == True: det.append(xs) #setup xspress3 yield from abs_set(xs.settings.acquire_time, acqtime) yield from abs_set(xs.total_points, len(ept)) #setup the preamp if struck == True: yield from abs_set(sclr1.preset_time, acqtime) else: yield from abs_set(current_preamp.exp_time, acqtime - delaytime) #setup dcm/energy options if correct_c2_x is False: yield from abs_set(energy.move_c2_x, False) if correct_c1_r is not False: yield from abs_set(dcm.c1_roll, correct_c1_r) if harmonic != 1: yield from abs_set(energy.harmonic, harmonic) #prepare to peak up DCM at first scan point if align_at is not None: align = True if align is True: if align_at == None: yield from abs_set(energy, ept[0], wait=True) else: print("aligning at ", align_at) yield from abs_set(energy, float(align_at), wait=True) # energy.u_gap.corrfunc_dis.put(1) #open b shutter if shutter is True: #shut_b.open() yield from mv(shut_b, 'Open') #yield from abs_set(shut_b,1,wait=True) #peak up DCM at first scan point if align is True: ps = PeakStats(dcm.c2_pitch.name, 'sclr_i0') e_value = energy.energy.get()[1] # if e_value < 10.: # yield from abs_set(sclr1.preset_time,0.1, wait = True) # peakup = scan([sclr1], dcm.c2_pitch, -19.335, -19.305, 31) # else: # yield from abs_set(sclr1.preset_time,1., wait = True) # peakup = scan([sclr1], dcm.c2_pitch, -19.355, -19.320, 36) if e_value < 14.: sclr1.preset_time.put(0.1) else: sclr1.preset_time.put(1.) peakup = scan([sclr1], dcm.c2_pitch, -19.320, -19.360, 41) peakup = subs_wrapper(peakup, ps) yield from peakup yield from abs_set(dcm.c2_pitch, ps.cen, wait=True) #ttime.sleep(10) #yield from abs_set(c2pitch_kill, 1) #setup the live callbacks myscan = list_scan(det, energy, list(ept), per_step=per_step) livecallbacks = [] livetableitem = ['energy_energy'] if struck == True: livetableitem = livetableitem + ['sclr_i0', 'sclr_it'] else: livetableitem = livetableitem + [ 'current_preamp_ch0', 'current_preamp_ch2' ] if fluor == True: roi_name = 'roi{:02}'.format(roinum[0]) roi_key = [] roi_key.append(getattr(xs.channel1.rois, roi_name).value.name) roi_key.append(getattr(xs.channel2.rois, roi_name).value.name) roi_key.append(getattr(xs.channel3.rois, roi_name).value.name) livetableitem.append(roi_key[0]) livecallbacks.append(LiveTable(livetableitem)) liveploty = roi_key[0] liveplotx = energy.energy.name liveplotfig = plt.figure('raw xanes') elif struck == True: liveploty = 'sclr_it' liveplotx = energy.energy.name liveplotfig = plt.figure('raw xanes') # livecallbacks.append(LiveTable([sclr1, xs, energy])) livecallbacks.append(LivePlot(liveploty, x=liveplotx, fig=liveplotfig)) #livecallbacks.append(LivePlot(liveploty, x=liveplotx, ax=plt.gca(title='raw xanes'))) if struck == True: liveploty = 'sclr_i0' i0 = 'sclr_i0' else: liveploty = 'current_preamp_ch2' i0 = 'current_preamp_ch2' liveplotfig2 = plt.figure('i0') livecallbacks.append(LivePlot(liveploty, x=liveplotx, fig=liveplotfig2)) #livecallbacks.append(LivePlot(liveploty, x=liveplotx, ax=plt.gca(title='incident intensity'))) livenormfig = plt.figure('normalized xanes') if fluor == True: livecallbacks.append( NormalizeLivePlot(roi_key[0], x=liveplotx, norm_key=i0, fig=livenormfig)) #livecallbacks.append(NormalizeLivePlot(roi_key[0], x=liveplotx, norm_key = i0, ax=plt.gca(title='normalized xanes'))) else: livecallbacks.append( NormalizeLivePlot('sclr_it', x=liveplotx, norm_key=i0, fig=livenormfig)) #livecallbacks.append(NormalizeLivePlot(roi_key[0], x=liveplotx, norm_key = i0, ax=plt.gca(title='normalized xanes'))) def after_scan(name, doc): if name != 'stop': print( "You must export this scan data manually: xanes_afterscan_plan(doc[-1], <filename>, <roinum>)" ) return xanes_afterscan_plan(doc['run_start'], filename, roinum) logscan_detailed('xanes') def at_scan(name, doc): scanrecord.current_scan.put(doc['uid'][:6]) scanrecord.current_scan_id.put(str(doc['scan_id'])) scanrecord.current_type.put(RE.md['scaninfo']['type']) scanrecord.scanning.put(True) def finalize_scan(): # yield from abs_set(energy.u_gap.corrfunc_en,1) # disabled to test if # undulator gets stuck -AMK yield from abs_set(energy.move_c2_x, True) yield from abs_set(energy.harmonic, 1) scanrecord.scanning.put(False) if shutter == True: yield from mv(shut_b, 'Close') if detune is not None: energy.detune.put(0) del RE.md['sample']['name'] del RE.md['scaninfo'] myscan = list_scan(det, energy, list(ept), per_step=per_step) # myscan = list_scan(det, energy, list(ept), per_step=per_step(detectors, motor, step)) # myscan = list_scan(det, energy.bragg, list(ebragg), energy.u_gap, list(egap), energy.c2_x, list(exgap)) # myscan = scan_nd(det, energy.bragg, list(ebragg), energy.u_gap, list(egap), energy.c2_x, list(exgap)) myscan = finalize_wrapper(myscan, finalize_scan) return (yield from subs_wrapper(myscan, { 'all': livecallbacks, 'stop': after_scan, 'start': at_scan }))
def nano_xrf(xstart, xstop, xstep, ystart, ystop, ystep, dwell, shutter=True, extra_dets=None, xmotor=nano_stage.sx, ymotor=nano_stage.sy, flag_snake=True): # calculate number of points xnum = np.int(np.abs(np.round((xstop - xstart) / xstep)) + 1) ynum = np.int(np.abs(np.round((ystop - ystart) / ystep)) + 1) # Setup detectors if extra_dets is None: extra_dets = [] dets = [sclr1, xs, xbpm2, xmotor, ymotor] + extra_dets # Record relevant metadata in the Start document, defined in 90-usersetup.py scan_md = {} get_stock_md(scan_md) # scan_md['scan_input'] = str([xstart, xstop, xstep, ystart, ystop, ystep, dwell]) # scan_md['scaninfo'] = {'type': 'XRF', # 'raster' : True} scan_md['scan']['type'] = 'XRF_STEP' scan_md['scan']['scan_input'] = [ xstart, xstop, xstep, ystart, ystop, ystep, dwell ] scan_md['scan']['detectors'] = [d.name for d in dets] scan_md['scan']['fast_axis'] = { 'motor_name': xmotor.name, 'units': xmotor.motor_egu.get() } scan_md['scan']['slow_axis'] = { 'motor_name': ymotor.name, 'units': ymotor.motor_egu.get() } scan_md['scan']['theta'] = { 'val': nano_stage.th.user_readback.get(), 'units': nano_stage.th.motor_egu.get() } scan_md['scan']['delta'] = {'val': 0, 'units': xmotor.motor_egu.get()} scan_md['scan']['snake'] = 1 if flag_snake else 0 scan_md['scan']['shape'] = (xnum, ynum) # Set counting time sclr1.preset_time.put(dwell) xs.external_trig.put(False) xs.settings.acquire_time.put(dwell) xs.total_points.put(xnum * ynum) if (merlin in dets): merlin.cam.acquire_time.put(dwell) merlin.cam.acquire_period.put(dwell + 0.005) merlin.hdf5.stage_sigs['num_capture'] = xnum * ynum scan_md['scan']['merlin'] = { 'merlin_exp_time': dwell, 'merlin_exp_period': dwell + 0.005 } # LiveGrid livecallbacks = [] livecallbacks.append(LiveTable([xmotor.name, ymotor.name])) roi_name = 'roi{:02}'.format(1) roi_key = getattr(xs.channel1.rois, roi_name).value.name livecallbacks.append( LiveGrid((ynum, xnum), roi_key, clim=None, cmap='viridis', xlabel='x [um]', ylabel='y [um]', extent=[xstart, xstop, ystart, ystop], x_positive='right', y_positive='down')) myplan = grid_scan(dets, ymotor, ystart, ystop, ynum, xmotor, xstart, xstop, xnum, flag_snake, md=scan_md) myplan = subs_wrapper(myplan, {'all': livecallbacks}) # Open shutter # if (shutter): # yield from mv(shut_b,'Open') yield from check_shutters(shutter, 'Open') # grid scan uid = yield from myplan # Close shutter # if (shutter): # yield from mv(shut_b,'Close') yield from check_shutters(shutter, 'Close') return uid
def hf2dxrf(*, xstart, xnumstep, xstepsize, ystart, ynumstep, ystepsize, acqtime, shutter=True, align=False, xmotor=hf_stage.x, ymotor=hf_stage.y, numrois=1, extra_dets=[], setenergy=None, u_detune=None, echange_waittime=10, samplename=None, snake=True): '''input: xstart, xnumstep, xstepsize : float ystart, ynumstep, ystepsize : float acqtime : float acqusition time to be set for both xspress3 and F460 numrois : integer number of ROIs set to display in the live raster scans. This is for display ONLY. The actualy number of ROIs saved depend on how many are enabled and set in the read_attr However noramlly one cares only the raw XRF spectra which are all saved and will be used for fitting. energy (float): set energy, use with caution, hdcm might become misaligned u_detune (float): amount of undulator to detune in the unit of keV ''' # Record relevant metadata in the Start document, defined in 90-usersetup.py scan_md = {} get_stock_md(scan_md) scan_md['sample'] = {'name': samplename} scan_md['scan_input'] = str( [xstart, xnumstep, xstepsize, ystart, ynumstep, ystepsize, acqtime]) scan_md['scaninfo'] = {'type': 'XRF', 'raster': True} # Setup detectors dets = [sclr1, xs] dets = dets + extra_dets dets_by_name = {d.name: d for d in dets} # Scaler if (acqtime < 0.001): acqtime = 0.001 sclr1.preset_time.put(acqtime) # XS3 xs.external_trig.put(False) xs.settings.acquire_time.put(acqtime) xs.total_points.put((xnumstep + 1) * (ynumstep + 1)) if ('merlin' in dets_by_name): dpc = dets_by_name['merlin'] # Setup Merlin dpc.cam.trigger_mode.put(0) dpc.cam.acquire_time.put(acqtime) dpc.cam.acquire_period.put(acqtime + 0.005) dpc.cam.num_images.put(1) dpc.hdf5.stage_sigs['num_capture'] = (xnumstep + 1) * (ynumstep + 1) dpc._mode = SRXMode.step dpc.total_points.put((xnumstep + 1) * (ynumstep + 1)) if ('xs2' in dets_by_name): xs2 = dets_by_name['xs2'] xs2.external_trig.put(False) xs2.settings.acquire_time.put(acqtime) xs2.total_points.put((xnumstep + 1) * (ynumstep + 1)) # Setup the live callbacks livecallbacks = [] # Setup scanbroker to update time remaining def time_per_point(name, doc, st=ttime.time()): if ('seq_num' in doc.keys()): scanrecord.scan0.tpp.put((doc['time'] - st) / doc['seq_num']) scanrecord.scan0.curpt.put(int(doc['seq_num'])) scanrecord.time_remaining.put( (doc['time'] - st) / doc['seq_num'] * ((xnumstep + 1) * (ynumstep + 1) - doc['seq_num']) / 3600) livecallbacks.append(time_per_point) # Setup LiveTable livetableitem = [xmotor.name, ymotor.name, i0.name] xstop = xstart + xnumstep * xstepsize ystop = ystart + ynumstep * ystepsize for roi_idx in range(numrois): roi_name = 'roi{:02}'.format(roi_idx + 1) roi_key = getattr(xs.channel1.rois, roi_name).value.name livetableitem.append(roi_key) roimap = LiveGrid((ynumstep + 1, xnumstep + 1), roi_key, clim=None, cmap='viridis', xlabel='x (mm)', ylabel='y (mm)', extent=[xstart, xstop, ystart, ystop], x_positive='right', y_positive='down') livecallbacks.append(roimap) if ('xs2' in dets_by_name): for roi_idx in range(numrois): roi_key = getattr(xs2.channel1.rois, roi_name).value.name livetableitem.append(roi_key) fig = plt.figure('xs2_ROI{:02}'.format(roi_idx + 1)) fig.clf() roimap = LiveGrid((ynumstep + 1, xnumstep + 1), roi_key, clim=None, cmap='viridis', xlabel='x (mm)', ylabel='y (mm)', extent=[xstart, xstop, ystart, ystop], x_positive='right', y_positive='down', ax=fig.gca()) livecallbacks.append(roimap) if ('merlin' in dets_by_name) and (hasattr(dpc, 'stats1')): fig = plt.figure('DPC') fig.clf() dpc_tmap = LiveGrid((ynumstep + 1, xnumstep + 1), dpc.stats1.total.name, clim=None, cmap='viridis', xlabel='x (mm)', ylabel='y (mm)', x_positive='right', y_positive='down', extent=[xstart, xstop, ystart, ystop], ax=fig.gca()) livecallbacks.append(dpc_tmap) # Change energy (if provided) if (setenergy is not None): if (u_detune is not None): energy.detune.put(u_detune) print('Changing energy to ', setenergy) yield from mv(energy, setenergy) print('Waiting time (s) ', echange_waittime) yield from bps.sleep(echange_waittime) def at_scan(name, doc): scanrecord.current_scan.put(doc['uid'][:6]) scanrecord.current_scan_id.put(str(doc['scan_id'])) scanrecord.current_type.put(scan_md['scaninfo']['type']) scanrecord.scanning.put(True) def finalize_scan(name, doc): scanrecord.scanning.put(False) # Setup the scan hf2dxrf_scanplan = outer_product_scan(dets, ymotor, ystart, ystop, ynumstep + 1, xmotor, xstart, xstop, xnumstep + 1, snake, md=scan_md) hf2dxrf_scanplan = subs_wrapper(hf2dxrf_scanplan, { 'all': livecallbacks, 'start': at_scan, 'stop': finalize_scan }) # Move to starting position yield from mv(xmotor, xstart, ymotor, ystart) # Peak up monochromator at this energy if (align): yield from peakup_fine(shutter=shutter) # Open shutter if (shutter): yield from mv(shut_b, 'Open') # Run the scan scaninfo = yield from hf2dxrf_scanplan #TO-DO: implement fast shutter control (close) if (shutter): yield from mv(shut_b, 'Close') # Write to scan log if ('merlin' in dets_by_name): logscan_event0info('2dxrf_withdpc') # Should this be here? merlin.hdf5.stage_sigs['num_capture'] = 0 else: logscan_detailed('2dxrf') return scaninfo
def nano_xrf(xstart, xstop, xstep, ystart, ystop, ystep, acqtime, shutter=True, extra_dets=None, xmotor=nano_stage.sx, ymotor=nano_stage.sy): # define motors # xmotor = nano_stage.x # ymotor = nano_stage.y # Record relevant metadata in the Start document, defined in 90-usersetup.py scan_md = {} get_stock_md(scan_md) scan_md['scan_input'] = str( [xstart, xstop, xstep, ystart, ystop, ystep, acqtime]) scan_md['scaninfo'] = {'type': 'XRF', 'raster': True} # calculate number of points xnum = np.int(np.abs(np.round((xstop - xstart) / xstep)) + 1) ynum = np.int(np.abs(np.round((ystop - ystart) / ystep)) + 1) # Setup detectors if extra_dets is None: extra_dets = [] dets = [sclr1, xs, xbpm2, xmotor, ymotor] + extra_dets # Set counting time sclr1.preset_time.put(acqtime) xs.external_trig.put(False) xs.settings.acquire_time.put(acqtime) xs.total_points.put(xnum * ynum) if (merlin in dets): merlin.cam.acquire_time.put(acqtime) merlin.cam.acquire_period.put(acqtime + 0.005) merlin.hdf5.stage_sigs['num_capture'] = xnum * ynum scan_md['merlin'] = { 'merlin_exp_time': acqtime, 'merlin_exp_period': acqtime + 0.005 } # LiveGrid livecallbacks = [] livecallbacks.append(LiveTable([xmotor.name, ymotor.name])) roi_name = 'roi{:02}'.format(1) roi_key = getattr(xs.channel1.rois, roi_name).value.name livecallbacks.append( LiveGrid((ynum, xnum), roi_key, clim=None, cmap='viridis', xlabel='x [um]', ylabel='y [um]', extent=[xstart, xstop, ystart, ystop], x_positive='right', y_positive='down')) myplan = grid_scan(dets, ymotor, ystart, ystop, ynum, xmotor, xstart, xstop, xnum, True, md=scan_md) myplan = subs_wrapper(myplan, {'all': livecallbacks}) # Open shutter if (shutter): yield from mv(shut_b, 'Open') # grid scan uid = yield from myplan # Open shutter if (shutter): yield from mv(shut_b, 'Close') return uid