def calibrate_high_end(mono='111'): '''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) 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) 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) 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) 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) 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 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. For example: RE(timescan('it', 100, 0.5)) detector: detector to display -- if, it, ir, or i0 readings: number of measurements to make dwell: dwell time in seconds for each measurement delay: pause in seconds between measurements outfile: data file name (relative to DATA), False to not write force: 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. ''' RE, BMMuser, quadem1, _locked_dwell_time = user_ns['RE'], user_ns['BMMuser'], user_ns['quadem1'], user_ns['_locked_dwell_time'] ###################################################################### # 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 abs_set(_locked_dwell_time, dwell, wait=True) 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): uid = yield from count(dets, num=readings, delay=delay, md={**thismd, **md}) return uid dotfile = '/home/xf06bm/Data/.time.scan.running' with open(dotfile, "w") as f: f.write(str(datetime.datetime.timestamp(datetime.datetime.now())) + '\n') uid = yield from count_scan(dets, readings, delay) BMM_log_info('timescan: %s\tuid = %s, scan_id = %d' % (line1, uid, db[-1].start['scan_id'])) if os.path.isfile(dotfile): os.remove(dotfile) yield from abs_set(_locked_dwell_time, 0.5, wait=True) RE.msg_hook = BMM_msg_hook return(uid)
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 '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 with open(dotfile, "w") as f: f.write( str(datetime.datetime.timestamp(datetime.datetime.now())) + '\n') f.write('%d\n' % 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)