Skip to main content

rietx

Refine powder diffraction data with the rietx Python package (Rietveld, Le Bail, Pawley, phase quantification, indexing an unknown cell, judging a FitReport) — read it before the first fit() whenever a task involves a powder pattern, a CIF to fit against one, phase fractions, a cell to determine, an in-situ series, a batch of candidates or of patterns fitted as separate jobs, or an existing rietx result to judge.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
yue-here/rietx
آخر نشاط في المصدر
١٦ سبتمبر ٢٠٢٦ في ٢٢:٥٤
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
١١
التفرعات
١

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
15 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
rietx
description
Refine powder diffraction data with the rietx Python package (Rietveld, Le Bail, Pawley, phase quantification, indexing an unknown cell, judging a FitReport) — read it before the first fit() whenever a task involves a powder pattern, a CIF to fit against one, phase fractions, a cell to determine, an in-situ series, a batch of candidates or of patterns fitted as separate jobs, or an existing rietx result to judge.
license
MIT
compatibility
Requires the rietx Python package (pip install rietx) and Python 3.11+. Works offline — this file and its references ship in the wheel; the user manual it names is hosted at https://rietx.org.
metadata
{"version":"1.4.0","homepage":"https://rietx.org"}
# Refining powder diffraction data with rietx **Audience: an agent driving `rietx` on real data.** Not a tutorial and not an API reference. A *protocol*: what to do, in what order, what to check before believing a number, and where the package will tell you your answer is wrong even though it looks right. Rwp is not the objective function of your job. A refinement can converge, report an excellent Rwp, and return displacement parameters biased by 100 %, phase fractions wrong by 5 wt % and a cell that is right for the wrong reason. Every rule below exists because one of those happened and was measured. Sections 1-4 are ordinary Rietveld discipline that would apply in any code; sections 5-10 are specific to running it with no human at the plot. ## Load these when the task calls for them This file is the judgement core: what holds for every fit. The lookup tables, and the rules one task *shape* needs, live beside it, loaded on demand, one file each. The user manual holds the object model this protocol drives and is not restated here; a page named `x` below is `https://rietx.org/using/x.html`. | When | Load | Manual page | |---|---|---| | you are about to call rietx: entry points, constructors, the four answer types and their fields, the report | [`references/api.md`](references/api.md) | `quickstart`, `model`, `refining`, `results`, `agents` | | you were handed another program's input file, not a pattern | [`references/api.md`](references/api.md) § In | `recipe`, `files` | | §7/§7g/§7h — a `Diagnostic` fired and you need its row: every engine code, a foreign project file's import-time codes, and what a file you wrote back could not carry | [`references/diagnostics.md`](references/diagnostics.md), [`references/diagnostics-projects.md`](references/diagnostics-projects.md), [`references/diagnostics-gsas.md`](references/diagnostics-gsas.md) | `results` | | §6 — something declined to answer: abstentions, caveats, gate failures, `best_or_none()` returning `None` | [`references/abstention.md`](references/abstention.md) | `report` | | §5 — you are about to quote a number: which field carries which fact, and read numbers rather than pixels | [`references/numbers.md`](references/numbers.md) | `report`, `results` | | §4/§4b — a judging or deliverable rule needs its measurement, before you override one | [`references/judging.md`](references/judging.md) | `report`, `qpa`, `constraints` | | §8 — the fit did something that makes no sense: twenty-one measured results that contradict an intuition | [`references/surprises.md`](references/surprises.md) | `refining` | | §7b-7f — the phase is unknown, or you want the peaks themselves and no cell: peak picking, fitting peaks you name, indexing, the closed loop, the extinction screen | [`references/diagnostics-indexing.md`](references/diagnostics-indexing.md) | `indexing` | | §9 — one fit is not the answer: the trajectory, and the history DAG as a search structure | [`references/history.md`](references/history.md) | `history` | | §9b — an in-situ ramp, a sweep or a tray: chaining N patterns, and checking the chain both ways | [`references/series.md`](references/series.md) | `series` | | §9c, deciding: ranking, differencing, auditing, identifiability | [`references/batch.md`](references/batch.md) | `history`, `series` | | §9c, operating: budget, cost, timing, the log, inventory, fault tolerance | [`references/batch-operating.md`](references/batch-operating.md) | `history`, `series` | | §9d — a human may be watching this fit, or you want to hand one a window onto a long run; also reading a finished run off disk | [`references/watching.md`](references/watching.md) | `cli`, `refining`, `files` | | writing the answer out: CIF, QPA table, reflection table, plots | [`references/api.md`](references/api.md) § Out | `exports` | --- ## 1. Before you refine: what the method can and cannot do Rietveld refinement **fits a structural model you already believe** to a whole powder pattern. It is a local, gradient-based optimisation of a strongly non-convex, strongly correlated problem. It is not structure solution, not phase identification, and not a search. Preconditions, all of which must hold before `fit()` is meaningful: | Requirement | How to satisfy it | If you cannot | |---|---|---| | Every crystalline phase present is in the model | `Structure.from_cif` per phase | An unmodelled phase's peaks land in the residual; Layer 0's `unmatched_obs` list is how you find them | | The starting cell is within ~1 % | from the CIF, or from `index_pattern` when the phase is unknown (§7d) | The peaks are outside their frozen evaluation windows and the refinement cannot walk there; Layer 2 says so with `reindex_or_recheck_cell` rather than reporting a small shift (§6) | | The wavelength is right | from the beamline `.prm`, the file header, or `Instrument.bragg_brentano(radiation=...)` — `"CrKa"`, `"FeKa"`, `"CoKa"`, `"CuKa"`, `"MoKa"`, `"AgKa"`, or any of them suffixed `1` for a Kα1-only monochromated beam | Every cell you report is wrong by the same scale factor and *nothing in the fit will tell you*. Do not hand-enter a wavelength from a textbook to "match" one of these: the table is one scale end to end (§8.11) and mixing scales is a ~100 ppm cell error | | The geometry is right | `Instrument.debye_scherrer` vs `.bragg_brentano` | The aberration model is wrong; displacement/transparency/roughness/absorption are geometry-gated and silently absent | | The intensities are un-manipulated counts, with esds if available | `read_pattern` reads the file's esd column when present | Weights are wrong ⇒ every esd and every χ² is wrong | | The starting peak **width** is within a factor of ~2 | measure it: median FWHM of the dozen most prominent peaks, then `W ≈ (FWHM/2)²`, `X ≈ FWHM` | `ProfileTCHZ`'s `W = 1e-3 deg²` default is a *synchrotron* line (FWHM ≈ 0.03°). On lab data with 0.15-0.40° peaks the frozen evaluation windows are an order of magnitude narrower than the lines, and nothing recovers from that — see §2 and §6 | **Never subtract a background before refining.** Subtraction invalidates the counting-statistics weights and can make intensities negative. Hold an estimated background *additively* (`BackgroundFixedPlusChebyshev`) or co-refine it under a smoothness penalty (`BackgroundPSpline`). `rx.auto_background(data)` does the right thing. --- ## 2. The turn-on order, and why it is not negotiable Free parameters in groups, cumulatively, in a stable order (McCusker, Von Dreele, Cox, Louër & Scardi, 1999, *J. Appl. Cryst.* **32**, 36), each group running to convergence before the next is freed. The reason is not tradition: the correlations between groups are severe, and a simultaneous release from a poor starting point walks into a local minimum that a staged release avoids. Toby (2024, *J. Appl. Cryst.* **57**, 175, the "recipe problem"): once parameters have refined to unphysical values, adding more parameters no longer lets the fit recover. The plans encode this. Use them; do not hand-roll a free set unless you have a reason you can state. The staged *discipline* is what is not negotiable; the preset *sequence* is a default, because the right next group depends on the data and the current values — and `ref.suggest(data)` answers that at the current state, one analytic-Jacobian evaluation ranking every held parameter by predicted Δχ², with no fit and no mutation. ```python plan="mccusker_default" # scale+bkg → zero → cell → W → U,V,X,Y (profile only) plan="mccusker_structural" # …then coordinates → displacement → PO → extinction → roughness plan="lab_bragg_brentano" # …with sample displacement, Kα2 ratio, FCJ axial plan="lab_calibrate" # instrument calibration on a standard, certified cell HELD plan="lab_sample_refine" # sample against a frozen calibrated instrument plan="profile_only" # Le Bail plan="pawley_default" # Pawley ``` `rx.PLAN_INFO` carries a title, description, modes and when-to-use for each. **Three ordering rules.** None is in the guidelines; each is this package's own measured finding. 1. **Widths last among the profile terms, `W` before `U,V,X,Y`.** `W` is the constant term; freeing the tanθ and 1/cosθ terms first lets them absorb a constant offset and then fight it. 2. **Intensity-scaling corrections go last, after the structure has settled.** Preferred orientation, extinction and surface roughness rescale intensities in a Q-dependent way, and so do the scale, the occupancies and the displacement parameters. Freeing a correction early lets it eat structure that belongs to the structure. 3. **Anisotropic strain is freed *inside* the sample-broadening stage, not after.** A Stephens block locks `lor_strain` — its isotropic direction *is* that column — so deferring it leaves the isotropic width unrefined right up to the moment fifteen correlated coefficients turn on at once. **Structure-free first when you can.** Le Bail (`mode="lebail"`) extracts intensities from the data instead of computing them, so it converges the cell, zero and profile with no structural assumption. Do that first, then switch to Rietveld with the converged cell and profile: it is the single most reliable way to avoid a structural minimum that is really a profile error. Its **cell** is the weaker half of that: where reflections are dense, arbitrary intensities can index one pattern more than one way, so check a Le Bail cell against even a rough structural model before quoting it (Peterson 2005). The variable is reflections per FWHM, so on a resolved pattern skip the check. Two rules about it the API does not tell you, both measured on third-party lab data. 4. **Iterate the whole plan to a fixed point; one `fit()` is not enough**, and **keep the best pass, not the last.** The extracted per-hkl intensities are frozen inside each least-squares run, so intensities and profile converge only by *alternating*, and the alternation is not a descent on one objective, so a later pass can come back worse. 5. **Seed the background before the first pass, always.** `auto_background` starts every coefficient at 0.0, so the first `lebail_update` runs before the background has ever been fitted, is handed the whole pedestal, and gives it to the Bragg reflections. Seed the constant term from a low percentile of `y_obs`. Both measurements, and multi-phase Le Bail's one surviving caveat: [`references/judging.md`](references/judging.md). --- ## 3. The degeneracies. Memorise these Almost every wrong-but-good-looking Rietveld result is one of these. They are not bugs; they are the geometry of the problem. | Degenerate group | Their angular signatures | Consequence of getting it wrong | |---|---|---| | zero shift · sample displacement · cell | const · cosθ · tanθ | Over a narrow 2θ range these are collinear. A cell "refined" against a free zero on 20° of data is not measured. Bragg-Brentano only — the two flat-plate aberrations are held fixed on any other geometry. | | zero shift · the two capillary offsets · cell | const · sin2θ · cos2θ · tanθ | The same trap in Debye-Scherrer's own shapes (McCusker eq 4, §8.18). Separable over 5–160°, not over 5–25°: the unit-column Gram's smallest eigenvalue is 5.2e-2 against 1.1e-5, a factor of ~4600. | | crystallite size · microstrain | 1/cosθ · tanθ | Williamson-Hall separability. Over a short range they are one parameter, not two. | | phase scale · Biso/ADPs · background · absorption · surface roughness · extinction | all smooth in Q | This is the big one. Every member depresses or lifts intensity as a smooth function of angle. Any of them can absorb any other. | | capillary µR · phase scale · Biso | exp(c·sin²θ) — *exactly* | Not "correlated": singular. µR is computed from the specimen and never refined, and the fit is identical with and without it (§8.1). | | flat-plate µt · phase scale · Biso | mostly, but not exactly | 60–99 % absorbable, so it is also computed rather than refined — but the remainder does move Rwp, and a wrong thickness lands partly in the fit and partly in the ADPs (§8.12). | | preferred orientation · site occupancy | both rescale specific hkl | An occupancy refined against uncorrected texture is a texture measurement. | | overlapped reflection intensities (Pawley/Le Bail) | identical | The *sum* is determined; the split is not. | | a declared extra peak · the reflection under it | identical where they overlap | An extra peak on a reflection is a scale/intensity degeneracy by construction: two terms, one peak, and Rwp cannot say which owns the counts. `EXTRA_PEAK_ON_REFLECTION` fires. Legitimate when the intruder is real; never a way to make a misfitting reflection go away. | 6. **Do not free the second member of a group without checking the first is pinned by something outside the fit.** `lab_calibrate` exists for this: refining a certified standard with its **cell held fixed** is what decorrelates zero from displacement from cell, because the cell is supplied rather than fitted. 7. **A correlation of 0.98+ means you refined one parameter and reported two.** `HIGH_CORRELATION` fires for you. The right response is almost never "widen the bounds"; it is to fix one, or to extend the data range until the signatures separate. 8. **Where chemistry says two quantities are one quantity, constrain them rather than refining both.** `ref.tie_equal([paths])` makes an equality group, `ref.tie(path, source, scale=, offset=)` the general affine form (`occ₁ = 1 − occ₀` on a mixed site is `scale=-1, offset=1`), `ref.untie` releases them. A constraint *removes* a parameter, unlike a restraint, which adds a weighted observation and leaves the count alone, so it is the one move that raises the observation-to-parameter ratio. The two cases worth reaching for are McCusker's: equal displacement parameters across atoms in the same environment, and occupancies summing to a known total. Measured on fluorapatite's three phosphate oxygens, tying them gives a B(O) tighter than the best free value. **Check the premise before you tie, and not with Rwp** — it moved by 0.05 % of itself there. The check is in the free refinement: if each free value lies within its own esd of the others, the data does not contradict the claim that they are one parameter. Where they disagree by more than their esds, the atoms are saying they are *not* in the same environment, and tying them replaces a measurement with an assumption. Symmetry always outranks a user tie, and a refused tie says so by name. --- ## 4. Judging a fit — and what Rwp is actually for Rwp compares your model to the *data you have*, weighted by counting statistics. It is dominated by the strongest peaks and by the background level: a useful *relative* number between two fits of the same data over the same channels, and a nearly useless absolute one. Measured, 18 refinements of one identical PbSO₄ dataset returned Rwp 8.2–20.0 % (Hill, 1992, *J. Appl. Cryst.* **25**, 589), and Toby (2006, *Powder Diffr.* **21**, 67) finds "no simple way to distinguish a good fit from one that is just plain wrong based on R factors". Judge a fit in this order. `print(result)` renders steps 9 and 17 (per-stage status, every diagnostic, provenance, agreement indices last), and `ref.summary(deliverable=…)` adds the rows that need the compiled model. The measured evidence behind each rule is [`references/judging.md`](references/judging.md). 9. **Status and guards outrank every statistic.** `result.status`, then `result.diagnostics`. `statistics.max_shift_over_esd` is the measured quantity behind "converged" (McCusker §7 converges at ≤ 0.1). A converged solve satisfies it a fortiori, so read it where a stage stopped on `STAGE_MAX_ITER`: its magnitude says how far the solve was still moving, in esd units. 10. **Read the shape of the difference curve region by region, not its size.** `report.regions` carries per-region local Rwp and χ² share, and `cumulative_chi2_breakpoints` locates where the model starts failing. 11. **Read the unmatched peaks.** `report.unmatched` with `kind="unmatched_obs"` is an impurity or a missing phase; `"unmatched_calc"` is a phase you modelled that is not there, or an absence error. Read `unmatched_calc` in Rietveld mode only. Le Bail and Pawley extraction takes away most of the residual it looks for, so there it fires on noise near a tick. 12. **Ask whether the refined values are physically possible** — negative Biso, occupancies above 1, a cell that moved 0.5 %, an ADP tensor that is not an ellipsoid — **and ask it of the structure too.** `result.geometry` is a `GeometryTable` of `bonds`, `contacts` and `angles`, which McCusker §11 ranks *with* the profile fit and above every R value, so read it before step 16. Nothing scores it: a Si–O at 1.75 Å or a 60° O–M–O is yours to recognise. The number of rows naming an atom is its coordination number, and a `None` esd means no covariance behind the row or fixed by symmetry, never zero. 13. **Quote no esd without its inflation.** `statistics.esd_inflation` is the Bérar-Lelann factor for serial correlation, and it has an expected value of ≈1.51 even for perfectly white residuals, so it is an upper bound on the damage rather than a measurement of it. `report.identifiability` carries the trio to pass on with any esd — raw χ²_red, the inflation, Durbin-Watson — plus the δR line. Scaling variances by GoF² alone is "highly questionable" (Schwarzenbach, 1989). 14. **Ask whether the converged answer is the only one, and settle it by a swap.** `report.identifiability.exchanges` and `.soft_modes` outrank the statistics, and **the verdict that licenses is `ambiguous`, not `converged`.** They are about what "converged" *means*: `converged` is a statement about the free set, while an `exchangeable=True` row says a **held** parameter's signature is reproducible inside the fitted span *and* that a fitted partner stands many σ from its null. The swap resolves it and is a measurement: fit each member of the pair *alone*, the other held at its **null**, and compare χ² — two warm fits, seconds, and `rx.report.compare_rivals(ref, data, finding)` runs exactly that. R² cannot stand in for it. Read the outcome on `RIVAL_DECISIVE_MIN_CHI2_RATIO` (= 1.10, `rietx.report`), the losing rival's χ² over the winner's: at or above it **the data has chosen, and you quote the winner without caveat**, since hedging a won swap is a measured failure rather than caution; below it the pair is genuinely unresolved and the resolution is protocol or a declared ambiguity. No sentence converts a tie into an answer. The licence also travels as `result.statistics.identifiability_clause`. What you must **not** do is free the held parameter alongside its partner and refit: both free lands on §3's degenerate ridge and reports the unconstrained combination at a *better* Rwp — the most common misreading of the clause. 15. **Read what the background is doing before you read Rwp**, because it decides how to read Rwp. In `report.background`, `worst_absorption` (with `worst_absorption_path`) is how much of a structural parameter the background column span can reproduce, and `off_region_chi2_reduced` with `off_region_durbin_watson` is whether the residual *between* the peak regions is systematic. Layer 0's regions are peak clusters, so that second failure lands in no `report.regions` entry and step 10 cannot see it. 16. **Only then Rwp and GoF, and never alone** — as a pair with `background.rwp_background_subtracted`. The raw number is flattered by whatever the background carries. The subtracted one is what separates two fits of the same data. 17. **Read the structure R factors last, and never in isolation.** `result.phase_agreement` carries `r_bragg` (R_B) and `r_f` (R_F) per phase. A powder pattern does not measure individual reflection intensities, so I(obs) is the pattern *partitioned in proportion to I(calc)*: a wrong model receives the intensity it predicted and both flatter it (Toby 2006: R_Bragg "has no statistical validity"). Watch R_B fall as you improve a model; never read it as evidence a correction helped. Absent in Le Bail and Pawley, where the intensities *are* the fit. **Do not compare a trace phase's R_B with the major phase's**: neither is weighted, and a minor phase's windows sit under the major phase's peaks. **Adding parameters: use ΔBIC, not Hamilton's R-ratio.** Measured at 7251 channels, Hamilton's test blesses a 0.13 % χ² improvement that is physically inert; ΔBIC carries the sample-size penalty powder channel counts need. **Comparing against another code means adopting its protocol, not just reading its numbers.** Mirror its refined-parameter set, its held parameters and its excluded regions, then *check the channel count matches* before believing any Rwp comparison. Measured: guessing a plausible protocol on the GSAS-II fluorapatite tutorial gave Rwp 16 % and a +390 ppm cell, while mirroring the converged `.EXP` gave 9.73 % against GSAS's 10.05 % on an identical 5750 channels. --- ## 4b. Declare the deliverable — "good enough" is a question about purpose Much real work is non-ideal by construction — nanoparticle broadening, intensity error from unknown pore contents. **No bar moves for such data**: the gates auto-scale to information content, and "good enough" is a different question
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub