Example #1
0
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)