xrayscatteringtools 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xrayscatteringtools/__init__.py +3 -0
- xrayscatteringtools/calib/__init__.py +0 -0
- xrayscatteringtools/calib/geometry_calibration.py +204 -0
- xrayscatteringtools/calib/scattering_corrections.py +488 -0
- xrayscatteringtools/epicsArch.py +392 -0
- xrayscatteringtools/io.py +310 -0
- xrayscatteringtools/plotting.py +88 -0
- xrayscatteringtools/theory/Compton_Factors.npy +0 -0
- xrayscatteringtools/theory/Scattering_Factors.npy +0 -0
- xrayscatteringtools/theory/__init__.py +1 -0
- xrayscatteringtools/theory/data/sf6.h5 +0 -0
- xrayscatteringtools/theory/iam.py +213 -0
- xrayscatteringtools/theory/patterns.py +36 -0
- xrayscatteringtools/utils.py +456 -0
- xrayscatteringtools-0.0.1.dist-info/METADATA +79 -0
- xrayscatteringtools-0.0.1.dist-info/RECORD +18 -0
- xrayscatteringtools-0.0.1.dist-info/WHEEL +4 -0
- xrayscatteringtools-0.0.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from IPython import get_ipython
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
def enable_underscore_cleanup():
|
|
6
|
+
"""
|
|
7
|
+
Register a Jupyter Notebook post-cell hook to automatically delete user-defined
|
|
8
|
+
single-underscore variables after each cell execution.
|
|
9
|
+
|
|
10
|
+
Notes
|
|
11
|
+
-----
|
|
12
|
+
This helps keep the notebook namespace clean by removing temporary variables
|
|
13
|
+
that start with a single underscore (`_`) but are not standard IPython variables
|
|
14
|
+
(like `_i`, `_oh`, etc.) or Python "dunder" variables.
|
|
15
|
+
"""
|
|
16
|
+
ipython = get_ipython()
|
|
17
|
+
user_ns = ipython.user_ns # This gives you access to the Jupyter notebook namespace
|
|
18
|
+
|
|
19
|
+
def clean_user_underscore_vars(*args, **kwargs):
|
|
20
|
+
def is_user_defined_underscore(var):
|
|
21
|
+
return (
|
|
22
|
+
var.startswith('_')
|
|
23
|
+
and not re.match(r'^_i\d*$|^_\d*$|^_ih$|^_oh$|^_ii*$|^_iii$|^_dh$|^_$', var)
|
|
24
|
+
and not var.startswith('__')
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
for var in list(user_ns):
|
|
28
|
+
if is_user_defined_underscore(var):
|
|
29
|
+
del user_ns[var]
|
|
30
|
+
|
|
31
|
+
ipython.events.register('post_run_cell', clean_user_underscore_vars)
|
|
32
|
+
|
|
33
|
+
def azimuthalBinning(
|
|
34
|
+
img,
|
|
35
|
+
x,
|
|
36
|
+
y,
|
|
37
|
+
x0 = 0,
|
|
38
|
+
y0 = 0,
|
|
39
|
+
z0 = 90000,
|
|
40
|
+
tx = 0,
|
|
41
|
+
ty = 0,
|
|
42
|
+
keV = 10,
|
|
43
|
+
pPlane = 0,
|
|
44
|
+
threshADU = [0,np.inf],
|
|
45
|
+
threshRMS = None,
|
|
46
|
+
mask = None,
|
|
47
|
+
qBin = 0.05,
|
|
48
|
+
rBin = None,
|
|
49
|
+
phiBins = 1,
|
|
50
|
+
geomCorr = True,
|
|
51
|
+
polCorr = True,
|
|
52
|
+
darkImg = None,
|
|
53
|
+
gainImg = None,
|
|
54
|
+
z_off = 0,
|
|
55
|
+
square = False,
|
|
56
|
+
debug = False
|
|
57
|
+
):
|
|
58
|
+
"""Performs azimuthal binning of a 2D image.
|
|
59
|
+
|
|
60
|
+
This function integrates a 2D detector image into a 1D profile as a
|
|
61
|
+
function of a radial coordinate (either momentum transfer 'q' or
|
|
62
|
+
real-space radius 'r'). It can perform this integration in multiple
|
|
63
|
+
azimuthal sectors ('phi'). The geometry of the setup, including detector
|
|
64
|
+
distance, tilt, and beam center, is taken into account. Optional
|
|
65
|
+
corrections for polarization are also provided.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
img : np.ndarray
|
|
70
|
+
The input image data to be binned.
|
|
71
|
+
x, y : np.ndarray
|
|
72
|
+
Arrays of the same shape as `img` representing the pixel
|
|
73
|
+
x and y coordinates. Default for Jungfrau4M is in micron.
|
|
74
|
+
x0, y0 : float
|
|
75
|
+
x and y-coordinates of the beam center in detector coordinates (J4M: micron). Default is 0.
|
|
76
|
+
z0 : float
|
|
77
|
+
Sample-to-detector distance in detector coordinates (J4M: micron). Default is 90000.
|
|
78
|
+
tx, ty : float, optional
|
|
79
|
+
Detector tilt angles around the y and x axes, respectively, in degrees.
|
|
80
|
+
Default is 0.
|
|
81
|
+
kev : float, optional
|
|
82
|
+
Photon energy of the incident beam in keV. Required for q-space
|
|
83
|
+
binning. Default is 10.
|
|
84
|
+
p_plane : {0, 1}, optional
|
|
85
|
+
The polarization plane of the incident beam.
|
|
86
|
+
1 for vertical polarization, 0 for horizontal. Default is 0.
|
|
87
|
+
threshADU : tuple(float, float), optional
|
|
88
|
+
(min, max) threshold in ADU. Pixel values outside this range are
|
|
89
|
+
set to 0 for the binning calculation. Default is (0, np.inf).
|
|
90
|
+
threshRMS : float, optional
|
|
91
|
+
RMS threshold. Pixel values above this are set to 0. Default is None.
|
|
92
|
+
mask : np.ndarray, optional
|
|
93
|
+
A boolean or integer array of the same shape as `img`. A value of
|
|
94
|
+
True or 1 indicates a pixel to be excluded from the analysis. If none,
|
|
95
|
+
no pixels are excluded. Default is None.
|
|
96
|
+
qBin : float or array_like, optional
|
|
97
|
+
If a float, it's the size of each q-bin in inverse Angstroms (Å⁻¹).
|
|
98
|
+
If an array, it specifies the bin edges for non-uniform binning.
|
|
99
|
+
This parameter is ignored if `r_bin` is specified. Default is 0.05 Å⁻¹.
|
|
100
|
+
rBin : float or array_like, optional
|
|
101
|
+
If specified, binning is performed in real-space radius 'r' (in pixels)
|
|
102
|
+
instead of q-space. If a float, it is the bin size. If an array,
|
|
103
|
+
it specifies the bin edges. Default is None.
|
|
104
|
+
phiBins : int or array_like, optional
|
|
105
|
+
If an int, it's the number of uniform azimuthal bins.
|
|
106
|
+
If an array, it specifies the bin edges in radians for non-uniform
|
|
107
|
+
azimuthal sectors. Default is 1 (no azimuthal binning).
|
|
108
|
+
geom_corr : bool, optional
|
|
109
|
+
If True, apply a geometric (solid angle) correction. Default is True.
|
|
110
|
+
pol_corr : bool, optional
|
|
111
|
+
If True, apply a polarization (Thompson) correction. Default is True.
|
|
112
|
+
dark_img : np.ndarray, optional
|
|
113
|
+
A dark image to be subtracted from `img`. Default is None.
|
|
114
|
+
gain_img : np.ndarray, optional
|
|
115
|
+
A gain/flat-field image to divide `img` by. Default is None.
|
|
116
|
+
z_off : float or np.ndarray, optional
|
|
117
|
+
An additional offset along the beam direction (z-axis) in pixels.
|
|
118
|
+
Default is 0.
|
|
119
|
+
square : bool, optional
|
|
120
|
+
If True, the image is squared before binning. Default is False.
|
|
121
|
+
debug : bool, optional
|
|
122
|
+
If True, print debugging information. Default is False.
|
|
123
|
+
|
|
124
|
+
Returns
|
|
125
|
+
-------
|
|
126
|
+
radial_centers : np.ndarray
|
|
127
|
+
1D array of the center values for each radial bin (either q in Å⁻¹
|
|
128
|
+
or r in detector coordinates (J4M: micron).
|
|
129
|
+
azimuthal_average : np.ndarray
|
|
130
|
+
The binned data. A 2D array of shape (`n_phi_bins`, `n_radial_bins`)
|
|
131
|
+
or a 1D array if `phi_bins` is 1.
|
|
132
|
+
|
|
133
|
+
Notes
|
|
134
|
+
-----
|
|
135
|
+
- The geometric and angular calculations are based on the methodology
|
|
136
|
+
described in J. Chem. Phys. 113, 9140 (2000).
|
|
137
|
+
- The function preserves the original's specific, non-standard behavior
|
|
138
|
+
of placing pixels that fall outside the defined bin ranges into the
|
|
139
|
+
first bin.
|
|
140
|
+
- The normalization (pixel count per bin) includes all pixels, but the
|
|
141
|
+
intensity summation only includes unmasked pixels. This matches the
|
|
142
|
+
original's logic but may affect the normalization of the first bin if
|
|
143
|
+
a mask is used, as masked pixels are assigned to bin 0 for the count.
|
|
144
|
+
|
|
145
|
+
Examples
|
|
146
|
+
--------
|
|
147
|
+
>>> radial_centers, azimuthal_average = azimuthalBinning(img, x, y)
|
|
148
|
+
>>> radial_centers, azimuthal_average = azimuthalBinning(img, x, y, x0=100, y0=150, z0=95000, keV=12.7, qBin=0.02, phiBins=8)
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
# --- 1. Image Preprocessing ---
|
|
152
|
+
# Apply dark and gain corrections if provided
|
|
153
|
+
if darkImg is not None:
|
|
154
|
+
img = img - darkImg
|
|
155
|
+
if gainImg is not None:
|
|
156
|
+
img = img / gainImg
|
|
157
|
+
if square:
|
|
158
|
+
img = img ** 2
|
|
159
|
+
threshold_mask = (img < threshADU[0]) | (img > threshADU[1])
|
|
160
|
+
if threshRMS is not None:
|
|
161
|
+
threshold_mask |= (img > threshRMS)
|
|
162
|
+
if mask is None:
|
|
163
|
+
mask = np.zeros_like(img, dtype=bool)
|
|
164
|
+
|
|
165
|
+
# --- 2. Geometric Transformations ---
|
|
166
|
+
tx_rad, ty_rad = np.deg2rad(tx), np.deg2rad(ty)
|
|
167
|
+
z_total = z0 + z_off
|
|
168
|
+
|
|
169
|
+
# Geometric parameters from J Chem Phys 113, 9140 (2000)
|
|
170
|
+
A = -np.sin(ty_rad) * np.cos(tx_rad)
|
|
171
|
+
B = -np.sin(tx_rad)
|
|
172
|
+
C = -np.cos(ty_rad) * np.cos(tx_rad)
|
|
173
|
+
a = x0 + z_total * np.tan(ty_rad)
|
|
174
|
+
b = y0 - z_total * np.tan(tx_rad)
|
|
175
|
+
c = z_total
|
|
176
|
+
|
|
177
|
+
# Transforming (x,y) to r, theta, phi
|
|
178
|
+
r = np.sqrt((x - a) ** 2 + (y - b) ** 2 + c ** 2)
|
|
179
|
+
matrix_theta = np.arccos((A * (x - a) + B * (y - b) - C * c) / r)
|
|
180
|
+
with np.errstate(invalid='ignore'):
|
|
181
|
+
matrix_phi = np.arccos(
|
|
182
|
+
((A**2 + C**2) * (y - b) - A * B * (x - a) + B * C * c)
|
|
183
|
+
/ np.sqrt((A**2 + C**2) * (r**2 - (A * (x - a) + B * (y - b) - C * c) ** 2))
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
# Correct NaN values and wrap phi to [0, 2pi]
|
|
187
|
+
matrix_phi[(y >= y0) & (np.isnan(matrix_phi))] = 0
|
|
188
|
+
matrix_phi[(y < y0) & (np.isnan(matrix_phi))] = np.pi
|
|
189
|
+
matrix_phi[x < x0] = 2 * np.pi - matrix_phi[x < x0]
|
|
190
|
+
|
|
191
|
+
# --- 3 Correction Factor Calculations ---
|
|
192
|
+
# Default to ones if no correction is applied
|
|
193
|
+
geom_correction = np.ones_like(img, dtype=float)
|
|
194
|
+
pol_correction = np.ones_like(img, dtype=float)
|
|
195
|
+
|
|
196
|
+
if geomCorr:
|
|
197
|
+
# Solid angle correction.
|
|
198
|
+
geom_correction = (z_total / r**3)
|
|
199
|
+
geom_correction /= np.nanmax(geom_correction)
|
|
200
|
+
|
|
201
|
+
if polCorr:
|
|
202
|
+
# Polarization or Thompson correction. This is a mixing term, not just a pure polarization correction.
|
|
203
|
+
Pout = 1 - pPlane
|
|
204
|
+
pol_correction = Pout * (
|
|
205
|
+
1 - (np.sin(matrix_phi) * np.sin(matrix_theta)) ** 2
|
|
206
|
+
) + pPlane * (1 - (np.cos(matrix_phi) * np.sin(matrix_theta)) ** 2)
|
|
207
|
+
|
|
208
|
+
correction = geom_correction * pol_correction
|
|
209
|
+
|
|
210
|
+
# --- 4. Binning Setup ---
|
|
211
|
+
# Azimuthal, (phi) binning
|
|
212
|
+
if isinstance(phiBins, (list, np.ndarray)):
|
|
213
|
+
phi_edges = np.sort(np.asarray(phiBins))
|
|
214
|
+
# Ensure range is fully covered for dgitization
|
|
215
|
+
if phi_edges.max() < (2 * np.pi - 0.01):
|
|
216
|
+
phi_edges = np.append(phi_edges, phi_edges.max() + 0.001)
|
|
217
|
+
if phi_edges.min() > 0:
|
|
218
|
+
phi_edges = np.insert(phi_edges, 0, phi_edges.min() - 0.001)
|
|
219
|
+
n_phi_bins = len(phi_edges) - 1
|
|
220
|
+
else:
|
|
221
|
+
n_phi_bins = phiBins
|
|
222
|
+
phi_min, phi_max = np.nanmin(matrix_phi), np.nanmax(matrix_phi)
|
|
223
|
+
phi_edges = np.linspace(phi_min, phi_max, n_phi_bins + 1)
|
|
224
|
+
|
|
225
|
+
# Radial (q or r) binning
|
|
226
|
+
if rBin is not None:
|
|
227
|
+
# Binning in real-space radius (r)
|
|
228
|
+
radial_map = np.sqrt((x - x0) ** 2 + (y - y0) ** 2)
|
|
229
|
+
r_min = np.nanmin(radial_map[~mask])
|
|
230
|
+
r_max = np.nanmax(radial_map[~mask])
|
|
231
|
+
|
|
232
|
+
if np.isscalar (rBin):
|
|
233
|
+
if debug: print("r-bin size given: rmax: ", r_max, " rBin ", rBin)
|
|
234
|
+
radial_edges = np.arange(r_min - rBin, r_max + rBin, rBin)
|
|
235
|
+
else:
|
|
236
|
+
radial_edges = np.asarray(rBin)
|
|
237
|
+
radial_centers = (radial_edges[:-1] + radial_edges[1:]) / 2
|
|
238
|
+
n_radial_bins = len(radial_centers)
|
|
239
|
+
else:
|
|
240
|
+
# Binning in reciprocal space (q)
|
|
241
|
+
lam = keV2Angstroms(keV)
|
|
242
|
+
radial_map = 4 * np.pi / lam * np.sin(matrix_theta / 2)
|
|
243
|
+
q_min = np.nanmin(radial_map[~mask])
|
|
244
|
+
q_max = np.nanmax(radial_map[~mask])
|
|
245
|
+
|
|
246
|
+
if np.isscalar(qBin):
|
|
247
|
+
if debug: print("q-bin size given: qmax: ", q_max, " qBin ", qBin)
|
|
248
|
+
radial_edges = np.arange(0, q_max + qBin, qBin)
|
|
249
|
+
else:
|
|
250
|
+
radial_edges = np.asarray(qBin)
|
|
251
|
+
radial_centers = (radial_edges[:-1] + radial_edges[1:]) / 2
|
|
252
|
+
n_radial_bins = len(radial_centers)
|
|
253
|
+
|
|
254
|
+
# --- 5. Binning Assignment ---
|
|
255
|
+
# Shift phi map slightly to handle edge cases
|
|
256
|
+
phi_step = (phi_edges[1] - phi_edges[0]) / 2 if len(phi_edges) > 1 else 0
|
|
257
|
+
phi_shifted = (matrix_phi + phi_step) % (2 * np.pi)
|
|
258
|
+
|
|
259
|
+
phi_indices = np.digitize(phi_shifted.ravel(), phi_edges) - 1
|
|
260
|
+
radial_indices = np.digitize(radial_map.ravel(), radial_edges) - 1
|
|
261
|
+
|
|
262
|
+
# Overflow/Underflow handling: put out-of-bounds into first bin
|
|
263
|
+
phi_indices[phi_indices < 0] = 0
|
|
264
|
+
phi_indices[phi_indices >= n_phi_bins] = 0
|
|
265
|
+
radial_indices[mask.ravel()] = 0
|
|
266
|
+
|
|
267
|
+
# --- 6. Binning and Normalization ---
|
|
268
|
+
# Create a signle 1D index for each pixels (phi, radial) combination
|
|
269
|
+
total_bins = n_phi_bins * n_radial_bins
|
|
270
|
+
combined_indices = np.ravel_multi_index((phi_indices, radial_indices), (n_phi_bins, n_radial_bins))
|
|
271
|
+
|
|
272
|
+
indicies_for_norm = combined_indices.copy()
|
|
273
|
+
indicies_for_norm[mask.ravel()] = 0 # Masked pixels go to first bin
|
|
274
|
+
pixel_counts = np.bincount(indicies_for_norm, minlength=total_bins)
|
|
275
|
+
norm_map = np.reshape(pixel_counts, (n_phi_bins, n_radial_bins))
|
|
276
|
+
|
|
277
|
+
# Prep data for intensity summation, excluding masked and thresholded pixels
|
|
278
|
+
final_mask = mask.ravel() | threshold_mask.ravel()
|
|
279
|
+
valid_pixels = ~final_mask
|
|
280
|
+
|
|
281
|
+
valid_indices = combined_indices[valid_pixels]
|
|
282
|
+
valid_img = img.ravel()[valid_pixels]
|
|
283
|
+
valid_correction = correction.ravel()[valid_pixels]
|
|
284
|
+
|
|
285
|
+
# Calculate the sum of corrected intensities in each bin
|
|
286
|
+
summed_intensity = np.bincount(
|
|
287
|
+
valid_indices,
|
|
288
|
+
weights=valid_img / valid_correction,
|
|
289
|
+
minlength=total_bins,
|
|
290
|
+
)
|
|
291
|
+
intensity_map = np.reshape(summed_intensity, (n_phi_bins, n_radial_bins))
|
|
292
|
+
|
|
293
|
+
# Calculate the final azimuthal average
|
|
294
|
+
with np.errstate(invalid='ignore', divide='ignore'):
|
|
295
|
+
azimuthal_average = intensity_map / norm_map
|
|
296
|
+
|
|
297
|
+
return np.squeeze(radial_centers), np.squeeze(azimuthal_average)
|
|
298
|
+
|
|
299
|
+
def keV2Angstroms(keV):
|
|
300
|
+
"""
|
|
301
|
+
Convert photon energy from keV to wavelength in Angstroms.
|
|
302
|
+
|
|
303
|
+
Parameters
|
|
304
|
+
----------
|
|
305
|
+
keV : float
|
|
306
|
+
Photon energy in kilo-electron volts.
|
|
307
|
+
|
|
308
|
+
Returns
|
|
309
|
+
-------
|
|
310
|
+
float
|
|
311
|
+
Corresponding wavelength in Angstroms.
|
|
312
|
+
|
|
313
|
+
Notes
|
|
314
|
+
-----
|
|
315
|
+
Uses the relation λ(Å) = 12.39841984 / E(keV).
|
|
316
|
+
"""
|
|
317
|
+
return 12.39841984/keV
|
|
318
|
+
|
|
319
|
+
def Angstroms2keV(angstroms):
|
|
320
|
+
"""
|
|
321
|
+
Convert wavelength in Angstroms to photon energy in keV.
|
|
322
|
+
|
|
323
|
+
Parameters
|
|
324
|
+
----------
|
|
325
|
+
angstroms : float
|
|
326
|
+
Wavelength in Angstroms.
|
|
327
|
+
|
|
328
|
+
Returns
|
|
329
|
+
-------
|
|
330
|
+
float
|
|
331
|
+
Photon energy in kilo-electron volts.
|
|
332
|
+
|
|
333
|
+
Notes
|
|
334
|
+
-----
|
|
335
|
+
Uses the relation E(keV) = 12.39841984 / λ(Å).
|
|
336
|
+
"""
|
|
337
|
+
return 12.39841984/angstroms
|
|
338
|
+
|
|
339
|
+
def q2theta(q, keV):
|
|
340
|
+
"""
|
|
341
|
+
Convert momentum transfer q to scattering angle theta in radians.
|
|
342
|
+
|
|
343
|
+
Parameters
|
|
344
|
+
----------
|
|
345
|
+
q : float or array-like
|
|
346
|
+
Momentum transfer in inverse Angstroms (Å⁻¹).
|
|
347
|
+
keV : float
|
|
348
|
+
Photon energy in keV.
|
|
349
|
+
|
|
350
|
+
Returns
|
|
351
|
+
-------
|
|
352
|
+
float or array-like
|
|
353
|
+
Scattering angle θ in radians.
|
|
354
|
+
|
|
355
|
+
Notes
|
|
356
|
+
-----
|
|
357
|
+
Uses the relation θ = 2 * arcsin(q * λ / (4π)), where λ is the photon
|
|
358
|
+
wavelength corresponding to the given energy.
|
|
359
|
+
"""
|
|
360
|
+
return 2 * np.arcsin(q * keV2Angstroms(keV) / (4 * np.pi))
|
|
361
|
+
|
|
362
|
+
def theta2q(theta, keV):
|
|
363
|
+
"""
|
|
364
|
+
Convert scattering angle theta in radians to momentum transfer q.
|
|
365
|
+
|
|
366
|
+
Parameters
|
|
367
|
+
----------
|
|
368
|
+
theta : float or array-like
|
|
369
|
+
Scattering angle in radians.
|
|
370
|
+
keV : float
|
|
371
|
+
Photon energy in keV.
|
|
372
|
+
|
|
373
|
+
Returns
|
|
374
|
+
-------
|
|
375
|
+
float or array-like
|
|
376
|
+
Momentum transfer q in inverse Angstroms (Å⁻¹).
|
|
377
|
+
|
|
378
|
+
Notes
|
|
379
|
+
-----
|
|
380
|
+
Uses the relation q = (4π / λ) * sin(θ / 2), where λ is the photon wavelength
|
|
381
|
+
corresponding to the given energy.
|
|
382
|
+
"""
|
|
383
|
+
return 4 * np.pi / keV2Angstroms(keV) * np.sin(theta / 2)
|
|
384
|
+
|
|
385
|
+
ELEMENT_NUMBERS = {
|
|
386
|
+
"H": 1, "He": 2, "Li": 3, "Be": 4, "B": 5,
|
|
387
|
+
"C": 6, "N": 7, "O": 8, "F": 9, "Ne": 10,
|
|
388
|
+
"Na": 11, "Mg": 12, "Al": 13, "Si": 14, "P": 15,
|
|
389
|
+
"S": 16, "Cl": 17, "Ar": 18, "K": 19, "Ca": 20,
|
|
390
|
+
"Sc": 21, "Ti": 22, "V": 23, "Cr": 24, "Mn": 25,
|
|
391
|
+
"Fe": 26, "Co": 27, "Ni": 28, "Cu": 29, "Zn": 30,
|
|
392
|
+
"Ga": 31, "Ge": 32, "As": 33, "Se": 34, "Br": 35,
|
|
393
|
+
"Kr": 36, "Rb": 37, "Sr": 38, "Y": 39, "Zr": 40,
|
|
394
|
+
"Nb": 41, "Mo": 42, "Tc": 43, "Ru": 44, "Rh": 45,
|
|
395
|
+
"Pd": 46, "Ag": 47, "Cd": 48, "In": 49, "Sn": 50,
|
|
396
|
+
"Sb": 51, "Te": 52, "I": 53, "Xe": 54, "Cs": 55,
|
|
397
|
+
"Ba": 56, "La": 57, "Ce": 58, "Pr": 59, "Nd": 60,
|
|
398
|
+
"Pm": 61, "Sm": 62, "Eu": 63, "Gd": 64, "Tb": 65,
|
|
399
|
+
"Dy": 66, "Ho": 67, "Er": 68, "Tm": 69, "Yb": 70,
|
|
400
|
+
"Lu": 71, "Hf": 72, "Ta": 73, "W": 74, "Re": 75,
|
|
401
|
+
"Os": 76, "Ir": 77, "Pt": 78, "Au": 79, "Hg": 80,
|
|
402
|
+
"Tl": 81, "Pb": 82, "Bi": 83, "Po": 84, "At": 85,
|
|
403
|
+
"Rn": 86, "Fr": 87, "Ra": 88, "Ac": 89, "Th": 90,
|
|
404
|
+
"Pa": 91, "U": 92, "Np": 93, "Pu": 94, "Am": 95,
|
|
405
|
+
"Cm": 96, "Bk": 97, "Cf": 98, "Es": 99, "Fm": 100,
|
|
406
|
+
"Md": 101, "No": 102, "Lr": 103, "Rf": 104, "Db": 105,
|
|
407
|
+
"Sg": 106, "Bh": 107, "Hs": 108, "Mt": 109, "Ds": 110,
|
|
408
|
+
"Rg": 111, "Cn": 112, "Nh": 113, "Fl": 114, "Mc": 115,
|
|
409
|
+
"Lv": 116, "Ts": 117, "Og": 118
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
ELEMENT_SYMBOLS = {v: k for k, v in ELEMENT_NUMBERS.items()}
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def element_symbol_to_number(symbol: str) -> int:
|
|
416
|
+
"""
|
|
417
|
+
Convert an element symbol (e.g. 'O') to its atomic number (e.g. 8).
|
|
418
|
+
|
|
419
|
+
Parameters
|
|
420
|
+
----------
|
|
421
|
+
symbol : str
|
|
422
|
+
The element symbol, case-sensitive (e.g. 'H', 'He', 'Fe').
|
|
423
|
+
|
|
424
|
+
Returns
|
|
425
|
+
-------
|
|
426
|
+
int
|
|
427
|
+
Atomic number of the element.
|
|
428
|
+
|
|
429
|
+
Raises
|
|
430
|
+
------
|
|
431
|
+
KeyError
|
|
432
|
+
If the symbol is not valid.
|
|
433
|
+
"""
|
|
434
|
+
return ELEMENT_NUMBERS[symbol]
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def element_number_to_symbol(number: int) -> str:
|
|
438
|
+
"""
|
|
439
|
+
Convert an atomic number (e.g. 8) to its element symbol (e.g. 'O').
|
|
440
|
+
|
|
441
|
+
Parameters
|
|
442
|
+
----------
|
|
443
|
+
number : int
|
|
444
|
+
The atomic number (1 to 118).
|
|
445
|
+
|
|
446
|
+
Returns
|
|
447
|
+
-------
|
|
448
|
+
str
|
|
449
|
+
Element symbol.
|
|
450
|
+
|
|
451
|
+
Raises
|
|
452
|
+
------
|
|
453
|
+
KeyError
|
|
454
|
+
If the atomic number is not valid.
|
|
455
|
+
"""
|
|
456
|
+
return ELEMENT_SYMBOLS[number]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xrayscatteringtools
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A library for gas phase analysis at the CXI endstation
|
|
5
|
+
Project-URL: Homepage, https://github.com/Weber-Group/xrayscatteringtools
|
|
6
|
+
Project-URL: Issues, https://github.com/Weber-Group/xrayscatteringtools/issues
|
|
7
|
+
Author-email: David Romano <david_j_romano@brown.edu>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Requires-Dist: h5py
|
|
12
|
+
Requires-Dist: ipython
|
|
13
|
+
Requires-Dist: matplotlib
|
|
14
|
+
Requires-Dist: numpy<2
|
|
15
|
+
Requires-Dist: pathlib
|
|
16
|
+
Requires-Dist: pyyaml
|
|
17
|
+
Requires-Dist: requests
|
|
18
|
+
Requires-Dist: scipy>=1.11
|
|
19
|
+
Requires-Dist: tqdm
|
|
20
|
+
Requires-Dist: xraylib
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: black>=24.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: mypy>=1.9; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: ruff>=0.3; extra == 'dev'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# xrayscatteringtools
|
|
29
|
+
|
|
30
|
+
## A python library for the analysis of data from the CXI endstation at the LCLS.
|
|
31
|
+
|
|
32
|
+
### List of all methods:
|
|
33
|
+
All methods have full docstrings in the NumPy docstring standard.
|
|
34
|
+
Proper namespaces have yet to be defined. Some of these functions can remain internal, and the more useful ones can be defined at the surface level.
|
|
35
|
+
* calib
|
|
36
|
+
* geometry_calibration
|
|
37
|
+
- run_geometry_calibration()
|
|
38
|
+
- model()
|
|
39
|
+
- thompson_correction()
|
|
40
|
+
- geometry_correction()
|
|
41
|
+
* scattering_corrections
|
|
42
|
+
- correction_factor()
|
|
43
|
+
- Si_correction()
|
|
44
|
+
- KaptonHN_correction()
|
|
45
|
+
- Al_correction()
|
|
46
|
+
- Be_correction()
|
|
47
|
+
- cell_correction()
|
|
48
|
+
- Si_attenuation_length()
|
|
49
|
+
- Al_attenuation_length()
|
|
50
|
+
- Be_attenuation_length()
|
|
51
|
+
- KaptonHN_attenuation_length()
|
|
52
|
+
- J4M_efficiency()
|
|
53
|
+
* theory
|
|
54
|
+
* iam
|
|
55
|
+
- iam_elastic_pattern()
|
|
56
|
+
- iam_inelastic_pattern()
|
|
57
|
+
- iam_total_pattern()
|
|
58
|
+
- iam_compton_spectrum()
|
|
59
|
+
* patterns
|
|
60
|
+
- sf6()
|
|
61
|
+
* io
|
|
62
|
+
- combineRuns()
|
|
63
|
+
- get_tree()
|
|
64
|
+
- is_leaf()
|
|
65
|
+
- get_leaves()
|
|
66
|
+
- runNumToString()
|
|
67
|
+
- read_xyz()
|
|
68
|
+
* plotting
|
|
69
|
+
- plot_jungfrau()
|
|
70
|
+
- compute_pixel_edges()
|
|
71
|
+
* utils
|
|
72
|
+
- enable_underscore_cleanup()
|
|
73
|
+
- azimuthalBinning()
|
|
74
|
+
- keV2Angstroms()
|
|
75
|
+
- Angstroms2keV()
|
|
76
|
+
- q2theta()
|
|
77
|
+
- theta2q()
|
|
78
|
+
- element_symbol_to_number()
|
|
79
|
+
- element_number_to_symbol()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
xrayscatteringtools/__init__.py,sha256=LSeycYuFQF7RB0_NIyxhHbeF86ncE22TD9VLroRmPnU,62
|
|
2
|
+
xrayscatteringtools/epicsArch.py,sha256=mdFs-TviBf8JGAFEuxwE49c3dEb2dayZtmICy_uUJEQ,13140
|
|
3
|
+
xrayscatteringtools/io.py,sha256=hE89nXvNK0235t5KYRhJ1uhDfgvw-piHbfuvDSTne3k,11067
|
|
4
|
+
xrayscatteringtools/plotting.py,sha256=uV48_MTrFq1KOtwSyggLKfDclHcRw4GpK9xOOBzazlw,2986
|
|
5
|
+
xrayscatteringtools/utils.py,sha256=6L6aWI4ML2qA7ESOm8pksmIqB7CNMKJtzaBgDTQ5pUU,16271
|
|
6
|
+
xrayscatteringtools/calib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
xrayscatteringtools/calib/geometry_calibration.py,sha256=Zgkj0V3vfeBj9YheL-cB9AoCvDub-tIfBlCb6SpwFIA,7650
|
|
8
|
+
xrayscatteringtools/calib/scattering_corrections.py,sha256=oXty94oiJ8HRw5s7PmR1W19w49ANpgy91rx9oKZom3I,19091
|
|
9
|
+
xrayscatteringtools/theory/Compton_Factors.npy,sha256=kuWFKAghH4ivP4uUbzbwZbf182yb5Y0U2RvqxW_QtkA,6728
|
|
10
|
+
xrayscatteringtools/theory/Scattering_Factors.npy,sha256=A_iYxvLrrGKruwOvtOWCLIc8b_iG-FSkPce5OrFPN_I,4681
|
|
11
|
+
xrayscatteringtools/theory/__init__.py,sha256=o0bQi18T1i2F9EBNYC1dRS8Bx2MvacVXsEZ-c1oHGuk,78
|
|
12
|
+
xrayscatteringtools/theory/iam.py,sha256=RUNwVkpwkTeuJwhalHpSYuMQPm8zcJCehGB3DPzGxzw,9406
|
|
13
|
+
xrayscatteringtools/theory/patterns.py,sha256=Jd6qA9MifqijClKvtWDd4Kp3w8FbOFhw4p8FfaqfGkM,1175
|
|
14
|
+
xrayscatteringtools/theory/data/sf6.h5,sha256=qzMffm4sCN1N0f7BWXWfmnFM0I6DzIy8K2PI6j6epzQ,6048
|
|
15
|
+
xrayscatteringtools-0.0.1.dist-info/METADATA,sha256=JtBKDkKgYCg6BrtD6-GvuSHY5cyuBAiLis29eO1fcYk,2176
|
|
16
|
+
xrayscatteringtools-0.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
17
|
+
xrayscatteringtools-0.0.1.dist-info/licenses/LICENSE,sha256=HAWdYNAScy8pUxw8FKQ9z6y-b0P8JIfm1cRR7SNE0ls,1069
|
|
18
|
+
xrayscatteringtools-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 David Romano
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|