Changelog#
All notable changes to the PowderLine package are recorded here. The format follows Keep a Changelog, and PowderLine versions follow Semantic Versioning.
The recipe schemas are versioned separately from the package and have their own history, on the versions page.
Unreleased#
0.2.0 - 2026-11-05#
PowderLine 0.2.0 is a clean break from the unified recipe schema 0.26.0: a recipe names one engine and is written in that engine’s own conventions, and nothing is translated between engines. Recipes written for 0.1.x do not validate; see the migration guide. Known limitations are listed in the known-issues register.
Highlights#
One recipe, one engine:
gsasii.*,topas.*andeasydiffraction.*recipes, each in its engine’s own names and units, through one API and one CLI.New schemas, starting at 0.1.0: a core schema plus one schema per engine replace the single 0.1–0.26.0 schema (engines).
Validation states what the engine computes: symmetry, engine floors and silent defaults become errors or structured warnings, never silent changes.
Uniform fit statistics:
rwp,r_exp,gof,chi2_redare computed by PowderLine over the fit window, the same way for every engine.The output recipe: every result carries the recipe with refined values written back, ready to validate and run again (KI-04).
Ionic scattering types and March–Dollase preferred orientation, and every failure raises an exception with a reason and a
failure.jsonrecord.
Upgrading#
Read the migration guide: a 0.26.0 recipe (
GSASII_Rietveld/GSASII_SPF) is refused atschema_name.Convert gsasii recipes with
python scripts/convert_recipe_026.py IN.json -o OUT.json; it reports every change and stops where 0.1.1’s refinement cannot be stated. TOPAS and easydiffraction recipes are written natively.API and CLI:
run()has noengine=; failures raise instead of returningsuccess: False; results havestatus, notsuccess/error;topas-kickeris gone (usepowderline); engine modules moved underpowderline.gateways.Environments: the default pixi environment is core-only; install an engine with
pixi install -e gsasii,-e easydiffraction(waseasydiff),-e allor-e dev, then runpixi reinstall powderline --allandpowderline --doctor.rwpis now PowderLine’s uniform Rwp over the fit window, not the engine’s own value (GSAS-II’s wR is underengine_details); compare old values with care.
Added#
Engine schemas
gsasii.rietveld/gsasii.spf(GSAS-II 5.7.9),topas.rietveld/topas.spf(TOPAS 6) andeasydiffraction.rietveld(easydiffraction 0.21.1), on a shared core phase block (fields).Declared schema compatibility: each gateway states the core and engine schema versions it accepts,
validate()enforces them, andpowderline.support_matrix()lists them (support matrix).powderline.validate(), engine-free, returningValidationResult(recipe, warnings); an invalid recipe raises pydantic’sValidationErrorlisting every problem at its field path.Structured warnings
{code, message, field_path, level}in validation output and results (level"warning"or"info"); infosymmetry_value_derivedrecords a value held in its exact symmetry-derived form.The output recipe (KI-04):
output_recipe,output_recipe_validandparameter_dispositionsin every result and validate-only summary, written tooutput_recipe.jsonandparameter_dispositions.csv.metadata.powderline_provenancein the output recipe andfailure.json, naming the PowderLine version, the engine and its version; gsasiiengine_detailsgainsengine_version.powderline.recipes.block/with_blockmove core blocks (xrd_data,fit_range, a phase) between recipes, e.g. to chain a sequential refinement.A
gsasii.spfresult carriespeak_fit: every parameter the peak fit varied, with value and ESD, by GSAS-II’s own name.Ionic
scattering_types(CIF spelling, e.g.La3+) per atom label in the gsasii and easydiffraction (cryspy) phase blocks, checked against each engine’s ion table (scattering types by engine; EB-94–EB-96).March–Dollase
preferred_orientation(hkl,ratio) in the gsasii and easydiffraction (cryspy) phase blocks (EB-97, EB-98).TOPAS accepts ionic
scattering_types(TOPAS 6’s table, 113 ions, written asLa+3inocc) and March–Dollasepreferred_orientation(thePOmacro; TOPAS’s default lower limit on r, 0.0001).powderline --doctor(pixi run doctor): gateways found, engine versions against their pins and the GSAS-II server’s state; non-zero exit on a stale install (KI-13).A failed run writes its failure envelope to
failure.jsonin the output directory, and a failedgsasii.*run carries GSAS-II’s console tail (KI-05).TOPAS time limit:
--topas-timeout SECONDS, configtopas.timeoutor thetopas_timeoutoption (default 3600 s pertc.exerun, 0 = none); past ittc.exeis stopped and the run raisesExecutionBackendError(reason="timeout"). The second run that only evaluates the background (y_bkg) does not fail a finished fit: stopped at the limit, it leaves the column empty withtopas_background_not_calculated.scripts/convert_recipe_026.py, the 0.26.0 →gsasii.*converter.Examples: per-engine recipes under
examples/<case>/{topas,easydiffraction}/,example_LaB6_temperature_series(sequential refinement),example_LaB6_ionicandexample_LaB6_textured, with easydiffraction references.Documentation, organized by reader: Get started, Concepts, How-to guides, Examples, Engines, Reference and Development, on pydata-sphinx-theme with diagrams and per-engine tabs (docs). Among its pages: outputs, fields, validation, engine behavior, cross-engine comparison and policies.
Every engine behavior (
EB-NN) and known issue (KI-NN) has its own entry and link, listed in the ID index. Known issues KI-19 to KI-21 cover the GSAS-II server’s lifetime, its state directory and a race ingsas-server stop(known issues).Engine citations in
CITATION.cffand on the citing page (#12).
Changed#
The recipe schema is split: the single 0.1–0.26.0 schema is replaced by a core schema and one schema per engine, each starting at 0.1.0 and told apart by
schema_name; the 0.x bump rule is in policies.A recipe names its engine and workflow in
schema_name(<engine>.<workflow>) and states that engine’s own terms and units; unknown keys are errors at every level.The public API is
run,validate,ValidationResult,load_recipe_asset,support_matrixand the exceptions;run()dispatches onschema_nameand takes engine options as keywords;import powderlineimports no engine.One CLI,
powderline <recipe.json>, installed with the package, serves every schema (--output,--validate-only,--verbose,--use-server/--no-server,--topas-dir,--topas-version,--topas-timeout);--validate-onlywrites nothing.Every failure raises
EngineExecutionError(the engine ran and failed) orExecutionBackendError(it did not run), with.reasonand.result, the failed envelope; the exceptions pickle.Every result carries
status(ok, orgeneratedfor a TOPAS run withouttc.exe),converged,simulation_modeandenvelope_version; a statistic without degrees of freedom isNone, never NaN.rwp,r_exp,gofandchi2_redare PowderLine’s uniform statistics over the weighted points of the fit window; the engine’s own values move toengine_details(LaB6: 6.5345 vs GSAS-II 6.5346).The fit window is exactly min ≤ 2θ ≤ max on the data points; a window with no weighted point is an error. A converted gsasii recipe fits one point fewer when its maximum falls between data points (EB-54).
gsasii defaults are stated and warned about: size/strain left out means 10 µm / 0 microstrain (was GSAS-II’s 1 µm / 1000), background left out means none (was 1.0), and refinement cycles left out mean 5, each with a warning.
New gsasii validation errors where GSAS-II used a floor silently or failed at run time: SH/L < 0.002, background or Peak List peaks below the floors,
scale< 0, wavelength or size ≤ 0, and more (EB-35, EB-37, EB-38, EB-53).Space groups are gemmi’s canonical names (
"P m -3 m","F d -3 m:2"); gsasii refuses origin choice 1 and the settings GSAS-II cannot express (EB-03, EB-41).Refine flags and values must match the symmetry: a tie group is stated whole with one flag, a symmetry-fixed parameter is not refined, and a stated multiplicity must equal the derived one.
A
topas.*recipe whose total TCHZ peak width is not positive somewhere in the fit window is a validation error (TOPAS writes no results there); a negative Lorentzian part X·tanθ + Y/cosθ with a positive total width runs as written.A
gsasii.*refinement that GSAS-II aborted (no step lowered χ²) raises adivergedfailure instead of returning its rejected pattern (EB-99).A failed run leaves only the engine’s own files and
failure.json: a gsasii run no longer writes result tables before PowderLine’s checks.powderline.run()removes PowderLine’s own fixed-name outputs from the output directory before every run, so a reused directory holds one run’s results; only once the recipe has validated and the engine is importable, so an invalid recipe or a run in an environment without the engine leaves the previous results in place.Every engine writes the same seven unit-cell report rows,
cell_a…cell_gamma,cell_volume; a gsasii simulation writes ESD0.0(was empty).The GSAS-II server needs no shared filesystem: output files come back inside the signed response (KI-12); it runs one job at a time and a stale server is detected and refused. Waiting for its answer has no time limit by default (as in-process);
--server-timeout SECONDS/ theserver_timeoutoption set one (past itExecutionBackendErrortimeout, no in-process fallback).TOPAS runs only from a declared directory (
--topas-dirortopas.dir); without one a run writes the INP and data and stops (status: generated).topas.*recipes stateengine_version: "6"and the installed version is declared the same way ("6", not"6.0"); TOPAS 7 is not supported.TOPAS execution is verified on TOPAS 6: the reference fixtures are reproduced byte for byte (KI-16).
easydiffraction recipes state the calculator (
cryspyorcrysfml) and the engine’s own instrument terms; anisotropic ADPs work with CrysPy (EB-23).Modules moved, without shims:
powderline.topas→powderline.gateways.topas,powderline.easydiff→powderline.gateways.easydiffraction;powderline.symmetryraisesSymmetryError.pixi environments: the default is core-only; engines live in
gsasii,easydiffraction,allanddev; a run in an environment without its engine raisesEngineNotAvailableErrornaming the install command.Pins: GSAS-II 5.7.9 and easydiffraction 0.21.1, checked at run time (
EngineVersionError); gemmi==0.7.5; pixi ≥ 0.82.1.The regression references under
examples/*/output/were regenerated once on the new path and gainoutput_recipe.jsonandparameter_dispositions.csv; the LaB6 examples drop their undeterminable background peak.The simulation recipe builder writes SH/L 0.002 (GSAS-II’s floor) and emits a
gsasii.rietveld0.1.0 recipe.CLI and GSAS-II server messages name the current commands:
pixi run powderline …,pixi install --frozen -e <env>,pixi run -e gsasii gsas-server stopfor a stale server (the next run starts a fresh one),pixi run -e gsasii gsas-server start, andpixi reinstall powderline --all.Messages say what they mean: an atom near a special position reports the distance to its symmetry image, and the GSAS-II background-default warning says GSAS-II’s own default background is fixed.
Removed#
The unified 0.26.0 schema and the cross-engine translation layer (
powderline.schema, the legacy TOPAS writer and easydiffraction builder).From the API:
run(engine=...),RecipeModel,validate_simulation_mode_parameters,powderline.engine, top-levelGSASClientand the shimspowderline.constraints,powderline.gsas_client,powderline.gsas_server.The
topas-kickerconsole script and pixi task.The result keys
success,errorandtraceback, the reasonoutput_not_visible, andGSASClient.run_simulation.gsasii fields with no effect:
refinement_algorithm, thenullinstrument and phase forms, parameter bounds,payload.asset_pathandIparm2.The Materials Project simulation tool (
mp-simulate) and its configuration; the simulation recipe builder stays.The
easydiffpixi environment (noweasydiffraction) and GSAS-II in the default environment.The TOPAS 7.25 references under
examples/*/output/topas/andexample_LaB6_easydiff.The pre-refactor TOPAS helpers (
topas/conversions.py,runner.run_topas,RunResult) and symmetry API (cell_constraints,site_dof,adp_dof,check_uij).The unused dependencies
h5py,pybaselinesandxmltodict.
Fixed#
A gsasii run no longer computes 4× the intensity for some 2-fold sites in R32, R-3m and R-3c, nor crashes on a site GSAS-II cannot name; both are errors naming a position to state (EB-40, EB-05).
A diverged gsasii refinement (non-finite pattern) no longer returns success with Rwp 100 % and a NaN profile (EB-52).
easydiffraction: 0.1.1’s wrong polarization (p = P, not 1 − P), swapped Lorentzian X/Y, FCJ S/L and H/L, and 2θ rounded to 4 decimals are gone (EB-72, EB-75, EB-76).
The simulation recipe builder counted a site multiplicity times and used origin choice 1 coordinates as origin 2 (EB-03); its grid now includes
max_2theta.powderline.symmetryhandles the monoclinic groups Pm, Pc, Cm and Cc in every setting, and classifies trigonal and hexagonal sites correctly.An exception while easydiffraction builds the project is
EngineExecutionError(reason="engine_crashed"), like one in the fit.A TOPAS
output_missingfailure carries its envelope: the files kept,tc_path, the exit code and any console text.A TOPAS output folder outside the Windows ANSI code page is run through the folder’s 8.3 short path (file names kept), or refused with a clear message before
tc.exestarts.The TOPAS at-limit warning tolerates TOPAS stopping just past a bound or a fit window edge.
A timed-out GSAS-II server request is a
timeoutfailure and no longer falls back in-process into the same directory; a bad port, a busy port or a Windows sharing violation is reported instead of crashing.Recipe and
.powderline_config.yamlfiles are read as UTF-8; malformed JSON or YAML is an error naming the file (the CLI says “Cannot read recipe”).
Security#
The GSAS-II server no longer writes into a client-chosen directory; the client writes returned files by bare name only, size-capped; a request body read before the signature check is capped at 4 KiB except on
/simulate(KI-12).pip >= 26.2.2and refreshedca-certificates/certifiafter the emSign CA incident; pixi ≥ 0.82.1 is required.
0.1.2 - 2026-10-10#
Tagged on main after the refactor branch was cut; merged into the 0.2.0
branch on 2026-10-14 (the server and client live at
src/powderline/gateways/gsasii/server.py / client.py there; the
known-issue entry is KI-14 on 0.2.0 because KI-13 was already taken).
Fixed#
GSAS-II server made per-user and token-authenticated: per-user state directory, loopback bind on an ephemeral port, bearer token on every route,
POWDERLINE_NO_SERVERto disable the server (#10).
0.1.1 - 2026-09-24#
The pre-refactor baseline; unified recipe schema 0.26.0.
Added#
easydiffraction engine (
engine="easydiffraction", optionaleasydiffpixi environment) with the SH/L → Thompson-Cox-Hastings/FCJ profile mapping (#2).Documentation published on GitHub Pages (#4–#7).
Fixed#
GSAS-II’s refinement failure message is surfaced instead of a silent no-Rwp result;
run()normalization no longer crashes on null tables from server failure responses (#3).
0.1.0 - 2026-08-17#
Initial public release.