Exemple #1
0
    def trigger(self):
        """
        Trigger the EventSequencer

        This method reconfigures the EventSequencer to take a new reading. This
        means:

            * Stopping the EventSequencer if it is already running
            * Restarting the EventSequencer

        The returned status object will indicate different behavior based on
        the configuration of the EventSequencer itself. If set to "Run
        Forever", the status object merely indicates that we have succesfully
        started our sequence. Otherwise, the status object will be completed
        when the sequence we have set it to play is complete.
        """
        # Stop the Sequencer if it is already running
        self.stop()
        # Fire the EventSequencer
        self.start()
        # If we are running forever, count this is as triggered
        if self.play_mode.get() == 2:
            logger.debug("EventSequencer is set to run forever, "
                         "trigger is complete")
            return DeviceStatus(self, done=True, success=True)

        # Create our status
        def done(*args, value=None, old_value=None, **kwargs):
            return value == 2 and old_value == 0

        # Create our status object
        return SubscriptionStatus(self.play_status, done, run=True)
Exemple #2
0
    def _clear_flag(self, flag, wait=False, timeout=10):
        """Clear flag whose information is in :attr:`._bit_flags`"""
        # Gather our flag information
        flag_info = self._bit_flags[flag]
        bit = flag_info['readback']
        mask = flag_info.get('mask', 1)

        # Create a callback function to check for bit
        def flag_is_cleared(value=None, **kwargs):
            return not bool((int(value) >> bit) & mask)

        # Check that we need to actually set the flag
        if flag_is_cleared(value=self.bit_status.get()):
            logger.debug("%s flag is not currently active", flag)
            st = DeviceStatus(self)
            st.set_finished()
            return st

        # Issue our command
        logger.info('Clearing %s flag ...', flag)
        self.seq_seln.put(flag_info['clear'])
        # Generate a status
        st = SubscriptionStatus(self.bit_status, flag_is_cleared)
        if wait:
            status_wait(st, timeout=timeout)
        return st
Exemple #3
0
    def reinitialize(self, wait=False):
        """
        Reinitialize the IMS motor.

        Parameters
        ----------
        wait : bool
            Wait for the motor to be fully intialized.

        Returns
        -------
        :class:`~ophyd.status.SubscriptionStatus`
            Status object reporting the initialization state of the motor.
        """
        logger.info('Reinitializing motor')
        # Issue command
        self.reinit_command.put(1)

        # Check error
        def initialize_complete(value=None, **kwargs):
            return value != 3

        # Generate a status
        st = SubscriptionStatus(self.error_severity,
                                initialize_complete,
                                settle_time=0.5)
        # Wait on status if requested
        if wait:
            status_wait(st)
        return st
Exemple #4
0
def test_subscription_status():
    # Arbitrary device
    d = Device("Tst:Prefix", name='test')
    # Mock callback
    m = Mock()

    # Full fake callback signature
    def cb(*args, done=False, **kwargs):
        # Run mock callback
        m()
        # Return finished or not
        return done

    status = SubscriptionStatus(d, cb, event_type=d.SUB_ACQ_DONE)

    # Run callbacks but do not mark as complete
    d._run_subs(sub_type=d.SUB_ACQ_DONE, done=False)
    time.sleep(0.1)  # Wait for callbacks to run.
    assert m.called
    assert not status.done and not status.success

    # Run callbacks and mark as complete
    d._run_subs(sub_type=d.SUB_ACQ_DONE, done=True)
    time.sleep(0.1)  # Wait for callbacks to run.
    assert status.done and status.success
Exemple #5
0
    def set(self, value, *args, **kwargs):
        """Set the sequencer start PV to the inputted value."""
        def cb(*args, **kwargs):
            time.sleep(self._cb_sleep)
            return self.play_status.get() == 0

        self.play_control.put(value)
        return SubscriptionStatus(self.play_status, cb)
Exemple #6
0
    def trigger(self):
        super().trigger()
        print(f"I got the trigger!")
        acquire_status = SubscriptionStatus(self.cam.acquire,
                                            acquire_high_to_low)

        self.cam.acquire.set(PerkinElmerCamera.Acquire.ACQUIRE)

        return acquire_status
Exemple #7
0
    def set(self, command):
        if command == 'prepare':

            # This function will receive Events from the IOC and check whether
            # we are seeing the trajectory_ready go low after having been high.
            def callback(value, old_value, **kwargs):
                if int(round(old_value)) == 1 and int(round(value)) == 0:
                    if self._preparing or self._preparing is None:
                        self._preparing = False
                        return True
                    else:
                        self._preparing = True
                return False

            # Creating this status object subscribes `callback` Events from the
            # IOC. Starting at this line, we are now listening for the IOC to
            # tell us it is done. When it does, this status object will
            # complete (status.done = True).
            status = SubscriptionStatus(self.trajectory_ready, callback)

            # Finally, now that we are litsening to the IOC, prepare the
            # trajectory.
            self.prepare_trajectory.set('1')  # Yes, the IOC requires a string.

            # Return the status object immediately, without waiting. The caller
            # will be able to watch for it to become done.
            return status

        if command == 'start':

            def callback(value, old_value, **kwargs):
                if int(round(old_value)) == 1 and int(round(value)) == 0:
                    if self._starting or self._starting is None:
                        self._starting = False
                        return True
                    else:
                        self._starting = True
                return False

            status = SubscriptionStatus(self.trajectory_running, callback)
            self.start_trajectory.set('1')

            return status
Exemple #8
0
 def _wait(self, sig, *goals):
     """
     Helper function to wait for a signal to reach a value. This is used
     here because most commands are only valid when mode is IDLE.
     """
     def cb(value, *args, **kwargs):
         logger.debug((value, goals))
         return value in goals
     status = SubscriptionStatus(sig, cb)
     status_wait(status)
Exemple #9
0
    def complete(self):
        # Use whether X in the coordinate system is moving
        # as a proxy for whether the total flyscan is done.
        # This might be brittle but there is no straightforward way
        # to check for done-ness, and this is easy to put together.
        # Should probably be improved to account for y also.

        def is_done(value, **kwargs):
            return not value

        x_moving = SubscriptionStatus(scan_in_progress, is_done)
        return x_moving
    def set(self, val):
        def check_if_done(value, old_value, **kwargs):
            if ((val in ['Open', 1] and value == 0)
                    or (val in ['Close', 0] and value == 1)):
                if self.st is not None:
                    self.st._finished()
                    self.st = None
                return True
            return False

        self.cmd.set(self.setmap[val])
        status = SubscriptionStatus(self.status, check_if_done)
        return status
Exemple #11
0
    def trigger(self, *args, **kwargs):
        "Trigger one acquisition."
        if self._staged != Staged.yes:
            raise RuntimeError("This detector is not ready to trigger."
                               "Call the stage() method before triggering.")

        def callback(value, old_value, **kwargs):
            if int(round(old_value)) == 1 and int(round(value)) == 0:
                return True
            return False

        status = SubscriptionStatus(self.mca.when_acq_stops, callback, run=False)
        self._acquisition_signal.set(1)

        return status
Exemple #12
0
    def kickoff(self):
        """
        Start the EventSequencer

        Returns
        -------
        status : SubscriptionStatus
            Status indicating whether or not the EventSequencer has started
        """
        self.start()
        # Start monitor signals
        super().kickoff()

        # Create our status
        def done(*args, value=None, old_value=None, **kwargs):
            return value == 2 and old_value == 0

        # Create our status object
        return SubscriptionStatus(self.play_status, done, run=True)
Exemple #13
0
    def complete(self):
        """
        Complete the EventSequencer's current sequence.

        The result of this method varies on the mode that the EventSequencer is
        configured. If the EventSequencer is either set to 'Run Once' or 'Run N
        Times' this method allows the current sequence to complete and returns
        a status object that indicates a successful completion. However, this
        mode of operation does not make sense if the EventSequencer is in
        'Run Forever' mode. In this case, the EventSequencer is stopped
        immediately and a completed status object is returned.

        Returns
        -------
        status : DeviceStatus or SubscriptionStatus
            Status indicating completion of sequence.

        Notes
        -----
        If you want to stop the sequence from running regardless of
        configuration use the :meth:`.stop` command.
        """

        # Clear the monitor subscriptions
        super().complete()
        # If we are running forever we can stop whenever
        if self.play_mode.get() == 2:
            logger.debug("EventSequencer is set to run forever, "
                         "stopping immediately")
            self.stop()
            return DeviceStatus(self, done=True, success=True)

        # Otherwise we should wait for the sequencer to end
        def done(*args, value=None, old_value=None, timestamp=0, **kwargs):
            return all((value == 0, old_value == 2,
                        timestamp > self.play_control.timestamp))

        # Create a SubscriptionStatus
        logger.debug("EventSequencer has a determined stopping point, "
                     " waiting for sequence to complete")
        st = SubscriptionStatus(self.play_status, done, run=True)
        return st
Exemple #14
0
    def complete(self):
        def callback_det(value, old_value, **kwargs):
            print(f"complete: {ttime.time()} {old_value} ---> {value}")
            if int(round(old_value)) == 1 and int(round(value)) == 0:
                return True
            else:
                return False

        streaming_st = SubscriptionStatus(self.det.streaming, callback_det)

        def callback_motor():
            # print(f'callback_motor {ttime.time()}')
            self.det.stream.set(0)
            self.det.complete()
            for pb in self.pbs:
                pb.complete()

        self._motor_status.add_callback(callback_motor)
        print(f"complete operation is happening ({ttime.ctime(ttime.time())})")
        return streaming_st & self._motor_status
Exemple #15
0
    def kickoff(self):
        """
        Start the EventSequencer.

        Returns
        -------
        status : ~ophyd.status.SubscriptionStatus
            Status indicating whether or not the EventSequencer has started.
        """

        self.start()
        # Start monitor signals
        super().kickoff()

        # Create our status
        def done(*args, value=None, old_value=None, timestamp=0, **kwargs):
            return all((value == 2, old_value == 0,
                        timestamp > self.play_control.timestamp))

        # Create our status object
        return SubscriptionStatus(self.play_status, done, run=True)
Exemple #16
0
    def kickoff(self, *args, **kwargs):
        set_and_wait(self.det.trig_source, 1)

        # TODO: handle it on the plan level
        # set_and_wait(self.motor, 'prepare')

        def callback(value, old_value, **kwargs):
            print(f"kickoff: {ttime.ctime()} {old_value} ---> {value}")
            if int(round(old_value)) == 0 and int(round(value)) == 1:
                # Now start mono move
                self._motor_status = self.motor.set("start")
                return True
            else:
                return False

        streaming_st = SubscriptionStatus(self.det.streaming, callback)
        self.det.stream.set(1)
        self.det.stage()
        for pb in self.pbs:
            pb.stage()
            pb.kickoff()
        return streaming_st
Exemple #17
0
    def trigger(self):
        """
        Set the acquire PV to 1 and wait for the acquiring PV
        to go from high (1) to low (0).

        Return
        ------
        SubscriptionStatus
            a Status object that indicates when acquisition is finished
        """

        def callback(value, old_value, **kwargs):
            # print(f'{ttime.time()} {old_value} ---> {value}')
            if self._capturing and int(round(old_value)) == 1 and int(round(value)) == 0:
                self._capturing = False
                return True
            else:
                self._capturing = True
                return False

        status = SubscriptionStatus(self.acquiring, callback)
        self.acquire.set(1)
        return status
Exemple #18
0
    def trigger(self, *args, **kwargs):
        "Trigger one acquisition."
        if self._staged != Staged.yes:
            raise RuntimeError("This detector is not ready to trigger."
                               "Call the stage() method before triggering.")

        def callback(value, old_value, **kwargs):
            print(f'  {self.name} old value {old_value} --> new_value {value}')
            if int(round(old_value)) == 1 and int(round(value)) == 0:
                if self._starting or self._starting is None:
                    self.starting = False
                    return True
                else:
                    self.starting = True
                return False

        status = SubscriptionStatus(self.mca.when_acq_stops, callback, run=False)
        print(f'  !!! attempting to put to {self._acquisition_signal.pvname} value 1')
        # ttime.sleep(0.1)
        timeout = 10  # s
        self._acquisition_signal.put(1)

        print(f'  !!! sleeping 0.1s after putting')
        t0 = ttime.time()
        print(f'Start waiting at {ttime.ctime(t0)}...')
        while True:
            ttime.sleep(0.01)
            if int(round(self.mca.when_acq_stops.get())) == 1:
                print(f'Success, {self.mca.when_acq_stops.pvname} was set to 1. Waited for {ttime.time() - t0}s.')
                break
            else:
                if ttime.time() - t0 > timeout:
                    print(f'Waited for {timeout}s, but the signal {self.mca.when_acq_stops.pvname} did not change. Attempting again.')
                    self._acquisition_signal.put(1)
                    break

        return status
Exemple #19
0
    def kickoff(self):
        set_scanning.put(1)

        def is_started(value, **kwargs):
            return bool(value)

        ready_to_scan = SubscriptionStatus(scan_in_progress, is_started)
        self._traj_info.update({
            'nx': int(self.hxn_stage.nx.get()),
            'ny': int(self.hxn_stage.ny.get()),
            'x_start': self.hxn_stage.x_start.get(),
            'x_stop': self.hxn_stage.x_stop.get(),
            'y_start': self.hxn_stage.y_start.get(),
            'y_stop': self.hxn_stage.y_stop.get(),
        })

        self._array_size.update({
            'height':
            getattr(self.detector, self.plugin_type).array_size.height.get(),
            'width':
            getattr(self.detector, self.plugin_type).array_size.width.get()
        })

        return ready_to_scan & self.hxn_stage.start_scan.set(1)
Exemple #20
0
 def set(self, device, function):
     return SubscriptionStatus(device, function)
