API Reference
This page provides detailed documentation for PowderLine’s Python API.
Schema Module
Pydantic models for recipe validation.
Pydantic models for validating GSAS-II refinement recipe JSON files.
Schema 0.25 introduced a two-tier structure: schema_name + payload pattern. This enables distinct validation rules for Rietveld vs single peak fitting workflows.
Schema 0.26 changes recipe semantics without changing recipe shape: per-parameter refine flags are now honored for unit-cell parameters, atomic coordinates, and anisotropic displacement components (previously collapsed into GSAS-II’s lumped whole-cell / per-atom flags). A parameter refines iff it is present with refine_flag=true; absent or false means fixed. Symmetry-linked parameters (e.g. cubic a=b=c) refine together if any member is requested. See docs/SCHEMA_HISTORY.md.
- powderline.schema.RefinementParameter
Format for a single refinement parameter,
[value, refine_flag, min, max]. Modeled as a fixed 4-tuple (rather than a list) so each position keeps its own type; serialized back to a JSON list via the attachedPlainSerializer.alias of
Annotated[tuple[float|None,bool|None,float|None,float|None],PlainSerializer(func=~powderline.schema., return_type=list, when_used=json)]
- class powderline.schema.RefinementParameterModel(*, value: float | None, refine_flag: bool | None, min_val: float | None = None, max_val: float | None = None)[source]
Bases:
BaseModelModel for the standard [value, refine_flag, min, max] parameter format.
- classmethod from_list(param_list: list) RefinementParameterModel[source]
Create from [value, refine_flag, min, max] list format.
- class powderline.schema.InstrumentBroadening(*, U: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, V: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, W: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, X: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, Y: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, Z: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, **extra_data: ~typing.Any)[source]
Bases:
BaseModelInstrument broadening parameters (Thompson-Cox-Hastings pseudo-Voigt).
- U: RefinementParameter | None
- V: RefinementParameter | None
- W: RefinementParameter | None
- X: RefinementParameter | None
- Y: RefinementParameter | None
- Z: RefinementParameter | None
- class powderline.schema.InstrumentCorrections(*, zero_shift: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, axial_divergence: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, **extra_data: ~typing.Any)[source]
Bases:
BaseModelInstrument correction parameters.
- zero_shift: RefinementParameter | None
- axial_divergence: RefinementParameter | None
- class powderline.schema.InstrumentParameterization(*, wavelength: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, polarization: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, broadening: ~powderline.schema.InstrumentBroadening | None = None, corrections: ~powderline.schema.InstrumentCorrections | None = None, **extra_data: ~typing.Any)[source]
Bases:
BaseModelInstrument parameter settings for refinement.
- wavelength: RefinementParameter | None
- polarization: RefinementParameter | None
- broadening: InstrumentBroadening | None
- corrections: InstrumentCorrections | None
- class powderline.schema.InstrumentModel(*, description: str, initialization: list[dict[str, Any]], parameterization: InstrumentParameterization | None = None, **extra_data: Any)[source]
Bases:
BaseModelInstrument configuration.
- parameterization: InstrumentParameterization | None
- class powderline.schema.ChebyshevBackground(*, num_coefficients: Annotated[int, Gt(gt=0)], coefficients: list[float], refine_flag: bool, **extra_data: Any)[source]
Bases:
BaseModelChebyshev polynomial background.
- class powderline.schema.SinglePeaksBackground(*, positions: list[~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)]] | None = None, intensities: list[~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)]] | None = None, pv_gaussian_sigma: list[~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)]] | None = None, pv_lorentzian_gamma: list[~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)]] | None = None, **extra_data: ~typing.Any)[source]
Bases:
BaseModelSingle peak background parameters (for background.single_peaks).
Width convention: uses Gaussian sigma (σ), not sigma squared (σ²). This is the natural convention for describing peak widths and matches scipy/TOPAS usage. Contrast with
SinglePeaks(peak-list peaks) which uses σ² to match GSAS-II’s internal Peak List storage format. See also:SinglePeaks.pv_gaussian_sigma_sq.- positions: list[RefinementParameter] | None
- intensities: list[RefinementParameter] | None
- pv_gaussian_sigma: list[RefinementParameter] | None
- pv_lorentzian_gamma: list[RefinementParameter] | None
- class powderline.schema.SinglePeaks(*, positions: list[~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)]] | None = None, intensities: list[~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)]] | None = None, pv_gaussian_sigma_sq: list[~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)]] | None = None, pv_lorentzian_gamma: list[~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)]] | None = None, **extra_data: ~typing.Any)[source]
Bases:
BaseModelSingle peak fitting parameters (for top-level single_peaks).
These peaks are fitted in the Peak List, allowing individual peak refinement independent of phase structure.
- positions: list[RefinementParameter] | None
- intensities: list[RefinementParameter] | None
- pv_gaussian_sigma_sq: list[RefinementParameter] | None
- pv_lorentzian_gamma: list[RefinementParameter] | None
- class powderline.schema.BackgroundModel(*, chebyshev: ChebyshevBackground | None = None, single_peaks: SinglePeaksBackground | None = None, **extra_data: Any)[source]
Bases:
BaseModelBackground model configuration.
- chebyshev: ChebyshevBackground | None
- single_peaks: SinglePeaksBackground | None
- class powderline.schema.SinglePeakFittingMode(*, use_instrument_profile: bool, **extra_data: Any)[source]
Bases:
BaseModelSingle peak fitting mode configuration.
Schema 0.25 Addition: Required for GSASII_SPF schema.
- class powderline.schema.RefinementControls(*, refinement_cycles: Annotated[int, Ge(ge=1)] = 5, refinement_algorithm: str | None = None, single_peak_fitting_mode: SinglePeakFittingMode | None = None, **extra_data: Any)[source]
Bases:
BaseModelControls for refinement execution.
Schema 0.25 Simplification: Removed multi-strategy refinement system from 0.24. PowderLine now executes a single refinement pass (proj.refine() for Rietveld, hist.refine_peaks() for SPF).
Future algorithm selection (e.g., Powell vs Levenberg-Marquardt) may be controlled via refinement_algorithm field.
- single_peak_fitting_mode: SinglePeakFittingMode | None
- class powderline.schema.UnitCellParameters(*, a: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, b: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, c: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, alpha: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, beta: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, gamma: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, **extra_data: ~typing.Any)[source]
Bases:
BaseModelUnit cell parameters (a, b, c, alpha, beta, gamma).
Schema 0.26 semantics: each parameter refines iff it is present with refine_flag=true; absent or false means fixed (held). Parameters that are symmetry-linked for the phase’s Laue class (e.g. cubic a=b=c, or the coupled monoclinic a/c/beta) refine together if any member is requested; flags on symmetry-fixed parameters (e.g. cubic angles) have no effect. Listing only the parameters you wish to refine is equivalent to listing all six with explicit flags.
- a: RefinementParameter | None
- b: RefinementParameter | None
- c: RefinementParameter | None
- alpha: RefinementParameter | None
- beta: RefinementParameter | None
- gamma: RefinementParameter | None
- class powderline.schema.AtomParameters(*, x: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, y: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, z: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, occupancy: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, ADP: str, Uiso: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, Uaniso: dict[str, ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None] | None = None, **extra_data: ~typing.Any)[source]
Bases:
BaseModelAtomic position and displacement parameters.
Schema 0.26 semantics: each coordinate (x/y/z) and each anisotropic Uaniso component refines iff present with refine_flag=true; absent or false means fixed (held). Site-symmetry-linked components refine together if any member is requested; symmetry-fixed components ignore their flags.
- x: RefinementParameter | None
- y: RefinementParameter | None
- z: RefinementParameter | None
- occupancy: RefinementParameter | None
- Uiso: RefinementParameter | None
- class powderline.schema.SizeBroadening(*, model: ~typing.Literal['isotropic', 'uniaxial', 'ellipsoidal'] = 'isotropic', isotropic_size: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, uniaxial_equatorial: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, uniaxial_axial: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, hkl_direction: list[int] | None = None, S11: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, S22: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, S33: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, S12: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, S13: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, S23: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, LG_eta: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, **extra_data: ~typing.Any)[source]
Bases:
BaseModelCrystallite size broadening parameters.
Schema 0.25 Change: Renamed size to isotropic_size to prepare for future uniaxial/ellipsoidal size broadening support. Added model field to specify broadening geometry (isotropic, uniaxial, ellipsoidal).
Models: - isotropic: Single size parameter (currently implemented) - uniaxial: Equatorial and axial sizes with hkl direction (future) - ellipsoidal: Full S11-S23 tensor (future)
- model: Literal['isotropic', 'uniaxial', 'ellipsoidal']
- isotropic_size: RefinementParameter | None
- uniaxial_equatorial: RefinementParameter | None
- uniaxial_axial: RefinementParameter | None
- S11: RefinementParameter | None
- S22: RefinementParameter | None
- S33: RefinementParameter | None
- S12: RefinementParameter | None
- S13: RefinementParameter | None
- S23: RefinementParameter | None
- LG_eta: RefinementParameter | None
- class powderline.schema.StrainBroadening(*, model: ~typing.Literal['isotropic', 'uniaxial', 'generalized'] = 'isotropic', isotropic_strain: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, uniaxial_equatorial: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, uniaxial_axial: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, hkl_direction: list[int] | None = None, stephens_parameters: dict[str, ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)]] | None = None, LG_eta: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, **extra_data: ~typing.Any)[source]
Bases:
BaseModelMicrostrain broadening parameters.
Schema 0.25 Change: Renamed strain to isotropic_strain to prepare for future uniaxial/generalized strain broadening support. Added model field to specify strain model (isotropic, uniaxial, generalized).
Models: - isotropic: Single strain parameter (currently implemented) - uniaxial: Equatorial and axial strains with hkl direction (future) - generalized: Stephens model - symmetry-dependent parameters based on Laue class (future)
Note: The generalized Stephens model requires complex parameterization that depends on the crystal symmetry (Laue class). Implementation deferred to Phase 2.
- model: Literal['isotropic', 'uniaxial', 'generalized']
- isotropic_strain: RefinementParameter | None
- uniaxial_equatorial: RefinementParameter | None
- uniaxial_axial: RefinementParameter | None
- stephens_parameters: dict[str, RefinementParameter] | None
- LG_eta: RefinementParameter | None
- class powderline.schema.PeakBroadening(*, size_broadening: SizeBroadening | None = None, strain_broadening: StrainBroadening | None = None, **extra_data: Any)[source]
Bases:
BaseModelPhase-specific peak broadening from size and strain.
Schema 0.25 Change: Model field moved to individual size_broadening and strain_broadening classes to allow independent model selection.
- size_broadening: SizeBroadening | None
- strain_broadening: StrainBroadening | None
- class powderline.schema.PhaseParameterization(*, scale: ~typing.Annotated[tuple[float | None, bool | None, float | None, float | None], ~pydantic.functional_serializers.PlainSerializer(func=~powderline.schema.<lambda>, return_type=list, when_used=json)] | None = None, unit_cell: ~powderline.schema.UnitCellParameters | None = None, atoms: dict[str, ~powderline.schema.AtomParameters] | None = None, peak_broadening: ~powderline.schema.PeakBroadening | None = None, **extra_data: ~typing.Any)[source]
Bases:
BaseModelPhase-specific refinement parameters.
- scale: RefinementParameter | None
- unit_cell: UnitCellParameters | None
- atoms: dict[str, AtomParameters] | None
- peak_broadening: PeakBroadening | None
- class powderline.schema.AtomStructure(*, element: str, x: float, y: float, z: float, occupancy: float = 1.0, Multiplicity: int | None = None, ADP: str, Uiso: float | None = None, Uaniso: dict[str, float | None] | None = None, **extra_data: Any)[source]
Bases:
BaseModelAtomic structure definition.
- class powderline.schema.UnitCellStructure(*, a: float, b: float, c: float, alpha: float, beta: float, gamma: float, volume: float | None = None, **extra_data: Any)[source]
Bases:
BaseModelUnit cell structure (actual values, not refinement parameters).
- class powderline.schema.PhaseStructure(*, phase_name: str, space_group: str, unit_cell: UnitCellStructure, atoms: dict[str, AtomStructure], **extra_data: Any)[source]
Bases:
BaseModelPhase structure definition.
- unit_cell: UnitCellStructure
- atoms: dict[str, AtomStructure]
- class powderline.schema.PhaseModel(*, structure: PhaseStructure, parameterization: PhaseParameterization | None = None, **extra_data: Any)[source]
Bases:
BaseModelComplete phase definition.
- structure: PhaseStructure
- parameterization: PhaseParameterization | None
- class powderline.schema.XRDDataModel(*, tth: list[float], Itth: list[float], Itth_weights: list[float], filename: str | None = None, **extra_data: Any)[source]
Bases:
BaseModelXRD data arrays.
- validate_arrays_wellformed()[source]
Reject ill-formed XRD data. PowderLine never repairs data — it rejects it.
Transforming raw data (unit conversion, weight derivation, handling background-subtracted negatives) is the job of the reader/parser that builds this block, not PowderLine. Here we only enforce that what arrives is usable:
arrays must be non-empty;
every tth / Itth / Itth_weights value must be finite (no NaN or inf) — this catches, e.g., a weight computed as 1/esd**2 with esd == 0 (inf);
tth must be strictly increasing (a powder pattern is monotonic in 2-theta);
weights must be >= 0 (a 0 weight legitimately excludes a point; a negative weight is nonsensical) and at least one weight must be > 0 (all-zero = nothing to fit).
A negative intensity is explicitly allowed: background-subtracted data legitimately dips below zero, so Itth is checked for finiteness only, not sign.
- class powderline.schema.PayloadModel(*, xrd_data: XRDDataModel, instrument: InstrumentModel | None = None, phases: dict[str, PhaseModel] | None = None, asset_path: str | None = None, fit_range: list[float | None] | None = None, background: BackgroundModel | None = None, single_peaks: SinglePeaks | None = None, refinement_controls: RefinementControls, **extra_data: Any)[source]
Bases:
BaseModelRefinement data payload containing all refinement parameters.
Payload structure: The payload contains recipe-specific refinement data, separated from top-level metadata (schema_name, schema_version). This allows distinct validation rules for different refinement types (Rietveld vs SPF) while maintaining a consistent outer structure.
Type Preservation: Refinement parameters use [value, refine_flag, min, max] format where refine_flag must remain boolean. Always export with model_dump(mode=’json’) to preserve types.
Validation rules: - GSASII_Rietveld: Requires phases and instrument - GSASII_SPF: Requires single_peaks, forbids phases
- xrd_data: XRDDataModel
- instrument: InstrumentModel | None
- phases: dict[str, PhaseModel] | None
- background: BackgroundModel | None
- single_peaks: SinglePeaks | None
- refinement_controls: RefinementControls
- class powderline.schema.RecipeModel(*, schema_name: Literal['GSASII_Rietveld', 'GSASII_SPF'], schema_version: str, payload: PayloadModel, **extra_data: Any)[source]
Bases:
BaseModelTop-level refinement recipe model for schema 0.26.
Architecture: Two-tier structure (since schema 0.25) with schema metadata and payload:
{ "schema_name": "GSASII_Rietveld", "schema_version": "0.26.0", "payload": { "xrd_data": {...}, "phases": {...}, ... } }
Schema Types:
GSASII_Rietveld: Full Rietveld refinement (requires phases + instrument)GSASII_SPF: Single peak fitting only (requires single_peaks, forbids phases)
Validation Rules:
GSASII_Rietveld:
payload.phasesmust be present,payload.instrumentrequiredGSASII_SPF:
payload.single_peaksmust be present,payload.phasesmust be None
Breaking Changes from 0.24:
Removed multi-strategy refinement system (strategy, spf_first, iterative_cycles, etc.)
Removed sample_name, recipe_description, software_package from payload
Added schema_name for explicit workflow type declaration
Payload structure replaces flat top-level fields
Migration from 0.24 to 0.25:
// Old (0.24): { "schema_version": "0.24", "sample_name": "LaB6", "xrd_data": {...}, "phases": {...}, "refinement_controls": { "strategy": "structural_only", "refinement_cycles": 5 } } // New (0.25): { "schema_name": "GSASII_Rietveld", "schema_version": "0.26.0", "payload": { "xrd_data": {...}, "phases": {...}, "refinement_controls": { "refinement_cycles": 5 } } }
- schema_name: Literal['GSASII_Rietveld', 'GSASII_SPF']
- payload: PayloadModel
Kicker Module
Main refinement workflow and parameter setting functions.
Key Functions
Template and Validation
- powderline.kicker.is_template_file(recipe_dict: dict, input_path: Path) tuple[bool, str | None][source]
Detect if the recipe file is a template that shouldn’t be run directly.
Uses two-level detection strategy: 1. Path contains “template” (case-insensitive) 2. Missing required fields based on schema_name (for GSASII_Rietveld or GSASII_SPF)
- Parameters:
recipe_dict – Recipe dictionary loaded from JSON
input_path – Path to the JSON file
- Returns:
A 2-tuple
(is_template, reason).is_templateis True if this appears to be a template, andreasonexplains why it was detected as a template. If not a template, returns(False, None).- Return type:
Examples
>>> is_template_file({}, Path("example_template/input.json")) (True, "filename or path contains 'template'")
>>> is_template_file({"schema_name": "GSASII_Rietveld", "payload": {"xrd_data": {...}}}, Path("example_LaB6/input.json")) (False, None)
Output Generation
Functions for exporting refinement results with uncertainty quantification.
- powderline.kicker.export_refined_parameters_csv(param_dict: Dict[str, Dict[str, Any]], output_file: Path, proj: Any = None, include_category: bool = True) DataFrame | None[source]
Export refined parameters to CSV file and return the DataFrame.
- Parameters:
param_dict – Dictionary from extract_refined_params_* functions
output_file – Path to output CSV file
proj – GSAS-II project object (optional, needed for phase/atom names)
include_category – If True, add ‘category’ and ‘descriptive_name’ columns (default: True)
- Returns:
DataFrame with the exported parameters, or None if param_dict is empty.
- Output CSV / DataFrame columns:
parameter_name: GSAS-II internal parameter name
descriptive_name: Human-readable parameter description (if include_category=True)
phase_name: Name of associated phase (None if not phase-specific)
phase_idx: Index of associated phase (None if not phase-specific)
atom_name: Label of associated atom (None if not atom-specific)
atom_idx: Index of associated atom (None if not atom-specific)
value: Refined value
esd: Estimated standard deviation (None for fixed parameters)
category: Parameter category (instrument, background, cell, etc.) if include_category=True
- powderline.kicker.calculate_cell_esds_from_A_matrix(phase_idx: int, proj: Any, phase_name: str) List[float | None][source]
Calculate unit cell parameter ESDs using GSAS-II’s reciprocal metric tensor conversion.
GSAS-II refines reciprocal metric tensor components (A-matrix: A11, A22, A33, A12, A13, A23) and this function converts those ESDs to direct lattice parameter ESDs (a, b, c, α, β, γ).
- Parameters:
phase_idx – Phase index (0-based) for parameter naming (e.g., “0::A0”)
proj – GSAS-II project object after refinement
phase_name – Name of the phase
- Returns:
The 7 ESDs, in order
[esd_a, esd_b, esd_c, esd_alpha, esd_beta, esd_gamma, esd_volume].- Return type:
- Raises:
RuntimeError – If covariance data is unavailable or the ESD calculation fails.
Note
The A-matrix parameters (A0-A5) in GSAS-II correspond to: A0=A11, A1=A22, A2=A33, A3=A12, A4=A13, A5=A23 (reciprocal metric tensor) NOT direct cell parameters a, b, c, α, β, γ.
- powderline.kicker.extract_refined_params_from_project(proj: Any, verbose: bool = False) Dict[str, Dict[str, Any]][source]
Extract all refined parameters with their values and ESDs from proj.data.
Uses the covariance data stored in proj.data[‘Covariance’][‘data’] after refinement. This includes both independent and dependent parameters (via ComputeDepESD).
- Parameters:
proj – GSAS-II project object after refinement
verbose – If True, print progress messages.
- Returns:
Mapping of parameter names to
{"value": float, "esd": float}. Returns an empty dict if no covariance data is available.- Return type:
- Raises:
RuntimeError – If ComputeDepESD fails (dependent parameter ESDs cannot be calculated).
Example
>>> params = extract_refined_params_from_project(proj) >>> params[":0:U"] {"value": 47.406, "esd": 8.314}
Note
These helpers document the GSAS-II engine’s extraction path. ESDs (estimated
standard deviations) are read from GSAS-II’s covariance matrix
(proj.data['Covariance']). Unit cell ESDs require conversion from the reciprocal
metric tensor (A-matrix) to direct lattice parameters via calculate_cell_esds_from_A_matrix().
Post-Refinement Extraction Helpers (Private)
The four private _extract_* helpers encapsulate the post-refinement data
extraction and file-writing logic. They are not part of the public API but are
documented here for maintainers.
- powderline.kicker._extract_fit_profile(hist: Any, output_dir: Path) dict[source]
Extract fit profile arrays from histogram and save fit_profile.txt.
- Parameters:
hist – GSAS-II histogram object after refinement.
output_dir – Directory to write
fit_profile.txt.
- Returns:
Column-oriented data (JSON-serializable) with keys
two_theta,y_obs,y_weights,y_calc,y_diff,y_bkg,q_values,d_spacings.- Return type:
- powderline.kicker._extract_spf_peak_report(proj: Any, hist: Any, recipe: RecipeModel, output_dir: Path, verbose: bool) tuple[dict, dict][source]
Extract single peak fitting results and save report files.
Called only for
GSASII_SPFruns whererecipe.payload.single_peaksis set. Returns two column-oriented dicts (JSON-serializable) that are normalised to DataFrames byrun().Also writes: -
single_peaks_report.txt— per-peak widths and convergence status -peak_convergence_diagnostics.txt— only when peaks have issues- Parameters:
proj – GSAS-II project object after refinement.
hist – GSAS-II histogram object.
recipe – Validated RecipeModel.
output_dir – Directory to write report files.
verbose – If True, print convergence warnings to stdout.
- Returns:
(spf_peaks_data, spf_diagnostics_data)where each is a column-oriented dict, or({}, {})when single peaks are not used.
- powderline.kicker._extract_phase_reports(proj: Any, hist: Any, recipe: RecipeModel, param_dict: dict, output_dir: Path) tuple[dict, dict][source]
Extract unit cell and peak list reports for all phases.
Writes
{phase}_unit_cell_report.csvand{phase}_peak_list_report.csvfor each phase.- Parameters:
proj – GSAS-II project object after refinement.
hist – GSAS-II histogram object.
recipe – Validated RecipeModel (used to check if phases exist).
param_dict – Refined parameter dict from
extract_refined_params_from_project()(needed for cell ESDs).output_dir – Directory to write CSV files.
- Returns:
(unit_cell_data, peak_list_data)— each is a{phase_name: list-of-records}dict (JSON-serializable).
- powderline.kicker._extract_refined_parameters(param_dict: dict, output_dir: Path, proj: Any, verbose: bool) list[source]
Export refined parameters to CSV and return as list-of-records.
- Parameters:
param_dict – From
extract_refined_params_from_project().output_dir – Directory to write
refined_parameters.csv.proj – GSAS-II project object (for phase/atom name mappings).
verbose – If True, print export status to stdout.
- Returns:
List of dicts (records) with the 9-column schema. Returns
[]whenparam_dictis empty (simulation mode, SPF, etc.).
Background Functions
- powderline.kicker.set_chebyshev_background(proj: Any, hist: Any, chebyshev_dict: dict, print_info: bool = False) None[source]
Set the Chebyshev background for a given histogram.
Chebyshev polynomials provide smooth curved backgrounds. Coefficients start at 0th order (constant term) and increase: [c0, c1, c2, …] represents c0 + c1*T1(x) + c2*T2(x) + … where Tn are Chebyshev polynomials.
The function manipulates proj.data[hist.name][‘Background’][0] which has structure: [background_type, refine_flag, num_coefficients, c0, c1, c2, …]
- Parameters:
proj – GSAS-II project object containing the histogram
hist – Histogram object to set the background for
chebyshev_dict – Dictionary containing Chebyshev background parameters: - num_coefficients (int): Number of Chebyshev coefficients - coefficients (list[float]): Coefficient values [c0, c1, c2, …] - refine_flag (bool): Whether to refine background during fitting
print_info – If True, print background configuration to stdout
- Returns:
None
- Raises:
ValueError – If number of coefficients doesn’t match list length or required background entries are missing
Examples
>>> chebyshev_dict = { ... 'num_coefficients': 3, ... 'coefficients': [100.0, -50.0, 10.0], ... 'refine_flag': True ... } >>> set_chebyshev_background(proj, hist, chebyshev_dict)
- powderline.kicker.set_single_peak_background(proj: Any, hist: Any, bkg_single_peaks_dict: dict, print_info: bool = False) None[source]
Set single peak background for histogram using pseudo-Voigt profiles.
Single peaks are useful for modeling known impurity peaks or other non-background features that shouldn’t be included in the main phase refinement. Each peak is described by a pseudo-Voigt profile (weighted sum of Gaussian and Lorentzian).
Peak profile: I(2θ) = intensity * [η*L(2θ) + (1-η)*G(2θ)] where: - G(2θ) is Gaussian with width sigma - L(2θ) is Lorentzian with width gamma - η (eta) is mixing parameter (0=pure Gaussian, 1=pure Lorentzian)
- Parameters:
proj – GSAS-II project object
hist – Histogram object to set single peaks for
bkg_single_peaks_dict – Dictionary with keys: - positions: List of [[2θ, refine, min, max], …] for peak positions - intensities: List of [[I, refine, min, max], …] for peak heights - pv_gaussian_sigma: List of [[σ, refine, min, max], …] for Gaussian widths - pv_lorentzian_gamma: List of [[γ, refine, min, max], …] for Lorentzian widths All lists must have same length (number of peaks)
print_info – If True, print peak configuration to stdout
- Returns:
None
- Raises:
ValueError – If parameter lists have inconsistent lengths
Examples
>>> # Two single peaks at 2θ=35.5° and 42.0° >>> single_peaks = { ... 'positions': [[35.5, False, None, None], [42.0, False, None, None]], ... 'intensities': [[50.0, True, None, None], [30.0, True, None, None]], ... 'pv_gaussian_sigma': [[0.1, False, None, None], [0.1, False, None, None]], ... 'pv_lorentzian_gamma': [[0.05, False, None, None], [0.05, False, None, None]] ... } >>> set_single_peak_background(proj, hist, single_peaks)
Fit Range
Types
Refinement Parameter Format
Throughout the API, parameters use the format:
[value, refine_flag, min, max]
Where:
value(float): Current parameter valuerefine_flag(bool): True to refine, False to hold fixedmin(float | None): Minimum bound (placeholder, not enforced yet)max(float | None): Maximum bound (placeholder, not enforced yet)
Example:
"wavelength": [0.45236, false, null, null] # Fixed at 0.45236 Å
"scale": [1.0, true, null, null] # Refined starting from 1.0
Phase vs Histogram Parameters
Phase parameters: Belong to crystal structure (unit cell, atoms)
Histogram parameters: Belong to measurement (scale, broadening, background)
In multi-phase refinements, phase parameters are phase-specific, while histogram parameters are shared across all phases (except scale factors, which are phase-histogram pairs). Multi-phase refinement is fully supported.