def _per_step(detectors, step, pos_cache):
        '''This triggers multiple spectra at each point in a plan.

        This function is analogous to the `bluesky.plan_stubs.one_nd_step`
        function and should be used instead of that via the kwarg
        `per_step=multi_spectrum` in a call to any default plan except
        count.

        Parameters
        ----------
        detectors : list
            a list of detectors to trigger at each point
        step : dict
            a dictionary mapping motors to values for this point in the
            scan
        pos_cache : dict
            a dictionary mapping motors to their last-set positions.
        '''
        motors = step.keys()
        # move any motors that the outer plan requires to be moved.
        yield from move_per_step(step, pos_cache)

        # set the mode for the specs detector if necessary
        if specs in detectors:
            yield from specs.set_mode('single_point')

        for (edge_name, parameters, settings) in spectra:
            # move the devices in settings into place
            yield from _move_from_dict(settings)
            extra_dets = []
            # add ``spectra_num`` to the extra_dets list if needed
            if parameters['num_spectra'] is None:
                parameters['num_spectra'] = 1
            elif parameters['num_spectra'] > 1:
                extra_dets.append(spectra_num)

            # reset the photon energy and the feedback loop for the given
            # spectra
            yield from pgm.reset_fbl(
                parameters['alignment_energy'],
                epu_lookup_table=parameters['epu_lookup_table'],
                epu_input_offset=parameters['epu_input_offset'],
                fbl_setpoint=parameters['fbl_setpoint'])

            # collect num_spectra individual spectra at this point.
            for num_spectra in range(1, parameters['num_spectra'] + 1):
                if spectra_num in extra_dets:  # update spectra_num if needed
                    yield from mv(spectra_num, num_spectra)
                # perform the fly scan
                yield from stub_wrapper(
                    ERamp(list(detectors) + list(motors) + [pgm.energy] +
                          extra_dets,
                          parameters['low_energy'],
                          parameters['high_energy'],
                          parameters['velocity'],
                          streamname=edge_name))
Example #2
0
def test_stub_wrapper():
    def plan():
        yield Msg('open_run')
        yield Msg('stage')
        yield Msg('read')
        yield Msg('unstage')
        yield Msg('close_run')

    stub_plan = list(stub_wrapper(plan()))
    assert len(stub_plan) == 1
    assert stub_plan[0].command == 'read'
Example #3
0
def test_stub_wrapper():
    def plan():
        yield Msg('open_run')
        yield Msg('stage')
        yield Msg('read')
        yield Msg('unstage')
        yield Msg('close_run')

    stub_plan = list(stub_wrapper(plan()))
    assert len(stub_plan) == 1
    assert stub_plan[0].command == 'read'
Example #4
0
def measure_average(detectors, num, delay=None, stream=None):
    """
    Measure an average over a number of shots from a set of detectors

    Parameters
    ----------
    detectors : list
        List of detectors to read

    num : int
        Number of shots to average together

    delay: iterable or scalar, optional
        Time delay between successive readings. See ``bluesky.count`` for more
        details

    stream : AverageStream, optional
        If a plan will call :func:`.measure_average` multiple times, a single
        ``AverageStream`` instance can be created and then passed in on each
        call. This allows other callbacks to subscribe to the averaged data
        stream. If no ``AverageStream`` is provided then one is created for the
        purpose of this function.

    Returns
    -------
    averaged_event : dict
        A dictionary of all the measurements taken from the list of detectors
        averaged for ``num`` shots. The keys follow the same naming convention
        as that will appear in the event documents i.e "{name}_{field}"

    Notes
    -----
    The returned average dictionary will only contain keys for 'number' or
    'array' fields. Field types that can not be averaged such as 'string' will
    be ignored, do not expect them in the output.
    """
    # Create a stream and subscribe if not given one
    if not stream:
        stream = AverageStream(num=num)
        yield from subscribe('all', stream)
        # Manually kick the LiveDispatcher to emit a start document because we
        # will not see the original one since this is subscribed after open_run
        stream.start({'uid': None})
    # Ensure we sync our stream with request if using a prior one
    else:
        stream.num = num
    # Measure our detectors
    yield from stub_wrapper(count(detectors, num=num, delay=delay))
    # Return the measured average as a dictionary for use in adaptive plans
    return stream.last_event
Example #5
0
    def outer_per_step(detectors, motor, step):
        # Set a checkpoint in case the scan is interrupted
        yield from checkpoint()

        # Move the monochrometer to the inputted energy
        logger.info('Outer Step: Moving {0} to {1}'.format(
            outer_motor.name, step))
        yield from abs_set(outer_motor, step, wait=True)

        # Define what we will do at every motor step
        def inner_per_step(detectors, motor, step):
            # Set a checkpoint in case the scan is interrupted
            yield from checkpoint()
            """
            # Notify the user where we are trying to move to
            goal_sample = inner_motor.position + inner_step_size
            goal_index = inner_motor.locate_1d(goal_sample)
            logger.info('Inner Step: Moving {0} to {1} (sample {2})'.format(
                inner_motor.name, goal_index, goal_sample))
            """

            # Move the motor to the inputted step
            yield from rel_set(inner_motor, inner_step_size, wait=True)

            if use_sequencer:
                # # Start and wait for the sequencer
                logger.info('Inner Step: Starting the sequencer')
                yield from abs_set(sequencer, 1, wait=True)

            # Wait the specified amount of time
            if wait:
                logger.info(
                    "Inner Step: Waiting for {0} second(s)...".format(wait))
                time.sleep(wait)

            # Fill the dataframe
            scan_positions.append((
                outer_motor.position,
                #inner_motor.chip,
                inner_motor.position,
                #*inner_motor.index,
                #*inner_motor.coordinates
            ))

        # Define the larger inner scan as a list_scan. We cannot use
        # rel_list_scan because it includes the reset_positions_decorator,
        # which we do not want to do
        yield from stub_wrapper(
            list_scan([], inner_motor, inner_steps, per_step=inner_per_step))
Example #6
0
 def inner_scan():
     try:
         for i in range(len(ss)):
             yield from bps.mv(scan_motor, ss[i])
             for j in range(n_shots):
                 x = (next(item['pos'] for item in cycle_xx
                           if item["status"] is False))
                 y = (next(item['pos'] for item in cycle_yy
                           if item["status"] is False))
                 yield from bpp.stub_wrapper(
                     bp.list_scan(detectors, x_motor, [x], y_motor, [y]))
         update_sample(sample, path, (n_shots * len(ss)))
     except Exception:
         current_position = x_motor.position
         try:
             last_index = next((index for (index, d) in enumerate(xx)
                                if np.isclose(d["pos"], current_position)))
             update_sample(sample, path, (last_index - next_index + 1))
         except Exception:
             logger.warning(
                 'Could not find the index in the targets list '
                 'for the current motor value: %d', current_position)
Example #7
0
 def inner():
     plan = scan([detector], motor, start, stop, steps, per_step=per_step)
     yield from stub_wrapper(plan)
Example #8
0
def mcgrane_scan(outer_motor,
                 inner_motor,
                 sequencer,
                 outer_start,
                 outer_stop,
                 outer_steps,
                 inner_steps,
                 inner_step_size=1,
                 use_sequencer=True,
                 wait=None):
    """Relative scan nested into a normal scan, that starts the sequencer at
    each inner step.

    Performs a normal scan using the outer motor, and then performs a
    relative scan within each outer motor step using the inner motor. The
    sequencer is then triggered at every inner step in the scan.

    Parameters
    ----------
    outer_motor : Motor
        Motor to perform the outer normal scan

    inner_motor : Motor
        Motor to perform the inner relative scan

    sequencer : Sequencer
        Sequencer to trigger at every inner motor step

    outer_start : float
        Starting position of the outer motor

    outer_stop : float
        Stopping position of the outer motor
    
    outer_steps : float
        Number of steps to take during the scan, including the endpoints

    inner_steps : int or list
        Number of relative steps to take at every outer step if an int. If it's
        a list, it is the list of relative motions to perform at every outer
        step

    wait : float, optional
        The amount of time to wait at each step     
    """
    # Create the list of relative motions that will be performed
    if isinstance(inner_steps, int):
        # If it is an int, create a list of unit motions of that length
        inner_steps = [1] * inner_steps

    scan_positions = []

    # Define what will be done at every monochrometer step
    def outer_per_step(detectors, motor, step):
        # Set a checkpoint in case the scan is interrupted
        yield from checkpoint()

        # Move the monochrometer to the inputted energy
        logger.info('Outer Step: Moving {0} to {1}'.format(
            outer_motor.name, step))
        yield from abs_set(outer_motor, step, wait=True)

        # Define what we will do at every motor step
        def inner_per_step(detectors, motor, step):
            # Set a checkpoint in case the scan is interrupted
            yield from checkpoint()
            """
            # Notify the user where we are trying to move to
            goal_sample = inner_motor.position + inner_step_size
            goal_index = inner_motor.locate_1d(goal_sample)
            logger.info('Inner Step: Moving {0} to {1} (sample {2})'.format(
                inner_motor.name, goal_index, goal_sample))
            """

            # Move the motor to the inputted step
            yield from rel_set(inner_motor, inner_step_size, wait=True)

            if use_sequencer:
                # # Start and wait for the sequencer
                logger.info('Inner Step: Starting the sequencer')
                yield from abs_set(sequencer, 1, wait=True)

            # Wait the specified amount of time
            if wait:
                logger.info(
                    "Inner Step: Waiting for {0} second(s)...".format(wait))
                time.sleep(wait)

            # Fill the dataframe
            scan_positions.append((
                outer_motor.position,
                #inner_motor.chip,
                inner_motor.position,
                #*inner_motor.index,
                #*inner_motor.coordinates
            ))

        # Define the larger inner scan as a list_scan. We cannot use
        # rel_list_scan because it includes the reset_positions_decorator,
        # which we do not want to do
        yield from stub_wrapper(
            list_scan([], inner_motor, inner_steps, per_step=inner_per_step))

    # # Set the sequencer to run once
    if use_sequencer:
        yield from abs_set(sequencer.play_mode, 0, wait=True)

    try:
        # Perform the larger scan
        yield from stub_wrapper(
            scan([],
                 outer_motor,
                 outer_start,
                 outer_stop,
                 outer_steps,
                 per_step=outer_per_step))
    except InvalidSampleError:
        logger.warning('Reached the end of "{0}". Ending scan in position '
                       '{1} (sample {2})'.format(inner_motor.name,
                                                 inner_motor.index,
                                                 inner_motor.position))

    # Create the dataframe and return it
    '''
    columns = ('mono', 'chip', 'sample', 'i', 'j', 'x', 'y', 'z')
    df = pd.DataFrame(scan_positions, columns=columns)
    df.index.name = 'Scan Step'
    return df
    '''
    return None