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

<a id="the-forward-model"></a>

# The forward model

This chapter states the equation that turns a structure, an instrument and a source into a calculated powder pattern.

A constant-wavelength powder pattern is modelled as a background plus a
triple sum over phases $p$, source emission lines $l$ and reflections $k$:

<a id="equation-fm-ycalc"></a>
$$
y_{\mathrm{calc}}(2\theta_i) \;=\; y_{\mathrm{bkg}}(2\theta_i)
\;+\; \sum_p \sum_l \sum_k I_{pk}\, w_l\, \Omega_{lk}(2\theta_i)
\qquad [\text{counts}]
$$

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

Each emission line (Kα₁/Kα₂, …) diffracts at its own Bragg angle, so the
doublet splitting grows with $\tan\theta$, as in [(2.5)](peak-positions.html.md#equation-pos-doublet). It is not a
fixed $2\theta$ offset. The line weight $w_l$ is the intensity of line $l$
relative to line 0. Line 0 itself is locked at 1, because its weight is
degenerate with the phase scales.

The three factors carry the units of [Symbols and units](index.html.md#sec-units).
$\Omega_{lk}$ is a unit-area profile (chapter [Peak profiles](profiles.html.md#ch-profiles)), so it is a
density on the angle axis, in deg⁻¹. $w_l$ is a ratio. The reflection intensity
$I_{pk}$ is therefore an area, in counts·deg 2θ: what the line integrates to,
and not the height it reaches. That is the conversion a reader coming from
another code needs most often.

<a id="three-intensity-models"></a>

## Three intensity models

<a id="rietveld-mode"></a>

### Rietveld mode

Intensities come from the structural model [[Rietveld, 1969](references.html.md#id2)]:

<a id="equation-fm-rietveld"></a>
$$
I_{pk} \;=\; S_p \cdot m_{pk} \cdot |F_{pk}|^2 \cdot \mathrm{Lp}(2\theta_{lk}),
$$

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

with phase scale $S_p$, multiplicity $m_{pk}$ (chapter [Intensities](intensities.html.md#ch-intensities)),
structure factor $|F|^2$ in e² and the Lorentz-polarisation factor Lp (chapter
[Intensity corrections](corrections.html.md#ch-corrections)). Everything but $S_p$ is fixed by the model, so the
scale is what turns e² into the counts·deg 2θ of $I_{pk}$. Its value carries no
meaning on its own. It is meaningful against the other phases’ scales, and the
quantitative fractions of [(5.18)](corrections.html.md#equation-corr-qpa) are therefore ratios. $|F|^2$ depends
only on $\sin\theta/\lambda = 1/2d$ and is shared across emission lines. Lp is
evaluated per line.

<a id="le-bail-mode"></a>

### Le Bail mode

Intensities are empirical per-$hkl$ values [[Le Bail *et al.*, 1988](references.html.md#id3)], updated between
least-squares cycles by observed-intensity partitioning summed over lines:

<a id="equation-fm-lebail"></a>
$$
I_k \;\leftarrow\;
\frac{\sum_l \sum_i \bigl[I_k\, w_l\, \Omega_{lk,i} / y_{\mathrm{bragg},i}\bigr]
      \cdot \max(y_{\mathrm{obs},i} - y_{\mathrm{bkg},i},\, 0)}
     {\sum_l w_l \sum_i \Omega_{lk,i}},
$$

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

Here $y_{\mathrm{bragg},i}$ is the Bragg part of [(1.1)](#equation-fm-ycalc) at point $i$.
It sums over every phase and leaves out the background. The bracket is then
reflection $k$’s share of the calculated Bragg intensity at that point, and the
shares sum to 1 at each point. The update is a fixed point when $y_{\mathrm{obs}} = y_{\mathrm{calc}}$. The
extracted intensities live outside the parameter vector and are path-dependent,
so a history node serialises them beside the parameters it stores.

<a id="pawley-mode"></a>

### Pawley mode

The per-$hkl$ intensities sit inside the least-squares problem
[[Pawley, 1981](references.html.md#id4)], as an off-table parameter block appended to $\theta$.
Equation [(1.3)](#equation-fm-lebail) is then used once, to seed the block before the first
solve. Reflections whose primary-line centres sit within
0.5 × their mean FWHM form an overlapped group and
receive a soft equal-split restraint, scaled so that the split-direction esd is
of order the group intensity itself. An unresolved split is then reported at
≈100 % uncertainty, where a bare pseudo-inverse of a singular $J^\top J$ would
report a spuriously tight one. Such groups come back flagged
`PAWLEY_OVERLAP_UNRESOLVED`.

The reflection list runs 0.5° past each end of the fitted window, so that a
reflection a stage moves onto the data is modelled. A reflection with no
emission line centred on the data reaches it only through a tail, so its column
is nearly zero and its intensity is bounded below only. Each such reflection
gets one more row in the same block, a ridge toward zero,

<a id="equation-fm-pawley-ridge"></a>
$$
r_k \;=\; \frac{\sqrt{\lambda}}{s_p}\, I_k,
\qquad s_p = \max_{j\,\text{on the data}} I_j ,
$$

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

where $s_p$ is the phase’s largest on-data intensity when the stage starts.
An intensity the data do not determine then stays within $s_p$, with an esd of
that order. One the data do reach has a column far more precise than a prior
that wide. Without the ridge, a synthetic series refined one such intensity to
$10^{12}$, and TRF’s step test, which is relative to $\lVert x\rVert$, ended
warm refits early (WP-1459). The result names the ridged reflections, one
`PAWLEY_OFF_DATA_RIDGED` diagnostic per phase, because their intensities are
the ridge’s and not the data’s.

<a id="the-residual-row-layout"></a>

## The residual row layout

The residual carries four blocks of rows, and the data is the first. The
layout,

<a id="equation-fm-rows"></a>
$$
r \;=\; \bigl[\; \text{data} \;\big|\; \text{background penalty}
\;\big|\; \text{Pawley restraint} \;\big|\; \text{soft restraint} \;\bigr],
$$

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

is defined once, in `rietx.model.rows`. Every builder consumes it: the numpy
residual, the numpy Jacobian’s row offsets, and the traced jax/torch residuals.
The data rows are $\sqrt{w_i}\,(y_{\mathrm{obs},i} - y_{\mathrm{calc},i})$. The
remaining blocks are described with the background models
([Background](background.html.md#ch-background)) and the restraints ([Parameterisation and constraints](parameterisation.html.md#ch-parameterisation)).

<a id="discreteness-frozen-per-stage"></a>

## Discreteness frozen per stage

Four things are computed when a stage is compiled and never change during a
least-squares run: the reflection list, the per-atom symmetry-operator subsets,
the per-(line, reflection) evaluation windows, and the FCJ quadrature node
counts. A window extends ±(k(η) · estimated FWHM + a floor + the FCJ smear
extent), with k(η) sized so that the discarded pseudo-Voigt area stays at or
below 0.02 (`rietx.model.forward.window_fwhm_mult`). That is
a declared stage’s fraction. A plan’s closing stage, a stage run by hand and
any model evaluated outside a fit use 0.001. Each phase’s
reflections are generated 0.5° past either edge of the range
(`rietx.model.forward.REFLECTION_MARGIN_DEG`), so a peak centred outside
the range still adds its tail.

Node positions and weights follow the parameters, smoothly. Freezing everything
else keeps the residual smooth for finite-difference and autodiff Jacobians.
Regeneration happens between stages.
