class ICDevicewMotor(ICDeviceBase):
    """ ICDeviceBase with detector motors """

    # motors
    x = FormattedComponent(EpicsMotor, '4iddx:{_motorx}',
                           labels=('motors', 'detectors'))
    y = FormattedComponent(EpicsMotor, '4iddx:{_motory}',
                           labels=('motors', 'detectors'))

    def __init__(self, prefix, name, motorx, motory, scaler_num, preamp_num,
                 **kwargs):
        """
        Parameters
        ----------
        prefix : str
            PV prefix, here for ophyd compatibility, it won't be used.
        name : str
            Unique device name.
        motorx, motory : str
            PV sufix for the x, y motors.
        scaler_num : int
            Scaler channel number.
        preamp_num: int
            SRS pre-amplifier number.
        kwargs : dict
            Passed to `ophyd.Device`
        """
        self._motorx = motorx
        self._motory = motory
        super().__init__(prefix, name, scaler_num, preamp_num, **kwargs)
示例#2
0
class RubyDevice(Device):
    """ Ruby system """

    focus = Component(EpicsMotor, 'm37', labels=('motor', 'ruby'))
    y = Component(EpicsMotor, 'm38', labels=('motor', 'ruby'))
    z = Component(EpicsMotor, 'm39', labels=('motor', 'ruby'))
    zoom = Component(EpicsMotor, 'm40', labels=('motor', 'ruby'))

    led = FormattedComponent(DAC, '4idd:DAC1_1', labels=('ruby', ))
    laser = FormattedComponent(DAC, '4idd:DAC1_2', labels=('ruby', ))
示例#3
0
class AmplfierGainDevice(Device):
    _default_configuration_attrs = ()
    _default_read_attrs = ('gain', 'background', 'background_error')

    gain = FormattedComponent(EpicsSignal, '{self.prefix}gain{self._ch_num}')
    background = FormattedComponent(EpicsSignal,
                                    '{self.prefix}bkg{self._ch_num}')
    background_error = FormattedComponent(EpicsSignal,
                                          '{self.prefix}bkgErr{self._ch_num}')

    def __init__(self, prefix, ch_num=None, **kwargs):
        assert ch_num is not None, "Must provide `ch_num=` keyword argument."
        self._ch_num = ch_num
        super().__init__(prefix, **kwargs)
示例#4
0
class OneSlot(Device):
    """ Configure one filter slot. """

    label = FormattedComponent(EpicsSignal,
                               '{prefix}{_num}.DESC',
                               kind='config',
                               string=True)
    status = FormattedComponent(EpicsSignal,
                                '{prefix}{_num}.VAL',
                                kind='config',
                                string=True)

    def __init__(self, *args, num=0, **kwargs):
        self._num = num
        super().__init__(*args, **kwargs)
class HorizontalDiffractionMirror(XYMotor):
    "x and y with pitch, which has different read and write PVs"
    #p = FormattedComponent(EpicsSignal, read_pv='{self.prefix}-Ax:P}}E-I', write_pv='{self.prefix}-Ax:P}}E-SP', add_prefix=('read_pv', 'write_pv', 'suffix'))
    p = FormattedComponent(EpicsSignal,
                           read_pv='{self.prefix}-Ax:P}}Pos-I',
                           write_pv='{self.prefix}-Ax:P}}PID-SP',
                           add_prefix=('read_pv', 'write_pv', 'suffix'))
class ICDeviceBase(Device):
    """ Holds basic configuration of ion chambers/photodiodes. """

    # SRS amplifier
    preamp = FormattedComponent(PreAmpDevice, '4idd:A{_num}', kind='config',
                                labels=('preamps', 'detectors',))

    # Scaler channel name
    scaler_name = Component(Signal, value=0, kind='config')

    def __init__(self, prefix, name, scaler_num, preamp_num, **kwargs):
        """
        Parameters
        ----------
        prefix : str
            PV prefix, here for ophyd compatibility, it won't be used.
        name : str
            Unique device name.
        scaler_num : int
            Scaler channel number.
        preamp_num: int
            SRS pre-amplifier number.
        kwargs : dict
            Passed to `ophyd.Device`
        """

        # preamp_num
        self._num = preamp_num

        super().__init__(prefix=prefix, name=name, **kwargs)

        # Scaler channel name
        self.scaler_name.put(
            getattr(scalerd.channels, 'chan{:02d}'.format(scaler_num)).s.name
            )
示例#7
0
class LS336Device(Device):
    """
    Support for Lakeshore 336 temperature controller
    """
    loop1 = FormattedComponent(LS336_LoopControl, "{prefix}", loop_number=1)
    loop2 = FormattedComponent(LoopSample, "{prefix}", loop_number=2)
    loop3 = FormattedComponent(LS336_LoopRO, "{prefix}", loop_number=3)
    loop4 = FormattedComponent(LS336_LoopRO, "{prefix}", loop_number=4)

    # same names as apstools.synApps._common.EpicsRecordDeviceCommonAll
    scanning_rate = Component(EpicsSignal, "read.SCAN", kind="omitted")
    process_record = Component(EpicsSignal, "read.PROC", kind="omitted")

    read_all = Component(EpicsSignal, "readAll.PROC", kind="omitted")
    serial = Component(AsynRecord, "serial", kind="omitted")

    track_vaporizer = Component(TrackingSignal, value=True, kind="config")
