Source code for epdfsuite.calibration

from pymatgen.core import Structure
from pymatgen.analysis.diffraction.xrd import XRDCalculator
from .filereader import load_data
import fabio
import os
import sys

[docs] def build_calibration_data_from_cif( cif_file, wavelength, n_peaks=15, two_theta_range=(0, 2) ): """ Generate a list of diffraction peaks from a CIF structure file. Uses pymatgen's XRD calculator to compute the simulated diffraction pattern, then exports the d-spacings to a text file (``distances.txt``) for use by pyFAI-calib2. Parameters ---------- cif_file : str Path to the CIF structure file. wavelength : float Electron (or X-ray) wavelength in Å. n_peaks : int, optional Maximum number of peaks to return. Default is 15. two_theta_range : tuple of float, optional Angular range in degrees ``(2θ_min, 2θ_max)`` used to filter peaks. Default is ``(0, 2)``. Returns ------- peaks : list of dict Each element contains: - ``'hkl'``: Miller indices - ``'d'``: d-spacing in Å - ``'two_theta'``: Bragg angle in degrees - ``'intensity'``: relative intensity """ # Lecture de la structure structure = Structure.from_file(cif_file) # Calculateur XRD xrd = XRDCalculator(wavelength=wavelength) pattern = xrd.get_pattern(structure, two_theta_range=two_theta_range) peaks = [] for i in range(min(n_peaks, len(pattern.x))): peaks.append({ "hkl": pattern.hkls[i][0]["hkl"], "d": pattern.d_hkls[i], "two_theta": pattern.x[i], "intensity": pattern.y[i] }) line2write='' for p in peaks: line2write += str(p['d'])+'\n' with open('./distances.txt','w') as f: f.write(line2write) return peaks
[docs] def perform_geometric_calibration( cif_file: str, image_file: str, mtf_file: str = None): """ Perform geometric calibration of electron diffraction data using pyFAI-calib2. Exports the image as a temporary EDF file, optionally applies MTF deconvolution, computes calibrant d-spacings from the CIF, prints the instrument settings to enter in pyFAI-calib2, and launches the calibration GUI. Parameters ---------- cif_file : str Path to the CIF structure file of the calibrant. image_file : str Path to the DM4 image file of the calibrant diffraction pattern. mtf_file : str, optional Path to the MTF file. If provided, Wiener deconvolution is applied to the image before calibration. """ # load data and metadata detector_info, raw_image = load_data(image_file) if mtf_file is not None: # apply MTF deconvolution to raw image from .utilities import deconvolve_mtf_2d raw_image = deconvolve_mtf_2d(raw_image, mtf_file) # Define output EDF file name edffile = image_file.replace('.dm4', '.edf') # Create EDF image and save edf_image = fabio.edfimage.EdfImage(data=raw_image, header=detector_info) edf_image.write(edffile) # Create distance files for use in pyFAI-calib2 peaks = build_calibration_data_from_cif( cif_file, wavelength=detector_info['wavelength'], n_peaks=10) print("=" * 70) print('EXPERIMENT SETTINGS TO INPUT IN PYFAI-CALIB2:') print('='*70) print(f'Camera description={detector_info["description"]}') print(f'pixel_size_x={detector_info["pixel_size"]}X{detector_info["pixel_size"]}') # in µmeters print(f'image dimension={detector_info["image_width"]}X{detector_info["image_height"]}') # in pixels print(f'Electron wavelength={detector_info["wavelength"]} Å') print('=' * 70 ) print('Launching pyFAI-calib2') os.system(f'"{sys.executable}" -m pyFAI.app.calib2 -c ./distances.txt {edffile}') # Clean up distance file and edf file os.remove(edffile) os.remove('./distances.txt')
[docs] def get_calibration_parameters(poni_file: str): """ Extract calibration parameters from a PONI file generated by pyFAI-calib2. Parameters ---------- poni_file : str Path to the PONI file produced after calibration. Returns ------- calibration_params : dict Dictionary containing the following keys (when present in the file): - ``'distance'``: sample-to-detector distance (m) - ``'poni1'``, ``'poni2'``: point of normal incidence coordinates (m) - ``'rot1'``, ``'rot2'``, ``'rot3'``: detector rotation angles (rad) - ``'wavelength'``: wavelength (m) - ``'pixel1'``, ``'pixel2'``: pixel sizes (m) - ``'max_shape'``: detector shape in pixels """ import json calibration_params = {} if not os.path.exists(poni_file): raise FileNotFoundError(f"Fichier PONI non trouvé: {poni_file}") with open(poni_file, 'r') as f: lines = f.readlines() for line in lines: if line.startswith('Distance:'): calibration_params['distance'] = float(line.split(':')[1].strip()) elif line.startswith('Poni1:'): calibration_params['poni1'] = float(line.split(':')[1].strip()) elif line.startswith('Poni2:'): calibration_params['poni2'] = float(line.split(':')[1].strip()) elif line.startswith('Rot1:'): calibration_params['rot1'] = float(line.split(':')[1].strip()) elif line.startswith('Rot2:'): calibration_params['rot2'] = float(line.split(':')[1].strip()) elif line.startswith('Rot3:'): calibration_params['rot3'] = float(line.split(':')[1].strip()) elif line.startswith('Wavelength:'): calibration_params['wavelength'] = float(line.split(':')[1].strip()) elif line.startswith('Detector_config:'): config_str = line.split(':', 1)[1].strip() config = json.loads(config_str) calibration_params['pixel1'] = config.get('pixel1', None) calibration_params['pixel2'] = config.get('pixel2', None) calibration_params['max_shape'] = config.get('max_shape', None) return calibration_params