def take_image(global_PVs, params): log.info(' *** *** taking a single image') nRow = global_PVs['Cam1SizeY_RBV'].get() nCol = global_PVs['Cam1SizeX_RBV'].get() image_size = nRow * nCol global_PVs['Cam1NumImages'].put(1, wait=True) global_PVs['Cam1TriggerMode'].put('Off', wait=True) wait_time_sec = int(params.exposure_time) + 5 global_PVs['Cam1Acquire'].put(DetectorAcquire, wait=True, timeout=1000.0) time.sleep(0.1) if pv.wait_pv(global_PVs['Cam1Acquire'], DetectorIdle, wait_time_sec) == False: # adjust wait time global_PVs['Cam1Acquire'].put(DetectorIdle) # Get the image loaded in memory img_vect = global_PVs['Image'].get(count=image_size) img = np.reshape(img_vect, [nRow, nCol]) pixelFormat = global_PVs['Cam1PixelFormat_RBV'].get(as_string=True) if (pixelFormat == "Mono16"): pixel_f = 16 elif (pixelFormat == "Mono8"): pixel_f = 8 else: log.error(' *** *** bit %s format not supported' % pixelFormat) exit() img_uint = np.mod(img, 2**pixel_f) return img_uint
def adjust(what, params): global_PVs = pv.init_general_PVs(params) try: detector_sn = global_PVs['Cam1SerialNumber'].get() if ((detector_sn == None) or (detector_sn == 'Unknown')): log.error('*** The detector with EPICS IOC prefix %s is down' % params.detector_prefix) log.error(' *** Failed!') else: log.info('*** The detector with EPICS IOC prefix %s and serial number %s is on' \ % (params.detector_prefix, detector_sn)) if (what == 'resolution'): detector.init(global_PVs, params) detector.set(global_PVs, params) dark_field, white_field = detector.take_dark_and_white( global_PVs, params) find_resolution(params, dark_field, white_field, angle_shift=-0.7) config.update_sphere(params) else: if (params.image_pixel_size == None): # resolution must be measured at least once log.error( ' *** Detector resolution is not determined. Please run adjust resolution first!' ) time.sleep( 2 ) # to avoid a calling callback function/epics.ca.ChannelAccessException exit() else: dark_field, white_field = detector.take_dark_and_white( global_PVs, params) if (what == 'focus'): adjust_focus(params) if (what == 'center'): adjust_center(params, dark_field, white_field) if (what == 'roll'): adjust_roll(params, dark_field, white_field, angle_shift=-0.7) if (what == 'pitch'): adjust_pitch(params, dark_field, white_field, angle_shift=-0.7) if (what == 'roll') or (what == 'pitch'): # align center again for higher accuracy adjust_center(params, dark_field, white_field) config.update_sphere(params) except KeyError: log.error(' *** Some PV assignment failed!') pass
def center_of_mass(image): threshold_value = filters.threshold_otsu(image) log.info(" *** *** threshold_value: %f" % (threshold_value)) labeled_foreground = (image < threshold_value).astype(int) properties = regionprops(labeled_foreground, image) return properties[0].weighted_centroid
def take_dark_and_white(global_PVs, params): pv.close_shutters(global_PVs, params) log.info(' *** *** acquire dark') dark_field = take_image(global_PVs, params) # plot(dark_field) pv.open_shutters(global_PVs, params) pv.move_sample_out(global_PVs, params) log.info(' *** *** acquire white') white_field = take_image(global_PVs, params) # plot(white_field) pv.move_sample_in(global_PVs, params) return dark_field, white_field
def check_center(params, white_field, dark_field): global_PVs = pv.init_general_PVs(params) log.warning(' *** CHECK center of mass for the centered sphere') log.info(' *** moving rotary stage to %f deg position ***' % float(0)) global_PVs["Rotation"].put(float(0), wait=True, timeout=600.0) log.info(' *** acquire sphere at %f deg position ***' % float(0)) sphere_0 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) cmass_0 = util.center_of_mass(sphere_0) log.warning( ' *** center of mass for the centered sphere at 0 deg: [%f,%f] ***' % (cmass_0[1], cmass_0[0]))
def normalize(arr, flat, dark, cutoff=None, out=None): """ Normalize raw projection data using the flat and dark field projections. Parameters ---------- arr : ndarray 2D of projections. flat : ndarray 2D flat field data. dark : ndarray 2D dark field data. cutoff : float, optional Permitted maximum vaue for the normalized data. out : ndarray, optional Output array for result. If same as arr, process will be done in-place. Returns ------- ndarray Normalized 2D tomographic data. """ arr = as_float32(arr) l = np.float32(1e-5) log.info(' *** *** image size: [%d, %d]' % (flat.shape[0], flat.shape[1])) # flat = np.mean(flat, axis=0, dtype=np.float32) # dark = np.mean(dark, axis=0, dtype=np.float32) flat = flat.astype('float32') dark = dark.astype('float32') denom = ne.evaluate('flat') # denom = ne.evaluate('flat-dark') ne.evaluate('where(denom<l,l,denom)', out=denom) out = ne.evaluate('arr', out=out) # out = ne.evaluate('arr-dark', out=out) ne.evaluate('out/denom', out=out, truediv=True) if cutoff is not None: cutoff = np.float32(cutoff) ne.evaluate('where(out>cutoff,cutoff,out)', out=out) return out
def show_configs(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('adjust 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('show_configs', 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('adjust status end')
def set(global_PVs, params): if (params.detector_prefix == '2bmbSP1:'): log.info(' ') log.info(' *** setup FLIR camera') global_PVs['Cam1Acquire'].put(DetectorIdle) pv.wait_pv(global_PVs['Cam1Acquire'], DetectorIdle, 2) global_PVs['Cam1TriggerMode'].put('Off', wait=True) global_PVs['Cam1TriggerSource'].put('Line2', wait=True) global_PVs['Cam1TriggerOverlap'].put('ReadOut', wait=True) global_PVs['Cam1ExposureMode'].put('Timed', wait=True) global_PVs['Cam1TriggerSelector'].put('FrameStart', wait=True) global_PVs['Cam1TriggerActivation'].put('RisingEdge', wait=True) global_PVs['Cam1ImageMode'].put('Multiple') global_PVs['Cam1ArrayCallbacks'].put('Enable') global_PVs['Cam1FrameRateOnOff'].put(0) global_PVs['Cam1AcquireTimeAuto'].put('Off') global_PVs['Cam1AcquireTime'].put(float(params.exposure_time)) wait_time_sec = int(params.exposure_time) + 5 global_PVs['Cam1TriggerMode'].put('On', wait=True) log.info(' *** setup FLIR camera: Done!') else: log.error('Detector %s is not supported' % params.detector_prefix) return
def close_shutters(global_PVs, params): log.info(' ') log.info(' *** close_shutters') global_PVs['ShutterClose'].put(params.shutter_close_value, wait=True) wait_pv(global_PVs['ShutterStatus'], params.shutter_status_close_value) log.info(' *** close_shutter: Done!')
def open_shutters(global_PVs, params): log.info(' ') log.info(' *** open_shutters') global_PVs['ShutterOpen'].put(str(params.shutter_open_value), wait=True) wait_pv(global_PVs['ShutterStatus'], params.shutter_status_open_value) log.info(' *** open_shutter: Done!')
def adjust_focus(params): global_PVs = pv.init_general_PVs(params) step = 1 direction = 1 max_std = 0 three_std = np.ones(3) * 2**16 cnt = 0 decrease_step = False while (step > 0.01): initpos = global_PVs['Focus'].get() curpos = initpos + step * direction global_PVs['Focus'].put(curpos, wait=True, timeout=600.0) img = detector.take_image(global_PVs, params) cur_std = np.std(img) log.info(' *** *** Positon: %f Standard deviation: %f ' % (curpos, cur_std)) if (cur_std > max_std): # store max std max_std = cur_std three_std[np.mod(cnt, 3)] = cur_std # store std for 3 last measurements if (np.sum(three_std < max_std) == 3): # pass a peak direction = -direction if (decrease_step): # decrease focusing motor step step /= 2 else: #do not decrease step for the first direction change decrease_step = True three_std = np.ones(3) * 2**16 max_std = 0 log.warning(' *** change direction and step to %f' % (step)) cnt += 1 log.warning(' *** Focusing done') return
def move_sample_in(global_PVs, params): axis = params.flat_field_axis log.info('move_sample_in axis: %s', axis) if axis in ('horizontal', 'both'): position = params.sample_in_x log.info(' *** *** Move Sample X in at: %f' % position) global_PVs['SampleX'].put(position, wait=True) if axis in ('vertical', 'both'): position = params.sample_in_y log.info(' *** *** Move Sample Y in at: %f' % position) global_PVs['SampleY'].put(position, wait=True)
def move_center(params, cmass_0, x, y): global_PVs = pv.init_general_PVs(params) log.info(' *** moving sample top X to the rotation center ***') global_PVs["SampleXCent"].put(global_PVs["SampleXCent"].get() + x * params.image_pixel_size / 1000, wait=True, timeout=5.0) log.info(' *** moving sample top Z to the rotation center ***') global_PVs["SampleZCent"].put(global_PVs["SampleZCent"].get() + y * params.image_pixel_size / 1000, wait=True, timeout=5.0) log.info(' *** moving rotation center to the detector center ***') global_PVs["SampleX"].put( global_PVs["SampleX"].get() - (cmass_0[1] - x - global_PVs['Cam1SizeX'].get() / 2) * params.image_pixel_size / 1000, wait=True, timeout=600.0)
def init(global_PVs, params): if (params.detector_prefix == '2bmbSP1:'): log.info(' ') log.info(' *** init FLIR camera') log.info(' *** *** set detector to idle') global_PVs['Cam1Acquire'].put(DetectorIdle) pv.wait_pv(global_PVs['Cam1Acquire'], DetectorIdle, 2) log.info(' *** *** set detector to idle: Done') time.sleep(2) log.info(' *** *** set trigger mode to Off') global_PVs['Cam1TriggerMode'].put('Off', wait=True) # log.info(' *** *** set trigger mode to Off: done') time.sleep(7) log.info(' *** *** set image mode to single') global_PVs['Cam1ImageMode'].put( 'Single', wait=True ) # here is where it crashes with (ValueError: invalid literal for int() with base 0: 'Single') Added 7 s delay before log.info(' *** *** set image mode to single: done') log.info(' *** *** set cam display to 1') global_PVs['Cam1Display'].put(1) log.info(' *** *** set cam display to 1: done') log.info(' *** *** set cam acquire') global_PVs['Cam1Acquire'].put(DetectorAcquire) pv.wait_pv(global_PVs['Cam1Acquire'], DetectorAcquire, 2) log.info(' *** *** set cam acquire: done') log.info(' *** init FLIR camera: Done!') else: log.error('Detector %s is not supported' % params.detector_prefix) return
def adjust_roll(params, dark_field, white_field, angle_shift): # angle_shift is the correction that is needed to apply to the rotation axis position # to align the Z stage on top of the rotary stage with the beam global_PVs = pv.init_general_PVs(params) log.warning(' *** Adjusting roll ***') log.info(' *** moving rotary stage to %f deg position ***' % float(0 + angle_shift)) global_PVs["Rotation"].put(float(0 + angle_shift), wait=True, timeout=600.0) log.info(' *** moving sphere to the detector border ***') global_PVs["SampleXCent"].put( global_PVs["SampleXCent"].get() + global_PVs['Cam1SizeX'].get() / 2 * params.image_pixel_size / 1000 - ((SPHERE_DIAMETER / 2) + GAP), wait=True, timeout=600.0) log.info(' *** acquire sphere at %f deg position ***' % float(0 + angle_shift)) sphere_0 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) log.info(' *** moving rotary stage to %f deg position ***' % float(180 + angle_shift)) global_PVs["Rotation"].put(float(180 + angle_shift), wait=True, timeout=600.0) log.info(' *** acquire sphere at %f deg position ***' % float(180 + angle_shift)) sphere_180 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) cmass_0 = util.center_of_mass(sphere_0) cmass_180 = util.center_of_mass(sphere_180) log.info(' *** center of mass for the sphere at 0 deg (%f,%f) ***' % (cmass_0[1], cmass_0[0])) log.info(' *** center of mass for the sphere at 180 deg (%f,%f) ***' % (cmass_180[1], cmass_180[0])) roll = np.rad2deg( np.arctan((cmass_180[0] - cmass_0[0]) / (cmass_180[1] - cmass_0[1]))) log.warning(' *** found roll error: %f' % roll) log.info(' *** moving rotary stage to %f deg position ***' % float(0 + angle_shift)) global_PVs["Rotation"].put(float(0 + angle_shift), wait=True, timeout=600.0) log.info(' *** moving sphere back to the detector center ***') global_PVs["SampleXCent"].put( global_PVs["SampleXCent"].get() - (global_PVs['Cam1SizeX'].get() / 2 * params.image_pixel_size / 1000 - ((SPHERE_DIAMETER / 2) + GAP)), wait=True, timeout=600.0) log.info(' *** find shifts resulting by the roll change ***') log.info(' *** acquire sphere at the current roll position ***') sphere_0 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) ang = roll / 2 # if roll is too big then ang should be decreased to keep the sphere in the field of view log.info(' *** acquire sphere after testing roll change %f ***' % float(global_PVs["SampleRoll"].get() + ang)) global_PVs["SampleRoll"].put(global_PVs["SampleRoll"].get() + ang, wait=True, timeout=600.0) sphere_1 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) shift0 = register_translation(sphere_1, sphere_0, 100)[0][1] shift1 = shift0 * np.sin(roll) * (np.cos(roll) * 1 / np.tan(ang) + np.sin(roll)) log.info( ' *** the testing roll change corresponds to %f shift in x, calculated resulting roll change gives %f shift in x ***' % (shift0, shift1)) log.warning(' *** change roll to %f ***' % float(global_PVs["SampleRoll"].get() + roll - ang)) global_PVs["SampleRoll"].put(global_PVs["SampleRoll"].get() + roll - ang, wait=True, timeout=600.0) log.info(' *** moving sphere to the detector center ***') global_PVs["SampleX"].put(global_PVs["SampleX"].get() - shift1 * params.image_pixel_size / 1000, wait=True, timeout=600.0) log.info(' *** TEST: acquire sphere at %f deg position ***' % float(0 + angle_shift)) sphere_0 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) cmass_0 = util.center_of_mass(sphere_0) log.info(' *** TEST: center of mass for the sphere at 0 deg (%f,%f) ***' % (cmass_0[1], cmass_0[0]))
def adjust_pitch(params, dark_field, white_field, angle_shift): global_PVs = pv.init_general_PVs(params) log.warning(' *** Adjusting pitch ***') log.info( ' *** acquire sphere after moving it along the beam axis by 1mm ***') global_PVs["SampleZCent"].put(global_PVs["SampleZCent"].get() - 1.0, wait=True, timeout=600.0) log.info(' *** moving rotary stage to %f deg position ***' % float(0 + angle_shift)) global_PVs["Rotation"].put(float(0 + angle_shift), wait=True, timeout=600.0) log.info(' *** acquire sphere at %f deg position ***' % float(0 + angle_shift)) sphere_0 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) log.info(' *** moving rotary stage to %f deg position ***' % float(0 + angle_shift)) global_PVs["Rotation"].put(float(180 + angle_shift), wait=True, timeout=600.0) log.info(' *** acquire sphere at %f deg position ***' % float(180 + angle_shift)) sphere_180 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) cmass_0 = util.center_of_mass(sphere_0) cmass_180 = util.center_of_mass(sphere_180) log.info(' *** center of mass for the initial sphere (%f,%f) ***' % (cmass_0[1], cmass_0[0])) log.info(' *** center of mass for the shifted sphere (%f,%f) ***' % (cmass_180[1], cmass_180[0])) pitch = np.rad2deg( np.arctan((cmass_180[0] - cmass_0[0]) * params.image_pixel_size / 1000 / 2.0)) log.warning(' *** found pitch error: %f' % pitch) log.info(' *** acquire sphere back along the beam axis by -1mm ***') global_PVs["SampleZCent"].put(global_PVs["SampleZCent"].get() + 1.0, wait=True, timeout=600.0) log.warning(' *** change pitch to %f ***' % float(global_PVs["SamplePitch"].get() - pitch)) global_PVs["SamplePitch"].put(global_PVs["SamplePitch"].get() - pitch, wait=True, timeout=600.0) global_PVs["Rotation"].put(float(0 + angle_shift), wait=True, timeout=600.0) log.info(' *** TEST: acquire sphere at %f deg position ***' % float(0 + angle_shift)) sphere_0 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) cmass_0 = util.center_of_mass(sphere_0) log.info(' *** TEST: center of mass for the sphere at 0 deg (%f,%f) ***' % (cmass_0[1], cmass_0[0]))
def find_resolution(params, dark_field, white_field, angle_shift): global_PVs = pv.init_general_PVs(params) log.warning(' *** Find resolution ***') log.info(' *** moving rotary stage to %f deg position ***' % float(0 + angle_shift)) global_PVs["Rotation"].put(float(0 + angle_shift), wait=True, timeout=600.0) log.info(' *** First image at X: %f mm' % (params.sample_in_x)) log.info(' *** acquire first image') sphere_0 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) second_image_x_position = params.sample_in_x + params.off_axis_position log.info(' *** Second image at X: %f mm' % (second_image_x_position)) global_PVs["SampleX"].put(second_image_x_position, wait=True, timeout=600.0) log.info(' *** acquire second image') sphere_1 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) log.info(' *** moving X stage back to %f mm position' % (params.sample_in_x)) pv.move_sample_in(global_PVs, params) shift = register_translation(sphere_0, sphere_1, 100) log.info(' *** shift X: %f, Y: %f' % (shift[0][1], shift[0][0])) image_pixel_size = abs(params.off_axis_position) / np.linalg.norm( shift[0]) * 1000.0 log.warning(' *** found resolution %f um/pixel' % (image_pixel_size)) params.image_pixel_size = image_pixel_size global_PVs['ImagePixelSize'].put(params.image_pixel_size, wait=True)
def init_general_PVs(params): global_PVs = {} global_PVs['ShutterOpen'] = PV(params.shutter_open_pv_name + '.VAL') global_PVs['ShutterClose'] = PV(params.shutter_close_pv_name + '.VAL') global_PVs['ShutterStatus'] = PV(params.shutter_status_pv_name + '.VAL') global_PVs['SampleX'] = PV(params.sample_x_pv_name + '.VAL') global_PVs['SampleXSet'] = PV(params.sample_x_pv_name + '.SET') global_PVs['SampleY'] = PV(params.sample_y_pv_name + '.VAL') global_PVs['SampleYSet'] = PV(params.sample_y_pv_name + '.SET') global_PVs['Rotation'] = PV(params.rotation_pv_name + '.VAL') global_PVs['RotationRBV'] = PV(params.rotation_pv_name + '.RBV') global_PVs['RotationCnen'] = PV(params.rotation_pv_name + '.CNEN') global_PVs['RotationAccl'] = PV(params.rotation_pv_name + '.ACCL') global_PVs['RotationStop'] = PV(params.rotation_pv_name + '.STOP') global_PVs['RotationSet'] = PV(params.rotation_pv_name + '.SET') global_PVs['RotationVelo'] = PV(params.rotation_pv_name + '.VELO') global_PVs['SampleXCent'] = PV(params.sample_x_center_pv_name + '.VAL') global_PVs['SampleZCent'] = PV(params.sample_z_center_pv_name + '.VAL') global_PVs['SamplePitch'] = PV(params.sample_pitch_pv_name + '.VAL') global_PVs['SampleRoll'] = PV(params.sample_roll_pv_name + '.VAL') global_PVs['Focus'] = PV(params.focus_pv_name + '.VAL') global_PVs['ImagePixelSize'] = PV(params.image_pixel_size_pv_name + '.VAL') # detector pv's camera_prefix = params.detector_prefix + 'cam1:' global_PVs['CamManufacturer'] = PV(camera_prefix + 'Manufacturer_RBV') global_PVs['CamModel'] = PV(camera_prefix + 'Model_RBV') global_PVs['Cam1SerialNumber'] = PV(camera_prefix + 'SerialNumber_RBV') global_PVs['Cam1ImageMode'] = PV(camera_prefix + 'ImageMode') global_PVs['Cam1ArrayCallbacks'] = PV(camera_prefix + 'ArrayCallbacks') global_PVs['Cam1AcquirePeriod'] = PV(camera_prefix + 'AcquirePeriod') global_PVs['Cam1SoftwareTrigger'] = PV(camera_prefix + 'SoftwareTrigger') global_PVs['Cam1AcquireTime'] = PV(camera_prefix + 'AcquireTime') global_PVs['Cam1FrameType'] = PV(camera_prefix + 'FrameType') global_PVs['Cam1AttributeFile'] = PV(camera_prefix + 'NDAttributesFile') global_PVs['Cam1SizeX'] = PV(camera_prefix + 'SizeX') global_PVs['Cam1SizeY'] = PV(camera_prefix + 'SizeY') global_PVs['Cam1NumImages'] = PV(camera_prefix + 'NumImages') global_PVs['Cam1TriggerMode'] = PV(camera_prefix + 'TriggerMode') global_PVs['Cam1Acquire'] = PV(camera_prefix + 'Acquire') global_PVs['Cam1SizeX_RBV'] = PV(camera_prefix + 'SizeX_RBV') global_PVs['Cam1SizeY_RBV'] = PV(camera_prefix + 'SizeY_RBV') global_PVs['Cam1MaxSizeX_RBV'] = PV(camera_prefix + 'MaxSizeX_RBV') global_PVs['Cam1MaxSizeY_RBV'] = PV(camera_prefix + 'MaxSizeY_RBV') global_PVs['Cam1PixelFormat_RBV'] = PV(camera_prefix + 'PixelFormat_RBV') image_prefix = params.detector_prefix + 'image1:' global_PVs['Image'] = PV(image_prefix + 'ArrayData') global_PVs['Cam1Display'] = PV(image_prefix + 'EnableCallbacks') manufacturer = global_PVs['CamManufacturer'].get(as_string=True) model = global_PVs['CamModel'].get(as_string=True) if model == 'Oryx ORX-10G-51S5M': log.info('Detector %s model %s:' % (manufacturer, model)) global_PVs['Cam1AcquireTimeAuto'] = PV(params.detector_prefix + 'AcquireTimeAuto') global_PVs['Cam1FrameRateOnOff'] = PV(params.detector_prefix + 'FrameRateEnable') global_PVs['Cam1TriggerSource'] = PV(params.detector_prefix + 'TriggerSource') global_PVs['Cam1TriggerOverlap'] = PV(params.detector_prefix + 'TriggerOverlap') global_PVs['Cam1ExposureMode'] = PV(params.detector_prefix + 'ExposureMode') global_PVs['Cam1TriggerSelector'] = PV(params.detector_prefix + 'TriggerSelector') global_PVs['Cam1TriggerActivation'] = PV(params.detector_prefix + 'TriggerActivation') else: log.error('Detector %s model %s is not supported' % (manufacturer, model)) return None return global_PVs
def adjust_center(params, dark_field, white_field): global_PVs = pv.init_general_PVs(params) log.warning(' *** Adjusting center ***') for ang in [params.adjust_center_angle_1, params.adjust_center_angle_2]: log.warning(' *** take 3 spheres angular %f deg ***' % float(ang)) #sphere 0 log.info(' *** sphere 0') log.info(' *** *** moving rotary stage to %f deg position ***' % float(0)) global_PVs["Rotation"].put(float(0), wait=True, timeout=600.0) log.error(' *** *** acquire sphere at %f deg position ***' % float(0)) sphere_0 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) #sphere 1 log.info(' *** sphere 1') log.info(' *** *** moving rotary stage to %f deg position ***' % float(ang)) global_PVs["Rotation"].put(float(ang), wait=True, timeout=600.0) log.error(' *** *** acquire sphere at %f deg position ***' % float(ang)) sphere_1 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) #sphere 2 log.info(' *** sphere 2') log.info(' *** *** moving rotary stage to %f deg position ***' % float(2 * ang)) global_PVs["Rotation"].put(float(2 * ang), wait=True, timeout=600.0) log.error(' *** *** acquire sphere at %f deg position ***' % float(2 * ang)) sphere_2 = util.normalize(detector.take_image(global_PVs, params), white_field, dark_field) # find shifts shift0 = register_translation(sphere_1, sphere_0, 100)[0][1] shift1 = register_translation(sphere_2, sphere_1, 100)[0][1] a = ang * np.pi / 180 # x=-(1/4) (d1+d2-2 d1 Cos[a]) Csc[a/2]^2, x = -(1 / 4) * (shift0 + shift1 - 2 * shift0 * np.cos(a)) * 1 / np.sin( a / 2)**2 # r = 1/2 Csc[a/2]^2 Csc[a] Sqrt[(d1^2+d2^2-2 d1 d2 Cos[a]) Sin[a/2]^2] r = 1 / 2 * 1 / np.sin(a / 2)**2 * 1 / np.sin(a) * np.sqrt( np.abs((shift0**2 + shift1**2 - 2 * shift0 * shift1 * np.cos(a)) * np.sin(a / 2)**2)) # g = ArcCos[((-d1-d2+2 d1 Cos[a]) Sin[a])/(2 Sqrt[(d1^2+d2^2-2 d1 d2 Cos[a]) Sin[a/2]^2])] g = np.arccos( ((-shift0 - shift1 + 2 * shift0 * np.cos(a)) * np.sin(a)) / (2 * np.sqrt( np.abs( (shift0**2 + shift1**2 - 2 * shift0 * shift1 * np.cos(a)) * np.sin(a / 2)**2)))) y = r * np.sin(g) * np.sign(shift0) # find center of mass cmass_0 = util.center_of_mass(sphere_0) log.info(' ') log.info( ' *** position of the initial sphere wrt to the rotation center (%f,%f) ***' % (x, y)) log.info(' *** center of mass for the initial sphere (%f,%f) ***' % (cmass_0[1], cmass_0[0])) log.info( ' *** moving sphere to the position of the rotation center ***') if (params.ask): if util.yes_or_no(' *** Yes or No'): move_center(params, cmass_0, x, y) check_center(params, white_field, dark_field) else: log.warning(' No motion ') exit() else: move_center(params, cmass_0, x, y) check_center(params, white_field, dark_field)