def insert_take_dark(msg): now = time.time() nonlocal need_dark qualified_dark_uid = _validate_dark(expire_time=glbl.dk_window) # FIXME: should we do "or" or "and"? if (not need_dark) and (not qualified_dark_uid): need_dark = True if need_dark \ and (not qualified_dark_uid) \ and msg.command == 'open_run' \ and ('dark_frame' not in msg.kwargs): # We are about to start a new 'run' (e.g., a count or a scan). # Insert a dark frame run first. need_dark = False # Annoying detail: the detector was probably already staged. # Unstage it (if it wasn't staged, nothing will happen) and # then take_dark() and then re-stage it. return bp.pchain(bp.unstage(glbl.area_det), take_dark(), bp.stage(glbl.area_det), bp.single_gen(msg), bp.abs_set(glbl.shutter, 60, wait=True)), None elif msg.command == 'open_run' and 'dark_frame' not in msg.kwargs: return bp.pchain(bp.single_gen(msg), bp.abs_set(glbl.shutter, 60, wait=True)), None else: # do nothing if (not need_dark) return None, None
def take_dark(): """a plan for taking a single dark frame""" print('INFO: closing shutter...') yield from bp.abs_set(glbl.shutter, 0) if glbl.shutter_control: yield from bp.sleep(2) print('INFO: taking dark frame....') # upto this stage, glbl.pe1c has been configured to so exposure time is # correct acq_time = glbl.area_det.cam.acquire_time.get() num_frame = glbl.area_det.images_per_set.get() computed_exposure = acq_time * num_frame # update md _md = {'sp_time_per_frame': acq_time, 'sp_num_frames': num_frame, 'sp_computed_exposure': computed_exposure, 'sp_type': 'ct', # 'sp_uid': str(uuid.uuid4()), # dark plan doesn't need uid 'sp_plan_name': 'dark_{}'.format(computed_exposure), 'dark_frame': True} c = bp.count([glbl.area_det], md=_md) yield from bp.subs_wrapper(c, {'stop': [_update_dark_dict_list]}) print('opening shutter...') yield from bp.abs_set(glbl.shutter, 1) if glbl.shutter_control: yield from bp.sleep(2)
def test_sigint_manyhits(fresh_RE, motor_det): motor, det = motor_det motor._fake_sleep = 0.3 RE = fresh_RE pid = os.getpid() def sim_kill(n=1): for j in range(n): print('KILL') os.kill(pid, signal.SIGINT) lp = RE.loop motor.loop = lp lp.call_later(.02, sim_kill, 3) lp.call_later(.02, sim_kill, 3) lp.call_later(.02, sim_kill, 3) start_time = ttime.time() RE(bp.finalize_wrapper(bp.abs_set(motor, 1, wait=True), bp.abs_set(motor, 0, wait=True))) end_time = ttime.time() assert end_time - start_time < 0.2 # not enough time for motor to cleanup RE.abort() # now cleanup done_cleanup_time = ttime.time() assert done_cleanup_time - end_time > 0.3
def test_sigint_three_hits(fresh_RE, motor_det): motor, det = motor_det motor._fake_sleep = 0.3 RE = fresh_RE pid = os.getpid() def sim_kill(n=1): for j in range(n): print('KILL') os.kill(pid, signal.SIGINT) lp = RE.loop motor.loop = lp lp.call_later(.02, sim_kill, 3) lp.call_later(.02, sim_kill, 3) lp.call_later(.02, sim_kill, 3) start_time = ttime.time() RE( bp.finalize_wrapper(bp.abs_set(motor, 1, wait=True), bp.abs_set(motor, 0, wait=True))) end_time = ttime.time() assert end_time - start_time < 0.2 # not enough time for motor to cleanup RE.abort() # now cleanup done_cleanup_time = ttime.time() assert done_cleanup_time - end_time > 0.3
def inner(): # Prepare TIFF plugin if filepath is not None and filename is not None: fp = filepath if fp[-1] != '/': fp+= '/' print("Saving files as", "".join((fp, filename, "_XXX.tif"))) print("First file number:", cam_8.tiff.file_number.get()) yield from bp.mv( tiff.enable, 1, tiff.auto_increment, 1, tiff.file_path, fp, tiff.file_name, filename, tiff.file_template, "%s%s_%3.3d.tif", tiff.file_write_mode, 1, # Capture mode tiff.num_capture, steps, ) # Prepare statistics plugin yield from bp.mv( stats.enable, 1, stats.compute_centroid, 1 ) # Prepare Camera yield from bp.mv(cam.acquire, 0) # Stop camera... yield from bp.sleep(.5) # ...and wait for the pipeline to empty. yield from bp.mv( cam.trigger_mode, "Sync In 1", # External Trigger cam.array_counter, 0, ) yield from bp.abs_set(cam.acquire, 1) # wait=False yield from bp.abs_set(tiff.capture, 1) # Move to the starting positions yield from bp.mv( slt_gap, gap, # Move gap to desired position slt_ctr, start - move_slack, # Move slits to the beginning of the motion stats.ts_control, "Erase/Start", # Prepare statistics Time Series ) # Set Slits Center velocity for the scan yield from bp.mv(slt_ctr.velocity, speed) # Go yield from bp.kickoff(flyer, wait=True) st = yield from bp.complete(flyer) yield from bp.abs_set(slt_ctr, end + move_slack) while not st.done: yield from bp.collect(flyer, stream=True) yield from bp.sleep(0.2) yield from bp.sleep(1) yield from bp.collect(flyer, stream=True) yield from bp.mv(stats.ts_control, "Stop")
def take_dark(): """a plan for taking a single dark frame""" print('INFO: closing shutter...') # 60 means open at XPD, Oct.4, 2016 yield from bp.abs_set(glbl.shutter, 0, wait=True) #if glbl.shutter_control: # yield from bp.sleep(2) print('INFO: taking dark frame....') # upto this stage, glbl.pe1c has been configured to so exposure time is # correct acq_time = glbl.area_det.cam.acquire_time.get() num_frame = glbl.area_det.images_per_set.get() computed_exposure = acq_time * num_frame # update md _md = { 'sp_time_per_frame': acq_time, 'sp_num_frames': num_frame, 'sp_computed_exposure': computed_exposure, 'sp_type': 'ct', # 'sp_uid': str(uuid.uuid4()), # dark plan doesn't need uid 'sp_plan_name': 'dark_{}'.format(computed_exposure), 'dark_frame': True } c = bp.count([glbl.area_det], md=_md) yield from bp.subs_wrapper(c, {'stop': [_update_dark_dict_list]}) print('opening shutter...')
def plan(): while True: for step in np.linspace(start, stop, num): yield from abs_set(motor, step, wait=True) yield from trigger_and_read(list(detectors) + [motor]) err = errorbar(lf.result, 'sigma') if err < .03: break
def continuous_step_scan(mymotor, motor_min, motor_max, motor_step, collection_time): "Step mymotor, produce a single file." # Move to start position yield from abs_set(mymotor, motor_min, wait=True) # Start yield from bp.kickoff(detector, wait=True) # and immediately pause yield from bp.pause(detector, wait=True) for num in range(motor_min, motor_max, motor_step): yield from abs_set(mymotor, num, wait=True) yield from abs_set(bs_adned_reset_counters, 1, wait=True) yield from bp.resume(detector, wait=True) yield from bp.sleep(collection_time) yield from bp.pause(detector, wait=True) yield from bp.complete(detector, wait=True) yield from bp.collect(detector)
def step_scan_pcharge(mymotor, motor_min, motor_max, motor_step, pcharge): "Step mymotor from min -> max with a step size of step and collect for a given pcharge" for num in np.arange(motor_min, motor_max, motor_step): yield from abs_set(mymotor, num, wait=True) yield from bp.kickoff(detector, wait=True) yield from _waitfor_proton_charge(pcharge) yield from bp.complete(detector, wait=True) yield from bp.collect(detector) yield from bp.trigger_and_read([mymotor, bs_neutrons_roi, bs_pcharge])
def slit_scan_fiducialize(slits, yag, x_width=0.01, y_width=0.01, samples=10, filters=None, centroid='detector_stats2_centroid_y'): """ Assists beam alignment by setting the slits to a w,h and checking, returning the centroid position. Parameters ---------- slits : pcdsdevices.slits.Slits Ophyd slits object from pcdsdevices.slits.Slits yag : pcdsdevices.pim.PIM Detector to fidicuialize. This plan assumes the detector is stated and inserted x_width : float x dimensions of the gap in the slits. EGU: mm y_width : float y dimensions of the gap in the slits. EGU: mm samples : int Returned measurements are averages over multiple samples. samples arg determines the number of samples to average over for returned data filters : dict, optional Key, callable pairs of event keys and single input functions that evaluate to True or False. For more infromation see :meth:`.apply_filters` centroid : str, optional Key to gather centroid information Returns ------- float return centroid position in pixel space, single axis """ #Set slits yield from abs_set(slits, x_width, wait=True) #Collect data from yags yag_measurements = yield from measure_average([yag], num=samples, filters=filters) #Extract centroid positions from yag_measurments dict centroid = yag_measurements[field_prepend(centroid, yag)] return centroid
def Gas_Plan(gas_in='He', liveplot_key=None, totExpTime=5, num_exp=1, delay=1): """ Example ------- Set the gasses. They can be in any other, nothing to do with the order they are used in the plan. But, should match the connections on switch. >>> gas.gas_list = ['He', 'N2', 'CO2'] >>> RGA mass is set to different value, base shows 1^-13 with He 5 cc flow shows max 2^-8 >>> RGA mass setup in mID mode: 4,18,28,31,44,79,94,32,81 Parameters ---------- gas_in : string e.g., 'He', default is 'He' These gas must be in `gas.gas_list` but they may be in any order. liveplot_key : str, optional e. g., liveplot_key = rga_mass1 data key for LivePlot. default is None, which means no LivePlot totExpTime : float total exposure time per frame in seconds. Dafault value is 5 sec num_exp : int number of images/exposure, default is 1 delay: float delay time between exposures in sec Execute it ---------- >> %run -i /home/xf28id1/Documents/Sanjit/Scripts/GasXrun_Plan.py >> change all the parameters inside Gas_Plan as required >>> gas_plan = Gas_Plan(gas_in = 'He', liveplot_key= 'rga_mass1', totExpTime = 5, num_exp = 3, delay = 1) >> to run the xrun, save metadata & save_tiff run the following >>> run_and_save(sample_num = 0) """ ## switch gas yield from abs_set(gas, gas_in) ## configure the exposure time first _configure_area_det(totExpTime) # 5 secs exposuretime ## ScanPlan you need plan = bp.count([pe1c, gas.current_gas, rga], num=num_exp, delay=delay) #plan = bp.subs_wrapper(plan, LiveTable([xpd_configuration['area_det'], rga])) # give you LiveTable plan = bp.subs_wrapper( plan, LiveTable([xpd_configuration['area_det'], gas.current_gas, rga])) if liveplot_key and isinstance(liveplot_key, str): plan = bp.subs_wrapper(plan, LivePlot(liveplot_key)) yield from plan
def test_dets_shutter(db, tmp_dir, name, fp): det = det_factory(name, db.fs, fp, save_path=tmp_dir, shutter=shctl1) RE = setup_test_run_engine() RE.subscribe('all', db.mds.insert) scan = Count([det], ) db.fs.register_handler('RWFS_NPY', be.ReaderWithFSHandler) cycle2 = build_image_cycle(fp) cg = cycle2() # With the shutter down RE(abs_set(shctl1, 0, wait=True)) uid = RE(scan) for n, d in db.restream(db[-1], fill=True): if n == 'event': assert_array_equal(d['data']['pe1_image'], np.zeros(next(cg)['pe1_image'].shape)) assert uid is not None # With the shutter up RE(abs_set(shctl1, 1, wait=True)) uid = RE(scan) for n, d in db.restream(db[-1], fill=True): if n == 'event': assert_array_equal(d['data']['pe1_image'], next(cg)['pe1_image']) assert uid is not None
def get_ID_calibration_dan(gapstart,gapstop,gapstep=.2,gapoff=0): """ by LW 04/20/2015 function to automatically take a ID calibration curve_fit calling sequence: get_ID_calibration(gapstart,gapstop,gapstep=.2,gapoff=0) gapstart: minimum gap used in calibration (if <5.2, value will be set to 5.2) gapstop: maximum gap used in calibration gapstep: size of steps between two gap points gapoff: offset applied to calculation gap vs. energy from xfuncs.get_Es(gap-gapoff) thermal management of Bragg motor is automatic, waiting for cooling <80C between Bragg scans writes outputfile with fitted value for the center of the Bragg scan to: '/home/xf11id/Repos/chxtools/chxtools/X-ray_database/ changes 03/18/2016: made compatible with python V3 and latest versio of bluesky (working on it!!!) """ import numpy as np #import xfuncs as xf #from dataportal import DataBroker as db, StepScan as ss, DataMuxer as dm import time from epics import caput, caget from matplotlib import pyplot as plt from scipy.optimize import curve_fit gaps = np.arange(gapstart, gapstop, gapstep) - gapoff # not sure this should be '+' or '-' ... print('ID calibration will contain the following gaps [mm]: ',gaps) xtal_map = {1: 'Si111cryo', 2: 'Si220cryo'} pos_sts_pv = 'XF:11IDA-OP{Mono:DCM-Ax:X}Pos-Sts' try: xtal = xtal_map[caget(pos_sts_pv)] except KeyError: raise CHX_utilities_Exception('error: trying to do ID gap calibration with no crystal in the beam') print('using', xtal, 'for ID gap calibration') # create file for writing calibration data: fn='id_CHX_IVU20_'+str(time.strftime("%m"))+str(time.strftime("%d"))+str(time.strftime("%Y"))+'.dat' fpath='/tmp/' # fpath='/home/xf11id/Repos/chxtools/chxtools/X-ray_database/' try: outFile = open(fpath+fn, 'w') outFile.write('% data from measurements '+str(time.strftime("%D"))+'\n') outFile.write('% K colkumn is a placeholder! \n') outFile.write('% ID gap [mm] K E_1 [keV] \n') outFile.close() print('successfully created outputfile: ',fpath+fn) except: raise CHX_utilities_Exception('error: could not create output file') ### do the scanning and data fitting, file writing,.... t_adjust=0 center=[] E1=[] realgap=[] detselect(xray_eye1) print(gaps) MIN_GAP = 5.2 for i in gaps: if i >= MIN_GAP: B_guess=-1.0*xf.get_Bragg(xtal,xf.get_Es(i+gapoff,5)[1])[0] else: i = MIN_GAP B_guess=-1.0*xf.get_Bragg(xtal,xf.get_Es(i,5)[1])[0] if i > 8 and t_adjust == 0: # adjust acquistion time once while opening the gap (could write something more intelligent in the long run...) exptime=caget('XF:11IDA-BI{Bpm:1-Cam:1}cam1:AcquireTime') caput('XF:11IDA-BI{Bpm:1-Cam:1}cam1:AcquireTime',2*exptime) t_adjust = 1 print('initial guess: Bragg= ',B_guess,' deg. ID gap = ',i,' mm') es = xf.get_Es(i, 5)[1] mirror_stripe_pos = round(caget('XF:11IDA-OP{Mir:HDM-Ax:Y}Mtr.VAL'),1) SI_STRIPE = -7.5 RH_STRIPE = 7.5 if es < 9.5: stripe = SI_STRIPE elif es >= 9.5: stripe = RH_STRIPE yield from bp.abs_set(hdm.y, stripe) yield from bp.abs_set(foil_y, 0) # Put YAG in beam. print('moving DCM Bragg angle to:', B_guess ,'deg and ID gap to', i, 'mm') yield from bp.abs_set(dcm.b, B_guess) yield from bp.abs_set(ivu_gap,i) print('hurray, made it up to here!') print('about to collect data') yield from ascan(dcm.b, float(B_guess-.4), float(B_guess+.4), 60, md={'plan_name': 'ID_calibration', 'mirror_stripe': stripe}) header = db[-1] #retrive the data (first data point is often "wrong", so don't use data = get_table(header) B = data.dcm_b[2:] intdat = data.xray_eye1_stats1_total[2:] B=np.array(B) intdat=np.array(intdat) A=np.max(intdat) # initial parameter guess and fitting xc=B[np.argmax(intdat)] w=.2 yo=np.mean(intdat) p0=[yo,A,xc,w] print('initial guess for fitting: ',p0) try: coeff,var_matrix = curve_fit(gauss,B,intdat,p0=p0) center.append(coeff[2]) E1.append(xf.get_EBragg(xtal,-coeff[2])/5.0) realgap.append(caget('SR:C11-ID:G1{IVU20:1-LEnc}Gap')) # # append data file by i, 1 & xf.get_EBragg(xtal,-coeff[2]/5.0): with open(fpath+fn, "a") as myfile: myfile.write(str(caget('SR:C11-ID:G1{IVU20:1-LEnc}Gap'))+' 1.0 '+str(float(xf.get_EBragg(xtal,-coeff[2])/5.0))+'\n') print('added data point: ',caget('SR:C11-ID:G1{IVU20:1-LEnc}Gap'),' ',1.0,' ',str(float(xf.get_EBragg(xtal,-coeff[2])/5.0))) except: print('could not evaluate data point for ID gap = ',i,' mm...data point skipped!') while caget('XF:11IDA-OP{Mono:DCM-Ax:Bragg}T-I') > 80: time.sleep(30) print('DCM Bragg axis too hot (>80C)...waiting...') plt.close(234) plt.figure(234) plt.plot(E1,realgap,'ro-') plt.xlabel('E_1 [keV]') plt.ylabel('ID gap [mm]') plt.title('ID gap calibration in file: '+fpath+fn,size=12) plt.grid()
def dwell(detectors, motor, step): yield from checkpoint() yield from bp.abs_set(motor, step, wait=True) yield from bp.sleep(sleep_time) return (yield from bp.trigger_and_read(list(detectors)+[motor]))
def slit_scan_area_comp(slits, yag, x_width=1.0, y_width=1.0, samples=1): """Find the ratio of real space/pixel in the PIM 1. Send slits to specified position 2. Measure pixel dimensions of passed light. The idea is that the width, height values will be pulled from the PIMPulnixDetector instance. 2b. Should diffraction issues (as observed with the test laser) persist when using the x-ray laser, another method will be necessary instead of using the gap dimensions for calibration, we could move the gap in the slits a small distance and observe the position change of the passed light. If the light is highly collimated (it should be), the motion of the gap should be 1:1 with the motion of the passed light on the PIM detector. Only investigate if issues persisit in x-ray. Parameters ---------- slits : pcdsdevices.slits.Slits Ophyd slits object from pcdsdevices.slits.Slits yag : pcdsdevices.sim.pim.PIM (subject to change?) Ophyd object of some type, this will allow me to read the w, h (w,h don't exist yet but they should shortly) x_width : int Define the target x width of the gap in the slits. Units: mm y_width : int Define the target y width of the gap in the slits. Units: mm samples : int number of sampels to use and average over when measuring width, height Returns ------- (float,float) returns a tuple of x and y scaling respectively. Units mm/pixels """ # place slits then read a value that doesn't exist yet # easy # measure_average() #data = yield from measure_average([yag],['xwidth','ywidth']) # set slits to specified gap size yield from abs_set(slits, x=x_width, y=y_width) # read profile dimensions from image (width plugin pending) yag_measurements = yield from measure_average([yag], num=samples) # extract measurements of interest from returned dict yag_measured_x_width = yag_measurements['xwidth'] yag_measured_y_width = yag_measurements['ywidth'] logger.debug("Measured x width: {}".format(yag_measured_x_width)) logger.debug("Measured y width: {}".format(yag_measured_y_width)) # err if image not received or image has 0 width,height if (yag_measured_x_width <= 0 \ or yag_measured_y_width <=0): raise ValueError("A measurement less than or equal to zero has been" "measured. Unable to calibrate") x_scaling = nan y_scaling = nan else: #data format: Real space / pixel x_scaling = x_width / yag_measured_x_width y_scaling = y_width / yag_measured_y_width return x_scaling, y_scaling
def prep_img_motors(n_mot, img_motors, prev_out=True, tail_in=True, timeout=None): """ Plan to prepare image motors for taking data. Moves the correct imagers in and waits for them to be ready. Parameters ---------- n_mot: int Index of the motor in img_motors that we need to take data with. img_motors: list of OphydObject OphydObjects to move in or out. These objects need to have .set methods that accept the strings "IN" and "OUT", reacting appropriately, and need to accept a "timeout" kwarg that allows their status to be set as done after a timeout. These should be ordered by increasing distance to the source. prev_out: bool, optional If True, pull out imagers closer to the source than the one we need to use. Default True. (True if imager blocks beam) tail_in: bool, optional If True, put in imagers after this one, to be ready for later. If False, don't touch them. We won't wait for the tail motors to move in. timeout: number, optional Only wait for this many seconds before moving on. Returns ------- ok: bool True if the wait succeeded, False otherwise. """ start_time = time.time() prev_img_mot = str(uuid.uuid4()) ok = True try: for i, mot in enumerate(img_motors): if i < n_mot and prev_out: if timeout is None: yield from abs_set(mot, "OUT", group=prev_img_mot) else: yield from abs_set(mot, "OUT", group=prev_img_mot, timeout=timeout) elif i == n_mot: if timeout is None: yield from abs_set(mot, "IN", group=prev_img_mot) else: yield from abs_set(mot, "IN", group=prev_img_mot, timeout=timeout) elif tail_in: yield from abs_set(mot, "IN") yield from plan_wait(group=prev_img_mot) except FailedStatus: ok = False if ok and timeout is not None: ok = time.time() - start_time < timeout if ok: logger.debug("prep_img_motors completed successfully") else: logger.debug("prep_img_motors exitted with timeout") return ok
def match_condition(signal, condition, mover, setpoint, timeout=None, sub_type=None, has_stop=True): """ Plan to adjust mover until condition(signal.value) returns True. Parameters ---------- signal: Signal Object that implements the Bluesky "readable" interface, including the optional subscribe function, sending at least the keyword "value" as in ophyd.Signal. condition: function Function that accepts a single argument, "value", and returns True or False. mover: Device Object that implements both the Bluesky "readable" and "movable" interfaces, accepting "moved_cb" as a keyword argument as in ophyd.positioner.PositionerBase. setpoint: any We will call mover.set(setpoint). Pick a good value (the limit switch?) timeout: float, optional Stop if we hit a timeout. sub_type: str, optional Use a different subscription than the signal's default. has_stop: bool, optional Boolean to indicate whether or not we can stop the motor. We usually use the motor's stop command to stop at the signal. If this is set to False (e.g. we can't stop it), go back to center of the largest range with the condition satisfied after reaching the end. Returns ------- ok: bool True if we reached the condition, False if we timed out or reached the setpoint before satisfying the condition. """ # done = threading.Event() success = threading.Event() if has_stop: def condition_cb(*args, value, **kwargs): if condition(value): success.set() mover.stop() else: pts = [] def condition_cb(*args, value, **kwargs): nonlocal pts if condition(value): pts.append((mover.position, True)) else: pts.append((mover.position, False)) if sub_type is not None: signal.subscribe(condition_cb, sub_type=sub_type) else: signal.subscribe(condition_cb) try: yield from abs_set(mover, setpoint, wait=True, timeout=timeout) except FailedStatus: logger.warning("Timeout on motor %s", mover) if not has_stop: best_start = -1 best_end = -1 curr_start = -1 curr_end = -1 def new_best(best_start, best_end, curr_start, curr_end): if -1 in (best_start, best_end): return curr_start, curr_end elif -1 in (curr_start, curr_end): return best_start, best_end else: curr_dist = abs(pts[curr_end][0] - pts[curr_start][0]) best_dist = abs(pts[best_end][0] - pts[best_start][0]) if curr_dist > best_dist: return curr_start, curr_end else: return best_start, best_end logger.debug("Checking a set of %i stored points", len(pts)) for i, (pos, ok) in enumerate(pts): if ok: if curr_start == -1: curr_start = i curr_end = i else: best_start, best_end = new_best(best_start, best_end, curr_start, curr_end) curr_start = -1 curr_end = -1 best_start, best_end = new_best(best_start, best_end, curr_start, curr_end) if -1 in (best_start, best_end): logger.debug('did not find any valid points: %s', pts) else: logger.debug('found valid points, moving back') start = pts[best_start][0] end = pts[best_end][0] try: yield from abs_set(mover, (end + start) / 2, wait=True, timeout=timeout) except FailedStatus: logger.warning("Timeout on motor %s", mover) if condition(signal.value): success.set() signal.clear_sub(condition_cb) ok = success.is_set() if ok: logger.debug(('condition met in match_condition, ' 'mover=%s setpt=%s cond value=%s'), mover.name, setpoint, signal.value) else: logger.debug(('condition fail in match_condition, ' 'mover=%s setpt=%s cond value=%s'), mover.name, setpoint, signal.value) return ok
def inner(): yield from bp.abs_set(motor, start, wait=True) yield from bp.sleep(sleep_time) yield from scan([detector], motor, start, stop, steps, per_step=dwell)
def inner(): # Prepare Camera yield from bp.mv(cam.acquire, 0) # Stop camera... yield from bp.sleep(.5) # ...and wait for the pipeline to empty. yield from bp.mv( cam.trigger_mode, "Sync In 1", # External Trigger cam.array_counter, 0, ) if use_roi4: yield from bp.mv( cam.min_x, roi.min_xyz.min_x.get(), cam.min_y, roi.min_xyz.min_y.get(), cam.size.size_x, roi.size.x.get(), cam.size.size_y, roi.size.y.get() ) # Prepare TIFF Plugin yield from bp.mv( tiff.file_write_mode, "Stream", tiff.num_capture, steps, tiff.auto_save, 1, tiff.auto_increment, 1, tiff.file_path, folder, tiff.file_name, filename, tiff.file_template, "%s%s_%d.tif", tiff.file_number, 1, tiff.enable, 1) yield from bp.abs_set(tiff.capture, 1) yield from bp.abs_set(cam.acquire, 1) # wait=False # Move to the starting positions yield from bp.mv( gonio.py, start_y - slack_y, gonio.pz, start_z - slack_z, ) # Set velocity for the scan yield from bp.mv( gonio.py.velocity, speed_y, gonio.pz.velocity, speed_z ) # Arm Zebra yield from bp.abs_set(zebra.pos_capt.arm.arm, 1) # Wait Zebra armed while not zebra2.download_status.get(): time.sleep(0.1) # Go yield from bp.mv( gonio.py, end_y + slack_y, gonio.pz, end_z + slack_z ) yield from abs_set(tiff.capture, 0) print(f"{cam.array_counter.get()} images captured")
def __call__(self, sample, plan, subs=None, *, verify_write=False, dark_strategy=periodic_dark, raise_if_interrupted=False, **metadata_kw): # The CustomizedRunEngine knows about a Beamtime object, and it # interprets integers for 'sample' as indexes into the Beamtime's # lists of Samples from all its Experiments. # deprecated from v0.5 release #if getattr(glbl, 'collection', None) is None: # raise RuntimeError("No collection has been linked to current " # "experiment yet.\nPlease do\n" # ">>> open_collection(<collection_name>)\n" # "before you run any prun") if isinstance(sample, int): try: sample = self.beamtime.samples[sample] except IndexError: print("WARNING: hmm, there is no sample with index `{}`" ", please do `bt.list()` to check if it exists yet" .format(sample)) return # If a plan is given as a string, look in up in the global registry. if isinstance(plan, int): try: plan = self.beamtime.scanplans[plan] except IndexError: print("WARNING: hmm, there is no scanplan with index `{}`" ", please do `bt.list()` to check if it exists yet" .format(plan)) return # If the plan is an xpdAcq 'ScanPlan', make the actual plan. if isinstance(plan, ScanPlan): plan = plan.factory() _subs = normalize_subs_input(subs) if verify_write: _subs.update({'stop': verify_files_saved}) # No keys in metadata_kw are allows to collide with sample keys. if set(sample) & set(metadata_kw): raise ValueError("These keys in metadata_kw are illegal " "because they are always in sample: " "{}".format(set(sample) & set(metadata_kw))) if self._beamtime.get('bt_wavelength') is None: print("WARNING: there is no wavelength information in current" "beamtime object, scan will keep going....") metadata_kw.update(sample) sh = glbl.shutter # force to open shutter before scan and close it after if glbl.shutter_control: plan = bp.pchain(bp.abs_set(sh, 1), plan, bp.abs_set(sh, 0)) # Alter the plan to incorporate dark frames. if glbl.auto_dark: plan = dark_strategy(plan) plan = bp.msg_mutator(plan, _inject_qualified_dark_frame_uid) # Load calibration file if glbl.auto_load_calib: plan = bp.msg_mutator(plan, _inject_calibration_md) # Execute super().__call__(plan, subs, raise_if_interrupted=raise_if_interrupted, **metadata_kw) # deprecated from v0.5 release # insert collection #_insert_collection(glbl.collection_name, glbl.collection, # self._run_start_uids) return self._run_start_uids
def per_step(dets, motor, step): yield from one_1d_step(dets, motor, step) yield from bp.abs_set(camera, 1, wait=True) yield from bp.abs_set(camera, 0, wait=True) yield from bp.sleep(idle_time)
def __call__(self, sample, plan, subs=None, *, verify_write=False, dark_strategy=periodic_dark, raise_if_interrupted=False, **metadata_kw): # The CustomizedRunEngine knows about a Beamtime object, and it # interprets integers for 'sample' as indexes into the Beamtime's # lists of Samples from all its Experiments. # deprecated from v0.5 release #if getattr(glbl, 'collection', None) is None: # raise RuntimeError("No collection has been linked to current " # "experiment yet.\nPlease do\n" # ">>> open_collection(<collection_name>)\n" # "before you run any xrun") if isinstance(sample, int): try: sample = self.beamtime.samples[sample] except IndexError: print( "WARNING: hmm, there is no sample with index `{}`" ", please do `bt.list()` to check if it exists yet".format( sample)) return # If a plan is given as a string, look in up in the global registry. if isinstance(plan, int): try: plan = self.beamtime.scanplans[plan] except IndexError: print( "WARNING: hmm, there is no scanplan with index `{}`" ", please do `bt.list()` to check if it exists yet".format( plan)) return # If the plan is an xpdAcq 'ScanPlan', make the actual plan. if isinstance(plan, ScanPlan): plan = plan.factory() _subs = normalize_subs_input(subs) if verify_write: _subs.update({'stop': verify_files_saved}) # No keys in metadata_kw are allows to collide with sample keys. if set(sample) & set(metadata_kw): raise ValueError("These keys in metadata_kw are illegal " "because they are always in sample: " "{}".format(set(sample) & set(metadata_kw))) if self._beamtime.get('bt_wavelength') is None: print("WARNING: there is no wavelength information in current" "beamtime object, scan will keep going....") metadata_kw.update(sample) sh = glbl.shutter if glbl.shutter_control: # Alter the plan to incorporate dark frames. # only works if user allows shutter control if glbl.auto_dark: plan = dark_strategy(plan) plan = bp.msg_mutator(plan, _inject_qualified_dark_frame_uid) # force to close shutter after scan plan = bp.finalize_wrapper(plan, bp.abs_set(sh, 0, wait=True)) # Load calibration file if glbl.auto_load_calib: plan = bp.msg_mutator(plan, _inject_calibration_md) # Insert glbl mask plan = bp.msg_mutator(plan, _inject_mask) # Execute return super().__call__(plan, subs, raise_if_interrupted=raise_if_interrupted, **metadata_kw)
def hf2dwire(*, xstart, xnumstep, xstepsize, zstart, znumstep, zstepsize, acqtime, numrois=1, i0map_show=True, itmap_show=False, energy=None, u_detune=None): ''' input: xstart, xnumstep, xstepsize (float) zstart, znumstep, zstepsize (float) acqtime (float): acqusition time to be set for both xspress3 and F460 numrois (integer): number of ROIs set to display in the live raster scans. This is for display ONLY. The actualy number of ROIs saved depend on how many are enabled and set in the read_attr However noramlly one cares only the raw XRF spectra which are all saved and will be used for fitting. i0map_show (boolean): When set to True, map of the i0 will be displayed in live raster, default is True itmap_show (boolean): When set to True, map of the trasnmission diode will be displayed in the live raster, default is True energy (float): set energy, use with caution, hdcm might become misaligned u_detune (float): amount of undulator to detune in the unit of keV ''' #record relevant meta data in the Start document, defined in 90-usersetup.py md = get_stock_md() #setup the detector # TODO do this with configure current_preamp.exp_time.put(acqtime - 0.09) xs.settings.acquire_time.put(acqtime) xs.total_points.put((xnumstep + 1) * (znumstep + 1)) # det = [current_preamp, xs] det = [xs] #setup the live callbacks livecallbacks = [] livetableitem = [ hf_stage.x, hf_stage.z, 'current_preamp_ch0', 'current_preamp_ch2', 'xs_channel1_rois_roi01_value' ] xstop = xstart + xnumstep * xstepsize zstop = zstart + znumstep * zstepsize print('xstop = ' + str(xstop)) print('zstop = ' + str(zstop)) for roi_idx in range(numrois): roi_name = 'roi{:02}'.format(roi_idx + 1) roi_key = getattr(xs.channel1.rois, roi_name).value.name livetableitem.append(roi_key) # livetableitem.append('saturn_mca_rois_roi'+str(roi_idx)+'_net_count') # livetableitem.append('saturn_mca_rois_roi'+str(roi_idx)+'_count') # #roimap = LiveRaster((xnumstep, znumstep), 'saturn_mca_rois_roi'+str(roi_idx)+'_net_count', clim=None, cmap='viridis', xlabel='x', ylabel='y', extent=None) colormap = 'inferno' #previous set = 'viridis' # roimap = LiveRaster((znumstep, xnumstep), 'saturn_mca_rois_roi'+str(roi_idx)+'_count', clim=None, cmap='inferno', # xlabel='x (mm)', ylabel='y (mm)', extent=[xstart, xstop, zstop, zstart]) # roimap = myLiveRaster((znumstep+1, xnumstep+1), roi_key, clim=None, cmap='inferno', aspect='equal', # xlabel='x (mm)', ylabel='y (mm)', extent=[xstart, xstop, zstop, zstart]) roimap = LiveRaster((znumstep + 1, xnumstep + 1), roi_key, clim=None, cmap='inferno', aspect=0.01, xlabel='x (mm)', ylabel='y (mm)', extent=[xstart, xstop, zstop, zstart]) # liveplotfig = plt.figure('through focus') # roiplot = LivePlot(roi_key,x=hf_stage.x.name, fig=liveplotfig) livecallbacks.append(roimap) # livecallbacks.append(roiplot) # if i0map_show is True: # i0map = myLiveRaster((znumstep+1, xnumstep+1), 'current_preamp_ch2', clim=None, cmap='inferno', # xlabel='x (mm)', ylabel='y (mm)', extent=[xstart, xstop, zstop, zstart]) # livecallbacks.append(i0map) # if itmap_show is True: # itmap = myLiveRaster((znumstep+1, xnumstep+1), 'current_preamp_ch0', clim=None, cmap='inferno', # xlabel='x (mm)', ylabel='y (mm)', extent=[xstart, xstop, zstop, zstart]) # livecallbacks.append(itmap) # commented out liveTable in 2D scan for now until the prolonged time issue is resolved livecallbacks.append(LiveTable(livetableitem)) #setup the plan if energy is not None: if u_detune is not None: # TODO maybe do this with set energy.detune.put(u_detune) # TODO fix name shadowing yield from bp.abs_set(energy, energy, wait=True) # shut_b.open_cmd.put(1) # while (shut_b.close_status.get() == 1): # epics.poll(.5) # shut_b.open_cmd.put(1) hf2dwire_scanplan = bp.grid_scan(det, hf_stage.z, zstart, zstop, znumstep + 1, hf_stage.x, xstart, xstop, xnumstep + 1, True, md=md) hf2dwire_scanplan = bp.subs_wrapper(hf2dwire_scanplan, livecallbacks) scaninfo = yield from hf2dwire_scanplan # shut_b.close_cmd.put(1) # while (shut_b.close_status.get() == 0): # epics.poll(.5) # shut_b.close_cmd.put(1) #write to scan log logscan('2dwire') return scaninfo
def fast_shutter_wrapper(plan): if gs.USE_FAST_SHUTTER: plan = bsp.pchain(bsp.abs_set(fast_shutter.output, FastShutter.OPEN_SHUTTER, settle_time=FastShutter.SETTLE_TIME), plan) plan = bsp.finalize_wrapper(plan, bsp.abs_set(fast_shutter.output, FastShutter.CLOSE_SHUTTER, settle_time=FastShutter.SETTLE_TIME)) return (yield from plan)
def step_scan(mymotor, motor_min, motor_max, motor_step, collection_time): "Step mymotor from min -> max with a step size of step and collect for a given time" for num in np.arange(motor_min, motor_max, motor_step): yield from abs_set(mymotor, num, wait=True) yield from _time_plan(collection_time)