def pe_count(
    filename="",
    exposure=1,
    num_images: int = 1,
    num_dark_images: int = 1,
    num_repetitions: int = 5,
    delay=60,
):

    year = "2020"  # RE.md["year"]
    cycle = "C2"  # RE.md["cycle"]
    proposal = "67890"  # RE.md["PROPOSAL"]

    # write_path_template = 'Z:\\data\\pe1_data\\%Y\\%m\\%d\\'
    # write_path_template = f"Z:\\users\\{year}\\{cycle}\\{proposal}XRD\\"
    # file_path = datetime.now().strftime(write_path_template)
    # filename = filename + str(uuid.uuid4())[:6]

    # this is an example of what would be used at the beamline
    pe_detector.tiff_writer.resource_root_path = PureWindowsPath(
        f"Z:\\users\\")
    pe_detector.tiff_writer.relative_write_path = PureWindowsPath(
        f"{year}\\{cycle}\\{proposal}XRD\\")

    # for testing
    pe_detector.tiff_writer.resource_root_path = Path("/tmp/")
    pe_detector.tiff_writer.relative_write_path = Path(
        f"perkin_elmer/detector/{year}/{cycle}/XRD{proposal}"  # remove "XRD" from the end?
    )

    # start the run
    yield from bps.open_run()

    # stage the detector
    yield from bps.stage(pe_detector)

    yield from bps.mv(pe_detector.tiff_writer.file_number, 1)
    tiff_full_file_path = (pe_detector.tiff_writer.resource_root_path /
                           pe_detector.tiff_writer.relative_write_path)

    print(f"tiff_full_file_path: {str(tiff_full_file_path)}")
    yield from bps.mv(pe_detector.tiff_writer.file_path,
                      str(tiff_full_file_path))

    for repetition_index in range(int(num_repetitions)):

        print("\n")
        print(
            "<<<<<<<<<<<<<<<<< Doing repetition {} out of {} >>>>>>>>>>>>>>>>>"
            .format(repetition_index + 1, num_repetitions))

        # TiffWriter or similar plugin should do this
        yield from bps.mv(pe_detector.tiff_writer.file_name,
                          filename + str(uuid.uuid4()))

        if num_dark_images > 0:
            # originally used pe_detector.num_dark_images
            # but this is really pe_num_offset_frames
            yield from bps.mv(pe_detector.cam.pe_num_offset_frames,
                              num_dark_images)
            yield from bps.mv(
                pe_detector.cam.image_mode,
                PerkinElmerCamera.PerkinElmerImageMode.AVERAGE,
            )
            # yield from bps.mv(fast_shutter, "Close")
            yield from bps.sleep(0.5)
            yield from bps.mv(pe_detector.tiff_writer.file_write_mode,
                              NDFile.FileWriteMode.SINGLE)

            # acquire a "dark frame"
            pe_acquire_offset_status = SubscriptionStatus(
                pe_detector.cam.pe_acquire_offset,
                high_to_low_pe_acquire_offset)
            yield from bps.abs_set(
                pe_detector.cam.pe_acquire_offset,
                PerkinElmerCamera.AcquireOffset.ACQUIRE,
                wait=False,
            )
            yield Msg("wait_for_status", None, pe_acquire_offset_status)

            yield from bps.mv(pe_detector.tiff_writer.write_file,
                              NDFile.WriteFile.WRITE)

        # yield from bps.mv(
        #  pe1.cam.image_mode,
        #  NewPerkinElmerDetector.ImageMode.MULTIPLE
        # )
        yield from bps.mv(
            pe_detector.cam.image_mode,
            PerkinElmerCamera.PerkinElmerImageMode.AVERAGE,
        )
        yield from bps.mv(pe_detector.cam.acquire_time, exposure)
        yield from bps.mv(pe_detector.cam.num_images, num_images)

        # yield from bps.mv(fast_shutter, "Open")
        yield from bps.sleep(0.5)

        ## Below 'Capture' mode is used with 'Multiple' image_mode
        # yield from bps.mv(pe1.tiff_writer.file_write_mode, 'Capture')

        ## Below 'Single' mode is used with 'Average' image_mode
        yield from bps.mv(
            pe_detector.tiff_writer.file_write_mode,
            NDFile.FileWriteMode.SINGLE,  # "Single"
        )

        ## Uncomment 'capture' bit settings when used in 'Capture' mode
        # yield from bps.mv(pe1.tiff_writer.capture, 1)

        # this was the old way to initiate the acquisition
        # yield from bps.mv(pe_detector, "acquire_light")

        yield from bps.trigger_and_read([pe_detector], name="primary")

        # can TiffWriter or similar plugin do this?
        ##Below write_file is needed when used in 'Average' mode
        yield from bps.mv(
            pe_detector.tiff_writer.write_file,
            NDFile.WriteFile.WRITE  # 1
        )

        yield from bps.sleep(delay)

    # unstage the detector
    yield from bps.unstage(pe_detector)

    # end the run
    yield from bps.close_run()