powder
Simulated powder X-ray diffraction (PXRD) patterns.
A powder pattern is computed from a crystal structure in a few steps:
- enumerate reflections (h, k, l) up to a resolution limit (
generate_hkl), - compute the structure factor F(hkl) = sum_j occ_j f_j(s) exp(2pii h.r_j)
from the unit-cell atoms and their X-ray form factors (
structure_factors), - place each reflection at its Bragg angle (lambda = 2 d sin(theta)) with intensity |F|^2 times the Lorentz-polarization correction, and
- (optionally) bin/convolve into a 1D profile I(2*theta).
Systematically absent reflections need no special handling: their structure factor is identically zero.
Intensities use neutral-atom X-ray form factors and the Lorentz-polarization factor only; no Debye-Waller (temperature) factor and no anomalous dispersion (f', f'') are applied, so relative intensities are most accurate for light atoms and may differ for heavy atoms near an absorption edge.
PowderPattern
dataclass
A simulated powder diffraction pattern.
Reflections are Laue-symmetry-unique; multiplicity is the number of
equivalent reflections and is already folded into intensity.
Attributes:
| Name | Type | Description |
|---|---|---|
wavelength |
float
|
X-ray wavelength in Angstroms |
two_theta_range |
tuple
|
(min, max) 2*theta in degrees this pattern spans |
hkl |
ndarray
|
(N, 3) Miller indices (one representative per Laue orbit) |
d_spacing |
ndarray
|
(N,) d-spacings in Angstroms |
two_theta |
ndarray
|
(N,) Bragg angles 2*theta in degrees |
multiplicity |
ndarray
|
(N,) number of equivalent reflections |
f2 |
ndarray
|
(N,) |F(hkl)|^2 |
intensity |
ndarray
|
(N,) multiplicity * |F|^2 * Lorentz-polarization |
Source code in chmpy/crystal/powder.py
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | |
peaks(n=None, normalize=True)
The reflections sorted by decreasing intensity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
keep only the n strongest reflections (default: all) |
None
|
|
normalize
|
scale intensities so the strongest is 100 |
True
|
Returns:
| Type | Description |
|---|---|
|
a structured array with fields ('h', 'k', 'l', 'd', 'two_theta', |
|
|
'multiplicity', 'intensity'), one row per reflection. |
Source code in chmpy/crystal/powder.py
plot(two_theta_range=None, num_bins=4500, fwhm=0.1, normalize=True, ax=None, **kwargs)
Plot the pattern as intensity versus 2*theta.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
two_theta_range
|
(min, max) 2*theta in degrees; defaults to the range this pattern was computed over. |
None
|
|
num_bins
|
number of bins across the range |
4500
|
|
fwhm
|
Gaussian peak width in degrees (set None for a stick pattern) |
0.1
|
|
normalize
|
scale the maximum intensity to 100 |
True
|
|
ax
|
an existing matplotlib Axes to draw on (a new one is created if not given) |
None
|
|
**kwargs
|
forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
|
the matplotlib Axes the pattern was drawn on. |
Source code in chmpy/crystal/powder.py
profile(two_theta_range=None, num_bins=4500, fwhm=None, normalize=False)
Bin (and optionally broaden) the reflections into a 1D profile.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
two_theta_range
|
(min, max) 2*theta in degrees; defaults to the range this pattern was computed over. |
None
|
|
num_bins
|
number of bins across the range |
4500
|
|
fwhm
|
if given, convolve with a Gaussian of this FWHM (degrees) to approximate peak shapes; otherwise a stick histogram is returned. |
None
|
|
normalize
|
scale the profile so its maximum is 100. |
False
|
Returns:
| Type | Description |
|---|---|
(two_theta, intensity)
|
bin-centre angles (degrees) and intensities. |
Source code in chmpy/crystal/powder.py
generate_hkl(unit_cell, d_min)
Enumerate Miller indices with d-spacing >= d_min.
The bound on each index is exact: since the reciprocal vector q of (h,k,l) satisfies q . a = h (and similarly for k, l), |h| <= |a| / d_min for any reflection with d = 1/|q| >= d_min.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unit_cell
|
a UnitCell |
required | |
d_min
|
float
|
minimum d-spacing in Angstroms |
required |
Returns:
| Type | Description |
|---|---|
(hkl, d_spacings)
|
an (N, 3) integer array and an (N,) float array, |
|
excluding (0, 0, 0), sorted by decreasing d-spacing. |
Source code in chmpy/crystal/powder.py
lorentz_polarization(two_theta)
Lorentz-polarization correction for an unpolarised powder source.
Lp = (1 + cos^2(2*theta)) / (sin^2(theta) * cos(theta))
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
two_theta
|
ndarray
|
2*theta values in radians |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
the Lp factor at each angle. |
Source code in chmpy/crystal/powder.py
plot_powder_patterns(patterns, labels=None, offset=10.0, x_offset=0.0, two_theta_range=None, num_bins=4500, fwhm=0.1, normalize=True, ax=None, **kwargs)
Overlay several powder patterns, stacked with an offset.
Each pattern is drawn in the next colour of the matplotlib cycle and shifted
from the one below it (a waterfall plot). With a non-zero x_offset the
stack is also sheared sideways for a pseudo-3D look.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
patterns
|
an iterable of PowderPattern |
required | |
labels
|
optional labels, one per pattern, shown in a legend |
None
|
|
offset
|
vertical shift between successive patterns (intensity units; with normalize=True the patterns are scaled to a maximum of 100) |
10.0
|
|
x_offset
|
horizontal shift between successive patterns, in 2*theta degrees (default 0 for a purely vertical stack) |
0.0
|
|
two_theta_range
|
(min, max) 2*theta in degrees; defaults to the union of the patterns' ranges |
None
|
|
num_bins
|
number of bins across the range |
4500
|
|
fwhm
|
Gaussian peak width in degrees (set None for stick patterns) |
0.1
|
|
normalize
|
scale each pattern's maximum to 100 |
True
|
|
ax
|
an existing matplotlib Axes to draw on (created if not given) |
None
|
|
**kwargs
|
forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
|
the matplotlib Axes the patterns were drawn on. |
Source code in chmpy/crystal/powder.py
powder_pattern(crystal, wavelength=LAMBDA_CU_KA, two_theta_range=(5.0, 50.0), dtype=np.float32, method='auto')
Compute a powder diffraction pattern for a crystal.
Reflections are reduced to the Laue-unique set with multiplicities, so only one structure factor is computed per symmetry-equivalent group.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
crystal
|
a Crystal |
required | |
wavelength
|
float
|
X-ray wavelength in Angstroms (default Cu K-alpha) |
LAMBDA_CU_KA
|
two_theta_range
|
(min, max) 2*theta in degrees to include |
(5.0, 50.0)
|
|
dtype
|
precision for the direct structure-factor sum; float32 (default) is fastest and accurate to ~1e-6 in relative intensity. Pass float64 for full double precision. |
float32
|
|
method
|
str
|
"direct" (exact summation), "fft" (gridding + FFT, faster for large low-symmetry cells), or "auto" (default) to pick per structure. |
'auto'
|
Returns:
| Type | Description |
|---|---|
PowderPattern
|
a PowderPattern with per-reflection data; call |
Source code in chmpy/crystal/powder.py
structure_factors(crystal, hkl, d_spacings, dtype=np.float64)
Structure factors F(hkl) for the given reflections.
F(hkl) = sum_j occ_j * f_j(s) * exp(2*pi*i * (h.r_j))
summed over all atoms in the unit cell, with s = sin(theta)/lambda = 1/(2d).
Atoms are grouped by element so each form factor is evaluated once per distinct element rather than once per atom:
F(hkl) = sum_e f_e(s) * sum_{j in e} occ_j * exp(2*pi*i * h.r_j)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
crystal
|
a Crystal |
required | |
hkl
|
(N, 3) integer Miller indices |
required | |
d_spacings
|
(N,) d-spacings for those reflections |
required | |
dtype
|
floating precision for the trigonometric sum. The default (float64) is exact; float32 is ~4x faster with a relative error in |F|^2 of ~1e-6, which is negligible for relative powder intensities. |
float64
|
Returns:
| Type | Description |
|---|---|
ndarray
|
(N,) complex array of structure factors. |
Source code in chmpy/crystal/powder.py
structure_factors_fft(crystal, hkl, d_spacings, oversample=2.0, half_width=4, sigma=1.0)
Structure factors via gridding + FFT (a non-uniform FFT, type 1).
Each element's atoms are spread onto a real-space grid with a Gaussian kernel; one FFT then yields the geometric structure factors at every Miller index simultaneously, and the smooth atomic form factors are applied analytically. The Gaussian spreading is deconvolved exactly in reciprocal space.
This costs O(V log V + M) instead of the direct method's O(N_refl * M), so
it is much faster for large, low-symmetry cells (thousands of atoms /
reflections) but slower for small or high-symmetry ones. See powder_pattern
with method="auto".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
crystal
|
a Crystal |
required | |
hkl
|
(N, 3) integer Miller indices |
required | |
d_spacings
|
(N,) d-spacings |
required | |
oversample
|
float
|
reciprocal-grid oversampling factor (>=1.5 recommended) |
2.0
|
half_width
|
int
|
Gaussian spreading half-width in grid points |
4
|
sigma
|
float
|
Gaussian width in grid units |
1.0
|
Returns:
| Type | Description |
|---|---|
ndarray
|
(N,) complex array of structure factors (relative error ~1e-5 versus the |
ndarray
|
direct method with the defaults). |
Source code in chmpy/crystal/powder.py
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | |