Esempio n. 1
0
def show_reference_wheel():
    xafs_ref = user_ns['xafs_ref']
    wheel = xafs_ref.content.copy()
    this = xafs_ref.current_slot() - 1
    #wheel[this] = go_msg(wheel[this])
    text = 'Foil wheel:\n'
    text += bold_msg(
        '    1      2      3      4      5      6      7      8      9     10     11     12\n'
    )
    text += ' '
    for i in range(12):
        if i == this:
            text += go_msg('%4.4s' % str(wheel[i])) + '   '
        else:
            text += '%4.4s' % str(wheel[i]) + '   '
    text += '\n'
    text += bold_msg(
        '   13     14     15     16     17     18     19     20     21     22     23     24\n'
    )
    text += ' '
    for i in range(12, 24):
        if i == this:
            text += go_msg('%4.4s' % str(wheel[i])) + '   '
        else:
            text += '%4.4s' % str(wheel[i]) + '   '
    text += '\n'
    return (text)
def xlsx():
    '''Prompt for a macro building spreadsheet for any instrument. Use the
    content of cell B1 to direct this spreadsheet to the correct builder.

    if cell B1 is "Glancing angle" --> build a glancing angle macro

    if cell B1 is "Sample wheel" --> build a sample wheel macro

    if cell B1 is empty --> build a sample wheel macro

    '''
    spreadsheet = present_options('xlsx')
    if spreadsheet is None:
        print(error_msg('No spreadsheet specified!'))
        return None
    #spreadsheet = os.path.join(BMMuser.folder, spreadsheet)
    wb = load_workbook(os.path.join(BMMuser.folder, spreadsheet),
                       read_only=True)
    ws = wb.active
    instrument = str(ws['B1'].value).lower()
    if instrument == 'glancing angle':
        print(bold_msg('This is a glancing angle spreadsheet'))
        pinwheel.spreadsheet(spreadsheet)
    else:
        print(bold_msg('This is a sample wheel spreadsheet'))
        wmb.spreadsheet(spreadsheet)
Esempio n. 3
0
 def do_ChangeXtals(self):
     if user_ns['dcm']._crystal == '111':
         print(
             go_msg('You would like to change from the ') +
             whisper('Si(111)') + go_msg(' to the ') + bold_msg('Si(311)') +
             go_msg(' crystals...\n'))
         print(disconnected_msg('yield from change_xtals("311")'))
     else:
         print(
             go_msg('You would like to change from the ') +
             whisper('Si(311)') + go_msg(' to the ') + bold_msg('Si(111)') +
             go_msg(' crystals...\n'))
         print(disconnected_msg('yield from change_xtals("111")'))
     yield from null()
 def finish_macro(self):
     #######################################
     # explain to the user what to do next #
     #######################################
     print(f'\nYour new {BMMuser.instrument} plan is called: ' + bold_msg('%s_macro' % self.basename))
     print('\nVerify:  ' + bold_msg('%s_macro??' % self.basename))
     if 'glancing angle' in self.instrument:
         print('Run:     '   + bold_msg('RE(%s_macro())' % self.basename))
         print('Add ref: '   + bold_msg('RE(%s_macro(ref=True))' % self.basename))
     else:
         print('Run:     '   + bold_msg('RE(%s_macro())' % self.basename))
         #print('Dryrun:  '   + bold_msg('RE(%s_macro(dryrun=True))' % self.basename))
     hours = int(self.totaltime/60)
     minutes = int(self.totaltime - hours*60)
     self.deltatime = numpy.sqrt(self.deltatime)
     print(f'\nApproximate time: {hours} hours, {minutes} minutes +/- {self.deltatime:.1f} minutes')
Esempio n. 5
0
    def verify_roi(self, xs, el, edge, tab=''):
        print(bold_msg(f'{tab}Attempting to set ROIs for {el} {edge} edge'))
        try:
            ## if el is not one of the "standard" 12 ROI sets, insert it into xs.slots[12]/index 13
            if xs.check_element(el, edge):
                forceit = False
                if el.capitalize() in ('Pb',
                                       'Pt') and edge.capitalize() in ('L2',
                                                                       'L1'):
                    forceit = True  # Pb and Pt L3 edges are "standard" ROIs
                if el not in xs.slots or forceit:
                    with open(os.path.join(startup_dir, 'rois.json'),
                              'r') as fl:
                        js = fl.read()
                    allrois = json.loads(js)
                    xs.slots[14] = el
                    for channel in xs.iterate_channels():
                        xs.set_roi_channel(
                            channel,
                            index=15,
                            name=f'{el.capitalize()}',
                            low=allrois[el.capitalize()][edge.lower()]['low'],
                            high=allrois[el.capitalize()][
                                edge.lower()]['high'])
                    xs.set_rois()

                xs.measure_roi()
            else:
                report(
                    f'{tab}No tabulated ROIs for the {el.capitalize()} {edge.capitalize()} edge.  Not setting ROIs for mesaurement.',
                    level='bold',
                    slack=True)
            xs.reset_rois(tab=tab)
        except Exception as E:
            print(error_msg(E))
    def cycle(self, mc=None):
        '''Cycle power to the amplifiers on a motor controller, then reenable
        the motors on that controller.

        Identify the motor controller by these strings:
           'dcm', 'slits2', 'm2', 'm3', 'dm3'

        '''
        if self.check(mc) is False:
            return
        print(bold_msg(f'Cycling amplifiers on {mc} motor controller'))
        print(whisper('killing amplifiers'))
        self.kill(mc)
        countdown(5)
        print(whisper('reactivating amplifiers'))
        self.enable(mc)
        print(whisper('enabling motors'))
        if mc == 'm2':
            user_ns['m2'].ena()
        elif mc == 'm3':
            user_ns['m3'].ena()
        elif mc == 'slits2':
            user_ns['slits2'].enable()
        elif mc == 'dm3':
            user_ns['slits3'].enable()
            for axis in ('dm3_bct', 'dm3_bpm', 'dm3_foils', 'dm3_fs'):
                user_ns[axis].enable()
                time.sleep(0.5)
                user_ns[axis].kill()
        elif mc == 'dcm':
            user_ns['dcm'].ena()
            time.sleep(0.5)
            user_ns['dcm'].kill()
