# Refining many patterns There are two ways to have more than one pattern, and they are not variants of each other. A series is N separate refinements, ordered, each starting from the one before it. A joint fit is one refinement whose residual is several patterns stacked together, sharing the parameters that describe the specimen. | | Series | Joint fit | |---|---|---| | Residual | N of them, solved one at a time | one, with every pattern's points in it | | What crosses a pattern | the starting values | the shared parameters themselves | | Answers | a trajectory: a(T), w(t) | one set of numbers, informed by every pattern | | Use it for | an in-situ ramp, a parametric sweep, a tray of specimens | one specimen measured twice, at two wavelengths or on two instruments | | Entry point | `SequentialRefinement`, `refine_sequential` | `MultiHistogramRefinement`, `refine_multi` | | Modes | any | Rietveld only | The question that separates them is whether the specimen changed. Eight mixtures with different compositions are eight specimens, so their cells are eight measurements and a series is the right shape. One powder measured at two wavelengths is one specimen, so its cell is one number and a joint fit is. ## A series is N refinements, chained `SequentialRefinement` takes the starting models once and the patterns at `SequentialRefinement.fit`. ```python import rietx as rx series = rx.SequentialRefinement(structure, instrument) result = series.fit(patterns, x=temperatures, x_label="T (K)") ``` `refine_sequential` is the same run as one call, and it is what most code wants: ```python result = rx.refine_sequential(patterns, structure, instrument, x=temperatures, x_label="T (K)") ``` ### Where `x` comes from `x` is the series coordinate: the quantity the experiment varied, and on an in-situ run the point of the experiment. A vendor file records it where its format has a field for it, and the reader puts it in the pattern's own metadata: ```python import rietx as rx patterns = [rx.read_pattern("ramp.raw", scan=i) for i in range(68)] temperatures = [float(p.metadata["temperature_k"]) for p in patterns] ``` `PatternData.metadata` holds strings, so the conversion is yours. Read the key with `dict.get` and refuse rather than substitute when it is missing. An absent key is a file that recorded nothing, and not a specimen at ambient. Today the Bruker `.raw` v3 range header is the one format here with such a field; the others record no specimen temperature, and a reader will not guess one from an axis named for something else. `rietx.io.readers.list_scans` answers the same question without reading the patterns. It returns one `rietx.io.formats.base.ScanInfo` per scan, each carrying `index`, `n_points`, the stepped range, and the temperature where the file gave one, which is also what its `label` says, since the scans of a reel are otherwise indistinguishable from each other. Both return a `SeriesResult`. The class keeps more: after a fit, `SequentialRefinement.results_` holds each pattern's full `RefinementResult` with its curves, `SequentialRefinement.trees_` holds the per-pattern histories, `SequentialRefinement.result_` is the `SeriesResult` that was returned, and `SequentialRefinement.backward_` is the backward chain when one was run. `SequentialRefinement.fitted_structures` and `SequentialRefinement.fitted_instruments` are each pattern's refined models in series order, one per pattern, because nothing here is shared. `SequentialRefinement.structure` and `SequentialRefinement.instrument` are the package's own deep copies of the models you passed, so your originals are not moved by the fit. Four settings are constructor arguments, because they describe the chain rather than a run of it: `backend`, `solver`, `history`, and `SequentialRefinement.carry`. [](refining.md) has the full table of which setting goes where. `history` behaves as it does for a single refinement ([](history.md)) with one addition: given a directory, each pattern's tree is written to `/