diff --git a/beamtime/xrd/io.py b/beamtime/xrd/io.py index 43ae2f7..b5a479c 100644 --- a/beamtime/xrd/io.py +++ b/beamtime/xrd/io.py @@ -8,6 +8,9 @@ import zipfile import xml.etree.ElementTree as ET +import beamtime.auxillary as aux + + def get_image_array(path): image = fabio.open(path) @@ -29,66 +32,95 @@ def integrate_1d(data, options={}): Required content of data: calibrant (str): path to .poni-file nbins (int): Number of bins to divide image into - path (str) (optional): path to image file - either this or image must be specified. If both is passed, image is prioritsed - image (str) (optional): image array (Numpy) as extracted from get_image_array + path (str) (optional, dependent on image): path to image file - either this or image must be specified. If both is passed, image is prioritsed + image (NumPy 2D Array) (optional, dependent on path): image array as extracted from get_image_array Output: df: DataFrame contianing 1D diffractogram if option 'return' is True ''' - required_options = ['unit', 'extension', 'filename', 'save_folder', 'overwrite', 'return'] + required_options = ['unit', 'save', 'save_filename', 'save_extension', 'save_folder', 'overwrite'] default_options = { 'unit': '2th_deg', - 'extension': '_integrated.dat', - 'filename': None, + 'save': False, + 'save_filename': None, + 'save_extension': '_integrated.xy', 'save_folder': '.', - 'overwrite': False, - 'return': False} + 'overwrite': False} - if not options: - options = default_options - - else: - for option in required_options: - if option not in options.keys(): - options[option] = default_options[option] - + options = aux.update_options(options=options, required_options=required_options, default_options=default_options) + + # Get image array from filename if not passed if 'image' not in data.keys(): data['image'] = get_image_array(data['path']) + # Instanciate the azimuthal integrator from pyFAI from the calibrant (.poni-file) ai = pyFAI.load(data['calibrant']) - - if not options['filename']: - if data['path']: - filename = os.path.join(options['save_folder'], os.path.split(data['path'])[-1].split('.')[0] + options['extension']) - else: - filename = os.path.join(options['save_folder'], 'integrated.dat') - - - if not options['overwrite']: - trunk = os.path.join(options['save_folder'], filename.split('\\')[-1].split('.')[0]) - extension = filename.split('.')[-1] - counter = 0 - - while os.path.isfile(filename): - counter_string = str(counter) - filename = trunk + '_' + counter_string.zfill(4) + '.' + extension - counter += 1 - - + # Determine filename + filename = make_filename(data=data, options=options) + + # Make save_folder if this does not exist already if not os.path.isdir(options['save_folder']): os.makedirs(options['save_folder']) res = ai.integrate1d(data['image'], data['nbins'], unit=options['unit'], filename=filename) - return read_diffractogram(filename) + diffractogram = read_xy(filename) + + if not options['save']: + os.remove(filename) + shutil.rmtree('tmp') + + return diffractogram +def make_filename(data, options): + + # Define save location for integrated diffractogram data + if not options['save']: + options['save_folder'] = 'tmp' + filename = os.path.join(options['save_folder'], 'tmp_diff.dat') + + elif options['save']: + + # Case 1: No filename is given. + if not options['save_filename']: + # If a path is given instead of an image array, the path is taken as the trunk of the savename + if data['path']: + # Make filename by joining the save_folder, the filename (with extension deleted) and adding the save_extension + filename = os.path.join(options['save_folder'], os.path.split(data['path'])[-1].split('.')[0] + options['save_extension']) + else: + # Make filename just "integrated.dat" in the save_folder + filename = os.path.join(options['save_folder'], 'integrated.xy') + + + else: + filename = os.path.join(options['save_folder'], options['save_filename']) + + + if not options['overwrite']: + trunk = filename.split('.')[0] + extension = filename.split('.')[-1] + counter = 0 + + while os.path.isfile(filename): + + # Rename first file to match naming scheme if already exists + if counter == 0: + os.rename(filename, trunk + '_' + str(counter).zfill(4) + '.' + extension) + + # Increment counter and make new filename + counter += 1 + counter_string = str(counter) + filename = trunk + '_' + counter_string.zfill(4) + '.' + extension + + + return filename @@ -220,16 +252,15 @@ def read_brml(path, options=None): return diffractogram -def read_diffractogram(path): +def read_xy(data): - - - with open(path, 'r') as f: + with open(data['path'], 'r') as f: position = 0 current_line = f.readline() - while current_line[0] == '#': + while current_line[0] == '#' or "\'": + find_wavelength(line=current_line, data=data) position = f.tell() current_line = f.readline() @@ -237,7 +268,10 @@ def read_diffractogram(path): diffractogram = pd.read_csv(f, header=None, delim_whitespace=True) - diffractogram.columns = ['2th', 'I'] + if diffractogram.shape[1] == 2: + diffractogram.columns = ['2th', 'I'] + elif diffractogram.shape[1] == 3: + diffractogram.columns = ['2th', 'I', 'sigma'] return diffractogram @@ -245,22 +279,17 @@ def read_diffractogram(path): def read_data(data, options={}): - if data['plot_kind'] == 'beamline': + beamline_extensions = ['mar3450', 'edf', 'cbf'] + file_extension = data['path'].split('.')[-1] - beamline = ['mar3450', 'edf', 'cbf'] - - if data['path'].split('.')[-1] in beamline: - diffractogram = integrate_1d(data=data, options=options) + if file_extension in beamline_extensions: + diffractogram = integrate_1d(data=data, options=options) - else: - diffractogram = read_diffractogram(data['path']) - - elif data['plot_kind'] == 'recx': - diffractogram = read_brml(data['path'], options=options) - - elif data['plot_kind'] == 'image': - diffractogram = get_image_array(data['path']) + elif file_extension == 'brml': + diffractogram = read_brml(path=data['path'], options=options) + elif file_extension in['xy', 'xye']: + diffractogram = read_xy(data['path']) return diffractogram @@ -290,4 +319,50 @@ def load_reflection_table(path): # Set the new modified headers as the headers of reflections.columns = headers - return reflections \ No newline at end of file + return reflections + + + +def translate_wavelengths(diffractogram, wavelength): + + # Translate to CuKalpha + cuka = 1.54059 # Å + + if cuka > wavelength: + max_2th_cuka = 2*np.arcsin(wavelength/cuka) * 180/np.pi + else: + max_2th_cuka = diffractogram['2th'].max() + + diffractogram['2th_cuka'] = np.NAN + + diffractogram['2th_cuka'].loc[diffractogram['2th'] <= max_2th_cuka] = 2*np.arcsin(cuka/wavelength * np.sin((diffractogram['2th']/2) * np.pi/180)) * 180/np.pi + + # Translate to MoKalpha + moka = 0.71073 # Å + + if moka > wavelength: + max_2th_moka = 2*np.arcsin(wavelength/moka) * 180/np.pi + else: + max_2th_moka = diffractogram['2th'].max() + + diffractogram['2th_moka'] = np.NAN + + diffractogram['2th_moka'].loc[diffractogram['2th'] <= max_2th_moka] = 2*np.arcsin(moka/wavelength * np.sin((diffractogram['2th']/2) * np.pi/180)) * 180/np.pi + + + # Convert to other parameters + diffractogram['d'] = wavelength / (2*np.sin(2*diffractogram['2th']) * 180/np.pi) + diffractogram['1/d'] = 1/diffractogram['d'] + diffractogram['q'] = np.abs((4*np.pi/wavelength)*np.sin(diffractogram['2th']/2 * np.pi/180)) + diffractogram['q2'] = diffractogram['q']**2 + diffractogram['q4'] = diffractogram['q']**4 + + + +def find_wavelength(line, data): + + # Find from EVA-exports + wavelength_dict = {'Cu': 1.54059, 'Mo': 0.71073} + + if 'Anode' in line: + \ No newline at end of file diff --git a/beamtime/xrd/plot.py b/beamtime/xrd/plot.py index 7c89c43..9e9ecee 100644 --- a/beamtime/xrd/plot.py +++ b/beamtime/xrd/plot.py @@ -183,11 +183,14 @@ def plot_reflection_indices(data, ax, options={}): reflection_table = xrd.io.load_reflection_table(data['path']) if data['reflection_indices'] > 0: - reflection_indices = reflection_table.nlargest(options['reflection_indices'], 'I') - - for i in range(data['reflection_indices']): - ax.text(s=f'({reflection_indices["h"].iloc[i]} {reflection_indices["k"].iloc[i]} {reflection_indices["l"].iloc[i]})', x=reflection_indices['2th'].iloc[i], y=0, fontsize=2.5, rotation=90, va='bottom', ha='center', c=data['text_colour']) + # Get the data['reflection_indices'] number of highest reflections within the subrange options['xlim'] + reflection_indices = reflection_table.loc[(reflection_table[options['x_vals']] > options['xlim'][0]) & (reflection_table[options['x_vals']] < options['xlim'][1])].nlargest(options['reflection_indices'], 'I') + + # Plot the indices + for i in range(data['reflection_indices']): + if reflection_indices.shape[0] > i: + ax.text(s=f'({reflection_indices["h"].iloc[i]} {reflection_indices["k"].iloc[i]} {reflection_indices["l"].iloc[i]})', x=reflection_indices[options['x_vals']].iloc[i], y=0, fontsize=2.5, rotation=90, va='bottom', ha='center', c=data['text_colour']) if options['xlim']: