Skip to content

Rietveld refinement ​

Stage order ​

Rietveld stages

refine_phase follows the McCusker order. Each stage changes only its own parameters and leaves the rest at the value the previous stage reached:

StageParametersMethod
background_scalescale and the background polynomialanalytic weighted least squares
zero_cellzero shift and the free cell numbersNelder-Mead simplex
widthmultiplier on the PXRD FWHMNelder-Mead simplex
structureWyckoff coordinates, isotropic ADPs, occupancies, March-Dollase textureNelder-Mead simplex

The scale and a constant, linear or quadratic background are linear, so they are solved directly at every model evaluation. The other parameters move the reflection positions or the relative intensities and are refined by a bounded direct search.

The zero shift, the cell and the width are strongly correlated: a small cell change can be absorbed by a width change, and a zero shift can be absorbed by the cell. At a displaced start the Gauss-Newton direction can point uphill, while a simplex still finds the valley. Every simplex vertex is projected onto the parameter bounds and the scale/background are refitted before the vertex is scored, so the search compares complete models.

Wyckoff-allowed coordinates ​

A site may only move along the directions its stabilizer leaves invariant. For every symmetry operation R that maps the site onto itself modulo a lattice translation, a displacement u keeps the site on the same Wyckoff position when R u = u. Intersecting that condition gives:

  • three directions on a general position,
  • one on a mirror or a rotation axis,
  • none at an inversion centre.

free_directions(operations, frac) returns an orthonormal deterministic basis of that subspace. The refinement creates one parameter per basis vector, so a rutile oxygen at 4f (x, x, 0) moves only along [1, 1, 0] / sqrt(2) and a site at the origin does not move at all.

Cell family ties ​

Only the numbers the metric family leaves free are refined, and the ties are restored after every move: a cubic cell keeps a = b = c, a tetragonal or hexagonal cell keeps a = b, and the angles of the higher-symmetry families stay at their base values. Without the ties, a refined a would no longer equal the untouched b and symmetry-equivalent reflections would split apart.

Texture ​

The March-Dollase factor for a reflection with unit normal n and a preferred-orientation axis a is

text
r^2 cos^2(theta) + sin^2(theta) / r,  raised to -3/2,

with cos(theta) = n . a. r = 1 is random orientation. In this port the axis is fixed by RefineOptions::texture_axis and only r is refined.

Standard uncertainties ​

At the final values the Jacobian is built by central differences of the complete model, so the analytic scale/background refit is already projected into every column. The covariance is (J^T W J)^-1 scaled by the reduced chi-squared, and the diagonal gives the parameter esds. The scale and the background coefficients are fitted analytically and are reported without esds.

Occupancies and the scale are degenerate: multiplying every occupancy by c and dividing the scale by c leaves the pattern unchanged. Only the occupancy ratios are observable, and the reported absolute values follow the fitted scale. This is why the CLI enables occupancy refinement only with --occupancies.

Validation ​

crates/xtalforge-analysis/tests/rietveld_golden.rs reads tests/golden/phase-7/rietveld/rutile.xy, generated by the Crystal-Builder _rutile_xy fixture (rutile, P4_2/mnm, a = 4.5940, c = 2.9590, oxygen at x = 0.29, Cu K alpha 1 + K alpha 2, 20-80 degrees, Poisson noise with seed 0). The structure starts at x = 0.26; the McCusker stages must return it to the generating position:

  • x within 3e-3 of 0.29, still on (x, x, 0),
  • a and c within 2e-3 Angstrom, with a = b exactly,
  • zero shift within 0.02 degree,
  • Rwp < 0.25, every requested parameter with a positive esd,
  • stages exactly pawley_cell -> background_scale -> zero_cell -> width -> structure.

When the cell is refined, a Pawley fit runs first (pawley_cell) and its cell becomes the starting point when it moves less than 5 %. A Rietveld cell refinement alone is local: from a rutile cell 1 % off it stopped at Rwp 0.47 with c = 2.932 instead of 2.989; with the Pawley start it recovers a = 4.6399 and c = 2.9890 (Rwp 0.12, the same as from the true cell). Added by the functional audit of 2026-11-11.

The synthetic tests in tests/rietveld_stages.rs add exact recoveries of a known zero shift, cell, width multiplier, March-Dollase ratio, ADP multiplier, occupancy ratio and the Wyckoff direction counts.

Checked on a second structure ​

A noisy, backgrounded NaCl pattern (Poisson noise, 150 counts of background, single wavelength) refined from a starting cell of 5.64 Angstrom returns a = 5.620, width_scale = 0.997 and a zero shift of 0.000 with Rwp 0.094 when the model uses one wavelength (doublet = false, CLI --no-doublet). With the doublet model on single-wavelength data the isotropic ADP multiplier runs to its bound to compensate (Rwp 0.26, a = 5.615), and on a noise-free pattern with zero background the 1 / y weights drive Rwp towards 0.7: match the radiation and give the data a background or an uncertainty column.

Documented deviations ​

  • The profile is the PXRD engine area-normalised Gaussian for every reflection; RietveldOptions::kind is accepted but does not change this curve. The reference uses a pseudo-Voigt with a Caglioti width.
  • With doublet = true the copper K alpha 1/K alpha 2 pair is placed from the K alpha 1 position with the 0.5 intensity ratio. Other radiations use one line. This is why the golden Rwp is 0.15, not the ~0.05 of the rietx reference, which uses the full instrument profile.
  • The isotropic ADP is one global multiplier on every site's U_iso, not one free U_ij per site.
  • The energy term of combined_objective needs a force-field calculator that this signature does not have, so it stays at zero during the fit.