示例#8
0
class PRDevice(Device):

    x = FormattedComponent(EpicsMotor,
                           '{self.prefix}:{_motorsDict[x]}',
                           labels=('motor', 'phase retarders'))

    y = FormattedComponent(EpicsMotor,
                           '{self.prefix}:{_motorsDict[y]}',
                           labels=('motor', 'phase retarders'))

    th = FormattedComponent(EpicsMotor,
                            '{self.prefix}:{_motorsDict[th]}',
                            labels=('motor', 'phase retarders'))

    def __init__(self, prefix, name, motorsDict, **kwargs):
        self._motorsDict = motorsDict
        super().__init__(prefix=prefix, name=name, **kwargs)
示例#9
0
class UserCalcChannel(Device):

    trigger_option = FormattedComponent(EpicsSignal,
                                        '{self.prefix}.IN{self._ch}P',
                                        kind=Kind.config)

    PVname = FormattedComponent(EpicsSignal,
                                '{self.prefix}.IN{self._ch}N',
                                kind=Kind.config)

    value = FormattedComponent(EpicsSignal,
                               '{self.prefix}.{self._ch}',
                               kind=Kind.config)

    def __init__(self, prefix, ch, **kwargs):
        self._ch = ch
        super().__init__(prefix, **kwargs)
示例#10
0
class KohzuPositioner(PVPositionerSoftDone):
    stop_theta = FormattedComponent(EpicsSignal,
                                    "{_theta_pv}.STOP",
                                    kind="omitted")
    stop_y = FormattedComponent(EpicsSignal, "{_y_pv}.STOP", kind="omitted")
    stop_z = FormattedComponent(EpicsSignal, "{_z_pv}.STOP", kind="omitted")

    actuate = Component(EpicsSignal, "KohzuPutBO", kind="omitted")
    actuate_value = 1

    def __init__(self,
                 prefix,
                 *,
                 limits=None,
                 readback_pv="",
                 setpoint_pv="",
                 name=None,
                 read_attrs=None,
                 configuration_attrs=None,
                 parent=None,
                 egu="",
                 **kwargs):
        def get_motor_pv(label):
            _pv_signal = EpicsSignalRO(f"{prefix}Kohzu{label}PvSI", name="tmp")
            _pv_signal.wait_for_connection()
            return _pv_signal.get(as_string=True)

        self._theta_pv = get_motor_pv("Theta")
        self._y_pv = get_motor_pv("Y")
        self._z_pv = get_motor_pv("Z")

        super().__init__(prefix,
                         limits=limits,
                         readback_pv=readback_pv,
                         setpoint_pv=setpoint_pv,
                         name=name,
                         read_attrs=read_attrs,
                         configuration_attrs=configuration_attrs,
                         parent=parent,
                         egu=egu,
                         **kwargs)

    def stop(self, *, success=False):
        for motor in ["theta", "y", "z"]:
            getattr(self, f"stop_{motor}").put(1, wait=False)
        super().stop(success=success)
示例#11
0
class LocalPositioner(PVPositionerSoftDone):
    """ Voltage/Current positioner """

    readback = FormattedComponent(
        EpicsSignalRO, '{prefix}d{_type}', kind='normal',
        labels=('kepko', 'magnet')
        )

    setpoint = FormattedComponent(
        EpicsSignal, "{prefix}{_type}", write_pv="{prefix}set{_type}",
        kind='normal', labels=('kepko', 'magnet')
        )

    def __init__(self, *args, progtype, **kwargs):
        self._type = progtype
        # TODO: This tolerance seems good, but may need to be tested.
        super().__init__(*args, tolerance=0.02, **kwargs)
示例#12
0
class PIM(PIMMotor, SimDevice):
    detector = FormattedComponent(PIMPulnixDetector, 
                                  "{self._section}:{self._imager}:CVV:01",
                                  read_attrs=['stats2'])
    def __init__(self, prefix, x=0, y=0, z=0, noise=0, settle_time=0, 
                 centroid_noise=False, size=(640,480), 
                 resolution=(0.0076,0.0062), zero_outside_yag=False, **kwargs):
        self._section=prefix
        self._imager=prefix
        if len(prefix.split(":")) < 2:
            prefix = "TST:{0}".format(prefix)
        super().__init__(prefix, pos_in=y, noise=noise, 
                         settle_time=settle_time, **kwargs)

        # Simulation Values
        self.sim_x.put(x)
        self.sim_y._get_readback = lambda : self._pos.value
        self.sim_z.put(z)
        self.log_pref = "{0} (PIM) - ".format(self.name)
        # Detector args
        self.zero_outside_yag = zero_outside_yag
        self.resolution = resolution
        self.size = size
        self.centroid_noise = centroid_noise
        
    @property
    def centroid_noise(self):
        return (self.detector.noise_x, self.detector.noise_y)

    @centroid_noise.setter
    def centroid_noise(self, val):
        self.detector.noise_x = bool(val)
        self.detector.noise_y = bool(val)

    @property
    def size(self):
        return self.detector.size

    @size.setter
    def size(self, val):
        self.detector.size = val

    @property
    def resolution(self):
        return self.detector.resolution
        
    @resolution.setter
    def resolution(self, val):
        self.detector.resolution = val

    @property
    def zero_outside_yag(self):
        return self.detector.zero_outside_yag
        
    @zero_outside_yag.setter
    def zero_outside_yag(self, val):
        self.detector.zero_outside_yag = bool(val)
