PowderLine is not yet on conda-forge or PyPI. In the meantime, it can be used in other local projects via an editable install that points directly at the repository. Changes to PowderLine source are picked up immediately — no reinstall required.
Two usage tracks are documented here:
- Full — schema validation + refinement execution (requires GSAS-II)
- Schema-only — validation only (pydantic is the only non-trivial dependency)
Template pixi.toml files and runnable example scripts live in docs/integration/.
Use this track when your project needs to run Rietveld refinements or single peak fitting, not just validate recipes.
cp /path/to/PowderLine/docs/integration/pixi_full.toml /path/to/your-project/pixi.tomlOpen your new pixi.toml and set:
[workspace]
name = "your-project-name" # ← change this
preview = ["pixi-build"] # required to build the GSAS-II conda package
[dependencies]
GSAS-II = { git = "https://github.com/tacaswell/GSAS-II", rev = "enh/pixi_pkg" }
[pypi-dependencies]
powderline = { path = "/path/to/PowderLine", editable = true } # ← change this pathGSAS-II is declared as a conda package built via pixi-build from the
tacaswell/GSAS-II fork (which adds the conda recipe), mirroring PowderLine's own
pixi.toml. This installs GSAS-II on all supported platforms
(linux-64/win-64/osx-arm64). It is not on PyPI or conda-forge, so it must be declared
in your own workspace rather than pulled in transitively by PowderLine.
Reproducibility tip: pin
gsas-iito the samerevPowderLine uses (see the[dependencies]block in the repo'spixi.toml) rather than a moving upstream branch, because GSAS-II profile-calculation changes can shift refinement results.
cd /path/to/your-project
pixi installpixi run python -c "import powderline; print(powderline.__version__)"Use this track for tools that construct or validate recipe JSON files (recipe builders, editors, CI pre-flight checks) without needing to run refinements. The environment is dramatically smaller — GSAS-II, wxpython, and all related native packages are not installed.
cp /path/to/PowderLine/docs/integration/pixi_schema_only.toml /path/to/your-project/pixi.toml[workspace]
name = "your-project-name" # ← change this
[pypi-dependencies]
powderline = { path = "/path/to/PowderLine", editable = true } # ← change this pathpixi install
pixi run python -c "from powderline.schema import RecipeModel; print('OK')"The imports a consuming project will use:
| Import | Purpose | Track |
|---|---|---|
from powderline.schema import RecipeModel |
Validate recipe dicts with Pydantic | Both |
powderline.validate() |
Validate a recipe dict (returns a RecipeModel); raises on invalid input |
Both |
powderline.load_recipe_asset() |
Load a recipe from a .json/.yaml/.txt file into a dict |
Both |
powderline.run() |
Primary programmatic entry point (validates + runs + returns DataFrames). Pass validate_only=True to validate without refining |
Full only |
from powderline.gsas_client import GSASClient |
Run via the persistent GSAS-II server | Full only |
import json
from pathlib import Path
from pydantic import ValidationError
from powderline.schema import RecipeModel
recipe_dict = json.loads(Path("input.json").read_text())
try:
recipe = RecipeModel.model_validate(recipe_dict)
except ValidationError as exc:
for error in exc.errors():
loc = " -> ".join(str(l) for l in error["loc"])
print(f"[{error['type']}] {loc}: {error['msg']}")The recommended entry point for new callers. Validates the recipe, dispatches to the GSAS-II server (or falls back to in-process execution), and returns results as pandas DataFrames.
import json
from pathlib import Path
import powderline
recipe = json.loads(Path("input.json").read_text())
result = powderline.run(recipe, Path("output/"))
# result keys (tabular outputs are pandas DataFrames; per-phase tables are
# dicts of DataFrames keyed by phase name):
# result['success'] bool
# result['rwp'] float
# result['elapsed_time'] float
# result['method'] str (which execution path was used)
# result['fit_profile'] DataFrame
# result['unit_cell_data'] dict[str, DataFrame] (keyed by phase name)
# result['peak_list_data'] dict[str, DataFrame] (keyed by phase name)
# result['refined_parameters'] DataFrame (9-column table with ESDs)
# result['spf_peaks'] DataFrame (SPF mode; empty for Rietveld)
# result['spf_convergence_diagnostics'] DataFrame
# result['output_files'] list[str]Execution mode can be controlled with the execution_mode parameter:
# 'auto' (default): tries server first, falls back to subprocess
# 'server': HTTP server only (fails if unavailable)
# 'subprocess': in-process fallback (always available, slower for repeated calls)
result = powderline.run(recipe, Path("output/"), execution_mode='server')from powderline.gsas_client import GSASClient
client = GSASClient(fallback_to_subprocess=True)
result = client.submit_simulation(
recipe=Path("input.json"), # also accepts a dict or RecipeModel
output_dir=Path("output/"),
auto_start_server=True,
)Both powderline.run() and GSASClient produce identical output files and results.
The difference is startup overhead:
| Mode | When to use | GSAS-II startup cost |
|---|---|---|
powderline.run() (auto) |
Default for single scripts; tries server then falls back | Avoided if server is running |
GSASClient (server) |
Batch pipelines, interactive tools, repeated calls in one session | Paid once per server lifetime (~10 s) |
GSASClient with auto_start_server=True will start the server automatically if
not running and fall back to subprocess mode if the server fails to start.
powderline.run() uses GSASClient internally.
docs/integration/example_full.py — runnable demonstration of the main import patterns.
docs/integration/example_schema_only.py — runnable demonstration of schema validation
and batch validation without importing GSAS-II.
Both scripts have a POWDERLINE_REPO constant at the top that you must edit to point
at your local clone.
PowderLine supports the open-source easydiffraction Rietveld engine via
engine="easydiffraction". This requires the optional easydiff pixi environment
(easydiffraction needs Python ≥3.12; the default environment stays at ≥3.10):
pixi install -e easydiffimport powderline
result = powderline.run(recipe, "output", engine="easydiffraction")v1 capabilities: translates unmodified GSASII_Rietveld recipes; supports unit-cell,
scale, wavelength, Chebyshev background, Caglioti U/V/W + Lorentzian X/Y broadening,
and zero-shift refinement; multi-phase; simulation mode (no refinement flags set).
Rejects loudly (translation error) atom-level refinement flags, Kα₁/Kα₂ two-wavelength
recipes, refined Z / polarization / axial divergence / background peaks, and SPF
recipes. Fixed anisotropic ADP values are not modeled and are dropped with a warning.
Profile model: a nonzero SH/L automatically selects the Thompson–Cox–Hastings
profile with fixed FCJ axial-divergence asymmetry (CrysFML calculator; hkl peak lists
are recovered with a post-fit CrysPy calculation). On the identical LaB6 recipe,
GSAS-II reaches Rwp 6.01% vs easydiffraction 9.63% (both χ² < 1); the remaining gap
comes from background peaks (not modeled) and residual profile differences, so
compare lattice parameters, not Rwp, across engines — Rwp is not an
apples-to-apples metric.
For the engine architecture and how to add a backend, see the Adding a Refinement Engine section of the developer guide. The full design dossier and backend survey live in the private PowderLine-devkit.
When PowderLine is published to conda-forge, the editable path dependency becomes a version pin:
# pixi_full.toml — after conda-forge release
[dependencies]
powderline = ">=1.0"
# gsas-ii may still need to be declared here until it too is on conda-forge
GSAS-II = { git = "https://github.com/tacaswell/GSAS-II", rev = "enh/pixi_pkg" }