コード例 #1
0
ファイル: ecli_stepscan.py プロジェクト: klauer/ECLI
    def _detectors_changed(self, *args):
        logger.info("Detector list updated: %s" % self.detectors)

        del self._detectors[:]
        for alias in self.detectors:
            pv = util.expand_alias(alias)
            try:
                det = stepscan.get_detector(pv, label=alias)
            except Exception as ex:
                logger.error("Bad detector: %s (%s) %s" % (pv, ex.__class__.__name__, ex))
            except KeyboardInterrupt:
                logger.warning("Skipping detector list entry: %s" % pv)
            else:
                self._detectors.append(det)
コード例 #2
0
ファイル: ecli_stepscan.py プロジェクト: klauer/ECLI
    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