Laue diffraction peak identification
The dataset used has been recorded at ESRF ID09 in 2022 with an energy of 17keV andd 1.7% bandpass. This is a small fragment of the experiment ch6495
performed by Dominik Schaniel (univ-lorraine.fr) helped by Marco Cammarata (local contact) The sample is a single crystal of iron complex (thus a small molecule).
Data files are available from: http://www.silx.org/pub/pyFAI/laue/
[1]:
from silx.resources import ExternalResources
#Nota: Useful to configure a proxy if you are behind a firewall
#os.environ["http_proxy"] = "http://proxy.company.fr:3128"
downloader = ExternalResources("laue", "http://www.silx.org/pub/pyFAI/laue/")
poni = downloader.getfile("detx_50mm_2.poni")
maskfile = downloader.getfile("mask.npy")
datafile = downloader.getfile("SNP_220K_21/SNP_220K_21_0002/scan0001/rayonix_0018.h5")
[2]:
import numpy
import pyFAI
import fabio
print(f"PyFAI version {pyFAI.version}")
PyFAI version 2024.9.0-dev0
[3]:
%matplotlib inline
# use `widget` instead of `inline` for better user-exeperience. `inline` allows to store plots into notebooks.
from matplotlib.pyplot import subplots
[4]:
from pyFAI.gui import jupyter
mask = fabio.open(maskfile).data
jupyter.display(mask, label="Mask")
pass
[5]:
data = fabio.open(datafile).data
fig, ax = subplots(figsize=(8,8))
jupyter.display(data, label="Last frame", ax=ax)
[5]:
<Axes: title={'center': 'Last frame'}>
Generate an azimuthal integrator, integrate and look at the background:
[6]:
npt = 512
error_model = "azimuth"
unit = "q_nm^-1"
ai = pyFAI.load(poni)
ai.detector.set_mask(mask)
print(ai)
Detector Rayonix MX170 PixelSize= 8.854e-05, 8.854e-05 m BottomRight (3)
Wavelength= 7.306081e-11 m
SampleDetDist= 4.928280e-02 m PONI= 8.602623e-02, 8.526832e-02 m rot1=0.000000 rot2=0.000000 rot3=0.000000 rad
DirectBeamDist= 49.283 mm Center: x=963.030, y=971.590 pix Tilt= 0.000° tiltPlanRotation= 0.000° 𝛌= 0.731Å
[7]:
it = ai.integrate1d(data, npt, unit=unit)
sc = ai.sigma_clip_ng(data, npt, error_model=error_model, unit=unit)
fig, ax = subplots(figsize=(10,8))
jupyter.plot1d(sc, label="sigma-clipping", ax=ax)
jupyter.plot1d(it, label="integration", ax=ax)
pass
Peak finding
This requires an OpenCL device, a GPU for best performances.
[8]:
from pyFAI.opencl.peak_finder import OCL_PeakFinder
engine = ai.setup_sparse_integrator(data.shape, npt, mask, unit=unit, split="no")
radius2d = ai.array_from_unit(data.shape, unit=unit)
pf = OCL_PeakFinder(engine.lut, data.size,
unit=unit,
bin_centers=engine.bin_centers,
radius=radius2d,
mask = mask)
[9]:
# The default parameters for the peakfinder are tuned for protein crystallography. Here peaks are much larger.
peaks = pf.peakfinder(data, error_model=error_model, patch_size=15, connected=15)
%timeit pf.peakfinder(data, error_model=error_model, patch_size=15, connected=15)
print(len(peaks))
peaks[:10]
21.2 ms ± 578 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)
131
[9]:
array([(2757305, 12326.779 , 184.56905 , 1436.2598 , 184.94702),
( 633832, 9462.711 , 170.47388 , 328.65286, 229.8383 ),
(1538207, 3261.6282, 103.686165, 801.0311 , 286.42944),
(3588792, 10536.642 , 76.822266, 1869.264 , 311.29846),
( 701196, 27166.893 , 264.11288 , 363.5771 , 394.54123),
(1052559, 54561.062 , 318.79062 , 547.92084, 397.61136),
(2571265, 5767.143 , 186.48306 , 1338.468 , 384.62204),
( 401725, 4898.5884, 227.50903 , 208.83492, 444.75378),
( 543776, 10289.169 , 241.31569 , 281.41272, 414.67313),
(1830199, 648705.75 , 399.308 , 953.9367 , 438.95844)],
dtype=[('index', '<i4'), ('intensity', '<f4'), ('sigma', '<f4'), ('pos0', '<f4'), ('pos1', '<f4')])
[10]:
#overlay peaks with image
fig, ax = subplots(figsize=(8,8))
jupyter.display(data, label="Peaks", ax=ax)
ax.plot(peaks["pos1"],peaks["pos0"], "2g")
pass
Conclusion
Peak position can easily be extracted for single crystal experiment at speed compatible with real-time data analysis.