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))
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 open_all_valves(valve_list): '''Open all the listed valves Parameters ---------- valve_list : sequence The valves to open ''' for v in valve_list: yield from bps.abs_set(v, 1, group='valve_set') yield from bps.wait('valve_set') # sleep might not be needed yield from bps.sleep(2)
def E_fly(scan_title, *, operator, element, start, stop, step_size, num_scans, flyspeed=0.05, xspress3=None): _validate_motor_limits(mono.energy, start, stop, "E") assert step_size > 0, f"step_size ({step_size}) must be more than 0" assert num_scans > 0, f"num_scans ({num_scans}) must be more than 0" e_back = yield from _get_v_with_dflt(mono.e_back, 1977.04) energy_cal = yield from _get_v_with_dflt(mono.cal, 0.40118) roi = rois(element) xs.channel1.rois.roi01.bin_low.set(roi[0]) xs.channel1.rois.roi01.bin_high.set(roi[1]) def _linear_to_energy(linear): linear = np.asarray(linear) return e_back / np.sin( np.deg2rad(45) + 0.5 * np.arctan((28.2474 - linear) / 35.02333) + np.deg2rad(energy_cal) / 2) def _energy_to_linear(energy): energy = np.asarray(energy) return 28.2474 + 35.02333 * np.tan(np.pi / 2 - 2 * np.arcsin(e_back / energy) + np.deg2rad(energy_cal)) # get limits in linear parameters l_start, l_stop = _energy_to_linear([start, stop]) l_step_size = np.diff(_energy_to_linear([start, start + step_size])) # scale to match motor resolution lmres = yield from _get_v_with_dflt(mono.linear.mres, 0.0001666) prescale = int(np.floor((l_step_size / (5 * lmres)))) a_l_step_size = prescale * (5 * lmres) num_pixels = int(np.floor((l_stop - l_start) / a_l_step_size)) bin_edges = _linear_to_energy(l_start + a_l_step_size * np.arange(num_pixels + 1)) bin_centers = (bin_edges[:-1] + bin_edges[1:]) / 2 yield from bps.mv(E_centers, bin_centers) # The flyspeed is set by Paul by edict # flyspeed = 0.05 # set up delta-tau trigger to fast motor for v in [ "p1600=0", "p1607=4", "p1601=5", "p1602 = 2", "p1604 = 0", "p1600=1" ]: yield from bps.mv(dtt, v) yield from bps.sleep(0.1) # TODO make this a message? sclr.set_mode("flying") # SRX original roi_key = getattr(xs.channel1.rois, roi_name).value.name # roi_livegrid_key = xs.channel1.rois.roi01.value.name # roi_livegrid = LivePlot(y=roi_livegrid_key) # poke the struck settings yield from bps.mv(sclr.mcas.prescale, prescale) yield from bps.mv(sclr.mcas.nuse, num_pixels) if xspress3 is not None: yield from bps.mv(xs.external_trig, True) yield from mv(xspress3.total_points, num_pixels) yield from mv(xspress3.hdf5.num_capture, num_pixels) yield from mv(xspress3.settings.num_images, num_pixels) @bpp.reset_positions_decorator([mono.linear]) @bpp.stage_decorator([sclr]) # @bpp.subs_decorator({"all": [roi_livegrid]}) @bpp.monitor_during_decorator([xs.channel1.rois.roi01.value]) @bpp.baseline_decorator([mono, xy_stage]) # TODO put is other meta data @bpp.run_decorator( md={ "scan_title": scan_title, "operator": operator, "user_input": { "element": element, "start": start, "stop": stop, "step_size": step_size, }, "derived_input": { "l_start": l_start, "l_stop": l_stop, "l_step_size": l_step_size, "lmres": lmres, "actual_l_step_size": a_l_step_size, "fly_velocity": flyspeed, "num_pixels": num_pixels, "prescale": prescale, }, }) def fly_body(): yield from bps.trigger_and_read([E_centers], name="energy_bins") @bpp.stage_decorator([x for x in [xspress3] if x is not None]) def fly_once(y): # for y in range(num_scans): # go to start of row yield from bps.checkpoint() yield from bps.mv(mono.linear, l_start) # set the fly speed yield from bps.mv(mono.linear.velocity, flyspeed) yield from bps.trigger_and_read([mono], name="row_ends") for v in ["p1600=0", "p1600=1"]: yield from bps.mv(dtt, v) yield from bps.sleep(0.1) # arm the Struck yield from bps.trigger(sclr, group=f"fly_energy_{y}") if xspress3 is not None: yield from bps.trigger(xspress3, group=f"fly_energy_{y}") # fly the motor yield from bps.abs_set(mono.linear, l_stop + a_l_step_size, group=f"fly_energy_{y}") yield from bps.wait(group=f"fly_energy_{y}") yield from bps.trigger_and_read([mono], name="row_ends") yield from bps.mv(mono.linear.velocity, 0.5) # hard coded to let the sclr count its fingers and toes yield from bps.sleep(0.1) # read and save the struck yield from bps.create(name="primary") yield from bps.read(sclr) if xspress3 is not None: yield from bps.read(xspress3) yield from bps.save() for scan_iter in range(num_scans): if xspress3 is not None: yield from bps.mv(xspress3.fly_next, True) yield from fly_once(scan_iter) yield from fly_body() print("Waiting for files... ...") yield from bps.sleep(15) artifacts = e_fly_export(db[-1]) pprint.pprint(artifacts)
def fly_scan(*, x_start, x_stop, nx, y_start, y_stop, ny, exp_time, trigger_rate=7, md={}): """Fly scan plan with a stage (X and Y motors) and a camera. How to run: ----------- RE(fly_scan(x_start=0, x_stop=0.1, nx=50, y_start=0, y_stop=0.1, ny=4, exp_time=0.01, trigger_rate=5)) Parameters ---------- x_start : float start position of the X-motor of the stage x_stop : float stop position of the X-motor of the stage nx : integer number of points for the X-motor y_start : float start position of the X-motor of the stage y_stop : float stop position of the Y-motor of the stage ny : integer number of points for the Y-motor exp_time : float exposure time of the camera trigger_rate : integer, optional trigger rate of the camera md : dict, optional metadata """ yield from bps.mv( # X motor: flyer.hxn_stage.x_start, x_start, flyer.hxn_stage.x_stop, x_stop, flyer.hxn_stage.nx, nx, # Y motor: flyer.hxn_stage.y_start, y_start, flyer.hxn_stage.y_stop, y_stop, flyer.hxn_stage.ny, ny, # Trigger rate: flyer.hxn_stage.trigger_rate, trigger_rate, ) yield from bps.sleep(1.0) for c in flyer.hxn_stage.component_names: print(f'{getattr(flyer.hxn_stage, c).read()}') yield from bps.mv(flyer.detector.cam.acquire_time, exp_time) yield from bps.mv( flyer.detector.cam.num_images, int(flyer.hxn_stage.nx.get()) * int(flyer.hxn_stage.ny.get())) # md.update({'x_start': x_start, 'x_stop': x_stop, 'nx': nx, # 'y_start': y_start, 'y_stop': y_stop, 'ny': nx, # 'exp_time': exp_time, 'trigger_rate': trigger_rate, # }) yield from bps.sleep(1.0) @bpp.stage_decorator([flyer]) def _fly_scan(): yield from bp.fly([flyer]) yield from _fly_scan()
def tune_GslitsCenter(md=None): """ plan: optimize the guard slits' position tune to the peak centers """ _md = dict() _md.update(md or {}) # yield from IfRequestedStopBeforeNextScan() title = "tuning USAXS Gslit center" ts = str(datetime.datetime.now()) # yield from bps.mv( # user_data.sample_title, title, # user_data.state, "tune Guard slits center", # user_data.user_name, USERNAME, # # user_data.user_dir, ZZZZZZZZZZZ, # user_data.spec_scan, str(RE.md["scan_id"]+1+1), # TODO: Why SCAN_N+1? # user_data.time_stamp, ts, # user_data.scan_macro, "tune_GslitCenter", # ) # yield from mode_USAXS() # yield from bps.mv( # usaxs_slit.v_size, terms.SAXS.usaxs_v_size.get(), # usaxs_slit.h_size, terms.SAXS.usaxs_h_size.get(), # ) # yield from bps.mv(ti_filter_shutter, "open") # yield from insertTransmissionFilters() yield from bps.sleep(0.1) logger.info("autoranging the PD -- skipped") # yield from bps.mv( # user_data.state, "autoranging the PD", # ) # yield from autoscale_amplifiers([upd_controls, I0_controls, I00_controls]) # yield from bps.mv(user_data.state, title) old_preset_time = scaler0.preset_time.get() yield from bps.mv(scaler0.preset_time, 0.2) def tune_guard_slit_motor(motor, width, steps): if steps < 10: raise GuardSlitTuneError( f"Not enough points ({steps}) to tune guard slits.") x_c = motor.position x_0 = x_c - abs(width) / 2 x_n = x_c + abs(width) / 2 scaler0.select_channels([UPD_SIGNAL.chname.get()]) CLOCK_SIGNAL.kind = Kind.config tuner = TuneAxis([scaler0], motor, signal_name=UPD_SIGNAL.chname.get()) yield from tuner.tune(width=-width, num=steps + 1) bluesky_runengine_running = RE.state != "idle" if bluesky_runengine_running: found = tuner.peak_detected() center = tuner.peaks.com # center of mass table = pyRestTable.Table() table.addLabel("tune parameter") table.addLabel("fitted value") table.addRow(("peak detected?", found)) table.addRow(("center of mass", center)) table.addRow(("center from half max", tuner.peaks.cen)) table.addRow(("peak max (x,y)", tuner.peaks.max)) table.addRow(("FWHM", tuner.peaks.fwhm)) logger.info(table) def cleanup_then_GuardSlitTuneError(msg): logger.warning( "cleanup: %s -- %s: move to %f (initial position)", msg, motor.name, x_c, ) scaler0.select_channels(None) yield from bps.mv( motor, x_c, scaler0.preset_time, old_preset_time, # ti_filter_shutter, "close" ) raise GuardSlitTuneError(msg) if not found: yield from cleanup_then_GuardSlitTuneError( f"{motor.name} Peak not found.") if center < x_0: # sanity check that start <= COM msg = f"{motor.name}: Computed center too low: {center} < {x_0}" yield from cleanup_then_GuardSlitTuneError(msg) if center > x_n: # sanity check that COM <= end yield from cleanup_then_GuardSlitTuneError( f"{motor.name}: Computed center too high: {center} > {x_n}" ) if (max(tuner.peaks.y_data) <= guard_slit.tuning_intensity_threshold): msg = f"{motor.name}: Peak intensity not strong enough to tune." msg += f" {max(tuner.peaks.y_data)} < {guard_slit.tuning_intensity_threshold}" yield from cleanup_then_GuardSlitTuneError(msg) logger.info(f"{motor.name}: move to {center} (center of mass)") yield from bps.mv(motor, center) # Here is the MAIN EVENT try: yield from tune_guard_slit_motor(guard_slit.y, 2, 50) except GuardSlitTuneError as exc: logger.warning("Could not tune guard_slit.y -- %s", str(exc)) try: yield from tune_guard_slit_motor(guard_slit.x, 4, 20) except GuardSlitTuneError as exc: logger.warning("Could not tune guard_slit.y -- %s", str(exc)) yield from bps.mv(scaler0.preset_time, old_preset_time)
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
def fly_each_step(motor, step): def move_to_start_fly(): "See http://nsls-ii.github.io/bluesky/plans.html#the-per-step-hook" yield from abs_set(xmotor, xstart-delta, group='row') yield from one_1d_step([temp_nanoKB], motor, step) yield from bps.wait(group='row') # t_mvstartfly = tic() yield from move_to_start_fly() # toc(t_mvstartfly, str='Move to start fly each') # TODO Why are we re-trying the move? This should be fixed at # a lower level # yield from bps.sleep(1.0) # wait for the "x motor" to move x_set = xstart - delta x_dial = xmotor.user_readback.get() # Get retry deadband value and check against that i = 0 if (xmotor.egu == 'mm'): DEADBAND = 0.0005 else: DEADBAND = 0.02 while (np.abs(x_set - x_dial) > DEADBAND): if (i == 0): print('Waiting for motor to reach starting position...', end='', flush=True) i = i + 1 yield from mv(xmotor, xstart - delta) yield from bps.sleep(0.1) x_dial = xmotor.user_readback.get() if (i != 0): print('done') # Set the scan speed # Is abs_set(wait=True) or mv() faster? v = ((xstop - xstart) / (xnum-1)) / dwell # compute "stage speed" # yield from abs_set(xmotor.velocity, v, wait=True) # set the "stage speed" yield from mv(xmotor.velocity, v) # Change backlash speed for hf_stage.x and hf_stage.y if (hf_stage.x is xmotor): yield from mv(hf_stage.BACKLASH_SPEED_X, v) if (hf_stage.y is xmotor): yield from mv(hf_stage.BACKLASH_SPEED_Y, v) # set up all of the detectors # TODO we should be able to move this out of the per-line call?! if ('xs' in dets_by_name): xs = dets_by_name['xs'] # yield from abs_set(xs.hdf5.num_capture, xnum, wait=True) # yield from abs_set(xs.settings.num_images, xnum, wait=True) yield from mv(xs.hdf5.num_capture, xnum, xs.settings.num_images, xnum) if ('xs2' in dets_by_name): xs2 = dets_by_name['xs2'] # yield from abs_set(xs2.hdf5.num_capture, xnum, wait=True) # yield from abs_set(xs2.settings.num_images, xnum, wait=True) yield from mv(xs2.hdf5.num_capture, xnum, xs2.settings.num_images, xnum) if ('merlin' in dets_by_name): merlin = dets_by_name['merlin'] yield from abs_set(merlin.hdf5.num_capture, xnum, wait=True) yield from abs_set(merlin.cam.num_images, xnum, wait=True) if ('dexela' in dets_by_name): dexela = dets_by_name['dexela'] yield from abs_set(dexela.hdf5.num_capture, xnum, wait=True) yield from abs_set(dexela.cam.num_images, xnum, wait=True) ion = flying_zebra.sclr yield from abs_set(ion.nuse_all,xnum) # arm the Zebra (start caching x positions) # @timer_wrapper def zebra_kickoff(): yield from kickoff(flying_zebra, xstart=xstart, xstop=xstop, xnum=xnum, dwell=dwell, wait=True) # t_zebkickoff = tic() yield from zebra_kickoff() # toc(t_zebkickoff, str='Zebra kickoff') # arm SIS3820, note that there is a 1 sec delay in setting X # into motion so the first point *in each row* won't # normalize... yield from abs_set(ion.erase_start, 1) # trigger all of the detectors for d in flying_zebra.detectors: yield from bps.trigger(d, group='row') if (d.name == 'dexela'): yield from bps.sleep(1) yield from bps.sleep(1.5) # start the 'fly' yield from abs_set(xmotor, xstop + 1*delta, group='row') # move in x # wait for the motor and detectors to all agree they are done yield from bps.wait(group='row') # we still know about ion from above yield from abs_set(ion.stop_all, 1) # stop acquiring scaler # @timer_wrapper def zebra_complete(): yield from complete(flying_zebra) # tell the Zebra we are done # t_zebcomplete = tic() yield from zebra_complete() # toc(t_zebcomplete, str='Zebra complete') # @timer_wrapper def zebra_collect(): yield from collect(flying_zebra) # extract data from Zebra # t_zebcollect = tic() yield from zebra_collect() # toc(t_zebcollect, str='Zebra collect') # TODO what? if ('e_tomo' in xmotor.name): v_return = min(4, xmotor.velocity.high_limit) yield from mv(xmotor.velocity, v_return) if ('nano_stage' in xmotor.name): yield from mv(xmotor.velocity, 30) else: # set the "stage speed" yield from mv(xmotor.velocity, 1.0)
def infinite_plan(): while True: for i in range(1, 5): yield from sleep(2) yield from scan([det], motor, -1, 1, 5 * i)
def planHeaterProcess(): """BS plan: Run one temperature profile on the sample heater.""" log_it(f"Starting planHeaterProcess() for {linkam.name}") report() yield from bps.mv( linkam.ramp, 3, ) log_it(f"Change {linkam.name.get()} rate to {linkam.ramp.get():.0f} C/min") t0 = time.time() # note: bps.mv waits until OBJECT.done.get() == 1 (just like a motor) # bps.abs_set only _sets_ the setpoint, must wait in a later step yield from bps.abs_set( linkam, 1083, ) log_it( f"Change {linkam.name.get()} setpoint to {linkam.setpoint.get():.2f} C" ) while linkam.done.get() not in (1, "Done"): if linkam_exit.get(): # Watch for user exit while waiting yield from bps.abs_set(linkam.stop_signal, linkam_stop_value) log_it("User requested exit during set" f" after {(time.time()-t0)/60:.2f}m." " Stopping the heater.") report() return yield from bps.sleep(1) log_it(f"Done, that took {time.time()-t0:.2f}s") report() # two hours = 2 * HOUR, two minutes = 2 * MINUTE log_it("{linkam.name.get()} holding for 3 hours") t0 = time.time() time_expires = t0 + 3 * HOUR while time.time() < time_expires: if linkam_exit.get(): yield from bps.abs_set(linkam.stop_signal, linkam_stop_value) log_it("User requested exit during hold" f" after {(time.time()-t0)/60:.2f}m." " Stopping the heater.") report() return yield from bps.sleep(1) log_it("{linkam.name.get()} holding period ended") report() # Change rate to 3 C/min : yield from bps.mv( linkam.ramp, 3, ) log_it(f"Change {linkam.name.get()} rate to {linkam.ramp.get():.0f} C/min") t0 = time.time() yield from bps.abs_set( linkam, 40, ) log_it( f"Change {linkam.name.get()} setpoint to {linkam.setpoint.get():.2f} C" ) while linkam.done.get() not in (1, "Done"): if linkam_exit.get(): # Watch for user exit while waiting yield from bps.abs_set(linkam.stop_signal, linkam_stop_value) log_it("User requested exit during set" f" after {(time.time()-t0)/60:.2f}m." " Stopping the heater.") report() return yield from bps.sleep(1) # note: bps.mv waits until OBJECT.done.get() == 1 (just like a motor) log_it(f"Done, that took {time.time()-t0:.2f}s") report() # DEMO: signal for an orderly exit after first run yield from bps.mv(linkam_exit, True)
def change_xtals(xtal=None): '''Move between the Si(111) and Si(311) monochromators, also moving 2nd crystal pitch and roll to approximate positions. Then do a rocking curve scan. ''' if xtal is None: print('No crystal set specified') return (yield from null()) (ok, text) = BMM_clear_to_start() if ok == 0: print(error_msg(text)) yield from null() return BMMuser, RE, dcm, dm3_bct = user_ns['BMMuser'], user_ns['RE'], user_ns[ 'dcm'], user_ns['dm3_bct'] dcm_pitch, dcm_roll, dcm_x = user_ns['dcm_pitch'], user_ns[ 'dcm_roll'], user_ns['dcm_x'] if '111' in xtal: xtal = 'Si(111)' if '311' in xtal: xtal = 'Si(311)' if xtal not in ('Si(111)', 'Si(311)'): print('%s is not a crytsal set' % xtal) return (yield from null()) ###################################################################### # this is a tool for verifying a macro. this replaces an xafs scan # # with a sleep, allowing the user to easily map out motor motions in # # a macro # if BMMuser.macro_dryrun: print( info_msg( '\nBMMuser.macro_dryrun is True. Sleeping for %.1f seconds rather than changing to the %s crystal.\n' % (BMMuser.macro_sleep, xtal))) countdown(BMMuser.macro_sleep) return (yield from null()) ###################################################################### print('Moving to %s crystals' % xtal) action = input('Begin moving motors? [Y/n then Enter] ') if action.lower() == 'q' or action.lower() == 'n': yield from null() return current_energy = dcm.energy.readback.get() start = time.time() RE.msg_hook = None BMM_log_info('Moving to the %s crystals' % xtal) yield from mv(dcm_pitch.kill_cmd, 1) yield from mv(dcm_roll.kill_cmd, 1) if xtal is 'Si(111)': yield from mv(dcm_pitch, 4.1, dcm_roll, -6.26, dcm_x, 0.5) #dcm._crystal = '111' dcm.set_crystal('111') # set d-spacing and bragg offset elif xtal is 'Si(311)': yield from mv(dcm_pitch, 2.28, dcm_roll, -23.86, dcm_x, 65.3) #dcm._crystal = '311' dcm.set_crystal('311') # set d-spacing and bragg offset yield from sleep(2.0) yield from mv(dcm_roll.kill_cmd, 1) print('Returning to %.1f eV' % current_energy) yield from mv(dcm.energy, current_energy) print('Performing a rocking curve scan') yield from mv(dcm_pitch.kill_cmd, 1) yield from mv(dcm_pitch, approximate_pitch(current_energy)) yield from sleep(1) yield from mv(dcm_pitch.kill_cmd, 1) yield from rocking_curve() yield from sleep(2.0) yield from mv(dcm_pitch.kill_cmd, 1) RE.msg_hook = BMM_msg_hook BMM_log_info(motor_status()) close_last_plot() end = time.time() print('\n\nTime elapsed: %.1f min' % ((end - start) / 60))
def change_mode(mode=None, prompt=True, edge=None, reference=None, bender=True): '''Move the photon delivery system to a new mode. A: focused at XAS end station, energy > 8000 B: focused at XAS end station, energy < 6000 C: focused at XAS end station, 6000 < energy < 8000 D: unfocused, energy > 8000 E: unfocused, 6000 < energy < 8000 F: unfocused, energy < 8000 XRD: focused at XRD end station, energy > 8000 ''' BMMuser, RE, dcm, dm3_bct, slits3 = user_ns['BMMuser'], user_ns[ 'RE'], user_ns['dcm'], user_ns['dm3_bct'], user_ns['slits3'] xafs_table, m3, m2, m2_bender, xafs_ref = user_ns['xafs_table'], user_ns[ 'm3'], user_ns['m2'], user_ns['m2_bender'], user_ns['xafs_ref'] if mode is None: print('No mode specified') return (yield from null()) mode = mode.upper() if mode not in ('A', 'B', 'C', 'D', 'E', 'F', 'XRD'): print('%s is not a mode' % mode) return (yield from null()) current_mode = get_mode() # crude hack around a problem I don't understand if dm3_bct.hlm.get() < 55 or dm3_bct.llm.get() > -55: dm3_bct.llm.put(-60) dm3_bct.hlm.put(60) if pds_motors_ready() is False: print( error_msg( '\nOne or more motors are showing amplifier faults.\nToggle the correct kill switch, then re-enable the faulted motor.' )) return (yield from null()) ###################################################################### # this is a tool for verifying a macro. this replaces an xafs scan # # with a sleep, allowing the user to easily map out motor motions in # # a macro # if BMMuser.macro_dryrun: print( info_msg( '\nBMMuser.macro_dryrun is True. Sleeping for %.1f seconds rather than changing to mode %s.\n' % (BMMuser.macro_sleep, mode))) countdown(BMMuser.macro_sleep) return (yield from null()) ###################################################################### if mode == 'B': action = input( "You are entering Mode B -- focused beam below 6 keV is not properly configured at BMM. Continue? [y/N then Enter] " ) if action.lower() != 'y': return (yield from null()) if mode == 'A': description = 'focused, >8 keV' elif mode == 'B': description = 'focused, <6 keV' elif mode == 'C': description = 'focused, 6 to 8 keV' elif mode == 'D': description = 'unfocused, >8 keV' elif mode == 'E': description = 'unfocused, 6 to 8 keV' elif mode == 'F': description = 'unfocused, <6 keV' elif mode == 'XRD': description = 'focused at goniometer, >8 keV' print('Moving to mode %s (%s)' % (mode, description)) if prompt: action = input("Begin moving motors? [Y/n then Enter] ") if action.lower() == 'q' or action.lower() == 'n': return (yield from null()) RE.msg_hook = None BMM_log_info('Changing photon delivery system to mode %s' % mode) base = [ dm3_bct, float(MODEDATA['dm3_bct'][mode]), xafs_table.yu, float(MODEDATA['xafs_yu'][mode]), xafs_table.ydo, float(MODEDATA['xafs_ydo'][mode]), xafs_table.ydi, float(MODEDATA['xafs_ydi'][mode]), m3.yu, float(MODEDATA['m3_yu'][mode]), m3.ydo, float(MODEDATA['m3_ydo'][mode]), m3.ydi, float(MODEDATA['m3_ydi'][mode]), m3.xu, float(MODEDATA['m3_xu'][mode]), m3.xd, float(MODEDATA['m3_xd'][mode]), ] if reference is not None: #base.extend([xafs_linxs, foils.position(reference.capitalize())]) base.extend( [xafs_ref, xafs_ref.position_of_slot(reference.capitalize())]) if edge is not None: #dcm_bragg.clear_encoder_loss() base.extend([dcm.energy, edge]) # if mode in ('D', 'E', 'F'): # base.extend([slits3.hcenter, 2]) # else: # base.extend([slits3.hcenter, 0]) ################################################################### # check for amplifier faults on the motors, return without moving # # anything if any are found # ################################################################### motors_ready = True problem_motors = list() for m in base[::2]: try: # skip non-FMBO motors, which do not have the amfe or amfae attributes if m.amfe.get() == 1 or m.amfae.get() == 1: motors_ready = False problem_motors.append(m.name) except: continue if motors_ready is False: BMMuser.motor_fault = ', '.join(problem_motors) return (yield from null()) ########################## # do the motor movements # ########################## yield from dcm.kill_plan() if dm3_bct.ampen.get() == 0: yield from mv(dm3_bct.enable_cmd, 1) #yield from mv(dm3_bct.kill_cmd, 1) # need to explicitly kill this before # starting a move, it is one of the # motors that reports MOVN=1 even when # still yield from sleep(0.2) yield from mv(dm3_bct.kill_cmd, 1) if mode in ('D', 'E', 'F') and current_mode in ('D', 'E', 'F'): yield from mv(*base) elif mode in ('A', 'B', 'C') and current_mode in ('A', 'B', 'C'): # no need to move M2 yield from mv(*base) else: if bender is True: yield from mv(m2_bender.kill_cmd, 1) if mode == 'XRD': if abs( m2_bender.user_readback.get() - BMMuser.bender_xrd ) > BMMuser.bender_margin: # give some wiggle room for having base.extend([m2_bender, BMMuser.bender_xrd ]) # recently adjusted the bend elif mode in ('A', 'B', 'C'): if abs(m2_bender.user_readback.get() - BMMuser.bender_xas) > BMMuser.bender_margin: base.extend([m2_bender, BMMuser.bender_xas]) base.extend([m2.yu, float(MODEDATA['m2_yu'][mode])]) base.extend([m2.ydo, float(MODEDATA['m2_ydo'][mode])]) base.extend([m2.ydi, float(MODEDATA['m2_ydi'][mode])]) yield from mv(*base) yield from sleep(2.0) yield from mv(m2_bender.kill_cmd, 1) yield from mv(dm3_bct.kill_cmd, 1) yield from m2.kill_jacks() yield from m3.kill_jacks() BMMuser.pds_mode = mode RE.msg_hook = BMM_msg_hook BMM_log_info(motor_status())
def _inner_loop(dets, exposure_count, delay, deadline, per_step, stream_name, done_signal=None): """Helper plan for the inner loop of the sinter plans This is very much like the repeat plan, but has less delay input types and more logic about finishing on a deadline. Parameters ---------- dets : List[OphydObj] The detectors passed to per_step exposure_count : int The maximum number of times to call per_step delay : float The target delay between subsequent starts of per_step. deadline : float Wall time to be done by. Under no condition take longer than this to completely run through plan. per_step : Callable[List[OphydObj], Optional[str]] -> Generator[Msg] The plan to run 'per step'. This is the signature of triger_and_read primary : str Passed to per_step done_signal : Signal, optional If passed, will exit early when goes to 1 """ if done_signal is not None: from bluesky.utils import first_key_heuristic signal_key = first_key_heuristic(done_signal) def _check_signal(): val = yield from bps.read(done_signal) if val is None: return True val = val[signal_key]['value'] return bool(val) else: _check_signal = None for j in range(exposure_count): start_time = time.monotonic() yield from bps.checkpoint() # if things get bogged down in data collection, bail early! if start_time > deadline: print(f'{start_time} > {deadline} bail!') break # this triggers the cameras yield from per_step(dets, stream_name) stop_time = time.monotonic() exp_actual = stop_time - start_time sleep_time = delay - exp_actual yield from bps.checkpoint() if _check_signal is not None: done = yield from _check_signal() if done: return if stop_time + sleep_time > deadline: yield from bps.sleep(deadline - stop_time) return else: yield from bps.sleep(delay - exp_actual)
def cleanup_plan(slp): yield from mv(slits3.vsize, slit_height) yield from abs_set(user_ns['_locked_dwell_time'], 0.5, wait=True) yield from sleep(slp) yield from abs_set(motor.kill_cmd, 1, wait=True) yield from resting_state_plan()
def pe_count( filename="", exposure=1, num_images: int = 1, num_dark_images: int = 1, num_repetitions: int = 5, delay=60, ): year = "2020" # RE.md["year"] cycle = "C2" # RE.md["cycle"] proposal = "67890" # RE.md["PROPOSAL"] # write_path_template = 'Z:\\data\\pe1_data\\%Y\\%m\\%d\\' # write_path_template = f"Z:\\users\\{year}\\{cycle}\\{proposal}XRD\\" # file_path = datetime.now().strftime(write_path_template) # filename = filename + str(uuid.uuid4())[:6] # this is an example of what would be used at the beamline pe_detector.tiff_writer.resource_root_path = PureWindowsPath( f"Z:\\users\\") pe_detector.tiff_writer.relative_write_path = PureWindowsPath( f"{year}\\{cycle}\\{proposal}XRD\\") # for testing pe_detector.tiff_writer.resource_root_path = Path("/tmp/") pe_detector.tiff_writer.relative_write_path = Path( f"perkin_elmer/detector/{year}/{cycle}/XRD{proposal}" # remove "XRD" from the end? ) # start the run yield from bps.open_run() # stage the detector yield from bps.stage(pe_detector) yield from bps.mv(pe_detector.tiff_writer.file_number, 1) tiff_full_file_path = (pe_detector.tiff_writer.resource_root_path / pe_detector.tiff_writer.relative_write_path) print(f"tiff_full_file_path: {str(tiff_full_file_path)}") yield from bps.mv(pe_detector.tiff_writer.file_path, str(tiff_full_file_path)) for repetition_index in range(int(num_repetitions)): print("\n") print( "<<<<<<<<<<<<<<<<< Doing repetition {} out of {} >>>>>>>>>>>>>>>>>" .format(repetition_index + 1, num_repetitions)) # TiffWriter or similar plugin should do this yield from bps.mv(pe_detector.tiff_writer.file_name, filename + str(uuid.uuid4())) if num_dark_images > 0: # originally used pe_detector.num_dark_images # but this is really pe_num_offset_frames yield from bps.mv(pe_detector.cam.pe_num_offset_frames, num_dark_images) yield from bps.mv( pe_detector.cam.image_mode, PerkinElmerCamera.PerkinElmerImageMode.AVERAGE, ) # yield from bps.mv(fast_shutter, "Close") yield from bps.sleep(0.5) yield from bps.mv(pe_detector.tiff_writer.file_write_mode, NDFile.FileWriteMode.SINGLE) # acquire a "dark frame" pe_acquire_offset_status = SubscriptionStatus( pe_detector.cam.pe_acquire_offset, high_to_low_pe_acquire_offset) yield from bps.abs_set( pe_detector.cam.pe_acquire_offset, PerkinElmerCamera.AcquireOffset.ACQUIRE, wait=False, ) yield Msg("wait_for_status", None, pe_acquire_offset_status) yield from bps.mv(pe_detector.tiff_writer.write_file, NDFile.WriteFile.WRITE) # yield from bps.mv( # pe1.cam.image_mode, # NewPerkinElmerDetector.ImageMode.MULTIPLE # ) yield from bps.mv( pe_detector.cam.image_mode, PerkinElmerCamera.PerkinElmerImageMode.AVERAGE, ) yield from bps.mv(pe_detector.cam.acquire_time, exposure) yield from bps.mv(pe_detector.cam.num_images, num_images) # yield from bps.mv(fast_shutter, "Open") yield from bps.sleep(0.5) ## Below 'Capture' mode is used with 'Multiple' image_mode # yield from bps.mv(pe1.tiff_writer.file_write_mode, 'Capture') ## Below 'Single' mode is used with 'Average' image_mode yield from bps.mv( pe_detector.tiff_writer.file_write_mode, NDFile.FileWriteMode.SINGLE, # "Single" ) ## Uncomment 'capture' bit settings when used in 'Capture' mode # yield from bps.mv(pe1.tiff_writer.capture, 1) # this was the old way to initiate the acquisition # yield from bps.mv(pe_detector, "acquire_light") yield from bps.trigger_and_read([pe_detector], name="primary") # can TiffWriter or similar plugin do this? ##Below write_file is needed when used in 'Average' mode yield from bps.mv( pe_detector.tiff_writer.write_file, NDFile.WriteFile.WRITE # 1 ) yield from bps.sleep(delay) # unstage the detector yield from bps.unstage(pe_detector) # end the run yield from bps.close_run()
def delay_scan(detectors, motor, E0, start, stop, step_size, delay_time, per_step=delay_per_step, md={}): """ Scan over one multi-motor trajectory with delay time. Parameters ---------- detectors : list list of 'readable' objects motor : object, any 'settable' object (motor, temp controller, etc.) E0 : edge energy in eV start : start energy in eV stop : stop energy in eV step_size : energy step in eV per_step : callable, optional hook for customizing action of inner loop (messages per step) Expected signature: ``f(detectors, motor, step, delay_time) -> plan (a generator)`` md : dict, optional, metadata See Also -------- :func:`bluesky.plans.relative_inner_product_scan` :func:`bluesky.plans.grid_scan` :func:`bluesky.plans.scan_nd` """ _md = { 'detectors': [det.name for det in detectors], 'motors': [motor.name], 'plan_name': 'delay_scan', 'delay_after_set_energy': delay_time, 'hints': {}, } _md.update(md or {}) if per_step is None: per_step = bps.one_1d_step num = int((stop - start) / step_size) + 1 start = E0 + start stop = E0 + stop scan_list = np.linspace(start, stop, num, endpoint=True) @bpp.stage_decorator(list(detectors) + [motor]) @bpp.run_decorator(md=_md) def inner_scan_nd(): for step in list(scan_list): yield from per_step(detectors, motor, step, delay_time) # # move Energy to E0 # yield from bps.mv(dcm.energy, E0) # move Energy to Start_Energy - 200 eV yield from bps.mv(dcm.energy, start - 200) # sleep 2 seconds yield from bps.sleep(2) # move Energy to Start_Energy yield from bps.mv(dcm.energy, start) # sleep 1 seconds yield from bps.sleep(1) # mark as a checkpoint, motor comeback to this position # when scan is interrupted yield from bps.checkpoint() yield from inner_scan_nd() # move back to E0 after scan return (yield from bps.mv(dcm.energy, E0))
def energy_list_scan(detectors, motor, E0, energy_list, time_list, delay_time, per_step=delay_per_step, md={}): """ Scan over energy lists. Parameters ---------- detectors : list, list of 'readable' objects motor : object, any 'settable' object (motor, temp controller, etc.) E0 : edge energy in eV energy_list : list of energy list time_list : count time list per_step : callable, optional hook for customizing action of inner loop (messages per step) Expected signature: ``f(detectors, motor, step, delay_time) -> plan (a generator)`` md : dict, optional, metadata """ energy_list = list(energy_list) np_energy_list = np.array(energy_list).flatten() num_points = len(np_energy_list) _md = { 'detectors': [det.name for det in detectors], 'motors': [motor.name], 'num_points': num_points, 'num_intervals': num_points - 1, 'plan_name': 'energy_list_scan', 'delay_after_set_energy': delay_time, 'hints': {}, } _md.update(md or {}) if per_step is None: per_step = bps.one_1d_step @bpp.stage_decorator(list(detectors) + [motor]) @bpp.run_decorator(md=_md) def inner_list_scan(energy_list, time_list): index = 0 for item in time_list: # set counter time yield from bps.abs_set(scaler.preset_time, item) # move and count for step in energy_list[index]: yield from per_step(detectors, motor, step, delay_time) index += 1 startEnergy = energy_list[0][0] # move Energy to Start_Energy - 200 eV yield from bps.mv(dcm.energy, startEnergy - 200) # sleep 2 seconds at -200 eV from Start_Energy yield from bps.sleep(2) # move Energy to Start_Energy yield from bps.mv(dcm.energy, startEnergy) # sleep 1 seconds at Start_Energy yield from bps.sleep(1) # mark as a checkpoint, motor comeback to this position # when scan is interrupted yield from bps.checkpoint() yield from inner_list_scan(energy_list, time_list) # move back to E0 after scan yield from bps.mv(dcm.energy, E0) return 0
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 change_edge(el, focus=False, edge='K', energy=None, slits=True, target=300., xrd=False, bender=True): '''Change edge energy by: 1. Moving the DCM above the edge energy 2. Moving the photon delivery system to the correct mode 3. Running a rocking curve scan 4. Running a slits_height scan Parameters ---------- el : str one- or two-letter symbol focus : bool, optional T=focused or F=unfocused beam [False, unfocused] edge : str, optional edge symbol ['K'] energy : float, optional e0 value [None, determined from el/edge] slits : bool, optional perform slit_height() scan [False] target : float, optional energy where rocking curve is measured [300] xrd : boolean, optional force photon delivery system to XRD [False] Examples -------- Normal use, unfocused beam: >>> RE(change_edge('Fe')) Normal use, focused beam: >>> RE(change_edge('Fe', focus=True)) L2 or L1 edge: >>> RE(change_edge('Re', edge='L2')) Measure rocking curve at edge energy: >>> RE(change_edge('Fe', target=0)) XRD, new energy: >>> RE(change_edge('Fe', xrd=True, energy=8600)) note that you must specify an element, but it doesn't matter which one the energy will be moved to the specified energy xrd=True implies focus=True and target=0 ''' BMMuser, RE, dcm, dm3_bct, dcm_pitch = user_ns['BMMuser'], user_ns[ 'RE'], user_ns['dcm'], user_ns['dm3_bct'], user_ns['dcm_pitch'] rkvs = user_ns['rkvs'] try: xs = user_ns['xs'] except: pass #BMMuser.prompt = True el = el.capitalize() ###################################################################### # this is a tool for verifying a macro. this replaces an xafsmod scan # # with a sleep, allowing the user to easily map out motor motions in # # a macro # if BMMuser.macro_dryrun: print( info_msg( '\nBMMuser.macro_dryrun is True. Sleeping for %.1f seconds rather than changing to the %s edge.\n' % (BMMuser.macro_sleep, el))) countdown(BMMuser.macro_sleep) return (yield from null()) ###################################################################### if pds_motors_ready() is False: print( error_msg( '\nOne or more motors are showing amplifier faults.\nToggle the correct kill switch, then re-enable the faulted motor.' )) return (yield from null()) (ok, text) = BMM_clear_to_start() if ok is False: print( error_msg('\n' + text) + bold_msg('Quitting change_edge() macro....\n')) return (yield from null()) if energy is None: energy = edge_energy(el, edge) if energy is None: print( error_msg('\nEither %s or %s is not a valid symbol\n' % (el, edge))) return (yield from null()) if energy > 23500: edge = 'L3' energy = edge_energy(el, 'L3') if energy < 4000: print(warning_msg('The %s edge energy is below 4950 eV' % el)) print(warning_msg('You have to change energy by hand.')) return (yield from null()) if energy > 23500: print( warning_msg( 'The %s edge energy is outside the range of this beamline!' % el)) return (yield from null()) BMMuser.edge = edge BMMuser.element = el BMMuser.edge_energy = energy rkvs.set('BMM:pds:edge', edge) rkvs.set('BMM:pds:element', el) rkvs.set('BMM:pds:edge_energy', energy) if energy > 8000: mode = 'A' if focus else 'D' elif energy < 6000: #mode = 'B' if focus else 'F' ## mode B currently is inaccessible :( mode = 'C' if focus else 'F' else: mode = 'C' if focus else 'E' if xrd: mode = 'XRD' focus = True target = 0.0 current_mode = get_mode() ################################ # confirm configuration change # ################################ print(bold_msg('\nEnergy change:')) print(' %s: %s %s' % (list_msg('edge'), el.capitalize(), edge.capitalize())) print(' %s: %.1f' % (list_msg('edge energy'), energy)) print(' %s: %.1f' % (list_msg('target energy'), energy + target)) print(' %s: %s' % (list_msg('focus'), str(focus))) print(' %s: %s' % (list_msg('photon delivery mode'), mode)) print(' %s: %s' % (list_msg('optimizing slits height'), str(slits))) if BMMuser.prompt: action = input("\nBegin energy change? [Y/n then Enter] ") if action.lower() == 'q' or action.lower() == 'n': return (yield from null()) if mode == 'C' and energy < 6000: print( warning_msg( '\nMoving to mode C for focused beam and an edge energy below 6 keV.' )) action = input( "You will not get optimal harmonic rejection. Continue anyway? [Y/n then Enter] " ) if action.lower() == 'q' or action.lower() == 'n': return (yield from null()) start = time.time() if mode == 'XRD': report('Configuring beamline for XRD', level='bold', slack=True) else: report( f'Configuring beamline for {el.capitalize()} {edge.capitalize()} edge', level='bold', slack=True) yield from dcm.kill_plan() ################################################ # change to the correct photon delivery mode # # + move mono to correct energy # # + move reference holder to correct slot # ################################################ # if not calibrating and mode != current_mode: # print('Moving to photon delivery mode %s...' % mode) yield from change_mode(mode=mode, prompt=False, edge=energy + target, reference=el, bender=bender) if arrived_in_mode(mode=mode) is False: print(error_msg(f'\nFailed to arrive in Mode {mode}')) print( 'Fixing this is often as simple as re-running the change_mode() command.' ) print('If that doesn\'t work, call for help') return (yield from null()) yield from user_ns['kill_mirror_jacks']() yield from sleep(1) if BMMuser.motor_fault is not None: print( error_msg('\nSome motors are reporting amplifier faults: %s' % BMMuser.motor_fault)) print( 'Clear the faults and try running the same change_edge() command again.' ) print('Troubleshooting: ' + url_msg( 'https://nsls-ii-bmm.github.io/BeamlineManual/trouble.html#amplifier-fault' )) BMMuser.motor_fault = None return (yield from null()) BMMuser.motor_fault = None ############################ # run a rocking curve scan # ############################ print('Optimizing rocking curve...') yield from abs_set(dcm_pitch.kill_cmd, 1, wait=True) yield from mv(dcm_pitch, approximate_pitch(energy + target)) yield from sleep(1) yield from abs_set(dcm_pitch.kill_cmd, 1, wait=True) yield from rocking_curve() close_last_plot() ########################## # run a slit height scan # ########################## if slits: print('Optimizing slits height...') yield from slit_height(move=True) close_last_plot() ## redo rocking curve? ################################## # set reference and roi channels # ################################## if not xrd: ## reference channel rois = user_ns['rois'] print('Moving reference foil...') yield from rois.select_plan(el) ## Xspress3 BMMuser.verify_roi(xs, el, edge) ## feedback show_edges() if mode == 'XRD': report('Finished configuring for XRD', level='bold', slack=True) else: report( f'Finished configuring for {el.capitalize()} {edge.capitalize()} edge', level='bold', slack=True) if slits is False: print( ' * You may need to verify the slit position: RE(slit_height())') yield from dcm.kill_plan() end = time.time() print('\n\nThat took %.1f min' % ((end - start) / 60)) return ()
def E_Step_Scan(scan_title, *, operator, element, dwell_time=3, E_sections, step_size, num_scans, xspress3=None): #def E_Step_Scan(dwell_time,*, scan_title = "abc",E_sections = [2700, 2800, 2900, 3200], step_size = [4, 1, 2], num_scans=2, element = 's'): #for v in ["p1600=0", "p1607=4", "p1601=5", "p1602 = 2", "p1600=1"]: #yield from bps.mv(dtt, v) #yield from bps.sleep(0.1) roi = rois(element) yield from bps.mv(xs.channel1.rois.roi01.bin_low, roi[0], xs.channel1.rois.roi01.bin_high, roi[1]) yield from bps.sleep(0.1) # xs.channel1.rois.roi01.bin_low.set(roi[0]) # xs.channel1.rois.roi01.bin_high.set(roi[1]) E_sections = np.array(E_sections) step_size = np.array(step_size) ept = [] for ii in range(step_size.shape[0]): ept = ept[0:-1] ept = np.append( ept, np.linspace( E_sections[ii], E_sections[ii + 1], np.int((E_sections[ii + 1] - E_sections[ii]) / step_size[ii]) + 1)) sclr.set_mode("counting") yield from bps.mv(xs.external_trig, False) yield from bps.mv(sclr.cnts.preset_time, dwell_time, xs.settings.acquire_time, dwell_time) #yield from bps.mv(sclr.set_mode,"counting") #yield from bps.sleep(0.1) #@bpp.monitor_during_decorator([xs.channel1.rois.roi01.value]) #@bpp.baseline_decorator([mono, xy_stage]) # TODO put in other meta data def scan_once(): return (yield from list_scan( [sclr, xs], mono.energy, ept, md={ "scan_title": scan_title, "operator": operator, "user_input": { "element": element, "E_sections": E_sections, "dwell_time": dwell_time, "step_size": step_size, }, "derived_input": {}, })) for scan_iter in range(num_scans): yield from scan_once() h = db[-1] E = h.table()['mono_energy'] I0 = h.table()['I0'] If = h.table()['xs_channel1_rois_roi01_value_sum'] df = pd.DataFrame({'#Energy': E, 'I0': I0, 'If': If}) df.to_csv('/home/xf08bm/Users/TEMP/Step_Scan/' + f'{operator}-{scan_title}-{scan_iter}.csv') print('Please go /home/xf08bm/Desktop/Users/TEMP/ to copy your data ASAP!')
def infinite_plan(): while True: yield from sleep(3) yield from count([noisy_det], 20, delay=0.5)
def main_plan(detector, slow, startslow, stopslow, nslow, fast, startfast, stopfast, nfast, pluck, force, dwell, md): (ok, text) = BMM_clear_to_start() if force is False and ok is False: print(error_msg(text)) BMMuser.final_log_entry = False yield from null() return RE.msg_hook = None ## sanity checks on slow axis if type(slow) is str: slow = slow.lower() if slow not in motor_nicknames.keys() and 'EpicsMotor' not in str( type(slow)) and 'PseudoSingle' not in str(type(slow)): print( error_msg('\n*** %s is not an areascan motor (%s)\n' % (slow, str.join(', ', motor_nicknames.keys())))) BMMuser.final_log_entry = False yield from null() return if slow in motor_nicknames.keys(): slow = motor_nicknames[slow] ## sanity checks on fast axis if type(fast) is str: fast = fast.lower() if fast not in motor_nicknames.keys() and 'EpicsMotor' not in str( type(fast)) and 'PseudoSingle' not in str(type(fast)): print( error_msg('\n*** %s is not an areascan motor (%s)\n' % (fast, str.join(', ', motor_nicknames.keys())))) BMMuser.final_log_entry = False yield from null() return if fast in motor_nicknames.keys(): fast = motor_nicknames[fast] detector = detector.capitalize() yield from abs_set(_locked_dwell_time, dwell, wait=True) dets = [ quadem1, ] if detector == 'If': dets.append(vor) detector = 'ROI1' if detector.lower() == 'xs': dets.append(xs) detector = BMMuser.xs1 if 'PseudoSingle' in str(type(slow)): valueslow = slow.readback.get() else: valueslow = slow.user_readback.get() line1 = 'slow motor: %s, %.3f, %.3f, %d -- starting at %.3f\n' % \ (slow.name, startslow, stopslow, nslow, valueslow) if 'PseudoSingle' in str(type(fast)): valuefast = fast.readback.get() else: valuefast = fast.user_readback.get() line2 = 'fast motor: %s, %.3f, %.3f, %d -- starting at %.3f\n' % \ (fast.name, startfast, stopfast, nfast, valuefast) npoints = nfast * nslow estimate = int(npoints * (dwell + 0.7)) # extent = ( # valuefast + startfast, # valueslow + startslow, # valuefast + stopfast, # valueslow + stopslow, # ) # extent = ( # 0, # nfast-1, # 0, # nslow-1 # ) # print(extent) # return(yield from null()) # areaplot = LiveScatter(fast.name, slow.name, detector, # xlim=(startfast, stopfast), ylim=(startslow, stopslow)) areaplot = LiveGrid( (nslow, nfast), detector, #aspect='equal', #aspect=float(nslow/nfast), extent=extent, xlabel='fast motor: %s' % fast.name, ylabel='slow motor: %s' % slow.name) #BMMuser.ax = areaplot.ax #BMMuser.fig = areaplot.ax.figure BMMuser.motor = fast BMMuser.motor2 = slow #BMMuser.fig.canvas.mpl_connect('close_event', handle_close) thismd = dict() thismd['XDI'] = dict() thismd['XDI']['Facility'] = dict() thismd['XDI']['Facility']['GUP'] = BMMuser.gup thismd['XDI']['Facility']['SAF'] = BMMuser.saf thismd['slow_motor'] = slow.name thismd['fast_motor'] = fast.name ## engage suspenders right before starting scan sequence if force is False: BMM_suspenders() @subs_decorator(areaplot) #@subs_decorator(src.callback) def make_areascan(dets, slow, startslow, stopslow, nslow, fast, startfast, stopfast, nfast, snake=False): BMMuser.final_log_entry = False uid = yield from grid_scan(dets, slow, startslow, stopslow, nslow, fast, startfast, stopfast, nfast, snake) BMMuser.final_log_entry = True return uid rkvs.set('BMM:scan:type', 'area') rkvs.set('BMM:scan:starttime', str(datetime.datetime.timestamp(datetime.datetime.now()))) rkvs.set('BMM:scan:estimated', estimate) BMM_log_info('begin areascan observing: %s\n%s%s' % (detector, line1, line2)) uid = yield from make_areascan(dets, slow, valueslow + startslow, valueslow + stopslow, nslow, fast, valuefast + startfast, valuefast + stopfast, nfast, False) if pluck is True: action = input('\n' + bold_msg( 'Pluck motor position from the plot? [Y/n then Enter] ')) if action.lower() == 'n' or action.lower() == 'q': 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 65-derivedplot.py and while BMMuser.x is None: # https://matplotlib.org/users/event_handling.html yield from sleep(0.5) print('Converting plot coordinates to real coordinates...') begin = valuefast + startfast stepsize = (stopfast - startfast) / (nfast - 1) pointfast = begin + stepsize * BMMuser.x #print(BMMuser.x, pointfast) begin = valueslow + startslow stepsize = (stopslow - startslow) / (nslow - 1) pointslow = begin + stepsize * BMMuser.y #print(BMMuser.y, pointslow) print('That translates to x=%.3f, y=%.3f' % (pointfast, pointslow)) yield from mv(fast, pointfast, slow, pointslow)
def sscan_1D( sscan, poll_delay_s=0.001, phase_timeout_s = 60.0, running_stream="primary", final_array_stream=None, device_settings_stream="settings", md={}): """ simple 1-D scan using EPICS synApps sscan record assumes the sscan record has already been setup properly for a scan PARAMETERS sscan : Device one EPICS sscan record (instance of `apstools.synApps_ophyd.sscanRecord`) running_stream : str or `None` (default: ``"primary"``) Name of document stream to write positioners and detectors data made available while the sscan is running. This is typically the scan data, row by row. If set to `None`, this stream will not be written. final_array_stream : str or `None` (default: ``None``) Name of document stream to write positioners and detectors data posted *after* the sscan has ended. If set to `None`, this stream will not be written. device_settings_stream : str or `None` (default: ``"settings"``) Name of document stream to write *settings* of the sscan device. This is all the information returned by ``sscan.read()``. If set to `None`, this stream will not be written. poll_delay_s : float (default: 0.001 seconds) How long to sleep during each polling loop while collecting interim data values and waiting for sscan to complete. Must be a number between zero and 0.1 seconds. phase_timeout_s : float (default: 60 seconds) How long to wait after last update of the ``sscan.FAZE``. When scanning, we expect the scan phase to update regularly as positioners move and detectors are triggered. If the scan hangs for some reason, this is a way to end the plan early. To cancel this feature, set it to ``None``. NOTE about the document stream names Make certain the names for the document streams are different from each other. If you make them all the same (such as ``primary``), you will have difficulty when reading your data later on. *Don't cross the streams!* EXAMPLE Assume that the chosen sscan record has already been setup. from apstools.devices import sscanDevice scans = sscanDevice(P, name="scans") from apstools.plans import sscan_1D RE(sscan_1D(scans.scan1), md=dict(purpose="demo")) """ global new_data, inactive_deadline msg = f"poll_delay_s must be a number between 0 and 0.1, received {poll_delay_s}" assert 0 <= poll_delay_s <= 0.1, msg t0 = time.time() sscan_status = ophyd.DeviceStatus(sscan.execute_scan) started = False new_data = False inactive_deadline = time.time() if phase_timeout_s is not None: inactive_deadline += phase_timeout_s def execute_cb(value, timestamp, **kwargs): """watch for sscan to complete""" if started and value in (0, "IDLE"): sscan_status._finished() sscan.execute_scan.unsubscribe_all() sscan.scan_phase.unsubscribe_all() def phase_cb(value, timestamp, **kwargs): """watch for new data""" global new_data, inactive_deadline if phase_timeout_s is not None: inactive_deadline = time.time() + phase_timeout_s if value in (15, "RECORD SCALAR DATA"): new_data = True # set flag for main plan # acquire only the channels with non-empty configuration in EPICS sscan.select_channels() # pre-identify the configured channels sscan_data_objects = _get_sscan_data_objects(sscan) # watch for sscan to complete sscan.execute_scan.subscribe(execute_cb) # watch for new data to be read out sscan.scan_phase.subscribe(phase_cb) md["plan_name"] = "sscan_1D" yield from bps.open_run(md) # start data collection yield from bps.mv(sscan.execute_scan, 1) # start sscan started = True # collect and emit data, wait for sscan to end while not sscan_status.done or new_data: if new_data and running_stream is not None: yield from bps.create(running_stream) for k, obj in sscan_data_objects.items(): yield from bps.read(obj) yield from bps.save() new_data = False if phase_timeout_s is not None and time.time() > inactive_deadline: print(f"No change in sscan record for {phase_timeout_s} seconds.") print("ending plan early as unsuccessful") sscan_status._finished(success=False) yield from bps.sleep(poll_delay_s) # dump the complete data arrays if final_array_stream is not None: yield from bps.create(final_array_stream) # we have to search for the arrays since they have ``kind="omitted"`` # (which means they do not get reported by the ``.read()`` method) for part in (sscan.positioners, sscan.detectors): for nm in part.read_attrs: if "." not in nm: # TODO: write just the acquired data, not the FULL arrays! yield from bps.read(getattr(part, nm).array) yield from bps.save() # dump the entire sscan record into another stream if device_settings_stream is not None: yield from bps.create(device_settings_stream) yield from bps.read(sscan) yield from bps.save() yield from bps.close_run() return sscan_status
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. Parameters ---------- filename : str name of file, will be appended to DATA for the full path (required) start : float starting energy value (required) end : float ending energy value (required) nsteps : int number of energy steps (required) delay : float pause between energy steps, in seconds [5] dosteps : bool 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) ''' 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 gridScan(dets, exp_spreadsheet_fn, glbl, xpd_configuration, XPD_SHUTTER_CONF, *, crossed=False, dx=None, dy=None, wait_time=5): """ Scan plan for the multi-sample grid scan. This function takes in a templated excel spreadsheet and constructs a spatial scan plan. Single-shot with total exposure specified in the ``Exposure time`` columns will be executed at the spatial points specified in the ``X-position`` and ``Y-position`` columns. A set of optional arguments ``crossed``, ``dx`` and ``dy`` can be passed so that 4 extra data will be collected with respect at each spatial point. An optional wait time between spatial points data can also be set to avoid residuals (ghost image). Please see ``Examples`` below. Parameters ---------- dets : list A list of detectors will be triggered in the experiment. Note the first three detectors in the list must be in the order as "area detector, x-motor, y-motor". exp_spreadsheet_fn : str filename of the spreadsheet contains sample metadata in each well, locations, exposure times and all additional metadata. This spread MUST be placed inside ``xpdUser/Import``. crossed : bool, optional option if to perform a crossed scan in each well. If it's true, then at each well (x0, y0), 4 additional data will be collected at (x0-dx, y0), (x0+dx, y0), (x0, dy+y0), (x0, y0-dy). Default to False. dx : float, optional offset in x-direction for crossed scan per well. Must be a float if ``crossed`` is set to True. Default to None. dy : float, optional offset in y-direction for crossed scan per well. Must be a float if ``crossed`` is set to True. Default to None. wait_time : float, optional Wait time between each count, default is 5s Examples -------- # define a list of detectors will be triggered in the spatial scan # plan. The first 3 detectors should be in the sequence of # "area_det, x-motor, y-motor" used in the scan. dets = [pe1c, diff_x, diff_y, shctl1] # case 1 # define a plan based on the information entered in the # spreadsheet ``wandaHY1_sample.xlsx``. # Note, this spreadsheet MUST be placed in the ``Import`` directory grid_plan = gridScan(dets, 'wandaHY1_sample.xlsx', wait_time=5) # preview the plan to check. summarize_plan(grid_plan) # redefine the scan plan again then execute the plan. grid_plan = gridScan(dets, 'wandaHY1_sample.xlsx', wait_time=5) uids = xrun(gridScan_sample, grid_plan) # case 2 # define a grid scan that collects 4 extra points at each spatial # point to account for potential inhomogeneity grid_plan = gridScan(dets, 'wandaHY1_sample.xlsx', crossed=True, dx=0.2, dy=0.1, wai_time=5) # preview the plan to check. summarize_plan(grid_plan) # redefine the scan plan again then execute the plan. grid_plan = gridScan(dets, 'wandaHY1_sample.xlsx', wait_time=5) uids = xrun(gridScan_sample, grid_plan) # finally, retrieve event information as a dataframe hdrs = db[-len(uids):] df = db.get_table(hdrs) # visualize the dataframe df # save the dataframe as a csv df.to_csv('wandaHY1_spatial_scan_df.csv') Notes ----- 1. ``gridScan_sample`` used in the example is in fact an empty dictionary (and it has been defined in this script as well). Sample metadata is handled inside the plan, therefore it's simply an auxiliary object. 2. ``gridScan`` yields a generator so you would need to construct it every time after using it. As demonstrated in the Example, we redefine the ``grid_plan`` again after printing the summary. Similarly, if you wish to execute the same scan plan, you would have to repeat the syntax. """ 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 # read exp spreadsheet spreadsheet_parser = ExceltoYaml(glbl['import_dir']) fp = os.path.join(spreadsheet_parser.src_dir, exp_spreadsheet_fn) spreadsheet_parser.pd_df = pd.read_excel(fp, skiprows=[1]) spreadsheet_parser.parse_sample_md() # get detectors area_det = xpd_configuration['area_det'] x_motor, y_motor = list(dets)[:2] dets = [area_det] + dets # compute Nsteps _md = { 'sp_time_per_frame': None, 'sp_num_frames': None, 'sp_requested_exposure': None, 'sp_computed_exposure': None, 'sp_type': 'gridScan', 'sp_uid': str(uuid.uuid4())[:4], 'sp_plan_name': 'gridScan' } # first validate through sa_md list for md_dict in spreadsheet_parser.parsed_sa_md_list: if not ('x-position' in md_dict and 'y-position' in md_dict and 'exposure_time(s)' in md_dict): raise xpdAcqException("either X-position, Y-position " "or Exposure time column in {} " "row is missing. Please fill it " "and rerun".format(md_dict['sample_name'])) # validate crossed scan if crossed and (not dx or not dy): raise xpdAcqException( "dx and dy must both be provided if crossed is set to True") # construct scan plan for md_dict in spreadsheet_parser.parsed_sa_md_list: expo = float(md_dict['exposure_time(s)']) # setting up area_detector yield from _configure_area_det(expo) expo_md = calc_expo_md(dets[0], expo) # inject md for each sample full_md = dict(_md) full_md.update(expo_md) full_md.update(md_dict) # Manually open shutter before collecting. See the reason # stated below. # main plan x_center = float(md_dict['x-position']) y_center = float(md_dict['y-position']) yield from bps.mv(x_motor, x_center) yield from bps.mv(y_motor, y_center) yield from count_dets(dets, full_md) # no crossed if crossed: x_traj = [-dx + x_center, x_center + dx, x_center, x_center] y_traj = [y_center, y_center, y_center + dy, y_center - dy] for x_setpoint, y_setpoint in zip(x_traj, y_traj): yield from bps.mv(x_motor, x_setpoint) yield from bps.mv(y_motor, y_setpoint) full_md['x-position'] = x_setpoint full_md['y-position'] = y_setpoint yield from count_dets(dets, full_md) # use specified sleep time -> avoid residual from the calibrant yield from bps.sleep(wait_time)
def fly_body(): yield from bps.mv(xy_fly_stage.x, xstart, xy_fly_stage.y, ystart) # This part is not necessary to be here. revised by YDu for v in ["p1600=0", "p1600=1"]: yield from bps.mv(dtt, v) yield from bps.sleep(0.1) @bpp.stage_decorator([x for x in [xspress3] if x is not None]) def fly_row(): # go to start of row target_y = ystart + y * a_ystep_size yield from bps.mv(xy_fly_stage.x, xstart, xy_fly_stage.y, target_y) yield from bps.mv(y_centers, np.ones(num_xpixels) * target_y) # set the fly speed # ret = yield from bps.read(xy_fly_stage.z.user_readback) # (in mm) # revised by YDu, no such value before #yield from bps.sleep(0) # zpos = ( # ret[xy_fly_stage.z.user_readback.name]["value"] # if ret is not None # else 0 # ) # yield from bps.mov(z_centers, np.ones(num_xpixels) * zpos) yield from bps.mv(xy_fly_stage.x.velocity, flyspeed) yield from bps.trigger_and_read([xy_fly_stage], name="row_ends") # arm the struck yield from bps.trigger(sclr, group=f"fly_row_{y}") # maybe start the xspress3 if xspress3 is not None: yield from bps.trigger(xspress3, group=f"fly_row_{y}") # revised by YDu, use to be 0.1 yield from bps.sleep(1.5) # fly the motor yield from bps.abs_set(xy_fly_stage.x, xstop + a_xstep_size, group=f"fly_row_{y}") yield from bps.wait(group=f"fly_row_{y}") # yield from bps.trigger_and_read([xy_fly_stage], name="row_ends") yield from bps.mv(xy_fly_stage.x.velocity, 5.0) # revised by YDu, use to be 0.1 yield from bps.sleep(0.1) # read and save the struck yield from bps.create(name="primary") # yield from bps.read(sclr) yield from bps.read(mono) yield from bps.read(x_centers) yield from bps.read(y_centers) yield from bps.read(z_centers) yield from bps.read(xy_fly_stage.y) yield from bps.read(xy_fly_stage.z) # and maybe the xspress3 if xspress3 is not None: yield from bps.read(xspress3) yield from bps.sleep(0.2) yield from bps.save() yield from bps.sleep(0.2) # if 5 - abs(xstop - xstart)/5 > 0: # #print(5 - abs(xstop - xstart)/5) # time.sleep(5.3 - abs(xstop - xstart)/5) for y in range(num_ypixels): if xspress3 is not None: yield from bps.mv(xspress3.fly_next, True) yield from fly_row()
def sleepy_scan(): yield from checkpoint() yield from sleep(0.2)
def remote_ops(self, *args, **kwargs): """ Bluesky plan to enable PV-directed data collection To start the automatic data collection plan: RE(auto_collect.remote_ops()) The plan will exit when: * `permit` is not "yes" or 1 * user types `^C` twice (user types `RE.abort()` then) * unhandled exception The plan will collect data when `trigger_signal` goes to "start" or 1. `trigger_signal` immediately goes back to "stop" or 0. The command to be run is in `commands` which is: * a named command defined here * a command file in the present working directory """ yield from bps.mv(self.permit, "yes") yield from bps.sleep(1) logger.info("auto_collect is waiting for user commands") while self.permit.get() in (1, "yes"): if self.trigger_signal.get() in (1, "start"): print() # next line if emerging from idle_reporter() logger.debug("starting user commands") yield from bps.mv(self.trigger_signal, 0) command = self.commands.get() try: if command == "preUSAXStune": yield from bps.mv( user_data.collection_in_progress, 1, ) yield from preUSAXStune() yield from bps.mv( user_data.collection_in_progress, 0, ) elif command == "useModeRadiography": yield from bps.mv( user_data.collection_in_progress, 1, ) yield from mode_Radiography() yield from bps.mv( user_data.collection_in_progress, 0, ) elif os.path.exists(command): yield from run_command_file(command) else: logger.warning("unrecognized command: %s", command) except Exception as exc: logger.warn( "Exception during execution of command %s:\n%s", command, str(exc)) logger.info("waiting for next user command") else: yield from bps.sleep(self.idle_interval) idle_reporter() print() # next line if emerging from idle_reporter() logger.info("auto_collect is ending")
def fly_each_step(motor, step, row_start, row_stop): def move_to_start_fly(): "See http://nsls-ii.github.io/bluesky/plans.html#the-per-step-hook" # row_str = short_uid('row') # yield from abs_set(xmotor, row_start, group=row_str) # yield from one_1d_step([temp_nanoKB], motor, step) # yield from bps.wait(group=row_str) print(f"Start moving to beginning of the row") row_str = short_uid('row') yield from bps.checkpoint() yield from bps.abs_set(xmotor, row_start, group=row_str) yield from bps.abs_set(motor, step, group=row_str) yield from bps.wait(group=row_str) # yield from bps.trigger_and_read([temp_nanoKB, motor]) ## Uncomment this print(f"Finished moving to the beginning of the row") print(f"Fast axis: {xmotor.read()} Slow axis: {motor.read()}") if verbose: t_mvstartfly = tic() yield from move_to_start_fly() # TODO Why are we re-trying the move? This should be fixed at # a lower level # yield from bps.sleep(1.0) # wait for the "x motor" to move x_set = row_start x_dial = xmotor.user_readback.get() # Get retry deadband value and check against that i = 0 DEADBAND = 0.050 # retry deadband of nPoint scanner while (np.abs(x_set - x_dial) > DEADBAND): if (i == 0): print('Waiting for motor to reach starting position...', end='', flush=True) i = i + 1 yield from mv(xmotor, row_start) yield from bps.sleep(0.1) x_dial = xmotor.user_readback.get() if (i != 0): print('done') if verbose: toc(t_mvstartfly, str='Move to start fly each') # Set the scan speed # Is abs_set(wait=True) or mv() faster? v = ((xstop - xstart) / (xnum - 1)) / dwell # compute "stage speed" # yield from abs_set(xmotor.velocity, v, wait=True) # set the "stage speed" # if (v > xmotor.velocity.high_limit): # raise ValueError(f'Desired motor velocity too high\nMax velocity: {xmotor.velocity.high_limit}') # elif (v < xmotor.velocity.low_limit): # raise ValueError(f'Desired motor velocity too low\nMin velocity: {xmotor.velocity.low_limit}') # else: # yield from mv(xmotor.velocity, v) yield from mv(xmotor.velocity, v) # set up all of the detectors # TODO we should be able to move this out of the per-line call?! # if ('xs' in dets_by_name): # xs = dets_by_name['xs'] # yield from abs_set(xs.hdf5.num_capture, xnum, group='set') # yield from abs_set(xs.settings.num_images, xnum, group='set') # yield from bps.wait(group='set') # # yield from mv(xs.hdf5.num_capture, xnum, # # xs.settings.num_images, xnum) # # xs.hdf5.num_capture.put(xnum) # # xs.settings.num_images.put(xnum) # if ('xs2' in dets_by_name): # xs2 = dets_by_name['xs2'] # # yield from abs_set(xs2.hdf5.num_capture, xnum, wait=True) # # yield from abs_set(xs2.settings.num_images, xnum, wait=True) # yield from mv(xs2.hdf5.num_capture, xnum, # xs2.settings.num_images, xnum) # if ('merlin' in dets_by_name): # merlin = dets_by_name['merlin'] # yield from abs_set(merlin.hdf5.num_capture, xnum, wait=True) # yield from abs_set(merlin.cam.num_images, xnum, wait=True) # if ('dexela' in dets_by_name): # dexela = dets_by_name['dexela'] # yield from abs_set(dexela.hdf5.num_capture, xnum, wait=True) # # yield from abs_set(dexela.hdf5.num_frames_chunks, xnum, wait=True) # yield from abs_set(dexela.cam.num_images, xnum, wait=True) ion = flying_zebra.sclr if ion: yield from abs_set(ion.nuse_all, 2 * xnum) # arm the Zebra (start caching x positions) # @timer_wrapper def zebra_kickoff(): # start_zebra, stop_zebra = xstart * 1000000, xstop * 1000000 start_zebra, stop_zebra = xstart, xstop if row_start < row_stop: yield from kickoff(flying_zebra, xstart=start_zebra, xstop=stop_zebra, xnum=xnum, dwell=dwell, wait=True) else: yield from kickoff(flying_zebra, xstart=stop_zebra, xstop=start_zebra, xnum=xnum, dwell=dwell, wait=True) if verbose: t_zebkickoff = tic() yield from zebra_kickoff() if verbose: toc(t_zebkickoff, str='Zebra kickoff') if verbose: t_datacollect = tic() # arm SIS3820, note that there is a 1 sec delay in setting X # into motion so the first point *in each row* won't # normalize... if ion: yield from abs_set(ion.erase_start, 1) if verbose: toc(t_datacollect, str=' reset scaler') # trigger all of the detectors row_str = short_uid('row') if verbose: print('Data collection:') for d in flying_zebra.detectors: if verbose: print(f' triggering {d.name}') st = yield from bps.trigger(d, group=row_str) st.add_callback(lambda x: toc( t_datacollect, str= f" status object {datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S.%f')}" )) if (d.name == 'dexela'): yield from bps.sleep(1) if verbose: toc(t_datacollect, str=' trigger detectors') # yield from bps.sleep(1.5) if verbose: toc(t_datacollect, str=' sleep') # start the 'fly' def print_watch(*args, **kwargs): with open('~/bluesky_output.txt', 'a') as f: f.write( datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S.%f\n')) # print(args) f.write(json.dumps(kwargs)) f.write('\n') st = yield from abs_set(xmotor, row_stop, group=row_str) # st.watch(print_watch) if verbose: toc(t_datacollect, str=' move start') if verbose and False: ttime.sleep(1) while (xmotor.motor_is_moving.get()): ttime.sleep(0.001) toc(t_datacollect, str=' move end') while (xs.settings.detector_state.get()): ttime.sleep(0.001) toc(t_datacollect, str=' xs done') while (sclr1.acquiring.get()): ttime.sleep(0.001) toc(t_datacollect, str=' sclr1 done') # wait for the motor and detectors to all agree they are done yield from bps.wait(group=row_str) st.wait() if verbose: toc(t_datacollect, str='Total time') # we still know about ion from above if ion: yield from abs_set(ion.stop_all, 1) # stop acquiring scaler print(f"Resetting scanner velocity") # set speed back reset_scanner_velocity() print(f"Completed resetting scanner velocity") # @timer_wrapper def zebra_complete(): yield from complete(flying_zebra) # tell the Zebra we are done if verbose: t_zebcomplete = tic() yield from zebra_complete() if verbose: toc(t_zebcomplete, str='Zebra complete') print(f"'zebra_complete' finished") # @timer_wrapper def zebra_collect(): yield from collect(flying_zebra) # extract data from Zebra if verbose: t_zebcollect = tic() yield from zebra_collect() if verbose: toc(t_zebcollect, str='Zebra collect') print(f"'zebra_collect' finished") print(f"Step is completed")
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.abs_set(diag3_y, sample_props['diag3_y'], 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.mov(au_mesh, e_scan_params['au_mesh']) # yield from bps.mov(appes_t, sample_props['pos_theta']) yield from bps.abs_set(feedback, 0, wait=True) yield from bps.abs_set(pgm_energy, e_scan_params['e_align'], 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(5) # 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 bps.abs_set(pd_sclr_gain, det_settings['pd_gain'], wait=True) yield from bps.abs_set(pd_sclr_decade, det_settings['pd_decade'], 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) yield from bps.abs_set(sample_sclr_decade, det_settings['sampledecade'], wait=True) yield from bps.abs_set(aumesh_sclr_decade, det_settings['aumeshdecade'], wait=True) yield from bps.abs_set(pd_sclr_decade, det_settings['pd_decade'], 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.abs_set(ioxas_x, tmp_pos, wait=True) yield from bps.abs_set(feedback, 0, wait=True) yield from bps.abs_set(pgm_energy, e_scan_params['e_align'], 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(20) # 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(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 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 _sim_plan_inner(npts: int, delay: float = 1.0): for j in range(npts): yield from bps.mov(motor1, j * 0.1 + 1, motor2, j * 0.2 - 2) yield from bps.trigger_and_read([motor1, motor2, det2]) yield from bps.sleep(delay)
def infinite_plan(): while True: yield from sleep(3) yield from count([noisy_det], 20, delay=0.5) yield from count([random_img], 10, delay=1)
def xy_fly( scan_title, *, beamline_operator, dwell_time, xstart, xstop, xstep_size, ystart, ystop, ystep_size=None, xspress3=None, ): """Do a x-y fly scan. The x-motor is the 'fast' direction. Parameters ---------- scan_title : str A name for the scan. beamline_operator : str The individual responsible for this scan. Appears in output directory path. dwell_time : float Target time is s on each pixel xstart, xstop : float The start and stop values in the fast direction in mm xstep_size : xstep_size is step of x movement ystart, ystop : float The start and stop values in the slow direction in mm ystep_size : ystep_size use xstep_size if it isn't passed in scan_title : str Title of scan, required. """ xy_fly_stage = xy_stage _validate_motor_limits(xy_fly_stage.x, xstart, xstop, "x") _validate_motor_limits(xy_fly_stage.y, ystart, ystop, "y") ystep_size = ystep_size if ystep_size is not None else xstep_size assert dwell_time > 0, f"dwell_time ({dwell_time}) must be more than 0" assert xstep_size > 0, f"xstep_size ({xstep_size}) must be more than 0" assert ystep_size > 0, f"ystep_size ({ystep_size}) must be more than 0" ret = yield from bps.read(xy_fly_stage.x.mres) # (in mm) xmres = ret[ xy_fly_stage.x.mres.name]["value"] if ret is not None else 0.0003125 ret = yield from bps.read(xy_fly_stage.y.mres) # (in mm) ymres = ret[ xy_fly_stage.y.mres.name]["value"] if ret is not None else 0.0003125 prescale = int(np.floor((xstep_size / (5 * xmres)))) a_xstep_size = prescale * (5 * xmres) a_ystep_size = int(np.floor((ystep_size / (ymres)))) * ymres num_xpixels = int(np.floor((xstop - xstart) / a_xstep_size)) num_ypixels = int(np.floor((ystop - ystart) / a_ystep_size)) yield from bps.mv( x_centers, a_xstep_size / 2 + xstart + np.arange(num_xpixels) * a_xstep_size) # SRX original roi_key = getattr(xs.channel1.rois, roi_name).value.name roi_livegrid_key = xs.channel1.rois.roi01.value.name fig = plt.figure("xs") fig.clf() roi_livegrid = LiveGrid( (num_ypixels + 1, num_xpixels + 1), roi_livegrid_key, clim=None, cmap="inferno", xlabel="x (mm)", ylabel="y (mm)", extent=[xstart, xstop, ystart, ystop], x_positive="right", y_positive="down", ax=fig.gca(), ) flyspeed = a_xstep_size / dwell_time # this is in mm/s try: xy_fly_stage.x.velocity.check_value(flyspeed) except LimitError as e: raise LimitError(f"You requested a range of {xstop - xstart} with " f"{num_xpixels} pixels and a dwell time of " f"{dwell_time}. This requires a " f"motor velocity of {flyspeed} which " "is out of range.") from e # set up delta-tau trigger to fast motor for v in ["p1600=0", "p1607=1", "p1600=1"]: yield from bps.mv(dtt, v) yield from bps.sleep(0.1) # TODO make this a message? sclr.set_mode("flying") # poke the struck settings yield from bps.mv(sclr.mcas.prescale, prescale) yield from bps.mv(sclr.mcas.nuse, num_xpixels) if xspress3 is not None: yield from bps.mv(xs.external_trig, True) yield from bps.mv(xspress3.total_points, num_xpixels) yield from bps.mv(xspress3.hdf5.num_capture, num_xpixels) yield from bps.mv(xspress3.settings.num_images, num_xpixels) @bpp.reset_positions_decorator([xy_fly_stage.x, xy_fly_stage.y]) @bpp.subs_decorator({"all": [roi_livegrid]}) @bpp.monitor_during_decorator([xs.channel1.rois.roi01.value]) @bpp.stage_decorator([sclr]) @bpp.baseline_decorator([mono, xy_fly_stage]) # TODO put is other meta data @bpp.run_decorator( md={ "scan_title": scan_title, "operator": beamline_operator, "user_input": { "dwell_time": dwell_time, "xstart": xstart, "xstop": xstop, "xstep_size": xstep_size, "ystart": ystart, "ystep_size": ystep_size, }, "derived_input": { "actual_ystep_size": a_ystep_size, "actual_xstep_size": a_xstep_size, "fly_velocity": flyspeed, "xpixels": num_xpixels, "ypixels": num_ypixels, "prescale": prescale, }, }) def fly_body(): yield from bps.mv(xy_fly_stage.x, xstart, xy_fly_stage.y, ystart) @bpp.stage_decorator([x for x in [xspress3] if x is not None]) def fly_row(): # go to start of row target_y = ystart + y * a_ystep_size yield from bps.mv(xy_fly_stage.x, xstart, xy_fly_stage.y, target_y) yield from bps.mv(y_centers, np.ones(num_xpixels) * target_y) # set the fly speed ret = yield from bps.read(xy_fly_stage.z.user_readback) # (in mm) zpos = (ret[xy_fly_stage.z.user_readback.name]["value"] if ret is not None else 0) yield from bps.mov(z_centers, np.ones(num_xpixels) * zpos) yield from bps.mv(xy_fly_stage.x.velocity, flyspeed) yield from bps.trigger_and_read([xy_fly_stage], name="row_ends") for v in ["p1600=0", "p1600=1"]: yield from bps.mv(dtt, v) yield from bps.sleep(0.1) # arm the struck yield from bps.trigger(sclr, group=f"fly_row_{y}") # maybe start the xspress3 if xspress3 is not None: yield from bps.trigger(xspress3, group=f"fly_row_{y}") yield from bps.sleep(0.1) # fly the motor yield from bps.abs_set(xy_fly_stage.x, xstop + a_xstep_size, group=f"fly_row_{y}") yield from bps.wait(group=f"fly_row_{y}") yield from bps.trigger_and_read([xy_fly_stage], name="row_ends") yield from bps.mv(xy_fly_stage.x.velocity, 5.0) yield from bps.sleep(0.1) # read and save the struck yield from bps.create(name="primary") # yield from bps.read(sclr) yield from bps.read(mono) yield from bps.read(x_centers) yield from bps.read(y_centers) yield from bps.read(z_centers) yield from bps.read(xy_fly_stage.y) yield from bps.read(xy_fly_stage.z) # and maybe the xspress3 if xspress3 is not None: yield from bps.read(xspress3) yield from bps.save() for y in range(num_ypixels): if xspress3 is not None: yield from bps.mv(xspress3.fly_next, True) yield from fly_row() yield from fly_body() # save the start document to a file for the benefit of the user start = db[-1].start dt = datetime.datetime.fromtimestamp(start["time"]) filepath = os.path.expanduser( f"~/Users/Data/{start['operator']}/{dt.date().isoformat()}/xy_fly/" f"{start['scan_title']}-{start['scan_id']}-{start['operator']}-{dt.time().isoformat()}.log" ) os.makedirs(os.path.dirname(filepath), exist_ok=True) with open(filepath, "wt") as output_file: output_file.write(pprint.pformat(start))
def plan(): yield from fly_during_wrapper(run_wrapper(sleep(1)), [seq])
def autoplan(bt: Beamtime, sample_index, plan_index, wait_time=30., auto_shutter=False): """ Yield messages to count the predefined measurement plan on the a list of samples on a sample rack. It requires the following information to be added for each sample. position_x The x position of the sample in mm. position_y The y position of the sample in mm. wait_time The waiting time between the end of the former plan and the start of the latter plan in second. Parameters ---------- bt: Beamtime The Beamtime instance that contains the sample information. sample_index : List[int] A list of the sample index in the BeamTime instance. plan_index: List[int] A list of the plan index in the BeamTime instance. wait_time : float Waiting time before conduct plan for each sample in second. auto_shutter : bool Whether to mutate the plan with inner_shutter_control. Yields ------ Msg Messages of the plan. Examples -------- Add position controller to the xpd_configuration. >>> xpd_configuration["posx_controller"] = Grid_X >>> xpd_configuration["posy_controller"] = Grid_Y Register the scan plan to the beamtime. >>> ScanPlan(bt, ct, 30) Add the information of 'position_x', 'position_y' and 'wait_time' to the excel and import. Automatically conduct the scan plan for sample No.0 and No.1 >>> plan = autoplan(bt, [0, 1]) >>> xrun({}, plan) """ posx_controller = xpd_configuration["posx_controller"] posy_controller = xpd_configuration["posy_controller"] for sample_ind, plan_ind in zip(sample_index, plan_index): sample = translate_to_sample(bt, int(sample_ind)) posx = mg.get_from_sample(sample, "position_x") posy = mg.get_from_sample(sample, "position_y") count_plan = mg.translate_to_plan(bt, int(plan_ind), sample) if auto_shutter: count_plan = plan_mutator(count_plan, inner_shutter_control) if posx and posy and count_plan: yield from checkpoint() print(f"INFO: Move to x: {posx}") yield from mv(posx_controller, float(posx)) yield from checkpoint() print(f"INFO: Move to y: {posy}") yield from mv(posy_controller, float(posy)) yield from checkpoint() yield from wait() print(f"INFO: Wait for {wait_time} s") yield from sleep(float(wait_time)) yield from checkpoint() yield from count_plan
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