Repository navigation
Re/05 topas schema - #6
Merged
Merged
Conversation
src/powderline/topas/ -> src/powderline/gateways/topas/, verbatim (git rename, no content change beyond the module path). The entry point (powderline.gateways:topas), the topas-kicker pixi task and every src/tests import use the new path; no powderline.topas shim (A136). Prose docs citing the old path are left for re/10. An existing checkout needs `pixi reinstall powderline` so the entry-point metadata points at the new module. Suite: 2781 passed, 4 skipped (baseline 139e72d identical except six parametrized IDs that contain the module path). Assisted-by: claude-code:claude-opus-5-5
The count of independently refined parameters (one per refined symmetry tie group, A94) now lives in core and accepts both parameter shapes, so the TOPAS and easydiffraction gateways report it the same way as gsasii. gateways.gsasii.fit_report re-exports it; behaviour unchanged. Assisted-by: claude-code:claude-opus-5-5
Engine schema 1.0.0 over the core phase block (Phase[BoundedRefinableParameter]): native TOPAS terms and units, no defaults (A142); required engine_version, TOPAS ==6 (A143, A144); instrument radiation (lh required, lg only with lh, C30), geometry radii as the axial model needs them (C26), corrections keyed by macro (A140), peak types TCHZ/PV/PVII with exact parameter names (A141); background Chebyshev / One_on_X / peaks; isotropic size and strain (CS_L/CS_G, Strain_L/Strain_G); SPF single peaks. Rules: a refined start outside TOPAS's fixed default limit on a side the recipe leaves null is an error (A138, C20); widths >= 0 (C24); wavelength, size, scale > 0 (A126); peaks inside the fit window; LP_Factor_Synchrotron never refines pp and mono together (A147); simulation (iters 0) refines nothing. Space groups: 541 canonical settings TOPAS 6 reads as themselves, 23 refused (C16), committed as tests/data/topas_space_groups.txt. TopasPhase registered in the phase canary (A122). 62 schema tests. Assisted-by: claude-code:claude-opus-5-5
…e/05) - native_writer: INP from the validated model only; one TOPAS parameter per symmetry tie group with exact equations (C25); index-based names (D9); macro parameters as prm with stated or TOPAS.INC limits per side (A138), passed to the macros by name; geometry corrections at xdd level, LP and the peak type per str (A148); outputs: results CSV (incl. number_independent_parameters, derived LVol-IB/e0/volume), profile, phase_out reflection lists. - native_run: success judged from fresh output files, not the exit code (C13); standard statistics over exactly the stated window (A131); divergence and missing outputs are EngineExecutionError (A130); warnings topas_parameters_not_varied (A128, C22), topas_parameter_at_limit (Q-L4, C21), topas_phase_contributes_nothing (Q-Z1, C23), topas_adp_converted (D8); background column computed from the refined terms (C17, C18, Q-B3); SPF columns per D13. - gateway: topas.* recipes validate and run natively; a run that executes TOPAS needs a declared TOPAS version equal to the recipe's (A145); EngineVersionError takes an explicit message. The 0.26.0 path is unchanged (A146). - Six hand-written native fixtures with their derivations (A137); 30 native tests; the import-block test covers the native modules. Suite: 2875 passed, 4 skipped. Assisted-by: claude-code:claude-opus-5-5 Assisted-by: claude-code:claude-sonnet-5-5
- build_result matched TOPAS's profile X to the recipe's 2theta with searchsorted, so an X that TOPAS printed rounded above the recipe value (10 significant digits) missed its own point. Match the nearest point, for Ycalc and for the profile's weights. - The cell volume (category cell_volume) is not refined, so the out block skipped it and the unit-cell report had no volume. Export it like the derived values. - The fixtures README said lab6_spf has 38 peaks; it has 36. Assisted-by: claude-code:claude-opus-5-5
TOPAS fits the data points nearest start_X/finish_X (EB-59) and GSAS-II one point past a max between points (EB-54), so the same recipe range fitted different points per engine. Core fit_limits_on_data moves each stated end onto the first/last weighted data point inside the window; the TOPAS writer writes those as start_X/finish_X with the .xye's digits. TOPAS 6 pack 3: r_wp then equals core Rwp in all six fixtures. A window with no weighted point is now a validation error. Assisted-by: claude-code:claude-opus-5-5
run_refinement's fit-range read hands GSAS-II the first/last weighted data points inside fit_range (core fit_limits_on_data). GSAS-II's slice x[searchsorted(lo) : searchsorted(hi) + 1] is then exactly min <= 2theta <= max (EB-54): LaB6 n_obs 3767, GSAS-II Rwp = core Rwp. set_fit_range_hist and the call order are unchanged; the 0.26.0 path (legacy copy) is untouched. Code hash refreshed. Assisted-by: claude-code:claude-opus-5-5
TOPAS 6 cannot output the background (Get(bkg) = 0, C17; phase_out_X and Get(phase_ycalc) are TOPAS 7 only, C34), and the computed y_bkg misses TOPAS's convolutions of background peaks. render_background writes a second INP: the main run's .xye, window, corrections, emission and background with every parameter fixed at its refined value, no str phases or SPF peaks, iters 0; its Ycalc is the background. Runner integration follows the TOPAS 6 check (probe pack 5). Assisted-by: claude-code:claude-opus-5-5
After the fit, run_native runs the background-only INP (render_background: refined values fixed, no phases, iters 0) and build_result reads its Ycalc as y_bkg, so the column carries every convolution TOPAS applies. Without that profile the column is empty with a topas_background_not_calculated warning; a stale profile is removed first. The computed background (Chebyshev + analytic peak shapes, which missed the convolutions) is gone. TOPAS 6 pack 5: the background run matches the analytic Chebyshev to 1e-7 where no peaks or convolutions apply, and Ycalc >= background everywhere. Assisted-by: claude-code:claude-opus-5-5
TOPAS-64 Version 6 outputs (devkit packs 3 and 5): the writer's INP, the results CSV, profile, reflection lists and the background run. The tests check the writer still emits those INPs (main and background) and that the result built from TOPAS's files has core Rwp = TOPAS r_wp (A149), 3767 points, requested = varied, y_bkg = the background run, TOPAS's refined values and, for DRX_33, the cells. Assisted-by: claude-code:claude-opus-5-5
…sasii, core) Assisted-by: claude-code:claude-opus-5-5
…gence (A130, A154) The native runner read the results CSV with the 0.26.0 round-trip parser, which drops a row whose value is not finite, so a NaN refined value gave a success with the parameter missing; a NaN in a reflection list passed; MSVC spellings in the profile (1.#QNAN, -1.#IND, -nan(ind)) raised a raw ValueError. native_run now reads the results CSV, the profile and the reflection lists itself: a non-finite value (Python or MSVC spelling) raises "the refinement diverged"; a non-finite ESD stays empty (undetermined ESDs of degenerate parameters are normal); an unreadable token is an EngineExecutionError. The 0.26.0 parser is unchanged (A146). re/05 PR review S1. Assisted-by: claude-code:claude-opus-5-5
…stamps (A154) Success was judged by modification time (written within a second of the run's start). On a network share whose clock is behind the PC's a successful run read as failed; a clock ahead of it, or a failed re-run soon after a successful one, let an earlier run's files pass for this run's. The runner now removes the expected results, profile and reflection lists before it starts TOPAS and checks only that they exist (the background profile was already handled so). re/05 PR review S3. Assisted-by: claude-code:claude-opus-5-5
- topas_parameter_at_limit gives the limit in recipe units (a Uiso stopped at beq 20 reads "max limit 0.253303 (..., TOPAS value 20)", not 20). - A start-outside-limit message prints the limit to 6 digits only when that value is itself allowed, else exactly (the Uiso maximum printed as 0.253303 failed when written back). - The writer records the fixed part of a Min/Max limit in either argument, so CS's ceiling 10000 nm is a known limit for limit-hit warnings. - test_spf_runs_with_standard_statistics asserts core Rwp = GSAS-II's Rwp (A149/R17 also governs gsasii.spf). re/05 PR review N1, N2, N3, N7. Assisted-by: claude-code:claude-opus-5-5
…154; ledger R17 note) fit_limits_on_data left an open end (and a recipe without fit_range) as None. GSAS-II then kept its default limit, the first/last data point even when its weight is 0, counted those points in Nobs and mapped its Chebyshev basis over them, while the TOPAS .xye has no zero-weight points, so TOPAS mapped from the first weighted point: one recipe, two background bases. An open end now becomes the first or last weighted data point, so every engine gets explicit limits on the same points. Unchanged wherever the data's edge points are weighted (every committed example and golden). GSAS-II: the R17 line in run_refinement is unchanged; the values it receives change as above (ledger R17 annotation, signed by the maintainer with the review answers). TOPAS: start_X/finish_X are always written. re/05 PR review S2. Assisted-by: claude-code:claude-opus-5-5
- Fit window (gsasii, topas): the first/last weighted points; open ends the data's first/last weighted point. - topas: divergence = any non-finite number TOPAS writes; outputs removed before the run; INP numbers to 10 significant digits. - topas: why la, lo, lh, lg and the capillary diameter must be > 0; fixed peak-type terms are not checked (a negative width stops TOPAS 6 for convolutions, C24; unverified for the peak types): documented only. - Writer: the kept del / omitted val_on_continue noted. re/05 PR review N5, N6, N8, Q2, Q6. Assisted-by: claude-code:claude-opus-5-5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
re/05: native
topas.*schemas, writer and runner (TOPAS 6)Merges
re/05-topas-schemaintorefactor/multi-engine(base139e72d, re/04merged; tip
240147e, 16 commits: 11 for the branch, 5 from its review).Native TOPAS recipes (
topas.rietveld,topas.spf) can now be validated,written to an INP, run on TOPAS, and turned into the same standard result dict
and report files as the GSAS-II gateway. The branch declares TOPAS 6 only
(A143): the only TOPAS available is TOPAS-64 Version 6. Everything that needs
TOPAS was checked on it through five probe packs (devkit
probes/re05_topas/pack{1..5}).The 0.26.0
GSASII_*→ TOPAS path is unchanged; it keeps its>=7,<8gateand its v7.25 references until re/07 (A146).
What changes
Package move (A136).
powderline.topasis nowpowderline.gateways.topas, with no shim.topas-kickerentry point and pixi task follow.pixi reinstall powderline.Native schemas (
gateways/topas/schema.py; draft rev 3 signed as a set,A147). The recipe uses TOPAS's own keywords, macro parameters and units (A142),
and PowderLine fills in no defaults: a block left out is not modelled.
engine_versionis a required field; only"6"is supported (A144). A runneeds the installed version declared (
topas_versionor config) and equalto it (A145).
min/maxreplaces TOPAS's default limit on that side(A138). A refined start value outside a default limit on an open side is a
validation error, because TOPAS would move it silently.
radiation:lamwithlhrequired;lgonly together withlh.geometry:Rp/Rs.corrections, keyed by macro:Zero_Error,LP_Factor/LP_Factor_Synchrotron, Simple/Full axial, capillary (parallel ordivergent beam).
broadening: TCHZ / PV / PVII peak types.One_on_X, and pv/spv/spvii background peaks.TopasPhase:scale;CS_L/CS_GandStrain_L/Strain_G, reported with TOPAS's LVol-IBand e0;
Uisowritten asbeq,Uanisoasu_ij.operator output.
Gaussian/Lorentzian width.
Writer and runner (
native_writer.py,native_run.py, gateway routing).files the INP asks for. They are removed before the run, so an earlier
run's files can never pass; timestamps are not used.
profile or a reflection list is a divergence error, in Python or MSVC
spelling (
nan,1.#QNAN,-nan(ind)). An undetermined ESD is leftempty.
topas_adp_converted;topas_parameter_at_limit, which names the stated bound or TOPAS's default;topas_parameters_not_varied;topas_phase_contributes_nothing(informative only: a phase absent fromthe sample legitimately contributes nothing);
topas_background_not_calculated.Fit window on data points, every engine (A149, A150).
Core
fit_limits_on_datahands each engine the first and last weighted datapoints inside
fit_rangeas its limits. An open end, or nofit_range,becomes the data's first or last weighted point, so zero-weight edge points
never widen an engine's window. The data themselves are not cut.
The two engines round a limit that falls between data points differently:
With limits on data points, both fit exactly min ≤ 2θ ≤ max, the same points
core scores.
TOPAS's own
r_wpnow equals core Rwp in all six fixtures. GSAS-II's Rwpequals core Rwp on LaB6, for
gsasii.rietveldandgsasii.spf. With theopen ends on weighted points, every engine's Chebyshev basis spans the same
first and last points.
The GSAS-II side is frozen-code ledger row R17 (signed, and annotated
for the open ends). It changes only the fit-range read in
executors.run_refinement; the 0.26.0 path is untouched.A
fit_rangewith no positively weighted point is now a validation error.Background column from a second TOPAS run (A152).
Get(bkg)is 0, andphase_out_XisTOPAS 7 only.
no phases,
iters 0. Its Ycalc becomesy_bkg, with every convolutionTOPAS applies.
Goldens.
tests/data/topas/native/golden/holds the TOPAS 6 outputs for the sixhand-written fixtures (A137).
tests/test_topas_native_golden.pychecks that the writer still emitsexactly the INPs TOPAS ran, and that the result built from TOPAS's files is
right.
Docs:
docs/SCHEMA_HISTORY.mdgains the topas 1.0.0 entry and fit-windownotes for core and gsasii.
Commits
5cde3e7— move the TOPAS package intogateways/topas(A136).e448e16—parameters_requestedmoves intoschema_core, re-exportedfrom the gsasii
fit_report(D12).a357bda— the native schemas.68f7926— native writer, runner and gateway routing; six fixtures.5062d3c— two bugs found by the pack 2 runs:720d883— A149: core rule plus the TOPAS writer.4347ae0— A149 for GSAS-II (ledger R17, signed; code hash refreshed).c677b0d— the background-run INP (A152).8cd5c86— runner integration of the background run; the analyticbackground code is removed.
450c803— TOPAS 6 goldens and roundtrip tests.ff17579— SCHEMA_HISTORY.From the PR review (record: devkit
tasks/re05-pr-review-record.md; decisionsA154–A157):
1a35898— TOPAS's files read strictly: any non-finite number is adivergence (S1).
e8b2bf2— outputs removed before the run; no timestamps (S3).06cb9a4— nits: limit messages in recipe units and with a limit thatvalidates; CS's 10000 nm ceiling known for limit-hit warnings; SPF window
test.
b5342c8— open fit-range ends on the first/last weighted point (S2;ledger R17 annotation).
240147e— SCHEMA_HISTORY and docstrings.Most of the +128k lines are test data: six fixtures carrying the full 4096-point
patterns, the space-group list, and the goldens.
src/changes are +2262/−123lines.
Verification
Default suite 2954 passed, 9 skipped. Five of the skips are the DRX_33-only
golden test on the other fixtures.
Every
139e72dbaseline ID passes, except the six whose IDs the package moverenamed; every
ff17579ID passes (one test is now parametrized in two)(devkit
tasks/re05-prreview-240147e.ids).easydiff suite 55 passed, with IDs identical to the baseline.
Undefined-name probe 0; no CRLF;
examples/untouched; code hash current.TOPAS 6 evidence (maintainer's machine):
r_wp= core Rwp over 3767 points;Chebyshev is modelled;
DRX_33 cubic a, all fits over the same 3767 points:
The two TOPAS versions agree. The GSAS-II difference comes from the engines'
different profile models; the 0.26.0 paths show the same difference.
Behaviour changes (devkit
tasks/deliberate-changes.mdrows 22–24)powderline.topas.*imports break, since the package movedwithout a shim.
between data points,
Nobsdrops by one and refined values move slightly(LaB6: scale 5e-6 relative, U 7e-4). Without a
fit_range, zero-weightpoints at the data's edges are no longer inside GSAS-II's window.
Known, documented, not blocking
the last fitted point of a background or SPF peak (TOPAS
xo_Ispeaks).excludealso drops the in-window neighbour.y_bkgshows the same value, so it stays consistent with Ycalc.X < 0 with Y = 0) validates; TOPAS 6 stops on a negative convolution width,
but whether it does for the peak types is unverified. Documented for now; if
it does, any negative value becomes a validation error.
explicitly (A143).
powderline.run(..., engine="topas"), not only the INPs it writes) is checked by the G4 smoke.engine=, atopas.*recipe needsengine="topas".Decision log: master plan §3, A134–A157. TOPAS 6 findings: devkit
tasks/re05-topas6-compat.md(C1–C36). Engine behaviour: EB-55..69. PR review:devkit
tasks/re05-pr-review-record.md. Execution log entries of 2026-10-09.Assisted-by: claude-code:claude-opus-5-5
Assisted-by: claude-code:claude-sonnet-5-5