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))
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'
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
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))
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)
def inner(): plan = scan([detector], motor, start, stop, steps, per_step=per_step) yield from stub_wrapper(plan)
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