def find_slot(close=False):
    yield from rectangle_scan(motor=xafs_y, start=-3,  stop=3,  nsteps=31, detector='It')
    yield from rectangle_scan(motor=xafs_x, start=-10, stop=10, nsteps=31, detector='It')
    user_ns['xafs_wheel'].in_place()
    print(bold_msg(f'Found slot at (X,Y) = ({xafs_x.position}, {xafs_y.position})'))
    if close:
        close_all_plots()
        def doscan():
            line1 = '%s, %s, %.3f, %.3f, %d -- starting at %.3f\n' % \
                    (motor.name, sgnl, start, stop, nsteps, motor.user_readback.get())

            uid = yield from rel_scan(dets, motor, start, stop, nsteps, md={'plan_name' : f'rel_scan linescan {motor.name} I0'})
            t  = user_ns['db'][-1].table()
            if detector.lower() == 'if':
                signal   = numpy.array((t[BMMuser.xs1]+t[BMMuser.xs2]+t[BMMuser.xs3]+t[BMMuser.xs4])/t['I0'])
            elif detector.lower() == 'it':
                signal   = numpy.array(t['It']/t['I0'])
            elif detector.lower() == 'ir':
                signal   = numpy.array(t['Ir']/t['It'])

            signal = signal - signal[0]
            if negate is True:
                signal = -1 * signal
            pos      = numpy.array(t[motor.name])
            mod      = RectangleModel(form='erf')
            pars     = mod.guess(signal, x=pos)
            out      = mod.fit(signal, pars, x=pos)
            print(whisper(out.fit_report(min_correl=0)))
            out.plot()
            if filename is not None:
                plt.savefig(filename)
            #middle   = out.params['center1'].value + (out.params['center2'].value - out.params['center1'].value)/2
            yield from mv(motor, out.params['midpoint'].value)
            print(bold_msg(f'Found center at {motor.name} = {motor.position}'))
            rkvs.set('BMM:lmfit:center1',   out.params['center1'].value)
            rkvs.set('BMM:lmfit:center2',   out.params['center2'].value)
            rkvs.set('BMM:lmfit:sigma1',    out.params['sigma1'].value)
            rkvs.set('BMM:lmfit:sigma2',    out.params['sigma2'].value)
            rkvs.set('BMM:lmfit:amplitude', out.params['amplitude'].value)
            rkvs.set('BMM:lmfit:midpoint',  out.params['midpoint'].value)
Esempio n. 9
0
def center_sample_y():
    yield from linescan('it', xafs_liny, -1.5, 1.5, 61, pluck=False)
    table = db[-1].table()
    diff = -1 * table['It'].diff()
    inflection = table['xafs_liny'][diff.idxmax()]
    yield from mv(xafs_liny, inflection)
    print(bold_msg('Optimal position in y at %.3f' % inflection))
    def to_xdi(self, filename=None):
        '''Write an XDI-style file with bin energy in the first column and the
        waveform of each of the 4 channels in the other columns.

        '''
        dcm, BMMuser, ring = user_ns['dcm'], user_ns['BMMuser'], user_ns[
            'ring']

        column_list = ['MCA1', 'MCA2', 'MCA3', 'MCA4']
        column_list = [
            f'MCA{channel_number}' for channel_number in self.channel_numbers
        ]
        m2state, m3state = mirror_state()

        handle = open(filename, 'w')
        handle.write('# XDI/1.0 BlueSky/%s\n' % bluesky_version)
        #handle.write('# Scan.uid: %s\n'          % dataframe['start']['uid'])
        #handle.write('# Scan.transient_id: %d\n' % dataframe['start']['scan_id'])
        handle.write(
            '# Beamline.name: BMM (06BM) -- Beamline for Materials Measurement'
        )
        handle.write('# Beamline.xray_source: NSLS-II three-pole wiggler\n')
        handle.write(
            '# Beamline.collimation: paraboloid mirror, 5 nm Rh on 30 nm Pt\n')
        handle.write('# Beamline.focusing: %s\n' % m2state)
        handle.write('# Beamline.harmonic_rejection: %s\n' % m3state)
        handle.write('# Beamline.energy: %.3f\n' % dcm.energy.position)
        handle.write(
            '# Detector.fluorescence: SII Vortex ME4 (4-element silicon drift)\n'
        )
        handle.write('# Scan.end_time: %s\n' % now())
        handle.write('# Scan.dwell_time: %.2f\n' % self.cam.acquire_time.value)
        handle.write('# Facility.name: NSLS-II\n')
        handle.write('# Facility.current: %.1f mA\n' % ring.current.value)
        handle.write('# Facility.mode: %s\n' % ring.mode.value)
        handle.write('# Facility.cycle: %s\n' % BMMuser.cycle)
        handle.write('# Facility.GUP: %d\n' % BMMuser.gup)
        handle.write('# Facility.SAF: %d\n' % BMMuser.saf)
        handle.write('# Column.1: energy (eV)\n')
        for c, mca_number in enumerate(column_list):
            handle.write(f'# Column.{c+2}: MCA{mca_number} (counts)\n')
        handle.write(
            '# ==========================================================\n')
        handle.write('# energy ')

        ## data table
        e = numpy.arange(0, len(
            self.channels.channel01.mca.array_data.get())) * 10
        mca_data_array_list = [
            channel.mca.array_data.get()
            for channel in self.iterate_channels()
        ]
        a = numpy.vstack(mca_data_array_list)
        b = pandas.DataFrame(a.transpose(), index=e, columns=column_list)
        handle.write(b.to_csv(sep=' '))

        handle.flush()
        handle.close()
        print(bold_msg('wrote XRF spectra to %s' % filename))
Esempio n. 11
0
def ls2dat(datafile, key):
    '''
    Export a linescan database entry to a simple column data file.

      ls2dat('/path/to/myfile.dat', '0783ac3a-658b-44b0-bba5-ed4e0c4e7216')

    or

      ls2dat('/path/to/myfile.dat', 1533)

    The arguments are a data file name and the database key.
    '''
    #BMMuser, db = user_ns['BMMuser'], user_ns['db']
    if os.path.isfile(datafile):
        print(error_msg('%s already exists!  Bailing out....' % datafile))
        return
    handle = open(datafile, 'w')
    dataframe = user_ns['db'][key]
    devices = dataframe.devices() # note: this is a _set_ (this is helpful: https://snakify.org/en/lessons/sets/)
    if 'vor' in devices:
        abscissa = dataframe['start']['motors'][0]
        column_list = [abscissa, 'I0', 'It', 'Ir',
                       BMMuser.dtc1, BMMuser.dtc2, BMMuser.dtc3, BMMuser.dtc4,
                       BMMuser.roi1, 'ICR1', 'OCR1',
                       BMMuser.roi2, 'ICR2', 'OCR2',
                       BMMuser.roi3, 'ICR3', 'OCR3',
                       BMMuser.roi4, 'ICR4', 'OCR4']
        template = "  %.3f  %.6f  %.6f  %.6f  %.6f  %.6f  %.6f  %.6f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f\n"
    elif 'DualI0' in devices:
        abscissa = dataframe['start']['motors'][0]
        column_list = [abscissa, 'Ia', 'Ib',]
        template = "  %.3f  %.6f  %.6f\n"
    else:
        abscissa = dataframe['start']['motors'][0]
        template = "  %.3f  %.6f  %.6f  %.6f\n"
        column_list = [abscissa, 'I0', 'It', 'Ir']

    #print(column_list)
    table = dataframe.table()
    this = table.loc[:,column_list]

    handle.write('# XDI/1.0 BlueSky/%s\n'    % bluesky_version)
    handle.write('# Scan.uid: %s\n'          % dataframe['start']['uid'])
    handle.write('# Scan.transient_id: %d\n' % dataframe['start']['scan_id'])
    try:
        handle.write('# Facility.GUP: %s\n'  % dataframe['start']['XDI']['Facility']['GUP'])
    except:
        pass
    try:
        handle.write('# Facility.SAF: %s\n'  % dataframe['start']['XDI']['Facility']['SAF'])
    except:
        pass
    handle.write('# ==========================================================\n')
    handle.write('# ' + '  '.join(column_list) + '\n')
    for i in range(0,len(this)):
        handle.write(template % tuple(this.iloc[i]))
    handle.flush()
    handle.close()
    print(bold_msg('wrote linescan to %s' % datafile))
    def to_xdi(self, filename=None):
        '''Write an XDI-style file with bin energy in the first column and the
        waveform of the measurement channel in the second column.

        '''

        dcm, BMMuser, ring = user_ns['dcm'], user_ns['BMMuser'], user_ns[
            'ring']

        column_list = ['MCA8']
        #template = "  %.3f  %.6f  %.6f  %.6f  %.6f\n"
        m2state, m3state = mirror_state()

        handle = open(filename, 'w')
        handle.write('# XDI/1.0 BlueSky/%s\n' % bluesky_version)
        #handle.write('# Scan.uid: %s\n'          % dataframe['start']['uid'])
        #handle.write('# Scan.transient_id: %d\n' % dataframe['start']['scan_id'])
        handle.write(
            '# Beamline.name: BMM (06BM) -- Beamline for Materials Measurement'
        )
        handle.write('# Beamline.xray_source: NSLS-II three-pole wiggler\n')
        handle.write(
            '# Beamline.collimation: paraboloid mirror, 5 nm Rh on 30 nm Pt\n')
        handle.write('# Beamline.focusing: %s\n' % m2state)
        handle.write('# Beamline.harmonic_rejection: %s\n' % m3state)
        handle.write('# Beamline.energy: %.3f\n' % dcm.energy.position)
        handle.write(
            '# Detector.fluorescence: SII Vortex ME4 (4-element silicon drift)\n'
        )
        handle.write('# Scan.end_time: %s\n' % now())
        handle.write('# Scan.dwell_time: %.2f\n' %
                     self.settings.acquire_time.value)
        handle.write('# Facility.name: NSLS-II\n')
        handle.write('# Facility.current: %.1f mA\n' % ring.current.value)
        handle.write('# Facility.mode: %s\n' % ring.mode.value)
        handle.write('# Facility.cycle: %s\n' % BMMuser.cycle)
        handle.write('# Facility.GUP: %d\n' % BMMuser.gup)
        handle.write('# Facility.SAF: %d\n' % BMMuser.saf)
        handle.write('# Column.1: energy (eV)\n')
        handle.write('# Column.2: MCA1 (counts)\n')
        handle.write(
            '# ==========================================================\n')
        handle.write('# energy ')

        ## data table
        e = numpy.arange(0, len(self.mca1.value)) * 10
        a = numpy.vstack([
            self.mca1.value, self.mca2.value, self.mca3.value, self.mca4.value
        ])
        b = pd.DataFrame(a.transpose(), index=e, columns=column_list)
        handle.write(b.to_csv(sep=' '))

        handle.flush()
        handle.close()
        print(bold_msg('wrote XRF spectra to %s' % filename))
