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()
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)
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()
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')
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')
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
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()
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)
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()
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
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()
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()
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()
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)
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)
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()
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()
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()
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.' )
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)
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)
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
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)
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)
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
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.')
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()