xrdkit 0.1.0__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.
- xrdkit/__init__.py +226 -0
- xrdkit/broadening.py +1155 -0
- xrdkit/config.py +660 -0
- xrdkit/density.py +144 -0
- xrdkit/gsas2.py +915 -0
- xrdkit/gsas2_driver.py +2551 -0
- xrdkit/indexing.py +750 -0
- xrdkit/io.py +115 -0
- xrdkit/lattice.py +233 -0
- xrdkit/peaks.py +340 -0
- xrdkit/phases.py +494 -0
- xrdkit/plotting.py +1072 -0
- xrdkit/py.typed +0 -0
- xrdkit/sizestrain.py +539 -0
- xrdkit/structure.py +470 -0
- xrdkit-0.1.0.dist-info/METADATA +229 -0
- xrdkit-0.1.0.dist-info/RECORD +19 -0
- xrdkit-0.1.0.dist-info/WHEEL +4 -0
- xrdkit-0.1.0.dist-info/licenses/LICENSE +21 -0
xrdkit/density.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""Theoretical density from a refined cell and a composition."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from scipy.constants import Avogadro
|
|
9
|
+
|
|
10
|
+
from xrdkit.indexing import TetragonalCell
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"ATOMIC_MASSES",
|
|
14
|
+
"cell_volume",
|
|
15
|
+
"formula_mass",
|
|
16
|
+
"theoretical_density",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
# Standard atomic weights in g/mol, IUPAC 2021 (Prohaska et al., Pure Appl.
|
|
20
|
+
# Chem. 94 (2022) 573). Elements whose standard atomic weight is an interval
|
|
21
|
+
# (Li, O, Mg, Si, Pb) take the IUPAC conventional value. The 2024 table revised
|
|
22
|
+
# Gd to 157.249 and Zr to 91.222; the 2021 values are kept here.
|
|
23
|
+
ATOMIC_MASSES: dict[str, float] = {
|
|
24
|
+
"Li": 6.94,
|
|
25
|
+
"O": 15.999,
|
|
26
|
+
"Na": 22.98976928,
|
|
27
|
+
"Mg": 24.305,
|
|
28
|
+
"Al": 26.9815384,
|
|
29
|
+
"Si": 28.085,
|
|
30
|
+
"K": 39.0983,
|
|
31
|
+
"Ca": 40.078,
|
|
32
|
+
"Ti": 47.867,
|
|
33
|
+
"Cr": 51.9961,
|
|
34
|
+
"Mn": 54.938043,
|
|
35
|
+
"Fe": 55.845,
|
|
36
|
+
"Co": 58.933194,
|
|
37
|
+
"Ni": 58.6934,
|
|
38
|
+
"Cu": 63.546,
|
|
39
|
+
"Zn": 65.38,
|
|
40
|
+
"Sr": 87.62,
|
|
41
|
+
"Y": 88.905838,
|
|
42
|
+
"Zr": 91.224,
|
|
43
|
+
"Nb": 92.90637,
|
|
44
|
+
"Sn": 118.710,
|
|
45
|
+
"Ba": 137.327,
|
|
46
|
+
"La": 138.90547,
|
|
47
|
+
"Ce": 140.116,
|
|
48
|
+
"Nd": 144.242,
|
|
49
|
+
"Sm": 150.36,
|
|
50
|
+
"Gd": 157.25,
|
|
51
|
+
"Hf": 178.486,
|
|
52
|
+
"Ta": 180.94788,
|
|
53
|
+
"W": 183.84,
|
|
54
|
+
"Pb": 207.2,
|
|
55
|
+
"Bi": 208.98040,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# Cubic angstroms in a cubic centimetre.
|
|
59
|
+
A3_PER_CM3 = 1e24
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def formula_mass(composition: Mapping[str, float]) -> float:
|
|
63
|
+
"""Return the mass of one formula unit in g/mol.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
composition
|
|
68
|
+
Element symbol to stoichiometric coefficient, such as
|
|
69
|
+
``{"Sr": 1, "Ti": 1, "O": 3}``.
|
|
70
|
+
|
|
71
|
+
Raises
|
|
72
|
+
------
|
|
73
|
+
ValueError
|
|
74
|
+
If the composition is empty, names an element not in
|
|
75
|
+
:data:`ATOMIC_MASSES`, or has a negative coefficient.
|
|
76
|
+
"""
|
|
77
|
+
if not composition:
|
|
78
|
+
raise ValueError("composition is empty")
|
|
79
|
+
unknown = sorted(set(composition) - set(ATOMIC_MASSES))
|
|
80
|
+
if unknown:
|
|
81
|
+
raise ValueError(f"No atomic mass for {', '.join(unknown)}")
|
|
82
|
+
negative = sorted(element for element, n in composition.items() if n < 0)
|
|
83
|
+
if negative:
|
|
84
|
+
raise ValueError(f"Negative coefficient for {', '.join(negative)}")
|
|
85
|
+
return float(sum(ATOMIC_MASSES[element] * n for element, n in composition.items()))
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def cell_volume(
|
|
89
|
+
cell: TetragonalCell,
|
|
90
|
+
esd_a: float | None = None,
|
|
91
|
+
esd_c: float | None = None,
|
|
92
|
+
) -> tuple[float, float | None]:
|
|
93
|
+
"""Return the volume a^2 c of a tetragonal cell and its esd, in cubic angstroms.
|
|
94
|
+
|
|
95
|
+
The esd is propagated to first order, sqrt((2ac esd_a)^2 + (a^2 esd_c)^2),
|
|
96
|
+
treating a and c as uncorrelated since the fits here report no covariance.
|
|
97
|
+
An esd left as ``None`` counts as zero, and the esd returned is ``None``
|
|
98
|
+
only when neither is given.
|
|
99
|
+
"""
|
|
100
|
+
volume = cell.a**2 * cell.c
|
|
101
|
+
if esd_a is None and esd_c is None:
|
|
102
|
+
return float(volume), None
|
|
103
|
+
from_a = 2.0 * cell.a * cell.c * (esd_a or 0.0)
|
|
104
|
+
from_c = cell.a**2 * (esd_c or 0.0)
|
|
105
|
+
return float(volume), float(np.hypot(from_a, from_c))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def theoretical_density(
|
|
109
|
+
composition: Mapping[str, float],
|
|
110
|
+
z: float,
|
|
111
|
+
volume_a3: float,
|
|
112
|
+
esd_volume_a3: float | None = None,
|
|
113
|
+
) -> tuple[float, float | None]:
|
|
114
|
+
"""Return the X-ray density in g/cm^3 and its esd.
|
|
115
|
+
|
|
116
|
+
The density is Z M / (N_A V), with M the formula mass and V the cell
|
|
117
|
+
volume. Only the volume carries an error here, so the density has the same
|
|
118
|
+
relative esd as the volume; the esd returned is ``None`` when no volume esd
|
|
119
|
+
is given.
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
composition
|
|
124
|
+
Element symbol to stoichiometric coefficient for one formula unit.
|
|
125
|
+
z
|
|
126
|
+
Formula units per cell.
|
|
127
|
+
volume_a3
|
|
128
|
+
Cell volume in cubic angstroms.
|
|
129
|
+
esd_volume_a3
|
|
130
|
+
Estimated standard deviation of the volume, in cubic angstroms.
|
|
131
|
+
|
|
132
|
+
Raises
|
|
133
|
+
------
|
|
134
|
+
ValueError
|
|
135
|
+
If ``z`` or ``volume_a3`` is not positive, or from :func:`formula_mass`.
|
|
136
|
+
"""
|
|
137
|
+
if z <= 0:
|
|
138
|
+
raise ValueError(f"z must be positive, got {z}")
|
|
139
|
+
if volume_a3 <= 0:
|
|
140
|
+
raise ValueError(f"volume_a3 must be positive, got {volume_a3}")
|
|
141
|
+
density = z * formula_mass(composition) / (Avogadro * volume_a3 / A3_PER_CM3)
|
|
142
|
+
if esd_volume_a3 is None:
|
|
143
|
+
return float(density), None
|
|
144
|
+
return float(density), float(density * esd_volume_a3 / volume_a3)
|