示例#13
0
class LS336_LoopRO(Device):
    """
    loop3 and loop4 do not use the heaters.
    """
    # Set this to normal because we don't use it.
    readback = FormattedComponent(EpicsSignalRO,
                                  "{prefix}IN{loop_number}",
                                  kind="normal")
    units = FormattedComponent(EpicsSignalWithRBV,
                               "{prefix}IN{loop_number}:Units",
                               kind="omitted")
    loop_name = FormattedComponent(EpicsSignalRO,
                                   "{prefix}IN{loop_number}:Name_RBV",
                                   kind="omitted")

    def __init__(self, *args, loop_number=None, **kwargs):
        self.loop_number = loop_number
        super().__init__(*args, **kwargs)
示例#14
0
class SlitDevice(Device):

    # Setting motors
    top = FormattedComponent(EpicsMotor,
                             '{prefix}{_motorsDict[top]}',
                             labels=('motors', 'slits'))

    bot = FormattedComponent(EpicsMotor,
                             '{prefix}{_motorsDict[bot]}',
                             labels=('motors', 'slits'))

    out = FormattedComponent(EpicsMotor,
                             '{prefix}{_motorsDict[out]}',
                             labels=('motors', 'slits'))

    inb = FormattedComponent(EpicsMotor,
                             '{prefix}{_motorsDict[inb]}',
                             labels=('motors', 'slits'))

    # Setting pseudo positioners
    vcen = FormattedComponent(PVPositionerSoftDone,
                              '{prefix}{_slit_prefix}',
                              readback_pv='Vt2.D',
                              setpoint_pv='Vcenter.VAL',
                              labels=('slits', ))

    vsize = FormattedComponent(PVPositionerSoftDone,
                               '{prefix}{_slit_prefix}',
                               readback_pv='Vt2.C',
                               setpoint_pv='Vsize.VAL',
                               labels=('slits', ))

    hcen = FormattedComponent(PVPositionerSoftDone,
                              '{prefix}{_slit_prefix}',
                              readback_pv='Ht2.D',
                              setpoint_pv='Hcenter.VAL',
                              labels=('slits', ))

    hsize = FormattedComponent(PVPositionerSoftDone,
                               '{prefix}{_slit_prefix}',
                               readback_pv='Ht2.C',
                               setpoint_pv='Hsize.VAL',
                               labels=('slits', ))

    def __init__(self, PV, name, motorsDict, slitnum, **kwargs):

        self._motorsDict = motorsDict
        self._slit_prefix = f'Slit{slitnum}'

        super().__init__(prefix=PV, name=name, **kwargs)
示例#15
0
class Monochromator(KohzuSeqCtl_Monochromator):
    """ Tweaks from apstools mono """

    wavelength = Component(KohzuPositioner,
                           "",
                           readback_pv="BraggLambdaRdbkAO",
                           setpoint_pv="BraggLambdaAO")

    energy = Component(KohzuPositioner,
                       "",
                       readback_pv="BraggERdbkAO",
                       setpoint_pv="BraggEAO")

    theta = Component(KohzuPositioner,
                      "",
                      readback_pv="BraggThetaRdbkAO",
                      setpoint_pv="BraggThetaAO")

    # No y1 at 4-ID-D
    y1 = None

    x2 = Component(EpicsMotor, 'm6', labels=('motors', 'mono'))
    y2 = Component(EpicsSignalRO, 'KohzuYRdbkAI', labels=('motors', 'mono'))
    z2 = Component(EpicsSignalRO, 'KohzuZRdbkAI', labels=('motors', 'mono'))

    thf2 = Component(EpicsMotor, 'm4', labels=('motors', 'mono'))
    chi2 = Component(EpicsMotor, 'm5', labels=('motors', 'mono'))

    table_x = Component(EpicsMotor, 'm7', labels=('motors', 'mono'))
    table_y = Component(EpicsMotor, 'm8', labels=('motors', 'mono'))

    feedback = FormattedComponent(MonoFeedback, '4id:')

    def calibrate_energy(self, value):
        """Calibrate the mono energy.
        Parameters
        ----------
        value: float
            New energy for the current monochromator position.
        """
        self.use_set.put('Set', use_complete=True)
        self.energy.put(value)
        self.use_set.put('Use', use_complete=True)
