Beispiel #1
0
    def end_scan(self):
        """Performs the operations needed at the very end of a scan.

        This does the following:

        - Add theta to the raw data file. 

        - Close the shutter

        - Calls the base class method.
        """
        log.info('end scan')

        # Close the shutter
        self.close_shutter()

        # Stop the file plugin, though it should be done already
        self.epics_pvs['FPCapture'].put('Done')
        self.wait_pv(self.epics_pvs['FPCaptureRBV'], 0)

        # Add theta in the hdf file
        self.add_theta()

        # Copy file to the analysis computer, if desired
        self.auto_copy_data()

        # Call the base class method
        super().end_scan()
Beispiel #2
0
    def add_theta(self):
        """Add theta at the end of a scan.
        """
        log.info('add theta')

        full_file_name = self.epics_pvs['FPFullFileName'].get(as_string=True)
        if os.path.exists(full_file_name):
            try:
                f = h5py.File(full_file_name, "a")
                with f:
                    try:
                        if self.theta is not None:
                            # theta_ds = f.create_dataset('/exchange/theta', (len(self.theta),))
                            # theta_ds[:] = self.theta[:]

                            unique_ids = f['/defaults/NDArrayUniqueId']
                            shift_start = int(self.num_dark_fields > 0 and (self.dark_field_mode in ('Start', 'Both')))+ \
                                          int(self.num_flat_fields > 0 and (self.flat_field_mode in ('Start', 'Both')))

                            # find beginnings of sorted subarrays
                            # for [1,2,1,3,1,2,3,4,1,2] returns 0,2,4,8
                            ids_list = [
                                0, *np.where(unique_ids[1:] -
                                             unique_ids[:-1] < 0)[0] + 1
                            ]
                            # extract projection ids
                            if (len(ids_list[shift_start:]) == 1):
                                proj_ids = unique_ids[ids_list[shift_start]:]
                            else:
                                proj_ids = unique_ids[ids_list[shift_start]:
                                                      ids_list[shift_start +
                                                               1]]
                            # subtract first id
                            proj_ids -= proj_ids[0]
                            # create theta dataset in hdf5 file
                            theta_ds = f.create_dataset(
                                '/exchange/theta', (len(proj_ids), ))
                            theta_ds[:] = self.theta[proj_ids]

                            if (len(proj_ids) != len(self.theta)):
                                log.warning('There are %d missing frames',
                                            len(self.theta) - len(proj_ids))
                                missed_ids = [
                                    ele for ele in range(len(self.theta))
                                    if ele not in proj_ids
                                ]
                                missed_theta = self.theta[missed_ids]
                                log.warning(f'Missed ids: {list(missed_ids)}')
                                log.warning(
                                    f'Missed theta: {list(missed_theta)}')

                    except:
                        log.error('Add theta: Failed accessing: %s',
                                  full_file_name)
                        traceback.print_exc(file=sys.stdout)
            except OSError:
                log.error('Add theta aborted: %s not closed', full_file_name)
        else:
            log.error('Failed adding theta. %s file does not exist',
                      full_file_name)
Beispiel #3
0
    def end_scan(self):
        """Performs the operations needed at the very end of a scan.

        This does the following:

        - Calls ``save_configuration()``.

        - Put the camera back in "FreeRun" mode and acquiring so the user sees live images.

        - Sets the speed of the rotation stage back to the maximum value.

        - Calls ``move_sample_in()``.

        - Calls the base class method.
        """
        log.info('end scan')
        # Save the configuration
        # Strip the extension from the FullFileName and add .config
        full_file_name = self.epics_pvs['FPFullFileName'].get(as_string=True)
        log.info('data save location: %s', full_file_name)
        config_file_root = os.path.splitext(full_file_name)[0]
        self.save_configuration(config_file_root + '.config')

        # Put the camera back in FreeRun mode and acquiring
        self.set_trigger_mode('FreeRun', 1)

        # Set the rotation speed to maximum
        self.epics_pvs['RotationSpeed'].put(self.max_rotation_speed)
        self.cleanup_PSO()

        # Move the sample in.  Could be out if scan was aborted while taking flat fields
        self.move_sample_in()

        # Call the base class method
        super().end_scan()
