def __init__(self, shell, config): super(ECLIxmlrpc, self).__init__(shell=shell, config=config, init_traits=False) logging.info('Initializing ECLI xmlrpc server plugin') self._scan_number = 0 scan_plugin = get_plugin(self.SCAN_PLUGIN) callbacks = [(scan_plugin.CB_PRE_SCAN, self.pre_scan), (scan_plugin.CB_POST_SCAN, self.post_scan), (scan_plugin.CB_SCAN_STEP, self.single_step)] for cb_name, fcn in callbacks: scan_plugin.add_callback(cb_name, fcn) self.server_functions = self._find_functions(prefix='server_') self.server_thread = None self.server = None self.handler = None self._scan_info = {} self._scan_data = {} self._new_scan = {} self._scan_key = 0 self._reset() self._port_changed()
def __init__(self, shell, config): super(ECLIScanPrinter, self).__init__(shell=shell, config=config) if self.outfile is None: self.outfile = sys.stdout logger.info('ECLI Scan printer writing to: file=%s' % self.outfile) self._scan_number = 0 self._last_point = None scan_plugin = get_plugin(SCAN_PLUGIN) scan_plugin.add_callback(scan_plugin.CB_PRE_SCAN, self.pre_scan) scan_plugin.add_callback(scan_plugin.CB_POST_SCAN, self.post_scan) scan_plugin.add_callback(scan_plugin.CB_SCAN_STEP, self.single_step)
def get_save_files(self): files = [] base = 'ECLIScanWriter' plugins = ('HDF5', 'SPEC') for plugin_name in plugins: plugin_name = '%s%s' % (base, plugin_name) try: plugin = get_plugin(plugin_name) except: pass else: files.append(plugin.filename) return files
def __init__(self, pv, **kwargs): pv = str(pv) # aliasedpv bugfix TODO if pv.endswith(".VAL"): pv = pv[:-4] super(ECLIPositioner, self).__init__(pv, **kwargs) self.move_time = 0 motor_plugin = get_plugin("ECLIMotor") if pv in motor_plugin.motor_list: self.motor_rec = motor_plugin.get_motor(pv) self.motor_rec.SYNC = 1 else: self.motor_rec = None
def __init__(self, shell, config): super(ECLIScanWriterHDF5, self).__init__(shell=shell, config=config) logger.info('Initializing ECLI HDF5 file writer plugin') self._scan_number = 0 self._scans_group = None # Group for all scans self._scan_group = None # Group for single scan (under scans_group) self._open_file(self.filename) scan_plugin = get_plugin(self.SCAN_PLUGIN) callbacks = [(scan_plugin.CB_PRE_SCAN, self.pre_scan), (scan_plugin.CB_POST_SCAN, self.post_scan), (scan_plugin.CB_SCAN_STEP, self.single_step), (scan_plugin.CB_SAVE_PATH, self.save_path_set), ] self.scan_plugin = scan_plugin for cb_name, fcn in callbacks: scan_plugin.add_callback(cb_name, fcn)
def __init__(self, shell, config): logger.info('Initializing ECLI SPEC file writer plugin') self._scan_number = 0 self._new_scan = True scan_plugin = get_plugin(self.SCAN_PLUGIN) self.scan_plugin = scan_plugin self._motors = [] super(ECLIScanWriterSPEC, self).__init__(shell=shell, config=config) if self.filename: self._file = SPECFileWriter(self.filename) else: self._file = None callbacks = [(scan_plugin.CB_PRE_SCAN, self.pre_scan), (scan_plugin.CB_POST_SCAN, self.post_scan), (scan_plugin.CB_SCAN_STEP, self.single_step), (scan_plugin.CB_SAVE_PATH, self.save_path_set), ] for cb_name, fcn in callbacks: scan_plugin.add_callback(cb_name, fcn)
def xmlrpc_url(self): return get_plugin('ECLIxmlrpc').server_url
def get_pv_manager(): return get_plugin('ECLIcas').manager
def get_plugin(): return get_plugin('ECLIcas')
def scan_run( self, positioners, dwell_time, move_back=True, command="", dimensions=None, breakpoints=[], counters=[], detectors=[], triggers=[], run=True, **kwargs ): """ Perform a generic scan :param positioners: Motors to scan, with absolute position arrays previously set :param dwell_time: Seconds at each point :param move_back: Move all positioners back to their starting position post scan :param command: the command-line command used to start the scan :param dimensions: the scan dimensions :param counters: additional counters not normally included (can be a PV name) :param detectors: additional detectors not normally included :param triggers: additional triggers not normally included (can be a PV name) :param run: run the scan (or just return one ready to run) :param kwargs: passed onto the scan's ECLI info :returns: the scan instance """ array_shapes = set([pos.array.shape for pos in positioners]) if len(array_shapes) != 1: raise ValueError("Positioners must have the same position array dimensions") data_points = np.size(positioners[0].array) self.scan = sc = stepscan.StepScan() if dimensions is None or not isinstance(dimensions, (list, tuple)): dimensions = (data_points,) for positioner in positioners: sc.add_positioner(positioner) for counter in counters: sc.add_counter(counter) for trigger in triggers: sc.add_trigger(trigger) motor_plugin = get_plugin("ECLIMotor") for motor in motor_plugin.motor_list: motor_rec = motor_plugin.get_motor(motor) sc.add_extra_pvs([(motor, motor_rec.PV("RBV"))]) for pv in self.extra_pvs: if pv in self.core.aliases: name, pv = pv, self.core.aliases[pv] else: name = self.core.get_aliased_name(pv) sc.add_extra_pvs([(name, pv)]) mca_calib = {} for det_pv in set(self.detectors + list(detectors) + list(self.trigger_detectors.keys())): type_ = self.detector_types.get(det_pv, None) det = stepscan.get_detector(util.expand_alias(det_pv), kind=type_, label=det_pv) if det is None: logger.error("Scan %s invalid detector: %s" % (sc, det_pv)) return None logger.debug("Scan %s added detector: %s" % (sc, det)) sc.add_detector(det) # TODO bug report - hardware triggered detectors if det.trigger is not None: sc.triggers.remove(det.trigger) if det_pv in self.trigger_detectors: trigger_value = self.trigger_detectors[det_pv] logger.debug("Added detector trigger: %s = %s" % (det.trigger, trigger_value)) sc.add_trigger(det.trigger, value=trigger_value) if isinstance(det, stepscan.McaDetector): det_pv = util.expand_alias(det_pv) calib_pvs = ["%s.CALO", "%s.CALS", "%s.CALQ"] prefix = det.prefix calib = [epics.caget(pv % prefix) for pv in calib_pvs] mca_calib[det_pv] = calib # TODO StepScan bug report: # add_trigger needs to check for None (as in SimpleDetector) sc.triggers = [trigger for trigger in sc.triggers if trigger is not None] sc.set_dwelltime(dwell_time) start_pos = [pos.current() for pos in positioners] for counter in sc.counters: counter.label = str(counter.label) self._scan_number += 1 sc.ecli_info = { "command": command, "scan_number": self._scan_number, "dimensions": dimensions, "ndim": calc_ndim(dimensions), "scanning": [str(pos.label) for pos in positioners], "mca_calib": mca_calib, } if hasattr(sc, "timestamps"): # Added timestamps in ECLI stepscan fork sc.ecli_info["timestamps"] = sc.timestamps sc.get_timestamp = lambda i: sc.timestamps[i] else: sc.get_timestamp = lambda i: None sc.ecli_info.update(kwargs) sc.pos_settle_time = self.pos_settle_time sc.det_settle_time = self.det_settle_time if not run: return sc ex_raised = None # TODO: check all PVs prior to scan # Run the scan try: sc.run(None) except Exception as ex: if sc.message_thread is not None: sc.message_thread.cpt = None logger.error("Scan failed: (%s) %s" % (ex.__class__.__name__, ex)) ex_raised = ex finally: # Wait for the message thread to catch up if sc.message_thread is not None: sc.message_thread.join(1.0) if move_back: # Move the positioners back to their starting positions for pos, start in zip(positioners, start_pos): logger.info("Moving %s back to the starting position %g" % (pos, start)) try: pos.move_to(start, wait=True) except KeyboardInterrupt as ex: print("%s move to %g cancelled (current position=%s)" % (pos.label, start, pos.current())) ex_raised = ex if self.core.script_running: raise ex # Make a simple dictionary holding the scan data data = {} for counter in sc.counters: data[counter.label] = counter.buff # And export that data back to the user namespace as `scan_data` self.core.set_variable("scan_data", data) return sc
def get_plugin(cls): return get_plugin(cls.__name__)
def create_motors(self, create=[], aliases={}, desc='', rotary=[], **kwargs): """ Create pseudomotors that mimic an EPICS motor records For example, >>> create_motors(create=['pseudo1', 'pseudo2'], ... m1='pseudo1 / 2.0', ... pseudo1='m1 * 2', ... pseudo2='(m1 * 2) + 0.1', ... aliases={'m1': 'IOC:m1'}, ... ) Assuming the CAS prefix is set to ECLI:, this will create two pseudomotors `ECLI:pseudo1` and `ECLI:pseudo2`. Their readback values will be updated each time `m1` (which has a full record name of `IOC:m1`) is updated, showing twice m1's readback value (and with a slight offset). % caget IOC:m1.RBV ECLI:pseudo1.RBV ECLI:pseudo2.RBV IOC:m1.RBV 1.0 ECLI:pseudo1.RBV 2.0 ECLI:pseudo2.RBV 2.1 % caput ECLI:pseudo 3.0 % caget IOC:m1.RBV ECLI:pseudo1.RBV ECLI:pseudo2.RBV IOC:m1.RBV 1.5 ECLI:pseudo1.RBV 3.0 ECLI:pseudo2.RBV 3.1 :param create: The pseudo motor names (appended onto PCASpy prefix) The expression to be evaluated for the pseudomotor readback value should be set as a keyword argument. :param aliases: Define aliases for motors e.g., {'m1': 'IOC:m1'} :type aliases: dict :param rotary: If a motor is the rotary list, motor values will be displayed in degrees, but automatically converted to radians when doing calculations. :type rotary: list :param kwargs: Each time the pseudomotor is commanded to move, all related motors specified in the kwargs will be commanded to move. :returns: tuple containing (Pseudomotor instance list, MotorGroup instance) .. note:: Expressions cannot have colons (:) in them -- that is, motors must be valid Python identifiers. Prior to adding the pseudomotor, either add aliases via the `aliases` parameter or use normal ECLI aliasing. """ if not create: raise ValueError('No motors to create') mplugin = get_plugin('ECLIMotor') cas_plugin = get_plugin('ECLIcas') core = self.core all_aliases = copy.deepcopy(core.aliases) all_aliases.update(aliases) group = pseudo.MotorGroup(aliases=all_aliases) pseudo_names = list(create) for pseudo_name in pseudo_names: if pseudo_name in self.pseudo_to_group: logger.info('Removing previously created pseudomotor of the same name (%s)' % pseudo_name) self.delete_pseudomotor(pseudo_name) pseudos_full = [all_aliases.get(pseudo_name, pseudo_name) for pseudo_name in pseudo_names] for pseudo_name, pseudo_full in zip(pseudo_names, pseudos_full): readback_expr = kwargs[pseudo_name] logger.info('Pseudomotor: %s (%s) Readback expression: %s' % (pseudo_name, pseudo_full, readback_expr)) # Add the pseudomotor expressions group.add_motor(pseudo_name, pseudo_full, readback_expr) # And all of the related motor expressions for motor, expression in kwargs.items(): if motor in pseudo_names: continue full_pv = all_aliases.get(motor, motor) logger.info('Motor: %s (%s) Expression: %s' % (motor, full_pv, expression)) group.add_motor(motor, full_pv, expression) # Check all of the equations first group.start() logger.debug('Equations checked') for param in kwargs.keys(): if param in pseudo_names: continue logger.debug('Adding record %s' % param) full_param = all_aliases.get(param, param) rtype = util.get_record_type(full_param) if rtype == 'motor': record = mplugin.get_motor(full_param) group.set_record(param, record) logger.debug('Rotary motors: %s' % ', '.join(rotary)) pseudos = [] # Create the pseudomotor instance itself for pseudo_name, pseudo_full in zip(pseudo_names, pseudos_full): p = pseudo.PseudoMotor(cas_plugin.manager, group, pseudo_full, pseudo_name, rotary=pseudo_name in rotary) pseudos.append(p) group.set_record(pseudo_name, p) # And start them up for pseudomotor in pseudos: pseudomotor.startup() for pseudo_name, pseudomotor in zip(pseudo_names, pseudos): pseudomotor.update_readback() self.pseudo_to_group[pseudo_name] = group self.groups.append(group) return pseudos, group
logging.error('Scaler list undefined (see %%config ECLIScaler.scalers)') return if seconds is None: seconds = self.default_count_time for scaler in scalers: if self.show_timestamp: print(' %s' % util.timestamp_string()) print() dev = self._get_device(scaler) table = self.scaler_counts_table(dev, seconds) table.print_() show_elapsed = ShowElapsed(lambda: get_plugin('ECLIScaler').show_elapsed) @show_elapsed.wrapper @ecli_magic_args(ECLIScaler) @argument('seconds', type=float, nargs='?', help='PV') @argument('-r', '--record', type=AliasedPV, nargs='?', help='Record to use') def ct(margs, self, args): """ $ ct [seconds] [-r/--record record] """ if args.record is not None: scalers = [args.record] else: