Skip to content

fix(#293) add ConstraintSet.with_constraint_values and document fixed-axis overrides#296

Merged
prjemian merged 1 commit into
mainfrom
293-document-and-ease-fixed-axis-overrides
Jun 9, 2026
Merged

fix(#293) add ConstraintSet.with_constraint_values and document fixed-axis overrides#296
prjemian merged 1 commit into
mainfrom
293-document-and-ease-fixed-axis-overrides

Conversation

@prjemian

@prjemian prjemian commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Issue #293 asked how to provide a non-default value for a fixed-axis
constraint, and whether it was even possible. The answer was yes — by
rebuilding the whole ConstraintSet — but the recipe was hard to
discover from the per-mode reference docs, and the rebuild was verbose
for any mode pinning more than one value (the psic B3 mode pins three,
the sixc zaxis modes pin three, etc.).

This PR delivers three coordinated changes on the single issue, per the
operator's standing preference for batched fixes.

Code

Adds ConstraintSet.with_constraint_values(**updates) — a functional
update method that returns a fresh ConstraintSet with the named
constraint values replaced. Constraint order, computed, extras
(with sentinel identity preserved), and cut_points all survive
unchanged. Receiver is not mutated.

# Single value
g.modes["fixed_chi_vertical"] = (
    g.modes["fixed_chi_vertical"].with_constraint_values(chi=45.0)
)

# Multiple values at once (psic B3)
g.modes["fixed_alpha_i_fixed_chi_fixed_phi"] = (
    g.modes["fixed_alpha_i_fixed_chi_fixed_phi"]
    .with_constraint_values(chi=15.0, phi=30.0, alpha_i=5.0)
)
  • Sample/detector/reference constraints are matched by their .name.
  • BisectConstraint / VirtualBisectConstraint are relational (no
    scalar value) and are intentionally invisible to the helper; any
    kwarg targeting one raises KeyError.
  • Unknown keys raise KeyError with a single message listing every
    unrecognised key and the available names (batched typo reporting).
  • Duplicate names within the receiver (a malformed ConstraintSet
    that the YAML loader does not produce) raise ValueError.

Tests

14 new tests in tests/test_mode.py: parametrized replacements
(sample / detector / reference, float and bool), multi-value, empty
kwargs (returns equal fresh instance), KeyError single+batched,
ValueError on duplicate name, BisectConstraint ignored both
solo and alongside settable constraints, round-trip via to_dict().

Docs

  • docs/source/howto/constraints.md — new 'Why constraint values
    are immutable' section, new 'Use with_constraint_values for a
    one-call override' subsection, new 'Rebuild the whole
    ConstraintSet' subsection with detector and reference worked
    examples.
  • docs/source/howto/modes.md — updates 'Fixed-angle modes' to
    lead with the new helper; new top-level 'Change a fixed-axis value' FAQ heading.
  • Every fixed_* mode entry in the per-geometry reference pages
    (psic, fourcv, fourch, fivec, sixc, kappa4cv, kappa4ch, kappa6c,
    zaxis, s2d2) gains a uniform 'Override at run time with
    g.modes[...].with_constraint_values(...)' cross-link sentence,
    making the answer discoverable from where users actually land.

CHANGES.md

### Added
- `ConstraintSet.with_constraint_values()` one-call value override. (#293)

### Changed
- Document how to override fixed-axis constraint values. (#293)

Incidental

The insert-license hook restored the SPDX header on
tests/test_regression_issue_292.py (it had landed in #292 without
the header). ruff-format also applied two line-wrap nits to the
same file. Both are pre-existing, non-functional changes carried in
this PR because they were on the working tree when pre-commit ran.

Verification on wow.xray.aps.anl.gov (Python 3.14.4, NumPy 2.4)

  • pytest: 2606 passed, 2 skipped, 3 deselected — 100.00 % coverage
  • pre-commit run --all-files: clean
  • make -C docs clean html: clean build, no warnings
  • Both AGENTS.md RST-leak grep patterns: clean
  • US-English spelling check on every changed file: clean

Contributed by: OpenCode (argo/claudeopus47)

…-axis overrides

Issue #293 asked how to provide a non-default value for a fixed-axis
constraint, and whether it was even possible.  The answer was yes —
by rebuilding the whole ConstraintSet — but the recipe was hard to
discover from the per-mode reference docs, and the rebuild was verbose
for any mode pinning more than one value (the psic B3 mode pins three,
the sixc zaxis modes pin three, etc.).

Add ConstraintSet.with_constraint_values(**updates) — a functional
update method that returns a new ConstraintSet with the named
constraint values replaced.  Constraint order, computed, extras
(with sentinel identity), and cut_points are all preserved.
Receiver is unchanged; the method always returns a fresh instance.

* Sample, detector, and reference constraints are matched by their
  .name attribute.
* BisectConstraint and VirtualBisectConstraint are relational (no
  scalar value) and are intentionally invisible to the helper; any
  kwarg targeting one raises KeyError.
* Unknown keys raise KeyError with a single message listing every
  unrecognised key and the available names.
* Duplicate names within the receiver (a malformed mode that the YAML
  loader does not produce) raise ValueError.

Document the helper, the rebuild-whole-ConstraintSet alternative, and
the rationale for the immutable-constraint design in
docs/source/howto/constraints.md.  Add a top-level
'Change a fixed-axis value' FAQ heading to docs/source/howto/modes.md.

Add a uniform 'Override at run time with g.modes[...]
.with_constraint_values(...)' cross-link sentence to every fixed_*
mode entry in the per-geometry reference pages (psic, fourcv, fourch,
fivec, sixc, kappa4cv, kappa4ch, kappa6c, zaxis, s2d2) so this answer
is discoverable from where users land.

Contributed by: OpenCode (argo/claudeopus47)
@prjemian prjemian added this to the v0.11.1 patches milestone Jun 9, 2026
@prjemian prjemian merged commit ece40b2 into main Jun 9, 2026
7 checks passed
@prjemian prjemian deleted the 293-document-and-ease-fixed-axis-overrides branch June 9, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

any mode with a fixed_AXIS

1 participant