示例#16
0
class Transfocator(Device):
    """
    Class to represent the MFX Transfocator
    """
    # Define EPICS signals
    xrt_limit = Component(EpicsSignalRO, ":XRT_ONLY")
    tfs_limit = Component(EpicsSignalRO, ":MFX_ONLY")
    faulted = Component(EpicsSignalRO, ":BEAM:FAULTED")

    # XRT Lenses
    prefocus_top = Component(Lens, ":DIA:03")
    prefocus_mid = Component(Lens, ":DIA:02")
    prefocus_bot = Component(Lens, ":DIA:01")

    # TFS Lenses
    tfs_02 = Component(Lens, ":TFS:02")
    tfs_03 = Component(Lens, ":TFS:03")
    tfs_04 = Component(Lens, ":TFS:04")
    tfs_05 = Component(Lens, ":TFS:05")
    tfs_06 = Component(Lens, ":TFS:06")
    tfs_07 = Component(Lens, ":TFS:07")
    tfs_08 = Component(Lens, ":TFS:08")
    tfs_09 = Component(Lens, ":TFS:09")
    tfs_10 = Component(Lens, ":TFS:10")

    # Translation
    translation = FormattedComponent(IMS, "MFX:TFS:MMS:21")

    def __init__(self, prefix, *, nominal_sample=399.88103, **kwargs):
        self.nominal_sample = nominal_sample
        super().__init__(prefix, **kwargs)

    @property
    def lenses(self):
        """
        Component lenses
        """
        return [getattr(self, dev) for dev in self._sub_devices
                if isinstance(getattr(self, dev), Lens)]

    @property
    def xrt_lenses(self):
        """
        Lenses in the XRT
        """
        return [lens for lens in self.lenses if 'DIA' in lens.prefix]

    @property
    def tfs_lenses(self):
        """
        Transfocator lenses
        """
        return [lens for lens in self.lenses if 'TFS' in lens.prefix]

    @property
    def current_focus(self):
        """
        The distance from the focus of the Transfocator to nominal_sample

        Note
        ----
        If no lenses are inserted this will retun NaN
        """
        # Find inserted lenses
        inserted = [lens for lens in self.lenses if lens.inserted]
        # Check that we have any inserted lenses at all
        if not inserted:
            logger.warning("No lenses are currently inserted")
            return math.nan
        # Calculate the image from this set of lenses
        return LensConnect(*inserted).image(0.0) - self.nominal_sample

    def find_best_combo(self, target=None, show=True, **kwargs):
        """
        Calculate the best lens array to hit the nominal sample point

        Parameters
        ----------
        target : float, optional
            The target image of the lens array. By default this is
            `nominal_sample`

        show : bool, optional
            Print a table of the of the calculated lens combination

        kwargs:
            Passed to :meth:`.Calculator.find_solution`
        """
        target = target or self.nominal_sample
        # Only included allowed XRT lenses
        xrt_limit = self.xrt_limit.get()
        allowed_xrt = [lens for lens in self.xrt_lenses
                       if lens.radius >= xrt_limit]
        # Warn users if no XRT lenses are over the required radius
        if not allowed_xrt:
            logger.warning("Can not find a prefocusing lens that meets the "
                           "safety requirements")
        # Create a calculator
        calc = Calculator(allowed_xrt, self.tfs_lenses)
        # Return the solution
        combo = calc.find_solution(target, **kwargs)
        combo.show_info()
        return combo

    def set(self, value, **kwargs):
        """
        Set the Transfocator focus

        Parameters
        """
        return self.focus_at(value=value, **kwargs)

    def focus_at(self, value=None, wait=False, timeout=None, **kwargs):
        """
        Calculate a combination and insert the lenses

        Parameters
        ----------
        value: float, optional
            Chosen focal plane. Nominal sample by default

        wait : bool, optional
            Wait for the motion of the transfocator to complete

        timeout: float, optional
            Timeout for motion

        kwargs:
            All passed to :meth:`.find_best_combo`

        Returns
        -------
        StateStatus
            Status that represents whether the move is complete
        """
        # Find the best combination of lenses to match the target image
        plane = value or self.nominal_sample
        best_combo = self.find_best_combo(target=plane, **kwargs)
        # Collect status to combine
        statuses = list()
        # Only tell one XRT lens to insert
        prefocused = False
        for lens in self.xrt_lenses:
            if lens in best_combo.lenses:
                statuses.append(lens.insert(timeout=timeout))
                prefocused = True
                break
        # If we have no XRT lenses one remove will do
        if not prefocused:
            statuses.append(self.xrt_lenses[0].remove(timeout=timeout))
        # Ensure all Transfocator lenses are correct
        for lens in self.tfs_lenses:
            if lens in best_combo.lenses:
                statuses.append(lens.insert(timeout=timeout))
            else:
                statuses.append(lens.remove(timeout=timeout))
        # Conglomerate all status objects
        status = statuses.pop(0)
        for st in statuses:
            status = status & st
        # Wait if necessary
        if wait:
            status_wait(status, timeout=timeout)
        return status
示例#17
0
class SimulatedApsPssShutterWithStatus(Device):
    """
    Simulated APS PSS shutter
    """
    open_bit = Component(SynSignal)
    close_bit = Component(SynSignal)
    pss_state = FormattedComponent(SynSignal)

    # strings the user will use
    open_str = 'open'
    close_str = 'close'

    # pss_state PV values from EPICS
    open_val = 1
    close_val = 0

    # simulated response time for PSS status
    response_time = 0.5

    def __init__(self, *args, **kwargs):
        super().__init__(self, *args, **kwargs)
        self.open_bit.set(0)
        self.close_bit.set(0)
        self.pss_state.set(self.close_val)

    def open(self, timeout=10):
        """request the shutter to open"""
        self.set(self.open_str)

    def close(self, timeout=10):
        """request the shutter to close"""
        self.set(self.close_str)

    def set(self, value, **kwargs):
        """set the shutter to "close" or "open" """
        # first, validate the input value
        acceptables = (self.close_str, self.open_str)
        if value not in acceptables:
            msg = "value should be one of " + " | ".join(acceptables)
            msg += " : received " + str(value)
            raise ValueError(msg)

        command_signal = {
            self.open_str: self.open_bit,
            self.close_str: self.close_bit
        }[value]
        expected_value = {
            self.open_str: self.open_val,
            self.close_str: self.close_val
        }[value]

        working_status = DeviceStatus(self)
        simulate_delay = self.pss_state.value != expected_value

        def shutter_cb(value, timestamp, **kwargs):
            self.pss_state.clear_sub(shutter_cb)
            if simulate_delay:
                time.sleep(self.response_time)
            self.pss_state.set(expected_value)
            working_status._finished()

        self.pss_state.subscribe(shutter_cb)

        command_signal.put(1)

        # finally, make sure both signals are reset
        self.open_bit.put(0)
        self.close_bit.put(0)
        return working_status

    @property
    def isOpen(self):
        """is the shutter open?"""
        if self.pss_state.value is None:
            self.pss_state.set(self.close_val)
        return self.pss_state.value == self.open_val

    @property
    def isClosed(self):
        """is the shutter closed?"""
        if self.pss_state.value is None:
            self.pss_state.set(self.close_val)
        return self.pss_state.value == self.close_val
示例#18
0
class FourCircleDiffractometer(E4CV):
    """
    E4CV: huber diffractometer in 4-circle vertical geometry with energy.

    4-ID-D setup.
    """

    # HKL and 4C motors
    h = Component(PseudoSingle, '', labels=("hkl", "fourc"))
    k = Component(PseudoSingle, '', labels=("hkl", "fourc"))
    l = Component(PseudoSingle, '', labels=("hkl", "fourc"))

    theta = Component(EpicsMotor, 'm65', labels=("motor", "fourc"))
    chi = Component(EpicsMotor, 'm67', labels=("motor", "fourc"))
    phi = Component(EpicsMotor, 'm68', labels=("motor", "fourc"))
    tth = Component(EpicsMotor, 'm66', labels=("motor", "fourc"))

    th_tth_min = Component(EpicsSignal,
                           "userCalc1.C",
                           labels=('fourc', 'limits'),
                           kind='config')
    th_tth_permit = Component(EpicsSignal,
                              "userCalc1.VAL",
                              labels=('fourc', 'limits'),
                              kind='config')

    # Explicitly selects the real motors
    _real = ['theta', 'chi', 'phi', 'tth']

    # Cryo carrier
    x = Component(EpicsMotor, 'm14', labels=('motor', 'fourc'))  # Cryo X
    y = Component(EpicsMotor, 'm15', labels=('motor', 'fourc'))  # Cryo Y
    z = Component(EpicsMotor, 'm16', labels=('motor', 'fourc'))  # Cryo Z

    # Base motors
    baseth = Component(EpicsMotor, 'm69', labels=('motor', 'fourc'))
    basetth = Component(EpicsMotor, 'm70', labels=('motor', 'fourc'))

    tablex = Component(EpicsMotor, 'm18', labels=('motor', 'fourc'))
    tabley = Component(EpicsMotor, 'm17', labels=('motor', 'fourc'))

    # Analyzer motors
    ath = Component(EpicsMotor, 'm77', labels=('motor', 'fourc'))
    achi = Component(EpicsMotor, 'm79', labels=('motor', 'fourc'))
    atth = Component(EpicsMotor, 'm78', labels=('motor', 'fourc'))

    # Energy
    energy = FormattedComponent(EpicsSignalRO,
                                "4idb:BraggERdbkAO",
                                kind='omitted')
    # energy_EGU = Component(EpicsSignal, "optics:energy.EGU")
    energy_update_calc_flag = Component(Signal, value=1)
    energy_offset = Component(Signal, value=0)

    # TODO: This is needed to prevent busy plotting.
    @property
    def hints(self):
        fields = []
        for _, component in self._get_components_of_kind(Kind.hinted):
            if (~Kind.normal & Kind.hinted) & component.kind:
                c_hints = component.hints
                fields.extend(c_hints.get('fields', []))
        return {'fields': fields}
示例#19
0
class SlitDevice(Device):

    ## Setting motors ##
    top = FormattedComponent(EpicsMotor,
                             '{self.prefix}:{_motorsDict[top]}',
                             labels=('motor', 'slit'))

    bot = FormattedComponent(EpicsMotor,
                             '{self.prefix}:{_motorsDict[bot]}',
                             labels=('motor', 'slit'))

    out = FormattedComponent(EpicsMotor,
                             '{self.prefix}:{_motorsDict[out]}',
                             labels=('motor', 'slit'))

    inb = FormattedComponent(EpicsMotor,
                             '{self.prefix}:{_motorsDict[inb]}',
                             labels=('motor', 'slit'))

    ## Setting pseudo positioners ##
    vcen = FormattedComponent(EpicsSignal,
                              '{self.prefix}:{_signalsDict[vcen][0]}',
                              write_pv='{self.prefix}:{_signalsDict[vcen][1]}',
                              labels=('slit'))

    hcen = FormattedComponent(EpicsSignal,
                              '{self.prefix}:{_signalsDict[hcen][0]}',
                              write_pv='{self.prefix}:{_signalsDict[hcen][1]}',
                              labels=('slit'))

    vsize = FormattedComponent(
        EpicsSignal,
        '{self.prefix}:{_signalsDict[vsize][0]}',
        write_pv='{self.prefix}:{_signalsDict[vsize][1]}',
        labels=('slit'))

    hsize = FormattedComponent(
        EpicsSignal,
        '{self.prefix}:{_signalsDict[hsize][0]}',
        write_pv='{self.prefix}:{_signalsDict[hsize][1]}',
        labels=('slit'))

    def __init__(self,
                 PV,
                 name,
                 motorsDict,
                 slitnum=None,
                 signalsDict=None,
                 **kwargs):

        self._motorsDict = motorsDict

        if signalsDict is None:
            if type(slitnum) != int:
                raise TypeError(
                    'If signalsDict is None, then slitnum has to be an integer!'
                )
            else:
                prefix = 'Slit{}'.format(slitnum)
                self._signalsDict = {
                    'vcen': [prefix + 'Vt2.D', prefix + 'Vcenter'],
                    'vsize': [prefix + 'Vt2.C', prefix + 'Vsize'],
                    'hcen': [prefix + 'Ht2.D', prefix + 'Hcenter'],
                    'hsize': [prefix + 'Ht2.C', prefix + 'Hsize']
                }
        else:
            self._signalsDict = signalsDict

        super().__init__(prefix=PV, name=name, **kwargs)
示例#20
0
class Xspress3Channel(Device):

    rois = FormattedComponent(ROIDevice, '{prefix}MCA{_chnum}ROI:')

    # Timestamp --> it's used to tell when the ROI plugin is done.
    timestamp = FormattedComponent(EpicsSignalRO,
                                   '{prefix}MCA{_chnum}ROI:TimeStamp_RBV',
                                   kind='omitted',
                                   auto_monitor=True)

    # SCAs
    clock_ticks = FormattedComponent(EpicsSignalRO,
                                     '{prefix}C{_chnum}SCA0:Value_RBV')

    reset_ticks = FormattedComponent(EpicsSignalRO,
                                     '{prefix}C{_chnum}SCA1:Value_RBV')

    reset_counts = FormattedComponent(EpicsSignalRO,
                                      '{prefix}C{_chnum}SCA2:Value_RBV')

    all_events = FormattedComponent(EpicsSignalRO,
                                    '{prefix}C{_chnum}SCA3:Value_RBV')

    all_good = FormattedComponent(EpicsSignalRO,
                                  '{prefix}C{_chnum}SCA4:Value_RBV')

    pileup = FormattedComponent(EpicsSignalRO,
                                '{prefix}C{_chnum}SCA7:Value_RBV')

    dt_factor = FormattedComponent(EpicsSignalRO,
                                   '{prefix}C{_chnum}SCA8:Value_RBV')

    def __init__(self, *args, chnum, **kwargs):
        # TODO: I don't like how this is currently implemented, but it works.
        self._chnum = chnum
        super().__init__(*args, **kwargs)

    def _status_done(self):

        # Create status that checks when the timestamp updates.
        status = Status(self.timestamp, settle_time=0.01)

        def _set_finished(**kwargs):
            status.set_finished()
            self.timestamp.clear_sub(_set_finished)

        self.timestamp.subscribe(_set_finished, event_type='value', run=False)

        return status

    @property
    def all_rois(self):
        for roi in range(1, self.rois.num_rois.get() + 1):
            yield getattr(self.rois, 'roi{:02d}'.format(roi))

    def set_roi(self, index, ev_low, ev_size, name=None, enable=True):
        '''Set specified ROI to (ev_low, ev_size)
        Parameters
        ----------
        index : int or list of int
            ROI index. It can be passed as an integer or an iterable with
            integers.
        ev_low : int
            low eV setting.
        ev_size : int
            size eV setting.
        name : str, optional
            ROI name, if nothing is passed it will keep the current name.
        enable : boolean
            Flag to enable the ROI.
        '''
        if isinstance(index, int):
            index = [index]

        rois = list(self.all_rois)

        for ind in index:
            if ind <= 0:
                raise ValueError('ROI index starts from 1')

            roi = rois[ind - 1]

            if not name:
                name = roi.roi_name.get()

            roi.configure(name, ev_low, ev_size, enable=enable)
示例#21
0
class LS340Device(Device):
    """ Lakeshore 340 setup EPICS version 1.1 """

    control = FormattedComponent(LS340_LoopControl, "{prefix}",
                                 loop_number=1)
    sample = FormattedComponent(LS340_LoopSample, "{prefix}",
                                loop_number=2)

    heater = Component(EpicsSignalRO, "Heater")
    heater_range = Component(EpicsSignal, "Rg_rdbk", write_pv="HeatRg",
                             kind="normal", put_complete=True)

    auto_heater = Component(TrackingSignal, value=False, kind="config")

    read_pid = Component(EpicsSignal, "readPID.PROC", kind="omitted")

    # same names as apstools.synApps._common.EpicsRecordDeviceCommonAll
    scanning_rate = Component(EpicsSignal, "read.SCAN", kind="omitted")
    process_record = Component(EpicsSignal, "read.PROC", kind="omitted")

    serial = Component(AsynRecord, "serial", kind="omitted")

    # This must be modified either here, or before using auto_heater.
    _auto_ranges = None

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # TODO: I don't know why this has to be done, otherwise it gets hinted.
        self.control.readback.kind = "normal"

    @auto_heater.sub_value
    def _subscribe_auto_heater(self, value=None, **kwargs):
        if value:
            self.control.setpoint.subscribe(self._switch_heater,
                                            event_type='value')
        else:
            self.control.setpoint.clear_subs(self._switch_heater)

    def _switch_heater(self, value=None, **kwargs):
        # TODO: Find a better way to do this, perhaps with an array?
        for _heater_range, _temp_range in self._auto_ranges.items():
            if _temp_range:
                if _temp_range[0] < value <= _temp_range[1]:
                    self.heater_range.put(_heater_range)

    @property
    def auto_ranges(self):
        return self._auto_ranges

    @auto_ranges.setter
    def auto_ranges(self, value):
        if not isinstance(value, dict):
            raise TypeError('auto_ranges must be a dictionary.')

        for _heater_range, _temp_range in value.items():
            if _heater_range not in self.heater_range.enum_strs:
                raise ValueError("The input dictionary keys must be one of "
                                 f"these: {self.heater_range.enum_strs}, but "
                                 f"{_heater_range} was entered.")

            if _temp_range is not None and len(_temp_range) != 2:
                raise ValueError(f"The value {_temp_range} is invalid! It "
                                 "must be either None or an iterable with two "
                                 "items.")

            self._auto_ranges = value
