Ejemplo n.º 1
0
        def scan_slit(slp):

            #if slit_height < 0.5:
            #    yield from mv(slits3.vsize, 0.5)

            yield from abs_set(quadem1.averaging_time, 0.1, wait=True)
            yield from abs_set(motor.velocity, 0.4, wait=True)
            yield from abs_set(motor.kill_cmd, 1, wait=True)

            uid = yield from rel_scan([quadem1], motor, start, stop, nsteps)

            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 = 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 abs_set(motor.kill_cmd, 1, wait=True)
                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 abs_set(motor.kill_cmd, 1, wait=True)
                yield from move_after_scan(motor)
            yield from abs_set(quadem1.averaging_time, 0.5, wait=True)
    def into_control_range(self, p_theta=2, p_y=-15, p_z=90):
        """
        Move the Kohzu motors into range so the energy controls will work.

        Written as a bluesky plan so that all motors can be moved
        simultaneously.  Return early if the motors are already in range.

        USAGE::

            RE(dcm.into_control_range())
        """
        args = []
        if self.m_theta.position < p_theta:
            args += [self.m_theta, p_theta]
        if self.m_y.position > p_y:
            args += [self.m_y, p_y]
        if self.m_z.position < p_z:
            args += [self.m_z, p_z]
        if (len(args) == 0):
            # all motors in range, no work to do, MUST yield something
            yield from bps.null()
            return
        yield from bps.sleep(1)  # allow IOC to react
        yield from bps.mv(self.operator_acknowledge, 1, self.mode, "Auto")
Ejemplo n.º 3
0
def execute_command_list(filename, commands, md=None):
    """
    plan: execute the command list

    The command list is a tuple described below.

    * Only recognized commands will be executed.
    * Unrecognized commands will be reported as comments.

    See example implementation with APS USAXS instrument:
    https://github.com/APS-USAXS/ipython-usaxs/blob/5db882c47d935c593968f1e2144d35bec7d0181e/profile_bluesky/startup/50-plans.py#L381-L469

    PARAMETERS

    filename : str
        Name of input text file.  Can be relative or absolute path,
        such as "actions.txt", "../sample.txt", or
        "/path/to/overnight.txt".
    commands : list[command]
        List of command tuples for use in ``execute_command_list()``

    where

    command : tuple
        (action, OrderedDict, line_number, raw_command)
    action: str
        names a known action to be handled
    parameters: list
        List of parameters for the action.
        The list is empty of there are no values
    line_number: int
        line number (1-based) from the input text file
    raw_command: obj (str or list(str)
        contents from input file, such as:
        ``SAXS 0 0 0 blank``

    SEE ALSO

    .. autosummary::

        ~execute_command_list
        ~register_command_handler
        ~run_command_file
        ~summarize_command_file
        ~parse_Excel_command_file
        ~parse_text_command_file

    *new in apstools release 1.1.7*
    """
    full_filename = os.path.abspath(filename)

    if len(commands) == 0:
        yield from bps.null()
        return

    text = f"Command file: {filename}\n"
    text += str(APS_utils.command_list_as_table(commands))
    print(text)

    for command in commands:
        action, args, i, raw_command = command
        print(f"file line {i}: {raw_command}")

        _md = {}
        _md["full_filename"] = full_filename
        _md["filename"] = filename
        _md["line_number"] = i
        _md["action"] = action
        _md["parameters"] = args    # args is shorter than parameters, means the same thing here

        _md.update(md or {})      # overlay with user-supplied metadata

        action = action.lower()
        if action == "tune_optics":
            # example: yield from tune_optics(md=_md)
            emsg = "This is an example.  action={raw_command}."
            emsg += "  Must define your own execute_command_list() function"
            logger.warn(emsg)
            yield from bps.null()

        else:
            print(f"no handling for line {i}: {raw_command}")
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
 def per_nd_step(detectors, post_cache, *args, **kwargs):
     yield from bps.null()
Ejemplo n.º 6
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!')
Ejemplo n.º 7
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 ()
Ejemplo n.º 8
0
    def main_plan(start, stop, nsteps, move, slp, force):
        (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
        BMMuser.motor = user_ns['dm3_bct']
        func = lambda doc: (doc['data'][motor.name], doc['data']['I0'])
        plot = DerivedPlot(func,
                           xlabel=motor.name,
                           ylabel='I0',
                           title='I0 signal vs. slit height')
        line1 = '%s, %s, %.3f, %.3f, %d -- starting at %.3f\n' % \
                (motor.name, 'i0', start, stop, nsteps, motor.user_readback.get())
        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_slit(slp):

            #if slit_height < 0.5:
            #    yield from mv(slits3.vsize, 0.5)

            yield from abs_set(quadem1.averaging_time, 0.1, wait=True)
            yield from abs_set(motor.velocity, 0.4, wait=True)
            yield from abs_set(motor.kill_cmd, 1, wait=True)

            uid = yield from rel_scan([quadem1], motor, start, stop, nsteps)

            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 = 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 abs_set(motor.kill_cmd, 1, wait=True)
                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 abs_set(motor.kill_cmd, 1, wait=True)
                yield from move_after_scan(motor)
            yield from abs_set(quadem1.averaging_time, 0.5, wait=True)

        yield from scan_slit(slp)
Ejemplo n.º 9
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()
Ejemplo n.º 10
0
 def bailout():
     print(whisper('doing nothing'))
     yield from null()
Ejemplo n.º 11
0
 def do_nothing(self):
     print(whisper('doing nothing'))
     yield from null()
Ejemplo n.º 12
0
 def do_SlitHeight(self):
     print(go_msg('You would like to set the slit height...\n'))
     print(disconnected_msg('yield from slit_height()'))
     yield from null()
Ejemplo n.º 13
0
 def do_XRFSpectrum(self):
     print(go_msg('You would like to see an XRF spectrum...\n'))
     user_ns['xs'].measure_xrf()
     yield from null()
Ejemplo n.º 14
0
 def do_RockingCurve(self):
     print(go_msg('You would like to measure a rocking curve scan...\n'))
     print(disconnected_msg('yield from rocking_curve()'))
     yield from null()
Ejemplo n.º 15
0
 def do_Spreadsheet(self):
     print(go_msg('You would like to import a spreadsheet...\n'))
     ## prompt for type of spreadsheet: wheel or glancing angle
     ret = user_ns['wmb'].spreadsheet()
     yield from null()
Ejemplo n.º 16
0
def set_filters(thickness=None, state=None):
    positions = [55, -46.5, -20.5, 5.5, 31]

    BMMuser = user_ns['BMMuser']
    if thickness == 0 or state == 0:
        yield from mv(dm1_filters1, positions[0], dm1_filters2, positions[0])
        BMMuser.filter_state = 0
    elif thickness == 100 or state == 1:
        yield from mv(dm1_filters1, positions[1], dm1_filters2, positions[0])
        BMMuser.filter_state = 1
    elif thickness == 200 or state == 2:
        yield from mv(dm1_filters1, positions[2], dm1_filters2, positions[0])
        BMMuser.filter_state = 2
    elif thickness == 300 or state == 3:
        yield from mv(dm1_filters1, positions[2], dm1_filters2, positions[1])
        BMMuser.filter_state = 3
    elif thickness == 400 or state == 4:
        yield from mv(dm1_filters1, positions[2], dm1_filters2, positions[2])
        BMMuser.filter_state = 4
    elif thickness == 500 or state == 5:
        yield from mv(dm1_filters1, positions[3], dm1_filters2, positions[0])
        BMMuser.filter_state = 5
    elif thickness == 600 or state == 6:
        yield from mv(dm1_filters1, positions[3], dm1_filters2, positions[1])
        BMMuser.filter_state = 6
    elif thickness == 700 or state == 7:
        yield from mv(dm1_filters1, positions[3], dm1_filters2, positions[2])
        BMMuser.filter_state = 7
    elif thickness == 1000 or state == 8:
        yield from mv(dm1_filters1, positions[3], dm1_filters2, positions[3])
        BMMuser.filter_state = 8
    elif thickness == 1700 or state == 9:
        yield from mv(dm1_filters1, positions[4], dm1_filters2, positions[0])
        BMMuser.filter_state = 9
    elif thickness == 1800 or state == 10:
        yield from mv(dm1_filters1, positions[4], dm1_filters2, positions[1])
        BMMuser.filter_state = 10
    elif thickness == 1900 or state == 11:
        yield from mv(dm1_filters1, positions[4], dm1_filters2, positions[2])
        BMMuser.filter_state = 11
    elif thickness == 2200 or state == 12:
        yield from mv(dm1_filters1, positions[4], dm1_filters2, positions[3])
        BMMuser.filter_state = 12
    elif thickness == 3400 or state == 13:
        yield from mv(dm1_filters1, positions[4], dm1_filters2, positions[4])
        BMMuser.filter_state = 13
    else:
        print(error_msg('Valid filter thicknesses are: '))
        print(error_msg('    state  0: 0 μm'))
        print(error_msg('    state  1: 100 μm'))
        print(error_msg('    state  2: 200 μm'))
        print(error_msg('    state  3: 300 μm'))
        print(error_msg('    state  4: 400 μm'))
        print(error_msg('    state  5: 500 μm'))
        print(error_msg('    state  6: 600 μm'))
        print(error_msg('    state  7: 700 μm'))
        print(error_msg('    state  8: 1000 μm'))
        print(error_msg('    state  9: 1700 μm'))
        print(error_msg('    state 10: 1800 μm'))
        print(error_msg('    state 11: 1900 μm'))
        print(error_msg('    state 12: 2200 μm'))
        print(error_msg('    state 13: 3400 μm'))
        yield from null()
Ejemplo n.º 17
0
def empty_plan(*args, **kwargs):
    logger.info(f"Doing nothing: args={args}, kwargs={kwargs}")
    yield from bps.null()
Ejemplo n.º 18
0
def rocking_curve(start=-0.10,
                  stop=0.10,
                  nsteps=101,
                  detector='I0',
                  choice='peak'):
    '''Perform a relative scan of the DCM 2nd crystal pitch around the current
    position to find the peak of the crystal rocking curve.  Begin by opening
    the hutch slits to 3 mm. At the end, move to the position of maximum 
    intensity on I0, then return to the hutch slits to their original height.

    Parameters
    ----------
    start : (float)
        starting position relative to current [-0.1]
    end : (float)
        ending position relative to current [0.1]
    nsteps : (int)
        number of steps [101]
    detector : (string)
        'I0' or 'Bicron' ['I0']
    choice : (string)
        'peak', fit' or 'com' (center of mass) ['peak']

    If choice is fit, the fit is performed using the
    SkewedGaussianModel from lmfit, which works pretty well for this
    measurement at BMM.  The line shape is a bit skewed due to the
    convolution with the slightly misaligned entrance slits.

    '''
    def main_plan(start, stop, nsteps, detector):
        (ok, text) = BMM_clear_to_start()
        if ok is False:
            print(error_msg(text))
            yield from null()
            return

        RE.msg_hook = None
        BMMuser.motor = motor

        if detector.lower() == 'bicron':
            func = lambda doc: (doc['data'][motor.name], doc['data']['Bicron'])
            dets = [
                bicron,
            ]
            sgnl = 'Bicron'
            titl = 'Bicron signal vs. DCM 2nd crystal pitch'
        else:
            func = lambda doc: (doc['data'][motor.name], doc['data']['I0'])
            dets = [
                quadem1,
            ]
            sgnl = 'I0'
            titl = 'I0 signal vs. DCM 2nd crystal pitch'

        plot = DerivedPlot(func, xlabel=motor.name, ylabel=sgnl, title=titl)

        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_dcmpitch(sgnl):
            line1 = '%s, %s, %.3f, %.3f, %d -- starting at %.3f\n' % \
                    (motor.name, sgnl, start, stop, nsteps, motor.user_readback.get())

            yield from abs_set(user_ns['_locked_dwell_time'], 0.1, wait=True)
            yield from dcm.kill_plan()

            yield from mv(slits3.vsize, 3)
            if sgnl == 'Bicron':
                yield from mv(slitsg.vsize, 5)

            uid = yield from rel_scan(dets, motor, start, stop, nsteps)
            #yield from rel_adaptive_scan(dets, 'I0', motor,
            #                             start=start,
            #                             stop=stop,
            #                             min_step=0.002,
            #                             max_step=0.03,
            #                             target_delta=.15,
            #                             backstep=True)
            t = db[-1].table()
            signal = t[sgnl]
            if choice.lower() == 'com':
                position = com(signal)
                top = t[motor.name][position]
            elif choice.lower() == 'fit':
                pitch = t['dcm_pitch']
                mod = SkewedGaussianModel()
                pars = mod.guess(signal, x=pitch)
                out = mod.fit(signal, pars, x=pitch)
                print(whisper(out.fit_report(min_correl=0)))
                out.plot()
                top = out.params['center'].value
            else:
                position = peak(signal)
                top = t[motor.name][position]

            yield from sleep(3.0)
            yield from abs_set(motor.kill_cmd, 1, wait=True)
            RE.msg_hook = BMM_msg_hook

            BMM_log_info('rocking curve scan: %s\tuid = %s, scan_id = %d' %
                         (line1, uid, user_ns['db'][-1].start['scan_id']))
            yield from mv(motor, top)
            if sgnl == 'Bicron':
                yield from mv(slitsg.vsize, gonio_slit_height)

        yield from scan_dcmpitch(sgnl)

    def cleanup_plan():
        yield from mv(user_ns['slits3'].vsize, slit_height)
        yield from abs_set(user_ns['_locked_dwell_time'], 0.5, wait=True)
        yield from sleep(1.0)
        yield from abs_set(motor.kill_cmd, 1, wait=True)
        yield from sleep(1.0)
        yield from user_ns['dcm'].kill_plan()
        yield from resting_state_plan()

    RE, BMMuser, db, rkvs = user_ns['RE'], user_ns['BMMuser'], user_ns[
        'db'], user_ns['rkvs']
    dcm, slits3, slitsg, quadem1 = user_ns['dcm'], user_ns['slits3'], user_ns[
        'slitsg'], user_ns['quadem1']
    ######################################################################
    # this is a tool for verifying a macro.  this replaces this rocking  #
    # curve 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 rocking curve scan.\n'
                % BMMuser.macro_sleep))
        countdown(BMMuser.macro_sleep)
        return (yield from null())
    ######################################################################
    motor = user_ns['dcm_pitch']
    slit_height = user_ns['slits3'].vsize.readback.get()
    try:
        gonio_slit_height = slitsg.vsize.readback.get()
    except:
        gonio_slit_height = 1
    RE.msg_hook = None
    yield from finalize_wrapper(main_plan(start, stop, nsteps, detector),
                                cleanup_plan())
    RE.msg_hook = BMM_msg_hook
Ejemplo n.º 19
0
def slit_height(start=-1.5,
                stop=1.5,
                nsteps=31,
                move=False,
                force=False,
                slp=1.0,
                choice='peak'):
    '''Perform a relative scan of the DM3 BCT motor around the current
    position to find the optimal position for slits3. Optionally, the
    motor will moved to the center of mass of the peak at the end of
    the scan.

    Parameters
    ----------
    start : float
        starting position relative to current [-3.0]
    end : float 
        ending position relative to current [3.0]
    nsteps : int
        number of steps [61]
    move : bool
        True=move to position of max signal, False=pluck and move [False]
    slp : float
        length of sleep before trying to move dm3_bct [3.0]
    choice : str 
        'peak' or 'com' (center of mass) ['peak']
    '''
    def main_plan(start, stop, nsteps, move, slp, force):
        (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
        BMMuser.motor = user_ns['dm3_bct']
        func = lambda doc: (doc['data'][motor.name], doc['data']['I0'])
        plot = DerivedPlot(func,
                           xlabel=motor.name,
                           ylabel='I0',
                           title='I0 signal vs. slit height')
        line1 = '%s, %s, %.3f, %.3f, %d -- starting at %.3f\n' % \
                (motor.name, 'i0', start, stop, nsteps, motor.user_readback.get())
        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_slit(slp):

            #if slit_height < 0.5:
            #    yield from mv(slits3.vsize, 0.5)

            yield from abs_set(quadem1.averaging_time, 0.1, wait=True)
            yield from abs_set(motor.velocity, 0.4, wait=True)
            yield from abs_set(motor.kill_cmd, 1, wait=True)

            uid = yield from rel_scan([quadem1], motor, start, stop, nsteps)

            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 = 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 abs_set(motor.kill_cmd, 1, wait=True)
                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 abs_set(motor.kill_cmd, 1, wait=True)
                yield from move_after_scan(motor)
            yield from abs_set(quadem1.averaging_time, 0.5, wait=True)

        yield from scan_slit(slp)

    def cleanup_plan(slp):
        yield from mv(slits3.vsize, slit_height)
        yield from abs_set(user_ns['_locked_dwell_time'], 0.5, wait=True)
        yield from sleep(slp)
        yield from abs_set(motor.kill_cmd, 1, wait=True)
        yield from resting_state_plan()

    RE, BMMuser, db, slits3, quadem1 = user_ns['RE'], user_ns[
        'BMMuser'], user_ns['db'], user_ns['slits3'], user_ns['quadem1']
    rkvs = user_ns['rkvs']
    #######################################################################
    # this is a tool for verifying a macro.  this replaces this slit      #
    # height 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 slit height scan.\n'
                % BMMuser.macro_sleep))
        countdown(BMMuser.macro_sleep)
        return (yield from null())
    #######################################################################
    motor = user_ns['dm3_bct']
    slit_height = slits3.vsize.readback.get()
    RE.msg_hook = None
    yield from finalize_wrapper(
        main_plan(start, stop, nsteps, move, slp, force), cleanup_plan(slp))
    RE.msg_hook = BMM_msg_hook
Ejemplo n.º 20
0
def linescan(detector,
             axis,
             start,
             stop,
             nsteps,
             pluck=True,
             force=False,
             inttime=0.1,
             md={}):  # integration time?
    '''
    Generic linescan plan.  This is a RELATIVE scan, relative to the
    current position of the selected motor.

    Examples
    --------

    >>> RE(linescan('it', 'x', -1, 1, 21))

    Parameters
    ----------
    detector : str
        detector to display -- if, it, ir, or i0
    axis : str or EpicsMotor
        motor or nickname
    start : float
        starting value for a relative scan
    stop : float
         ending value for a relative scan
    nsteps : int
        number of steps in scan
    pluck : bool, optional
        flag for whether to offer to pluck & move motor
    force : bool, optional
        flag for forcing a scan even if not clear to start
    inttime : float, optional
        integration time in seconds (default: 0.1)

    The motor is either the BlueSky name for a motor (e.g. xafs_linx)
    or a nickname for an XAFS sample motor (e.g. 'x' for xafs_linx).

    This does not write an ASCII data file, but it does make a log entry.

    Use the ls2dat() function to extract the linescan from the
    database and write it to a file.
    '''
    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 cleanup_plan():
        ## BMM_clear_suspenders()
        ##RE.clear_suspenders()       # disable suspenders
        yield from resting_state_plan()

    RE, BMMuser, rkvs = user_ns['RE'], user_ns['BMMuser'], user_ns['rkvs']
    try:
        xs = user_ns['xs']
    except:
        pass
    ######################################################################
    # 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 line scan.\n'
                % BMMuser.macro_sleep))
        countdown(BMMuser.macro_sleep)
        return (yield from null())
    ######################################################################
    RE.msg_hook = None
    yield from finalize_wrapper(
        main_plan(detector, axis, start, stop, nsteps, pluck, force),
        cleanup_plan())
    RE.msg_hook = BMM_msg_hook
Ejemplo n.º 21
0
 def do_XAFS(self):
     print(go_msg('You would like to do an XAFS scan...\n'))
     howlong()
     yield from null()
Ejemplo n.º 22
0
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
Ejemplo n.º 23
0
    def main_plan(start, stop, nsteps, detector):
        (ok, text) = BMM_clear_to_start()
        if ok is False:
            print(error_msg(text))
            yield from null()
            return

        RE.msg_hook = None
        BMMuser.motor = motor

        if detector.lower() == 'bicron':
            func = lambda doc: (doc['data'][motor.name], doc['data']['Bicron'])
            dets = [
                bicron,
            ]
            sgnl = 'Bicron'
            titl = 'Bicron signal vs. DCM 2nd crystal pitch'
        else:
            func = lambda doc: (doc['data'][motor.name], doc['data']['I0'])
            dets = [
                quadem1,
            ]
            sgnl = 'I0'
            titl = 'I0 signal vs. DCM 2nd crystal pitch'

        plot = DerivedPlot(func, xlabel=motor.name, ylabel=sgnl, title=titl)

        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_dcmpitch(sgnl):
            line1 = '%s, %s, %.3f, %.3f, %d -- starting at %.3f\n' % \
                    (motor.name, sgnl, start, stop, nsteps, motor.user_readback.get())

            yield from abs_set(user_ns['_locked_dwell_time'], 0.1, wait=True)
            yield from dcm.kill_plan()

            yield from mv(slits3.vsize, 3)
            if sgnl == 'Bicron':
                yield from mv(slitsg.vsize, 5)

            uid = yield from rel_scan(dets, motor, start, stop, nsteps)
            #yield from rel_adaptive_scan(dets, 'I0', motor,
            #                             start=start,
            #                             stop=stop,
            #                             min_step=0.002,
            #                             max_step=0.03,
            #                             target_delta=.15,
            #                             backstep=True)
            t = db[-1].table()
            signal = t[sgnl]
            if choice.lower() == 'com':
                position = com(signal)
                top = t[motor.name][position]
            elif choice.lower() == 'fit':
                pitch = t['dcm_pitch']
                mod = SkewedGaussianModel()
                pars = mod.guess(signal, x=pitch)
                out = mod.fit(signal, pars, x=pitch)
                print(whisper(out.fit_report(min_correl=0)))
                out.plot()
                top = out.params['center'].value
            else:
                position = peak(signal)
                top = t[motor.name][position]

            yield from sleep(3.0)
            yield from abs_set(motor.kill_cmd, 1, wait=True)
            RE.msg_hook = BMM_msg_hook

            BMM_log_info('rocking curve scan: %s\tuid = %s, scan_id = %d' %
                         (line1, uid, user_ns['db'][-1].start['scan_id']))
            yield from mv(motor, top)
            if sgnl == 'Bicron':
                yield from mv(slitsg.vsize, gonio_slit_height)

        yield from scan_dcmpitch(sgnl)
Ejemplo n.º 24
0
 def per_step_old(detectors, motor, step):
     yield from bps.null()
Ejemplo n.º 25
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)
Ejemplo n.º 26
0
 def per_step_extra(detectors, motor, step, some_kwarg=None):
     yield from bps.null()
Ejemplo n.º 27
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!')
Ejemplo n.º 28
0
 def per_step_exact(detectors, motor, step, take_reading=None):
     yield from bps.null()
Ejemplo n.º 29
0
 def _unstage():
     for component in hinted_stash:
         component.kind = Kind.hinted
     yield from null()
Ejemplo n.º 30
0
 def per_step_kwargs(detectors, motor, step, **kwargs):
     yield from bps.null()