def fly(global_PVs, params): angular_range = params.sample_rotation_end - params.sample_rotation_start flyscan_time_estimate = angular_range / params.slew_speed log.warning(' *** Fly Scan Time Estimate: %4.2f minutes' % (flyscan_time_estimate/60.)) #Trigger fly motion to start. Don't wait for it, since it takes time. start_time = time.time() driver.motor.move(motor_end, wait=False) time.sleep(1) old_image_counter = 0 expected_framerate = driver.motor.slew_speed / delta_egu #Monitor the motion to make sure we aren't stuck. i = 0 while time.time() - start_time < 1.5 * flyscan_time_estimate: i += 1 if i % 10 == 0: log.info(' *** *** Sample rotation at angle {:f}'.format(driver.motor.readback)) time.sleep(1) if not driver.motor.moving: log.info(' *** *** Sample rotation stopped moving.') if abs(driver.motor.drive - motor_end) > 1e-2: log.error(' *** *** Sample rotation ended but not at right position!') raise ValueError else: log.info(' *** *** Stopped at correct position.') break #Make sure we're actually getting frames. current_image_counter = global_PVs['Cam1_NumImagesCounter'].get() if current_image_counter - old_image_counter < 0.2 * expected_framerate: log.error(' *** *** Not collecting frames!') raise ValueError else: old_image_counter = current_image_counter else: log.warning(' *** *** Fly motion timed out!') raise ValueError
def take_image(global_PVs, params): log.info(' *** taking a single image') nRow = global_PVs['Cam1_SizeY_RBV'].get() nCol = global_PVs['Cam1_SizeX_RBV'].get() image_size = nRow * nCol global_PVs['Cam1_ImageMode'].put('Single', wait=True) global_PVs['Cam1_NumImages'].put(1, wait=True) global_PVs['Cam1_TriggerMode'].put('Internal', wait=True) wait_time_sec = int(params.exposure_time) + 5 global_PVs['Cam1_Acquire'].put(DetectorAcquire, wait=True, timeout=1000.0) time.sleep(0.1) if aps7bm.wait_pv(global_PVs['Cam1_Acquire'], DetectorIdle, wait_time_sec) == False: # adjust wait time global_PVs['Cam1_Acquire'].put(DetectorIdle) log.warning( 'The camera failed to finish acquisition. Set to done manually.') # Get the image loaded in memory img_vect = global_PVs['Cam1_Image'].get(count=image_size) if global_PVs['Cam1_Image_Dtype'].get(as_string=True) == 'UInt16': img_vect = img_vect.astype(np.uint16) img = np.reshape(img_vect, [nRow, nCol]) return img
def set(global_PVs, params): '''Sets up detector and arms it for PSO pulses. ''' fname = params.file_name # Set detectors if params.camera_ioc_prefix in params.valid_camera_prefixes: log.info(' ') log.info(' *** setup Point Grey') # Make sure that we aren't acquiring now global_PVs['Cam1_Acquire'].put(DetectorIdle) aps7bm.wait_pv(global_PVs['Cam1_Acquire'], DetectorIdle) #Set up the XML files to determine HDF file layout attrib_file = Path.joinpath( Path(__file__).parent, 'mctDetectorAttributes1.xml') global_PVs['Cam1_AttributeFile'].put(str(attrib_file), wait=True) layout_file = Path.joinpath(Path(__file__).parent, 'mct3.xml') global_PVs['HDF1_XMLFileName'].put(str(layout_file), wait=True) global_PVs['Cam1_ArrayCallbacks'].put('Enable', wait=True) global_PVs['Cam1_AcquirePeriod'].put(float(params.exposure_time), wait=True) global_PVs['Cam1_AcquireTime'].put(float(params.exposure_time), wait=True) log.info(' *** setup Point Grey: Done!') else: log.error('Detector %s is not defined' % params.camera_ioc_prefix) return if params.file_name is None: log.warning(' *** hdf_writer will not be configured') else: _setup_hdf_writer(global_PVs, params, fname)
def acquire(global_PVs, params): # Make sure that we aren't acquiring now global_PVs['Cam1_Acquire'].put(DetectorIdle) aps7bm.wait_pv(global_PVs['Cam1_Acquire'], DetectorIdle) global_PVs['Cam1_FrameType'].put(FrameTypeData, wait=True) global_PVs['Cam1_ImageMode'].put('Multiple', wait=True) num_images = int(params.num_projections) * params.recursive_filter_n_images global_PVs['Cam1_NumImages'].put(num_images, wait=True) # Set trigger mode global_PVs['Cam1_TriggerMode'].put('Overlapped', wait=True) # start acquiring global_PVs['Cam1_Acquire'].put(DetectorAcquire) aps7bm.wait_pv(global_PVs['Cam1_Acquire'], DetectorAcquire) log.info(' ') log.info(' *** Fly Scan: Start!') pso.fly(global_PVs, params) # if the fly scan wait times out we should call done on the detector if aps7bm.wait_pv(global_PVs['Cam1_Acquire'], DetectorIdle, 5) == False: log.warning(' *** *** Camera did not finish acquisition') global_PVs['Cam1_Acquire'].put(DetectorIdle) log.info(' *** Fly Scan: Done!') # Set trigger mode to internal for post dark and white global_PVs['Cam1_TriggerMode'].put('Internal') return pso.proj_positions
def log_info(): log.warning(' *** *** Positions for fly scan.') log.info(' *** *** *** Motor start = {0:f}'.format(req_start)) log.info(' *** *** *** Motor end = {0:f}'.format(actual_end)) log.info(' *** *** *** # Points = {0:4d}'.format(num_proj)) log.info(' *** *** *** Degrees per image = {0:f}'.format(delta_egu)) log.info(' *** *** *** Degrees per projection = {0:f}'.format(delta_egu / num_images_per_proj)) log.info(' *** *** *** Encoder counts per image = {0:d}'.format(delta_encoder_counts))
def close_shutters(global_PVs, params): log.info(' ') log.info(' *** close_shutters') if TESTING: log.warning( ' *** testing mode - shutters are deactivated during the scans !!!!' ) else: global_PVs['ShutterA_Close'].put(1, wait=True) wait_pv(global_PVs['ShutterA_Move_Status'], ShutterA_Close_Value) log.info(' *** close_shutter A: Done!')
def fly_scan(params): '''Perform potentially repeated fly scan. ''' tic = time.time() global_PVs = aps7bm.init_general_PVs(params) try: if not check_camera_IOC(global_PVs, params): return False # Set the slew speed, possibly based on blur and acquisition parameters set_slew_speed(global_PVs, params) # init camera flir.init(global_PVs, params) log.info(' ') log.info(" *** Running %d sleep scans" % params.sleep_steps) for i in np.arange(params.sleep_steps): tic_01 = time.time() # set sample file name params.file_path = global_PVs['HDF1_FilePath'].get(as_string=True) params.file_name = str('{:03}'.format( global_PVs['HDF1_FileNumber'].get( ))) + '_' + global_PVs['Sample_Name'].get(as_string=True) log.info(' ') log.info(' *** Start scan {:d} of {:d}'.format( int(i + 1), int(params.sleep_steps))) tomo_fly_scan(global_PVs, params) if ((i + 1) != params.sleep_steps): log.warning(' *** Wait (s): %s ' % str(params.sleep_time)) time.sleep(params.sleep_time) log.info(' ') log.info(' *** Data file: %s' % global_PVs['HDF1_FullFileName_RBV'].get(as_string=True)) log.info(' *** Total scan time: %s minutes' % str( (time.time() - tic_01) / 60.)) log.info(' *** Scan Done!') #dm.scp(global_PVs, params) log.info(' *** Total loop scan time: %s minutes' % str( (time.time() - tic) / 60.)) global_PVs['Cam1_ImageMode'].put('Continuous') log.info(' *** Done!') except KeyError: log.error(' *** Some PV assignment failed!') except Exception as ee: stop_scan(global_PVs, params) log.info(' Exception recorded: ' + str(ee))
def update_config(args): # update tomo2bm.conf sections = SCAN_PARAMS write(args.config, args=args, sections=sections) # copy tomo2bm.conf to the raw data directory with a unique name (sample_name.conf) log.info(args.file_path) log.info(args.file_name) log_fname = str(Path.joinpath(Path(args.file_path), args.file_name + '.conf')) try: shutil.copyfile(args.config, log_fname) log.info(' *** copied %s to %s ' % (args.config, log_fname)) except: log.error(' *** attempt to copy %s to %s failed' % (args.config, log_fname)) pass log.warning(' *** command to repeat the scan: tomo scan --config {:s}'.format(log_fname))
def log_values(args): """Log all values set in the args namespace. Arguments are grouped according to their section and logged alphabetically using the DEBUG log level thus --verbose is required. """ args = args.__dict__ log.warning('tomo scan status start') for section, name in zip(SECTIONS, NICE_NAMES): entries = sorted((k for k in args.keys() if k.replace('_', '-') in SECTIONS[section])) # print('log_values', section, name, entries) if entries: log.info(name) for entry in entries: value = args[entry] if args[entry] is not None else "-" log.info(" {:<16} {}".format(entry, value)) log.warning('tomo scan status end')
def compute_positions(): '''Computes several parameters describing the fly scan motion. These calculations are for tomography scans, where for N images we need N pulses. Moreover, we base these on the number of images, not the delta between. ''' global actual_end, delta_egu, delta_encoder_counts, motor_start, motor_end, PSO_positions global proj_positions _compute_senses() #Get the distance needed for acceleration = 1/2 a t^2 = 1/2 * v * t motor_accl_time = driver.motor.acceleration #Acceleration time in s accel_dist = motor_accl_time * speed / 2.0 #Compute the actual delta to keep things at an integral number of encoder counts raw_delta_encoder_counts = (abs(req_end - req_start) / ((num_proj - 1) * num_images_per_proj) * driver.encoder_multiply) delta_encoder_counts = round(raw_delta_encoder_counts) if abs(raw_delta_encoder_counts - delta_encoder_counts) > 1e-4: log.warning(' *** *** *** Requested scan would have used a non-integer number of encoder pulses.') log.warning(' *** *** *** Calculated # of encoder pulses per step = {0:9.4f}'.format(raw_delta_encoder_counts)) log.warning(' *** *** *** Instead, using {0:d}'.format(delta_encoder_counts)) delta_egu = delta_encoder_counts / driver.encoder_multiply #Make taxi distance an integral number of measurement deltas >= accel distance #Add 1/2 of a delta to ensure that we are really up to speed. taxi_dist = (math.ceil(accel_dist / delta_egu) + 0.5) * delta_egu motor_start = req_start - taxi_dist * user_direction motor_end = req_end + taxi_dist * user_direction #Where will the last point actually be? actual_end = req_start + (num_proj * num_images_per_proj- 1) * delta_egu * user_direction end_proj = req_start + (num_proj - 1) * delta_egu * user_direction * num_images_per_proj PSO_positions = np.linspace(req_start, actual_end, num_proj * num_images_per_proj) proj_positions = np.linspace(req_start, end_proj, num_proj) log_info()
def fly_scan_vertical(params): tic = time.time() # aps7bm.update_variable_dict(params) global_PVsx = aps7bm.init_general_PVs(global_PVs, params) try: detector_sn = global_PVs['Cam1_SerialNumber'].get() if ((detector_sn == None) or (detector_sn == 'Unknown')): log.info( '*** The Point Grey Camera with EPICS IOC prefix %s is down' % params.camera_ioc_prefix) log.info(' *** Failed!') else: log.info('*** The Point Grey Camera with EPICS IOC prefix %s and serial number %s is on' \ % (params.camera_ioc_prefix, detector_sn)) # calling global_PVs['Cam1_AcquireTime'] to replace the default 'ExposureTime' with the one set in the camera params.exposure_time = global_PVs['Cam1_AcquireTime'].get() # calling calc_blur_pixel() to replace the default 'SlewSpeed' blur_pixel, rot_speed, scan_time = calc_blur_pixel( global_PVs, params) params.slew_speed = rot_speed start_y = params.vertical_scan_start end_y = params.vertical_scan_end step_size_y = params.vertical_scan_step_size # init camera flir.init(global_PVs, params) log.info(' ') log.info(" *** Running %d scans" % params.sleep_steps) log.info(' ') log.info(' *** Vertical Positions (mm): %s' % np.arange(start_y, end_y, step_size_y)) for ii in np.arange(0, params.sleep_steps, 1): log.info(' ') log.info(' *** Start scan %d' % ii) for i in np.arange(start_y, end_y, step_size_y): tic_01 = time.time() # set sample file name params.file_path = global_PVs['HDF1_FilePath'].get( as_string=True) params.file_name = str( '{:03}'.format(global_PVs['HDF1_FileNumber'].get()) ) + '_' + global_PVs['Sample_Name'].get(as_string=True) log.info(' ') log.info(' *** The sample vertical position is at %s mm' % (i)) global_PVs['Motor_SampleY'].put(i, wait=True, timeout=1000.0) tomo_fly_scan(global_PVs, params) log.info(' ') log.info(' *** Data file: %s' % global_PVs['HDF1_FullFileName_RBV'].get( as_string=True)) log.info(' *** Total scan time: %s minutes' % str( (time.time() - tic_01) / 60.)) log.info(' *** Scan Done!') dm.scp(global_PVs, params) log.info(' *** Moving vertical stage to start position') global_PVs['Motor_SampleY'].put(start_y, wait=True, timeout=1000.0) if ((ii + 1) != params.sleep_steps): log.warning(' *** Wait (s): %s ' % str(params.sleep_time)) time.sleep(params.sleep_time) log.info(' *** Total loop scan time: %s minutes' % str( (time.time() - tic) / 60.)) log.info(' *** Moving rotary stage to start position') global_PVs["Motor_SampleRot"].put(0, wait=True, timeout=600.0) log.info(' *** Moving rotary stage to start position: Done!') global_PVs['Cam1_ImageMode'].put('Continuous') log.info(' *** Done!') except KeyError: log.error(' *** Some PV assignment failed!') pass
def set_slew_speed(global_PVs, params): '''Determines the slew speed of the rotation stage. Make sure that we aren't moving so fast that the camera can't keep up. Based on user input, choices are: * Use value from config file. Show how much blur this is and if camera can keep up. * Base on acquisition parameters (data throughput and exposure). Show how much blur this is. * Base on both blur and data throughput. ''' log.info(' *** Calculate slew speed and blur') scan_range = abs(params.sample_rotation_start - params.sample_rotation_end) set_image_factor(global_PVs, params) delta_angle = scan_range / (params.num_projections - 1) / params.recursive_filter_n_images data_max_framerate = flir.calc_max_framerate(global_PVs, params) acq_max_framerate = 1.0 / (params.exposure_time + params.ccd_readout) #Compute the distance from the rotation axis to the farthest edge of the image #Assume SampleX motor is at zero when rotation axis is centered overall_res = float(global_PVs['PixelSizeMicrons'].get()) / float( global_PVs['Lens_Magnification'].get()) rot_axis_offset = abs(global_PVs['Motor_SampleX'].drive * 1e3 / overall_res) log.info( ' *** *** rotation axis offset {0:f} pixels'.format(rot_axis_offset)) im_half_width = global_PVs['Cam1_SizeX'].get() / 2.0 + rot_axis_offset blur_max_framerate = 1e6 if params.auto_slew_speed == 'manual': log.info(' *** *** Using manual slew speed') req_framerate = params.slew_speed / delta_angle log.info( ' *** *** Requested framerate is {:6.3} Hz'.format(req_framerate)) if acq_max_framerate < req_framerate: log.warning( ' *** *** Requested framerate too fast for exposure time given.' ) log.warning(' *** *** You will miss frames!') if data_max_framerate < req_framerate: log.warning( ' *** *** Requested framerate too fast for data transfer.') log.warning(' *** *** You will miss frames!') return finish_set_slew_speed(global_PVs, params) elif params.auto_slew_speed == 'acqusition': log.info( ' *** *** Calc slew speed from data throughput and exposure limits.' ) elif params.recursive_filter_n_images > 1: log.warning( ' *** *** Blur calculation makes less sense with averaging in each projection.' ) else: log.info( ' *** *** Calc slew speed based on blur and acquisition parameters.' ) max_blur_angle = np.degrees( np.arcsin(params.permitted_blur / im_half_width)) blur_max_framerate = max_blur_angle / ( params.exposure_time) / delta_angle framerates = np.array( [data_max_framerate, acq_max_framerate, blur_max_framerate]) params.slew_speed = np.min(framerates) * delta_angle log.info(' *** *** Max framerate for data transfer is {:6.3f} Hz'.format( data_max_framerate)) log.info(' *** *** Max framerate for exposure time is {:6.3f} Hz'.format( acq_max_framerate)) if blur_max_framerate == np.min(framerates): log.info(' *** *** Limited by blur to {:6.3f} Hz'.format( blur_max_framerate)) elif data_max_framerate == np.min(framerates): log.info(' *** *** Limited by data throughput to {:6.3f} Hz'.format( data_max_framerate)) else: log.info(' *** *** Limited by acquisition time to {:6.3f} Hz'.format( acq_max_framerate)) blur = np.sin(np.radians( params.slew_speed * params.exposure_time)) * im_half_width if params.recursive_filter_n_images > 1: blur = np.sin(np.radians(delta_angle)) * im_half_width if blur > params.permitted_blur: log.warning( ' *** *** Motion blur on image edge = {:6.2f} px'.format(blur)) else: log.info( ' *** *** Motion blur on image edge = {:6.2f} px'.format(blur)) log.info(' *** *** Slew speed set to {:6.3f} deg/s'.format( params.slew_speed)) global_PVs['Sample_Rotation_Speed'].put(params.slew_speed, wait=True) return params.slew_speed