Beispiel #4
0
    def begin_scan(self):
        """Performs the operations needed at the very start of a scan.

        This does the following:

        - Calls the base class method.
        - Sets the speed of the rotation motor
        - Computes the delta theta, start and stop motor positions for the scan
        - Programs the Aerotech driver to provide pulses at the right positions
        """
        log.info('begin scan')
        # Call the base class method
        super().begin_scan()
 
        # Compute the time for each frame
        time_per_angle = self.compute_frame_time()
        self.motor_speed = self.rotation_step / time_per_angle
        time.sleep(0.1)

        # Program the stage driver to provide PSO pulses
        self.compute_positions_PSO()
        self.program_PSO()

        self.epics_pvs['FPNumCapture'].put(self.total_images, wait=True)
        self.epics_pvs['FPCapture'].put('Capture')
Beispiel #5
0
    def move_sample_out(self):
        """Moves the sample to the out of beam position for collecting flat fields.

        The out of beam position is defined by the ``SampleOutX`` and ``SampleOutY`` PVs.

        Which axis to move is defined by the ``FlatFieldAxis`` PV,
        which can be ``X``, ``Y``, or ``Both``.
        """

        if self.epics_pvs['SampleOutAngleEnable'].get():
            if self.max_rotation_speed != None:  # max_rotation_speed is not initialized when the scan has not been started
                cur_speed = self.epics_pvs['RotationSpeed'].get()
                self.epics_pvs['RotationSpeed'].put(self.max_rotation_speed)
            angle = self.epics_pvs['SampleOutAngle'].get()
            log.info('move_sample_out angle: %s', angle)
            self.rotation_save = self.epics_pvs['Rotation'].get()
            self.epics_pvs['Rotation'].put(angle, wait=True)
            if self.max_rotation_speed != None:
                self.epics_pvs['RotationSpeed'].put(cur_speed)

        axis = self.epics_pvs['FlatFieldAxis'].get(as_string=True)
        log.info('move_sample_out axis: %s', axis)
        if axis in ('X', 'Both'):
            position = self.epics_pvs['SampleOutX'].value
            self.epics_pvs['SampleX'].put(position, wait=True, timeout=600)

        if axis in ('Y', 'Both'):
            position = self.epics_pvs['SampleOutY'].value
            self.epics_pvs['SampleY'].put(position, wait=True, timeout=600)

        self.epics_pvs['MoveSampleOut'].put('Done')
Beispiel #6
0
    def retake_dark(self):
        """Recollect dark  fields while in the streaming mode

        - set capturing flag to 1
        - save file_name    
        - change file name to dark_fields.h5
        - set frame type to DarkField
        - disable circular buffer plugin
        - close shutter
        - collect dark fields
        - enable circular buffer plugin        
        - return file name to the initial one 
        - set the frame type to 'Projection'
        - set the retake dark button to Done
        - broadcast dark fields   
        - set capturing flag to 0
        """
        
        log.info('retake dark')
        self.epics_pvs['StreamMessage'].put('Capturing dark fields')        
        self.capturing = 1

        file_name = self.epics_pvs['FPFileName'].get(as_string=True)
        file_template = self.epics_pvs['FPFileTemplate'].get(as_string=True)
        autoincrement =  self.epics_pvs['FPAutoIncrement'].get(as_string=True)

        self.epics_pvs['FPFileName'].put('dark_fields.h5', wait=True)        
        self.epics_pvs['FPFileTemplate'].put('%s%s', wait=True)
        self.epics_pvs['FPAutoIncrement'].put('No', wait=True)                                
        
        # switch frame type before closing the shutter to let the reconstruction engine 
        # know that following frames should not be used for reconstruction 
        self.epics_pvs['FrameType'].put('DarkField', wait=True)      
        
        self.epics_pvs['CBEnableCallbacks'].put('Disable')  

        super().collect_dark_fields()        
        self.epics_pvs['FPNumCapture'].put(self.num_dark_fields, wait=True)        
        self.epics_pvs['FPCapture'].put('Capture', wait=True)   
        self.wait_pv(self.epics_pvs['FPCaptureRBV'], 0)                                        

        self.open_shutter()

        self.epics_pvs['CBEnableCallbacks'].put('Enable')  

        self.epics_pvs['FPFileName'].put(file_name, wait=True)                        
        self.epics_pvs['ScanStatus'].put('Collecting projections', wait=True)

        self.epics_pvs['HDF5Location'].put(self.epics_pvs['HDF5ProjectionLocation'].value)
        self.epics_pvs['FrameType'].put('Projection', wait=True)
        self.epics_pvs['StreamRetakeDark'].put('Done')   
        
        self.epics_pvs['FPFileName'].put(file_name, wait=True)
        self.epics_pvs['FPFileTemplate'].put(file_template, wait=True)        
        self.epics_pvs['FPAutoIncrement'].put(autoincrement, wait=True) 
        
        self.broadcast_dark()
        self.epics_pvs['StreamMessage'].put('Done')        
        
        self.capturing = 0
