def initialize_zoneplate_data(self, reset=False): """Initialize values for the zoneplate used as well as detector pixel size. Asks the user what the parameters of the zone plate are and detector pixel size. If they have been already set then the program displays the current values when setting up SXDMFrameset object Parameters ========== self (SXDMFrameset) the sxdmframset reset (bool) if True this allows the user to reset all values Returns ======= Nothing - sets values inside /zone_plate/ """ if reset == False: if h5path_exists(self.file, 'zone_plate/D_um') == False: D_um_val = input( 'What Is The Diameter Of The Zone Plate Used In Microns? (Typically 150)' ) h5create_dataset(self.file, 'zone_plate/D_um', D_um_val) else: print('Diameter Of The Zone Plate Is Set To {} microns'.format( h5grab_data(self.file, 'zone_plate/D_um'))) if h5path_exists(self.file, 'zone_plate/d_rN_nm') == False: d_rN_nm_val = input( 'What Is The Outer Most d Spacing Is ' 'For The Zone Plate Used In Nanometers? (Typically 20)') h5create_dataset(self.file, 'zone_plate/d_rN_nm', d_rN_nm_val) else: print('Outermost Zone Plate d Spacing Is Set To {} nanometers'. format(h5grab_data(self.file, 'zone_plate/d_rN_nm'))) if h5path_exists(self.file, 'zone_plate/detector_pixel_size') == False: detector_pixel_size_val = input( 'What Pixel Size Of The Detector In Microns? (Typically 15)') h5create_dataset(self.file, 'zone_plate/detector_pixel_size', detector_pixel_size_val) else: print( 'The Size Of Your Detector Pixels Is Set To {} microns'.format( h5grab_data(self.file, 'zone_plate/detector_pixel_size'))) elif reset == True: D_um_val = input( 'What Is The Diameter Of The Zone Plate Used In Microns? (Typically 150)' ) h5replace_data(self.file, 'zone_plate/D_um', D_um_val) d_rN_nm_val = input( 'What Is The Outer Most d Spacing Is For The Zone Plate Used In Nanometers? (Typically 20)' ) h5replace_data(self.file, 'zone_plate/d_rN_nm', d_rN_nm_val) detector_pixel_size_val = input( 'What Pixel Size Of The Detector In Microns? (Typically 15)') h5replace_data(self.file, 'zone_plate/detector_pixel_size', detector_pixel_size_val)
def return_chi_images(file, chi_figures): """Return the detector movement data Parameters ========== file (str): the file the user would like to find the detector images from chi_figures (Chi_FigureClass): the figure class. used to make it easier to move data around Returns ======= Nothing - sets chi_fiures.images value """ # Obtain the images for the figure images_loc = chi_figures.images_location image_array = [] if images_loc != None: for image in images_loc: image_array.append(h5grab_data(file=file, data_loc=image)) # If it errors then load psyduck elif images_loc == None: image_array = [sum_error(), sum_error()] chi_figures.images = image_array
def saved_return(file, group, summed_dif_return=False): """Load saved data Parameters ========== file (str) a user defined hdf5 file group (str) the group the user would like to import summed_dif_return (bool) if True this will import all data. it is set to False because this import take up a lot of RAM Returns ======= a nd.array thay can be set to the self.results value """ acceptable_values = ['row_column', 'summed_dif', 'ttheta', 'chi', 'ttheta_corr', 'ttheta_centroid', 'chi_corr', 'chi_centroid', 'full_roi'] pre_store = [] for value in tqdm(acceptable_values): if value != 'summed_dif': data = h5grab_data(file, '{}/{}'.format(group, value)) rc_appender = [] if value == 'row_column': length_data = len(data) for rc_data in data: rc_appender.append((rc_data[0], rc_data[1])) pre_store.append(rc_appender) else: pre_store.append(data) elif value == 'summed_dif' and summed_dif_return == True: data = h5grab_data(file, '{}/{}'.format(group, value)) pre_store.append(data) elif value == 'summed_dif' and summed_dif_return == False: pre_store.append(np.zeros(length_data)) results_store = [] for i, iteration in enumerate(pre_store[0]): base_store = [] for j, its in enumerate(pre_store): base_store.append(its[i]) results_store.append(base_store) return np.asarray(results_store)
def initialize_scans(self, scan_numbers=False, fill_num=4): """Initialize all necessities for each scan Parameters ========== self (SXDMFrameset) the sxdmframeset scan_numbers (nd.array of int) the list of scan numbers the user wants to create [178, 178, ...] fill_num (int) the zfill number for the scan number integers Returns ======= Nothing - sets self.scan_numbers, self.det_smpl_theta, and self.scan_theta """ # When .mda files are missing this script cannot pull scan information try: if scan_numbers != False: self.scan_numbers = scan_num_convert(scan_numbers, fill_num=fill_num) else: import_scans = h5grab_data(self.file, self.dataset_name + '/scan_numbers') import_scans = [int(scan) for scan in import_scans] self.scan_numbers = scan_num_convert(list(import_scans), fill_num=fill_num) self.det_smpl_theta = str( h5grab_data(self.file, 'detector_channels/sample_theta')[0]).zfill(2) scan_theta_grab = [ h5grab_data(self.file, 'mda/' + scan + '/D' + self.det_smpl_theta) for scan in self.scan_numbers ] self.scan_theta = [ np.mean(scan, axis=(0, 1)) for scan in scan_theta_grab ] except Exception as ex: print('preprocess.py/initialize_scans', ex) warnings.warn( 'Cannot Initialize Scans. Some .mda Files Might Be Missing...')
def broadening_in_pixles(self): """Determine the instrumental broadening in pixels as well as the focal length and numberical aperature Returns ======= Nothing Sets ==== self.focal_length_mm self.NA_mrads self.broadening_in_pix """ # Read attributes set by the User Kev = float( h5read_attr(file=self.file, loc=self.dataset_name, attribute_name='Kev')) D_um = float(h5grab_data(file=self.file, data_loc='zone_plate/D_um')) d_rN_nm = float(h5grab_data(file=self.file, data_loc='zone_plate/d_rN_nm')) r_mm = self.r_mm pix_size_um = self.pix_size_um D_nm = D_um * 1000 r_um = r_mm * 1000 half_zp_nm = D_nm / 2 plancks_constant = (6.62607004 * 10**-34) / (1.60217662 * 10**-19) speed_of_light = 299792458 hc = plancks_constant * speed_of_light * 10**9 wavelength_nm = hc / (Kev * 1000) f_nm = (D_nm * d_rN_nm) / wavelength_nm fraction = half_zp_nm / f_nm len_in_pix = r_um / pix_size_um self.focal_length_mm = f_nm / 1000000 self.NA_mrads = fraction * 1000 self.broadening_in_pix = (half_zp_nm / f_nm) * len_in_pix
def chis(self): """Calculates the bounds for the detector Parameters ========== self (SXDMFrameset) the sxdmframeset Returns ======= Nothing Prints and Sets ====== self.chi value, self.focal_length, self.NA_mrads (numberical aperature), self.broadening_in_pix of the detector """ # Grab pixel size, and angle difference, and scan dimensions pix_size_um = float( h5grab_data(file=self.file, data_loc='zone_plate/detector_pixel_size')) self.pix_size_um = pix_size_um tot_angle_diff = self.chi_angle_difference dimensions = self.chi_image_dimensions pixel_diff = self.chi_position_difference # Determine the angle and total length angle_rads = math.radians(tot_angle_diff) length = (pixel_diff * pix_size_um) r = (length / math.tan(angle_rads)) / 1000 self.r_mm = r Chi = math.degrees( math.atan((((((dimensions[0]) / 2) * pix_size_um) / 1000)) / r)) self.chi = Chi broadening_in_pixles(self) print( 'Chi bound is: {} Degrees\nFocal Length is : {} mm\nNumberical Aperature is: {} mrads\n' 'Radius of Broadening is: {} pixels'.format(self.chi, self.focal_length_mm, self.NA_mrads, self.broadening_in_pix)) # Making sure the output is OK self.testing_chi_output = [ self.chi, self.focal_length_mm, self.NA_mrads, self.broadening_in_pix ]
def grab_dxdy(self): """Return the dxdy movements for each scan Parameters ========== self (SXDMFrameset) the sxdmframeset Returns ======= the dxdy values stored in the self.file """ data = h5grab_data(file=self.file, data_loc=self.dataset_name + '/dxdy') store = {} for i, d in enumerate(data): store[i] = (d[0], d[1]) return store
def array_shift(self, arrays2shift, centering_idx): """Translate a 3D stack of numpy arrays to align based on set centering values Parameters ========== self (SXDMFrameset) the sxdmframeset arrays2shift (numpy array) the 3 dimensional array the user wants to center around one of the indexes centering_idx (numpy array) the dxdy values (translation values) for each matrix in the array Returns ======= the shifted array based on the dxdy values """ # Obtain the array from stored file and make it into a dictionary complete_array = array2dic( h5grab_data(self.file, self.dataset_name + '/dxdy')) center = complete_array[centering_idx] center_x = center[0] center_y = center[1] translation_array = {} # Translate arrays for array in complete_array: translation_array[array] = (center_x - complete_array[array][0], center_y - complete_array[array][1]) shifted_arrays = [] for i, array in enumerate(translation_array): trans = translation_array[array] movement_x = trans[0] movement_y = trans[1] shifted_arrays.append( shift(arrays2shift[i], (movement_y, movement_x), cval=np.nan, order=0)) return shifted_arrays
def return_det(file, scan_numbers, group='fluor', default=False, dim_correction=True): """Returns all information for a given detector channel for an array of scan numbers Parameters ========== file: (str) the .h5 file location scan_numbers: (np.array) an array of scan numbers the user wants to get a specific detector channel information for group: (str) a string corresponding to a group value that the user wants to return default: (bool) If True this will default to the first acceptable detector_channel in the hdf5 file dim_correction: (bool) If False this will not add rows and columns to the returned array to make them all the same shape Returns ======= The specified detector channel for all specified scan numbers, the .mda detector value """ # Get the acceptable values acceptable_values = h5grab_data(file=file, data_loc='detector_channels') if group in acceptable_values: path = 'detector_channels/' + group acceptable_values = h5grab_data(file=file, data_loc=path) end = False fluor_array = [] # Keep asking the User for an acceptable value if it doesnt exsist while end == False: if group not in ['filenumber', 'sample_theta', 'hybrid_x', 'hybrid_y']: if default == False: user_val = str(input('Which - ' + group + ' - Would You Like To Center To/Return: ' + str(acceptable_values))) elif default == True: user_val = acceptable_values[0] else: user_val = str(acceptable_values[0]) acceptable_values = [str(user_val)] # Grab the right data if user_val in acceptable_values: if group not in ['filenumber', 'sample_theta', 'hybrid_x', 'hybrid_y']: det = str(h5grab_data(file=file, data_loc=path + '/' + user_val)) else: det = user_val det = 'D' + det.zfill(2) shapes = [] for i, scan in enumerate(scan_numbers): if group != 'xrf': fluors = h5grab_data(file=file, data_loc='mda/' + scan + '/' + det) elif group == 'xrf': fluors = h5grab_data(file=file, data_loc='xrf/' + scan + '/' + det) if group == 'filenumber': shapes.append(np.shape(fluors)) fluor_array.append(fluors) end = True # Correcting for terrible matlab code filenumber logging if group == 'filenumber': fluor_array = [] fluor_array = true_filenumbers(file=file, scan_numbers=scan_numbers, shapes=shapes) # Correct the dimensions of each scan to make sure they are all the same if dim_correction == True: m_row, m_column = max_dims(fluor_array) n_fluor_array = det_dim_fix(fluor_array, m_row, m_column) else: n_fluor_array = fluor_array return n_fluor_array, user_val else: warnings.warn('Please Type In An Acceptable Value') else: warnings.warn('Please Type In An Acceptable Value')
def disp_det_chan(file): """Allows the user to quicky see what all values are set to in the detector_channel group Parameters ========== file (str): the .h5 file you would like to delete the detector_channel group from Returns ======= prints the current values of the detector_channel group. If no values are currently set it displays something the User can copy and paste into a cell to set the appropriate dectector values """ try: det_chans = h5group_list(file=file, group_name='/detector_channels/') types = [] dic_values = [] for channel in det_chans: types.append(channel[0]) # Try to grab the current detector_channel values to display to the User for chan_type in types: try: dic_values.append(h5group_list(file=file, group_name='/detector_channels/'+chan_type)) except: dic_values.append(h5grab_data(file=file, data_loc='/detector_channels/'+chan_type)) for i, vals in enumerate(dic_values): text = (types[i]+' = ') lens = len(vals)-1 for j, sets in enumerate(vals): try: dummy = h5grab_data(file=file, data_loc='/detector_channels/'+types[i]+'/'+sets[0]) if j == 0: text = text + '{\n \t' text = (text + str("'"+sets[0])+"'"+':'+' ' + str(h5grab_data(file=file, data_loc='/detector_channels/'+types[i]+'/'+sets[0]))+',\n \t') if j == lens: text = text + '}' except: text = text + str(sets) print(text+'\n') # If you can't then display something that can help the User set the appropriate variables except: warnings.warn('No Detector Channels Set. Configure Them As You See Above') base = ("fluor = {\n\t'Fe':2,\n\t'Cu':2,\n\t'Ni':2,\n\t'Mn':2\n\t}"+'\n' + "roi = {\n\t'ROI_1':2,\n\t'ROI_2':2,\n\t'ROI_3':2,\n\t}"+'\n' + "detector_scan = {\n\t'Main_Scan':2,\n\t}"+'\n' + "filenumber = 2"+'\n' + "sample_theta = 2"+'\n' + "hybrid_x = 2" + '\n' + "hybrid_y = 2" + '\n' + "xrf = {\n\t'Fe':2,\n\t'Cu':2,\n\t'Ni':2,\n\t'Full':2\n\t}" + '\n' + "mis = {'2Theta':2,\n\t'Storage_Ring_Current':2,\n\t'Relative_r_To_Detector':2,}"+'\n' ) print(base)
def alignment_function(self): """Allows the user to align the scans based on Fluorescence or Region Of Interest. Sets alignment variables and stores them in designated .h5 file. Easier to reload alignment data or redo alignment data Parameters ========== self: (SXDMFrameset) the sxdmframeset object Returns ======= Nothing """ # Check to see if /dxdy group exsists if not make it and set attributes if h5path_exists(file=self.file, loc=self.dataset_name + '/dxdy') == True: warnings.warn('Previous Data Found') redo_alignment = input('Previous Data Found. Redo Alignment? y/n ') # Determining if User wants to reload or redo alignment if redo_alignment == 'y': start_alignment = 'y' try: self.alignment_group = h5read_attr( file=self.file, loc=self.dataset_name + '/dxdy', attribute_name='alignment_group') self.alignment_subgroup = h5read_attr( file=self.file, loc=self.dataset_name + '/dxdy', attribute_name='alignment_subgroup') except Exception as ex: print('alignment.py/alignment_function 1', ex) # If no redo and no start, save those choices else: start_alignment = 'n' redo_alignment = 'n' else: start_alignment = 'y' redo_alignment = 'n' # Initialize the alignment process if we are starting the alignment if start_alignment == 'y': if start_alignment == 'y' and redo_alignment == 'n': init_dxdy(self) else: try: # Try to pull previous alignment data - if you can't throw error to the user print('Previous Alignment Done On - {} - {}'.format( self.alignment_group, self.alignment_subgroup)) except Exception as ex: print('alignment.py/alignment_function 2', ex) # Grabbing old alignment and setting alignment circles retrieve_old_data = array2dic(array=h5grab_data( file=self.file, data_loc=self.dataset_name + '/dxdy')) warnings.warn('Refreshing Old Alignment Data') if len(retrieve_old_data.keys()) > len(self.scan_numbers): warnings.warn( 'Saved Alignment Has More Scans Than Current Import - Please Set reset=True' ) # Create variables to store data self.clicks = {} self.correction_store = {} plt.close('all') cont = True # Ask which images the user wants to align to while cont == True: user_val = input('Would You Like To Align On fluor Or roi? ') if user_val in ['fluor', 'roi']: cont = False else: warnings.warn('Please Type In An Acceptable Values: ') # Grab data and set alignment data det_return = return_det(file=self.file, scan_numbers=self.scan_numbers, group=user_val) # Setting up figure data images = det_return[0] self.alignment_subgroup = det_return[1] self.alignment_group = user_val self.max_images = np.shape(images)[0] starting = figure_size_finder(images=images) plt.close('all') # Setting up initial figure for alignment fig, axs = plt.subplots(starting, starting, figsize=(10, 10), facecolor='w', edgecolor='k') # Try to ravel axis - if data is 1D continue to the except code try: self.loc_axs = axs.ravel() except: warnings.warn( 'Ravel Function Not Called. Possible 1D Image Trying To Load') self.loc_axs = [axs] axs_store = [] # Set up saving, and click functions into partials saving = partial(save_alignment, self=self) initiate = partial(onclick_1, self=self) click1 = partial(fig1_click, self=self, fig=fig, images=images) # Display circles for alignment for i, image in enumerate(images): self.loc_axs[i].imshow(image) axs_store.append(self.loc_axs[i].get_position()) if redo_alignment == 'y': for num, old_ax in enumerate(retrieve_old_data): old_clicks = retrieve_old_data[old_ax] circ = Circle((old_clicks[0], old_clicks[1]), 0.3, color='r') self.loc_axs[old_ax].add_patch(circ) plt.suptitle('Please Click On Any Of The Images Below') plt.show() # Based on the Users clicks display different information fig.canvas.mpl_connect('button_press_event', initiate) fig.canvas.mpl_connect('button_press_event', click1) fig.canvas.mpl_connect('button_press_event', saving) elif redo_alignment == 'n': print('Staying With Current Alignment Parameters')
def return_chi_images_loc( file, chi_figures, detector_channel_loc='detector_channels/detector_scan/Main_Scan', zfill_num=4, ): """Grabs the image location for the detector sweep scan Parameters ========== file: (str) the .h5 file associated with the dataset chi_figures: (Chi_FigureClass) the Chi_FigureClass allowing transfer of data from figure to figure detector_channel_loc: (str) the h5 group location to the detector sweep scan used for chi bounds determination zfill_num: (int) the integer value for how many digits the scan number must have Returns ======= Nothing - sets the chi_figures.scan_theta and chi_figures.images_location valuess """ # Attempt to pull chi determination scan information try: # Grab the detector channel data scan = h5grab_data(file=file, data_loc=detector_channel_loc) scan_str = str(scan).zfill(zfill_num) # Grab the scans in the images and mda group im_loc = h5grab_data(file=file, data_loc='images/{}'.format(scan_str)) mda_loc = h5grab_data(file=file, data_loc='mda/{}'.format(scan_str)) # See if the images or mda group exsists im_check = h5path_exists(file=file, loc='images/{}'.format(scan_str)) mda_check = h5path_exists(file=file, loc='mda/{}'.format(scan_str)) # Formatting the image locations images_loc = ['images/{}/{}'.format(scan_str, loc) for loc in im_loc] chi_figures.images_location = images_loc # Based on what the user rocked to get the chi scan this will pull different values if chi_figures.user_rocking == 'spl': theta = return_det(file=file, scan_numbers=[scan_str], group='sample_theta') chi_figures.scan_theta = theta[0] elif chi_figures.user_rocking == 'det': det_find = 'D' + str( h5grab_data(file=file, data_loc='detector_channels/mis/2Theta')).zfill(2) theta = h5grab_data(file=file, data_loc='/mda/{}/{}'.format( scan_str, det_find)) sh = np.shape(theta) theta = np.reshape(theta, (1, sh[0] * sh[1]))[0] chi_figures.scan_theta = theta # Throw error if the program cannot pull info except Exception as ex: print('chi_determination.py/return_chi_images_loc', ex) warnings.warn( 'You Have Failed To Load In The Correct Detector Channel. ' 'Correct The detector_channel_loc or Import Correct Data') chi_figures.images_location = None # Throw error if the images or mda group does not exist if im_check == False or mda_check == False: warnings.warn( 'You Have Failed To Load In The Correct Detector Channel. ' 'Correct The detector_channel_loc or Import Correct Data ' 'im_check: {} - mda_check: {}'.format(im_check, mda_check)) chi_figures.images_location = None
def initialize_group(self): """ Initialized the group assigned by the user to the user defined file. From the scan numbers the program determines the scan_theta as well checking if identical settings have already been imported. If so the program reloads saved settings Parameters ========== self (SXDMFrameset) the sxdmframeset Returns ======= Nothing - sets /scan_numbers and /scan_theta """ # When .mda files are missing this function cannot import /scan_theta try: if h5path_exists(self.file, self.dataset_name) == False: # Creating groups and initializing their datasets h5create_group(self.file, self.dataset_name) scan_numbers = scan_num_convert(self.scan_numbers) h5create_dataset(self.file, self.dataset_name + '/scan_numbers', scan_numbers) h5create_dataset(self.file, self.dataset_name + '/scan_theta', np.asarray(self.scan_theta)) else: # Grabbing old data from stored datasets old_scan_nums = h5grab_data(self.file, self.dataset_name + '/scan_numbers') new_scan_nums = self.scan_numbers new_scan_nums = np.asarray(scan_num_convert(new_scan_nums)) print('Saved Scans: ' + str(old_scan_nums)) print('Current User Input: ' + str(new_scan_nums)) try: # See if an alignment data has already been set checker = self.dxdy_store except: try: # Try to grab old alignment data self.dxdy_store = grab_dxdy(self) except Exception as ex: warnings.warn('{} - Alignment Data Not Found'.format(ex)) # If the old scans equal the new scans tell the User if np.array_equal(old_scan_nums, new_scan_nums) == True: print('Importing Identical Scans. Reloading Saved Data...\n') # If they don't give them the option to delete the old group and start again else: user_val = input( 'New Scans Detected. Would You Like To Delete Current Group And Start Again? y/n ' ) if user_val == 'n': print('Importing Saved Scans...') elif user_val == 'y': print('Replacing - ' + self.dataset_name + ' - Group\n') scan_numbers = scan_num_convert(self.scan_numbers) try: h5del_group(self.file, self.dataset_name + '/scan_numbers') except: pass try: h5del_group(self.file, self.dataset_name + '/scan_theta') except: pass try: h5create_dataset(self.file, self.dataset_name + '/scan_numbers', scan_numbers) except: pass try: h5create_dataset(self.file, self.dataset_name + '/scan_theta', np.asarray(self.scan_theta)) except: pass except Exception as ex: print('preprocess.py/initialize_group', ex) warnings.warn( 'Cannot Initialize Group. Some .mda Files Might Be Missing...')