xrdkit 0.1.0__tar.gz
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-0.1.0/LICENSE +21 -0
- xrdkit-0.1.0/PKG-INFO +229 -0
- xrdkit-0.1.0/README.md +199 -0
- xrdkit-0.1.0/pyproject.toml +55 -0
- xrdkit-0.1.0/pyproject.toml.orig +58 -0
- xrdkit-0.1.0/src/xrdkit/__init__.py +226 -0
- xrdkit-0.1.0/src/xrdkit/broadening.py +1155 -0
- xrdkit-0.1.0/src/xrdkit/config.py +660 -0
- xrdkit-0.1.0/src/xrdkit/density.py +144 -0
- xrdkit-0.1.0/src/xrdkit/gsas2.py +915 -0
- xrdkit-0.1.0/src/xrdkit/gsas2_driver.py +2551 -0
- xrdkit-0.1.0/src/xrdkit/indexing.py +750 -0
- xrdkit-0.1.0/src/xrdkit/io.py +115 -0
- xrdkit-0.1.0/src/xrdkit/lattice.py +233 -0
- xrdkit-0.1.0/src/xrdkit/peaks.py +340 -0
- xrdkit-0.1.0/src/xrdkit/phases.py +494 -0
- xrdkit-0.1.0/src/xrdkit/plotting.py +1072 -0
- xrdkit-0.1.0/src/xrdkit/py.typed +0 -0
- xrdkit-0.1.0/src/xrdkit/sizestrain.py +539 -0
- xrdkit-0.1.0/src/xrdkit/structure.py +470 -0
xrdkit-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Amir Khesro
|
|
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.
|
xrdkit-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xrdkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Reusable X-ray diffraction analysis toolkit for electroceramics research
|
|
5
|
+
Keywords: x-ray diffraction,XRD,powder diffraction,Rietveld,Le Bail,GSAS-II,materials science,ceramics,crystallography
|
|
6
|
+
Author: Amir Khesro
|
|
7
|
+
Author-email: Amir Khesro <am.khesro@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Dist: matplotlib>=3.11.1
|
|
20
|
+
Requires-Dist: numpy>=2.0.0
|
|
21
|
+
Requires-Dist: scipy>=1.13.0
|
|
22
|
+
Requires-Dist: pymatgen>=2026.5.4 ; extra == 'phases'
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Project-URL: Homepage, https://github.com/amirkhesro/xrdkit
|
|
25
|
+
Project-URL: Repository, https://github.com/amirkhesro/xrdkit
|
|
26
|
+
Project-URL: Issues, https://github.com/amirkhesro/xrdkit/issues
|
|
27
|
+
Project-URL: Changelog, https://github.com/amirkhesro/xrdkit/blob/main/CHANGELOG.md
|
|
28
|
+
Provides-Extra: phases
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# xrdkit
|
|
32
|
+
|
|
33
|
+
A reusable X-ray diffraction analysis toolkit for electroceramics research.
|
|
34
|
+
|
|
35
|
+
`xrdkit` provides shared, importable routines for loading, processing and
|
|
36
|
+
analysing XRD patterns, so that the same analysis code can be reused across
|
|
37
|
+
projects instead of being copied between one-off scripts.
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install xrdkit
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Phase matching against the COD needs pymatgen, which comes with the `phases`
|
|
46
|
+
extra:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install "xrdkit[phases]"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
GSAS-II is optional and is needed only for the Rietveld driver in
|
|
53
|
+
`xrdkit.gsas2`. It is not a Python dependency: install it separately and
|
|
54
|
+
point `XRDKIT_GSAS2_PYTHON` and `XRDKIT_GSAS2_HOME` at it, or leave it at
|
|
55
|
+
`~/gsas2main`. Every other module works without it.
|
|
56
|
+
|
|
57
|
+
## Data
|
|
58
|
+
|
|
59
|
+
This repository contains **code only**. Raw and processed diffraction data
|
|
60
|
+
(including `.xrdml` files) live in a separate data repository and are never
|
|
61
|
+
committed here.
|
|
62
|
+
|
|
63
|
+
## GSAS-II refinement
|
|
64
|
+
|
|
65
|
+
GSAS-II runs under its own Python, so `xrdkit.gsas2` writes a job as JSON and
|
|
66
|
+
runs `gsas2_driver.py` on it there (`run_job`), with `-B`; xrdkit writes
|
|
67
|
+
nothing into the GSAS-II installation. `find_gsas2` locates it
|
|
68
|
+
(`XRDKIT_GSAS2_PYTHON`, `XRDKIT_GSAS2_HOME`, or `~/gsas2main`).
|
|
69
|
+
|
|
70
|
+
GSAS-II's own version and update check, run whenever its scripting module is
|
|
71
|
+
imported, writes one bytecode file inside its installation
|
|
72
|
+
(`Lib/site-packages/scipy/__pycache__/__config__.cpython-313.pyc` in the
|
|
73
|
+
`~/gsas2main` install); it is written once, not on every run, and does not
|
|
74
|
+
come from xrdkit.
|
|
75
|
+
|
|
76
|
+
`build_refine_job` assembles a refinement from a list of stages, each adding
|
|
77
|
+
flags to the ones before (see the `gsas2_driver` module notes for every key):
|
|
78
|
+
|
|
79
|
+
| Stage key | Refines |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `background`, `scale`, `zero`, `displacement`, `instrument` | histogram and instrument |
|
|
82
|
+
| `cell`, `le_bail`, `phase_fractions`, `size`, `mustrain` | phase, by name or all |
|
|
83
|
+
| `overall_uiso` | one Uiso for every atom of a phase |
|
|
84
|
+
| `uiso_groups` | `{phase: [[site, ...], ...]}`: one Uiso for every atom on each group's sites |
|
|
85
|
+
| `atoms`, `atom_flags` | F, X, U for every atom, or for named atoms |
|
|
86
|
+
| `coordinates` | `{phase: {site: "xz" or "all"}}`: the coordinates to free on each site; the rest are held, atoms sharing a site move together |
|
|
87
|
+
| `origin` | `{phase: {"site": label, "axis": "z"}}`: a site's coordinate held to fix the origin; a stage that would leave the origin floating along a polar axis fails |
|
|
88
|
+
| `occupancies` | `[{"phase", "sites": [...], "elements": [...]}]`: the named elements' occupancies on the named sites, each element's content over them held (so the vacancies over them too) |
|
|
89
|
+
|
|
90
|
+
Job options besides the stages: `limits`, `cycles`, `broadening`,
|
|
91
|
+
`background_start`, `scale_start`, `overall_uiso_start`, `le_bail_cycles`,
|
|
92
|
+
`max_passes` and `pass_tolerance` (refine each stage until it settles),
|
|
93
|
+
`on_flagged` and `on_unsettled` (below), `sanity` (`{"max_shift": 0.05,
|
|
94
|
+
"reference": {phase: [{"label", "xyz"}]}}`) and `bonds` (`True` or
|
|
95
|
+
`{"anions", "dmax", "dmin"}`). A phase's `atoms` edits the structure read
|
|
96
|
+
from its CIF in the project only: occupancies, positions and Uiso, and atoms
|
|
97
|
+
added on existing sites; `structure_edits` gives the edits that set up a
|
|
98
|
+
refined structure again, so that one refinement starts where another ended.
|
|
99
|
+
|
|
100
|
+
Every stage of the result records its residuals and parameters with esds, the
|
|
101
|
+
atoms as it left them, the coordinates it refined and held by site, its
|
|
102
|
+
occupancy constraints, and a sanity check: negative Uiso, occupancies outside
|
|
103
|
+
0 to 1 (and site totals above 1), and sites moved more than `max_shift`
|
|
104
|
+
(fractional) from the reference. With `bonds`, `run_job` adds the final
|
|
105
|
+
model's cation to anion distances (`xrdkit.structure.bond_lengths`, to oxygen
|
|
106
|
+
up to 3 Å by default) to the result.
|
|
107
|
+
|
|
108
|
+
### What becomes of a stage that goes wrong
|
|
109
|
+
|
|
110
|
+
So that a sequence can be run unattended and still leave a usable record,
|
|
111
|
+
every stage carries a `status` and the run goes on from the last stage kept:
|
|
112
|
+
|
|
113
|
+
| Status | The stage | The run |
|
|
114
|
+
| --- | --- | --- |
|
|
115
|
+
| `clean` | settled, and raised no sanity flag the stage before it lacked | kept |
|
|
116
|
+
| `unsettled` | reached `max_passes` still moving, and raised no new flag | kept |
|
|
117
|
+
| `flagged` | raised a new sanity flag, with `on_flagged` `"accept"` | kept |
|
|
118
|
+
| `rejected` | raised a new flag under `on_flagged` `"reject"` (the default), or did not settle under `on_unsettled` `"reject"` | rolled back |
|
|
119
|
+
| `failed` | raised | rolled back, and the run ends |
|
|
120
|
+
|
|
121
|
+
**Rejected.** A sanity flag means the model has gone somewhere it should not
|
|
122
|
+
be — a Uiso below zero, an occupancy outside 0 to 1, a site further from the
|
|
123
|
+
reference than `max_shift` — so the stage that raised one is rejected by
|
|
124
|
+
default. It is recorded in full, residuals, parameters and atoms, with
|
|
125
|
+
`rejected_because` and its name in the result's `rejected`. The project then
|
|
126
|
+
goes back to the state the last stage kept left it in — parameters, atoms
|
|
127
|
+
and constraints — and is saved so, and the stage's own entries are dropped
|
|
128
|
+
from the stages, so that what it alone refined is held in every stage after
|
|
129
|
+
it. `on_flagged: "accept"` keeps it instead, as `"flagged"`.
|
|
130
|
+
|
|
131
|
+
**Unsettled.** Reaching the pass cap only means the stage was still moving
|
|
132
|
+
when the passes ran out, which is not in itself wrong, so it is kept by
|
|
133
|
+
default and `largest_remaining_move` records the parameter that moved most
|
|
134
|
+
in its last pass and by how many esds. `on_unsettled: "reject"` rolls one
|
|
135
|
+
back like a flagged stage, for a caller that wants nothing unsettled in its
|
|
136
|
+
model.
|
|
137
|
+
|
|
138
|
+
**Undetermined.** Each stage also records, as `undetermined`, the refined
|
|
139
|
+
atom parameters the data do not determine
|
|
140
|
+
(`gsas2_driver.find_undetermined`): an occupancy whose esd is more than half
|
|
141
|
+
its allowed range, 0 to 1, and a coordinate or an isotropic Uiso whose esd
|
|
142
|
+
is larger than its shift from where the job found it. Such a value is not a
|
|
143
|
+
result, whatever its stage's status. The result's `undetermined` are those
|
|
144
|
+
of the last stage kept.
|
|
145
|
+
|
|
146
|
+
**The model a run leaves.** Every run ends with `final`, and with
|
|
147
|
+
`export_prefix` an `exports`, whatever became of its stages: the model of
|
|
148
|
+
the last stage kept, or, where no stage was kept, the one the job started
|
|
149
|
+
from, computed by a refinement of no cycles that moves nothing. The result's
|
|
150
|
+
`final_from` names the stage they come from, or `"job start"`; a starting
|
|
151
|
+
model has no refined parameter and so no esd.
|
|
152
|
+
|
|
153
|
+
### Writing a sequence up
|
|
154
|
+
|
|
155
|
+
For a pipeline that runs several refinements in turn, `xrdkit.gsas2` writes
|
|
156
|
+
what they came to:
|
|
157
|
+
|
|
158
|
+
| Function | Gives |
|
|
159
|
+
| --- | --- |
|
|
160
|
+
| `stage_status` | one stage's status, worked out for a result written before the driver recorded one |
|
|
161
|
+
| `accepted_stages` | the stages of a result that were refined and kept |
|
|
162
|
+
| `stage_statuses` | every stage as `{name, status, reason, passes, rwp, gof, undetermined}`, `reason` saying why it is not clean |
|
|
163
|
+
| `stage_status_table` | those as markdown table lines |
|
|
164
|
+
| `log_tail` | the last lines of a GSAS-II log |
|
|
165
|
+
| `failure_markdown` | a write up of a refinement that could not be finished: the error, the stages it got through and the log tail |
|
|
166
|
+
| `summary_markdown` | a summary of a sequence: a row per refinement with its final Rwp, GOF and key values, the status of each stage, then every stage not clean with why and the parameters left undetermined |
|
|
167
|
+
|
|
168
|
+
## Refinement settings
|
|
169
|
+
|
|
170
|
+
`xrdkit.config` reads the settings of a refinement pipeline from a TOML file
|
|
171
|
+
with the standard library's `tomllib` (`load_config`): one table per sample
|
|
172
|
+
under `samples` and one per reference structure under `structures`. It
|
|
173
|
+
checks them as it reads, and a key missing or unknown, a value of the wrong
|
|
174
|
+
kind, or a sample composition that does not fit its structure's sites (an
|
|
175
|
+
element on no site and not added by the rule, or more atoms per cell on a
|
|
176
|
+
kind of site than it has positions) raises `ConfigError` naming the file and
|
|
177
|
+
the table. `sample_settings` finds a sample by its id or table name, with its
|
|
178
|
+
structure.
|
|
179
|
+
|
|
180
|
+
| Table | Keys |
|
|
181
|
+
| --- | --- |
|
|
182
|
+
| `samples.<name>` | `id`, `scan`, `composition` (atoms per formula unit), `structure`, `start_cell` (`{file, model}` or `{a, c}`), `two_theta`, `background` (`{function, terms}`), `refine_microstrain`, `notes`; optionally `followed_reflections`, `trials` (`{runs = [{low, terms}], followed}`), `write_up` (text by mode and section), `unsettled` (the rule for each mode, over the top level one) |
|
|
183
|
+
| `unsettled` | at the top level, the default rule for a stage of each mode that has not settled, `"accept"` (the pipeline's default) or `"reject"`, by the caller's own mode names; each sample carries it merged with its own as its `unsettled` |
|
|
184
|
+
| `structures.<name>` | `cif`, `label`, `phase_name`, `space_group`, `formula_units`, `sites` (`{atoms = {label = element}, wyckoff, kind}`, kind A, B or O), `uiso_groups` (`{name, sites}`), `origin` (`{site, axis}`), `exchange` (`{elements, sites}`), `composition` (`{added = {element = host}}`); optionally `free_coordinates` (by Wyckoff position), `bond_limits` (`{kind = {min, max}}`) |
|
|
185
|
+
|
|
186
|
+
From a structure table, `xrdkit.structure.site_setup` finds the sites among a
|
|
187
|
+
phase's atoms as the driver reports them, checking that each site's atoms
|
|
188
|
+
share one position, are of the elements given and have the multiplicity of
|
|
189
|
+
its Wyckoff position, and that no atom is left over. It returns the sites by
|
|
190
|
+
kind, the Uiso groups, the coordinates to refine on each site, the origin site
|
|
191
|
+
and the exchange, in the forms the stage keys above take.
|
|
192
|
+
`composition_edits` gives the atom edits that put a nominal composition on
|
|
193
|
+
the sites by the table's rule: each element the CIF holds is scaled by one
|
|
194
|
+
factor over its sites, which keeps its distribution, and each added element
|
|
195
|
+
goes on its host's sites in proportion to the host's occupancy.
|
|
196
|
+
`cell_contents` gives the atoms of each element per cell.
|
|
197
|
+
|
|
198
|
+
For example, the sample pipeline of the XRD analysis repository reads every
|
|
199
|
+
sample and structure setting from its `config/samples.toml` and runs Le Bail,
|
|
200
|
+
fixed atoms, coordinates and occupancies in turn, each from the saved result
|
|
201
|
+
of the one before:
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
python -B scripts/refine_sample.py 10 # Le Bail only
|
|
205
|
+
python -B scripts/refine_sample.py 10 --trials # Le Bail with the configured trial ranges and background terms
|
|
206
|
+
python -B scripts/refine_sample.py 10 --through occupancies # all four modes
|
|
207
|
+
python -B scripts/refine_sample.py 10 --from coordinates # one mode, from the saved fixed atoms result
|
|
208
|
+
python -B scripts/refine_sample.py 10 --from coordinates --through occupancies
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
It passes each mode's `unsettled` rule and pass cap to its job, writes the
|
|
212
|
+
mode's write up with `failure_markdown` and stops with a non-zero status
|
|
213
|
+
where a mode cannot be finished, and writes `summary.md` beside the write
|
|
214
|
+
ups with `summary_markdown` at the end of every run.
|
|
215
|
+
|
|
216
|
+
## Status
|
|
217
|
+
|
|
218
|
+
Under active development. The API is not yet stable and may change without
|
|
219
|
+
notice.
|
|
220
|
+
|
|
221
|
+
## Citing
|
|
222
|
+
|
|
223
|
+
If xrdkit contributes to work you publish, please cite it. The metadata is in
|
|
224
|
+
[CITATION.cff](CITATION.cff), which GitHub renders as a ready-made citation
|
|
225
|
+
under **Cite this repository**.
|
|
226
|
+
|
|
227
|
+
## License
|
|
228
|
+
|
|
229
|
+
MIT — see [LICENSE](LICENSE).
|
xrdkit-0.1.0/README.md
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# xrdkit
|
|
2
|
+
|
|
3
|
+
A reusable X-ray diffraction analysis toolkit for electroceramics research.
|
|
4
|
+
|
|
5
|
+
`xrdkit` provides shared, importable routines for loading, processing and
|
|
6
|
+
analysing XRD patterns, so that the same analysis code can be reused across
|
|
7
|
+
projects instead of being copied between one-off scripts.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install xrdkit
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Phase matching against the COD needs pymatgen, which comes with the `phases`
|
|
16
|
+
extra:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install "xrdkit[phases]"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
GSAS-II is optional and is needed only for the Rietveld driver in
|
|
23
|
+
`xrdkit.gsas2`. It is not a Python dependency: install it separately and
|
|
24
|
+
point `XRDKIT_GSAS2_PYTHON` and `XRDKIT_GSAS2_HOME` at it, or leave it at
|
|
25
|
+
`~/gsas2main`. Every other module works without it.
|
|
26
|
+
|
|
27
|
+
## Data
|
|
28
|
+
|
|
29
|
+
This repository contains **code only**. Raw and processed diffraction data
|
|
30
|
+
(including `.xrdml` files) live in a separate data repository and are never
|
|
31
|
+
committed here.
|
|
32
|
+
|
|
33
|
+
## GSAS-II refinement
|
|
34
|
+
|
|
35
|
+
GSAS-II runs under its own Python, so `xrdkit.gsas2` writes a job as JSON and
|
|
36
|
+
runs `gsas2_driver.py` on it there (`run_job`), with `-B`; xrdkit writes
|
|
37
|
+
nothing into the GSAS-II installation. `find_gsas2` locates it
|
|
38
|
+
(`XRDKIT_GSAS2_PYTHON`, `XRDKIT_GSAS2_HOME`, or `~/gsas2main`).
|
|
39
|
+
|
|
40
|
+
GSAS-II's own version and update check, run whenever its scripting module is
|
|
41
|
+
imported, writes one bytecode file inside its installation
|
|
42
|
+
(`Lib/site-packages/scipy/__pycache__/__config__.cpython-313.pyc` in the
|
|
43
|
+
`~/gsas2main` install); it is written once, not on every run, and does not
|
|
44
|
+
come from xrdkit.
|
|
45
|
+
|
|
46
|
+
`build_refine_job` assembles a refinement from a list of stages, each adding
|
|
47
|
+
flags to the ones before (see the `gsas2_driver` module notes for every key):
|
|
48
|
+
|
|
49
|
+
| Stage key | Refines |
|
|
50
|
+
| --- | --- |
|
|
51
|
+
| `background`, `scale`, `zero`, `displacement`, `instrument` | histogram and instrument |
|
|
52
|
+
| `cell`, `le_bail`, `phase_fractions`, `size`, `mustrain` | phase, by name or all |
|
|
53
|
+
| `overall_uiso` | one Uiso for every atom of a phase |
|
|
54
|
+
| `uiso_groups` | `{phase: [[site, ...], ...]}`: one Uiso for every atom on each group's sites |
|
|
55
|
+
| `atoms`, `atom_flags` | F, X, U for every atom, or for named atoms |
|
|
56
|
+
| `coordinates` | `{phase: {site: "xz" or "all"}}`: the coordinates to free on each site; the rest are held, atoms sharing a site move together |
|
|
57
|
+
| `origin` | `{phase: {"site": label, "axis": "z"}}`: a site's coordinate held to fix the origin; a stage that would leave the origin floating along a polar axis fails |
|
|
58
|
+
| `occupancies` | `[{"phase", "sites": [...], "elements": [...]}]`: the named elements' occupancies on the named sites, each element's content over them held (so the vacancies over them too) |
|
|
59
|
+
|
|
60
|
+
Job options besides the stages: `limits`, `cycles`, `broadening`,
|
|
61
|
+
`background_start`, `scale_start`, `overall_uiso_start`, `le_bail_cycles`,
|
|
62
|
+
`max_passes` and `pass_tolerance` (refine each stage until it settles),
|
|
63
|
+
`on_flagged` and `on_unsettled` (below), `sanity` (`{"max_shift": 0.05,
|
|
64
|
+
"reference": {phase: [{"label", "xyz"}]}}`) and `bonds` (`True` or
|
|
65
|
+
`{"anions", "dmax", "dmin"}`). A phase's `atoms` edits the structure read
|
|
66
|
+
from its CIF in the project only: occupancies, positions and Uiso, and atoms
|
|
67
|
+
added on existing sites; `structure_edits` gives the edits that set up a
|
|
68
|
+
refined structure again, so that one refinement starts where another ended.
|
|
69
|
+
|
|
70
|
+
Every stage of the result records its residuals and parameters with esds, the
|
|
71
|
+
atoms as it left them, the coordinates it refined and held by site, its
|
|
72
|
+
occupancy constraints, and a sanity check: negative Uiso, occupancies outside
|
|
73
|
+
0 to 1 (and site totals above 1), and sites moved more than `max_shift`
|
|
74
|
+
(fractional) from the reference. With `bonds`, `run_job` adds the final
|
|
75
|
+
model's cation to anion distances (`xrdkit.structure.bond_lengths`, to oxygen
|
|
76
|
+
up to 3 Å by default) to the result.
|
|
77
|
+
|
|
78
|
+
### What becomes of a stage that goes wrong
|
|
79
|
+
|
|
80
|
+
So that a sequence can be run unattended and still leave a usable record,
|
|
81
|
+
every stage carries a `status` and the run goes on from the last stage kept:
|
|
82
|
+
|
|
83
|
+
| Status | The stage | The run |
|
|
84
|
+
| --- | --- | --- |
|
|
85
|
+
| `clean` | settled, and raised no sanity flag the stage before it lacked | kept |
|
|
86
|
+
| `unsettled` | reached `max_passes` still moving, and raised no new flag | kept |
|
|
87
|
+
| `flagged` | raised a new sanity flag, with `on_flagged` `"accept"` | kept |
|
|
88
|
+
| `rejected` | raised a new flag under `on_flagged` `"reject"` (the default), or did not settle under `on_unsettled` `"reject"` | rolled back |
|
|
89
|
+
| `failed` | raised | rolled back, and the run ends |
|
|
90
|
+
|
|
91
|
+
**Rejected.** A sanity flag means the model has gone somewhere it should not
|
|
92
|
+
be — a Uiso below zero, an occupancy outside 0 to 1, a site further from the
|
|
93
|
+
reference than `max_shift` — so the stage that raised one is rejected by
|
|
94
|
+
default. It is recorded in full, residuals, parameters and atoms, with
|
|
95
|
+
`rejected_because` and its name in the result's `rejected`. The project then
|
|
96
|
+
goes back to the state the last stage kept left it in — parameters, atoms
|
|
97
|
+
and constraints — and is saved so, and the stage's own entries are dropped
|
|
98
|
+
from the stages, so that what it alone refined is held in every stage after
|
|
99
|
+
it. `on_flagged: "accept"` keeps it instead, as `"flagged"`.
|
|
100
|
+
|
|
101
|
+
**Unsettled.** Reaching the pass cap only means the stage was still moving
|
|
102
|
+
when the passes ran out, which is not in itself wrong, so it is kept by
|
|
103
|
+
default and `largest_remaining_move` records the parameter that moved most
|
|
104
|
+
in its last pass and by how many esds. `on_unsettled: "reject"` rolls one
|
|
105
|
+
back like a flagged stage, for a caller that wants nothing unsettled in its
|
|
106
|
+
model.
|
|
107
|
+
|
|
108
|
+
**Undetermined.** Each stage also records, as `undetermined`, the refined
|
|
109
|
+
atom parameters the data do not determine
|
|
110
|
+
(`gsas2_driver.find_undetermined`): an occupancy whose esd is more than half
|
|
111
|
+
its allowed range, 0 to 1, and a coordinate or an isotropic Uiso whose esd
|
|
112
|
+
is larger than its shift from where the job found it. Such a value is not a
|
|
113
|
+
result, whatever its stage's status. The result's `undetermined` are those
|
|
114
|
+
of the last stage kept.
|
|
115
|
+
|
|
116
|
+
**The model a run leaves.** Every run ends with `final`, and with
|
|
117
|
+
`export_prefix` an `exports`, whatever became of its stages: the model of
|
|
118
|
+
the last stage kept, or, where no stage was kept, the one the job started
|
|
119
|
+
from, computed by a refinement of no cycles that moves nothing. The result's
|
|
120
|
+
`final_from` names the stage they come from, or `"job start"`; a starting
|
|
121
|
+
model has no refined parameter and so no esd.
|
|
122
|
+
|
|
123
|
+
### Writing a sequence up
|
|
124
|
+
|
|
125
|
+
For a pipeline that runs several refinements in turn, `xrdkit.gsas2` writes
|
|
126
|
+
what they came to:
|
|
127
|
+
|
|
128
|
+
| Function | Gives |
|
|
129
|
+
| --- | --- |
|
|
130
|
+
| `stage_status` | one stage's status, worked out for a result written before the driver recorded one |
|
|
131
|
+
| `accepted_stages` | the stages of a result that were refined and kept |
|
|
132
|
+
| `stage_statuses` | every stage as `{name, status, reason, passes, rwp, gof, undetermined}`, `reason` saying why it is not clean |
|
|
133
|
+
| `stage_status_table` | those as markdown table lines |
|
|
134
|
+
| `log_tail` | the last lines of a GSAS-II log |
|
|
135
|
+
| `failure_markdown` | a write up of a refinement that could not be finished: the error, the stages it got through and the log tail |
|
|
136
|
+
| `summary_markdown` | a summary of a sequence: a row per refinement with its final Rwp, GOF and key values, the status of each stage, then every stage not clean with why and the parameters left undetermined |
|
|
137
|
+
|
|
138
|
+
## Refinement settings
|
|
139
|
+
|
|
140
|
+
`xrdkit.config` reads the settings of a refinement pipeline from a TOML file
|
|
141
|
+
with the standard library's `tomllib` (`load_config`): one table per sample
|
|
142
|
+
under `samples` and one per reference structure under `structures`. It
|
|
143
|
+
checks them as it reads, and a key missing or unknown, a value of the wrong
|
|
144
|
+
kind, or a sample composition that does not fit its structure's sites (an
|
|
145
|
+
element on no site and not added by the rule, or more atoms per cell on a
|
|
146
|
+
kind of site than it has positions) raises `ConfigError` naming the file and
|
|
147
|
+
the table. `sample_settings` finds a sample by its id or table name, with its
|
|
148
|
+
structure.
|
|
149
|
+
|
|
150
|
+
| Table | Keys |
|
|
151
|
+
| --- | --- |
|
|
152
|
+
| `samples.<name>` | `id`, `scan`, `composition` (atoms per formula unit), `structure`, `start_cell` (`{file, model}` or `{a, c}`), `two_theta`, `background` (`{function, terms}`), `refine_microstrain`, `notes`; optionally `followed_reflections`, `trials` (`{runs = [{low, terms}], followed}`), `write_up` (text by mode and section), `unsettled` (the rule for each mode, over the top level one) |
|
|
153
|
+
| `unsettled` | at the top level, the default rule for a stage of each mode that has not settled, `"accept"` (the pipeline's default) or `"reject"`, by the caller's own mode names; each sample carries it merged with its own as its `unsettled` |
|
|
154
|
+
| `structures.<name>` | `cif`, `label`, `phase_name`, `space_group`, `formula_units`, `sites` (`{atoms = {label = element}, wyckoff, kind}`, kind A, B or O), `uiso_groups` (`{name, sites}`), `origin` (`{site, axis}`), `exchange` (`{elements, sites}`), `composition` (`{added = {element = host}}`); optionally `free_coordinates` (by Wyckoff position), `bond_limits` (`{kind = {min, max}}`) |
|
|
155
|
+
|
|
156
|
+
From a structure table, `xrdkit.structure.site_setup` finds the sites among a
|
|
157
|
+
phase's atoms as the driver reports them, checking that each site's atoms
|
|
158
|
+
share one position, are of the elements given and have the multiplicity of
|
|
159
|
+
its Wyckoff position, and that no atom is left over. It returns the sites by
|
|
160
|
+
kind, the Uiso groups, the coordinates to refine on each site, the origin site
|
|
161
|
+
and the exchange, in the forms the stage keys above take.
|
|
162
|
+
`composition_edits` gives the atom edits that put a nominal composition on
|
|
163
|
+
the sites by the table's rule: each element the CIF holds is scaled by one
|
|
164
|
+
factor over its sites, which keeps its distribution, and each added element
|
|
165
|
+
goes on its host's sites in proportion to the host's occupancy.
|
|
166
|
+
`cell_contents` gives the atoms of each element per cell.
|
|
167
|
+
|
|
168
|
+
For example, the sample pipeline of the XRD analysis repository reads every
|
|
169
|
+
sample and structure setting from its `config/samples.toml` and runs Le Bail,
|
|
170
|
+
fixed atoms, coordinates and occupancies in turn, each from the saved result
|
|
171
|
+
of the one before:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
python -B scripts/refine_sample.py 10 # Le Bail only
|
|
175
|
+
python -B scripts/refine_sample.py 10 --trials # Le Bail with the configured trial ranges and background terms
|
|
176
|
+
python -B scripts/refine_sample.py 10 --through occupancies # all four modes
|
|
177
|
+
python -B scripts/refine_sample.py 10 --from coordinates # one mode, from the saved fixed atoms result
|
|
178
|
+
python -B scripts/refine_sample.py 10 --from coordinates --through occupancies
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
It passes each mode's `unsettled` rule and pass cap to its job, writes the
|
|
182
|
+
mode's write up with `failure_markdown` and stops with a non-zero status
|
|
183
|
+
where a mode cannot be finished, and writes `summary.md` beside the write
|
|
184
|
+
ups with `summary_markdown` at the end of every run.
|
|
185
|
+
|
|
186
|
+
## Status
|
|
187
|
+
|
|
188
|
+
Under active development. The API is not yet stable and may change without
|
|
189
|
+
notice.
|
|
190
|
+
|
|
191
|
+
## Citing
|
|
192
|
+
|
|
193
|
+
If xrdkit contributes to work you publish, please cite it. The metadata is in
|
|
194
|
+
[CITATION.cff](CITATION.cff), which GitHub renders as a ready-made citation
|
|
195
|
+
under **Cite this repository**.
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "xrdkit"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Reusable X-ray diffraction analysis toolkit for electroceramics research"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
keywords = [
|
|
10
|
+
"x-ray diffraction",
|
|
11
|
+
"XRD",
|
|
12
|
+
"powder diffraction",
|
|
13
|
+
"Rietveld",
|
|
14
|
+
"Le Bail",
|
|
15
|
+
"GSAS-II",
|
|
16
|
+
"materials science",
|
|
17
|
+
"ceramics",
|
|
18
|
+
"crystallography",
|
|
19
|
+
]
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Development Status :: 3 - Alpha",
|
|
22
|
+
"Intended Audience :: Science/Research",
|
|
23
|
+
"Operating System :: OS Independent",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Topic :: Scientific/Engineering :: Physics",
|
|
28
|
+
"Topic :: Scientific/Engineering :: Chemistry",
|
|
29
|
+
"Typing :: Typed",
|
|
30
|
+
]
|
|
31
|
+
dependencies = [
|
|
32
|
+
"matplotlib>=3.11.1",
|
|
33
|
+
"numpy>=2.0.0",
|
|
34
|
+
"scipy>=1.13.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[[project.authors]]
|
|
38
|
+
name = "Amir Khesro"
|
|
39
|
+
email = "am.khesro@gmail.com"
|
|
40
|
+
|
|
41
|
+
[project.urls]
|
|
42
|
+
Homepage = "https://github.com/amirkhesro/xrdkit"
|
|
43
|
+
Repository = "https://github.com/amirkhesro/xrdkit"
|
|
44
|
+
Issues = "https://github.com/amirkhesro/xrdkit/issues"
|
|
45
|
+
Changelog = "https://github.com/amirkhesro/xrdkit/blob/main/CHANGELOG.md"
|
|
46
|
+
|
|
47
|
+
[project.optional-dependencies]
|
|
48
|
+
phases = ["pymatgen>=2026.5.4"]
|
|
49
|
+
|
|
50
|
+
[build-system]
|
|
51
|
+
requires = ["uv_build>=0.12.0,<0.13.0"]
|
|
52
|
+
build-backend = "uv_build"
|
|
53
|
+
|
|
54
|
+
[dependency-groups]
|
|
55
|
+
dev = ["pytest>=9.1.1"]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "xrdkit"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Reusable X-ray diffraction analysis toolkit for electroceramics research"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [
|
|
10
|
+
{ name = "Amir Khesro", email = "am.khesro@gmail.com" }
|
|
11
|
+
]
|
|
12
|
+
keywords = [
|
|
13
|
+
"x-ray diffraction",
|
|
14
|
+
"XRD",
|
|
15
|
+
"powder diffraction",
|
|
16
|
+
"Rietveld",
|
|
17
|
+
"Le Bail",
|
|
18
|
+
"GSAS-II",
|
|
19
|
+
"materials science",
|
|
20
|
+
"ceramics",
|
|
21
|
+
"crystallography",
|
|
22
|
+
]
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Development Status :: 3 - Alpha",
|
|
25
|
+
"Intended Audience :: Science/Research",
|
|
26
|
+
"Operating System :: OS Independent",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Programming Language :: Python :: 3.13",
|
|
30
|
+
"Topic :: Scientific/Engineering :: Physics",
|
|
31
|
+
"Topic :: Scientific/Engineering :: Chemistry",
|
|
32
|
+
"Typing :: Typed",
|
|
33
|
+
]
|
|
34
|
+
dependencies = [
|
|
35
|
+
"matplotlib>=3.11.1",
|
|
36
|
+
"numpy>=2.0.0",
|
|
37
|
+
"scipy>=1.13.0",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://github.com/amirkhesro/xrdkit"
|
|
42
|
+
Repository = "https://github.com/amirkhesro/xrdkit"
|
|
43
|
+
Issues = "https://github.com/amirkhesro/xrdkit/issues"
|
|
44
|
+
Changelog = "https://github.com/amirkhesro/xrdkit/blob/main/CHANGELOG.md"
|
|
45
|
+
|
|
46
|
+
[project.optional-dependencies]
|
|
47
|
+
phases = [
|
|
48
|
+
"pymatgen>=2026.5.4",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[build-system]
|
|
52
|
+
requires = ["uv_build>=0.12.0,<0.13.0"]
|
|
53
|
+
build-backend = "uv_build"
|
|
54
|
+
|
|
55
|
+
[dependency-groups]
|
|
56
|
+
dev = [
|
|
57
|
+
"pytest>=9.1.1",
|
|
58
|
+
]
|