def dark_current(self): print(f'Measuring current offsets for {self.name}, this will take several seconds') yield from mv(self.compute_current_offset1,1) yield from mv(self.compute_current_offset2,1) yield from mv(self.compute_current_offset3,1) yield from mv(self.compute_current_offset4,1) BMM_log_info('Measured dark current on quadem1')
def set_roi(self, i, el): '''Configure an ROI channel i ∈ (1 .. 3) for element el''' if Z_number(el) is None: self.slots[i - 1] = None else: self.slots[i - 1] = element_symbol(el) BMM_log_info('Set ROI channel %d to %s' % (i, str(self.slots[i - 1])))
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. filename: name of file, will be appended to DATA for the full path (required) start: starting energy value (required) end: ending energy value (required) nsteps: number of energy steps (required) delay: pause between energy steps, in seconds [5] dosteps: 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) ''' BMMuser, dcm = user_ns['BMMuser'], user_ns['dcm'] 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 scan_dcmpitch(sgnl): line1 = '%s, %s, %.3f, %.3f, %d -- starting at %.3f\n' % \ (motor.name, sgnl, start, stop, nsteps, motor.user_readback.get()) yield from abs_set(user_ns['_locked_dwell_time'], 0.1, wait=True) yield from dcm.kill_plan() yield from mv(slits3.vsize, 3) if sgnl == 'Bicron': yield from mv(slitsg.vsize, 5) uid = yield from rel_scan(dets, motor, start, stop, nsteps) #yield from rel_adaptive_scan(dets, 'I0', motor, # start=start, # stop=stop, # min_step=0.002, # max_step=0.03, # target_delta=.15, # backstep=True) t = db[-1].table() signal = t[sgnl] if choice.lower() == 'com': position = com(signal) top = t[motor.name][position] elif choice.lower() == 'fit': pitch = t['dcm_pitch'] mod = SkewedGaussianModel() pars = mod.guess(signal, x=pitch) out = mod.fit(signal, pars, x=pitch) print(whisper(out.fit_report(min_correl=0))) out.plot() top = out.params['center'].value else: position = peak(signal) top = t[motor.name][position] yield from sleep(3.0) yield from abs_set(motor.kill_cmd, 1, wait=True) RE.msg_hook = BMM_msg_hook BMM_log_info('rocking curve scan: %s\tuid = %s, scan_id = %d' % (line1, uid, user_ns['db'][-1].start['scan_id'])) yield from mv(motor, top) if sgnl == 'Bicron': yield from mv(slitsg.vsize, gonio_slit_height)
def cleanup_plan(): print('Cleaning up after an area scan') RE.clear_suspenders() if BMMuser.final_log_entry is True: BMM_log_info('areascan finished\n\tuid = %s, scan_id = %d' % (db[-1].start['uid'], db[-1].start['scan_id'])) yield from resting_state_plan() RE.msg_hook = BMM_msg_hook print('Disabling plot for re-plucking.') try: cid = BMMuser.fig.canvas.mpl_disconnect(cid) except: pass BMMuser.x = None BMMuser.y = None BMMuser.motor = None BMMuser.motor2 = None BMMuser.fig = None BMMuser.ax = None
def dark_current(): shb = user_ns['shb'] reopen = shb.state.get() == shb.openval if reopen: print('\nClosing photon shutter') yield from shb.close_plan() print('Measuring current offsets, this will take several seconds') EpicsSignal("XF:06BM-BI{EM:1}EM180:ComputeCurrentOffset1.PROC", name='').put(1) EpicsSignal("XF:06BM-BI{EM:1}EM180:ComputeCurrentOffset2.PROC", name='').put(1) EpicsSignal("XF:06BM-BI{EM:1}EM180:ComputeCurrentOffset3.PROC", name='').put(1) EpicsSignal("XF:06BM-BI{EM:1}EM180:ComputeCurrentOffset4.PROC", name='').put(1) yield from sleep(3) BMM_log_info('Measured dark current on quadem1') if reopen: print('Opening photon shutter') yield from shb.open_plan() print('You are ready to measure!\n')
def dark_current(self): reopen = shb.state.get() == shb.openval if reopen: print('\nClosing photon shutter') yield from shb.close_plan() print('Measuring current offsets, this will take several seconds') ###################################################################### # from Pete (email Feb 7, 2020): # # caput XF:06BM-BI{EM:3}EM180:CalibrationMode 1 # # caput XF:06BM-BI{EM:3}EM180:CopyADCOffsets.PROC 1 # # caput XF:06BM-BI{EM:3}EM180:CalibrationMode 0 # # ADC offset values should be around 3800, might need to hit Compute # # buttons to get lovely low dark current values # ###################################################################### ## this almost works.... self.current_offsets.ch1.put(0.0) self.current_offsets.ch2.put(0.0) self.calibration_mode.put(1) yield from sleep(0.5) self.copy_adc_offsets.put(1) yield from sleep(0.5) self.calibration_mode.put(0) yield from sleep(0.5) self.compute_current_offset1.put(1) self.compute_current_offset1.put(2) # EpicsSignal("XF:06BM-BI{EM:3}EM180:CalibrationMode", name='').put(1) # EpicsSignal("XF:06BM-BI{EM:3}EM180:CopyADCOffsets.PROC", name='').put(1) # EpicsSignal("XF:06BM-BI{EM:3}EM180:CalibrationMode", name='').put(0) # EpicsSignal("XF:06BM-BI{EM:1}EM180:ComputeCurrentOffset1.PROC", name='').put(1) # EpicsSignal("XF:06BM-BI{EM:1}EM180:ComputeCurrentOffset2.PROC", name='').put(1) yield from sleep(0.5) print(self.sigma1.get(), self.sigma2.get()) BMM_log_info('Measured dark current on dualio ion chamber') if reopen: print('Opening photon shutter') yield from shb.open_plan() print('You are ready to measure!\n')
def scan_slit(slp): #if slit_height < 0.5: # yield from mv(slits3.vsize, 0.5) yield from mv(quadem1.averaging_time, 0.1) yield from mv(motor.velocity, 0.4) yield from mv(motor.kill_cmd, 1) uid = yield from rel_scan([quadem1], motor, start, stop, nsteps, md={'plan_name' : f'rel_scan linescan {motor.name} I0'}) user_ns['RE'].msg_hook = BMM_msg_hook BMM_log_info('slit height scan: %s\tuid = %s, scan_id = %d' % (line1, uid, user_ns['db'][-1].start['scan_id'])) if move: t = user_ns['db'][-1].table() signal = t['I0'] #if get_mode() in ('A', 'B', 'C'): # position = com(signal) #else: position = peak(signal) top = t[motor.name][position] yield from sleep(slp) yield from mv(motor.kill_cmd, 1) yield from sleep(slp) yield from mv(motor, top) else: 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()) yield from sleep(slp) yield from mv(motor.kill_cmd, 1) #yield from mv(motor.inpos, 1) yield from sleep(slp) yield from move_after_scan(motor) yield from mv(quadem1.averaging_time, 0.5)
def main_plan(detector, axis, start, stop, nsteps, pluck, force): (ok, text) = BMM_clear_to_start() if force is False and ok is False: print(error_msg(text)) yield from null() return detector, axis = ls_backwards_compatibility(detector, axis) # print('detector is: ' + str(detector)) # print('axis is: ' + str(axis)) # return(yield from null()) RE.msg_hook = None ## sanitize input and set thismotor to an actual motor if type(axis) is str: axis = axis.lower() detector = detector.capitalize() ## sanity checks on axis if axis not in motor_nicknames.keys() and 'EpicsMotor' not in str(type(axis)) \ and 'PseudoSingle' not in str(type(axis)) and 'WheelMotor' not in str(type(axis)): print( error_msg('\n*** %s is not a linescan motor (%s)\n' % (axis, str.join(', ', motor_nicknames.keys())))) yield from null() return if 'EpicsMotor' in str(type(axis)): thismotor = axis elif 'PseudoSingle' in str(type(axis)): thismotor = axis elif 'WheelMotor' in str(type(axis)): thismotor = axis else: # presume it's an xafs_XXXX motor thismotor = motor_nicknames[axis] current = thismotor.position if current + start < thismotor.limits[0]: print( error_msg( f'These scan parameters will take {thismotor.name} outside it\'s lower limit of {thismotor.limits[0]}' )) print(whisper(f'(starting position = {thismotor.position})')) return (yield from null()) if current + stop > thismotor.limits[1]: print( error_msg( f'These scan parameters will take {thismotor.name} outside it\'s upper limit of {thismotor.limits[1]}' )) print(whisper(f'(starting position = {thismotor.position})')) return (yield from null()) BMMuser.motor = thismotor ## sanity checks on detector if detector not in ('It', 'If', 'I0', 'Iy', 'Ir', 'Both', 'Bicron', 'Ia', 'Ib', 'Dualio', 'Xs', 'Xs1'): print( error_msg( '\n*** %s is not a linescan measurement (%s)\n' % (detector, 'it, if, i0, iy, ir, both, bicron, dualio, xs, xs1'))) yield from null() return yield from abs_set(user_ns['_locked_dwell_time'], inttime, wait=True) if detector == 'Xs': yield from mv(xs.settings.acquire_time, inttime) yield from mv(xs.total_points, nsteps) dets = [ user_ns['quadem1'], ] if user_ns['with_dualem']: dualio = user_ns['dualio'] denominator = '' detname = '' ## func is an anonymous function, built on the fly, for feeding to DerivedPlot if detector == 'It': denominator = ' / I0' detname = 'transmission' func = lambda doc: (doc['data'][thismotor.name], doc['data']['It'] / doc['data']['I0']) elif detector == 'Ia' and dualio is not None: dets.append(dualio) detname = 'Ia' func = lambda doc: (doc['data'][thismotor.name], doc['data']['Ia']) elif detector == 'Ib' and dualio is not None: dets.append(dualio) detname = 'Ib' func = lambda doc: (doc['data'][thismotor.name], doc['data']['Ib']) elif detector == 'Ir': #denominator = ' / It' detname = 'reference' #func = lambda doc: (doc['data'][thismotor.name], doc['data']['Ir']/doc['data']['It']) func = lambda doc: (doc['data'][thismotor.name], doc['data']['Ir']) elif detector == 'I0': detname = 'I0' func = lambda doc: (doc['data'][thismotor.name], doc['data']['I0']) elif detector == 'Bicron': dets.append(user_ns['vor']) detname = 'Bicron' func = lambda doc: (doc['data'][thismotor.name], doc['data'][ 'Bicron']) elif detector == 'Iy': denominator = ' / I0' detname = 'electron yield' func = lambda doc: (doc['data'][thismotor.name], doc['data']['Iy'] / doc['data']['I0']) elif detector == 'If': dets.append(user_ns['vor']) denominator = ' / I0' detname = 'fluorescence' func = lambda doc: (doc['data'][thismotor.name], (doc['data'][ BMMuser.dtc1] + doc['data'][BMMuser.dtc2] + doc['data'][ BMMuser.dtc3] + doc['data'][BMMuser.dtc4]) / doc['data'][ 'I0']) elif detector == 'Xs': dets.append(user_ns['xs']) denominator = ' / I0' detname = 'fluorescence' func = lambda doc: (doc['data'][thismotor.name], (doc['data'][BMMuser.xs1] + doc['data'][ BMMuser.xs2] + doc['data'][BMMuser.xs3] + doc['data'][BMMuser.xs4]) / doc['data']['I0']) yield from mv(xs.total_points, nsteps) # Xspress3 demands that this be set up front elif detector == 'Xs1': dets.append(user_ns['xs']) denominator = ' / I0' detname = 'fluorescence' func = lambda doc: (doc['data'][thismotor.name], doc['data'][ BMMuser.xs8] / doc['data']['I0']) yield from mv(xs1.total_points, nsteps) # Xspress3 demands that this be set up front elif detector == 'Dualio': dets.append(dualio) funcia = lambda doc: (doc['data'][thismotor.name], doc['data']['Ia' ]) funcib = lambda doc: (doc['data'][thismotor.name], doc['data']['Ib' ]) ## need a "Both" for trans + xs !!!!!!!!!! elif detector == 'Both': dets.append(user_ns['vor']) functr = lambda doc: (doc['data'][thismotor.name], doc['data'][ 'It'] / doc['data']['I0']) funcfl = lambda doc: (doc['data'][thismotor.name], (doc['data'][ BMMuser.dtc1] + doc['data'][BMMuser.dtc2] + doc['data'][ BMMuser.dtc3] + doc['data'][BMMuser.dtc4]) / doc['data'][ 'I0']) ## and this is the appropriate way to plot this linescan #abs_set(_locked_dwell_time, 0.5) if detector == 'Both': plot = [ DerivedPlot(funcfl, xlabel=thismotor.name, ylabel='If/I0', title='fluorescence vs. %s' % thismotor.name), DerivedPlot(functr, xlabel=thismotor.name, ylabel='It/I0', title='transmission vs. %s' % thismotor.name) ] elif detector == 'Dualio': plot = [ DerivedPlot(funcia, xlabel=thismotor.name, ylabel='Ia/I0', title='Ia vs. %s' % thismotor.name), DerivedPlot(funcib, xlabel=thismotor.name, ylabel='Ib/I0', title='Ib vs. %s' % thismotor.name) ] else: plot = DerivedPlot(func, xlabel=thismotor.name, ylabel=detector + denominator, title='%s vs. %s' % (detname, thismotor.name)) if 'PseudoSingle' in str(type(axis)): value = thismotor.readback.get() else: value = thismotor.user_readback.get() line1 = '%s, %s, %.3f, %.3f, %d -- starting at %.3f\n' % \ (thismotor.name, detector, start, stop, nsteps, value) ##BMM_suspenders() # engage suspenders thismd = dict() thismd['XDI'] = dict() thismd['XDI']['Facility'] = dict() thismd['XDI']['Facility']['GUP'] = BMMuser.gup thismd['XDI']['Facility']['SAF'] = BMMuser.saf rkvs.set('BMM:scan:type', 'line') rkvs.set('BMM:scan:starttime', str(datetime.datetime.timestamp(datetime.datetime.now()))) rkvs.set('BMM:scan:estimated', 0) @subs_decorator(plot) #@subs_decorator(src.callback) def scan_xafs_motor(dets, motor, start, stop, nsteps): uid = yield from rel_scan(dets, motor, start, stop, nsteps, md={ **thismd, **md }) return uid uid = yield from scan_xafs_motor(dets, thismotor, start, stop, nsteps) #global mytable #run = src.retrieve() #mytable = run.primary.read().to_dataframe() BMM_log_info('linescan: %s\tuid = %s, scan_id = %d' % (line1, uid, user_ns['db'][-1].start['scan_id'])) 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()) yield from move_after_scan(thismotor)
def clear_encoder_loss(self): self.clear_enc_lss.put(1) self.enable() BMM_log_info('clearing encoder loss for %s' % self.name)
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 user_ns['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 mv(_locked_dwell_time, dwell) dets = [ quadem1, ] if with_xspress3 and detector == 'If': detector = 'Xs' if detector == 'If': dets.append(vor) detector = 'ROI1' if detector.lower() == 'xs': dets.append(xs) detector = BMMuser.xs1 yield from mv(xs.total_points, nslow * nfast) 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)) close_all_plots() 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 report( f'Starting areascan at x,y = {fast.position:.3f}, {slow.position:.3f}', level='bold', slack=True) ## 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, md={ 'plan_name': f'grid_scan measurement {slow.name} {fast.name} {detector}' }) 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, snake=False) if pluck is True: close_all_plots() thismap = user_ns['db'].v2[uid] x = numpy.array(thismap.primary.read()[fast.name]) y = numpy.array(thismap.primary.read()[slow.name]) z=numpy.array(thismap.primary.read()[BMMuser.xs1]) +\ numpy.array(thismap.primary.read()[BMMuser.xs2]) +\ numpy.array(thismap.primary.read()[BMMuser.xs3]) +\ numpy.array(thismap.primary.read()[BMMuser.xs4]) z = z.reshape(nfast, nslow) # grabbing the first nfast elements of x and every # nslow-th element of y is more reliable than # numpy.unique due to float &/or motor precision issues #plt.title(f'Energy = {energies["below"]}') plt.xlabel(f'fast axis ({fast.name}) position (mm)') plt.ylabel(f'slow axis ({slow.name}) position (mm)') plt.gca().invert_yaxis() # plot an xafs_x/xafs_y plot upright plt.contourf(x[:nfast], y[::nslow], z, cmap=plt.cm.viridis) plt.colorbar() plt.show() fname = os.path.join(BMMuser.folder, 'map-' + now() + '.png') plt.savefig(fname) try: img_to_slack(fname) except: post_to_slack('failed to post image: {fname}') pass BMMuser.x = None figs = list(map(plt.figure, plt.get_fignums())) canvas = figs[0].canvas 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 = 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, BMMuser.x, slow, BMMuser.y) report( f'Moved to position x,y = {fast.position:.3f}, {slow.position:.3f}', level='bold', slack=True)
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 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 main_plan(inifile, force, **kwargs): ## --*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-- ## read and check INI content orig = inifile if not os.path.isfile(inifile): inifile = DATA + inifile if not os.path.isfile(inifile): print( warning_msg('\n%s does not exist! Bailing out....\n' % orig)) return (orig, -1) print(bold_msg('reading ini file: %s' % inifile)) (p, f) = scan_metadata(inifile=inifile, **kwargs) if not any( p): # scan_metadata returned having printed an error message return (yield from null()) #if not os.path.isdir(p['folder']): # print(error_msg('\n%s is not a folder\n' % p['folder'])) # return(yield from null()) detector = 'It' if 'trans' in p['mode']: detector = 'It' elif 'fluo' in p['mode']: detector = 'If' ## --*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-- ## verify output file name won't be overwritten outfile = '%s.%3.3d' % (os.path.join(p['folder'], p['filename']), p['start']) if os.path.isfile(outfile): print(error_msg('%s already exists! Bailing out....' % outfile)) return (yield from null()) ## --*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-- ## prompt user and verify that we are clear to start text = '\n' for k in ('folder', 'filename', 'experimenters', 'e0', 'npoints', 'dwell', 'delay', 'sample', 'prep', 'comment', 'mode', 'snapshots'): text = text + ' %-13s : %-50s\n' % (k, p[k]) if BMMuser.prompt: boxedtext('How does this look?', text + '\n %-13s : %-50s\n' % ('output file', outfile), 'green', width=len(outfile) + 25) # see 05-functions action = input("\nBegin time scan? [Y/n then Enter] ") if action.lower() == 'q' or action.lower() == 'n': return (yield from null()) (ok, ctstext) = BMM_clear_to_start() if force is False and ok is False: print(error_msg(ctstext)) yield from null() return ## --*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-- # organize metadata for injection into database and XDI output print(bold_msg('gathering metadata')) md = bmm_metadata( measurement=p['mode'], experimenters=p['experimenters'], edge=p['edge'], element=p['element'], edge_energy=p['e0'], direction=0, scantype='fixed', channelcut=p['channelcut'], mono='Si(%s)' % dcm._crystal, i0_gas='N2', #\ it_gas='N2', # > these three need to go into INI file ir_gas='N2', #/ sample=p['sample'], prep=p['prep'], stoichiometry=None, mode=p['mode'], comment=p['comment'], ) del (md['XDI']['Element']['edge']) del (md['XDI']['Element']['symbol']) md['XDI']['Column']['01'] = 'time seconds' md['XDI']['Column']['02'] = md.copy()['XDI']['Column']['03'] md['XDI']['Column']['03'] = md.copy()['XDI']['Column']['04'] md['XDI']['Column']['04'] = md['XDI']['Column']['05'] del (md['XDI']['Column']['05']) md['_kind'] = 'sead' rightnow = metadata_at_this_moment() # see 62-metadata.py for family in rightnow.keys(): # transfer rightnow to md if type(rightnow[family]) is dict: if family not in md: md[family] = dict() for k in rightnow[family].keys(): md[family][k] = rightnow[family][k] xdi = {'XDI': md} BMM_log_info( 'Starting single-energy absorption detection time scan using\n%s:\n%s\nCommand line arguments = %s\nMoving to measurement energy: %.1f eV' % (inifile, text, str(kwargs), p['e0'])) ## --*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-- ## move to the energy specified in the INI file print(bold_msg('Moving to measurement energy: %.1f eV' % p['e0'])) dcm.mode = 'fixed' yield from mv(dcm.energy, p['e0']) ## --*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-- ## snap photos if p['snapshots']: image = os.path.join( p['folder'], 'snapshots', "%s_XASwebcam_%s.jpg" % (p['filename'], now())) snap('XAS', filename=image) image = os.path.join(p['folder'], 'snapshots', "%s_analog_%s.jpg" % (p['filename'], now())) snap('analog', filename=image) ## --*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-- ## engage suspenders right before starting measurement if not force: BMM_suspenders() ## --*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-- ## perform the actual time scan uid = yield from timescan(detector, p['npoints'], p['dwell'], p['delay'], force=force, md={**xdi}) ## --*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-- ## write the output file header = db[uid] write_XDI(outfile, header) # yield from ? report('wrote time scan to %s' % outfile)
def timescan(detector, readings, dwell, delay, force=False, md={}): ''' Generic timescan plan. Parameters ---------- detector : str detector to display -- if, it, ir, or i0 readings : int number of measurements to make dwell : float dwell time in seconds for each measurement delay : float pause in seconds between measurements outfile : str data file name (relative to DATA), False to not write force : bool flag for forcing a scan even if not clear to start This does not write an ASCII data file, but it does make a log entry. Use the ts2dat() function to extract the linescan from the database and write it to a file. Examples >>> RE(timescan('it', 100, 0.5)) ''' RE, BMMuser, quadem1, _locked_dwell_time = user_ns['RE'], user_ns[ 'BMMuser'], user_ns['quadem1'], user_ns['_locked_dwell_time'] rkvs = user_ns['rkvs'] ###################################################################### # 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 running a time scan.\n' % BMMuser.macro_sleep)) countdown(BMMuser.macro_sleep) return (yield from null()) ###################################################################### (ok, text) = BMM_clear_to_start() if force is False and ok is False: print(error_msg(text)) yield from null() return RE.msg_hook = None ## sanitize and sanity checks on detector detector = detector.capitalize() if detector not in ('It', 'If', 'I0', 'Iy', 'Ir') and 'Dtc' not in detector: print( error_msg('\n*** %s is not a timescan measurement (%s)\n' % (detector, 'it, if, i0, iy, ir'))) yield from null() return yield from mv(_locked_dwell_time, dwell) dets = [ quadem1, ] denominator = '' epoch_offset = pandas.Timestamp.now(tz='UTC').value / 10**9 ## func is an anonymous function, built on the fly, for feeding to DerivedPlot if detector == 'It': denominator = ' / I0' func = lambda doc: (doc['time'] - epoch_offset, doc['data']['It'] / doc['data']['I0']) elif detector == 'Ir': denominator = ' / It' func = lambda doc: (doc['time'] - epoch_offset, doc['data']['Ir'] / doc['data']['It']) elif detector == 'I0': func = lambda doc: (doc['time'] - epoch_offset, doc['data']['I0']) elif detector == 'Iy': denominator = ' / I0' func = lambda doc: (doc['time'] - epoch_offset, doc['data']['Iy'] / doc['data']['I0']) elif detector == 'Dtc': dets.append(vor) denominator = ' / I0' func = lambda doc: (doc['time'] - epoch_offset, doc['data'][ BMMuser.dtc2] / doc['data']['I0']) func3 = lambda doc: (doc['time'] - epoch_offset, doc['data'][ BMMuser.dtc3] / doc['data']['I0']) elif detector == 'If': dets.append(vor) denominator = ' / I0' func = lambda doc: (doc['time'] - epoch_offset, (doc['data'][ BMMuser.dtc1] + doc['data'][BMMuser.dtc2] + doc['data'][ BMMuser.dtc3] + doc['data'][BMMuser.dtc4]) / doc['data']['I0']) ## and this is the appropriate way to plot this linescan if detector == 'Dtc': plot = [ DerivedPlot(func, xlabel='elapsed time (seconds)', ylabel='dtc2', title='time scan'), DerivedPlot(func3, xlabel='elapsed time (seconds)', ylabel='dtc3', title='time scan') ] else: plot = DerivedPlot(func, xlabel='elapsed time (seconds)', ylabel=detector + denominator, title='time scan') line1 = '%s, N=%s, dwell=%.3f, delay=%.3f\n' % (detector, readings, dwell, delay) thismd = dict() thismd['XDI'] = dict() thismd['XDI']['Facility'] = dict() thismd['XDI']['Facility']['GUP'] = BMMuser.gup thismd['XDI']['Facility']['SAF'] = BMMuser.saf thismd['XDI']['Beamline'] = dict() thismd['XDI']['Beamline']['energy'] = dcm.energy.readback.get() thismd['XDI']['Scan'] = dict() thismd['XDI']['Scan']['dwell_time'] = dwell thismd['XDI']['Scan']['delay'] = delay @subs_decorator(plot) #@subs_decorator(src.callback) def count_scan(dets, readings, delay): #if 'purpose' not in md: # md['purpose'] = 'measurement' uid = yield from count(dets, num=readings, delay=delay, md={ **thismd, **md, 'plan_name': f'count measurement {detector}' }) return uid rkvs.set('BMM:scan:type', 'time') rkvs.set('BMM:scan:starttime', str(datetime.datetime.timestamp(datetime.datetime.now()))) rkvs.set('BMM:scan:estimated', 0) uid = yield from count_scan(dets, readings, delay, md) BMM_log_info('timescan: %s\tuid = %s, scan_id = %d' % (line1, uid, db[-1].start['scan_id'])) yield from mv(_locked_dwell_time, 0.5) RE.msg_hook = BMM_msg_hook return (uid)
def calibrate_high_end(mono='111', focus=False): '''Step through the upper 5 elements of the mono calibration procedure.''' BMMuser, shb, dcm_pitch = user_ns['BMMuser'], user_ns['shb'], user_ns[ 'dcm_pitch'] (ok, text) = BMM_clear_to_start() if ok is False: print(error_msg('\n' + text) + bold_msg('Quitting macro....\n')) return (yield from null()) BMM_log_info('Beginning high end calibration macro') def main_plan(): BMMuser.prompt = False datafile = os.path.join(BMMuser.DATA, 'edges%s.ini' % mono) handle = open(datafile, 'a') #yield from shb.open_plan() yield from change_edge('Pt', target=0, focus=focus) pitch = dcm_pitch.user_readback.get() yield from xafs('/home/xf06bm/Data/Staff/mono_calibration/cal.ini', folder=BMMuser.DATA, filename='ptcal', edge='Pt', e0=11563, sample='Pt foil') close_last_plot() handle.write('pt = 11111.11, 11562.76, 22222.22, %.5f\n' % pitch) handle.flush() yield from change_edge('Au', target=0, focus=focus) pitch = dcm_pitch.user_readback.get() yield from xafs('/home/xf06bm/Data/Staff/mono_calibration/cal.ini', folder=BMMuser.DATA, filename='aucal', edge='Au', e0=11919, sample='Au foil') close_last_plot() handle.write('au = 11111.11, 11919.70, 22222.22, %.5f\n' % pitch) handle.flush() yield from change_edge('Pb', target=0, focus=focus) pitch = dcm_pitch.user_readback.get() yield from xafs('/home/xf06bm/Data/Staff/mono_calibration/cal.ini', folder=BMMuser.DATA, filename='pbcal', edge='Pb', e0=13035, sample='Pb foil') close_last_plot() handle.write('pb = 11111.11, 13035.07, 22222.22, %.5f\n' % pitch) handle.flush() yield from change_edge('Nb', target=0, focus=focus) pitch = dcm_pitch.user_readback.get() yield from xafs('/home/xf06bm/Data/Staff/mono_calibration/cal.ini', folder=BMMuser.DATA, filename='nbcal', edge='Nb', e0=18986, sample='Nb foil') close_last_plot() handle.write('nb = 11111.11, 18982.97, 22222.22, %.5f\n' % pitch) handle.flush() yield from change_edge('Mo', target=0, focus=focus) pitch = dcm_pitch.user_readback.get() yield from xafs('/home/xf06bm/Data/Staff/mono_calibration/cal.ini', folder=BMMuser.DATA, filename='mocal', edge='Mo', e0=20000, sample='Mo foil') close_last_plot() handle.write('mo = 11111.11, 20000.36, 22222.22, %.5f\n' % pitch) handle.flush() handle.close() #yield from shb.close_plan() def cleanup_plan(): yield from resting_state_plan() yield from finalize_wrapper(main_plan(), cleanup_plan()) yield from resting_state_plan() BMM_log_info('High end calibration macro finished!')
def calibrate_low_end(mono='111', focus=False): '''Step through the lower 5 elements of the mono calibration procedure.''' BMMuser, shb, dcm_pitch = user_ns['BMMuser'], user_ns['shb'], user_ns[ 'dcm_pitch'] (ok, text) = BMM_clear_to_start() if ok is False: print(error_msg('\n' + text) + bold_msg('Quitting macro....\n')) return (yield from null()) BMM_log_info('Beginning low end calibration macro') def main_plan(): BMMuser.prompt = False datafile = os.path.join(BMMuser.DATA, 'edges%s.ini' % mono) handle = open(datafile, 'w') handle.write('[config]\n') handle.write("mono = %s\n" % mono) if mono == '111': handle.write('DSPACING = 3.13597211\n') else: handle.write('DSPACING = 1.63762644\n') handle.write('thistitle = Si(%s) calibration curve\n' % mono) handle.write( 'reference = Kraft et al, Review of Scientific Instruments 67, 681 (1996)\n' ) handle.write('doi = https://doi.org/10.1063/1.1146657\n\n') handle.write('## found, tabulated, found_angle, dcm_pitch\n') handle.write('[edges]\n') handle.flush() yield from change_edge('Fe', target=0, focus=focus) pitch = dcm_pitch.user_readback.get() yield from xafs('/home/xf06bm/Data/Staff/mono_calibration/cal.ini', folder=BMMuser.DATA, filename='fecal', edge='Fe', e0=7112, sample='Fe foil') close_last_plot() handle.write('fe = 11111.11, 7110.75, 22222.22, %.5f\n' % pitch) handle.flush() yield from change_edge('Co', target=0, focus=focus) pitch = dcm_pitch.user_readback.get() yield from xafs('/home/xf06bm/Data/Staff/mono_calibration/cal.ini', folder=BMMuser.DATA, filename='cocal', edge='Co', e0=7709, sample='Co foil') close_last_plot() handle.write('co = 11111.11, 7708.78, 22222.22, %.5f\n' % pitch) handle.flush() yield from change_edge('Ni', target=0, focus=focus) pitch = dcm_pitch.user_readback.get() yield from xafs('/home/xf06bm/Data/Staff/mono_calibration/cal.ini', folder=BMMuser.DATA, filename='nical', edge='Ni', e0=8333, sample='Ni foil') close_last_plot() handle.write('ni = 11111.11, 8331.49, 22222.22, %.5f\n' % pitch) handle.flush() yield from change_edge('Cu', target=0, focus=focus) pitch = dcm_pitch.user_readback.get() yield from xafs('/home/xf06bm/Data/Staff/mono_calibration/cal.ini', folder=BMMuser.DATA, filename='cucal', edge='Cu', e0=8979, sample='Cu foil') close_last_plot() handle.write('cu = 11111.11, 8980.48, 22222.22, %.5f\n' % pitch) handle.flush() yield from change_edge('Zn', target=0, focus=focus) pitch = dcm_pitch.user_readback.get() yield from xafs('/home/xf06bm/Data/Staff/mono_calibration/cal.ini', folder=BMMuser.DATA, filename='zncal', edge='Zn', e0=9659, sample='Zn foil') close_last_plot() handle.write('zn = 11111.11, 9660.76, 22222.22, %.5f\n' % pitch) handle.flush() handle.close() #yield from shb.close_plan() def cleanup_plan(): yield from resting_state_plan() yield from finalize_wrapper(main_plan(), cleanup_plan()) yield from resting_state_plan() BMM_log_info('Low end calibration macro finished!')
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)