示例#22
0
class PVPositionerSoftDone(PVPositioner):

    # positioner
    readback = FormattedComponent(EpicsSignalRO,
                                  "{prefix}{_readback_pv}",
                                  kind="hinted",
                                  auto_monitor=True)
    setpoint = FormattedComponent(EpicsSignal,
                                  "{prefix}{_setpoint_pv}",
                                  kind="normal",
                                  put_complete=True)
    done = Component(Signal, value=True, kind="config")
    done_value = True

    # tolerance always updated during init.
    tolerance = Component(Signal, value=1, kind="config")
    report_dmov_changes = Component(Signal, value=False, kind="omitted")

    def cb_readback(self, *args, **kwargs):
        """
        Called when readback changes (EPICS CA monitor event).
        """
        diff = self.readback.get() - getattr(self, self._target_attr).get()
        dmov = abs(diff) <= self.tolerance.get()
        if self.report_dmov_changes.get() and dmov != self.done.get():
            logger.debug(f"{self.name} reached: {dmov}")
        self.done.put(dmov)

    def cb_setpoint(self, *args, **kwargs):
        """
        Called when setpoint changes (EPICS CA monitor event).
        When the setpoint is changed, force done=False.  For any move,
        done must go != done_value, then back to done_value (True).
        Without this response, a small move (within tolerance) will not return.
        Next update of readback will compute self.done.
        """
        self.done.put(not self.done_value)

    def __init__(self,
                 prefix,
                 *,
                 limits=None,
                 readback_pv="",
                 setpoint_pv="",
                 name=None,
                 read_attrs=None,
                 configuration_attrs=None,
                 parent=None,
                 egu="",
                 tolerance=None,
                 target_attr="setpoint",
                 **kwargs):

        self._setpoint_pv = setpoint_pv
        self._readback_pv = readback_pv
        self._target_attr = target_attr

        super().__init__(prefix=prefix,
                         limits=limits,
                         name=name,
                         read_attrs=read_attrs,
                         configuration_attrs=configuration_attrs,
                         parent=parent,
                         egu=egu,
                         **kwargs)

        # Make the default alias for the readback the name of the
        # positioner itself as in EpicsMotor.
        self.readback.name = self.name

        self.readback.subscribe(self.cb_readback)
        self.setpoint.subscribe(self.cb_setpoint)

        if tolerance is None:
            self.readback.wait_for_connection(timeout=5.0)
            self.setpoint.wait_for_connection(timeout=5.0)

            rb = self.readback.precision
            sp = self.setpoint.precision

            tolerance = rb if rb >= sp else sp

        self.tolerance.put(tolerance)

    def _setup_move(self, position):
        '''Move and do not wait until motion is complete (asynchronous)'''
        self.log.debug('%s.setpoint = %s', self.name, position)
        self.setpoint.put(position, wait=False)
        if self.actuate is not None:
            self.log.debug('%s.actuate = %s', self.name, self.actuate_value)
            self.actuate.put(self.actuate_value, wait=False)