Beispiel #7
0
    def begin_scan(self):
        """Performs the operations needed at the very start of a scan.

        This does the following:

        - Set data directory.

        - Set the TomoScan xml files

        - Calls the base class method.
        
        - Opens the front-end shutter.
        """
        log.info('begin scan')

        # Set data directory
        file_path = self.epics_pvs['DetectorTopDir'].get(
            as_string=True) + self.epics_pvs['ExperimentYearMonth'].get(
                as_string=True
            ) + os.path.sep + self.epics_pvs['UserLastName'].get(
                as_string=True) + os.path.sep
        self.epics_pvs['FilePath'].put(file_path, wait=True)

        # set TomoScan xml files
        self.epics_pvs['CamNDAttributesFile'].put(
            'TomoScanDetectorAttributes.xml')
        self.epics_pvs['FPXMLFileName'].put('TomoScanLayout.xml')

        # Call the base class method
        super().begin_scan()
        # Opens the front-end shutter
        self.open_frontend_shutter()
    def begin_scan(self):
        """Performs the operations needed at the very start of a scan.

        This does the following:

        - Calls the base class method.
        - Sets the speed of the rotation motor
        - Computes the delta theta, start and stop motor positions for the scan
        - Programs the Aerotech driver to provide pulses at the right positions
        """
        log.info('begin scan')
        # Call the base class method
        super().begin_scan()

        # Compute the time for each frame
        time_per_angle = self.compute_frame_time(
        ) + 7.2 / 1000  # temporary fix for 2-BM-B
        self.motor_speed = self.rotation_step / time_per_angle
        time.sleep(0.1)

        # Program the stage driver to provide PSO pulses
        self.compute_positions_PSO()

        self.program_PSO()

        self.begin_stream()
Beispiel #9
0
    def set_trigger_mode_oryx(self, trigger_mode, num_images):
        self.epics_pvs['CamAcquire'].put('Done')  ###
        self.wait_pv(self.epics_pvs['CamAcquire'], 0)  ###
        log.info('set trigger mode: %s', trigger_mode)
        if trigger_mode == 'FreeRun':
            self.epics_pvs['CamImageMode'].put('Continuous', wait=True)
            self.epics_pvs['CamTriggerMode'].put('Off', wait=True)
            self.wait_pv(self.epics_pvs['CamTriggerMode'], 0)
            # self.epics_pvs['CamAcquire'].put('Acquire')
        elif trigger_mode == 'Internal':
            self.epics_pvs['CamTriggerMode'].put('Off', wait=True)
            self.wait_pv(self.epics_pvs['CamTriggerMode'], 0)
            self.epics_pvs['CamImageMode'].put('Multiple')
            self.epics_pvs['CamNumImages'].put(num_images, wait=True)
        else:  # set camera to external triggering
            # These are just in case the scan aborted with the camera in another state
            self.epics_pvs['CamTriggerMode'].put(
                'Off', wait=True
            )  # VN: For FLIR we first switch to Off and then change overlap. any reason of that?
            self.epics_pvs['CamTriggerSource'].put('Line2', wait=True)
            self.epics_pvs['CamTriggerOverlap'].put('ReadOut', wait=True)
            self.epics_pvs['CamExposureMode'].put('Timed', wait=True)
            self.epics_pvs['CamImageMode'].put(
                'Continuous')  # switched to Continuous for tomostream
            self.epics_pvs['CamArrayCallbacks'].put('Enable')
            self.epics_pvs['CamFrameRateEnable'].put(0)

            self.epics_pvs['CamNumImages'].put(num_images, wait=True)
            self.epics_pvs['CamTriggerMode'].put('On', wait=True)
            self.wait_pv(self.epics_pvs['CamTriggerMode'], 1)
Beispiel #10
0
    def end_scan(self):
        """Performs the operations needed at the very end of a scan.

        This does the following:
        - Calls ``save_configuration()``.
        - Put the camera back in "FreeRun" mode and acquiring so the user sees live images.

        - Sets the speed of the rotation stage back to the maximum value.

        - Calls ``move_sample_in()``.

        - Calls the base class method.

        - Closes shutter.
        """

        if self.return_rotation == 'Yes':
            # Reset rotation position by mod 360 , the actual return
            # to start position is handled by super().end_scan()
            log.info('wait until the stage is stopped')
            time.sleep(self.epics_pvs['RotationAccelTime'].get() * 1.2)
            ang = self.epics_pvs['RotationRBV'].get()
            current_angle = np.sign(ang) * (np.abs(ang) % 360)
            log.info('reset position to %f', current_angle)
            self.epics_pvs['RotationSet'].put('Set', wait=True)
            self.epics_pvs['Rotation'].put(current_angle, wait=True)
            self.epics_pvs['RotationSet'].put('Use', wait=True)

        # Call the base class method
        super().end_scan()
        # Close shutter
        self.close_shutter()
Beispiel #11
0
    def end_scan(self):
        """Performs the operations needed at the very end of a scan.

        This base class method does the following:

        - Sets the status string in the ``ScanStatus`` PV.

        - If the ``ReturnRotation`` PV is Yes then it moves the rotation motor back to the
          position defined by the ``RotationStart`` PV.  It does not wait for the move to complete.

        - Sets the ``StartScan`` PV to 0.  This PV is an EPICS ``busy`` record.
          Normally EPICS clients that start a scan with the ``StartScan`` PV will wait for
          ``StartScan`` to return to 0, often using the ``ca_put_callback()`` mechanism.

        It is expected that most derived classes will override this method.  In most cases they
        should first perform any beamline-specific operations and then call this base class method.
        This ensures that the scan is really complete before ``StartScan`` is set to 0.
        """

        if self.return_rotation == 'Yes':
            self.epics_pvs['Rotation'].put(self.rotation_start)
        log.info('Scan complete')
        self.epics_pvs['ScanStatus'].put('Scan complete')
        self.epics_pvs['StartScan'].put(0)
        self.scan_is_running = False
Beispiel #12
0
    def begin_scan(self):
        """Performs the operations needed at the very start of a scan.

        This does the following:

        - Set data directory.

        - Set the TomoScan xml files

        - Calls the base class method.
        
        - Opens the front-end shutter.

        - Sets the PSO controller.

        - Creates theta array using list from PSO. 

        - Turns on data capture.
        """
        log.info('begin scan')

        # Set data directory
        file_path = self.epics_pvs['DetectorTopDir'].get(
            as_string=True) + self.epics_pvs['ExperimentYearMonth'].get(
                as_string=True
            ) + os.path.sep + self.epics_pvs['UserLastName'].get(
                as_string=True) + os.path.sep
        self.epics_pvs['FilePath'].put(file_path, wait=True)

        # Call the base class method
        super().begin_scan()

        # Opens the front-end shutter
        self.open_frontend_shutter()
Beispiel #13
0
    def lens_change_sync(self):
        """Save/Update dark and flat fields for lenses"""

        # ref to pixel size
        # self.epics_pvs['MCTPixelSize'] = PV(prefix+'PixelSize')
        #
        # self.epics_pvs['PixelSize'].put(self.epics_pvs['MCTPixelSize'])

        log.info(f'switch lens from {self.lens_cur}')
        dirname = os.path.dirname(
            self.epics_pvs['FPFullFileName'].get(as_string=True))
        cmd = 'cp ' + dirname + '/dark_fields.h5 ' + dirname + '/dark_fields_' + str(
            self.lens_cur) + '.h5 2> /dev/null '
        os.system(cmd)
        cmd = 'cp ' + dirname + '/flat_fields.h5 ' + dirname + '/flat_fields_' + str(
            self.lens_cur) + '.h5 2> /dev/null '
        os.system(cmd)
        self.lens_cur = self.epics_pvs['LensSelect'].get()
        log.info(f'to {self.lens_cur}')
        cmd = 'cp ' + dirname + '/dark_fields_' + str(
            self.lens_cur) + '.h5 ' + dirname + '/dark_fields.h5 2> /dev/null '
        os.system(cmd)
        cmd = 'cp ' + dirname + '/flat_fields_' + str(
            self.lens_cur) + '.h5 ' + dirname + '/flat_fields.h5 2> /dev/null '
        os.system(cmd)
        self.broadcast_dark()
        self.broadcast_flat()
Beispiel #14
0
    def set_trigger_mode_grasshopper(self, trigger_mode, num_images):
        self.epics_pvs['CamAcquire'].put('Done')  ###
        self.wait_pv(self.epics_pvs['CamAcquire'], 0)  ###
        log.info('set trigger mode: %s', trigger_mode)
        if trigger_mode == 'FreeRun':
            self.epics_pvs['CamImageMode'].put('Continuous', wait=True)
            self.epics_pvs['CamTriggerMode'].put('Off', wait=True)
            self.wait_pv(self.epics_pvs['CamTriggerMode'], 0)
            #self.epics_pvs['CamAcquire'].put('Acquire')
        elif trigger_mode == 'Internal':
            self.epics_pvs['CamTriggerMode'].put('Off', wait=True)
            self.wait_pv(self.epics_pvs['CamTriggerMode'], 0)
            self.epics_pvs['CamImageMode'].put('Multiple')
            self.epics_pvs['CamNumImages'].put(num_images, wait=True)
        else:  # set camera to external triggering
            # These are just in case the scan aborted with the camera in another state
            self.epics_pvs['CamTriggerMode'].put(
                'On', wait=True
            )  # VN: For PG we need to switch to On to be able to switch to readout overlap mode
            self.epics_pvs['CamTriggerSource'].put('Line0', wait=True)
            self.epics_pvs['CamTriggerOverlap'].put('ReadOut', wait=True)
            self.epics_pvs['CamExposureMode'].put('Timed', wait=True)
            self.epics_pvs['CamImageMode'].put('Multiple')
            self.epics_pvs['CamArrayCallbacks'].put('Enable')
            self.epics_pvs['CamFrameRateEnable'].put(0)

            self.epics_pvs['CamNumImages'].put(self.num_angles, wait=True)
            self.epics_pvs['CamTriggerMode'].put('On', wait=True)
            self.wait_pv(self.epics_pvs['CamTriggerMode'], 1)
    def end_scan(self):
        """Performs the operations needed at the very end of a scan.

        This does the following:
        - Calls ``save_configuration()``.
        - Put the camera back in "FreeRun" mode and acquiring so the user sees live images.

        - Sets the speed of the rotation stage back to the maximum value.

        - Calls ``move_sample_in()``.

        - Calls the base class method.

        - Closes shutter.
        """

        log.info('end scan')

        # Close the shutter
        self.close_shutter()

        # Stop the file plugin, though it should be done already
        self.epics_pvs['FPCapture'].put('Done')
        self.wait_pv(self.epics_pvs['FPCaptureRBV'], 0)

        # Add theta in the hdf file
        #self.add_theta()

        # Call the base class method
        super().end_scan()
Beispiel #16
0
    def update_status(self, start_time):
        """
        When called updates ``ImagesCollected``, ``ImagesSaved``, ``ElapsedTime``, and ``RemainingTime``. 

        Parameters
        ----------
        start_time : time

            Start time to calculate elapsed time.

        Returns
        -------
        elapsed_time : float

            Elapsed time to be used for time out.
        """
        num_collected  = self.epics_pvs['CamNumImagesCounter'].value
        num_images     = self.epics_pvs['CamNumImages'].value
        num_saved      = self.epics_pvs['FPNumCaptured'].value
        num_to_save     = self.epics_pvs['FPNumCapture'].value
        current_time = time.time()
        elapsed_time = current_time - start_time
        remaining_time = (elapsed_time * (num_images - num_collected) /
                          max(float(num_collected), 1))
        collect_progress = str(num_collected) + '/' + str(num_images)
        log.info('Collected %s', collect_progress)
        self.epics_pvs['ImagesCollected'].put(collect_progress)
        save_progress = str(num_saved) + '/' + str(num_to_save)
        log.info('Saved %s', save_progress)
        self.epics_pvs['ImagesSaved'].put(save_progress)
        self.epics_pvs['ElapsedTime'].put(str(timedelta(seconds=int(elapsed_time))))
        self.epics_pvs['RemainingTime'].put(str(timedelta(seconds=int(remaining_time))))

        return elapsed_time
 def add_theta(self):
     """Add theta at the end of a scan.
     """
     log.info('add theta')
     self.theta = np.linspace(self.rotation_start, self.rotation_stop,
                              self.num_angles)
     full_file_name = self.epics_pvs['FPFullFileName'].get(as_string=True)
     file_name_path = Path(full_file_name)
     if os.path.exists(full_file_name):
         try:
             f = h5py.File(full_file_name, "a")
             with f:
                 try:
                     if self.theta is not None:
                         theta_ds = f.create_dataset('/exchange/theta',
                                                     data=self.theta)
                 except:
                     log.error('Add theta: Failed accessing: %s',
                               full_file_name)
                     traceback.print_exc(file=sys.stdout)
         except OSError:
             log.error('Add theta aborted')
     else:
         log.error('Failed adding theta. %s file does not exist',
                   full_file_name)
Beispiel #18
0
    def add_theta(self):
        """Add theta at the end of a scan.
        Taken from tomoscan_2BM.py function.  This gives the correct theta for scans with missing frames
        """
        log.info('add theta')

        if self.theta is None:
            log.warning('no theta to add')
            return

        full_file_name = self.epics_pvs['FPFullFileName'].get(as_string=True)
        if os.path.exists(full_file_name):
            try:
                with h5py.File(full_file_name, "a") as f:
                    unique_ids = f['/defaults/NDArrayUniqueId']
                    hdf_location = f['/defaults/HDF5FrameLocation']
                    total_dark_fields = self.num_dark_fields * (
                        (self.dark_field_mode in ('Start', 'Both')) +
                        (self.dark_field_mode in ('End', 'Both')))
                    total_flat_fields = self.num_flat_fields * (
                        (self.flat_field_mode in ('Start', 'Both')) +
                        (self.flat_field_mode in ('End', 'Both')))

                    proj_ids = unique_ids[hdf_location[:] == b'/exchange/data']
                    flat_ids = unique_ids[hdf_location[:] ==
                                          b'/exchange/data_white']
                    dark_ids = unique_ids[hdf_location[:] ==
                                          b'/exchange/data_dark']

                    # create theta dataset in hdf5 file
                    if len(proj_ids) > 0:
                        theta_ds = f.create_dataset('/exchange/theta',
                                                    (len(proj_ids), ))
                        theta_ds[:] = self.theta[proj_ids - proj_ids[0]]

                    # warnings that data is missing
                    if len(proj_ids) != len(self.theta):
                        log.warning(
                            f'There are {len(self.theta) - len(proj_ids)} missing data frames'
                        )
                        missed_ids = [
                            ele for ele in range(len(self.theta))
                            if ele not in proj_ids - proj_ids[0]
                        ]
                        missed_theta = self.theta[missed_ids]
                        log.warning(f'Missed theta: {list(missed_theta)}')
                    if len(flat_ids) != total_flat_fields:
                        log.warning(
                            f'There are {total_flat_fields - len(flat_ids)} missing flat field frames'
                        )
                    if (len(dark_ids) != total_dark_fields):
                        log.warning(
                            f'There are {total_dark_fields - len(dark_ids)} missing dark field frames'
                        )
            except:
                log.error('Add theta: Failed accessing: %s', full_file_name)
                traceback.print_exc(file=sys.stdout)
        else:
            log.error('Failed adding theta. %s file does not exist',
                      full_file_name)
Beispiel #19
0
 def collect_flat_fields(self):
     """Collects flat field images.
     Calls ``collect_static_frames()`` with the number of images specified
     by the ``NumFlatFields`` PV.
     """
     log.info('collect flat fields')
     super().collect_flat_fields()
