示例#1
0
 def align_linear(self, force=False, drop=None):
     '''Fit an error function to the linear scan against It. Plot the
     result. Move to the centroid of the error function.'''
     if self.orientation == 'parallel':
         motor = user_ns['xafs_liny']
     else:
         motor = user_ns['xafs_linx']
     yield from linescan(motor, 'it', -2.3, 2.3, 51, pluck=False)
     close_last_plot()
     table  = user_ns['db'][-1].table()
     yy     = table[motor.name]
     signal = table['It']/table['I0']
     if drop is not None:
         yy = yy[:-drop]
         signal = signal[:-drop]
     if float(signal[2]) > list(signal)[-2] :
         ss     = -(signal - signal[2])
         self.inverted = 'inverted '
     else:
         ss     = signal - signal[2]
         self.inverted    = ''
     mod    = StepModel(form='erf')
     pars   = mod.guess(ss, x=numpy.array(yy))
     out    = mod.fit(ss, pars, x=numpy.array(yy))
     print(whisper(out.fit_report(min_correl=0)))
     target = out.params['center'].value
     yield from mv(motor, target)
     self.y_plot(yy, out)
 def align_y(self, force=False, drop=None):
     '''Fit an error function to the xafs_y scan against It. Plot the
     result. Move to the centroid of the error function.'''
     xafs_y = user_ns['xafs_y']
     db = user_ns['db']
     yield from linescan(xafs_y, 'it', -1, 1, 31, pluck=False)
     close_last_plot()
     table = db[-1].table()
     yy = table['xafs_y']
     signal = table['It'] / table['I0']
     if drop is not None:
         yy = yy[:-drop]
         signal = signal[:-drop]
     if float(signal[2]) > list(signal)[-2]:
         ss = -(signal - signal[2])
         self.inverted = 'inverted '
     else:
         ss = signal - signal[2]
         self.inverted = ''
     mod = StepModel(form='erf')
     pars = mod.guess(ss, x=numpy.array(yy))
     out = mod.fit(ss, pars, x=numpy.array(yy))
     print(whisper(out.fit_report(min_correl=0)))
     self.y_plot(yy, out)
     target = out.params['center'].value
     yield from mv(xafs_y, target)
示例#3
0
def wafer_edge(motor='x'):
    '''Fit an error function to the linear scan against It. Plot the
    result. Move to the centroid of the error function.'''
    if motor == 'x':
        motor = user_ns['xafs_linx']
    else:
        motor = user_ns['xafs_liny']
    yield from linescan(motor, 'it', -2, 2, 41, pluck=False)
    close_last_plot()
    table = user_ns['db'][-1].table()
    yy = table[motor.name]
    signal = table['It'] / table['I0']
    if float(signal[2]) > list(signal)[-2]:
        ss = -(signal - signal[2])
    else:
        ss = signal - signal[2]
    mod = StepModel(form='erf')
    pars = mod.guess(ss, x=numpy.array(yy))
    out = mod.fit(ss, pars, x=numpy.array(yy))
    print(whisper(out.fit_report(min_correl=0)))
    out.plot()
    target = out.params['center'].value
    yield from mv(motor, target)
    yield from resting_state_plan()
    print(
        f'Edge found at X={user_ns["xafs_x"].position} and Y={user_ns["xafs_y"].position}'
    )
示例#4
0
 def align_pitch(self, force=False):
     '''Find the peak of xafs_pitch scan against It. Plot the
     result. Move to the peak.'''        
     xafs_pitch = user_ns['xafs_pitch']
     yield from linescan(xafs_pitch, 'it', -2.5, 2.5, 51, pluck=False, force=force)
     close_last_plot()
     table  = user_ns['db'][-1].table()
     pitch  = table['xafs_pitch']
     signal = table['It']/table['I0']
     target = signal.idxmax()
     yield from mv(xafs_pitch, pitch[target])
     self.pitch_plot(pitch, signal)
示例#5
0
    def auto_align(self, pitch=2, drop=None):
        '''Align a sample on a spinner automatically.  This performs 5 scans.
        The first four iterate twice between linear and pitch
        against the signal in It.  This find the flat position.

        Then the sample is pitched to the requested angle and a fifth
        scan is done to optimize the linear motor position against the
        fluorescence signal.

        The linear scans against It look like a step-down function.
        The center of this step is found as the centroid of a fitted
        error function.

        The xafs_pitch scan should be peaked.  Move to the max of the
        signal.

        The linear scan against fluorescence ideally looks like a
        flat-topped peak.  Move to the center of mass.

        At the end, a three-panel figure is drawn showing the last
        three scans.  This is posted to Slack.  It also finds its way
        into the dossier as a record of the quality of the alignment.

        Arguments
        =========
        pitch : int
          The angle at which to make the glancing angle measurements.
        drop : int or None
          If not None, then this many points will be dropped from the
          end of linear scan against transmission when fitting the error
          function. This is an attempt to deal gracefully with leakage 
          through the adhesive at very high energy.

        '''
        BMMuser = user_ns['BMMuser']
        if BMMuser.macro_dryrun:
            report(f'Auto-aligning glancing angle stage, spinner {self.current()}', level='bold', slack=False)
            print(info_msg(f'\nBMMuser.macro_dryrun is True.  Sleeping for %.1f seconds at spinner %d.\n' %
                           (BMMuser.macro_sleep, self.current())))
            countdown(BMMuser.macro_sleep)
            return(yield from null())

        report(f'Auto-aligning glancing angle stage, spinner {self.current()}', level='bold', slack=True)
            
        BMM_suspenders()

        ## first pass in transmission
        yield from self.align_linear(drop=drop)
        yield from self.align_pitch()

        ## for realsies X or Y in transmission
        yield from self.align_linear(drop=drop)
        self.y_uid = user_ns['db'].v2[-1].metadata['start']['uid'] 

        ## for realsies Y in pitch
        yield from self.align_pitch()
        self.pitch_uid = user_ns['db'].v2[-1].metadata['start']['uid'] 

        ## record the flat position
        if self.orientation == 'parallel':
            motor = user_ns['xafs_y']
        else:
            motor = user_ns['xafs_x']
        self.flat = [motor.position, user_ns['xafs_pitch'].position]

        ## move to measurement angle and align
        yield from mvr(user_ns['xafs_pitch'], pitch)
        yield from linescan(motor, 'xs', -2.3, 2.3, 51, pluck=False)
        self.f_uid = user_ns['db'].v2[-1].metadata['start']['uid'] 
        tf = user_ns['db'][-1].table()
        yy = tf[motor.name]
        signal = (tf[BMMuser.xs1] + tf[BMMuser.xs2] + tf[BMMuser.xs3] + tf[BMMuser.xs4]) / tf['I0']
        if BMMuser.element == 'Zr':
            centroid = yy[signal.idxmax()]
        else:
            com = int(center_of_mass(signal)[0])+1
            centroid = yy[com]
        yield from mv(motor, centroid)
        
        ## make a pretty picture, post it to slack
        self.alignment_plot(self.y_uid, self.pitch_uid, self.f_uid)
        self.alignment_filename = os.path.join(BMMuser.folder, 'snapshots', f'spinner{self.current()}-alignment-{now()}.png')
        plt.savefig(self.alignment_filename)
        try:
            img_to_slack(self.alignment_filename)
        except:
            post_to_slack('failed to post image: {self.alignment_filename}')
            pass
        BMM_clear_suspenders()
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
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