<a id="ch-parameterisation"></a>

<a id="parameterisation-and-constraints"></a>

# Parameterisation and constraints

This chapter states how the model becomes the parameter vector the solver moves, and how symmetry, restraints and the user’s own constraints tie its entries.

<a id="from-tree-to-vector"></a>

## From tree to vector

The pydantic model tree compiles to an ordered table of parameters with
stable dot-separated paths (`phases.0.cell.a`, `instrument.profile.w`) and
an affine constraint block

<a id="equation-par-affine"></a>
$$
p_{\mathrm{phys}} \;=\; C\, p_{\mathrm{free}} + d,
$$

*Source:* [`rietx.params.vector`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/params/vector.py#L1)

with sparse $C$ rebuilt at every stage boundary and constant during a
least-squares run, so a constant matrix product stays exact under the autodiff backends.
Cell ties ($b \leftarrow a$, fixed angles) are the identity-row special case,
and Wyckoff site constraints supply general rows. Three kinds of entry are
structurally locked and can never be freed by a glob: the first emission line’s
weight (degenerate with the phase scales), symmetry-fixed cell angles, and fully
fixed special positions.

The cell ties follow the space-group setting rather than the crystal system.
Three settings disagree with the system alone, and in each the number of free
cell parameters is the same either way. The count is right while the subspace is
wrong, so the test is which angle is held and which length follows which:

- a monoclinic symbol may be unique-axis $a$, $b$ or $c$, and the one angle its
  symmetry leaves free is $\alpha$, $\beta$ or $\gamma$ respectively;
- an R lattice on rhombohedral axes needs $a = b = c$ with
  $\alpha = \beta = \gamma$ free, in place of the hexagonal-axes
  $b \leftarrow a$ with $c$ free and all three angles fixed. The file decides
  which description arrives: `read_small_structure` resolves a bare `R -3 c`
  over a rhombohedral cell to the `:R` setting;
- the `:1`/`:2` extensions are origin choices and leave the metric untouched.

A symmetry-fixed angle is checked against the value its symmetry demands, and
the cell is refused if it disagrees by more than 0.001°.
The angle is held at its stored value, so an orthorhombic symbol over a cell
carrying $\beta = 93.2°$ would otherwise compute every $d$-spacing from that
angle in silence.

*Source:* [`rietx.crystallography.symmetry.cell_constraints`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/crystallography/symmetry.py#L615)

Every parameter refines in its own units, with its `min` and `max` passed to
the driver as a box. A `transform` stored before schema 0.46 is read as the box
it enforced: softplus and exp as a lower bound at zero, logit also as an upper
bound at one.

*Source:* [`rietx.schemas.common.legacy_transform_bounds`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/schemas/common.py#L786)

<a id="site-symmetry-degrees-of-freedom"></a>

## Site-symmetry degrees of freedom

Coordinates and anisotropic ADPs refine as site-symmetry DOFs. The constraint
bases are derived from the space-group operators by exact rational linear
algebra, with no floating-point tolerance and no per-site lookup table. (Wyckoff
naming is a separate job, delegated to spglib [[Togo *et al.*, 2024](references.html.md#id48)].)

A displacement δ of a site fixed by operations $\{(R, \mathbf{t})\}$ must
satisfy $R\,\delta = \delta$, so the coordinate basis spans

<a id="equation-par-coord"></a>
$$
\bigcap_R \ker(R - I)
$$

*Source:* [`rietx.crystallography.wyckoff.coordinate_basis`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/crystallography/wyckoff.py#L149)

([[Hahn, 2002](references.html.md#id16)] sect. 8.3.2). The same intersection taken over every rotation
of the group, not one site’s, gives the origin shifts that change no structure
factor,

<a id="equation-par-origin"></a>
$$
\bigcap_{R\in G} \ker(R - I)
$$

*Source:* [`rietx.crystallography.wyckoff.floating_origin_basis`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/crystallography/wyckoff.py#L160)

([[Hahn, 2002](references.html.md#id16)] Part 15): the polar axis of a polar group, nothing for a
non-polar one. A fit freeing a coordinate of every atom along it has a flat
direction.

With `Phase.floating_origin = "hold"` the parameter table fixes that
direction. For each basis row $\mathbf{f}$ of [(9.3)](#equation-par-origin), it first asks
whether the columns a stage could free can shift the phase along
$\mathbf{f}$ and move nothing else:

<a id="equation-par-origin-floats"></a>
$$
\exists\,\Delta p_{\mathrm{free}}:\quad C\,\Delta p_{\mathrm{free}} = \mathbf{v}_{\mathbf{f}}
$$

*Source:* [`rietx.params.vector.ParameterTable._origin_floats`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/params/vector.py#L2793)

Here $C$ is the block of [(9.1)](#equation-par-affine) over every column that is not held,
locked or tied. The vector $\mathbf{v}_{\mathbf{f}}$ moves each coordinate row
of the phase by its component of $\mathbf{f}$ and every other row the forward
model reads by zero. Where [(9.4)](#equation-par-origin-floats) has a solution, the table
holds the first displacement DOF that the shift moves. Atom $j$ states the
shift in its own basis as $B_j^\top \mathbf{a}_j = \mathbf{f}$, and the held
DOF is the first one, in atom order, with a nonzero coefficient:

<a id="equation-par-origin-hold"></a>
$$
\Delta\theta_{j^\ast k^\ast} = 0,
\qquad (j^\ast, k^\ast) = \min\{\, (j, k) : a_{jk} \neq 0 \,\}
$$

*Source:* [`rietx.params.vector.ParameterTable._fix_origin`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/params/vector.py#L2711)

The other atoms’ coordinates along $\mathbf{f}$ are then measured relative to
atom $j^\ast$. Their esds are the esds of those differences, and atom $j^\ast$
has none. Where a caller’s tie or hold already leaves
[(9.4)](#equation-par-origin-floats) without a solution, the table holds nothing more,
because a second hold would remove a real degree of freedom.

With `Phase.floating_origin = "centroid"` nothing is held. Each stage whose
*free* columns solve [(9.4)](#equation-par-origin-floats) instead gains one
pseudo-observation per floating direction, restraining a weighted centroid
of the phase’s sites to where the stage found it [[Flack and Schwarzenbach, 1988](references.html.md#id17)] (equation 9):

<a id="equation-par-origin-centroid"></a>
$$
Z_p = \sum_n a_n\,\boldsymbol{\Delta}_p^\top(\mathbf{x}_n - \mathbf{x}_n^0) = 0
$$

*Source:* [`rietx.model.origin.origin_residual`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/model/origin.py#L273)

The $\boldsymbol{\Delta}_p$ are the rows of [(9.3)](#equation-par-origin), orthonormal in
fractional components, and $\mathbf{x}_n^0$ the coordinates at the start of
the solve. The data are flat along the shift, so the solve satisfies
[(9.6)](#equation-par-origin-centroid) exactly whatever the $a_n$. The weights change only
the covariance. They solve the paper’s equation 21,

<a id="equation-par-origin-weights"></a>
$$
a_m \sum_{n \neq m} a_n = b_m,
\qquad b_m = \frac{1}{P}\sum_p \bigl\lVert \sqrt{w} \odot
\partial \mathbf{y} / \partial(\text{site } m \text{ moved by } \boldsymbol{\Delta}_p) \bigr\rVert^2
$$

*Source:* [`rietx.model.origin.centroid_coefficients`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/model/origin.py#L90)

with $b_m$ the curvature of the data rows when site $m$ moves alone along the
floating directions, measured once per stage by central difference
(`rietx.model.origin.site_curvatures`), and the system solved by the
paper’s (A6) iteration. These weights make the restrained normal matrix as
nearly diagonal as it can be along the floating directions (the paper’s
equation 20). Each coordinate then keeps an esd that can be quoted without its
covariances, and on average the weights are proportional to $Z_n^2$. Two sites give
$b_1 = b_2$ identically, so the equation fixes only the product and
$a_1 = a_2 = \sqrt{b}$. The restrained matrix is then diagonal, and each
site’s esd is that of their difference over $\sqrt{2}$. A direction only one
site can move along is held as `"hold"` holds it. Where (A5) has no solution,
because one site’s curvature exceeds the others’ combined, that curvature is
clipped a little below the bound, close to a hold on that site, and the
diagnostic says so. The rows form a block of their own, so a stage’s
restraint weight $c_w$ never scales them.

The $U^{ij}$ tensor transforms as $U \to R\,U
R^\top$ under a rotation acting on fractional coordinates, so the allowed
ADP pattern spans the invariant subspace of that action on symmetric 3×3
matrices [[Peterse and Palm, 1966](references.html.md#id44)] (cross-checked against the cctbx tables
[[Grosse-Kunstleve and Adams, 2002](references.html.md#id45)]):

<a id="equation-par-adp"></a>
$$
U \;=\; \sum_k \theta_k\, B_k,
\qquad R\, B_k\, R^\top \in \operatorname{span}\{B_j\} \ \forall R.
$$

*Source:* [`rietx.crystallography.wyckoff.adp_basis`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/crystallography/wyckoff.py#L190)

Both bases come back as smallest-integer row vectors in a deterministic
RREF-derived form. An $x,x,z$ site gives $[[1,1,0],[0,0,1]]$, and a hexagonal
three-fold site gives $U_{11} = U_{22} = 2U_{12}$ as $[2,2,0,1,0,0]$. Coordinate
DOFs are affine ties through [(9.1)](#equation-par-affine). ADP DOFs are absolute
($U = \sum_k \theta_k B_k$), which enforces the site symmetry exactly, and a
tensor outside the allowed subspace raises rather than being symmetrised. The
same construction one rank up yields the Stephens $S_{HKL}$ bases of
[Microstructure](microstructure.html.md#ch-microstructure).

The stabiliser also fixes how many atoms the site puts in the cell. The
site multiplicity is the orbit length, and by orbit-stabiliser it is

<a id="equation-par-multiplicity"></a>
$$
m \;=\; \frac{|G|}{|G_{\mathbf{x}}|},
\qquad G_{\mathbf{x}} = \{(R, \mathbf{t}) : R\,\mathbf{x} + \mathbf{t} \equiv
\mathbf{x} \bmod 1\},
$$

*Source:* [`rietx.crystallography.symmetry.site_orbit`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/crystallography/symmetry.py#L865)

so $m$ always divides the group order [[Hahn, 2002](references.html.md#id16)], and the orbit is generated
one image per left coset of $G_{\mathbf{x}}$. Counting distinct images by
pairwise comparison instead gives the same answer wherever the comparison is
exact, and no answer at all where it is inexact: proximity within a tolerance is
not transitive, so the partition follows the order the operators arrive in and
its size need not divide $|G|$. A coordinate within the tolerance of a special
position is therefore projected onto it before the images are generated, by the
Reynolds average over $G_{\mathbf{x}}$, which moves the coordinate only along
the directions [(9.2)](#equation-par-coord) forbids. Multiplicities feed $ZMV$ and hence
every quantitative phase fraction of [Estimation](estimation.html.md#ch-estimation), and none of that
reaches $R_{wp}$.

<a id="magnetic-moment-constraints"></a>

## Magnetic moment constraints

A site’s ordered magnetic moment is symmetry-constrained the way a coordinate
is, by the operators that fix the site. Two things differ. A moment is an axial
vector rather than a polar one, and a magnetic operation carries a time-reversal
sign $\varepsilon = \pm 1$ that an ordinary space-group operation does not. An
operation $(R, \mathbf{t}, \varepsilon)$ acts on a moment as

<a id="equation-par-moment-action"></a>
$$
\mathbf{m} \;\to\; \varepsilon \,\det(R)\, R\, \mathbf{m},
$$

*Source:* [`rietx.crystallography.magnetic.operators.MagneticOperator.moment_matrix`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/crystallography/magnetic/operators.py#L294)

with $R$ untransposed [[Halpern and Johnson, 1939](references.html.md#id46)] and $\varepsilon$ the magnetic
group’s own sign [[Perez-Mato *et al.*, 2015](references.html.md#id47)]. The reciprocal-space $R^\top$ convention
this manual uses elsewhere for an hkl does not apply to a real-space axial
vector. The allowed-moment subspace for a site’s stabiliser is then
$\bigcap \ker(\varepsilon\det(R)R - I)$, the same construction as
[(9.2)](#equation-par-coord) with this action in place of $R$.

Moment components are stored on the crystal axes, in a right-handed basis of
unit vectors parallel to the cell edges rather than the edges themselves.
Outside a cubic cell the magnitude is therefore something other than
$\sqrt{\sum_i m_i^2}$:

<a id="equation-par-moment-magnitude"></a>
$$
|\mathbf{m}| \;=\; \sqrt{\mathbf{m}^\top G\, \mathbf{m}},
$$

*Source:* [`rietx.crystallography.magnetic.operators.moment_magnitude`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/crystallography/magnetic/operators.py#L1288)

with $G$ the unit-vector metric, ones on the diagonal and the cell’s cosines
off it. A hexagonal $(1, 1, 0)$ moment therefore has magnitude 1 $\mu_B$, and
not $\sqrt{2}$. A moment in this crystal-axis form also converts to the
orthonormal Cartesian frame `rietx.crystallography.adp.cartesian_basis` already
builds for the ADP tensor of [(9.8)](#equation-par-adp). Normalise each direct-lattice basis
vector to unit length before applying it:

<a id="equation-par-moment-cartesian"></a>
$$
\mathbf{m}_{\mathrm{cart}} \;=\; \left(\frac{\mathbf{a}}{a}, \frac{\mathbf{b}}{b},
\frac{\mathbf{c}}{c}\right) \mathbf{m},
$$

*Source:* [`rietx.crystallography.magnetic.operators.moment_to_cartesian`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/crystallography/magnetic/operators.py#L1265)

the same Cholesky-derived Cartesian frame the ADP construction uses. The
crystal-axis and fractional components differ by $D = \mathrm{diag}(a, b, c)$,
so on crystal-axis components an operation acts by $D R D^{-1}$, which is $R$
itself exactly when every pair of axes $R$ mixes has equal lengths: a 4-fold’s
$a$ and $b$, a hexagonal 3-fold’s $a$ and $b$. Every tabulated setting meets
that, so the constraint algebra never has to see a cell. A sheared cell of the
same lattice does not: MnF₂’s group restated in $(a, b, a+c)$ has a 4-fold
that mixes $a+c$ with $a$, whose lengths no cell of that setting can make
equal. A magnetic group carries no cell, so in such a setting its crystal-axis
moment methods refuse by name rather than answer with $R$
(`MagneticGroup.axis_mixing` names the operation).

<a id="sec-moment-dofs"></a>

<a id="moment-degrees-of-freedom"></a>

## Moment degrees of freedom

A magnetic moment takes the same construction one tensor rank *down*, and then
departs from it in the one way that matters. The allowed subspace at a site is
the simultaneous fixed points of the axial action over the site’s magnetic
stabiliser: the rotation untransposed, times its determinant, times the
operation’s time-reversal sign:

<a id="equation-par-moment"></a>
$$
\bigcap_{(R,\,\mathbf{t},\,\varepsilon)\, \in\, G_{\mathbf{x}}}
\ker\bigl(\varepsilon \det(R)\, R - I\bigr).
$$

*Source:* [`rietx.crystallography.magnetic.operators`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/crystallography/magnetic/operators.py#L1)

The same exact rational nullspace as [(9.2)](#equation-par-coord) and [(9.8)](#equation-par-adp), and
the same deterministic smallest-integer basis. The transposed set is a group
too, so a wrong action leaves the *dimension* of this subspace unchanged in
every crystal system; the only test that can fail is whether a known moment
lies in the derived span. Measured over all 1651 magnetic space groups
against a grid of sites, $R$ and $R^{\mathsf T}$ give different spans for 543
(group, site) pairs and every one of them is trigonal or hexagonal, so a test
set built from rutile, perovskite and spinel proves nothing here.

Where the moment departs from the ADP is the parameterisation. A powder
average determines $|m|$ and, for a uniaxial structure, the angle to the
unique axis, and nothing else [[Shirane, 1959](references.html.md#id133)]. The directions it cannot
determine have to *be columns* of the least-squares problem for the package’s
flat-direction rule to name them, and neither the components nor their
coefficients on [(9.13)](#equation-par-moment) is one: a rotation of the moment is a
combination of all of them, so every coefficient would come back unmeasured
and the magnitude, which the data does determine, would come back with no esd.
So the DOFs are a modulus and angles inside the allowed subspace,

<a id="equation-par-moment-dof"></a>
$$
\mathbf{m} \;=\; \mu \sum_k \hat{u}_k(\phi,\theta)\, \mathbf{e}_k,
\qquad \mathbf{e}_i^{\mathsf T} G\, \mathbf{e}_j = \delta_{ij},
$$

*Source:* [`rietx.crystallography.magnetic.moments`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/crystallography/magnetic/moments.py#L1)

with $\{\mathbf{e}_k\}$ a Gram-Schmidt frame of [(9.13)](#equation-par-moment) in the magCIF
unit-vector metric $G$ (ones on the diagonal, cosines of the cell angles
off it). That metric is what makes $\mu$ equal $|m|$ as the CIF defines it: on
hexagonal axes the moment $(1, 1, 0)$ is $1\ \mu_B$, not $\sqrt 2$. One
dimension gives $(\mu)$ with $\mu$ *signed*, two give $(\mu, \phi)$ and three
$(\mu, \theta, \phi)$; the frame is frozen per stage from the declared cell,
like every other discrete object here.

Nothing bounds these DOFs while a stage solves, so a fit can end at
$\phi + 2\pi k$, at $(-\mu, \phi + \pi)$ or at $(\mu, -\theta, \phi + \pi)$,
which are all the same moment. Every commit therefore moves a block into one
chart: $\mu \ge 0$ for two or three DOFs, $\theta \in [0, \pi]$ and
$\phi \in (-\pi, \pi]$, the chart the stage’s seed is already in. Each move is
an identity on the moment and negates whole columns at most, so it changes no
esd, and the solver’s correlations are re-signed with it. An entry a tie reads
or the caller holds is left where it is. The chart still has a cut at
$\phi = \pm\pi$, so the series fences compare an angle across patterns
modulo a turn.

<a id="rigid-bodies"></a>

## Rigid bodies

A rigid body is a set of a phase’s atoms placed by one template. The atoms’
coordinates are not parameters of their own: they are the output of a
nonlinear map applied after the affine block, the *derived block* of the
parameter table,

<a id="equation-par-body"></a>
$$
\mathbf{x}_i \;=\; \mathbf{o} \;+\; M^{-1}(a, b, c, \alpha, \beta, \gamma)\,
\operatorname{Exp}(E\,\boldsymbol{\theta})\, R_0\, \mathbf{T}_i ,
$$

*Source:* [`rietx.params.bodies.RigidBodyBlock`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/params/bodies.py#L138)

with $\mathbf{T}_i$ the template point in Å, $R_0$ the stored orientation,
$\delta\boldsymbol{\omega} = E\,\boldsymbol{\theta}$ the refined rotation
increment (a rotation vector; Solà et al.’s left-plus increment
[[Solà *et al.*, 2018](references.html.md#id145)]), $\mathbf{o}$ the origin and $M$ the closed-form Cartesian
frame with $\mathbf{a}$ along $x$ and $\mathbf{b}$ in the $xy$ plane. There
are as many rotation parameters $\boldsymbol{\theta}$ as the template’s
inertia rank: three, with $E = I$, for any body that is not linear; two for a
linear one, $E$’s columns perpendicular to its axis, since a turn about the
axis moves nothing. Every commit composes the increment into the record,
$R_0 \leftarrow \operatorname{Exp}(\delta\boldsymbol{\omega})\,R_0$ and
$\boldsymbol{\theta} \leftarrow 0$, so each stage starts where the exponential
map’s Jacobian is the identity. The cell
is a live input, so a body keeps its geometry in Å while the cell refines.
The origin refines like an atom’s coordinates, on its site-symmetry degrees of
freedom. Each body atom’s esd comes through the map’s exact Jacobian at the
refined parameters, chained through the covariance of the origin, rotation and
cell. A distance between two atoms of one body has no esd, because the template
fixes it.

A named-bond torsion turns a declared set of the body’s atoms by an angle
$\varphi$ about the line through two other body atoms, before the pose, in
the right-handed sense from the first axis atom to the second (TOPAS’s
`Rotate_about_points` [[Coelho, 2018](references.html.md#id88)]):

<a id="equation-par-torsion"></a>
$$
\mathbf{T}_i \;\leftarrow\; \mathbf{T}_a + R_{\hat{\mathbf{u}}}(\varphi)\,
(\mathbf{T}_i - \mathbf{T}_a),
\qquad \hat{\mathbf{u}} = \frac{\mathbf{T}_b - \mathbf{T}_a}{|\mathbf{T}_b - \mathbf{T}_a|},
$$

*Source:* [`rietx.params.bodies.apply_torsions`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/params/bodies.py#L90)

with $R_{\hat{\mathbf u}}(\varphi)$ Rodrigues’ rotation. The moved set is
declared, not derived from bonds, so the derivative with respect to
$\varphi$ is exact by construction. Written with its middle pair in the
axis’s order, $i$–$a$–$b$–$j$, a dihedral changes by $\varphi$ when $j$ is
a moved atom and by $-\varphi$ when $i$ is. Like the body’s own rotation,
a torsion refines as an anchored increment, $\varphi = \varphi_0 + \delta\varphi$, and every
commit sets $\varphi_0 \leftarrow \varphi_0 + \delta\varphi$ and
$\delta\varphi \leftarrow 0$. About one axis that composition is addition,
so the chart moves by a translation and the esd of $\delta\varphi$ is the
esd of $\varphi$.

A body’s *shape* is a hypothesis the data can reject. `Refinement.check_rigid_bodies` releases each body’s atoms as free coordinates held near the template by soft restraints and compares the two fits on the data χ² alone, by Hamilton’s R-factor ratio test [[Hamilton, 1965](references.html.md#id77)] and by ΔBIC [[Schwarz, 1978](references.html.md#id76)], both at the effective sample size of the serially correlated residual. It warns (`RIGID_BODY_MISFIT`) only when both reject the body, and names the template bonds the released fit moved.

A hydrogen in a body rides with it, at a tabulated length from its parent atom
that depends on what the data measure: the SHELXL riding defaults for X-ray
data (C–H 0.93–0.98 Å, O–H 0.82 Å, the electron-density centroid) and the
neutron means of the *International Tables* Vol. C § 9.5 for neutron data
(C–H 1.06–1.10 Å, N–H 1.009 Å, O–H 0.967 Å). A joint X-ray and neutron fit takes the
neutron lengths, because the hydrogen signal is in the neutron histogram.

<a id="soft-restraints"></a>

## Soft restraints

A bond-length, angle or value restraint contributes one row to the residual
of [(1.5)](forward-model.html.md#equation-fm-rows) [[Waser, 1963](references.html.md#id98); [Watkin, 1994](references.html.md#id99)]:

<a id="equation-par-restraint"></a>
$$
r_{\mathrm{restr}} \;=\; \sqrt{w}\,
\frac{\mathrm{computed}(\theta) - \mathrm{target}}{\sigma},
$$

*Source:* [`rietx.model.restraints.restraint_residual`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/model/restraints.py#L233)

appended after the data rows, so restraints land in the covariance $J^\top J$
and are excluded from $R_{wp}$, Durbin-Watson and the Bérar-Lelann inflation. A
soft observation carries weight in the solution and none in the agreement
statistics. The geometry is nonlinear in θ,
where the background-penalty and Pawley rows are linear, because a bond length
$d = \sqrt{\Delta x^\top G\, \Delta x}$ depends on coordinates and cell. The
rows and their Jacobian are therefore recomputed per θ. The neighbour atom is
taken at a symmetry image $R\mathbf{x} + \mathbf{t} + \mathbf{n}$ with
$(R, \mathbf{t}, \mathbf{n})$ frozen per stage, the exact analogue of the
frozen reflection list, so positions move smoothly inside a stage while the
discrete image choice stays fixed.

Two one-sided distance rows follow the same pattern: a tether contributes
$\sqrt{w}\,\max(0, d - d_{\max})/\sigma$ and an anti-bump
$\sqrt{w}\,\min(0, d - d_{\min})/\sigma$, each zero on its flat side. An
anti-bump pair list is built once from the starting coordinates and kept for
the whole plan, so the number of restraint rows never changes between stages.

<a id="weighting-the-restraints"></a>

## Weighting the restraints

A stage scales every restraint at once. The minimised quantity is then
equation (7) of the IUCr guidelines [[McCusker *et al.*, 1999](references.html.md#id9)],

<a id="equation-par-restraint-weight"></a>
$$
S \;=\; S_y \;+\; c_w S_G,
\qquad S_G \;=\; \sum_k w_k \left(
\frac{\mathrm{computed}_k(\theta) - \mathrm{target}_k}{\sigma_k}\right)^2,
$$

*Source:* [`rietx.model.forward.CompiledModel.restraint_residual`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/model/forward.py#L3166)

with $S_y$ the data rows of [(8.1)](estimation.html.md#equation-est-obj) and $S_G$ the restraint rows of
[(9.17)](#equation-par-restraint) squared. The guidelines set $c_w$ high while the structural
model is incomplete or approximate, and reduce it as the model improves. That
makes it a property of the stage rather than of the restraint. It is frozen onto
the compiled model at stage compile, so a schedule changes it between stages and
never inside one.

Two seams decide where the scalar may act. $\sqrt{c_w}$ multiplies the assembled
rows, so every backend sees it through one row builder. It never reaches the
compiled restraints or their partials, whose second consumer computes the
derived-quantity esds of [(8.7)](estimation.html.md#equation-est-derived) at $\sigma = w = 1$; a scale leaking
that far would multiply every reported bond esd by $\sqrt{c_w}$. And $c_w = 0$
silences the rows without deleting them, so the row count the agreement
statistics exclude cannot move part-way through a plan.

<a id="par-parametric-section"></a>

<a id="a-parameter-as-a-function-of-each-pattern-s-coordinates"></a>

## A parameter as a function of each pattern’s coordinates

A joint fit stacks $N$ patterns into one residual [[Von Dreele, 1997](references.html.md#id5)], each
pattern with its own parameter table and the shared parameters folded onto one
column each. Parametric refinement [[Stinton and Evans, 2007](references.html.md#id14)] holds one parameter to a
declared function of where each pattern sits. Pattern $k$ carries coordinates
$z_k$, a temperature down a ramp or a composition across a library, and its
value of the target is

<a id="equation-par-parametric"></a>
$$
p_k \;=\; \sum_{j=1}^{m} \Phi_{kj}\, c_j,
\qquad
\Phi_{kj} \;=\; \prod_{i \in t_j} u_i(z_k),
\qquad
u_i(z) \;=\; \frac{z_i - z_i^{\mathrm{ref}}}{s_i},
$$

*Source:* [`rietx.params.parametric.resolve_parametric`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/params/parametric.py#L133)

where the term $t_j$ is a list of coordinate names, a repeated name being a
power and the empty term the intercept ($\Phi_{kj} = 1$), and the coefficients
$c_j$ are the refined parameters, shared by every pattern of the declared
subset. That is the polynomial basis. A design basis supplies $\Phi$ as the
caller’s own matrix, and a constant basis is the single column of ones.

The function is linear in its coefficients, so it is exactly one affine tie of
[(9.1)](#equation-par-affine) per pattern, with $C_k = \Phi_k$ and $d = 0$. The tie needs no
derivative of its own: what each coefficient’s column moves is read off $C$, as
for any tie. A function with a coefficient inside a power or an exponential (an
Arrhenius rate, an order-parameter exponent) is not of this form and cannot be
declared. A basis whose columns are collinear over the subset is refused before
any solve: pivoted QR on the column-normalised $\Phi$ names the dependent terms,
with its cut at $\sqrt{\mathrm{rcond}}$ of the leading diagonal, since an
eigenvalue of $\Phi^\top\Phi$ below the covariance’s own cut would leave a
declared coefficient with no esd. Mixture fractions summing to one make the
intercept their sum, so the Scheffé form drops it.

The reference $z^{\mathrm{ref}}$ and scale $s$ are part of the declaration.
Left out, they are the mid-range and half-range of the subset’s coordinates,
computed once when the declaration is resolved and stored with it, so a pattern
that joins later rebuilds $\Phi$ from the same numbers and never redefines a
coefficient. Centring makes the intercept’s coefficient the target at
$z^{\mathrm{ref}}$ rather than an extrapolation to $z = 0$, and removes the intercept-slope correlation an
off-centre coordinate creates. The equilibration of the normal matrix before
[(8.5)](estimation.html.md#equation-est-cov) fixes a column’s scale and not that correlation, which is why the
declaration centres.

The coefficients are reported per unit of the coordinates themselves, at the
reference:

<a id="equation-par-parametric-units"></a>
$$
\tilde c_j \;=\; \frac{c_j}{\prod_{i \in t_j} s_i},
\qquad
\sigma(\tilde c_j) \;=\; \frac{\sigma(c_j)}{\prod_{i \in t_j} s_i},
$$

*Source:* [`rietx.params.parametric.coefficient_rows`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/params/parametric.py#L345)

with $\sigma(c_j)$ from the joint covariance [(8.5)](estimation.html.md#equation-est-cov). So the intercept is
the target at the reference and the coefficient of a temperature its slope
there, in the target’s unit per kelvin. A design coefficient is reported as
$\Phi$ defines it. A constant basis’s one coefficient carries the target’s own
bounds, intersected over the subset; a sum of terms has no box that holds every
pattern’s target, so the coefficients are unbounded and a target that leaves
its range is reported after the fit.

When the coefficients are the only shared parameters and each pattern’s own fit
is linear, profiling out each pattern’s private parameters leaves a quadratic in
$p_k$ whose curvature is that pattern’s own information. The joint $c$ is then
the generalised least-squares fit of [(9.19)](#equation-par-parametric) to the per-pattern
values, weighted by that information, and the declaration changes no number
that line through the separate fits’ values would give. On a synthetic
ten-pattern ramp the joint slope sat a mean 0.0012 esd from that line. The joint form changes the
answer where a pattern’s own likelihood is not Gaussian in $p_k$, such as a
minor phase near its detection limit, or where other parameters are shared as
well.

The coefficients’ esds assume the declared form is right, so the fit tests
each declaration against the alternative that frees its target in every
pattern of the subset. In pattern $k$ a coefficient’s column is
$\Phi_{kj}\,\partial r/\partial p_k$, so each pattern’s own column for the
target is read off the coefficients’ columns with no further evaluation. The
declaration is rejected when

<a id="equation-par-parametric-form"></a>
$$
\frac{\min_\beta \lVert r - J\beta \rVert^2
      - \min_\beta \lVert r - J_{\mathrm{u}}\beta \rVert^2}
     {\chi^2_{\mathrm{red}}} \;>\; c_k,
\qquad F_k(c_k) = \gamma,
$$

*Source:* [`rietx.params.parametric.form_tests`](https://github.com/yue-here/rietx/blob/v1.10.0/src/rietx/params/parametric.py#L434)

with $r$ the weighted residual at the answer and $J$ its free columns, less any
the fit left on a bound. $J_{\mathrm{u}}$ is $J$ with the declaration’s
coefficient columns replaced by each subset pattern’s own target column. A
pattern that cannot see the target is left out of $J_{\mathrm{u}}$, as an
untied fit would hold the target there. $k$ is the number of directions
$J_{\mathrm{u}}$ adds past the covariance’s cut, the subset’s size less $m$
when nothing is degenerate. $F_k$ is the $\chi^2_k$ distribution function,
and $\gamma$ = 0.95. Each minimisation is one linear
step, so the numerator is the score statistic of [(8.17)](estimation.html.md#equation-est-suggest) for $k$
columns at once [[Rao, 1948](references.html.md#id123)], and the test needs no refit. The denominator
is the answer’s own $\chi^2_{\mathrm{red}}$, the restricted estimate the score
test takes. Dividing by the squared Bérar-Lelann factor of
[(8.6)](estimation.html.md#equation-est-berar-lelann) as well, as an esd is inflated, made the test far
stricter than $\gamma$. On equations that must hold any smooth truth, over three
real ramps, none of 261 readings rejected with that factor and 12 of 242
(5.0 %) without it.

A fit with several declarations reads each one a second time, with the other
declarations’ targets freed too. Let $J_{\mathrm{a}}$ swap every tested
declaration’s coefficient columns and $J_{\mathrm{o}}$ every one but this. The
numerator is then the difference
$\min_\beta \lVert r - J_{\mathrm{o}}\beta \rVert^2 - \min_\beta \lVert r - J_{\mathrm{a}}\beta \rVert^2$,
and $k$ is the difference of their directions. That reading does not assume the other
declarations’ forms, and the declaration is rejected when it passes its cut.
Two declarations whose target columns are nearly collinear can each pass this
way while both are wrong, because each one’s columns absorb the other’s
misfit. So the fit is also read once with $J_{\mathrm{a}}$ in place of
$J_{\mathrm{u}}$, every tested declaration swapped at once and $k$ their
directions together. That joint reading rejects the set and names no
declaration in it.

On the 33-pattern ZrMo₂O₈ ramp the numerator was 0.98-1.04 of the $\chi^2$ a
full untied refit removed, for the strong phase’s equations and for three equations
together, and the verdict matched the refit’s on all five equations tested. At the
three-equation answer, the second reading of the cubic equation’s numerator was 575.3,
against the 576.1 a refit of that equation alone removed. A pattern that cannot see
the target adds nothing to the numerator, so the test
cannot check how a form carries through the patterns where the target is
invisible. On synthetic ramps whose minor phase faded out, or was broad and
overlapped, a bent truth was not rejected in 20 seeds of 20, as it did under a
full untied refit, and no straight truth was rejected in 40.