Beispiel #20
0
    def begin_scan(self):
        """Performs the operations needed at the very start of a scan.

        This does the following:

        - Calls the base class method.

        - Opens the front-end shutter.
        
        - Sets the PSO controller.

        - Creates theta array using list from PSO. 

        """
        log.info('begin scan')
        # Call the base class method
        super().begin_scan()
        # Opens the front-end shutter
        self.open_frontend_shutter()
         
        # Confirm angle step is an integer number of encoder pulses
        # Pass the user selected values to the PSO
        self.epics_pvs['PSOstartPos'].put(self.rotation_start, wait=True)
        self.wait_pv(self.epics_pvs['PSOstartPos'], self.rotation_start)
        self.epics_pvs['PSOendPos'].put(self.rotation_stop, wait=True)
        self.wait_pv(self.epics_pvs['PSOendPos'], self.rotation_stop)
        # Compute and set the motor speed
        time_per_angle = self.compute_frame_time()+7.2/1000
        motor_speed = self.rotation_step / time_per_angle
        self.epics_pvs['PSOslewSpeed'].put(motor_speed)
        self.wait_pv(self.epics_pvs['PSOslewSpeed'], motor_speed)

        self.epics_pvs['PSOscanDelta'].put(self.rotation_step, wait=True)
        self.wait_pv(self.epics_pvs['PSOscanDelta'], self.rotation_step)

        # Get the number of projections and angle steps calculated by the PSO
        calc_rotation_step = self.epics_pvs['PSOscanDelta'].value
        calc_num_proj = int(self.epics_pvs['PSOcalcProjections'].value)
        # If this is different from the user selected values adjust them
        if calc_rotation_step != self.rotation_step:
            # This should happen most of the time since rotation_step is rounded down to the closest integer
            # number of encoder pulses
            log.warning('PSO changed rotation step from %s to %s', self.rotation_step, calc_rotation_step)
            self.rotation_step = calc_rotation_step
        if calc_num_proj != self.num_angles:
            # This happens rarely an it is a +/-1 change in the number of projections to make sure that
            # after the rotation_step round down we don't pass the user set rotation_stop
            log.warning('PSO changed number of projections from %s to %s', self.num_angles, calc_num_proj)
            self.num_angles = calc_num_proj

        self.epics_pvs['PSOscanControl'].put('Standard')
        self.wait_pv(self.epics_pvs['PSOscanControl'], 0)
        time.sleep(1)

        # Create theta array
        self.theta = []
        self.theta = self.epics_pvs['ThetaArray'].get(count=int(self.num_angles))       

        self.begin_stream()     
Beispiel #21
0
    def collect_dark_fields(self):
        """Collects dark field images.
        Calls ``collect_static_frames()`` with the number of images specified
        by the ``NumDarkFields`` PV.
        """

        log.info('collect dark fields')
        super().collect_dark_fields()
Beispiel #22
0
    def end_scan(self):
        """Performs the operations needed at the very end of a scan.

        This does the following:

        - Calls ``save_configuration()``.

        - Put the camera back in "FreeRun" mode and acquiring so the user sees live images.

        - Sets the speed of the rotation stage back to the maximum value.

        - Calls ``move_sample_in()``.

        - Calls the base class method.

        - Closes shutter.  

        - Add theta to the raw data file. 

        - Copy raw data to data analysis computer.      
        """

        if self.return_rotation == 'Yes':
            # Reset rotation position by mod 360 , the actual return
            # to start position is handled by super().end_scan()
            log.info('wait until the stage is stopped')
            time.sleep(self.epics_pvs['RotationAccelTime'].get() * 1.2)
            ang = self.epics_pvs['RotationRBV'].get()
            current_angle = np.sign(ang) * (np.abs(ang) % 360)
            self.epics_pvs['RotationSet'].put('Set', wait=True)
            self.epics_pvs['Rotation'].put(current_angle, wait=True)
            self.epics_pvs['RotationSet'].put('Use', wait=True)
        # Call the base class method
        super().end_scan()
        # Close shutter
        self.close_shutter()

        # Stop the file plugin
        self.epics_pvs['FPCapture'].put('Done')
        self.wait_pv(self.epics_pvs['FPCaptureRBV'], 0)
        # Add theta in the hdf file
        self.add_theta()

        # Copy raw data to data analysis computer
        if self.epics_pvs['CopyToAnalysisDir'].get():
            log.info(
                'Automatic data trasfer to data analysis computer is enabled.')
            full_file_name = self.epics_pvs['FPFullFileName'].get(
                as_string=True)
            remote_analysis_dir = self.epics_pvs['RemoteAnalysisDir'].get(
                as_string=True)
            dm.scp(full_file_name, remote_analysis_dir)
        else:
            log.warning(
                'Automatic data trasfer to data analysis computer is disabled.'
            )
Beispiel #23
0
 def cleanup_PSO(self):
     '''Cleanup activities after a PSO scan. 
     Turns off PSO and sets the speed back to default.
     '''
     log.info('Cleaning up PSO programming and setting to retrace speed.')
     asynRec = self.epics_pvs['PSOAsyn']
     pso_axis = self.epics_pvs['PSOAxisName'].get(as_string=True)
     pso_input = self.epics_pvs['PSOEncoderInput'].get(as_string=True)
     asynRec.put('PSOWINDOW %s OFF' % pso_axis, wait=True)
     asynRec.put('PSOCONTROL %s OFF' % pso_axis, wait=True)
Beispiel #24
0
    def close_shutter(self):
        """Closes the shutter to collect dark fields.

        The value in the ``CloseShutterValue`` PV is written to the ``CloseShutter`` PV.
        """
        if not self.epics_pvs['CloseShutter'] is None:
            pv = self.epics_pvs['CloseShutter']
            value = self.epics_pvs['CloseShutterValue'].get(as_string=True)
            log.info('close shutter: %s, value: %s', pv, value)
            self.epics_pvs['CloseShutter'].put(value, wait=True)
Beispiel #25
0
def create_remote_directory(remote_server, remote_dir):
    cmd = 'mkdir -p ' + remote_dir
    try:
        log.info('      *** creating remote directory %s' % (remote_dir))
        subprocess.check_call(['ssh', '-t', remote_server, cmd])
        log.info('      *** creating remote directory %s: Done!' % (remote_dir))
        return 0

    except subprocess.CalledProcessError as e:
        log.error('  *** Error while creating remote directory. Error code: %d' % (e.returncode))
        return -1
Beispiel #26
0
 def abort_scan(self):
     """Performs operations needed if a scan is aborted.
     
     Mostly handled by super class.
     Logic here to stop the Y motor.
     """
     super().abort_scan()
     log.info('helical: abort scan')
     if self.epics_pvs['ScanType'].get(as_string=True) == 'Helical':
         log.info('helical: stop vertical motion')
         self.epics_pvs['SampleYStop'].put(1)
Beispiel #27
0
    def open_shutter(self):
        """Opens the shutter to collect flat fields or projections.

        The value in the ``OpenShutterValue`` PV is written to the ``OpenShutter`` PV.
        """

        if not self.epics_pvs['OpenShutter'] is None:
            pv = self.epics_pvs['OpenShutter']
            value = self.epics_pvs['OpenShutterValue'].get(as_string=True)
            log.info('open shutter: %s, value: %s', pv, value)
            self.epics_pvs['OpenShutter'].put(value, wait=True)
Beispiel #28
0
 def fly_scan(self):
     """Overrides fly_scan in super class to catch a bad file path.
     """
     if self.epics_pvs['FilePathExists'].get() == 1:
         log.info('file path for file writer exists')
         super(TomoScanHelical, self).fly_scan()
     else:
         log.info('file path for file writer not found')
         self.epics_pvs['ScanStatus'].put('Abort: Bad File Path')
         self.epics_pvs['StartScan'].put(0)
         self.scan_is_running = False
Beispiel #29
0
 def auto_copy_data(self):
     '''Copies data from detector computer to analysis computer.
     '''
     # Copy raw data to data analysis computer    
     if self.epics_pvs['CopyToAnalysisDir'].get():
         log.info('Automatic data trasfer to data analysis computer is enabled.')
         full_file_name = self.epics_pvs['FPFullFileName'].get(as_string=True)
         remote_analysis_dir = self.epics_pvs['RemoteAnalysisDir'].get(as_string=True)
         dm.scp(full_file_name, remote_analysis_dir)
     else:
         log.warning('Automatic data trasfer to data analysis computer is disabled.')
Beispiel #30
0
    def abort_scan(self):
        """Performs the operations needed when a scan is aborted.

        This does the following:

        - Calls the base class method.
        """

        log.info('Stream abort')
        
        # Call the base class method        
        super().abort_scan()