diff --git a/AGENTS.md b/AGENTS.md index 19b5ccf..54327e8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,7 +5,7 @@ contributors). Tool-specific files (`CLAUDE.md`) only point here. This file links the page that owns each topic instead of restating it. PowderLine runs powder diffraction refinements from a **recipe** (structured -data: a dict, serialised as JSON). A recipe names one engine and one workflow +data: a dict, serialized as JSON). A recipe names one engine and one workflow in `schema_name` (`gsasii.rietveld`, `gsasii.spf`, `topas.rietveld`, `topas.spf`, `easydiffraction.rietveld`) and is written in that engine's own terms and units. `powderline.run()` and the `powderline` CLI hand it to the @@ -20,7 +20,7 @@ statistics. Nothing is translated between engines. - `docs/engines/*.md` + `docs/catalog/engine_behaviour.yaml` — what each engine does and PowderLine's policy (`EB-NN`). - `docs/reference/known-issues.md` + `docs/catalog/known_issues.yaml` — - known, deliberately deferred behaviours (`KI-NN`). Check before "fixing" a + known, deliberately deferred behaviors (`KI-NN`). Check before "fixing" a quirk. - The code under `src/` and `pixi.toml`: where a page and the code disagree, the code wins; report the discrepancy. @@ -94,12 +94,12 @@ Detail: `docs/development/contributing.md`. `src/powderline/gateways/gsasii/{helpers,project,setters,executors,extractors,constraints}.py` do GSAS-II's project-dictionary work. Rules (`docs/development/policies.md#frozen-gsas-ii-code`): -- A behaviour-changing edit needs the maintainers' explicit consent. An agent +- A behavior-changing edit needs the maintainers' explicit consent. An agent never makes one on its own: propose it, with its reason and proof. - Comment and docstring edits need no consent. Don't leave outdated comments. - After **any** edit, `pixi run update-code-hash` (the hash covers raw bytes; `tests/test_code_hash.py` guards it). -- New behaviour goes into the non-frozen modules (`fit_report`, `sites`, +- New behavior goes into the non-frozen modules (`fit_report`, `sites`, `routing`, `paths`, `gateway`). - Replace the GSAS-II server after any edit it runs (a stale server is detected: skipped in `auto` mode, refused in `server` mode): @@ -139,7 +139,7 @@ do GSAS-II's project-dictionary work. Rules (`docs/development/policies.md#froze `docs/concepts/results.md`. - Every failure raises `EngineExecutionError` or `ExecutionBackendError`; a gateway never returns a failed result — `docs/development/adding-an-engine.md`. -- Every intentional behaviour change is deliberate; references move only with +- Every intentional behavior change is deliberate; references move only with an equivalence check — `docs/development/policies.md`. - Docs follow the writing rules in `docs/development/contributing.md#writing-documentation`. diff --git a/CHANGELOG.md b/CHANGELOG.md index 07e1866..4cb054c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,15 +95,15 @@ limitations are listed in the [known-issues register](docs/reference/known-issue - Examples: per-engine recipes under `examples//{topas,easydiffraction}/`, `example_LaB6_temperature_series` (sequential refinement), `example_LaB6_ionic` and `example_LaB6_textured`, with easydiffraction references. -- Documentation, organised by reader: Get started, Concepts, How-to guides, +- Documentation, organized by reader: Get started, Concepts, How-to guides, Examples, Engines, Reference and Development, on pydata-sphinx-theme with diagrams and per-engine tabs ([docs](https://nsls2.github.io/PowderLine/)). Among its pages: [outputs](docs/reference/outputs.md), [fields](docs/reference/fields.md), [validation](docs/concepts/validation.md), - [engine behaviour](docs/engines/index.md), + [engine behavior](docs/engines/index.md), [cross-engine comparison](docs/concepts/comparing-engines.md) and [policies](docs/development/policies.md). -- Every engine behaviour (`EB-NN`) and known issue (`KI-NN`) has its own +- Every engine behavior (`EB-NN`) and known issue (`KI-NN`) has its own entry and link, listed in the [ID index](docs/reference/ids.md). Known issues KI-19 to KI-21 cover the GSAS-II server's lifetime, its state directory and a race in `gsas-server stop` @@ -283,7 +283,7 @@ The pre-refactor baseline; unified recipe schema 0.26.0. ### Fixed - GSAS-II's refinement failure message is surfaced instead of a silent - no-Rwp result; `run()` normalisation no longer crashes on null tables from + no-Rwp result; `run()` normalization no longer crashes on null tables from server failure responses (#3). ## [0.1.0] - 2026-08-17 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c10ccca..b8580d7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,7 +25,7 @@ pixi run test # the engine-free suites when they are stale). - The frozen GSAS-II modules (`src/powderline/gateways/gsasii/{helpers,project,setters,executors,extractors,constraints}.py`) - change behaviour only with the maintainers' explicit consent. Comment and + change behavior only with the maintainers' explicit consent. Comment and docstring edits are fine. After any edit, run `pixi run update-code-hash`. - `examples/**/output/` is tracked on purpose (regression references). It moves only as a deliberate, reviewed change. diff --git a/README.md b/README.md index a56898f..2efcb30 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ walks through them. | Engine | Workflows | Runs on | |---|---|---| | GSAS-II 5.7.9 | Rietveld, single-peak fitting | Linux, Windows, macOS\* | -| TOPAS 6 | Rietveld, single-peak fitting | Windows with a TOPAS licence (input files are written anywhere) | +| TOPAS 6 | Rietveld, single-peak fitting | Windows with a TOPAS license (input files are written anywhere) | | easydiffraction 0.21.1 | Rietveld | Linux, Windows, macOS\* | \* macOS (Apple Silicon) is expected to work but is not routinely tested. @@ -106,7 +106,7 @@ Full references, including the calculators and gemmi, are on [Citing PowderLine](https://nsls2.github.io/PowderLine/about/citing.html). Machine-readable metadata is in [`CITATION.cff`](CITATION.cff). -## Contributing and licence +## Contributing and license See the [developer guide](https://nsls2.github.io/PowderLine/development/). -BSD 3-Clause licence, see [LICENSE](LICENSE). +BSD 3-Clause license, see [LICENSE](LICENSE). diff --git a/docs/_generated/cross_engine_comparison.json b/docs/_generated/cross_engine_comparison.json index 646f6ec..905d971 100644 --- a/docs/_generated/cross_engine_comparison.json +++ b/docs/_generated/cross_engine_comparison.json @@ -247,7 +247,7 @@ "value": 4.156826, "esd": 4e-05, "label": "NIST SRM 660c", - "note": "certificate 2015-10-29: 0.4156826(8) nm, k = 2, 22.5 \u00b0C" + "note": "certificate 2015-10-29: 0.415\u202f682\u202f6 nm \u00b1 0.000\u202f008 nm, expanded uncertainty k = 2, 22.5 \u00b0C" } }, "DRX_33": { @@ -558,8 +558,8 @@ } ], "generated": { - "date": "2026-11-05", - "commit": "b6cee8a", - "no_run": false + "date": "2026-11-06", + "commit": "72a539a", + "no_run": true } } diff --git a/docs/_generated/cross_engine_comparison.md b/docs/_generated/cross_engine_comparison.md index c753686..31694e5 100644 --- a/docs/_generated/cross_engine_comparison.md +++ b/docs/_generated/cross_engine_comparison.md @@ -16,7 +16,7 @@ Fit window and points: 3767 points (every engine scores the same points). | easydiffraction | LaB6 | a | 4.157175(18) Å | -10 | -1.5 | +84 | +8.0 | | easydiffraction | LaB6 | a | 4.157495(17) Å | +67 | +10.2 | +161 | +15.4 | -Reference for the NIST columns: NIST SRM 660c, a = 4.156826 Å (certificate 2015-10-29: 0.4156826(8) nm, k = 2, 22.5 °C; standard uncertainty 4e-05 Å used for σ). +Reference for the NIST columns: NIST SRM 660c, a = 4.156826 Å (certificate 2015-10-29: 0.415 682 6 nm ± 0.000 008 nm, expanded uncertainty k = 2, 22.5 °C; standard uncertainty 4e-05 Å used for σ). ### DRX_33 @@ -59,4 +59,4 @@ Fit window and points: 3767 points (every engine scores the same points). - GSAS-II 5.7.9: run 2026-11-05 (PowderLine 0.2.0, Python 3.13.16); `execution_mode='subprocess'`. - TOPAS: TOPAS-64 Version 6 goldens (`tests/data/topas/native/golden/6/`, TOPAS machine runs of 2026-10-09); **not executed for this page**: the rows are the gateway's result built from the committed files. - easydiffraction goldens (`tests/data/easydiffraction/native/golden/`, runs of 2026-10-09): easydiffraction 0.21.1, cryspy 0.13.0, crysfml 0.8.0, lmfit 1.3.4, numpy 2.4.6, scipy 1.18.0. -- Table generated 2026-11-05 by `scripts/cross_engine_comparison.py` at commit `b6cee8a`. +- Table generated 2026-11-06 by `scripts/cross_engine_comparison.py` at commit `72a539a` in `--no-run` mode (GSAS-II rows from the committed JSON record). diff --git a/docs/_generated/eb_all.md b/docs/_generated/eb_all.md index 12fa614..166241d 100644 --- a/docs/_generated/eb_all.md +++ b/docs/_generated/eb_all.md @@ -44,6 +44,6 @@ {bdg-secondary}`documented` · GSAS-II 5.7.9; easydiffraction 0.21.1 (CrysPy 0.13.0, CrysFML 0.8.0) -**What happens:** Lattice parameters agree between GSAS-II and easydiffraction when axial asymmetry is modelled physically (FCJ). With a symmetric profile they shift by +67 to +91 ppm, whichever calculator runs it. +**What happens:** Lattice parameters agree between GSAS-II and easydiffraction when axial asymmetry is modeled physically (FCJ). With a symmetric profile they shift by +67 to +91 ppm, whichever calculator runs it. **PowderLine does:** Documented on the cross-engine comparison. Rwp compares models fitted to the same points, not engines. diff --git a/docs/_generated/eb_easydiffraction.md b/docs/_generated/eb_easydiffraction.md index 1916c41..5c85c02 100644 --- a/docs/_generated/eb_easydiffraction.md +++ b/docs/_generated/eb_easydiffraction.md @@ -178,7 +178,7 @@ {bdg-success}`handled` · easydiffraction 0.21.1 -**easydiffraction does:** When a fit starts, easydiffraction gives an unbounded side its physical limit: cell lengths 0–30 Å, angles 0–180°, occupancy 0–1, `adp_iso` and U11/U22/U33 0–10 Ų, scale, wavelength and μR ≥ 0. It refuses a value outside a physical limit at input, even when fixed, so no cell over 30 Å can be modelled. lmfit moves a start outside its bounds onto the bound without a message. +**easydiffraction does:** When a fit starts, easydiffraction gives an unbounded side its physical limit: cell lengths 0–30 Å, angles 0–180°, occupancy 0–1, `adp_iso` and U11/U22/U33 0–10 Ų, scale, wavelength and μR ≥ 0. It refuses a value outside a physical limit at input, even when fixed, so no cell over 30 Å can be modeled. lmfit moves a start outside its bounds onto the bound without a message. **PowderLine does:** A stated bound replaces the physical limit on its side, and `null` keeps it. A value outside a physical limit is a validation error. A refined value that ends within 1e-6 (relative) of a bound or physical limit gets a warning. For a limit of 0, the test is within 1e-6 of the starting value. @@ -191,9 +191,9 @@ {bdg-success}`handled` · easydiffraction 0.21.1 (CrysPy 0.13.0, CrysFML 0.8.0) -**easydiffraction does:** Both calculators model the Kα doublet, the Lorentz-polarization factor 1 − p + p cos²2θ_m cos²2θ, the 2θ offset, sample displacement and transparency, and Hewat cylinder absorption. A second wavelength alone does nothing. 2θ_m acts only with p > 0. GSAS-II's polarization P is easydiffraction's 1 − p: copying P to p is a 6.6 % intensity error at 15° 2θ. +**easydiffraction does:** Both calculators model the Kα doublet, the Lorentz factor and the polarization factor 1 − p + p cos²2θ_m cos²2θ, the 2θ offset, sample displacement and transparency, and Hewat cylinder absorption. A second wavelength alone does nothing. 2θ_m acts only with p > 0. GSAS-II's polarization P is easydiffraction's 1 − p: copying P to p is a 6.6 % intensity error at 15° 2θ. -**PowderLine does:** Every correction is a recipe slot; left out means not modelled. The schema requires both Kα2 fields or neither. The hand-derived per-engine recipes state p = 1 − P. +**PowderLine does:** Every correction is a recipe slot; left out means not modeled. The schema requires both Kα2 fields or neither. The hand-derived per-engine recipes state p = 1 − P. **You see:** validation error @@ -228,9 +228,9 @@ {bdg-secondary}`documented` · easydiffraction 0.21.1 (CrysPy 0.13.0) -**easydiffraction does:** CrysPy's texture correction is not volume-normalised, so every textured-to-untextured intensity ratio carries the constant r^1.5. With `march_random_fract` = 0 the scale absorbs it, and the refined `march_r` is the same r as GSAS-II's. With f > 0 the correction is (1 − f)·r^1.5·A + f, and the refined r and f are not GSAS-II's quantities. +**easydiffraction does:** CrysPy's texture correction is not volume-normalized, so every textured-to-untextured intensity ratio carries the constant r^1.5. With `march_random_fract` = 0 the scale absorbs it, and the refined `march_r` is the same r as GSAS-II's. With f > 0 the correction is (1 − f)·r^1.5·A + f, and the refined r and f are not GSAS-II's quantities. -**PowderLine does:** Documented. A test compares normalised ratios with GSAS-II's March–Dollase correction. +**PowderLine does:** Documented. A test compares normalized ratios with GSAS-II's March–Dollase correction. ### Data and the fit window @@ -336,7 +336,7 @@ {bdg-secondary}`documented` · easydiffraction 0.21.1 (CrysFML 0.8.0) -**easydiffraction does:** Relative to m·|F|²·Lorentz, CrysFML's integrated intensities drift by −4 % from 3° to 15° 2θ. This biases `Uiso` by about +0.001 Ų. +**easydiffraction does:** Relative to m·|F|²·Lorentz, CrysFML's integrated intensities drift by −4 % from 3° to 15° 2θ. A drift this size is worth about 0.001 Ų of `Uiso`; a refinement compensates by lowering `Uiso`. **PowderLine does:** The calculator is recorded in every result. @@ -345,7 +345,7 @@ {bdg-secondary}`documented` · easydiffraction 0.21.1 (CrysPy 0.13.0, CrysFML 0.8.0) -**easydiffraction does:** On GSAS-II-calculated LaB6 patterns, easydiffraction refines La's Uiso 10–22 % low. B's Uiso, the thermal expansion and GoF ≈ 1 agree. The cause is the series' profile: GSAS-II clamps its Lorentzian width to 0.001 centideg above about 10.7°, so the high-angle peaks are pure Gaussian. Neither a symmetric pseudo-Voigt nor TCH can represent that, and `Uiso` absorbs the mismatch. Simulated with a profile easydiffraction can represent, CrysPy's La Uiso is 0.00863 against 0.00858 programmed. CrysFML's is 0.00823 (−4 %), the size of its intensity drift ({ref}`EB-78 `). +**easydiffraction does:** On GSAS-II-calculated LaB6 patterns, easydiffraction refines La's Uiso 10–22 % low. B's Uiso, the thermal expansion and GoF ≈ 1 agree. Most of it comes from the series' profile: GSAS-II clamps its Lorentzian width to 0.001 centideg above about 10.7°, so the high-angle peaks are pure Gaussian. Neither a symmetric pseudo-Voigt nor TCH can represent that, and `Uiso` absorbs the mismatch. Simulated with a profile easydiffraction can represent, CrysPy's La Uiso is 0.00863 against 0.00858 programmed. CrysFML's is 0.00823 (−4 %); its remaining profile mismatch and its intensity drift ({ref}`EB-78 `) both act on `Uiso`, and the two were not separated. **PowderLine does:** Documented, no code change. Across engines, compare cells, with the {ref}`EB-88 `-size offsets in mind, and the expansion. Absolute `Uiso` agrees only when the profile models agree. diff --git a/docs/_generated/eb_gsasii.md b/docs/_generated/eb_gsasii.md index b7f7820..a4f16dc 100644 --- a/docs/_generated/eb_gsasii.md +++ b/docs/_generated/eb_gsasii.md @@ -110,7 +110,7 @@ **GSAS-II does:** GSAS-II carries negative `Uiso` and `Uij` values and refines from them. -**PowderLine does:** Core has no sign rule for ADPs: a negative ADP can compensate for an unmodelled effect. +**PowderLine does:** Core has no sign rule for ADPs: a negative ADP can compensate for an unmodeled effect. (eb-20)= #### EB-20 · Any occupancy is accepted diff --git a/docs/_generated/eb_topas.md b/docs/_generated/eb_topas.md index dde3c78..7275694 100644 --- a/docs/_generated/eb_topas.md +++ b/docs/_generated/eb_topas.md @@ -121,7 +121,7 @@ {bdg-success}`handled` · TOPAS 6 -**TOPAS does:** The `_LIMIT_MIN` and `_LIMIT_MAX` markers TOPAS 6 writes are mislabelled or spurious. +**TOPAS does:** The `_LIMIT_MIN` and `_LIMIT_MAX` markers TOPAS 6 writes are mislabeled or spurious. **PowderLine does:** The at-limit warning is judged from the final values and the limits the writer knows, not from TOPAS's markers. @@ -145,7 +145,7 @@ **TOPAS does:** TCHZ_Peak_Type combines a Gaussian width G and a Lorentzian width L = X·tanθ + Y/cosθ into one FWHM. With a fixed X < 0, TOPAS 6 neither takes |X| nor clamps it at 0. X = −0.01 runs, and the profile differs from X = 0. X = −0.1 makes the width negative at the top of the window, and TOPAS writes no results: a negative convolution FWHM stops TOPAS. -**PowderLine does:** PowderLine honours what TOPAS computes: a negative Lorentzian part passes while the total width is positive. With `TCHZ_Peak_Type`, the total width at the recipe's starting values must be positive at every data point of the fit window. Otherwise validation fails and names X, Y and the 2θ where the width is not positive. An output recipe whose refined values break the rule is not valid. +**PowderLine does:** PowderLine honors what TOPAS computes: a negative Lorentzian part passes while the total width is positive. With `TCHZ_Peak_Type`, the total width at the recipe's starting values must be positive at every data point of the fit window. Otherwise validation fails and names X, Y and the 2θ where the width is not positive. An output recipe whose refined values break the rule is not valid. **You see:** validation error `topas_tchz_width_not_positive`, `output_recipe_not_valid` diff --git a/docs/_generated/examples/example_DRX_33.svg b/docs/_generated/examples/example_DRX_33.svg index 0c07737..f6d7f26 100644 --- a/docs/_generated/examples/example_DRX_33.svg +++ b/docs/_generated/examples/example_DRX_33.svg @@ -1,7 +1,7 @@ -example_DRX_33 (GSAS-II): observed (grey), calculated (blue) and difference (orange) over the fit window +example_DRX_33 (GSAS-II): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_DRX_33_anisoADP.svg b/docs/_generated/examples/example_DRX_33_anisoADP.svg index 03c4a9b..73f76b0 100644 --- a/docs/_generated/examples/example_DRX_33_anisoADP.svg +++ b/docs/_generated/examples/example_DRX_33_anisoADP.svg @@ -1,7 +1,7 @@ -example_DRX_33_anisoADP (GSAS-II): observed (grey), calculated (blue) and difference (orange) over the fit window +example_DRX_33_anisoADP (GSAS-II): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_DRX_33_atomrefine.svg b/docs/_generated/examples/example_DRX_33_atomrefine.svg index 32ccb68..5fe373f 100644 --- a/docs/_generated/examples/example_DRX_33_atomrefine.svg +++ b/docs/_generated/examples/example_DRX_33_atomrefine.svg @@ -1,7 +1,7 @@ -example_DRX_33_atomrefine (GSAS-II): observed (grey), calculated (blue) and difference (orange) over the fit window +example_DRX_33_atomrefine (GSAS-II): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_DRX_33_easydiffraction.svg b/docs/_generated/examples/example_DRX_33_easydiffraction.svg index f9b2a59..4be425b 100644 --- a/docs/_generated/examples/example_DRX_33_easydiffraction.svg +++ b/docs/_generated/examples/example_DRX_33_easydiffraction.svg @@ -1,7 +1,7 @@ -example_DRX_33 (easydiffraction): observed (grey), calculated (blue) and difference (orange) over the fit window +example_DRX_33 (easydiffraction): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_DRX_33_simulation.svg b/docs/_generated/examples/example_DRX_33_simulation.svg index 4d9dc20..671daec 100644 --- a/docs/_generated/examples/example_DRX_33_simulation.svg +++ b/docs/_generated/examples/example_DRX_33_simulation.svg @@ -1,7 +1,7 @@ -example_DRX_33_simulation (GSAS-II): observed (grey), calculated (blue) and difference (orange) over the fit window +example_DRX_33_simulation (GSAS-II): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_DRX_33_strainonly.svg b/docs/_generated/examples/example_DRX_33_strainonly.svg index 7063fb8..9ad4e56 100644 --- a/docs/_generated/examples/example_DRX_33_strainonly.svg +++ b/docs/_generated/examples/example_DRX_33_strainonly.svg @@ -1,7 +1,7 @@ -example_DRX_33_strainonly (GSAS-II): observed (grey), calculated (blue) and difference (orange) over the fit window +example_DRX_33_strainonly (GSAS-II): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_LaB6.svg b/docs/_generated/examples/example_LaB6.svg index b01ff06..b910e3f 100644 --- a/docs/_generated/examples/example_LaB6.svg +++ b/docs/_generated/examples/example_LaB6.svg @@ -1,7 +1,7 @@ -example_LaB6 (GSAS-II): observed (grey), calculated (blue) and difference (orange) over the fit window +example_LaB6 (GSAS-II): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_LaB6_easydiffraction.svg b/docs/_generated/examples/example_LaB6_easydiffraction.svg index 6ee4a4b..37fc2bc 100644 --- a/docs/_generated/examples/example_LaB6_easydiffraction.svg +++ b/docs/_generated/examples/example_LaB6_easydiffraction.svg @@ -1,7 +1,7 @@ -example_LaB6 (easydiffraction): observed (grey), calculated (blue) and difference (orange) over the fit window +example_LaB6 (easydiffraction): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_LaB6_ionic.svg b/docs/_generated/examples/example_LaB6_ionic.svg index 66cad1e..8ef89f3 100644 --- a/docs/_generated/examples/example_LaB6_ionic.svg +++ b/docs/_generated/examples/example_LaB6_ionic.svg @@ -1,7 +1,7 @@ -example_LaB6_ionic (GSAS-II): observed (grey), calculated (blue) and difference (orange) over the fit window +example_LaB6_ionic (GSAS-II): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_LaB6_ionic_easydiffraction.svg b/docs/_generated/examples/example_LaB6_ionic_easydiffraction.svg index 6e25922..5759a1e 100644 --- a/docs/_generated/examples/example_LaB6_ionic_easydiffraction.svg +++ b/docs/_generated/examples/example_LaB6_ionic_easydiffraction.svg @@ -1,7 +1,7 @@ -example_LaB6_ionic (easydiffraction): observed (grey), calculated (blue) and difference (orange) over the fit window +example_LaB6_ionic (easydiffraction): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_LaB6_simulation.svg b/docs/_generated/examples/example_LaB6_simulation.svg index 89ae5d7..9b2b781 100644 --- a/docs/_generated/examples/example_LaB6_simulation.svg +++ b/docs/_generated/examples/example_LaB6_simulation.svg @@ -1,7 +1,7 @@ -example_LaB6_simulation (GSAS-II): observed (grey), calculated (blue) and difference (orange) over the fit window +example_LaB6_simulation (GSAS-II): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_LaB6_singlepeakfit.svg b/docs/_generated/examples/example_LaB6_singlepeakfit.svg index 2499756..d39f87f 100644 --- a/docs/_generated/examples/example_LaB6_singlepeakfit.svg +++ b/docs/_generated/examples/example_LaB6_singlepeakfit.svg @@ -1,7 +1,7 @@ -example_LaB6_singlepeakfit (GSAS-II): observed (grey), calculated (blue) and difference (orange) over the fit window +example_LaB6_singlepeakfit (GSAS-II): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_LaB6_temperature_series_easydiffraction.svg b/docs/_generated/examples/example_LaB6_temperature_series_easydiffraction.svg index d18c1a9..7254535 100644 --- a/docs/_generated/examples/example_LaB6_temperature_series_easydiffraction.svg +++ b/docs/_generated/examples/example_LaB6_temperature_series_easydiffraction.svg @@ -1,7 +1,7 @@ -example_LaB6_temperature_series (easydiffraction): observed (grey), calculated (blue) and difference (orange) over the fit window +example_LaB6_temperature_series (easydiffraction): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_LaB6_textured.svg b/docs/_generated/examples/example_LaB6_textured.svg index 3ee24bf..4143704 100644 --- a/docs/_generated/examples/example_LaB6_textured.svg +++ b/docs/_generated/examples/example_LaB6_textured.svg @@ -1,7 +1,7 @@ -example_LaB6_textured (GSAS-II): observed (grey), calculated (blue) and difference (orange) over the fit window +example_LaB6_textured (GSAS-II): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/examples/example_LaB6_textured_easydiffraction.svg b/docs/_generated/examples/example_LaB6_textured_easydiffraction.svg index a224d46..a8d618a 100644 --- a/docs/_generated/examples/example_LaB6_textured_easydiffraction.svg +++ b/docs/_generated/examples/example_LaB6_textured_easydiffraction.svg @@ -1,7 +1,7 @@ -example_LaB6_textured (easydiffraction): observed (grey), calculated (blue) and difference (orange) over the fit window +example_LaB6_textured (easydiffraction): observed (gray), calculated (blue) and difference (orange) over the fit window diff --git a/docs/_generated/fields_easydiffraction_rietveld.md b/docs/_generated/fields_easydiffraction_rietveld.md index edaf683..8a26e1b 100644 --- a/docs/_generated/fields_easydiffraction_rietveld.md +++ b/docs/_generated/fields_easydiffraction_rietveld.md @@ -15,7 +15,7 @@ | `payload.instrument.polarization` | engine | block | | no | Left out: no polarization correction (p = 0) | | `payload.instrument.polarization.setup_polarization_coefficient` | engine | number | `dimensionless` | yes | p, 0..1 | | `payload.instrument.polarization.setup_monochromator_twotheta` | engine | number | `degree` | yes | Monochromator 2theta_m, 0 <= 2theta_m < 180 | -| `payload.instrument.corrections` | engine | block | | yes | Peak-position corrections (degrees 2theta). Displacement and transparency left out: not modelled. | +| `payload.instrument.corrections` | engine | block | | yes | Peak-position corrections (degrees 2theta). Displacement and transparency left out: not modeled. | | `payload.instrument.corrections.calib_twotheta_offset` | engine | `[value, flag, min, max]` | `degree 2theta` | yes | Zero offset | | `payload.instrument.corrections.calib_sample_displacement` | engine | `[value, flag, min, max]` | `degree 2theta` | no | Specimen displacement term (shift x cos 2theta) | | `payload.instrument.corrections.calib_sample_transparency` | engine | `[value, flag, min, max]` | `degree 2theta` | no | Transparency term (shift x sin 2theta) | diff --git a/docs/_generated/fields_gsasii_rietveld.md b/docs/_generated/fields_gsasii_rietveld.md index 130324e..8698987 100644 --- a/docs/_generated/fields_gsasii_rietveld.md +++ b/docs/_generated/fields_gsasii_rietveld.md @@ -14,7 +14,7 @@ | `payload.instrument.geometry.bank` | engine | integer | | yes | GSAS-II 'Bank' | | `payload.instrument.geometry.azimuth` | engine | number | `degree` | yes | GSAS-II 'Azimuth' | | `payload.instrument.corrections` | engine | block | | yes | Instrument corrections: zero shift, polarization, axial divergence (GSAS-II 'SH/L'). | -| `payload.instrument.corrections.zero_shift` | engine | `[value, flag]` | `centidegree 2theta` | yes | GSAS-II 'Zero' | +| `payload.instrument.corrections.zero_shift` | engine | `[value, flag]` | `degree 2theta` | yes | GSAS-II 'Zero' | | `payload.instrument.corrections.polarization` | engine | `[value, flag]` | `dimensionless` | yes | GSAS-II 'Polariz.' | | `payload.instrument.corrections.axial_divergence` | engine | `[value, flag]` | `dimensionless` | yes | GSAS-II 'SH/L' (asymmetry); at least 0.002 (GSAS-II's own floor) | | `payload.instrument.broadening` | engine | block | | yes | Instrument profile (Caglioti U, V, W; Lorentzian X, Y, Z). | diff --git a/docs/_generated/fields_gsasii_spf.md b/docs/_generated/fields_gsasii_spf.md index 934d486..541a450 100644 --- a/docs/_generated/fields_gsasii_spf.md +++ b/docs/_generated/fields_gsasii_spf.md @@ -14,7 +14,7 @@ | `payload.instrument.geometry.bank` | engine | integer | | yes | GSAS-II 'Bank' | | `payload.instrument.geometry.azimuth` | engine | number | `degree` | yes | GSAS-II 'Azimuth' | | `payload.instrument.corrections` | engine | block | | yes | Instrument corrections: zero shift, polarization, axial divergence (GSAS-II 'SH/L'). | -| `payload.instrument.corrections.zero_shift` | engine | `[value, flag]` | `centidegree 2theta` | yes | GSAS-II 'Zero' | +| `payload.instrument.corrections.zero_shift` | engine | `[value, flag]` | `degree 2theta` | yes | GSAS-II 'Zero' | | `payload.instrument.corrections.polarization` | engine | `[value, flag]` | `dimensionless` | yes | GSAS-II 'Polariz.' | | `payload.instrument.corrections.axial_divergence` | engine | `[value, flag]` | `dimensionless` | yes | GSAS-II 'SH/L' (asymmetry); at least 0.002 (GSAS-II's own floor) | | `payload.instrument.broadening` | engine | block | | yes | Instrument profile (Caglioti U, V, W; Lorentzian X, Y, Z). | diff --git a/docs/_generated/fields_topas_rietveld.md b/docs/_generated/fields_topas_rietveld.md index f26dbc6..0303c43 100644 --- a/docs/_generated/fields_topas_rietveld.md +++ b/docs/_generated/fields_topas_rietveld.md @@ -21,10 +21,10 @@ | `payload.instrument.corrections` | engine | block | | no | Left out: no corrections | | `payload.instrument.corrections.Zero_Error` | engine | block | | no | TOPAS `ZE` / `Zero_Error`: `th2_offset`. | | `payload.instrument.corrections.Zero_Error.th2_offset` | engine | `[value, flag, min, max]` | `degree 2theta` | yes | Zero error | -| `payload.instrument.corrections.LP_Factor` | engine | block | | no | TOPAS `LP_Factor`: Lorentz-polarisation with a monochromator angle. | +| `payload.instrument.corrections.LP_Factor` | engine | block | | no | TOPAS `LP_Factor`: Lorentz-polarization with a monochromator angle. | | `payload.instrument.corrections.LP_Factor.monochromator_angle` | engine | `[value, flag, min, max]` | `degree` | yes | Monochromator 2theta: 90 synchrotron/neutron, 0 no monochromator | -| `payload.instrument.corrections.LP_Factor_Synchrotron` | engine | block | | no | TOPAS `LP_Factor_Synchrotron` (Madsen): in-plane polarisation and monochromator angle. | -| `payload.instrument.corrections.LP_Factor_Synchrotron.pp` | engine | `[value, flag, min, max]` | `dimensionless` | yes | Polarisation in the plane: 0 ideal synchrotron ... 1 laboratory tube | +| `payload.instrument.corrections.LP_Factor_Synchrotron` | engine | block | | no | TOPAS `LP_Factor_Synchrotron` (Madsen): in-plane polarization and monochromator angle. | +| `payload.instrument.corrections.LP_Factor_Synchrotron.pp` | engine | `[value, flag, min, max]` | `dimensionless` | yes | Polarization in the plane: 0 ideal synchrotron ... 1 laboratory tube | | `payload.instrument.corrections.LP_Factor_Synchrotron.mono` | engine | `[value, flag, min, max]` | `degree` | yes | Monochromator 2theta | | `payload.instrument.corrections.Simple_Axial_Model` | engine | block | | no | TOPAS `Simple_Axial_Model`: one axial length; reads `Rs`. | | `payload.instrument.corrections.Simple_Axial_Model.axial_length_mm` | engine | `[value, flag, min, max]` | `millimetre` | yes | Axial divergence length | diff --git a/docs/_generated/fields_topas_spf.md b/docs/_generated/fields_topas_spf.md index 0f73c0b..6f044d3 100644 --- a/docs/_generated/fields_topas_spf.md +++ b/docs/_generated/fields_topas_spf.md @@ -21,10 +21,10 @@ | `payload.instrument.corrections` | engine | block | | no | Left out: no corrections | | `payload.instrument.corrections.Zero_Error` | engine | block | | no | TOPAS `ZE` / `Zero_Error`: `th2_offset`. | | `payload.instrument.corrections.Zero_Error.th2_offset` | engine | `[value, flag, min, max]` | `degree 2theta` | yes | Zero error | -| `payload.instrument.corrections.LP_Factor` | engine | block | | no | TOPAS `LP_Factor`: Lorentz-polarisation with a monochromator angle. | +| `payload.instrument.corrections.LP_Factor` | engine | block | | no | TOPAS `LP_Factor`: Lorentz-polarization with a monochromator angle. | | `payload.instrument.corrections.LP_Factor.monochromator_angle` | engine | `[value, flag, min, max]` | `degree` | yes | Monochromator 2theta: 90 synchrotron/neutron, 0 no monochromator | -| `payload.instrument.corrections.LP_Factor_Synchrotron` | engine | block | | no | TOPAS `LP_Factor_Synchrotron` (Madsen): in-plane polarisation and monochromator angle. | -| `payload.instrument.corrections.LP_Factor_Synchrotron.pp` | engine | `[value, flag, min, max]` | `dimensionless` | yes | Polarisation in the plane: 0 ideal synchrotron ... 1 laboratory tube | +| `payload.instrument.corrections.LP_Factor_Synchrotron` | engine | block | | no | TOPAS `LP_Factor_Synchrotron` (Madsen): in-plane polarization and monochromator angle. | +| `payload.instrument.corrections.LP_Factor_Synchrotron.pp` | engine | `[value, flag, min, max]` | `dimensionless` | yes | Polarization in the plane: 0 ideal synchrotron ... 1 laboratory tube | | `payload.instrument.corrections.LP_Factor_Synchrotron.mono` | engine | `[value, flag, min, max]` | `degree` | yes | Monochromator 2theta | | `payload.instrument.corrections.Simple_Axial_Model` | engine | block | | no | TOPAS `Simple_Axial_Model`: one axial length; reads `Rs`. | | `payload.instrument.corrections.Simple_Axial_Model.axial_length_mm` | engine | `[value, flag, min, max]` | `millimetre` | yes | Axial divergence length | diff --git a/docs/_generated/ids.md b/docs/_generated/ids.md index d061f05..fccb215 100644 --- a/docs/_generated/ids.md +++ b/docs/_generated/ids.md @@ -1,6 +1,6 @@ -## Engine behaviours +## Engine behaviors | ID | Engine | Title | Status | |---|---|---|---| diff --git a/docs/_generated/known_issues.md b/docs/_generated/known_issues.md index 9c20e11..89cb3c7 100644 --- a/docs/_generated/known_issues.md +++ b/docs/_generated/known_issues.md @@ -193,6 +193,6 @@ {bdg-secondary}`withdrawn` -**What happens:** The reported behaviour was intentional, not a defect. +**What happens:** The reported behavior was intentional, not a defect. **What to do:** Nothing. The id is kept so it is never reused. diff --git a/docs/about/index.md b/docs/about/index.md index a947612..b6af072 100644 --- a/docs/about/index.md +++ b/docs/about/index.md @@ -3,8 +3,8 @@ - [Citing PowderLine](citing.md): the paper, the engines and the libraries behind them. - [Changelog](changelog.md): what changed in each release. -- Licence: PowderLine is released under the - [BSD 3-Clause licence](https://github.com/NSLS2/PowderLine/blob/main/LICENSE). +- License: PowderLine is released under the + [BSD 3-Clause license](https://github.com/NSLS2/PowderLine/blob/main/LICENSE). - Source code and issues: [github.com/NSLS2/PowderLine](https://github.com/NSLS2/PowderLine). PowderLine is developed at the National Synchrotron Light Source II (NSLS-II), diff --git a/docs/catalog/engine_behaviour.yaml b/docs/catalog/engine_behaviour.yaml index 775dba8..f8baa6f 100644 --- a/docs/catalog/engine_behaviour.yaml +++ b/docs/catalog/engine_behaviour.yaml @@ -1,4 +1,4 @@ -# PowderLine engine-behaviour catalogue (public). +# PowderLine engine-behavior catalog (public). # # One entry per EB-NN id: what an engine does on its own, and what PowderLine # does about it. scripts/gen_catalog.py renders it into docs/_generated/ @@ -45,7 +45,7 @@ # stops the run. A recipe cannot meet it silently. # warned The run goes ahead and the result carries a warning (or a # field) that names it. -# documented Documented only: the engine's behaviour stands, and the +# documented Documented only: the engine's behavior stands, and the # entry tells you what to expect. # fixed-upstream Fixed in the engine version PowderLine pins; the entry # stays for its id. @@ -471,7 +471,7 @@ GSAS-II carries negative `Uiso` and `Uij` values and refines from them. powderline_does: >- Core has no sign rule for ADPs: a negative ADP can compensate for an - unmodelled effect. + unmodeled effect. you_see: [] status: documented @@ -725,7 +725,7 @@ topic: bounds title: The limit markers TOPAS writes are unreliable engine_does: >- - The `_LIMIT_MIN` and `_LIMIT_MAX` markers TOPAS 6 writes are mislabelled + The `_LIMIT_MIN` and `_LIMIT_MAX` markers TOPAS 6 writes are mislabeled or spurious. powderline_does: >- The at-limit warning is judged from the final values and the limits the @@ -743,7 +743,7 @@ limit: cell lengths 0–30 Å, angles 0–180°, occupancy 0–1, `adp_iso` and U11/U22/U33 0–10 Ų, scale, wavelength and μR ≥ 0. It refuses a value outside a physical limit at input, even when fixed, so no cell over 30 Å - can be modelled. lmfit moves a start outside its bounds onto the bound + can be modeled. lmfit moves a start outside its bounds onto the bound without a message. powderline_does: >- A stated bound replaces the physical limit on its side, and `null` keeps @@ -857,7 +857,7 @@ from X = 0. X = −0.1 makes the width negative at the top of the window, and TOPAS writes no results: a negative convolution FWHM stops TOPAS. powderline_does: >- - PowderLine honours what TOPAS computes: a negative Lorentzian part passes + PowderLine honors what TOPAS computes: a negative Lorentzian part passes while the total width is positive. With `TCHZ_Peak_Type`, the total width at the recipe's starting values must be positive at every data point of the fit window. Otherwise validation fails and names X, Y and the 2θ where @@ -915,14 +915,14 @@ topic: profile title: The X-ray corrections easydiffraction models, and its polarization engine_does: >- - Both calculators model the Kα doublet, the Lorentz-polarization factor - 1 − p + p cos²2θ_m cos²2θ, the 2θ offset, sample displacement and + Both calculators model the Kα doublet, the Lorentz factor and the + polarization factor 1 − p + p cos²2θ_m cos²2θ, the 2θ offset, sample displacement and transparency, and Hewat cylinder absorption. A second wavelength alone does nothing. 2θ_m acts only with p > 0. GSAS-II's polarization P is easydiffraction's 1 − p: copying P to p is a 6.6 % intensity error at 15° 2θ. powderline_does: >- - Every correction is a recipe slot; left out means not modelled. The + Every correction is a recipe slot; left out means not modeled. The schema requires both Kα2 fields or neither. The hand-derived per-engine recipes state p = 1 − P. you_see: [validation error] @@ -972,14 +972,14 @@ topic: preferred-orientation title: CrysPy's March correction is Dollase's times r^1.5 engine_does: >- - CrysPy's texture correction is not volume-normalised, so every + CrysPy's texture correction is not volume-normalized, so every textured-to-untextured intensity ratio carries the constant r^1.5. With `march_random_fract` = 0 the scale absorbs it, and the refined `march_r` is the same r as GSAS-II's. With f > 0 the correction is (1 − f)·r^1.5·A + f, and the refined r and f are not GSAS-II's quantities. powderline_does: >- - Documented. A test compares normalised ratios with GSAS-II's + Documented. A test compares normalized ratios with GSAS-II's March–Dollase correction. you_see: [] status: documented @@ -1286,7 +1286,7 @@ title: A symmetric profile shifts the refined cell engine_does: >- Lattice parameters agree between GSAS-II and easydiffraction when axial - asymmetry is modelled physically (FCJ). With a symmetric profile they + asymmetry is modeled physically (FCJ). With a symmetric profile they shift by +67 to +91 ppm, whichever calculator runs it. powderline_does: >- Documented on the cross-engine comparison. Rwp compares models fitted to @@ -1349,7 +1349,8 @@ title: CrysFML's integrated intensities drift with angle engine_does: >- Relative to m·|F|²·Lorentz, CrysFML's integrated intensities drift by - −4 % from 3° to 15° 2θ. This biases `Uiso` by about +0.001 Ų. + −4 % from 3° to 15° 2θ. A drift this size is worth about 0.001 Ų of + `Uiso`; a refinement compensates by lowering `Uiso`. powderline_does: >- The calculator is recorded in every result. you_see: [] @@ -1362,13 +1363,15 @@ title: On the temperature series, easydiffraction refines La's Uiso low engine_does: >- On GSAS-II-calculated LaB6 patterns, easydiffraction refines La's Uiso - 10–22 % low. B's Uiso, the thermal expansion and GoF ≈ 1 agree. The cause - is the series' profile: GSAS-II clamps its Lorentzian width to + 10–22 % low. B's Uiso, the thermal expansion and GoF ≈ 1 agree. Most of + it comes from the series' profile: GSAS-II clamps its Lorentzian width to 0.001 centideg above about 10.7°, so the high-angle peaks are pure Gaussian. Neither a symmetric pseudo-Voigt nor TCH can represent that, and `Uiso` absorbs the mismatch. Simulated with a profile easydiffraction can represent, CrysPy's La Uiso is 0.00863 against 0.00858 programmed. - CrysFML's is 0.00823 (−4 %), the size of its intensity drift (EB-78). + CrysFML's is 0.00823 (−4 %); its remaining profile mismatch and its + intensity drift (EB-78) both act on `Uiso`, and the two were not + separated. powderline_does: >- Documented, no code change. Across engines, compare cells, with the EB-88-size offsets in mind, and the expansion. Absolute `Uiso` agrees only diff --git a/docs/catalog/known_issues.yaml b/docs/catalog/known_issues.yaml index 6618785..474b088 100644 --- a/docs/catalog/known_issues.yaml +++ b/docs/catalog/known_issues.yaml @@ -1,6 +1,6 @@ -# PowderLine known-issues catalogue (public). +# PowderLine known-issues catalog (public). # -# One entry per KI-NN id: a known behaviour of PowderLine itself, what it +# One entry per KI-NN id: a known behavior of PowderLine itself, what it # does today and what to do about it. scripts/gen_catalog.py renders it into # docs/_generated/known_issues.md (included by reference/known-issues.md) # and docs/_generated/ids.md; `--check` fails when a KI id used in src/ or @@ -174,7 +174,7 @@ title: Withdrawn status: withdrawn what_happens: >- - The reported behaviour was intentional, not a defect. + The reported behavior was intentional, not a defect. what_to_do: >- Nothing. The id is kept so it is never reused. diff --git a/docs/concepts/comparing-engines.md b/docs/concepts/comparing-engines.md index 30e6571..ce7e540 100644 --- a/docs/concepts/comparing-engines.md +++ b/docs/concepts/comparing-engines.md @@ -1,7 +1,7 @@ # Comparing engines -What happens when the same data are refined by different engines? This page -shows two reference cases, refined by every engine PowderLine drives and by +What happens when models are refined against the same data in different +engines? This page shows two reference cases, refined in every engine PowderLine drives and by each profile model the engines offer, and explains why the numbers differ. It does not rank the engines. @@ -26,7 +26,7 @@ model, and sometimes an unphysical one. - **Source.** `run` means the engine was run for this page. `golden` means the row is rebuilt from a stored reference run: the engine's committed output files, named after the recipe that produced them. The TOPAS rows - are always stored runs, produced on a computer with a TOPAS licence. + are always stored runs, produced on a computer with a TOPAS license. - **The LaB6 cell is refined** in every row here, unlike `example_LaB6`, which holds it at the certified value. That is why the GSAS-II LaB6 row differs from that example. @@ -58,10 +58,13 @@ Two lessons: ({ref}`EB-87 `, warning `easydiffraction_negative_width`). - **Compare cells, and know what each model was free to do.** -**Against the NIST certificate.** Every refined LaB6 cell sits about +80 to -+180 ppm above the certified a = 4.156826(8) Å. The offset is common to all -engines, so it belongs to the measurement, not to the refinement: the -wavelength and the sample position were not refined against the standard. +**Against the NIST certificate.** Every refined LaB6 cell sits above the +certified a = 0.415 682 6 nm ± 0.000 008 nm (expanded uncertainty, k = 2): by +84 to +94 ppm with +a physical asymmetry model, and by +161 to +181 ppm with a symmetric profile (the shift above). +The common part is in the data, not in an engine: the pattern was integrated +from 2D detector images without a parallax correction, which shifts the +peaks. A zero shift has the wrong angular dependence to correct that and +only partly compensates, so the recipes leave it at 0. The Δ vs GSAS-II columns are the ones that compare engines. **CrysFML depends on its starting values.** CrysFML computes in single @@ -80,13 +83,14 @@ GSAS-II with a known cell and Uiso. Refined by easydiffraction: | CrysFML, Thompson–Cox–Hastings + FCJ | 14–31 ppm low (1.7–4 ESD) | recovered to 0.8 % | 10–22 % low (8–12 ESD) | | CrysPy, symmetric pseudo-Voigt | +68 ppm (the asymmetry shift above) | — | 17 % low | -The cause is the peak shape, not the intensities ({ref}`EB-93 `). The +Most of the shortfall comes from the peak shape ({ref}`EB-93 `). The simulated peaks carry a GSAS-II Lorentzian width that neither easydiffraction profile can represent, and the mismatch lands in the parameter that most affects intensity versus angle: Uiso. Simulated with a profile easydiffraction *can* represent, the same pattern gives a La Uiso of 0.00863 with CrysPy and 0.00868 with GSAS-II, against 0.00858 programmed. CrysFML gives 0.00823, 4 % -low, the size of its own intensity drift ({ref}`EB-78 `). +low; its remaining profile mismatch and its intensity drift +({ref}`EB-78 `) both act on Uiso, and the two were not separated. **Lesson:** compare cells and their changes across engines. Compare absolute displacement parameters only when the profile models agree. diff --git a/docs/concepts/how-powderline-works.md b/docs/concepts/how-powderline-works.md index 26d8ccc..1a1a46b 100644 --- a/docs/concepts/how-powderline-works.md +++ b/docs/concepts/how-powderline-works.md @@ -154,7 +154,7 @@ flowchart LR ## 5. Metadata and provenance travel with the analysis A recipe can carry a free-form `metadata` block: a sample ID, a scan ID, the -data's location in your catalogue, how the recipe was generated. PowderLine +data's location in your catalog, how the recipe was generated. PowderLine never reads it, but carries it through. Every run gets its own ID. The output recipe records which run produced it, @@ -194,5 +194,5 @@ fourth gateway; nothing else changes. See - The PowderLine [preprint](https://doi.org/10.48550/arXiv.2608.17009) describes the design and its motivation. -- [Comparing engines](comparing-engines.md) refines the same data in every +- [Comparing engines](comparing-engines.md) fits the same data in every engine and explains why the numbers differ. diff --git a/docs/concepts/recipes.md b/docs/concepts/recipes.md index 6723530..c21ea3e 100644 --- a/docs/concepts/recipes.md +++ b/docs/concepts/recipes.md @@ -12,7 +12,7 @@ it is a `dict`. When it is stored or sent it is JSON. That makes a recipe easy to produce and to move: - a script or notebook can build one from your reduced data and a CIF; -- a database or catalogue can store one next to the measurement it analyses; +- a database or catalog can store one next to the measurement it analyzes; - a pipeline can fill one from a live data stream and pass it on; - a GUI or an LLM assistant can write one, and validation tells it what to fix. @@ -135,7 +135,7 @@ build recipes for you and has no CIF reader. That is deliberate: special position. Guessing silently is exactly what validation refuses. So the tool that knows where your data came from does the conversion, and -PowderLine checks the result. [Refine your own data](../getting-started/your-own-data.md) +PowderLine checks the result. [Analyze your own data](../getting-started/your-own-data.md) shows the steps. The `examples/` folder has complete recipes for every engine, and `examples/example_template/` has blank skeletons. diff --git a/docs/concepts/refinement-practice.md b/docs/concepts/refinement-practice.md index 344aeff..3653820 100644 --- a/docs/concepts/refinement-practice.md +++ b/docs/concepts/refinement-practice.md @@ -24,8 +24,8 @@ starting point, not a substitute for the references at the end. the noise level; Rwp well above it means a misfit the model does not explain. Rwp well below it (GoF < 1) usually means the weights overstate the noise. A pattern dominated by background can give a low Rwp with a wrong structural - model, and counting longer can *raise* χ² while improving the model - ([Toby 2006](#ref-toby2006)). + model, and counting longer can *raise* χ² for the same model, because the + smaller noise exposes its systematic errors ([Toby 2006](#ref-toby2006)). - **Compare models on the same points.** PowderLine's uniform Rwp, Rexp and GoF use the same points for every engine, so two models of the same data can be compared directly. Comparing Rwp across *different* datasets says @@ -55,7 +55,7 @@ large, correlated uncertainties and values that can drift to unphysical ones. |---|---|---| | Crystallite size and microstrain | Both broaden peaks. They differ only in how the broadening changes with angle: size as 1/cos θ, strain as tan θ. | A wide angular range with well-resolved peaks. Otherwise refine one and hold the other. In the IUCr size–strain round robin, many Rietveld refinements wrongly attributed size broadening to strain ([Balzar et al. 2004](#ref-balzar2004)). | | Occupancy and displacement parameter of a site | Both scale how strongly the site scatters. | Refine one at a time, or fix one from chemistry. Releasing both for oxygen limited accuracy with X-ray data in the IUCr round robin ([Hill 1992](#ref-hill1992)). | -| Scale, background and displacement parameters | All change overall intensity with angle. | A sensible number of background terms; check the correlation after the fit. | +| Scale, background and displacement parameters | All change the overall intensity or its fall-off with angle. | A sensible number of background terms; check the correlation after the fit. | | Light atoms with X-rays (Li, B, H) | They scatter weakly next to heavy atoms. | Expect large uncertainties; consider holding their parameters. | ## Check the result is physical @@ -65,7 +65,7 @@ large, correlated uncertainties and values that can drift to unphysical ones. chemically reasonable ([McCusker et al. 1999](#ref-mccusker1999)). - Least-squares uncertainties from a Rietveld refinement usually **underestimate** the true uncertainty ([McCusker et al. 1999](#ref-mccusker1999)). -- The same data analysed by different people can give different answers, and +- The same data analyzed by different people can give different answers, and the refinement strategy is a large part of why ([Hill 1992](#ref-hill1992); [Madsen et al. 2001](#ref-madsen2001)). Recording the strategy matters. A chain of recipes records it exactly. diff --git a/docs/concepts/results.md b/docs/concepts/results.md index 7948e38..1fc5601 100644 --- a/docs/concepts/results.md +++ b/docs/concepts/results.md @@ -99,7 +99,7 @@ A column `at_limit` marks values that ended on a bound. ## Provenance A recipe's `metadata` block is yours: sample IDs, scan IDs, where the data -live in your catalogue, how the recipe was made. PowderLine never reads it and +live in your catalog, how the recipe was made. PowderLine never reads it and carries it through to the output recipe. PowderLine adds one entry of its own, `metadata.powderline_provenance`, to diff --git a/docs/concepts/validation.md b/docs/concepts/validation.md index 06a0a19..9a76026 100644 --- a/docs/concepts/validation.md +++ b/docs/concepts/validation.md @@ -98,7 +98,7 @@ but by symmetry b = a; write b = 4.15682 An atom is either **on** a special position or clearly **off** it. PowderLine applies every symmetry operation to the atom and measures `d`, the distance between the atom and that image: the largest of the three -fractional-coordinate differences. On a mirror or an inversion centre, `d` is +fractional-coordinate differences. On a mirror or an inversion center, `d` is twice the atom's offset from the site. Each image is judged on its own: | `d` of an image (fractional) | PowderLine reads it as | @@ -164,7 +164,7 @@ stated: recipes refuse it, because easydiffraction limits displacement parameters to physical values. -## Validation is not judgement +## Validation is not judgment Passing validation means the recipe is **well formed and consistent with its symmetry**. It doesn't mean it is the model you intended, or that your data diff --git a/docs/conf.py b/docs/conf.py index 0251840..9077801 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -60,7 +60,7 @@ exclude_patterns = [ '_build', 'Thumbs.db', '.DS_Store', '_generated', # script-generated fragments pulled in with MyST {include}, not pages of their own - 'catalog', # the public engine-behaviour / known-issues catalogue (data, rendered by a script) + 'catalog', # the public engine-behavior / known-issues catalog (data, rendered by a script) ] # Treat missing cross-reference targets as warnings (not silently ignored) diff --git a/docs/development/adding-an-engine.md b/docs/development/adding-an-engine.md index 4c8a3b9..85db819 100644 --- a/docs/development/adding-an-engine.md +++ b/docs/development/adding-an-engine.md @@ -48,7 +48,7 @@ registers a gateway in code without an entry point. `json_schema_extra={"unit": ...}`, which the field tables read. Keep `extra='forbid'`. A block that may be left out is left out, never `null`. - - Add no default that silently replaces an engine behaviour. Either the + - Add no default that silently replaces an engine behavior. Either the value is required, or the default is documented and reported with a structured warning. - Write the recipe models as subclasses of `schema_core.EngineRecipe`, @@ -164,8 +164,8 @@ The goldens are the references. A change in what the engine is asked to do matrix regenerates itself. - Write the engine page under `docs/engines/` and add a column to the feature table on [Engines](../engines/index.md). -- Add a catalogue entry in `docs/catalog/engine_behaviour.yaml` for every - engine behaviour a user can meet, with PowderLine's policy. Regenerate with +- Add a catalog entry in `docs/catalog/engine_behaviour.yaml` for every + engine behavior a user can meet, with PowderLine's policy. Regenerate with `scripts/gen_catalog.py`. Anything the engine does silently is written up before the gateway ships. - Add the engine schema's entry to [Versions](../reference/versions.md) and a @@ -176,7 +176,7 @@ The goldens are the references. A change in what the engine is asked to do The same discipline, smaller. 1. **Find the ground truth.** Read and run the engine to see what it does with - the quantity. If the engine's behaviour is unknown, ask the maintainers + the quantity. If the engine's behavior is unknown, ask the maintainers rather than infer it. 2. **Add the field** to the engine's `schema.py`, with its unit, validators and refusals. A structural quantity shared by every engine goes into @@ -185,7 +185,7 @@ The same discipline, smaller. this way (`schema_core.MarchDollase`). 3. **Consume it in the runtime layer** from the validated model. For gsasii, put the read in a non-frozen module. A read inside a frozen module is a - behaviour change and needs the maintainers' consent + behavior change and needs the maintainers' consent ([Policies](policies.md#frozen-gsas-ii-code)). Map the refined parameter back to its recipe path (gsasii `paths.py`) so it reaches the output recipe. @@ -194,10 +194,10 @@ The same discipline, smaller. simulated pattern as the gate, and an example as the demonstration. 5. **Add an example** if it is a real case: `examples//` with its `DESCRIPTION.md` and, for gsasii, the committed output. -6. **Record it.** Regenerate the field tables, add catalogue entries for +6. **Record it.** Regenerate the field tables, add catalog entries for anything the engine does silently, and update [Versions](../reference/versions.md) and the CHANGELOG. If the new field changes what an existing recipe means, it is a deliberate change: a schema version bump, a CHANGELOG entry, and a note for users -([Policies](policies.md#deliberate-behaviour-changes)). +([Policies](policies.md#deliberate-behavior-changes)). diff --git a/docs/development/architecture.md b/docs/development/architecture.md index b8f45ae..d054ae8 100644 --- a/docs/development/architecture.md +++ b/docs/development/architecture.md @@ -192,7 +192,7 @@ flowchart TD SV --> R ``` -| Mode | CLI | Behaviour | +| Mode | CLI | Behavior | |---|---|---| | `auto` | default | Uses the server, starting it if needed; runs in-process if it is unavailable | | `server` | `--use-server` | Server only; fails if the server cannot be used | @@ -272,7 +272,7 @@ functions that set up and run a GSAS-II refinement: `helpers.py`, These conventions can't be fully pinned down by tests, so the modules are frozen. -- A behaviour-changing edit needs the maintainers' explicit consent. +- A behavior-changing edit needs the maintainers' explicit consent. - Comment and docstring edits need no consent. - `src/powderline/_code_hash.json` holds a hash of each module's raw bytes, and `tests/test_code_hash.py` fails when a module changes. After **any** @@ -280,7 +280,7 @@ frozen. change. The full rule is on [Policies](policies.md#frozen-gsas-ii-code). New -behaviour goes into the modules around the frozen code: +behavior goes into the modules around the frozen code: | Module | What it adds | |---|---| @@ -298,7 +298,7 @@ GSAS-II's own defaults are never used. GSAS-II sets refine flags in lumps (one for the cell, one for all three coordinates of an atom). `constraints.py` sets the lumped flag and adds GSAS-II "Hold" constraints for the parts the recipe does not refine. The schema has already refused any flag pattern -GSAS-II could not honour. +GSAS-II could not honor. ## Output generation diff --git a/docs/development/contributing.md b/docs/development/contributing.md index 39c0b08..3ea9b40 100644 --- a/docs/development/contributing.md +++ b/docs/development/contributing.md @@ -110,7 +110,7 @@ start-dependent points ({ref}`EB-90 `), so their goldens compare only the counts, the warnings and the cell. A reference moves only as a deliberate change, with an equivalence check -([Policies](policies.md#deliberate-behaviour-changes)). +([Policies](policies.md#deliberate-behavior-changes)). ## Build the docs @@ -128,7 +128,7 @@ same change that affects them, and commit the result. | Script | Writes | Check | |---|---|---| | `scripts/gen_schema_field_tables.py` | The field tables and support matrix in `docs/_generated/` | `pixi run fields-check` | -| `scripts/gen_catalog.py` | The engine-behaviour entries, the ID index and the known-issue entries, from `docs/catalog/*.yaml` | `pixi run catalog-check` | +| `scripts/gen_catalog.py` | The engine-behavior entries, the ID index and the known-issue entries, from `docs/catalog/*.yaml` | `pixi run catalog-check` | | `scripts/gen_example_figures.py` | The example gallery's figures, from each example's committed `fit_profile.txt` | `pixi run figures-check` | | `scripts/cross_engine_comparison.py` | The cross-engine comparison tables in `docs/_generated/` | none; `--no-run` rebuilds from committed results | @@ -139,7 +139,7 @@ declarations: pixi run python scripts/gen_schema_field_tables.py ``` -The engine-behaviour entries, the [ID index](../reference/ids.md) and +The engine-behavior entries, the [ID index](../reference/ids.md) and [Known issues](../reference/known-issues.md) are generated from `docs/catalog/engine_behaviour.yaml` and `docs/catalog/known_issues.yaml`. Edit the YAML, never the generated pages, then run @@ -184,7 +184,7 @@ These rules keep the pages consistent. They apply to every page under "no longer" or "previously". History belongs in the CHANGELOG. - **One home per fact.** Write a fact on the page that owns it. Everywhere else, write one sentence and link it. -- **A recipe is structured data.** It is a dictionary, serialised as JSON. +- **A recipe is structured data.** It is a dictionary, serialized as JSON. Don't define it as a file. - **Engine differences in tabs.** Use a sphinx-design `tab-set` with `:sync-group: engine` and the keys `gsasii`, `topas` and `easydiffraction`. @@ -267,7 +267,7 @@ points are missing and `GatewayNotInstalledError` follows. Fix that with 2. For a GSAS-II regression, compare the engine's log: `diff output/dummy.lst examples/example_LaB6/output/dummy.lst`. 3. If your change moves a result on purpose, it is a deliberate change - ([Policies](policies.md#deliberate-behaviour-changes)). Regenerate the + ([Policies](policies.md#deliberate-behavior-changes)). Regenerate the reference only then, for example: ```bash @@ -277,9 +277,9 @@ points are missing and `GatewayNotInstalledError` follows. Fix that with ### `test_code_hash` fails A frozen GSAS-II module changed. If the edit is a comment or docstring edit, -or a behaviour change the maintainers agreed to, run +or a behavior change the maintainers agreed to, run `pixi run update-code-hash` and commit `src/powderline/_code_hash.json` with -it. Otherwise revert the edit and put the behaviour in a non-frozen module +it. Otherwise revert the edit and put the behavior in a non-frozen module ([Architecture](architecture.md#the-frozen-gsas-ii-modules)). ### A generated-docs check fails diff --git a/docs/development/policies.md b/docs/development/policies.md index 50d77cd..17ee7aa 100644 --- a/docs/development/policies.md +++ b/docs/development/policies.md @@ -1,7 +1,7 @@ # Policies These rules bind every change to PowderLine: how versions are numbered, how -behaviour changes on purpose, which code is frozen, how engine versions move, +behavior changes on purpose, which code is frozen, how engine versions move, and how changes are reviewed. They also tell users what a version number promises. @@ -34,9 +34,9 @@ promises. The current declarations and the schema history are on [Versions](../reference/versions.md). -## Deliberate behaviour changes +## Deliberate behavior changes -Refinement results are regression references, so a change in behaviour is +Refinement results are regression references, so a change in behavior is never incidental. - **Every intentional change is deliberate.** A default, a validation rule, @@ -63,12 +63,12 @@ refinement by manipulating GSAS-II's project dictionary: GSAS-II's project-dictionary conventions can't be fully pinned down by tests. So these functions change only with the maintainers' explicit consent. -- **Behaviour-changing edits** need the maintainers' explicit consent before +- **Behavior-changing edits** need the maintainers' explicit consent before they are made. Propose the edit with its reason and its proof (for example, a diff of the project dictionary before and after). -- **Comment and docstring edits** need no consent: they change no behaviour. +- **Comment and docstring edits** need no consent: they change no behavior. Don't leave an outdated comment in place. -- **New behaviour** goes into the non-frozen modules around them +- **New behavior** goes into the non-frozen modules around them (`fit_report.py`, `sites.py`, `routing.py`, `paths.py`, `gateway.py`). - **After any edit**, run `pixi run update-code-hash` and commit `src/powderline/_code_hash.json` with the change. The hash covers the raw @@ -135,9 +135,9 @@ pixi run python scripts/check_engine_version_candidate.py --engine topas --versi 4. **On a pass**, open one pull request that moves the pin and the specifier together and updates every page that names the engine version. The references are not regenerated. -5. **On a fail**, record the behaviour change in the same report. Decide +5. **On a fail**, record the behavior change in the same report. Decide between a schema bump (with a re-baseline, see - [Deliberate behaviour changes](#deliberate-behaviour-changes)) and staying + [Deliberate behavior changes](#deliberate-behavior-changes)) and staying pinned. The pin stays where it is until that decision is made. Per engine: @@ -153,13 +153,13 @@ Per engine: `space_group_support.py`. `tests/test_easydiffraction_space_groups.py` skips until `space_group_table.py` is regenerated for the installed version (`scripts/generate_easydiffraction_space_groups.py`). Re-check the - behaviours on the [easydiffraction page](../engines/easydiffraction.md): an + behaviors on the [easydiffraction page](../engines/easydiffraction.md): an upstream fix may retire a workaround. - **TOPAS.** The goldens live under `tests/data/topas/native/golden//`, chosen by each fixture's `engine_version`. Adding TOPAS 7 needs a TOPAS 7 installation for the `topas_exec` run, its own goldens, and a check of TOPAS 7's convergence. It - also needs every behaviour on the [TOPAS page](../engines/topas.md) marked + also needs every behavior on the [TOPAS page](../engines/topas.md) marked unverified for TOPAS 7 to be checked on TOPAS 7. The generation suite (`topas_gen`) runs anywhere and compares INPs byte for byte with the TOPAS 6 goldens, so a change in what is written shows without @@ -181,7 +181,7 @@ Per engine: If a design decision is not written down (on this page, on [Versions](../reference/versions.md) or on an [engine page](../engines/index.md)), stop and ask the maintainers. Don't infer the answer from the code's current -behaviour or from what another engine does. Write the answer down where the +behavior or from what another engine does. Write the answer down where the next contributor will find it. The reason is the project's whole stance. An engine's silent default is not a diff --git a/docs/engines/easydiffraction.md b/docs/engines/easydiffraction.md index ef05426..3101b5c 100644 --- a/docs/engines/easydiffraction.md +++ b/docs/engines/easydiffraction.md @@ -109,7 +109,7 @@ error at 15° 2θ ({ref}`EB-75 `). ### Nothing has a default Every control is stated, and an instrument slot you leave out is not -modelled. A recipe without `background` has no background. A recipe with no +modeled. A recipe without `background` has no background. A recipe with no refine flag set is a simulation: lmfit is not run. ### Bounds @@ -120,7 +120,7 @@ physical limit on that side, and `null` keeps it ({ref}`EB-71 `). - The physical limits: cell lengths 0–30 Å, angles 0–180°, occupancy 0–1, `Uiso` and U11, U22, U33 0–10 Ų, and scale, wavelength and μR ≥ 0. - A value outside a physical limit is a validation error, even when it is - fixed. So no cell over 30 Å can be modelled. + fixed. So no cell over 30 Å can be modeled. - A refined value that ends within 1e-6 (relative) of a bound or a physical limit gets `easydiffraction_parameter_at_limit`. For a limit of 0, the test is within 1e-6 of the starting value. @@ -130,7 +130,7 @@ Bounds in every engine: [Recipe format](../reference/recipe-format.md#bounds). ## The instrument block Each correction easydiffraction models for constant-wavelength X-ray powder -data is a slot. A slot you leave out is not modelled. +data is a slot. A slot you leave out is not modeled. | Block | Fields | |---|---| @@ -193,8 +193,9 @@ displacement and transparency, and Hewat cylinder absorption settings whose computation passed for a general position and for every special site. The error names a setting of the same group that the calculator computes, or the other calculator ({ref}`EB-80 `). -- **CrysFML's intensities drift** by −4 % from 3° to 15° 2θ, which biases - `Uiso` by about +0.001 Ų ({ref}`EB-78 `). +- **CrysFML's intensities drift** by −4 % from 3° to 15° 2θ. A drift this + size is worth about 0.001 Ų of `Uiso`, and a refinement compensates by + lowering `Uiso` ({ref}`EB-78 `). - **Absolute `Uiso` agrees across engines only when the profile models agree.** On the LaB6 temperature series, easydiffraction refines La's `Uiso` 10–22 % low ({ref}`EB-93 `). Compare cells and expansion @@ -222,7 +223,7 @@ easydiffraction runs in the same process as PowderLine. - **Offline,** importing easydiffraction prints a warning about a PyPI version check and continues ({ref}`EB-82 `). -## Behaviours +## Behaviors Each entry says what easydiffraction does on its own and what PowderLine does about it. Messages and the changelog cite these IDs. diff --git a/docs/engines/gsasii.md b/docs/engines/gsasii.md index f24124c..d2e82aa 100644 --- a/docs/engines/gsasii.md +++ b/docs/engines/gsasii.md @@ -91,7 +91,7 @@ and [Fields: `gsasii.spf`](../reference/fields.md#gsasiispf). | Quantity | GSAS-II unit | |---|---| | `U`, `V`, `W` (Gaussian variance) | centidegree² | -| `X`, `Y`, `Z`, `zero_shift` | centidegree | +| `X`, `Y`, `Z` | centidegree | | `axial_divergence` (SH/L) | dimensionless | | `pv_gaussian_sigma_sq` (peak σ²) | centidegree² | | `pv_lorentzian_gamma` (peak γ) | centidegree | @@ -220,7 +220,7 @@ How to start, check and secure the server, and how to limit the wait for it: console text GSAS-II printed ({ref}`KI-05 `). Details: [Outputs](../reference/outputs.md#when-a-run-fails). -## Behaviours +## Behaviors Each entry says what GSAS-II does on its own and what PowderLine does about it. Messages and the changelog cite these IDs. diff --git a/docs/engines/index.md b/docs/engines/index.md index e38c262..3720561 100644 --- a/docs/engines/index.md +++ b/docs/engines/index.md @@ -144,7 +144,7 @@ PowderLine does not rank the engines. What each one needs and offers: tested). It does Rietveld refinement only, with bounds, and you choose one of two calculators. -The same data refined in every engine, and why the numbers differ, is in +The same data fitted in every engine, and why the numbers differ, is in [Comparing engines](../concepts/comparing-engines.md). ## How PowderLine treats engine quirks @@ -159,8 +159,8 @@ rule: unchanged, PowderLine runs and adds a warning to the result. The pages for [GSAS-II](gsasii.md), [TOPAS](topas.md) and -[easydiffraction](easydiffraction.md) list each behaviour PowderLine has -found, with what it does about it. Each behaviour has a permanent ID, +[easydiffraction](easydiffraction.md) list each behavior PowderLine has +found, with what it does about it. Each behavior has a permanent ID, `EB-NN`, that messages and the changelog cite. Every ID is listed in the [ID index](../reference/ids.md), and every warning code in [Messages](../reference/messages.md). @@ -171,16 +171,16 @@ Each entry carries a status: |---|---| | {bdg-success}`handled` | PowderLine prevents or corrects it: a validation error, a translation, or a check that stops the run. | | {bdg-warning}`warned` | The run goes ahead, and the result carries a warning that names it. | -| {bdg-secondary}`documented` | Documented only. The engine's behaviour stands, and the entry tells you what to expect. | +| {bdg-secondary}`documented` | Documented only. The engine's behavior stands, and the entry tells you what to expect. | | {bdg-info}`fixed upstream` | Fixed in the engine version PowderLine pins. | -The behaviours were established on GSAS-II 5.7.9, TOPAS 6 (TOPAS 7 where +The behaviors were established on GSAS-II 5.7.9, TOPAS 6 (TOPAS 7 where noted) and easydiffraction 0.21.1 with CrysPy 0.13.0 and CrysFML 0.8.0. An entry marked *unverified* is recorded from documentation or a model, not from a run. How PowderLine decides a policy is in [Policies](../development/policies.md). -## Behaviours that concern every engine +## Behaviors that concern every engine ```{include} ../_generated/eb_all.md ``` diff --git a/docs/engines/topas.md b/docs/engines/topas.md index af0c817..30445eb 100644 --- a/docs/engines/topas.md +++ b/docs/engines/topas.md @@ -113,7 +113,7 @@ reports LVol-IB and e0, computed by TOPAS, as derived rows ### Nothing has a default -A block you leave out is not modelled. Everything PowderLine would otherwise +A block you leave out is not modeled. Everything PowderLine would otherwise choose is a required field. A recipe without `background` has no background. ### Bounds @@ -258,7 +258,7 @@ TOPAS 6 write nothing. Latin-1 names and spaces work. ({ref}`KI-16 `). TOPAS 7 needs an explicit widening, with its own compatibility run. -## Behaviours +## Behaviors Each entry says what TOPAS does on its own and what PowderLine does about it. Messages and the changelog cite these IDs. diff --git a/docs/examples/index.md b/docs/examples/index.md index bfa99d5..c378708 100644 --- a/docs/examples/index.md +++ b/docs/examples/index.md @@ -35,7 +35,7 @@ They are also the regression references, so a change to them is a deliberate change. The figures show the committed fit over the fit window: the observed pattern -in grey, the calculated pattern in blue and the difference curve in orange, +in gray, the calculated pattern in blue and the difference curve in orange, below. ## Starting points @@ -48,7 +48,7 @@ below. :img-alt: Observed, calculated and difference curves of the LaB6 fit :link: https://github.com/NSLS2/PowderLine/tree/main/examples/example_LaB6 -Fit the NIST SRM 660c standard to measure the instrument profile. +Refine against a NIST SRM 660c pattern to determine the instrument profile. Rwp 6.53 %. {bdg-primary}`calibration` {bdg-secondary}`GSAS-II · TOPAS · easydiffraction` @@ -70,8 +70,8 @@ microstrain is refined. Rwp 8.46 %. :img-alt: Observed, calculated and difference curves of the first temperature step :link: https://github.com/NSLS2/PowderLine/tree/main/examples/example_LaB6_temperature_series -Six simulated patterns from 25 to 500 °C, refined in sequence through the -output recipe. The figure shows the first step in easydiffraction. +One model refined in sequence against six simulated patterns from 25 to +500 °C, through the output recipe. The figure shows the first step in easydiffraction. {bdg-primary}`sequential` {bdg-info}`simulated` {bdg-secondary}`GSAS-II · easydiffraction` ::: @@ -111,7 +111,7 @@ These examples show what an ill-posed refinement looks like. :::{admonition} These examples are ill-posed on purpose :class: caution -They ask the data for more than it can determine. They are kept as they are, +They ask more of the data than the data can determine. They are kept as they are, so you can see what that looks like and which signals PowderLine gives. Each one names its well-posed variant where one exists. Don't copy their refinement choices. diff --git a/docs/getting-started/first-refinement.md b/docs/getting-started/first-refinement.md index 7cbd024..6417783 100644 --- a/docs/getting-started/first-refinement.md +++ b/docs/getting-started/first-refinement.md @@ -142,4 +142,4 @@ explains why the results differ slightly. You checked a recipe, ran it, and read standard results. Next, see [how PowderLine works](../concepts/how-powderline-works.md), or go straight to -[refining your own data](your-own-data.md). +[analyzing your own data](your-own-data.md). diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index a8d8a1e..41b5b13 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -5,7 +5,7 @@ New to PowderLine? Work through these in order. 1. [Install](install.md) PowderLine and an engine. 2. [Your first refinement](first-refinement.md): run a complete refinement of LaB6 and read the results. -3. [Refine your own data](your-own-data.md): write a recipe for your +3. [Analyze your own data](your-own-data.md): write a recipe for your pattern and structure, validate it and run it. To understand what is happening along the way, read diff --git a/docs/getting-started/your-own-data.md b/docs/getting-started/your-own-data.md index 7590d94..a195ab1 100644 --- a/docs/getting-started/your-own-data.md +++ b/docs/getting-started/your-own-data.md @@ -1,4 +1,4 @@ -# Refine your own data +# Analyze your own data This tutorial takes you from your own pattern and structure to a validated, running recipe. It assumes you have done [your first refinement](first-refinement.md). @@ -170,5 +170,5 @@ Look at the fit (see [Plot the fit](first-refinement.md#plot-the-fit)), then adjust the flags and run again. Each run's `output_recipe.json` holds the refined values, ready to be the next starting point. -**Next:** [Run a series](../how-to/sequential-refinement.md) to refine many -patterns, or [Refine a structure](../how-to/refine-structure.md) to go further. +**Next:** [Run a series](../how-to/sequential-refinement.md) to refine one model +against many patterns, or [Refine a structure](../how-to/refine-structure.md) to go further. diff --git a/docs/how-to/beamline-operation.md b/docs/how-to/beamline-operation.md index adc328c..a151876 100644 --- a/docs/how-to/beamline-operation.md +++ b/docs/how-to/beamline-operation.md @@ -130,7 +130,7 @@ own, for example to watch the server start. ::: The server runs one refinement at a time. Requests from several of your -processes wait their turn. Time spent waiting counts towards a time +processes wait their turn. Time spent waiting counts toward a time limit. ### Restart it after an update diff --git a/docs/how-to/calibrate-instrument.md b/docs/how-to/calibrate-instrument.md index a6953ac..750b8ea 100644 --- a/docs/how-to/calibrate-instrument.md +++ b/docs/how-to/calibrate-instrument.md @@ -3,8 +3,8 @@ **Goal:** measure your instrument's contribution to the pattern once, on a standard, and reuse it for every sample measured the same way. That contribution is its peak shape and whichever corrections apply to your -geometry. Holding the instrument fixed means the sample refinement fits only -the sample: its peak broadening, cell and structure. +geometry. Holding the instrument fixed means the sample refinement refines only +the sample's parameters: its peak broadening, cell and structure. **You need:** - A pattern of a standard (LaB6, Si, CeO2) measured at the **same wavelength @@ -108,7 +108,7 @@ the standard's refinement before you copy anything. ## 3. Hold the instrument Set every refine flag in the copied block to `false`. The sample refinement -should fit the sample, not re-fit the instrument. +should refine only the sample's parameters, not the instrument's. Change only the flags. For each parameter, the value stays and the flag becomes `false`: @@ -207,8 +207,9 @@ pixi run -e easydiffraction powderline my_sample/input.json `path` starts with `payload.instrument` reads `held_by_user`. :::{warning} -An instrument block belongs to one engine. GSAS-II's `U, V, W` are in -centidegrees², TOPAS's and easydiffraction's in degrees², and `X` and `Y` +An instrument block belongs to one engine. GSAS-II's `U, V, W` give the +Gaussian variance σ² in centidegrees²; TOPAS's and easydiffraction's give +the Gaussian FWHM² in degrees² (FWHM² = 8 ln 2 · σ² / 10⁴). `X` and `Y` swap roles. To use a GSAS-II calibration with TOPAS, refine the standard again with TOPAS. ::: @@ -245,5 +246,5 @@ Run it in the engine's environment, for example `pixi run -e gsasii python calibrate.py`. **Next:** [Refine a structure](refine-structure.md), or -[Run a series](sequential-refinement.md) to refine many patterns from one -sample recipe. +[Run a series](sequential-refinement.md) to refine one sample's model against +many patterns. diff --git a/docs/how-to/disorder.md b/docs/how-to/disorder.md index 1e06264..9fd6c6f 100644 --- a/docs/how-to/disorder.md +++ b/docs/how-to/disorder.md @@ -19,7 +19,7 @@ would do silently becomes either a reported value or an error. PowderLine applies every symmetry operation to the atom and measures `d`, the distance between the atom and that image: the largest of the three -fractional-coordinate differences. Each image is judged on its own. On a mirror or an inversion centre, `d` is twice the atom's offset +fractional-coordinate differences. Each image is judged on its own. On a mirror or an inversion center, `d` is twice the atom's offset from the site. Fractional units make `d` independent of the cell, which is itself refined. The distance in ångströms is roughly d × a: 2e-3 is 0.008 Å in a 4 Å cell, 0.02 Å in a 10 Å cell and 0.04 Å in a 20 Å cell. @@ -28,7 +28,7 @@ itself refined. The distance in ångströms is roughly d × a: 2e-3 is 0.008 Å |---|---|---|---|---| | **Exactly on** it (`0.5`, `0.25`, `0`) | read it as special | read it as special | read it as special (only an exact value or an equation) | special position. A fixed coordinate cannot be refined: a refine flag on one is an error. | | **Within 5e-6** (`0.333333` for 1/3, `0.5000001` for 1/2) | read it as special (its tolerance is 2e-5 + 1e-5·\|x\|) | read it as special and **move the coordinate** to its Wyckoff value | read it as a **general** position: `k` atoms almost on top of each other | depends on the value. A third, or a value derived from another stated value, is held exact and reported as `symmetry_value_derived` (level `info`); every engine gets the exact value, TOPAS the equation `= 1/3;`. A constant with an exact decimal form is an **error**: `0.5000001` gets "write x = 0.5". | -| **5e-6 to 2e-3** (`0.3333`, `0.33`, or an atom 0.001 off) | special up to about 2e-5, then general, with the multiplicity changing in between | special or general, depending on how the decimals rationalise | general | **error** naming the atom, the special position it is near and the fix: state the position exactly, or move the atom until no symmetry image is 5e-6 to 2e-3 away | +| **5e-6 to 2e-3** (`0.3333`, `0.33`, or an atom 0.001 off) | special up to about 2e-5, then general, with the multiplicity changing in between | special or general, depending on how the decimals rationalize | general | **error** naming the atom, the special position it is near and the fix: state the position exactly, or move the atom until no symmetry image is 5e-6 to 2e-3 away | | **2e-3 or more** | general | general | general | general position, used as stated. Nothing is moved. | So every recipe PowderLine accepts is read the same way by all three @@ -101,7 +101,7 @@ No engine moves a refined coordinate back onto a special position: ({ref}`EB-47 `). - TOPAS compares exactly. -A disordered atom that refines towards its special position therefore stays +A disordered atom that refines toward its special position therefore stays a general position with near-coincident images. If it ends with an image 5e-6 to 2e-3 away, the run still returns its result, but the **output recipe is marked not valid**: `output_recipe_valid: false`, with the `output_recipe_not_valid` diff --git a/docs/how-to/index.md b/docs/how-to/index.md index d281aea..97b3462 100644 --- a/docs/how-to/index.md +++ b/docs/how-to/index.md @@ -8,7 +8,7 @@ then gives numbered steps and a check. - [Model disorder near special positions](disorder.md): write a split site that every engine reads the same way. - [Fit single peaks](single-peak-fitting.md): fit individual peaks without a crystal structure, in GSAS-II or TOPAS. - [Simulate a pattern](simulate.md): calculate a pattern from a model without fitting anything. -- [Run a series](sequential-refinement.md): refine many patterns in sequence, each step starting from the last. +- [Run a series](sequential-refinement.md): refine against many patterns in sequence, each step starting from the last. - [Use PowderLine from Python and in pipelines](python-pipelines.md): validate and run recipes from your own code, and handle failures. - [Run at a beamline](beamline-operation.md): the GSAS-II server, batches of recipes and unattended runs on shared workstations. - [Run TOPAS recipes](run-topas.md): run TOPAS 6 on Windows, or write its input anywhere. diff --git a/docs/how-to/python-pipelines.md b/docs/how-to/python-pipelines.md index 16e8367..d2d9d75 100644 --- a/docs/how-to/python-pipelines.md +++ b/docs/how-to/python-pipelines.md @@ -185,13 +185,13 @@ was, with any earlier results in place. All PowderLine errors derive from ## Carry metadata and provenance through A recipe may carry a free-form `metadata` block: a sample ID, a scan ID, the -data's place in your catalogue, how the recipe was made. +data's place in your catalog, how the recipe was made. ```python recipe["metadata"] = {"sample_id": "S-0421", "scan_id": "70c707"} ``` -PowderLine never reads it. It must be JSON-serialisable and at most 1 MiB as +PowderLine never reads it. It must be JSON-serializable and at most 1 MiB as JSON. The output recipe keeps it unchanged and adds one key, `powderline_provenance`: diff --git a/docs/how-to/refine-structure.md b/docs/how-to/refine-structure.md index e1296dd..28a128b 100644 --- a/docs/how-to/refine-structure.md +++ b/docs/how-to/refine-structure.md @@ -182,7 +182,7 @@ preferred orientation, between 0 and 1. The block needs :::{tip} Start `ratio` on the side of 1 you expect, not at exactly 1.0. In a cubic -phase the correction does not change at r = 1, and GSAS-II then aborts the +phase the correction is stationary at r = 1, and GSAS-II then aborts the refinement ({ref}`EB-99 `). ::: diff --git a/docs/how-to/run-topas.md b/docs/how-to/run-topas.md index 0d0dfef..7bc1bb1 100644 --- a/docs/how-to/run-topas.md +++ b/docs/how-to/run-topas.md @@ -94,7 +94,7 @@ exits 0, and the `topas_generate_only` note says how to run it. Run the ## Set a time limit Each `tc.exe` run is stopped after 3600 seconds by default, so a TOPAS -waiting for input (a licence dialog, for example) cannot hang a run. Change +waiting for input (a license dialog, for example) cannot hang a run. Change the limit with `--topas-timeout SECONDS`, `topas.timeout` in `.powderline_config.yaml`, or `topas_timeout` in Python. `0` means no limit. diff --git a/docs/how-to/sequential-refinement.md b/docs/how-to/sequential-refinement.md index 1c7fcbe..a4b41b1 100644 --- a/docs/how-to/sequential-refinement.md +++ b/docs/how-to/sequential-refinement.md @@ -1,11 +1,11 @@ # Run a series -**Goal:** refine a series of patterns of one sample (a temperature ramp, a -time series, an in situ experiment) in sequence. Each step starts from the +**Goal:** refine one sample's model against a series of patterns (a +temperature ramp, a time series, an in situ experiment) in sequence. Each step starts from the refined values of the step before, and only the data change. **You need:** -- A recipe that refines the first pattern well. Calibrate the instrument +- A recipe that fits the first pattern well. Calibrate the instrument first ([Calibrate the instrument](calibrate-instrument.md)). - Each further pattern as an `xrd_data` block: `tth`, `Itth`, `Itth_weights` and, optionally, `filename`. Your own reader builds these @@ -119,9 +119,9 @@ directly. ## Try the example -`examples/example_LaB6_temperature_series/` is this loop, complete. Six -simulated LaB6 patterns from 25 to 500 °C, with a known thermal expansion -and Poisson noise, are refined in sequence by `run_series.py`: +`examples/example_LaB6_temperature_series/` is this loop, complete. +`run_series.py` refines one model in sequence against six simulated LaB6 +patterns from 25 to 500 °C, with a known thermal expansion and Poisson noise: ```bash pixi run -e gsasii python examples/example_LaB6_temperature_series/run_series.py --output my_series diff --git a/docs/how-to/simulate.md b/docs/how-to/simulate.md index 7c0e60b..bb75b9c 100644 --- a/docs/how-to/simulate.md +++ b/docs/how-to/simulate.md @@ -106,7 +106,7 @@ in these ways: | | Value in a simulation | |---|---| | `simulation_mode` | `true` | -| `converged` | `null`: nothing was optimised | +| `converged` | `null`: nothing was optimized | | `rwp`, `r_exp`, `gof`, `chi2_red` | PowderLine's uniform statistics with no refined parameters. Against real data they show how good the starting values are. Against placeholder intensities they mean nothing. | | ESDs in `_unit_cell_report.csv` | `0.0` for every value | | `refined_parameters.csv` | not written by GSAS-II; written with no rows by TOPAS and easydiffraction | diff --git a/docs/index.md b/docs/index.md index b592bf8..1207f9e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -47,14 +47,14 @@ motivation. ::::{grid} 2 -:::{grid-item-card} 🔬 I refine powder data +:::{grid-item-card} 🔬 I analyze powder data Run a complete refinement in a few minutes, then write a recipe for your own data. [Get started →](getting-started/index.md) ::: :::{grid-item-card} 🛰️ I run a beamline -Calibrate once, refine every sample, chain a series, and run unattended. +Calibrate once, analyze every sample, chain a series, and run unattended. [Calibrate the instrument →](how-to/calibrate-instrument.md) · [Run a series →](how-to/sequential-refinement.md) · @@ -67,7 +67,7 @@ failures, and carry metadata through. [Use PowderLine from Python →](how-to/python-pipelines.md) ::: :::{grid-item-card} ⚙️ I develop a refinement engine -What PowderLine does with each engine, every behaviour it found, and how +What PowderLine does with each engine, every behavior it found, and how the engines compare on the same data. [Engines →](engines/index.md) · [Comparing engines →](concepts/comparing-engines.md) @@ -78,7 +78,7 @@ Real and teaching cases, with their recipes and results. [Examples →](examples/index.md) ::: :::{grid-item-card} 🛠️ I want to contribute -How the code is organised, how to test it, and how to add an engine. +How the code is organized, how to test it, and how to add an engine. [Development →](development/index.md) ::: @@ -88,7 +88,7 @@ How the code is organised, how to test it, and how to add an engine. | PowderLine **is** | PowderLine **is not** | |---|---| -| One validated, machine-writable description of a refinement | A new refinement algorithm: the engines do the maths | +| One validated, machine-writable description of a refinement | A new refinement algorithm: the engines do the math | | A strict checker of form and symmetry | A judge of your refinement choices: see [Good refinement practice](concepts/refinement-practice.md) | | One interface and one result format for three engines | A translator: a GSAS-II recipe stays a GSAS-II recipe | | A component you plug into larger workflows | A CIF reader or recipe builder: your tools write the recipe | diff --git a/docs/reference/glossary.md b/docs/reference/glossary.md index ba44810..dc5c3e2 100644 --- a/docs/reference/glossary.md +++ b/docs/reference/glossary.md @@ -5,8 +5,8 @@ window with a positive weight $w_i$. $P$ is the number of parameters the engine varied. ADP, `Uiso`, `Uaniso` -: Atomic displacement parameter: how far an atom vibrates or is displaced - about its site. `Uiso` is one isotropic value; `Uaniso` is the six values +: Atomic displacement parameter: the mean-square displacement of an atom + about its site, from vibration or static disorder. `Uiso` is one isotropic value; `Uaniso` is the six values `U11 U22 U33 U12 U13 U23`. Both are in Ų. An atom's `ADP` field says which one it states. @@ -100,7 +100,7 @@ Provenance Recipe : A complete refinement as structured data: a dictionary in Python, - serialised as JSON when it is stored or sent. + serialized as JSON when it is stored or sent. Refine flag : The second entry of a parameter: `true` to refine the value, `false` to diff --git a/docs/reference/ids.md b/docs/reference/ids.md index 2eecdcd..5957745 100644 --- a/docs/reference/ids.md +++ b/docs/reference/ids.md @@ -1,4 +1,4 @@ -# Engine behaviours and known issues: ID index +# Engine behaviors and known issues: ID index ```{include} ../_generated/ids.md ``` diff --git a/docs/reference/index.md b/docs/reference/index.md index edc6584..6ac3968 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -6,8 +6,8 @@ Exact, complete look-up pages. - [Fields](fields.md): every field of every schema, with its unit. - [Outputs](outputs.md): the result dict, the report files, the engines' own files and the failure record. - [Messages](messages.md): validation errors, warning codes and failure reasons. -- [ID index](ids.md): every engine-behaviour (EB) and known-issue (KI) ID, with a link to its entry. -- [Known issues](known-issues.md): PowderLine's own known, deliberately deferred behaviours, by `KI-NN` ID. +- [ID index](ids.md): every engine-behavior (EB) and known-issue (KI) ID, with a link to its entry. +- [Known issues](known-issues.md): PowderLine's own known, deliberately deferred behaviors, by `KI-NN` ID. - [Command line](cli.md): the `powderline` command and every option. - [Python API](api.md): `powderline.run`, `validate` and the public names. - [Versions and compatibility](versions.md): what a version promises, the support matrix and the schema history. diff --git a/docs/reference/known-issues.md b/docs/reference/known-issues.md index 4def52d..6e2e9f5 100644 --- a/docs/reference/known-issues.md +++ b/docs/reference/known-issues.md @@ -1,6 +1,6 @@ # Known issues -A **known issue** is a behaviour of PowderLine itself that is understood and +A **known issue** is a behavior of PowderLine itself that is understood and recorded: a limit it accepts, a failure route it documents, or a problem it has resolved. Each has a permanent ID, `KI-NN`, that the code, messages and the changelog cite. An ID is never reused, so a withdrawn or resolved issue diff --git a/docs/reference/outputs.md b/docs/reference/outputs.md index 7ae7b17..95863da 100644 --- a/docs/reference/outputs.md +++ b/docs/reference/outputs.md @@ -232,7 +232,7 @@ The unit-cell report follows one rule on every engine: | Volume of a cell with nothing refined | `0.0` | | Volume otherwise (easydiffraction) | empty | -## Native artefacts +## Native artifacts Each engine's own files stay in the output directory beside the reports. diff --git a/docs/reference/recipe-format.md b/docs/reference/recipe-format.md index d62aa9a..41df835 100644 --- a/docs/reference/recipe-format.md +++ b/docs/reference/recipe-format.md @@ -1,6 +1,6 @@ # Recipe format -A recipe is structured data: a dictionary in Python, serialised as JSON when +A recipe is structured data: a dictionary in Python, serialized as JSON when it is stored or sent. This page gives the rules every recipe follows, whatever its engine. Every individual field, with its unit, is on [Fields](fields.md). @@ -26,7 +26,7 @@ Every recipe has four required top-level keys (`schema_name`, | `schema_name` | yes | `.`: one of the five names below. It selects the engine that runs the recipe. | | `core_schema_version` | yes | The core schema version the recipe is written against: `"0.1.0"`. | | `engine_schema_version` | yes | The engine schema version the recipe is written against: `"0.1.0"` for every engine. | -| `metadata` | no | Free-form, JSON-serialisable data. At most 1 MiB as UTF-8 JSON. PowderLine never reads it and carries it into the [output recipe](outputs.md#the-output-recipe). | +| `metadata` | no | Free-form, JSON-serializable data. At most 1 MiB as UTF-8 JSON. PowderLine never reads it and carries it into the [output recipe](outputs.md#the-output-recipe). | | `payload` | yes | The refinement itself, written in the engine's own terms. | | `engine_version` | `topas.*` only | The TOPAS release the recipe is written for: `"6"`. | @@ -277,7 +277,7 @@ physical limit ({ref}`EB-71 `): keeps it. - easydiffraction refuses a value outside a physical limit, even a fixed one. Such a value is a validation error. A cell length over 30 Å cannot be - modelled. + modeled. - lmfit would silently move a start outside its bounds onto the bound. The rule that a value lies between its stated bounds prevents this. - A refined value that ends within 1e-6 (relative) of a bound or physical @@ -315,7 +315,7 @@ field means when it is left out. 10 µm and 0 microstrain, no background, and 5 refinement cycles. Each default comes with a [warning](messages.md#warning-codes). - In `topas.*` and `easydiffraction.*` nothing has a default. A block left - out is not modelled. + out is not modeled. ## Names @@ -344,7 +344,7 @@ centidegree², easydiffraction's `broad_gauss_u` in degree². | `degree` | degrees (angles, not 2θ) | every schema | | `angstrom` | Å | every schema | | `angstrom^2` | Ų (`Uiso`, `Uij`) | every schema | -| `arbitrary` | intensity units (counts, normalised) | every schema | +| `arbitrary` | intensity units (counts, normalized) | every schema | | `1/intensity^2` | weight, 1/σ² | every schema | | `dimensionless` | a pure number | every schema | | `centidegree 2theta` | 0.01° on the 2θ axis | `gsasii.*` | diff --git a/examples/example_DRX_33/DESCRIPTION.md b/examples/example_DRX_33/DESCRIPTION.md index 80e55db..9a17eb6 100644 --- a/examples/example_DRX_33/DESCRIPTION.md +++ b/examples/example_DRX_33/DESCRIPTION.md @@ -20,7 +20,7 @@ and easydiffraction recipes have committed reference output (`output/`, I am fitting a diffraction pattern collected on a disordered rocksalt battery material. Both the main phase of interest and a secondary phase are being fit. The main phase is a disordered rock salt (face centered cubic, space group Fm-3m, space group number 225) and the secondary phase is Li4MgWO6 (monoclinic, space group C2/m, space group number 12). -I am refining the phase scale factors, lattice parameters, phase size broadening including the LG_eta (Lorentzian-Gaussian weighting) parameters, phase strain broadening including the Lg_eta parameters, and a Chebyshev background with 6 terms. +I am refining the phase scale factors, lattice parameters, phase size broadening including the LG_eta (Lorentzian-Gaussian weighting) parameters, phase strain broadening including the LG_eta parameters, and a Chebyshev background with 6 terms. The intention is to quantify the relative phase fractions from the refined scale factors. ## Schema Features Demonstrated @@ -30,7 +30,7 @@ This example demonstrates multi-phase refinement capabilities: - **Multi-phase refinement**: Two phases with different crystal systems (cubic + monoclinic) - **Phase-specific parameters**: Independent scale, lattice, and broadening parameters for each phase - **Peak broadening modeling**: Both size and strain broadening with LG_eta (Lorentzian-Gaussian mixing) -- **Constrained atomic structure**: Atomic positions, occupancies, and ADPs fixed (structure-only refinement) +- **Held atomic structure**: Atomic positions, occupancies, and ADPs fixed (no atom parameters refined) - **File-less payload**: Complete multi-phase dataset embedded in JSON - **Phase fraction quantification**: Refined scale factors enable phase fraction determination @@ -89,7 +89,7 @@ is ill-conditioned (see the SVD warnings above): the Li4MgWO6 size ends at about −1356 µm (ESD ≈ 180 µm), which the schema refuses, so the output recipe is written and returned with that value and the warning names it. The reference is kept deliberately as the ill-conditioned posing; `example_DRX_33_strainonly` is the -physical re-parameterisation (size held at 10 µm; Rwp 8.46 % against 10.83 % here) +physical re-parameterization (size held at 10 µm; Rwp 8.46 % against 10.83 % here) whose output recipe is valid and feeds back. ## Refine flags (gsasii 0.1.0) diff --git a/examples/example_DRX_33_anisoADP/DESCRIPTION.md b/examples/example_DRX_33_anisoADP/DESCRIPTION.md index f798d2e..2b9c517 100644 --- a/examples/example_DRX_33_anisoADP/DESCRIPTION.md +++ b/examples/example_DRX_33_anisoADP/DESCRIPTION.md @@ -17,7 +17,7 @@ This example demonstrates **anisotropic atomic displacement parameter refinement Anisotropic ADPs are critical for: - **High-resolution structural analysis** - capturing directional thermal motion - **Materials with anisotropic bonding** - different thermal motion along different crystal axes -- **Low-temperature refinements** - where anisotropic effects become significant +- **High-temperature refinements** - where thermal motion is large and often anisotropic - **Publication-quality structures** - anisotropic ADPs are standard for single-crystal refinements The refinement uses the same disordered rocksalt battery material (DRX_33 + Li4MgWO6_SG12); the **O1 atom of the Li4MgWO6_SG12 phase** (general position 8j of C 1 2/m 1) is refined with anisotropic ADPs while every other atom stays isotropic and fixed. @@ -31,7 +31,7 @@ The refinement uses the same disordered rocksalt battery material (DRX_33 + Li4M **Li4MgWO6_SG12 Phase (monoclinic):** - **Anisotropic displacement (O1 atom only)**: - - U11, U22, U33 (diagonal elements) - thermal motion along a, b, c axes + - U11, U22, U33 (diagonal elements) - thermal motion along the reciprocal axes a*, b*, c* - U12, U13, U23 (off-diagonal elements) - thermal motion correlations between axes - All 6 components have `refine_flag=true` (O1 sits on the general position, so all six are independent; on a special position the schema would require the @@ -44,7 +44,7 @@ The refinement uses the same disordered rocksalt battery material (DRX_33 + Li4M **DRX_33 Phase (cubic):** - All atomic parameters locked (isotropic Uiso, no atom refinement) -### Parameters Constrained: +### Parameters Held: - **All atomic coordinates**: Locked in both phases - **All occupancies**: Locked in both phases - **Displacement parameters**: All locked except the Li4MgWO6_SG12 O1 atom's Uaniso @@ -66,7 +66,7 @@ The refinement uses the same disordered rocksalt battery material (DRX_33 + Li4M ## Expected Behavior ### Convergence: -- Refinement should converge after 5 cycles +- The refinement stops at its 5-cycle limit without converging (`converged: false`, warning `gsasii_fit_not_converged`) - The six Uij components of one atom can correlate strongly on powder data - In this run the O1 tensor ends unphysical: U11 = −0.170(12) Ų and U23 = −0.101(17) Ų (see *Positive-Definite Constraint* below) @@ -150,13 +150,15 @@ anisotropic displacement with every component refined; Li1 stays isotropic and f ### Thermal Ellipsoid: The refined Uij values define a thermal ellipsoid representing the atom's vibrational motion: -- **Diagonal terms (U11, U22, U33)**: Motion along crystallographic axes a, b, c +- **Diagonal terms (U11, U22, U33)**: Motion along the reciprocal axes a*, b*, c* - **Off-diagonal terms (U12, U13, U23)**: Correlations between axes For a general-position oxygen in the monoclinic Li4MgWO6_SG12 phase (C 1 2/m 1) all six -components are independent; a physically reasonable result has: -- U11, U22, U33 positive and of similar magnitude -- U12, U13, U23 small compared with the diagonal terms +components are independent. Judge the tensor by its principal values (the +eigenvalues of U in Cartesian axes), not by the size of U12, U13, U23: a +physically reasonable result has three positive principal values of similar +magnitude. In this cell (β = 109.96°) even an isotropic atom has +U13 = 0.34·Uiso. Significant deviations suggest: - Anisotropic bonding environment @@ -222,7 +224,7 @@ If anisotropic refinement fails to converge or produces unphysical Uij values: - High-resolution data available (d-spacing resolution < 1 Å) - Publication-quality structure refinement needed - Anisotropic bonding expected (layered materials, molecular crystals) -- Low-temperature data (thermal effects dominate) +- High-temperature data (large, often anisotropic thermal motion) **Use isotropic ADPs when:** - Routine refinements (phase identification, quantification) diff --git a/examples/example_DRX_33_atomrefine/DESCRIPTION.md b/examples/example_DRX_33_atomrefine/DESCRIPTION.md index b4d26fa..0ef047e 100644 --- a/examples/example_DRX_33_atomrefine/DESCRIPTION.md +++ b/examples/example_DRX_33_atomrefine/DESCRIPTION.md @@ -47,7 +47,7 @@ This example validates PowderLine's ability to refine structural parameters in m - **Isotropic displacement (Uiso)**: All atoms locked (Uiso=false) - **Occupancies**: All atoms locked (occupancy=false) -### Parameters Constrained: +### Parameters Held: - **Instrument parameters**: Wavelength, polarization, broadening locked ### Parameters Refined: @@ -66,7 +66,7 @@ This example validates PowderLine's ability to refine structural parameters in m ## Expected Behavior ### Convergence: -- Refinement should converge after 5 cycles +- The refinement stops at its 5-cycle limit without converging (`converged: false`, warning `gsasii_fit_not_converged`) - Atom parameters may show larger shifts in first few cycles - Coordinate refinement is sensitive to starting values @@ -113,7 +113,7 @@ The `ADP` field serves two purposes: ### Phase block (gsasii 0.1.0): Each atom states its values and flags together. DRX_33's Li (fixed position 4a) -refines occupancy and Uiso; Li4MgWO6_SG12's Li1 (site 4g: x and z fixed by +refines occupancy and Uiso; Li4MgWO6_SG12's Li1 (site 4h: x and z fixed by symmetry) refines only y: ```json "atoms": { @@ -126,7 +126,7 @@ symmetry) refines only y: }, "Li1": { "element": "Li", - "x": [0.0, false], "y": [0.33, true], "z": [0.5, false], // only y is free on 4g + "x": [0.0, false], "y": [0.33, true], "z": [0.5, false], // only y is free on 4h "occupancy": [1.0, false], "ADP": "Uiso", "Uiso": [0.0, false] diff --git a/examples/example_DRX_33_simulation/DESCRIPTION.md b/examples/example_DRX_33_simulation/DESCRIPTION.md index 48df540..c927670 100644 --- a/examples/example_DRX_33_simulation/DESCRIPTION.md +++ b/examples/example_DRX_33_simulation/DESCRIPTION.md @@ -2,7 +2,7 @@ ## Overview -This example demonstrates **powder diffraction pattern simulation** for a **two-phase system** using PowderLine. The sample is a composite mixture of two crystalline phases with locked structural parameters. Unlike the refinement mode (which optimizes parameters to fit data), simulation mode calculates the theoretical diffraction pattern for a given structure at fixed parameters. +This example demonstrates **powder diffraction pattern simulation** for a **two-phase system** using PowderLine. The model is a mixture of two crystalline phases with every parameter held. Unlike the refinement mode (which optimizes parameters to fit data), simulation mode calculates the theoretical diffraction pattern for a given structure at fixed parameters. ## Use Case: Multi-Phase Simulation @@ -22,8 +22,8 @@ This example demonstrates multi-phase simulation capabilities: - **Single-cycle execution**: `refinement_cycles: 1` (no iterative optimization) - **Phase-specific outputs**: Separate reports for each phase (unit cell, peak lists) - **Combined pattern calculation**: Theoretical pattern from superposition of both phases -- **Scale factor control**: Fixed relative phase intensities (both set to 1.0) -- **Meaningless fit statistics**: `rwp` compares the simulated pattern with the placeholder data (pure forward calculation, no fitting); GSAS-II's own 100 % is under `engine_details` +- **Scale factor control**: Fixed phase scales (both set to 1.0) +- **Meaningless fit statistics**: `rwp` compares the simulated pattern with the placeholder data (the measured pattern, used here only for its 2θ grid; pure forward calculation, no fitting); GSAS-II's own 100 % is under `engine_details` ## Key Differences from Refinement @@ -41,7 +41,7 @@ This example demonstrates multi-phase simulation capabilities: 1. **Structure Input**: Two crystal structures (DRX_33 + Li4MgWO6_SG12) from CIF with known unit cell parameters 2. **Instrument Definition**: Same synchrotron beamline setup as refinement example (λ = 0.1665 Å) 3. **Parameter Locking**: All structural and peak broadening parameters set to `refine_flag = false` -4. **Scale Factors**: Each phase has a fixed scale factor (1.0 in this example - equal contributions) +4. **Scale Factors**: Each phase has a fixed scale factor (1.0 in this example) 5. **Single Cycle**: `refinement_cycles = 1` with all parameters locked = pure calculation (no optimization) 6. **Output**: Theoretical y_calc values representing the combined two-phase pattern @@ -113,10 +113,10 @@ To study phase fractions, modify the scale factors in `input.json`: ```json "DRX_33": { - "scale": [0.7, false] // 70% relative phase fraction by mass + "scale": [0.7, false] // relative phase scale (not a mass fraction) }, "Li4MgWO6_SG12": { - "scale": [0.3, false] // 30% relative phase fraction by mass + "scale": [0.3, false] // relative phase scale (not a mass fraction) } ``` diff --git a/examples/example_DRX_33_strainonly/DESCRIPTION.md b/examples/example_DRX_33_strainonly/DESCRIPTION.md index e6b8856..952904a 100644 --- a/examples/example_DRX_33_strainonly/DESCRIPTION.md +++ b/examples/example_DRX_33_strainonly/DESCRIPTION.md @@ -3,14 +3,14 @@ ## Scientific Purpose This example is a re-parameterization of `example_DRX_33` (the same two-phase -disordered-rocksalt battery material — a face-centred-cubic DRX main phase, +disordered-rocksalt battery material — a face-centered-cubic DRX main phase, space group Fm-3m / No. 225, plus a monoclinic Li4MgWO6 secondary phase, space group C2/m / No. 12). Everything about the data, structures, and instrument is identical; only the **peak-broadening parameterization** changes. In the base example both **size** and **strain** broadening are refined per -phase. That refinement is ill-conditioned over this limited 1-15 deg 2-theta, -low-Q synchrotron range (lambda = 0.1665 A): size and strain broadening are +phase. That refinement is ill-conditioned over this 1-15 deg 2-theta +synchrotron range (lambda = 0.1665 A): size and strain broadening are strongly correlated, so the isotropic size parameters run away. In the committed base reference the DRX size ends near 253 um with a runaway LG-mixing coefficient (about 15 000), and the Li4MgWO6 size goes negative @@ -56,7 +56,7 @@ Concretely, each phase's `peak_broadening.size_broadening` is set to ## Expected Behavior -- **Convergence**: the refinement converges in a few cycles. Because both the +- **Convergence**: the refinement stops at its 5-cycle limit without converging (`converged: false`, warning `gsasii_fit_not_converged`). Because both the isotropic strain magnitude and the strain LG-mixing term are refined, the two are fully correlated and GSAS-II reports a soft (SVD) singularity — see *Known Issues*. The reported equatorial microstrain (which combines them) is @@ -64,7 +64,7 @@ Concretely, each phase's `peak_broadening.size_broadening` is set to - **Fit quality**: **Rwp = 8.46%, GOF = 0.86** (chi**2 = 2781.62 on 3767 observations: the native path fits exactly 1 ≤ 2θ ≤ 15). This is an improvement over the base example (Rwp = 10.83%, GOF = 1.10): removing the ill-conditioned size parameters yields a cleaner fit. - GOF < 1 indicates the profile ESDs are mildly overestimated. + GOF < 1 indicates the intensity uncertainties (σ of y_obs) are mildly overestimated. - **Refined values (with ESDs)**: Phase 1 — DRX (Fm-3m, cubic): diff --git a/examples/example_LaB6/DESCRIPTION.md b/examples/example_LaB6/DESCRIPTION.md index 504e67e..7a3ba6c 100644 --- a/examples/example_LaB6/DESCRIPTION.md +++ b/examples/example_LaB6/DESCRIPTION.md @@ -11,12 +11,12 @@ The intention is to capture the peak broadening that is contributed by the instr This example demonstrates fundamental refinement capabilities: -- **File-less JSON payload**: All data embedded directly in JSON (XRD data, CIF structure, instrument parameters) +- **File-less JSON payload**: All data embedded directly in JSON (XRD data, structure, instrument parameters) - **Standard refinement parameter format**: Uses `[value, refine_flag]` throughout (gsasii 0.1.0 exposes no bounds) - **Background modeling**: Chebyshev polynomial with 6 coefficients - **Instrument parameter refinement**: Thompson-Cox-Hastings pseudo-Voigt broadening (U, V, W, X, Y, Z parameters) - **Phase scale refinement**: Single-phase calibrant fitting for instrument profile characterization -- **Constrained structural parameters**: Lattice and atomic parameters fixed to known values (SRM certification) +- **Held structural parameters**: Lattice parameter held at the certified SRM value; atomic parameters held at the stated values ## Input Parameters diff --git a/examples/example_LaB6_simulation/DESCRIPTION.md b/examples/example_LaB6_simulation/DESCRIPTION.md index 668a485..9ac9c62 100644 --- a/examples/example_LaB6_simulation/DESCRIPTION.md +++ b/examples/example_LaB6_simulation/DESCRIPTION.md @@ -27,7 +27,7 @@ This example demonstrates simulation mode capabilities: - **Pure simulation mode**: All parameters have `refine_flag: false` (no optimization) - **Single-cycle execution**: `refinement_cycles: 1` with locked parameters (pure calculation) - **Complete parameter specification**: All structural, background, and instrument parameters provided -- **Meaningless fit statistics**: `rwp` compares the simulated pattern with the placeholder data (Ycalc not optimized to Yobs); GSAS-II's own 100 % is under `engine_details` +- **Meaningless fit statistics**: `rwp` compares the simulated pattern with the placeholder data (the measured pattern, used here only for its 2θ grid; Ycalc not optimized to Yobs); GSAS-II's own 100 % is under `engine_details` - **Forward calculation**: Demonstrates theoretical pattern generation from known structure - **Same schema as refinement**: Uses identical JSON structure with different refine_flag values diff --git a/examples/example_LaB6_temperature_series/DESCRIPTION.md b/examples/example_LaB6_temperature_series/DESCRIPTION.md index c02cb21..d560582 100644 --- a/examples/example_LaB6_temperature_series/DESCRIPTION.md +++ b/examples/example_LaB6_temperature_series/DESCRIPTION.md @@ -4,8 +4,8 @@ A heated powder standard measured at successive temperatures is the simplest sequential refinement: the structure does not change, the lattice expands and -the atoms vibrate more, and each pattern is best refined starting from the -previous one. This example runs that workflow end to end with PowderLine's +the atoms vibrate more, and each step's refinement is best started from the +previous step's result. This example runs that workflow end to end with PowderLine's **output recipe** (KI-04): each step's result is a complete recipe with the refined values written back, and the next step is that recipe with only the `xrd_data` block swapped (`powderline.recipes.with_block`). Nothing is copied @@ -194,8 +194,9 @@ What the leg shows: 25 °C pattern simulated with a GSAS-II profile easydiffraction can represent (the original `example_LaB6` posing, no clamp) gives CrysPy La Uiso 0.00863 vs 0.00858 programmed and GSAS-II itself 0.00868, while - CrysFML lands at 0.00823 (−4 %; no ESD, 0.00817(18) with X free — the size - of its own intensity drift, EB-78). On this pattern the axial asymmetry + CrysFML lands at 0.00823 (−4 %; no ESD, 0.00817(18) with X free; its + remaining profile mismatch and its intensity drift, EB-78, both act on + Uiso, and the two were not separated). On this pattern the axial asymmetry moves the cell for the symmetric profile (CrysPy +76 ppm, an EB-88-size shift), not Uiso. Compare cells (with the EB-88-size offsets in mind) and expansion across engines; absolute Uiso agrees only when the profile diff --git a/examples/example_LaB6_temperature_series/easydiffraction/README.md b/examples/example_LaB6_temperature_series/easydiffraction/README.md index 12483b1..a822dc9 100644 --- a/examples/example_LaB6_temperature_series/easydiffraction/README.md +++ b/examples/example_LaB6_temperature_series/easydiffraction/README.md @@ -8,7 +8,7 @@ describes) with - the `xrd_data` block replaced by the simulated 25 °C pattern (`../data/lab6_025C.json`, via `powderline.recipes.with_block`); -- both Uiso refined (the series programmes Uiso(T)), the scale and six +- both Uiso refined (the series programs Uiso(T)), the scale and six Chebyshev coefficients refined from 30, 0, 0, 0, 0, 0; - the cell (one tie group) and the TCH profile U, V, W, Y refined as in the parent recipe: the profile must be refined here because easydiffraction's diff --git a/examples/example_LaB6_textured/DESCRIPTION.md b/examples/example_LaB6_textured/DESCRIPTION.md index 96dd807..f8ac53e 100644 --- a/examples/example_LaB6_textured/DESCRIPTION.md +++ b/examples/example_LaB6_textured/DESCRIPTION.md @@ -11,11 +11,11 @@ programmed coefficient recovered by refinement?* The truth is the `example_LaB6` structure (SRM 660c, a = 4.15682 Å, La at the origin, B on 6f) with March–Dollase **r = 0.6 along [001]** — platy, in the IUCr / GSAS-II convention (1 random, < 1 platy, > 1 needle; the correction -`A = 1/sqrt((r cos P)² + sin²P / r)` averaged over the symmetry equivalents of -the axis, Dollase 1986). GSAS-II calculated it in one cycle on the measured -28-ID-1 2θ grid (λ = 0.1665 Å, 3821 points in 0.9–15.1°) with the *original* -`example_LaB6` instrument profile (U 18.72, V 0.600, W 1.147, X 0.281, Y 0.001, -Z 0 centideg² — a positive-Y profile every engine can represent, EB-93), the +A³, with `A = 1/sqrt((r cos P)² + sin²P / r)`, averaged over the symmetry +equivalents of the axis, Dollase 1986). GSAS-II calculated it in one cycle on +the measured 28-ID-1 2θ grid (λ = 0.1665 Å, 3821 points in 0.9–15.1°) with the +*original* `example_LaB6` instrument profile (U 18.72, V 0.600, W 1.147 +centideg²; X 0.281, Y 0.001, Z 0 centideg — a positive-Y profile every engine can represent, EB-93), the committed refinement's background and scale, and Poisson counting noise with a fixed seed (`data/truth.json`; `make_textured.py` regenerates everything). @@ -65,7 +65,7 @@ the sample suggests. | output recipe valid | yes | yes | Both engines recover r within two ESD of the truth, and agree with each other -within one. The residual 0.002 is the Poisson realisation (GoF ≈ 1). GSAS-II +within one. The residual 0.002 is the Poisson realization (GoF ≈ 1). GSAS-II refines `0:0:MD`; the output recipe carries it back as `payload.phases.LaB6.preferred_orientation.ratio` (`parameter_dispositions.csv` row `varied`). @@ -95,6 +95,6 @@ The cryspy calculator is required: CrysFML ignores preferred orientation `topas/input.json`: the same refinement as a `topas.rietveld` recipe, written with TOPAS's March–Dollase `PO(...)` macro. On TOPAS 6 the correction equals -GSAS-II's per reflection, and a refinement of this pattern recovers r = +GSAS-II's per reflection, and a refinement against this pattern recovers r = 0.5982(14). Its reference comes from the TOPAS machine (see `topas/README.md`). diff --git a/examples/example_template/DESCRIPTION.md b/examples/example_template/DESCRIPTION.md index b0e32cb..ba04ee9 100644 --- a/examples/example_template/DESCRIPTION.md +++ b/examples/example_template/DESCRIPTION.md @@ -38,7 +38,7 @@ Examples of features you might highlight: Describe what goes in `input.json`: - **Data file(s)**: Which XRD data files are being used? Format? Source? - **Phases**: Which phase(s) are being refined? CIF files used? -- **Constrained vs refined parameters**: What is fixed? What is being optimized? +- **Held vs refined parameters**: What is fixed? What is being optimized? - **Starting values**: Where do initial parameter values come from? - **Special GSAS-II settings**: Any specific options or unusual configurations? diff --git a/scripts/cross_engine_comparison.py b/scripts/cross_engine_comparison.py index 79f516a..0f5c45b 100644 --- a/scripts/cross_engine_comparison.py +++ b/scripts/cross_engine_comparison.py @@ -66,7 +66,7 @@ #: NIST SRM 660c certificate (issued 29 October 2015): a = 0.415 682 6 nm ± 0.000 008 nm, #: expanded uncertainty k = 2, at 22.5 °C. Standard uncertainty = 0.000 04 Å. NIST_660C = {"value": 4.156826, "esd": 0.00004, "label": "NIST SRM 660c", - "note": "certificate 2015-10-29: 0.4156826(8) nm, k = 2, 22.5 °C"} + "note": "certificate 2015-10-29: 0.415 682 6 nm ± 0.000 008 nm, expanded uncertainty k = 2, 22.5 °C"} #: The reference cases: the GSAS-II example and, per other engine, the committed fixture(s). CASES = { diff --git a/scripts/gen_catalog.py b/scripts/gen_catalog.py index a6572ad..03c56ed 100644 --- a/scripts/gen_catalog.py +++ b/scripts/gen_catalog.py @@ -291,7 +291,7 @@ def ref(entry_id: str) -> str: def cell(text: str) -> str: return " ".join(text.split()).replace("|", "\\|") - lines = [HEADER, "", "## Engine behaviours", "", "| ID | Engine | Title | Status |", "|---|---|---|---|"] + lines = [HEADER, "", "## Engine behaviors", "", "| ID | Engine | Title | Status |", "|---|---|---|---|"] for e in sorted(eb, key=lambda e: _id_key(e["id"])): lines.append(f"| {ref(e['id'])} | {ENGINES[e['engine']]} | {cell(e['title'])} | " f"{EB_STATUSES[e['status']][1]} |") diff --git a/scripts/gen_example_figures.py b/scripts/gen_example_figures.py index b94ceaa..34bfa07 100644 --- a/scripts/gen_example_figures.py +++ b/scripts/gen_example_figures.py @@ -7,7 +7,7 @@ * ``examples//output/fit_profile.txt`` -> ``.svg`` (the GSAS-II recipe); * ``examples///output/fit_profile.txt`` -> ``_.svg``. -Each figure shows the observed pattern (grey), the calculated pattern (blue) +Each figure shows the observed pattern (gray), the calculated pattern (blue) and the difference curve (orange, offset below) over the fit window, with a 2θ axis. The colours are mid-tones and the background is transparent, so a figure reads on the light and on the dark theme. @@ -190,7 +190,7 @@ def polyline(ys: list[float], colour: str, width: str, offset: float = 0.0) -> s f"", f'', - f"{example} ({label}): observed (grey), calculated (blue) and difference (orange) " + f"{example} ({label}): observed (gray), calculated (blue) and difference (orange) " f"over the fit window", f'', diff --git a/src/powderline/config_loader.py b/src/powderline/config_loader.py index c6c48f3..1dffcd5 100644 --- a/src/powderline/config_loader.py +++ b/src/powderline/config_loader.py @@ -76,7 +76,7 @@ def _get_defaults(self) -> Dict[str, Any]: 'instrument_defaults': { 'wavelength': 0.4133, # Angstroms (30 keV) 'polarization': 0.99, # GSAS-II 'Polariz.' - 'zero_shift': 0.0, # centidegrees 2theta ('Zero') + 'zero_shift': 0.0, # degrees 2theta ('Zero') 'axial_divergence': 0.002, # GSAS-II 'SH/L': its own floor (A91; P-05) 'broadening': { # TCH pseudo-Voigt (GSAS-II U..Z) 'U': 1.0, diff --git a/src/powderline/gateways/easydiffraction/schema.py b/src/powderline/gateways/easydiffraction/schema.py index 5ebd79f..afb00e6 100644 --- a/src/powderline/gateways/easydiffraction/schema.py +++ b/src/powderline/gateways/easydiffraction/schema.py @@ -267,7 +267,7 @@ class Polarization(CoreModel): class Corrections(CoreModel): - """Peak-position corrections (degrees 2theta). Displacement and transparency left out: not modelled.""" + """Peak-position corrections (degrees 2theta). Displacement and transparency left out: not modeled.""" calib_twotheta_offset: P = Field(json_schema_extra=unit_schema(UNIT_DEG_2THETA), description="Zero offset") calib_sample_displacement: Optional[P] = Field( diff --git a/src/powderline/gateways/gsasii/schema.py b/src/powderline/gateways/gsasii/schema.py index aacf207..9c55d14 100644 --- a/src/powderline/gateways/gsasii/schema.py +++ b/src/powderline/gateways/gsasii/schema.py @@ -186,7 +186,7 @@ class Geometry(CoreModel): class Corrections(CoreModel): """Instrument corrections: zero shift, polarization, axial divergence (GSAS-II 'SH/L').""" - zero_shift: RefinableParameter = Field(json_schema_extra=unit_schema(UNIT_CENTIDEG), description="GSAS-II 'Zero'") + zero_shift: RefinableParameter = Field(json_schema_extra=unit_schema(UNIT_DEG_2THETA), description="GSAS-II 'Zero'") polarization: RefinableParameter = Field(json_schema_extra=unit_schema(UNIT_DIMENSIONLESS), description="GSAS-II 'Polariz.'") axial_divergence: RefinableParameter = Field( diff --git a/src/powderline/gateways/gsasii/simulation_builder.py b/src/powderline/gateways/gsasii/simulation_builder.py index e2ab185..a8b0be6 100644 --- a/src/powderline/gateways/gsasii/simulation_builder.py +++ b/src/powderline/gateways/gsasii/simulation_builder.py @@ -264,7 +264,7 @@ def _get_hardcoded_defaults(self) -> Dict[str, Any]: 'instrument_defaults': { 'wavelength': 0.4133, # Angstroms (30 keV) 'polarization': 0.99, # GSAS-II 'Polariz.' - 'zero_shift': 0.0, # centidegrees 2theta ('Zero') + 'zero_shift': 0.0, # degrees 2theta ('Zero') 'axial_divergence': 0.002, # GSAS-II 'SH/L': its own floor (A91; P-05) # TCH pseudo-Voigt instrumental broadening (GSAS-II U,V,W,X,Y,Z) 'broadening': {'U': 1.0, 'V': -0.5, 'W': 0.1, diff --git a/src/powderline/gateways/topas/schema.py b/src/powderline/gateways/topas/schema.py index 6866bad..9379d28 100644 --- a/src/powderline/gateways/topas/schema.py +++ b/src/powderline/gateways/topas/schema.py @@ -288,17 +288,17 @@ class ZeroError(CoreModel): class LPFactor(CoreModel): - """TOPAS ``LP_Factor``: Lorentz-polarisation with a monochromator angle.""" + """TOPAS ``LP_Factor``: Lorentz-polarization with a monochromator angle.""" monochromator_angle: P = Field(json_schema_extra=unit_schema(UNIT_DEGREE), description="Monochromator 2theta: 90 synchrotron/neutron, 0 no monochromator") class LPFactorSynchrotron(CoreModel): - """TOPAS ``LP_Factor_Synchrotron`` (Madsen): in-plane polarisation and monochromator angle.""" + """TOPAS ``LP_Factor_Synchrotron`` (Madsen): in-plane polarization and monochromator angle.""" pp: P = Field(json_schema_extra=unit_schema(UNIT_DIMENSIONLESS), - description="Polarisation in the plane: 0 ideal synchrotron ... 1 laboratory tube") + description="Polarization in the plane: 0 ideal synchrotron ... 1 laboratory tube") mono: P = Field(json_schema_extra=unit_schema(UNIT_DEGREE), description="Monochromator 2theta") @model_validator(mode="after") diff --git a/tests/data/ions/README.md b/tests/data/ions/README.md index 0b246b1..e919789 100644 --- a/tests/data/ions/README.md +++ b/tests/data/ions/README.md @@ -3,7 +3,7 @@ `lab6_la3_over_la_gsasii.json` — GSAS-II 5.7.9's La3+/La per-reflection integrated-intensity ratios for the `example_LaB6_simulation` recipe (one cycle, nothing refined; the 28-ID-1 grid, λ = 0.1665 Å): the twelve resolved -reflections between 1.5 and 14.5° with no neighbour closer than 0.3°, as +reflections between 1.5 and 14.5° with no neighbor closer than 0.3°, as `hkl`, `two_theta` and `ratio_ion_over_neutral` (±0.12° windows, `tests/intensity_ratio.peak_areas`; `what` and `generated` inside the file record how it was produced). The (100) ratio is 0.9854 (the three removed