Esempio n. 13
0
 def show_rois(self):
     BMMuser = user_ns['BMMuser']
     text = 'Xspress3 ROIs:\n'
     text += bold_msg('    1      2      3      4      5      6      7      8\n')
     text += ' '
     for i in range(8):
         if self.slots[i] == BMMuser.element:
             text += go_msg('%4.4s' % self.slots[i]) + '   '
         else:
             text += '%4.4s' % self.slots[i] + '   '
     text += '\n'
     text += bold_msg('    9     10     11     12     13     14     15     16\n')
     text += ' '
     for i in range(8, 16):
         if self.slots[i] == BMMuser.element:
             text += go_msg('%4.4s' % self.slots[i]) + '   '
         else:
             text += '%4.4s' % self.slots[i] + '   '
     text += '\n'
     return(text)
Esempio n. 14
0
def amfe():
    print(bold_msg("%-12s : %s / %s" % ('motor', 'AMFE', 'AMFAE')))
    for m in mcs8_motors:
        if m.amfe.get():
            fe = warning_msg(m.amfe.enum_strs[m.amfe.get()])
        else:
            fe = m.amfe.enum_strs[m.amfe.get()]
        if m.amfae.get():
            fae = warning_msg(m.amfae.enum_strs[m.amfae.get()])
        else:
            fae = m.amfae.enum_strs[m.amfae.get()]
        print("%-12s : %s / %s" % (m.name, fe, fae))
Esempio n. 15
0
 def status(self):
     text = '\n  %s is %s\n\n' % (self.name, self.prefix)
     for signal in list(self.configuration_attrs):
         if signal.upper() not in status_list.keys():
             continue
         suffix = getattr(self, signal).pvname.replace(self.prefix, '')
         string = getattr(self, signal).enum_strs[getattr(self,
                                                          signal).get()]
         if signal != 'asscs':
             if getattr(self, signal).get() != status_list[signal.upper()]:
                 string = error_msg('%-19s' % string)
         text += '  %-26s : %-19s  %s   %s \n' % (
             getattr(self, signal + '_desc').get(), string,
             bold_msg(getattr(self, signal).get()), whisper(suffix))
     boxedtext('%s status signals' % self.name, text, 'green')
Esempio n. 16
0
def report(text, level=None, slack=False):
    '''Print a string to:
      * the log file
      * the screen
      * the BMM beamtime slack channel

    Report level decorations  on screen:

      * 'error' (red)
      * 'warning' (yellow)
      * 'info' (brown)
      * 'url' (undecorated)
      * 'bold' (bright white)
      * 'verbosebold' (bright cyan)
      * 'list' (cyan)
      * 'disconnected' (purple)
      * 'whisper' (gray)

    not matching a report level will be undecorated
    '''
    BMMuser = user_ns['BMMuser']
    BMM_log_info(text)
    if color:  # test that color is sensible...
        if level == 'error':
            print(error_msg(text))
        elif level == 'warning':
            print(warning_msg(text))
        elif level == 'info':
            print(info_msg(text))
        elif level == 'url':
            print(url_msg(text))
        elif level == 'bold':
            print(bold_msg(text))
        elif level == 'verbosebold':
            print(verbosebold_msg(text))
        elif level == 'disconnected':
            print(disconnected_msg(text))
        elif level == 'list':
            print(list_msg(text))
        elif level == 'whisper':
            print(whisper(text))
        else:
            print(text)
    else:
        print(text)
    if BMMuser.use_slack and slack:
        post_to_slack(text)