示例#23
0
class LS336_LoopControl(PVPositionerSoftDone):
    """
    Setup for loop with heater control.

    The lakeshore 336 accepts up to two heaters.
    """

    # position
    # TODO: Not sure this will work. May need to separate the RO again.
    readback = FormattedComponent(EpicsSignalRO,
                                  "{prefix}IN{loop_number}",
                                  auto_monitor=True,
                                  kind="hinted")
    setpoint = FormattedComponent(EpicsSignalWithRBV,
                                  "{prefix}OUT{loop_number}:SP",
                                  put_complete=True,
                                  kind="normal")
    # Due to ramping the setpoint will change slowly and the readback may catch
    # up even if the motion is not done.
    target = Component(Signal, value=0, kind="omitted")

    heater = FormattedComponent(EpicsSignalRO,
                                "{prefix}HTR{loop_number}",
                                auto_monitor=True,
                                kind="normal")

    # configuration
    units = FormattedComponent(EpicsSignalWithRBV,
                               "{prefix}IN{loop_number}:Units",
                               kind="config")
    pid_P = FormattedComponent(EpicsSignalWithRBV,
                               "{prefix}P{loop_number}",
                               kind="config")
    pid_I = FormattedComponent(EpicsSignalWithRBV,
                               "{prefix}I{loop_number}",
                               kind="config")
    pid_D = FormattedComponent(EpicsSignalWithRBV,
                               "{prefix}D{loop_number}",
                               kind="config")
    ramp_rate = FormattedComponent(EpicsSignalWithRBV,
                                   "{prefix}RampR{loop_number}",
                                   kind="config")
    ramp_on = FormattedComponent(EpicsSignalWithRBV,
                                 "{prefix}OnRamp{loop_number}",
                                 kind="config")

    loop_name = FormattedComponent(EpicsSignalRO,
                                   "{prefix}IN{loop_number}:Name_RBV",
                                   kind="config")
    control = FormattedComponent(EpicsSignalWithRBV,
                                 "{prefix}OUT{loop_number}:Cntrl",
                                 kind="config")
    manual = FormattedComponent(EpicsSignalWithRBV,
                                "{prefix}OUT{loop_number}:MOUT",
                                kind="config")
    mode = FormattedComponent(EpicsSignalWithRBV,
                              "{prefix}OUT{loop_number}:Mode",
                              kind="config")
    heater_range = FormattedComponent(EpicsSignalWithRBV,
                                      "{prefix}HTR{loop_number}:Range",
                                      kind="config",
                                      auto_monitor=True,
                                      string=True)

    auto_heater = Component(TrackingSignal, value=False, kind="config")

    # This must be modified either here, or before using auto_heater.
    _auto_ranges = None

    def __init__(self,
                 *args,
                 loop_number=None,
                 timeout=60 * 60 * 10,
                 **kwargs):
        self.loop_number = loop_number
        super().__init__(*args,
                         timeout=timeout,
                         tolerance=0.1,
                         target_attr="target",
                         **kwargs)
        self._settle_time = 0

    @property
    def settle_time(self):
        return self._settle_time

    @settle_time.setter
    def settle_time(self, value):
        if value < 0:
            raise ValueError('Settle value needs to be >= 0.')
        else:
            self._settle_time = value

    @property
    def egu(self):
        return self.units.get(as_string=True)

    def stop(self, *, success=False):
        if success is False:
            self.setpoint.put(self._position)
        super().stop(success=success)

    def pause(self):
        self.setpoint.put(self._position)

    def move(self, position, **kwargs):
        # Need to update the target.
        self.target.put(position)
        return super().move(position, **kwargs)

    @auto_heater.sub_value
    def _subscribe_auto_heater(self, value=None, **kwargs):
        if value:
            self.setpointRO.subscribe(self._switch_heater, event_type='value')
        else:
            self.setpointRO.clear_subs(self._switch_heater)

    def _switch_heater(self, value=None, **kwargs):
        # TODO: Find a better way to do this, perhaps with an array?
        for _heater_range, _temp_range in self._auto_ranges.items():
            if _temp_range:
                if _temp_range[0] < value <= _temp_range[1]:
                    self.heater_range.put(_heater_range)

    @property
    def auto_ranges(self):
        return self._auto_ranges

    @auto_ranges.setter
    def auto_ranges(self, value):
        if not isinstance(value, dict):
            raise TypeError('auto_ranges must be a dictionary.')

        for _heater_range, _temp_range in value.items():
            if _heater_range not in self.heater_range.enum_strs:
                raise ValueError("The input dictionary keys must be one of "
                                 f"these: {self.heater_range.enum_strs}, but "
                                 f"{_heater_range} was entered.")

            if _temp_range is not None and len(_temp_range) != 2:
                raise ValueError(f"The value {_temp_range} is invalid! It "
                                 "must be either None or an iterable with two "
                                 "items.")

            self._auto_ranges = value
示例#24
0
class LS340_LoopBase(PVPositionerSoftDone):
    """ Base settings for both sample and control loops. """

    # position
    readback = Component(Signal, value=0)
    setpoint = FormattedComponent(SetpointSignal, "{prefix}SP{loop_number}",
                                  write_pv="{prefix}wr_SP{loop_number}",
                                  kind="normal", put_complete=True)

    # This is here only because of ramping, because then setpoint will change
    # slowly.
    target = Component(Signal, value=0, kind="omitted")

    # configuration
    units = Component(Signal, value='K', kind="config")

    pid_P = FormattedComponent(EpicsSignal, "{prefix}P{loop_number}",
                               write_pv='{prefix}setPID{loop_number}.AA',
                               kind="config")
    pid_I = FormattedComponent(EpicsSignal, "{prefix}I{loop_number}",
                               write_pv='{prefix}setPID{loop_number}.BB',
                               kind="config")
    pid_D = FormattedComponent(EpicsSignal, "{prefix}D{loop_number}",
                               write_pv='{prefix}setPID{loop_number}.CC',
                               kind="config")

    ramp_rate = FormattedComponent(EpicsSignal,
                                   "{prefix}Ramp{loop_number}",
                                   write_pv='{prefix}setRamp{loop_number}.BB',
                                   kind="config")
    ramp_on = FormattedComponent(EpicsSignal,
                                 "{prefix}Ramp{loop_number}_on",
                                 kind="config")

    def __init__(self, *args, loop_number=None, timeout=60*60*10, **kwargs):
        self.loop_number = loop_number
        super().__init__(*args, timeout=timeout, tolerance=0.1,
                         target_attr="target", **kwargs)
        self._settle_time = 0

    @property
    def settle_time(self):
        return self._settle_time

    @settle_time.setter
    def settle_time(self, value):
        if value < 0:
            raise ValueError('Settle value needs to be >= 0.')
        else:
            self._settle_time = value

    @property
    def egu(self):
        return self.units.get(as_string=True)

    def stop(self, *, success=False):
        if success is False:
            self.setpoint.put(self._position)
        super().stop(success=success)

    def pause(self):
        self.setpoint.put(self._position, wait=True)

    def move(self, position, **kwargs):
        # Need to update the target.
        self.target.put(position)
        return super().move(position, **kwargs)