Results#
Every engine returns the same kind of result: the same tables, the same statistics, a recipe you can run next, and a record of how it was made. Outputs lists every key and file; this page explains what they mean.
What comes back#
flowchart LR
RUN{{run}} --> T["Tables<br/>refined parameters · unit cell<br/>reflections · fit profile"]
RUN --> S["Statistics<br/>Rwp · Rexp · GoF · χ²"]
RUN --> O["Output recipe<br/>+ parameter dispositions"]
RUN --> P["Provenance<br/>run ID · engine · versions"]
RUN --> E["Engine's own files<br/>and statistics"]
From Python, powderline.run() returns a dictionary with the tables as
pandas DataFrames. The same tables are written as files with fixed names, so
a script finds them without asking which engine ran.
The same statistics for every engine#
PowderLine computes Rwp, Rexp, the goodness of fit and reduced χ² itself, with one formula, over the points inside the fit window that have a positive weight:
N is the number of points used and P the number of parameters the engine varied.
Why compute them again? The engines define them differently. They count
different points, cap values at 100 %, or use one name for two quantities.
With one formula over the same points, two models of the same data can be
compared directly. The engine’s own values are kept in engine_details.
Note
A lower Rwp means this model fits these points better. It doesn’t mean one engine is better than another. Comparing engines shows why.
Did the engine do what you asked?#
Two counts in engine_details show it:
parameters_requested: the independent parameters your recipe asks to refine, with each symmetry-tied group counted once;parameters_varied: what the engine actually varied.
Engines quietly drop or merge parameters, so when fewer are varied than
requested you get a warning. converged says whether the engine reached its
convergence criterion: true, false, or null when the engine can’t tell
(TOPAS, a GSAS-II peak fit) or nothing was refined.
The output recipe#
Every result includes an output recipe: your recipe with the refined values written back, symmetry-derived values in their exact form, and any defaults stated. Your flags, bounds, controls and data are unchanged. It is a complete recipe of the same type, ready to run again.
flowchart LR
R1["recipe"] --> RUN1{{run}} --> O1["output recipe"]
O1 -- "swap in the next pattern" --> RUN2{{run}} --> O2["output recipe"]
O2 --> N["…"]
That is what makes chaining simple: calibrant to sample, or one pattern of a series to the next. See Run a series.
output_recipe_valid says whether the output recipe passes validation as
written. It fails when the engine returned a value the schema refuses, such as
a negative crystallite size or an occupancy above 1. The recipe is still
returned and written so you can see what the engine produced, and the
warning output_recipe_not_valid names the value. A chained next step should
stop there.
Parameter dispositions#
parameter_dispositions lists every refinable value by its place in the
recipe, with the refined value, its ESD, and what happened to it:
Disposition |
Meaning |
|---|---|
|
refined by the engine |
|
its flag was |
|
fixed by the space group |
|
its flag was |
|
not in your recipe; PowderLine applied a documented default |
A column at_limit marks values that ended on a bound.
Provenance#
A recipe’s metadata block is yours: sample IDs, scan IDs, where the data
live in your catalog, how the recipe was made. PowderLine never reads it and
carries it through to the output recipe.
PowderLine adds one entry of its own, metadata.powderline_provenance, to
every output recipe:
Key |
What |
|---|---|
|
the ID of the run that produced this recipe (the result’s |
|
the recipe type |
|
the engine and the version that ran |
|
the PowderLine version |
|
when, in UTC |
Each output recipe identifies the run that produced it. PowderLine replaces
any incoming powderline_provenance block rather than retaining its history.
To trace a whole series, your pipeline must archive each step’s input and result
and record the input recipe’s parent_run_id alongside the new result’s run_id.
flowchart LR
M["metadata: scan 1042"] --> R1[recipe]
R1 --> A["run A"]
A --> O1["output recipe<br/>parent_run_id = A"]
O1 --> B["run B"]
B --> O2["output recipe<br/>parent_run_id = B"]
When a run fails#
A failed run never returns a result. It raises one of two errors:
Error |
Meaning |
Example |
|---|---|---|
|
The engine ran and failed |
The refinement diverged |
|
The engine never ran |
The GSAS-II server could not start |
Both carry .reason, a short code, and .result, the full failure record.
The output folder then holds the engine’s own files and failure.json, the
same record with its provenance, and no result tables. PowderLine removes
its report tables before each run, so a table in the folder comes from a run
that succeeded. One GSAS-II diagnostics file is the exception: see
Report files.
Simulations#
A simulation calculates the pattern of the recipe as written, refining
nothing. Each engine has its own way to ask for one: every flag false plus
refinement_cycles: 1 (GSAS-II) or iters: 0 (TOPAS), or no flag set
(easydiffraction). The result then says simulation_mode: true. The statistics
are computed in the same way, so against real data they show how good your
starting values are. See Simulate a pattern.