Esempio n. 17
0
 def status(self):
     text = '\n  %s is %s\n\n' % (self.name, self.prefix)
     for signal in status_list.keys():
         sig = signal.lower()
         try:
             suffix = getattr(self, sig).pvname.replace(self.prefix, '')
             string = getattr(self, sig).enum_strs[getattr(self, sig).get()]
             if signal != 'asscs':
                 if getattr(self, sig).get() != status_list[signal]:
                     string = verbosebold_msg('%-19s' % string)
             #text += '  %-26s : %-19s  %s   %s \n' % (getattr(self, sig+'_desc').get(),
             #                                         string,
             #                                         bold_msg(getattr(self, sig).get()),
             #                                         whisper(suffix))
             text += '  %-19s  %s   %s \n' % (
                 string, bold_msg(getattr(self,
                                          sig).get()), whisper(suffix))
         except:
             pass
     boxedtext('%s status signals' % self.name, text, 'green')
    def read_spreadsheet(self):
        '''Slurp up the content of the spreadsheet and write the default control file
        '''
        print('Reading spreadsheet: %s' % self.source)
        count = 0
        self.offset = 0
        isok, explanation = True, ''
        if self.has_e0_column:  # deal with older xlsx that have e0 in column H
            self.offset = 1

        for row in self.ws.rows:
            count += 1
            if count < 6:
                continue
            defaultline = False
            if count == 6:
                defaultline = True
            if count > 200:
                break
            self.measurements.append(self.get_keywords(row, defaultline))

            # check that scan parameters make sense
            if type(self.measurements[-1]['bounds']) is str:
                b = re.split('[ ,]+', self.measurements[-1]['bounds'].strip())
            else:
                b = re.split('[ ,]+', self.measurements[0]['bounds'].strip())
            if type(self.measurements[-1]['steps']) is str:
                s = re.split('[ ,]+', self.measurements[-1]['steps'].strip())
            else:
                s = re.split('[ ,]+', self.measurements[0]['steps'].strip())
            if type(self.measurements[-1]['times']) is str:
                t = re.split('[ ,]+', self.measurements[-1]['times'].strip())
            else:
                t = re.split('[ ,]+', self.measurements[0]['times'].strip())

            (problem, text, reference) = sanitize_step_scan_parameters(b, s, t)
            if problem is True:
                isok = False
                explanation += bold_msg(f'\nrow {count}, sample {self.measurements[-1]["filename"]}:\n') + text
        return(isok, explanation, reference)
Esempio n. 19
0
        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)
Esempio n. 20
0
    def cycle(self, mc=None):
        '''Cycle power to the amplifiers on a motor controller, then reenable
        the motors on that controller.

        Identify the motor controller by these strings:
           'dcm', 'slits2', 'm2', 'm3', 'dm3'

        '''
        if self.check(mc) is False:
            return
        print(bold_msg(f'Cycling amplifiers on {mc} motor controller'))
        print(whisper('killing amplifiers'))
        self.kill(mc)
        countdown(5)
        print(whisper('reactivating amplifiers'))
        self.enable(mc)
        print(whisper('enabling motors'))
        if mc == 'm2':
            m2.ena()
        elif mc == 'm3':
            m3.ena()
        elif mc == 'slits2':
            slits2.enable()
        elif mc == 'dm3':
            slits3.enable()
            for axis in (dm3_bct, dm3_bpm, dm3_foils, dm3_fs):
                try:
                    axis.enable()
                    time.sleep(0.5)
                    axis.kill()
                except:
                    pass
        elif mc == dcm:
            dcm.ena()
            time.sleep(0.5)
            dcm.kill()
Esempio n. 21
0
def set_instrument(instrument=None):
    if instrument.lower() == 'glancing angle':
        print(bold_msg('Setting instrument as glancing angle stage'))
        BMMuser.instrument = 'glancing angle stage'
    elif instrument.lower() == 'double wheel':
        print(bold_msg('Setting instrument as double sample wheel'))
        BMMuser.instrument = 'double wheel'
    elif instrument.lower() == 'linkam':
        print(bold_msg('Setting instrument as Linkam stage'))
        BMMuser.instrument = 'Linkam stage'
    elif instrument.lower() == 'lakeshore':
        print(bold_msg('Setting instrument as LakeShore 331'))
        BMMuser.instrument = 'LakeShore'
    elif instrument.lower() == 'grid':
        print(bold_msg('Setting instrument as sample grid'))
        BMMuser.instrument = 'motor grid'
    else:
        print(bold_msg('Default instrument choice: sample wheel'))
        BMMuser.instrument = 'sample wheel'
    rkvs.set('BMM:automation:type', instrument)
def find_slot(xmargin=0.5, ymargin=2, force=False):
    '''Thin wrapper around repeated calls to linescan in order to align a
    sample wheel slot in the beam. This will perform a linescan in
    xafs_x over the range of -10 to 10 or in xafs_y from -3 to 3
    (which are suitable ranges for the size of the slot).  User is
    prompted to scan in X or Y, or to quit the loop.  The loop will
    return after 6 scans -- 3 iterations is certainly enough for this
    task.

    In bsui terms, this is a wrapper around these command:

       linescan(xafs_x, 'it', -10, 10, 31)

    and 

       linescan(xafs_y, 'it', -3, 3, 31)

    which are suitable linescans for aligning the sample wheel once it
    has been aligned roughly by hand.

    The high limit in xafs_x will be set to 500 microns (the default)
    above the selected position.  The margin cannot be less than 50
    microns.  The low limit in xafs_x is presumed not to be important.

    The high limit in xafs_y will be set to 2 mm (the default) above
    the selected position.  The low limit in xafs_y will be set to 2
    mm (the default) below the selected position.  The margin cannot
    be less than 50 microns.

    Parameters
    ==========

    xmargin : float
        margin for setting the high limit of the xafs_x axis, 
        default=0.5, minimum=0.05
    ymargin : float
        margin for setting the high limit of the xafs_y axis, 
        default=2, minimum=0.05
    force : bool
        passed along to linescan(), flag for forcing a scan even if 
        not clear to start

    '''
    xafs_x, xafs_y = user_ns['xafs_x'], user_ns['xafs_y']
    count = 1
    if xmargin < 0.05:
        xmargin = 0.05
    if ymargin < 0.05:
        ymargin = 0.05
    while True:
        action = input(
            bold_msg(
                "\nScan axis? [x=xafs_x / y=xafs_y / q=quit] (then Enter) "))
        if action[:1].lower() == 'x':
            yield from mv(xafs_x.hlm, xafs_x.default_hlm)
            yield from linescan(xafs_x, 'it', -10, 10, 31, force=force)
            yield from mv(xafs_x.hlm, xafs_x.position + xmargin)
        elif action[:1].lower() == 'y':
            yield from mv(xafs_y.hlm, xafs_y.default_hlm, xafs_y.llm,
                          xafs_y.default_llm)
            yield from linescan(xafs_y, 'it', -3, 3, 31, force=force)
            yield from mv(xafs_y.hlm, xafs_y.position + ymargin, xafs_y.llm,
                          xafs_y.position - ymargin)
        elif action[:1].lower() in ('q', 'n', 'c'):  # quit/no/cancel
            yield from null()
            close_all_plots()
            return
        else:
            continue
        count += 1
        if count > 6:
            print('Three iterations is plenty....')
            close_all_plots()
            return
Esempio n. 23
0
def change_edge(el,
                focus=False,
                edge='K',
                energy=None,
                slits=True,
                target=300.,
                xrd=False,
                bender=True):
    '''Change edge energy by:
    1. Moving the DCM above the edge energy
    2. Moving the photon delivery system to the correct mode
    3. Running a rocking curve scan
    4. Running a slits_height scan

    Parameters
    ----------
    el : str
        one- or two-letter symbol
    focus : bool, optional
        T=focused or F=unfocused beam [False, unfocused]
    edge : str, optional
        edge symbol ['K']
    energy : float, optional
        e0 value [None, determined from el/edge]
    slits : bool, optional
        perform slit_height() scan [False]
    target : float, optional
        energy where rocking curve is measured [300]
    xrd : boolean, optional
        force photon delivery system to XRD [False]

    Examples
    --------
    Normal use, unfocused beam:
       
    >>> RE(change_edge('Fe'))

    Normal use, focused beam:
       
    >>> RE(change_edge('Fe', focus=True))

    L2 or L1 edge:
       
    >>> RE(change_edge('Re', edge='L2'))

    Measure rocking curve at edge energy:
      
    >>> RE(change_edge('Fe', target=0))

    XRD, new energy:
       
    >>> RE(change_edge('Fe', xrd=True, energy=8600))
        
    note that you must specify an element, but it doesn't matter which
    one the energy will be moved to the specified energy xrd=True
    implies focus=True and target=0

    '''
    BMMuser, RE, dcm, dm3_bct = user_ns['BMMuser'], user_ns['RE'], user_ns[
        'dcm'], user_ns['dm3_bct']
    dcm_pitch, dcm_bragg = user_ns['dcm_pitch'], user_ns['dcm_bragg']
    rkvs = user_ns['rkvs']
    try:
        xs = user_ns['xs']
    except:
        pass
    #BMMuser.prompt = True
    el = el.capitalize()

    ######################################################################
    # this is a tool for verifying a macro.  this replaces an xafsmod scan  #
    # with a sleep, allowing the user to easily map out motor motions in #
    # a macro                                                            #
    if BMMuser.macro_dryrun:
        print(
            info_msg(
                '\nBMMuser.macro_dryrun is True.  Sleeping for %.1f seconds rather than changing to the %s edge.\n'
                % (BMMuser.macro_sleep, el)))
        countdown(BMMuser.macro_sleep)
        return (yield from null())
    ######################################################################

    if pds_motors_ready() is False:
        print(
            error_msg(
                '\nOne or more motors are showing amplifier faults.\nToggle the correct kill switch, then re-enable the faulted motor.'
            ))
        return (yield from null())

    (ok, text) = BMM_clear_to_start()
    if ok is False:
        print(
            error_msg('\n' + text) +
            bold_msg('Quitting change_edge() macro....\n'))
        return (yield from null())

    if energy is None:
        energy = edge_energy(el, edge)

    if energy is None:
        print(
            error_msg('\nEither %s or %s is not a valid symbol\n' %
                      (el, edge)))
        return (yield from null())
    if energy > 23500:
        edge = 'L3'
        energy = edge_energy(el, 'L3')

    if energy < 4000:
        print(warning_msg('The %s edge energy is below 4950 eV' % el))
        print(warning_msg('You have to change energy by hand.'))
        return (yield from null())

    if energy > 23500:
        print(
            warning_msg(
                'The %s edge energy is outside the range of this beamline!' %
                el))
        return (yield from null())

    BMMuser.edge = edge
    BMMuser.element = el
    BMMuser.edge_energy = energy
    rkvs.set('BMM:pds:edge', edge)
    rkvs.set('BMM:pds:element', el)
    rkvs.set('BMM:pds:edge_energy', energy)

    if energy > 8000:
        mode = 'A' if focus else 'D'
    elif energy < 6000:
        #mode = 'B' if focus else 'F'   ## mode B currently is inaccessible :(
        mode = 'C' if focus else 'F'
    else:
        mode = 'C' if focus else 'E'
    if xrd:
        mode = 'XRD'
        focus = True
        target = 0.0
    current_mode = get_mode()
    if mode in ('D', 'E', 'F') and current_mode in ('D', 'E', 'F'):
        with_m2 = False
    elif mode in ('A', 'B',
                  'C') and current_mode in ('A', 'B',
                                            'C'):  # no need to move M2
        with_m2 = False
    else:
        with_m2 = True
    if all_connected(with_m2) is False:
        print(warning_msg('Ophyd connection failure' % el))
        return (yield from null())

    ################################
    # confirm configuration change #
    ################################
    print(bold_msg('\nEnergy change:'))
    print('   %s: %s %s' %
          (list_msg('edge'), el.capitalize(), edge.capitalize()))
    print('   %s: %.1f' % (list_msg('edge energy'), energy))
    print('   %s: %.1f' % (list_msg('target energy'), energy + target))
    print('   %s: %s' % (list_msg('focus'), str(focus)))
    print('   %s: %s' % (list_msg('photon delivery mode'), mode))
    print('   %s: %s' % (list_msg('optimizing slits height'), str(slits)))
    if BMMuser.prompt:
        action = input("\nBegin energy change? [Y/n then Enter] ")
        if action.lower() == 'q' or action.lower() == 'n':
            return (yield from null())
        if mode == 'C' and energy < 6000:
            print(
                warning_msg(
                    '\nMoving to mode C for focused beam and an edge energy below 6 keV.'
                ))
            action = input(
                "You will not get optimal harmonic rejection.  Continue anyway?  [Y/n then Enter] "
            )
            if action.lower() == 'q' or action.lower() == 'n':
                return (yield from null())

    start = time.time()
    if mode == 'XRD':
        report('Configuring beamline for XRD', level='bold', slack=True)
    else:
        report(
            f'Configuring beamline for {el.capitalize()} {edge.capitalize()} edge',
            level='bold',
            slack=True)
    yield from dcm.kill_plan()

    ################################################
    # change to the correct photon delivery mode   #
    #      + move mono to correct energy           #
    #      + move reference holder to correct slot #
    ################################################
    # if not calibrating and mode != current_mode:
    #     print('Moving to photon delivery mode %s...' % mode)
    yield from mv(dcm_bragg.acceleration, BMMuser.acc_slow)
    yield from change_mode(mode=mode,
                           prompt=False,
                           edge=energy + target,
                           reference=el,
                           bender=bender)
    yield from mv(dcm_bragg.acceleration, BMMuser.acc_fast)
    if arrived_in_mode(mode=mode) is False:
        print(error_msg(f'\nFailed to arrive in Mode {mode}'))
        print(
            'Fixing this is often as simple as re-running the change_mode() command.'
        )
        print('Or try dm3_bct.kill() the re-run the change_mode() command.')
        print('If that doesn\'t work, call for help')
        return (yield from null())

    yield from user_ns['kill_mirror_jacks']()
    yield from sleep(1)
    if BMMuser.motor_fault is not None:
        print(
            error_msg('\nSome motors are reporting amplifier faults: %s' %
                      BMMuser.motor_fault))
        print(
            'Clear the faults and try running the same change_edge() command again.'
        )
        print('Troubleshooting: ' + url_msg(
            'https://nsls-ii-bmm.github.io/BeamlineManual/trouble.html#amplifier-fault'
        ))
        BMMuser.motor_fault = None
        return (yield from null())
    BMMuser.motor_fault = None

    ############################
    # run a rocking curve scan #
    ############################
    print('Optimizing rocking curve...')
    yield from abs_set(dcm_pitch.kill_cmd, 1, wait=True)
    yield from mv(dcm_pitch, approximate_pitch(energy + target))
    yield from sleep(1)
    yield from abs_set(dcm_pitch.kill_cmd, 1, wait=True)
    yield from rocking_curve()
    close_last_plot()

    ##########################
    # run a slit height scan #
    ##########################
    if slits:
        print('Optimizing slits height...')
        yield from slit_height(move=True)
        close_last_plot()
        ## redo rocking curve?

    ##################################
    # set reference and roi channels #
    ##################################
    if not xrd:
        ## reference channel
        rois = user_ns['rois']
        print('Moving reference foil...')
        yield from rois.select_plan(el)
        ## Xspress3
        BMMuser.verify_roi(xs, el, edge)
        ## feedback
        show_edges()

    if mode == 'XRD':
        report('Finished configuring for XRD', level='bold', slack=True)
    else:
        report(
            f'Finished configuring for {el.capitalize()} {edge.capitalize()} edge',
            level='bold',
            slack=True)
    if slits is False:
        print(
            '  * You may need to verify the slit position:  RE(slit_height())')
    self.to_json(os.path.join(self.DATA, '.BMMuser'))
    yield from dcm.kill_plan()
    end = time.time()
    print('\n\nThat took %.1f min' % ((end - start) / 60))
    return ()
Esempio n. 24
0
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!')
Esempio n. 25
0
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!')
Esempio n. 26
0
def as2dat(datafile, key):
    '''
    Export an areascan database entry to a simple column data file.

      as2dat('/path/to/myfile.dat', '42447313-46a5-42ef-bf8a-46fedc2c2bd1')

    or

      as2dat('/path/to/myfile.dat', 2948)

    The arguments are a data file name and the database key.
    '''

    BMMuser, db = user_ns['BMMuser'], user_ns['db']
    if os.path.isfile(datafile):
        print(error_msg('%s already exists!  Bailing out....' % datafile))
        return
    dataframe = db[key]
    if 'slow_motor' not in dataframe['start']:
        print(
            error_msg(
                'That database entry does not seem to be a an areascan (missing slow_motor)'
            ))
        return
    if 'fast_motor' not in dataframe['start']:
        print(
            error_msg(
                'That database entry does not seem to be a an areascan (missing fast_motor)'
            ))
        return

    devices = dataframe.devices(
    )  # note: this is a _set_ (this is helpful: https://snakify.org/en/lessons/sets/)

    if 'vor' in devices:
        column_list = [
            dataframe['start']['slow_motor'], dataframe['start']['fast_motor'],
            'I0', 'It', 'Ir', BMMuser.dtc1, BMMuser.dtc2, BMMuser.dtc3,
            BMMuser.dtc4, BMMuser.roi1, 'ICR1', 'OCR1', BMMuser.roi2, 'ICR2',
            'OCR2', BMMuser.roi3, 'ICR3', 'OCR3', BMMuser.roi4, 'ICR4', 'OCR4'
        ]
        template = "  %.3f  %.3f  %.6f  %.6f  %.6f  %.6f  %.6f  %.6f  %.6f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f  %.1f\n"
    else:
        column_list = [
            dataframe['start']['slow_motor'], dataframe['start']['fast_motor'],
            'I0', 'It', 'Ir'
        ]
        template = "  %.3f  %.3f  %.6f  %.6f  %.6f\n"

    table = dataframe.table()
    this = table.loc[:, column_list]

    handle = open(datafile, 'w')
    handle.write('# Scan.uid: %s\n' % dataframe['start']['uid'])
    handle.write('# Scan.transient_id: %d\n' % dataframe['start']['scan_id'])
    try:
        handle.write('# Facility.GUP: %d\n' %
                     dataframe['start']['XDI']['Facility']['GUP'])
    except:
        pass
    try:
        handle.write('# Facility.SAF: %d\n' %
                     dataframe['start']['XDI']['Facility']['SAF'])
    except:
        pass
    handle.write(
        '# ==========================================================\n')
    handle.write('# ' + '  '.join(column_list) + '\n')
    slowval = None
    for i in range(0, len(this)):
        if i > 0 and this.iloc[i, 0] != slowval:
            handle.write('\n')
        handle.write(template % tuple(this.iloc[i]))
        slowval = this.iloc[i, 0]
    handle.flush()
    handle.close()
    print(bold_msg('wrote areascan to %s' % datafile))
Esempio n. 27
0
def center_sample_roll():
    yield from linescan('it', xafs_roll, -3, 3, 61, pluck=False)
    table = db[-1].table()
    peak = table['xafs_roll'][table['It'].idxmax()]
    yield from mv(xafs_roll, peak)
    print(bold_msg('Optimal position in roll at %.3f' % peak))
Esempio n. 28
0
    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)
Esempio n. 29
0
    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 align_ga(ymargin=0.5, force=False):
    '''Thin wrapper around repeated calls to linescan in order to align 
    the glancing angle stage in the beam. This will perform a linescan in
    xafs_pitch over the range of -2 to 2 or in xafs_y from -1 to 1
    (which are suitable ranges for the size of the slot).  User is
    prompted to scan in pitch or Y, or to quit the loop.  The loop will
    return after 6 scans -- 3 iterations is certainly enough for this
    task.

    In bsui terms, this is a wrapper around these command:

       linescan(xafs_y, 'it', -1, 1, 31)

    and 

       linescan(xafs_pitch, 'it', -2, 2, 31)

    which are suitable linescans for aligning the glancing angle stage
    once it has been aligned roughly by hand.

    The high limit in xafs_y will be set to 0.5 mm (the default) above
    the selected position.  The low limit in xafs_y will be set to 0.5
    mm (the default) below the selected position.  The margin cannot
    be less than 50 microns.

    Parameters
    ==========

    ymargin : float
        margin for setting the high limit of the xafs_y axis, 
        default=2, minimum=0.05
    force : bool
        passed along to linescan(), flag for forcing a scan even if 
        not clear to start

    '''
    xafs_pitch, xafs_y = user_ns['xafs_pitch'], user_ns['xafs_y']
    db = user_ns['db']
    count = 1
    if ymargin < 0.05:
        ymargin = 0.05
    while True:
        action = input(
            bold_msg(
                "\nScan axis? [p=xafs_pitch / y=xafs_y / q=quit] (then Enter) "
            ))
        if action[:1].lower() == 'p':
            yield from linescan(xafs_pitch, 'it', -3, 3, 31, force=force)
        elif action[:1].lower() == 'y':
            yield from mv(xafs_y.hlm, xafs_y.default_hlm, xafs_y.llm,
                          xafs_y.default_llm)
            yield from linescan(xafs_y, 'it', -2, 2, 31, force=force)
            #yield from mv(xafs_y.hlm, xafs_y.position+ymargin, xafs_y.llm, xafs_y.position-ymargin)
        elif action[:1].lower() in ('q', 'n', 'c'):  # quit/no/cancel
            yield from null()
            close_all_plots()
            return
        else:
            continue
        count += 1
        if count > 6:
            print('Three iterations is plenty....')
            close_all_plots()
            return