From 4620fa8148baefb7e24e5201697594fd933e8463 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 00:55:48 +0200 Subject: [PATCH 01/55] Add space-group-database canonical-templates phase --- docs/dev/plans/space-group-database.md | 174 +++++++++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index fe2a4b93f..63e0a84c5 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -272,3 +272,177 @@ flagged rows visible for later International Tables verification. The data now ships as transparent, inspectable JSON instead of an opaque binary pickle. Existing projects load unchanged; structures in the previously-missing groups now get correct symmetry handling. + +--- + +## Follow-up phase: canonical Wyckoff `coords_xyz` templates + +_Added after #187 shipped — a second, standalone cycle of this ADR's +implementation. It is the **prerequisite** that +[`wyckoff-letter-detection`](../adrs/suggestions/wyckoff-letter-detection.md) +§10 / Decision 15 depends on and gates on at its P1.0, and it ships on +its **own PR** (separate from #187). When implementing this phase, treat +the `CT` checklist below as the active Phase 1 steps — the #187 Phase 1 +above is complete._ + +### Status (this phase) + +- [ ] Phase 1 — Implementation (data + tooling + docs) +- [ ] Phase 1 review gate +- [ ] Phase 2 — Verification (tests + checks) + +### Problem + +The bundled `space_groups.json.gz` stores cctbx **operator-form** +`coords_xyz` — e.g. R-3m (IT 166) `h` is `(1/2*x-1/2*y,-1/2*x+1/2*y,z)` — +for the coupled special positions (verified: 3826 templates; per the +wyckoff plan's Decision 15, 288 positions across 117 IT numbers). The +constraint helpers `_fract_constrained_flags()` (`crystallography.py:221`) +and `_apply_fract_constraints()` (`:250`), the Wyckoff orbit matcher, and +coordinate snapping all assume the **canonical ITA parametric form** +(`(x,-x,z)`). The operator-form spelling silently breaks the +constrained-axis flags, so a refined special-position coordinate drifts +off its symmetry site — the `ed-6` fit-3 → fit-4 regression. The +constraint **code** is correct; only the **data** spelling is wrong. + +### Decisions (this phase) + +1. **Re-parametrise every operator-form `coords_xyz` to canonical ITA + parametric form** — each component a signed single free variable plus + an optional rational constant; no numeric coefficient on a variable + and no coupled cross-variable term. The transform is deterministic and + **orbit-preserving**, verified by **exact symbolic equivalence** + (`sympy`) for each affected Wyckoff orbit: the canonical and + operator-form representative sets are proven to describe the same point + set as rational affine forms, not merely to agree at sampled parameters + (sampling may supplement but never replace the symbolic proof) — + review-1 [P1]. +2. **Apply it as a cctbx-free post-processing pass over the existing + bundled DB**, not a full cctbx regeneration. The transform parses the + existing `coords_xyz` strings and re-parametrises with `sympy` (already + a `crystallography.py` dependency), so it runs in this repo's + environment. The cctbx generator also gains the same pass + a + generation-time invariant for future rebuilds, but this PR's + `space_groups.json.gz` is produced by the post-processing transform. + _Rejected alternative — re-running the full cctbx generator — needs the + throwaway cctbx env and re-derives the whole table when only the + `coords_xyz` spelling is wrong._ +3. **No constraint-code change.** `_fract_constrained_flags()` / + `_apply_fract_constraints()` are correct as-is. +4. **No new runtime dependency.** `sympy` already backs + `crystallography.py`; `cctbx` stays generation-only and is not needed + for the transform. +5. **Guard both sides:** a generation-time invariant in the generator, a + `tools/check_packaged_db.py` assertion rejecting operator-form leakage + in the packaged wheel, and a unit data-invariant over loaded + `SPACE_GROUPS`. +6. **Record it in the ADR:** add the canonical-`coords_xyz` invariant as a + decision and update _Build Provenance_ with the new DB SHA-256 and the + transform's SHA-256. + +### Open questions (this phase) + +- If any affected position cannot be canonicalised automatically, fall + back to a maintainer-curated entry in the existing + `space_groups_overrides.yaml` channel and record it. Not expected. + +### Concrete files likely to change (this phase) + +- `src/easydiffraction/crystallography/space_groups.json.gz` — rewritten + with canonical `coords_xyz`; all other fields unchanged. +- `tmp/space-groups/helper-tools/canonicalize_coords.py` — **new**, local + ignored one-time transform (read DB → re-parametrise → verify orbit + equality → rewrite). +- `tmp/space-groups/helper-tools/generate_space_groups.py` — add the same + canonicalisation pass + generation-time invariant. +- `tools/check_packaged_db.py` — assert no packaged `coords_xyz` is + operator-form. +- `docs/dev/adrs/accepted/space-group-database.md` — canonical-form + invariant decision + updated _Build Provenance_. +- Phase 2 tests: + - `tests/unit/easydiffraction/crystallography/test_space_groups.py` + (or `_coverage.py`) — data invariant: no `SPACE_GROUPS` `coords_xyz` + is operator-form. + - `tests/unit/easydiffraction/crystallography/test_crystallography.py` + (or `_coverage.py`) — coupled-position constraint regression: for + R-3m `h` (`(x,-x,z)`), `_fract_constrained_flags()` marks `fract_y` + constrained and `_apply_fract_constraints()` slaves it to `-fract_x` + after a `fract_x` edit (existing tests cover only all-fixed / + all-free sites). + - `ed-6` functional/script regression: the special-position fit stays + on-site across fit-3 → fit-4. + +### Implementation steps — canonical-templates phase + +Per-step commit discipline as in Phase 1, **with the same deliberate +exception** that `tmp/space-groups/helper-tools/*` are local curation +tooling, not branch deliverables (review-1 [P1]). The local transform and +generator changes are therefore **not their own commits**: each tracked +commit stages only the tracked deliverable it produces, and the local +tools are recorded by SHA-256 in the ADR provenance (CT4). No step commits +only ignored files, and no empty commits. + +- [ ] **CT1 — Canonicalise the database (local transform → tracked + output).** Add the local, ignored + `tmp/space-groups/helper-tools/canonicalize_coords.py`: parse each + `coords_xyz` with `sympy`, detect operator form, re-parametrise to + canonical ITA form, and prove **exact symbolic orbit equivalence** + for every affected position (review-1 [P1]). Run it to rewrite + `src/easydiffraction/crystallography/space_groups.json.gz` (R-3m `h` + → `(x,-x,z)`; all other fields unchanged). The transform is local + tooling (recorded by SHA in CT4); **this commit stages only the + regenerated `space_groups.json.gz`**. Commit: + `Canonicalize space-group coords_xyz templates` +- [ ] **CT2 — Generator canonicalisation pass + invariant (local prep, + no commit).** Fold the same canonicalisation + a generation-time + invariant (rejecting operator-form leakage) into the local + `tmp/space-groups/helper-tools/generate_space_groups.py`, so a + future cctbx rebuild stays canonical. **Local curation tooling — not + committed** (deliberate exception); its updated SHA-256 is recorded + in CT4. No commit. +- [ ] **CT3 — Packaging assertion.** Extend the tracked + `tools/check_packaged_db.py` to assert no packaged `coords_xyz` + template is operator-form (catches future regression at the wheel + layer). Commit: `Assert canonical coords_xyz in packaged DB check` +- [ ] **CT4 — ADR invariant + provenance.** Add the canonical-`coords_xyz` + invariant as a decision in + `docs/dev/adrs/accepted/space-group-database.md`, and update its + _Build Provenance_ with the new `space_groups.json.gz` SHA-256, the + `canonicalize_coords.py` transform SHA-256, **and the updated + `generate_space_groups.py` SHA-256** plus the canonical-invariant + step in the rebuild path (review-1 [P2]). Commit: + `Record canonical coords_xyz invariant and provenance` +- [ ] **CT5 — Phase 1 review gate.** No code. Mark `[x]`, commit the + checklist update alone, hand off to review. Commit: + `Reach canonical-templates Phase 1 review gate` + +### Phase 2 — Verification (canonical-templates phase) + +Add the tests above, then run (zsh-safe capture): + +```bash +pixi run fix +pixi run test-structure-check > /tmp/easydiffraction-test-structure.log 2>&1; test_structure_exit_code=$?; tail -n 50 /tmp/easydiffraction-test-structure.log; exit $test_structure_exit_code +pixi run check > /tmp/easydiffraction-check.log 2>&1; check_exit_code=$?; tail -n 200 /tmp/easydiffraction-check.log; exit $check_exit_code +pixi run unit-tests > /tmp/easydiffraction-unit.log 2>&1; unit_tests_exit_code=$?; tail -n 100 /tmp/easydiffraction-unit.log; exit $unit_tests_exit_code +pixi run integration-tests > /tmp/easydiffraction-integration.log 2>&1; integration_tests_exit_code=$?; tail -n 100 /tmp/easydiffraction-integration.log; exit $integration_tests_exit_code +pixi run script-tests > /tmp/easydiffraction-script.log 2>&1; script_tests_exit_code=$?; tail -n 100 /tmp/easydiffraction-script.log; exit $script_tests_exit_code +``` + +Then the packaging regression from #187's Phase 2 (build the wheel + +`python tools/check_packaged_db.py dist/*.whl`), which now also exercises +the new operator-form assertion. + +### Suggested Pull Request — canonical-templates fix + +**Title:** Store space-group Wyckoff coordinates in canonical form + +**Description:** A refined atom on certain special positions (sites with +linked coordinates, like `(x, -x, z)`) could drift off its symmetry +position during a fit, because the bundled space-group table stored those +coordinate templates in an internal operator form the symmetry-constraint +code didn't recognise. This change rewrites every affected template into +the standard International Tables form so the constraints hold, adds +guards so the table can't silently regress, and fixes the related `ed-6` +tutorial refinement. It also unblocks automatic Wyckoff-position +detection, which builds on these canonical templates. From 74c410d4e2124d33e7b045e12b97415b1cf44393 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 01:05:14 +0200 Subject: [PATCH 02/55] Refine canonical-templates phase to re-source from cryspy --- docs/dev/plans/space-group-database.md | 116 ++++++++++++++----------- 1 file changed, 65 insertions(+), 51 deletions(-) diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index 63e0a84c5..94fbf5337 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -296,42 +296,50 @@ above is complete._ The bundled `space_groups.json.gz` stores cctbx **operator-form** `coords_xyz` — e.g. R-3m (IT 166) `h` is `(1/2*x-1/2*y,-1/2*x+1/2*y,z)` — for the coupled special positions (verified: 3826 templates; per the -wyckoff plan's Decision 15, 288 positions across 117 IT numbers). The -constraint helpers `_fract_constrained_flags()` (`crystallography.py:221`) -and `_apply_fract_constraints()` (`:250`), the Wyckoff orbit matcher, and -coordinate snapping all assume the **canonical ITA parametric form** -(`(x,-x,z)`). The operator-form spelling silently breaks the -constrained-axis flags, so a refined special-position coordinate drifts -off its symmetry site — the `ed-6` fit-3 → fit-4 regression. The -constraint **code** is correct; only the **data** spelling is wrong. +wyckoff plan's Decision 15, 288 positions across 117 IT numbers). +`_fract_constrained_flags()` (`crystallography.py:221`) decides which axis +is constrained purely by **which variable symbol is absent** from the +representative: canonical `(x,-x,z)` has `y` absent → `fract_y` constrained +→ slaved to `-x`; but operator-form `(1/2*x-1/2*y,…)` makes **both `x` and +`y` appear** → `fract_y` is wrongly "free" and the `y=-x` coupling is +lost, so a refined special-position coordinate drifts off its symmetry +site (the `ed-6` fit-3 → fit-4 regression). `_apply_fract_constraints()` +(`:250`) and `_parse_rotation_matrix()` (`:350`, which does +`int(coeff_str)`) share the same expectation. The constraint **code** is +correct; only the **data** spelling is wrong. **Root cause:** the +generator emitted cctbx operator-form `coords_xyz` for these positions +instead of cryspy's canonical form; the ADR's intended Wyckoff source, +cryspy's `wyckoff.dat`, already holds the canonical ITA form for them +(verified — R-3m gives `(x,x,1/2)`, `(x,-x,1/2)`, …). ### Decisions (this phase) -1. **Re-parametrise every operator-form `coords_xyz` to canonical ITA - parametric form** — each component a signed single free variable plus - an optional rational constant; no numeric coefficient on a variable - and no coupled cross-variable term. The transform is deterministic and - **orbit-preserving**, verified by **exact symbolic equivalence** - (`sympy`) for each affected Wyckoff orbit: the canonical and - operator-form representative sets are proven to describe the same point - set as rational affine forms, not merely to agree at sampled parameters - (sampling may supplement but never replace the symbolic proof) — - review-1 [P1]. -2. **Apply it as a cctbx-free post-processing pass over the existing - bundled DB**, not a full cctbx regeneration. The transform parses the - existing `coords_xyz` strings and re-parametrises with `sympy` (already - a `crystallography.py` dependency), so it runs in this repo's - environment. The cctbx generator also gains the same pass + a - generation-time invariant for future rebuilds, but this PR's - `space_groups.json.gz` is produced by the post-processing transform. - _Rejected alternative — re-running the full cctbx generator — needs the - throwaway cctbx env and re-derives the whole table when only the - `coords_xyz` spelling is wrong._ +1. **Re-source canonical `coords_xyz` from cryspy's `wyckoff.dat`** (the + ADR's intended Wyckoff source, ITA convention, already in the + environment) for every operator-form template, replacing the cctbx + operator-form spelling. Canonical form = each component a signed single + free variable (or an integer-coefficient ITA combination such as + `x-y`) plus an optional rational constant — **no fractional coefficient + on a variable** — with each genuine free DOF reduced to one canonical + variable so dependent axes' symbols are absent. +2. **Verify each replacement two ways** (review-1 [P1] plus the CT1 + correctness gap): (a) **exact symbolic orbit equivalence** (`sympy`) — + the cryspy canonical orbit and the cctbx operator-form orbit describe + the same point set as rational affine forms, not merely agree at + sampled parameters; **and** (b) **constraint correctness** — the + canonical representative's free-symbol set produces the right + `_fract_constrained_flags()` (free-DOF count matches the orbit's true + dimensionality; dependent axes constrained). Orbit equivalence alone is + insufficient: a non-minimal form like `(x-y,-x+y,z)` would pass it yet + leave `fract_y` wrongly free. _Rejected alternative — a blind `sympy` + re-parametrise of the existing operator strings — risks exactly that + non-minimal failure mode and re-derives the ITA convention cryspy + already encodes._ 3. **No constraint-code change.** `_fract_constrained_flags()` / `_apply_fract_constraints()` are correct as-is. -4. **No new runtime dependency.** `sympy` already backs - `crystallography.py`; `cctbx` stays generation-only and is not needed - for the transform. +4. **No new dependency.** Re-sourcing reads cryspy's `wyckoff.dat`; + `cryspy` and `sympy` are already project dependencies, and `cctbx` + stays generation-only (not needed for re-sourcing). 5. **Guard both sides:** a generation-time invariant in the generator, a `tools/check_packaged_db.py` assertion rejecting operator-form leakage in the packaged wheel, and a unit data-invariant over loaded @@ -351,10 +359,12 @@ constraint **code** is correct; only the **data** spelling is wrong. - `src/easydiffraction/crystallography/space_groups.json.gz` — rewritten with canonical `coords_xyz`; all other fields unchanged. - `tmp/space-groups/helper-tools/canonicalize_coords.py` — **new**, local - ignored one-time transform (read DB → re-parametrise → verify orbit - equality → rewrite). -- `tmp/space-groups/helper-tools/generate_space_groups.py` — add the same - canonicalisation pass + generation-time invariant. + ignored one-time tool (read DB → re-source canonical `coords_xyz` from + cryspy `wyckoff.dat` per `(IT, coord_code, letter)` → verify orbit + equivalence + constraint flags → rewrite). +- `tmp/space-groups/helper-tools/generate_space_groups.py` — source the + Wyckoff `coords_xyz` from cryspy's canonical form (not cctbx + operator-form) + a generation-time invariant rejecting operator-form. - `tools/check_packaged_db.py` — assert no packaged `coords_xyz` is operator-form. - `docs/dev/adrs/accepted/space-group-database.md` — canonical-form @@ -382,24 +392,28 @@ commit stages only the tracked deliverable it produces, and the local tools are recorded by SHA-256 in the ADR provenance (CT4). No step commits only ignored files, and no empty commits. -- [ ] **CT1 — Canonicalise the database (local transform → tracked - output).** Add the local, ignored - `tmp/space-groups/helper-tools/canonicalize_coords.py`: parse each - `coords_xyz` with `sympy`, detect operator form, re-parametrise to - canonical ITA form, and prove **exact symbolic orbit equivalence** - for every affected position (review-1 [P1]). Run it to rewrite +- [ ] **CT1 — Canonicalise the database (local re-sourcing tool → + tracked output).** Add the local, ignored + `tmp/space-groups/helper-tools/canonicalize_coords.py`: for each + operator-form `coords_xyz`, look up the canonical orbit from cryspy's + `wyckoff.dat` by `(IT_number, coord_code, letter)`, and verify the + replacement two ways — **exact symbolic orbit equivalence** (`sympy`) + against the cctbx operator-form orbit **and** correct + `_fract_constrained_flags()` (free-DOF count + dependent axes + constrained). Run it to rewrite `src/easydiffraction/crystallography/space_groups.json.gz` (R-3m `h` - → `(x,-x,z)`; all other fields unchanged). The transform is local - tooling (recorded by SHA in CT4); **this commit stages only the - regenerated `space_groups.json.gz`**. Commit: + → `(x,-x,z)`; all other fields unchanged). The tool is local tooling + (recorded by SHA in CT4); **this commit stages only the regenerated + `space_groups.json.gz`**. Commit: `Canonicalize space-group coords_xyz templates` -- [ ] **CT2 — Generator canonicalisation pass + invariant (local prep, - no commit).** Fold the same canonicalisation + a generation-time - invariant (rejecting operator-form leakage) into the local - `tmp/space-groups/helper-tools/generate_space_groups.py`, so a - future cctbx rebuild stays canonical. **Local curation tooling — not - committed** (deliberate exception); its updated SHA-256 is recorded - in CT4. No commit. +- [ ] **CT2 — Generator sources canonical coords + invariant (local prep, + no commit).** Update the local + `tmp/space-groups/helper-tools/generate_space_groups.py` to source + Wyckoff `coords_xyz` from cryspy's canonical `wyckoff.dat` (not cctbx + operator-form) and add a generation-time invariant rejecting + operator-form leakage, so a future rebuild stays canonical. **Local + curation tooling — not committed** (deliberate exception); its + updated SHA-256 is recorded in CT4. No commit. - [ ] **CT3 — Packaging assertion.** Extend the tracked `tools/check_packaged_db.py` to assert no packaged `coords_xyz` template is operator-form (catches future regression at the wheel From 940529e6b62e46347008e96571100be7c59630a4 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 07:10:42 +0200 Subject: [PATCH 03/55] Refine canonical-templates CT1 to fix generator and re-run --- docs/dev/plans/space-group-database.md | 83 ++++++++++++++------------ 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index 94fbf5337..40cd1132a 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -314,14 +314,22 @@ cryspy's `wyckoff.dat`, already holds the canonical ITA form for them ### Decisions (this phase) -1. **Re-source canonical `coords_xyz` from cryspy's `wyckoff.dat`** (the - ADR's intended Wyckoff source, ITA convention, already in the - environment) for every operator-form template, replacing the cctbx - operator-form spelling. Canonical form = each component a signed single - free variable (or an integer-coefficient ITA combination such as - `x-y`) plus an optional rational constant — **no fractional coefficient - on a variable** — with each genuine free DOF reduced to one canonical - variable so dependent axes' symbols are absent. +1. **Fix the generator to source `coords_xyz` from cryspy's canonical + `wyckoff.dat`, then re-run it.** The root cause is that + `_extract_wyckoff_positions` builds `coords_xyz` from cctbx + (`position.unique_ops().as_xyz()`, operator form) while cryspy's + `wyckoff.dat` — the ADR's intended Wyckoff source — was read only for + count-validation. Change the generator to take `coords_xyz` from + cryspy's canonical form, then re-run via `pixi exec --spec cctbx` (the + proven one-time-build path) so the whole table is uniformly canonical. + Canonical form = each component a signed single free variable (or an + integer-coefficient ITA combination such as `x-y`) plus an optional + rational constant — **no fractional coefficient on a variable** — with + each genuine free DOF reduced to one canonical variable so dependent + axes' symbols are absent. _Rejected alternative — a cctbx-free post-hoc + swap of only the operator-form strings — is not clean: cryspy's orbit + representation differs from cctbx's, risking mixed representations and + needing orbit-membership reconciliation._ 2. **Verify each replacement two ways** (review-1 [P1] plus the CT1 correctness gap): (a) **exact symbolic orbit equivalence** (`sympy`) — the cryspy canonical orbit and the cctbx operator-form orbit describe @@ -337,9 +345,9 @@ cryspy's `wyckoff.dat`, already holds the canonical ITA form for them already encodes._ 3. **No constraint-code change.** `_fract_constrained_flags()` / `_apply_fract_constraints()` are correct as-is. -4. **No new dependency.** Re-sourcing reads cryspy's `wyckoff.dat`; - `cryspy` and `sympy` are already project dependencies, and `cctbx` - stays generation-only (not needed for re-sourcing). +4. **No new runtime dependency.** `cryspy` and `sympy` are already + project dependencies; `cctbx` is temp-installed only for the one-time + re-run (generation-only, the proven build path), never a runtime dep. 5. **Guard both sides:** a generation-time invariant in the generator, a `tools/check_packaged_db.py` assertion rejecting operator-form leakage in the packaged wheel, and a unit data-invariant over loaded @@ -358,13 +366,13 @@ cryspy's `wyckoff.dat`, already holds the canonical ITA form for them - `src/easydiffraction/crystallography/space_groups.json.gz` — rewritten with canonical `coords_xyz`; all other fields unchanged. -- `tmp/space-groups/helper-tools/canonicalize_coords.py` — **new**, local - ignored one-time tool (read DB → re-source canonical `coords_xyz` from - cryspy `wyckoff.dat` per `(IT, coord_code, letter)` → verify orbit - equivalence + constraint flags → rewrite). -- `tmp/space-groups/helper-tools/generate_space_groups.py` — source the - Wyckoff `coords_xyz` from cryspy's canonical form (not cctbx - operator-form) + a generation-time invariant rejecting operator-form. +- `tmp/space-groups/helper-tools/generate_space_groups.py` — **local, + ignored** generator surgery: `_extract_wyckoff_positions` takes + `coords_xyz` from cryspy's canonical `wyckoff.dat` (not cctbx + operator-form), plus a generation-time invariant rejecting operator-form + leakage. Re-run via `pixi exec --spec cctbx`. The regenerated DB must + differ from the prior one **only** in `coords_xyz` (no field drift from + the cctbx re-run; pin the provenance cctbx version if needed). - `tools/check_packaged_db.py` — assert no packaged `coords_xyz` is operator-form. - `docs/dev/adrs/accepted/space-group-database.md` — canonical-form @@ -392,28 +400,25 @@ commit stages only the tracked deliverable it produces, and the local tools are recorded by SHA-256 in the ADR provenance (CT4). No step commits only ignored files, and no empty commits. -- [ ] **CT1 — Canonicalise the database (local re-sourcing tool → - tracked output).** Add the local, ignored - `tmp/space-groups/helper-tools/canonicalize_coords.py`: for each - operator-form `coords_xyz`, look up the canonical orbit from cryspy's - `wyckoff.dat` by `(IT_number, coord_code, letter)`, and verify the - replacement two ways — **exact symbolic orbit equivalence** (`sympy`) - against the cctbx operator-form orbit **and** correct - `_fract_constrained_flags()` (free-DOF count + dependent axes - constrained). Run it to rewrite - `src/easydiffraction/crystallography/space_groups.json.gz` (R-3m `h` - → `(x,-x,z)`; all other fields unchanged). The tool is local tooling - (recorded by SHA in CT4); **this commit stages only the regenerated - `space_groups.json.gz`**. Commit: +- [ ] **CT1 — Fix the generator + re-run to a canonical DB.** Modify the + local `tmp/space-groups/helper-tools/generate_space_groups.py` so + `_extract_wyckoff_positions` sources `coords_xyz` from cryspy's + canonical `wyckoff.dat` (matched per `(IT, coord_code, letter)`) + instead of cctbx `unique_ops().as_xyz()`, and add a generation-time + invariant rejecting any operator-form `coords_xyz`. Re-run via + `pixi exec --spec cctbx` (pin the provenance cctbx version) to + regenerate `src/easydiffraction/crystallography/space_groups.json.gz`. + The generator is local tooling (recorded by SHA in CT4); **this + commit stages only the regenerated `space_groups.json.gz`**. Commit: `Canonicalize space-group coords_xyz templates` -- [ ] **CT2 — Generator sources canonical coords + invariant (local prep, - no commit).** Update the local - `tmp/space-groups/helper-tools/generate_space_groups.py` to source - Wyckoff `coords_xyz` from cryspy's canonical `wyckoff.dat` (not cctbx - operator-form) and add a generation-time invariant rejecting - operator-form leakage, so a future rebuild stays canonical. **Local - curation tooling — not committed** (deliberate exception); its - updated SHA-256 is recorded in CT4. No commit. +- [ ] **CT2 — Verify the regenerated DB (local prep, no commit).** Before + committing CT1, confirm with `sympy` that each regenerated canonical + orbit is **exactly equivalent** to the prior cctbx operator-form + orbit (same point set), that `_fract_constrained_flags()` is now + crystallographically correct for every changed position (free-DOF + count + dependent axes), and that the regenerated DB differs from the + prior one **only** in `coords_xyz` (no cctbx-version field drift). + Local checks — gate CT1's commit on them; not a separate commit. - [ ] **CT3 — Packaging assertion.** Extend the tracked `tools/check_packaged_db.py` to assert no packaged `coords_xyz` template is operator-form (catches future regression at the wheel From 7c9f5d77d8b1343392ebb6cdafe562a0eeab3331 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 07:39:23 +0200 Subject: [PATCH 04/55] Settle canonical-templates phase on cctbx-free post-process --- docs/dev/plans/space-group-database.md | 99 +++++++++++++++----------- 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index 40cd1132a..2e49f9bdb 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -314,22 +314,27 @@ cryspy's `wyckoff.dat`, already holds the canonical ITA form for them ### Decisions (this phase) -1. **Fix the generator to source `coords_xyz` from cryspy's canonical - `wyckoff.dat`, then re-run it.** The root cause is that - `_extract_wyckoff_positions` builds `coords_xyz` from cctbx +1. **Produce canonical `coords_xyz` via a cctbx-free post-process that + re-sources from cryspy's `wyckoff.dat`.** The root cause is that the + generator's `_extract_wyckoff_positions` built `coords_xyz` from cctbx (`position.unique_ops().as_xyz()`, operator form) while cryspy's `wyckoff.dat` — the ADR's intended Wyckoff source — was read only for - count-validation. Change the generator to take `coords_xyz` from - cryspy's canonical form, then re-run via `pixi exec --spec cctbx` (the - proven one-time-build path) so the whole table is uniformly canonical. - Canonical form = each component a signed single free variable (or an - integer-coefficient ITA combination such as `x-y`) plus an optional - rational constant — **no fractional coefficient on a variable** — with - each genuine free DOF reduced to one canonical variable so dependent - axes' symbols are absent. _Rejected alternative — a cctbx-free post-hoc - swap of only the operator-form strings — is not clean: cryspy's orbit - representation differs from cctbx's, risking mixed representations and - needing orbit-membership reconciliation._ + count-validation. A local tool loads the bundled DB and, for each + position, **matches the orbit-equivalent cryspy position** (orbit-based, + not by letter or block index, since cryspy and cctbx differ in letter + labelling and representative choice) and replaces `coords_xyz` with + cryspy's canonical orbit. Canonical form = each component a signed + single free variable (or an integer-coefficient ITA combination such as + `x-y`) plus an optional rational constant — **no fractional coefficient + on a variable** — with each genuine free DOF reduced to one canonical + variable so dependent axes' symbols are absent. A cctbx-free dry-run + verified 3512/3826 templates directly; the ~31 edge cases (rhombohedral + `r` settings + cryspy/cctbx letter/representative differences) are + resolved by the orbit-based match, with any residual ambiguity curated + against International Tables. _No cctbx re-run is needed (the dry-run + proved the post-process viable); the rejected alternative — fix the + generator + full cctbx re-run — adds a heavy install + reproducibility + risk for the same cryspy↔cctbx reconciliation._ 2. **Verify each replacement two ways** (review-1 [P1] plus the CT1 correctness gap): (a) **exact symbolic orbit equivalence** (`sympy`) — the cryspy canonical orbit and the cctbx operator-form orbit describe @@ -345,9 +350,10 @@ cryspy's `wyckoff.dat`, already holds the canonical ITA form for them already encodes._ 3. **No constraint-code change.** `_fract_constrained_flags()` / `_apply_fract_constraints()` are correct as-is. -4. **No new runtime dependency.** `cryspy` and `sympy` are already - project dependencies; `cctbx` is temp-installed only for the one-time - re-run (generation-only, the proven build path), never a runtime dep. +4. **No new dependency, no cctbx.** The post-process uses `cryspy`'s + `wyckoff.dat` + `numpy`/`sympy` (already project deps); `cctbx` is not + used at all (it stays generation-only, relevant only if the generator + is ever fully re-run). 5. **Guard both sides:** a generation-time invariant in the generator, a `tools/check_packaged_db.py` assertion rejecting operator-form leakage in the packaged wheel, and a unit data-invariant over loaded @@ -366,13 +372,18 @@ cryspy's `wyckoff.dat`, already holds the canonical ITA form for them - `src/easydiffraction/crystallography/space_groups.json.gz` — rewritten with canonical `coords_xyz`; all other fields unchanged. +- `tmp/space-groups/helper-tools/canonicalize_coords.py` — **new**, local + ignored cctbx-free post-process: load DB → orbit-match each position to + cryspy's canonical orbit → verify (mod-1 orbit membership + + `_fract_constrained_flags`) → rewrite `coords_xyz` (all other fields + byte-identical). - `tmp/space-groups/helper-tools/generate_space_groups.py` — **local, - ignored** generator surgery: `_extract_wyckoff_positions` takes - `coords_xyz` from cryspy's canonical `wyckoff.dat` (not cctbx - operator-form), plus a generation-time invariant rejecting operator-form - leakage. Re-run via `pixi exec --spec cctbx`. The regenerated DB must - differ from the prior one **only** in `coords_xyz` (no field drift from - the cctbx re-run; pin the provenance cctbx version if needed). + ignored** future-proofing (CT2): `_extract_wyckoff_positions` sources + `coords_xyz` from cryspy (not cctbx) + a generation-time invariant + rejecting operator-form leakage. Not re-run now. +- `docs/dev/adrs/accepted/space-group-database/space_groups_overrides.yaml` + — record any position the orbit match leaves ambiguous (curated vs + International Tables). - `tools/check_packaged_db.py` — assert no packaged `coords_xyz` is operator-form. - `docs/dev/adrs/accepted/space-group-database.md` — canonical-form @@ -400,25 +411,31 @@ commit stages only the tracked deliverable it produces, and the local tools are recorded by SHA-256 in the ADR provenance (CT4). No step commits only ignored files, and no empty commits. -- [ ] **CT1 — Fix the generator + re-run to a canonical DB.** Modify the - local `tmp/space-groups/helper-tools/generate_space_groups.py` so - `_extract_wyckoff_positions` sources `coords_xyz` from cryspy's - canonical `wyckoff.dat` (matched per `(IT, coord_code, letter)`) - instead of cctbx `unique_ops().as_xyz()`, and add a generation-time - invariant rejecting any operator-form `coords_xyz`. Re-run via - `pixi exec --spec cctbx` (pin the provenance cctbx version) to - regenerate `src/easydiffraction/crystallography/space_groups.json.gz`. - The generator is local tooling (recorded by SHA in CT4); **this - commit stages only the regenerated `space_groups.json.gz`**. Commit: +- [ ] **CT1 — Canonicalise the DB via the cctbx-free post-process.** + Finish the local + `tmp/space-groups/helper-tools/canonicalize_coords.py`: parse cryspy + `wyckoff.dat`, **match each DB position to the orbit-equivalent + cryspy position** (orbit-based, not by letter/index), replace + operator-form `coords_xyz` with cryspy's canonical orbit, and verify + per position — exact orbit equivalence (mod-1 membership) **and** + correct `_fract_constrained_flags()` (free-DOF count + dependent + axes). Curate against International Tables any case the orbit match + leaves ambiguous, recording it in `space_groups_overrides.yaml`. Run + it to rewrite + `src/easydiffraction/crystallography/space_groups.json.gz` (R-3m `h` + → `(x,-x,z)`; all non-`coords_xyz` fields byte-identical). The tool + is local tooling (recorded by SHA in CT4); **this commit stages only + the regenerated `space_groups.json.gz`**. Commit: `Canonicalize space-group coords_xyz templates` -- [ ] **CT2 — Verify the regenerated DB (local prep, no commit).** Before - committing CT1, confirm with `sympy` that each regenerated canonical - orbit is **exactly equivalent** to the prior cctbx operator-form - orbit (same point set), that `_fract_constrained_flags()` is now - crystallographically correct for every changed position (free-DOF - count + dependent axes), and that the regenerated DB differs from the - prior one **only** in `coords_xyz` (no cctbx-version field drift). - Local checks — gate CT1's commit on them; not a separate commit. +- [ ] **CT2 — Fix the generator's coords source for future rebuilds + (local prep, no commit).** Update the local + `tmp/space-groups/helper-tools/generate_space_groups.py` so + `_extract_wyckoff_positions` sources `coords_xyz` from cryspy's + canonical `wyckoff.dat` (not cctbx `unique_ops`), plus a + generation-time invariant rejecting operator-form leakage, so a + future rebuild stays canonical. **No re-run now** (CT1's + post-process already produced the canonical DB). Local curation + tooling — not committed; its updated SHA-256 is recorded in CT4. - [ ] **CT3 — Packaging assertion.** Extend the tracked `tools/check_packaged_db.py` to assert no packaged `coords_xyz` template is operator-form (catches future regression at the wheel From 4811507207f15cc3673c067b59622f3efcca9420 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 07:59:59 +0200 Subject: [PATCH 05/55] Canonicalize space-group coords_xyz templates --- docs/dev/plans/space-group-database.md | 2 +- .../crystallography/space_groups.json.gz | Bin 117210 -> 108047 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index 2e49f9bdb..25f12f2a1 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -411,7 +411,7 @@ commit stages only the tracked deliverable it produces, and the local tools are recorded by SHA-256 in the ADR provenance (CT4). No step commits only ignored files, and no empty commits. -- [ ] **CT1 — Canonicalise the DB via the cctbx-free post-process.** +- [x] **CT1 — Canonicalise the DB via the cctbx-free post-process.** Finish the local `tmp/space-groups/helper-tools/canonicalize_coords.py`: parse cryspy `wyckoff.dat`, **match each DB position to the orbit-equivalent diff --git a/src/easydiffraction/crystallography/space_groups.json.gz b/src/easydiffraction/crystallography/space_groups.json.gz index 75d4f80ce725ad001c05e8a07fa6a6604ab31a1c..135015187be0422126c03d35164c8a745b58d0af 100644 GIT binary patch delta 100626 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 delta 109864 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 b9}kjVUoHR$2#D8LD2ORqc^I{45{Ul+%Hr+q From 1a2a9e6abde06b7da24dfdd9a222d3c4b04c1ce6 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 08:04:03 +0200 Subject: [PATCH 06/55] Assert canonical coords_xyz in packaged DB check --- docs/dev/plans/space-group-database.md | 2 +- tools/check_packaged_db.py | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index 25f12f2a1..ea81edd69 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -436,7 +436,7 @@ only ignored files, and no empty commits. future rebuild stays canonical. **No re-run now** (CT1's post-process already produced the canonical DB). Local curation tooling — not committed; its updated SHA-256 is recorded in CT4. -- [ ] **CT3 — Packaging assertion.** Extend the tracked +- [x] **CT3 — Packaging assertion.** Extend the tracked `tools/check_packaged_db.py` to assert no packaged `coords_xyz` template is operator-form (catches future regression at the wheel layer). Commit: `Assert canonical coords_xyz in packaged DB check` diff --git a/tools/check_packaged_db.py b/tools/check_packaged_db.py index d0bac73bd..efb844ecf 100644 --- a/tools/check_packaged_db.py +++ b/tools/check_packaged_db.py @@ -6,8 +6,10 @@ of the project's full dependency tree: it opens the wheel, reads ``space_groups.json.gz`` straight from it, and asserts the data is shipped as package data, that the obsolete ``space_groups.pkl.gz`` is gone, and that the -archive covers all 230 IT groups plus the cryspy coordinate-code alias surface. -Exits non-zero on any problem so a packaging regression fails the caller. +archive covers all 230 IT groups plus the cryspy coordinate-code alias +surface, and that no Wyckoff ``coords_xyz`` template is in cctbx operator form +(canonical ITA form only). Exits non-zero on any problem so a packaging +regression fails the caller. Usage: ``python tools/check_packaged_db.py [path/to/wheel]`` (defaults to the newest wheel in ``dist/``). @@ -17,6 +19,7 @@ import gzip import json +import re import sys import zipfile from pathlib import Path @@ -26,6 +29,9 @@ _REQUIRED_KEYS = [(14, '-b1'), (3, '-a1'), (1, None)] # Accepted seed record count (see the space-group-database ADR provenance). _EXPECTED_RECORD_COUNT = 816 +# Wyckoff coords_xyz must be canonical ITA form, never cctbx operator form +# (e.g. ``1/2*x-1/2*y``), which breaks symmetry-constraint detection. +_OPERATOR_FORM = re.compile(r'[0-9.]\s*\*\s*[xyz]|[xyz]\s*\*') def _wheel_path(argv: list[str]) -> Path: @@ -59,6 +65,19 @@ def main(argv: list[str]) -> None: if len(keys) != _EXPECTED_RECORD_COUNT: sys.exit(f'packaged database has {len(keys)} unique keys, expected {_EXPECTED_RECORD_COUNT}') + operator_form = [ + (record['IT_number'], record['IT_coordinate_system_code'], letter, template) + for record in records + for letter, position in record['Wyckoff_positions'].items() + for template in position['coords_xyz'] + if _OPERATOR_FORM.search(template) + ] + if operator_form: + sys.exit( + f'packaged database has {len(operator_form)} operator-form coords_xyz ' + f'(canonical ITA form required); first: {operator_form[0]}' + ) + print( f'packaged DB OK in {wheel.name}: ' f'{len({key[0] for key in keys})} IT groups, {len(records)} settings' From c4c7a7d1e8d963d500e148e23aea2b82b56f20dd Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 08:06:36 +0200 Subject: [PATCH 07/55] Record canonical coords_xyz invariant and provenance --- .../dev/adrs/accepted/space-group-database.md | 41 +++++++++++++++++-- docs/dev/plans/space-group-database.md | 2 +- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/docs/dev/adrs/accepted/space-group-database.md b/docs/dev/adrs/accepted/space-group-database.md index 74083fd76..ecc311217 100644 --- a/docs/dev/adrs/accepted/space-group-database.md +++ b/docs/dev/adrs/accepted/space-group-database.md @@ -297,6 +297,22 @@ sentinel value. through the curation overrides and a regeneration run, keeping the file and the documented decisions in sync. +### 9. Canonical ITA `coords_xyz` (no operator form) + +Every Wyckoff `coords_xyz` template is stored in **canonical +International Tables parametric form** — each component a signed single +free variable (or an integer-coefficient combination such as `x-y`) plus +an optional rational constant, never a fractional coefficient on a +variable. cctbx's `unique_ops().as_xyz()` (the generator's raw output) +emits **operator form** (e.g. `1/2*x-1/2*y`) for coupled special +positions, which silently breaks +`crystallography._fract_constrained_flags` so a refined special-position +coordinate drifts off its symmetry site. Canonical `coords_xyz` are +therefore re-sourced from cryspy's `wyckoff.dat` (the intended Wyckoff +source), matched by orbit equivalence; the invariant is enforced in the +unit tests and by `tools/check_packaged_db.py`, which rejects any +operator-form template in the packaged wheel. + ## Consequences ### Positive @@ -409,6 +425,21 @@ pixi exec --spec cctbx --spec gemmi --spec sympy --spec pyyaml \ --print-summary ``` +**Canonical-`coords_xyz` correction (§9).** The run above emits cctbx +operator-form `coords_xyz` for coupled special positions. The +canonical-templates post-process then re-sources canonical ITA +`coords_xyz` from cryspy's `wyckoff.dat`: + +```bash +python tmp/space-groups/helper-tools/canonicalize_coords.py --write +``` + +It matches each of the 288 coupled positions to the orbit-equivalent +cryspy position (one, IT 228 origin-1 `g`, is re-parametrised from +cctbx's own orbit), changes only `coords_xyz`, and asserts no +operator-form template remains. The `space_groups.json.gz` SHA-256 below +is **after** this correction. + Build environment: - **cctbx** from conda-forge: @@ -423,10 +454,14 @@ Build environment: Generated and curation artifacts: -- `src/easydiffraction/crystallography/space_groups.json.gz`: - `30f0051c669712ab34d991e60223c5e29264fc033b2ab03392cc01465ceba926` +- `src/easydiffraction/crystallography/space_groups.json.gz` + (after the §9 canonical-`coords_xyz` correction): + `234a9aeb9579c67fcb1a924554714407498cbb34fa94c8562b4dd454e9503225` - `tmp/space-groups/helper-tools/generate_space_groups.py`: - `bf10dcfbcf9e60485037ddabc65425e61f746ad9649cd3ccc67376dd6aae241a` + `3aa5f03cd1a69bdfe0a280158c9343b65d5eaa4d75a6d58f2606fb5fbe3df83d` +- `tmp/space-groups/helper-tools/canonicalize_coords.py` (§9 + canonical-`coords_xyz` post-process): + `c6b2b1ac50d59f6546c9fc9eadebb49a637ac4d6fba589a2a4a1d80deeb10e37` - `docs/dev/adrs/accepted/space-group-database/space_groups_overrides.yaml`: `7077eec25d0f3b852dd7096a24dc7ac438467f9cb594f91a65ce10cda0e0722a` - `tmp/space-groups/extracted-comparison/disagreements.md`: diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index ea81edd69..bb9b67f10 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -440,7 +440,7 @@ only ignored files, and no empty commits. `tools/check_packaged_db.py` to assert no packaged `coords_xyz` template is operator-form (catches future regression at the wheel layer). Commit: `Assert canonical coords_xyz in packaged DB check` -- [ ] **CT4 — ADR invariant + provenance.** Add the canonical-`coords_xyz` +- [x] **CT4 — ADR invariant + provenance.** Add the canonical-`coords_xyz` invariant as a decision in `docs/dev/adrs/accepted/space-group-database.md`, and update its _Build Provenance_ with the new `space_groups.json.gz` SHA-256, the From 62fd107872317b903de2e0031bd4318fa2fd3537 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 08:07:13 +0200 Subject: [PATCH 08/55] Reach canonical-templates Phase 1 review gate --- docs/dev/plans/space-group-database.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index bb9b67f10..d06b281cf 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -287,8 +287,8 @@ above is complete._ ### Status (this phase) -- [ ] Phase 1 — Implementation (data + tooling + docs) -- [ ] Phase 1 review gate +- [x] Phase 1 — Implementation (data + tooling + docs) +- [x] Phase 1 review gate - [ ] Phase 2 — Verification (tests + checks) ### Problem @@ -427,7 +427,7 @@ only ignored files, and no empty commits. is local tooling (recorded by SHA in CT4); **this commit stages only the regenerated `space_groups.json.gz`**. Commit: `Canonicalize space-group coords_xyz templates` -- [ ] **CT2 — Fix the generator's coords source for future rebuilds +- [x] **CT2 — Fix the generator's coords source for future rebuilds (local prep, no commit).** Update the local `tmp/space-groups/helper-tools/generate_space_groups.py` so `_extract_wyckoff_positions` sources `coords_xyz` from cryspy's @@ -448,7 +448,7 @@ only ignored files, and no empty commits. `generate_space_groups.py` SHA-256** plus the canonical-invariant step in the rebuild path (review-1 [P2]). Commit: `Record canonical coords_xyz invariant and provenance` -- [ ] **CT5 — Phase 1 review gate.** No code. Mark `[x]`, commit the +- [x] **CT5 — Phase 1 review gate.** No code. Mark `[x]`, commit the checklist update alone, hand off to review. Commit: `Reach canonical-templates Phase 1 review gate` From 176e6e682bdd40a0841acb316322c25f58fd03db Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 08:56:28 +0200 Subject: [PATCH 09/55] Keep pattern-plot top and bottom panels at fixed height --- .../display/plotters/plotly.py | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/src/easydiffraction/display/plotters/plotly.py b/src/easydiffraction/display/plotters/plotly.py index 61bd915c6..b9c28c879 100644 --- a/src/easydiffraction/display/plotters/plotly.py +++ b/src/easydiffraction/display/plotters/plotly.py @@ -2305,24 +2305,26 @@ def _bragg_row_height_pixels(plot_spec: PowderMeasVsCalcSpec) -> float: def _baseline_non_bragg_row_heights( cls, plot_spec: PowderMeasVsCalcSpec, - row_count: int, *, - has_bragg_ticks: bool, has_residual: bool, ) -> tuple[float, float | None]: - """Return baseline main and residual row heights in pixels.""" + """Return fixed main and residual row heights in pixels. + + Anchored to the reference three-row layout so the main and + residual rows keep their pixel height regardless of which + rows are shown; ``_composite_figure_height`` adapts instead. + """ baseline_height = cls._base_composite_height_pixels(plot_spec) plot_area_height = cls._composite_plot_area_height(baseline_height) - available_row_pixels = plot_area_height * cls._subplot_available_height_fraction(row_count) - baseline_bragg_pixels = float( - cls._bragg_tick_symbol_height_pixels() if has_bragg_ticks else 0 + available_row_pixels = plot_area_height * cls._subplot_available_height_fraction(3) + non_bragg_pixels = max( + available_row_pixels - cls._bragg_tick_symbol_height_pixels(), 1.0 ) - non_bragg_pixels = max(available_row_pixels - baseline_bragg_pixels, 1.0) + main_pixels = non_bragg_pixels / (1.0 + plot_spec.residual_height_fraction) if not has_residual: - return non_bragg_pixels, None + return main_pixels, None - main_pixels = non_bragg_pixels / (1.0 + plot_spec.residual_height_fraction) residual_pixels = main_pixels * plot_spec.residual_height_fraction return main_pixels, residual_pixels @@ -2334,8 +2336,6 @@ def _get_powder_composite_rows(plot_spec: PowderMeasVsCalcSpec) -> PowderComposi row_count = 1 + int(has_bragg_ticks) + int(has_residual) main_row_height, residual_row_height = PlotlyPlotter._baseline_non_bragg_row_heights( plot_spec=plot_spec, - row_count=row_count, - has_bragg_ticks=has_bragg_ticks, has_residual=has_residual, ) row_heights = [main_row_height] @@ -2359,22 +2359,19 @@ def _get_powder_composite_rows(plot_spec: PowderMeasVsCalcSpec) -> PowderComposi ) @classmethod - def _composite_figure_height( - cls, - plot_spec: PowderMeasVsCalcSpec, - layout: PowderCompositeRows, - ) -> float: - """Return figure height for Bragg row growth.""" - base_pixels = cls._base_composite_height_pixels(plot_spec) - phase_count = len(plot_spec.bragg_tick_sets) - if phase_count <= 1: - return base_pixels - - added_bragg_pixels = float((phase_count - 1) * cls._bragg_tick_symbol_height_pixels()) - growth_pixels = added_bragg_pixels / cls._subplot_available_height_fraction( - layout.row_count - ) - return base_pixels + growth_pixels + def _composite_figure_height(cls, layout: PowderCompositeRows) -> float: + """Return figure height that renders rows at their pixel heights. + + Each entry in ``layout.row_heights`` is an absolute pixel + target. Plotly distributes the plot area across rows by + fraction, so the figure height is the row-pixel sum scaled up + for the inter-row spacing, plus the vertical margins. The main + and residual rows stay fixed while the Bragg row (and the + figure) grow with the phase count. + """ + row_pixels = sum(layout.row_heights) + plot_area_height = row_pixels / cls._subplot_available_height_fraction(layout.row_count) + return plot_area_height + COMPOSITE_MARGIN_TOP + COMPOSITE_MARGIN_BOTTOM @classmethod def _get_main_intensity_range(cls, plot_spec: PowderMeasVsCalcSpec) -> tuple[float, float]: @@ -2698,7 +2695,7 @@ def _configure_powder_composite_layout( layout: PowderCompositeRows, ) -> None: fig.update_layout( - height=self._composite_figure_height(plot_spec, layout), + height=self._composite_figure_height(layout), margin={ 'autoexpand': True, 'r': COMPOSITE_MARGIN_RIGHT, From 7675de28c6cafb279498bba54539a30436dfbbdc Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 09:00:46 +0200 Subject: [PATCH 10/55] Test fixed pattern-plot panel heights across row layouts --- .../display/plotters/test_plotly.py | 67 ++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/tests/unit/easydiffraction/display/plotters/test_plotly.py b/tests/unit/easydiffraction/display/plotters/test_plotly.py index 51245c04c..53200f98a 100644 --- a/tests/unit/easydiffraction/display/plotters/test_plotly.py +++ b/tests/unit/easydiffraction/display/plotters/test_plotly.py @@ -885,7 +885,7 @@ def fake_show_figure(self, fig): x=np.array([1.0, 2.0, 3.0]), y_meas=np.array([10.0, 12.0, 11.0]), y_calc=np.array([9.0, 11.0, 10.5]), - y_resid=None, + y_resid=np.array([1.0, 1.0, 0.5]), bragg_tick_sets=( BraggTickSet( phase_id='phase-a', @@ -905,9 +905,74 @@ def fake_show_figure(self, fig): ), ) + # A full main + Bragg + residual composite renders at exactly the + # explicit height; reduced layouts derive a smaller height instead. assert captured['fig'].layout.height == 800 +def test_plot_powder_meas_vs_calc_keeps_top_and_bottom_rows_fixed(monkeypatch): + """Top and residual rows keep a fixed pixel height.""" + import easydiffraction.display.plotters.plotly as pp + + from easydiffraction.display.plotters.base import BraggTickSet + from easydiffraction.display.plotters.base import PowderMeasVsCalcSpec + + captured = {} + + def fake_show_figure(self, fig): + captured.setdefault('figures', []).append(fig) + + monkeypatch.setattr(pp.PlotlyPlotter, '_show_figure', fake_show_figure) + + bragg_tick_sets = ( + BraggTickSet( + phase_id='phase-a', + x=np.array([1.5]), + h=np.array([1]), + k=np.array([0]), + ell=np.array([1]), + f_squared_calc=np.array([100.0]), + f_calc=np.array([10.0]), + ), + ) + + def plot_spec(*, with_bragg: bool, with_residual: bool) -> PowderMeasVsCalcSpec: + return PowderMeasVsCalcSpec( + x=np.array([1.0, 2.0, 3.0]), + y_meas=np.array([10.0, 12.0, 11.0]), + y_calc=np.array([9.0, 11.0, 10.5]), + y_resid=np.array([1.0, 1.0, 0.5]) if with_residual else None, + bragg_tick_sets=bragg_tick_sets if with_bragg else (), + axes_labels=['2θ (deg)', 'Intensity (arb. units)'], + title='Powder', + residual_height_fraction=0.25, + bragg_peaks_height_fraction=0.10, + height=None, + ) + + plotter = pp.PlotlyPlotter() + plotter.plot_powder_meas_vs_calc(plot_spec=plot_spec(with_bragg=True, with_residual=True)) + plotter.plot_powder_meas_vs_calc(plot_spec=plot_spec(with_bragg=True, with_residual=False)) + plotter.plot_powder_meas_vs_calc(plot_spec=plot_spec(with_bragg=False, with_residual=True)) + plotter.plot_powder_meas_vs_calc(plot_spec=plot_spec(with_bragg=False, with_residual=False)) + + full, main_bragg, main_resid, main_only = captured['figures'] + + def row_pixels(fig, axis_name: str) -> float: + axis = getattr(fig.layout, axis_name) + plot_area_height = fig.layout.height - fig.layout.margin.t - fig.layout.margin.b + return plot_area_height * (axis.domain[1] - axis.domain[0]) + + # The top (main) row keeps the same pixel height in every layout. + assert row_pixels(main_bragg, 'yaxis') == pytest.approx(row_pixels(full, 'yaxis')) + assert row_pixels(main_resid, 'yaxis') == pytest.approx(row_pixels(full, 'yaxis')) + assert row_pixels(main_only, 'yaxis') == pytest.approx(row_pixels(full, 'yaxis')) + # The residual row keeps its height whether or not Bragg shows. + assert row_pixels(main_resid, 'yaxis2') == pytest.approx(row_pixels(full, 'yaxis3')) + # Hiding rows shrinks the figure instead of stretching the top row. + assert main_only.layout.height < main_resid.layout.height < full.layout.height + + def test_plot_powder_meas_vs_calc_skips_bragg_row_when_no_ticks(monkeypatch): import easydiffraction.display.plotters.plotly as pp From bb817a5fd16d20d0eb23269f836e4bbf39ced528 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 09:20:47 +0200 Subject: [PATCH 11/55] Inline composite row-height max() and trim docstring --- src/easydiffraction/display/plotters/plotly.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/easydiffraction/display/plotters/plotly.py b/src/easydiffraction/display/plotters/plotly.py index b9c28c879..383ac7b14 100644 --- a/src/easydiffraction/display/plotters/plotly.py +++ b/src/easydiffraction/display/plotters/plotly.py @@ -2317,9 +2317,7 @@ def _baseline_non_bragg_row_heights( baseline_height = cls._base_composite_height_pixels(plot_spec) plot_area_height = cls._composite_plot_area_height(baseline_height) available_row_pixels = plot_area_height * cls._subplot_available_height_fraction(3) - non_bragg_pixels = max( - available_row_pixels - cls._bragg_tick_symbol_height_pixels(), 1.0 - ) + non_bragg_pixels = max(available_row_pixels - cls._bragg_tick_symbol_height_pixels(), 1.0) main_pixels = non_bragg_pixels / (1.0 + plot_spec.residual_height_fraction) if not has_residual: @@ -2360,7 +2358,7 @@ def _get_powder_composite_rows(plot_spec: PowderMeasVsCalcSpec) -> PowderComposi @classmethod def _composite_figure_height(cls, layout: PowderCompositeRows) -> float: - """Return figure height that renders rows at their pixel heights. + """Return figure height matching the row pixel heights. Each entry in ``layout.row_heights`` is an absolute pixel target. Plotly distributes the plot area across rows by From bec2f5e73b4e6d163ce8fb1163ab9f3d1e6fba1f Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 09:20:53 +0200 Subject: [PATCH 12/55] Keep TeX report panels fixed when rows are hidden --- src/easydiffraction/report/fit_plot.py | 64 +++++++++++-------- .../easydiffraction/report/test_fit_plot.py | 40 ++++++++++++ 2 files changed, 77 insertions(+), 27 deletions(-) diff --git a/src/easydiffraction/report/fit_plot.py b/src/easydiffraction/report/fit_plot.py index 1f60fc677..cfa0c5756 100644 --- a/src/easydiffraction/report/fit_plot.py +++ b/src/easydiffraction/report/fit_plot.py @@ -105,16 +105,18 @@ def fit_plot_ranges(fit_data: dict[str, Any]) -> dict[str, float]: def fit_plot_geometry(fit_data: dict[str, Any]) -> dict[str, float]: - """Return Plotly-matched pgfplots axis geometry.""" + """Return Plotly-matched pgfplots axis geometry. + + Row heights are anchored to the reference three-row layout so the + main and residual panels keep a fixed centimetre height; the axis + stack grows or shrinks with the rows shown, matching the + interactive composite figure. + """ bragg_tick_sets = fit_data.get('bragg_tick_sets') or [] has_bragg_ticks = bool(bragg_tick_sets) has_residual = _has_residual(fit_data) row_count = 1 + int(has_bragg_ticks) + int(has_residual) - main_pixels, residual_pixels = _non_bragg_row_heights( - row_count=row_count, - has_bragg_ticks=has_bragg_ticks, - has_residual=has_residual, - ) + main_pixels, residual_pixels = _non_bragg_row_heights(has_residual=has_residual) row_heights = [main_pixels] if has_bragg_ticks: @@ -122,16 +124,15 @@ def fit_plot_geometry(fit_data: dict[str, Any]) -> dict[str, float]: if has_residual and residual_pixels is not None: row_heights.append(residual_pixels) - height_sum = sum(row_heights) - stack_height = _FIGURE_AXIS_WIDTH_CM * _FIGURE_AXIS_HEIGHT_TO_WIDTH - row_area_height = stack_height * _subplot_available_height_fraction(row_count) - scaled_heights = [row_area_height * row_height / height_sum for row_height in row_heights] + cm_per_pixel = _figure_cm_per_pixel() + row_heights_cm = [row_height * cm_per_pixel for row_height in row_heights] + plot_area_cm = sum(row_heights_cm) / _subplot_available_height_fraction(row_count) return { 'axis_width_cm': _FIGURE_AXIS_WIDTH_CM, - 'main_height_cm': scaled_heights[0], - 'bragg_height_cm': scaled_heights[1] if has_bragg_ticks else 0.0, - 'residual_height_cm': scaled_heights[-1] if has_residual else 0.0, - 'vertical_sep_cm': _vertical_sep_cm(stack_height), + 'main_height_cm': row_heights_cm[0], + 'bragg_height_cm': row_heights_cm[1] if has_bragg_ticks else 0.0, + 'residual_height_cm': row_heights_cm[-1] if has_residual else 0.0, + 'vertical_sep_cm': _vertical_sep_cm(plot_area_cm), } @@ -234,25 +235,34 @@ def _has_residual(fit_data: dict[str, Any]) -> bool: return isinstance(series, dict) and 'diff' in series -def _non_bragg_row_heights( - *, - row_count: int, - has_bragg_ticks: bool, - has_residual: bool, -) -> tuple[float, float | None]: +def _non_bragg_row_heights(*, has_residual: bool) -> tuple[float, float | None]: + """Return fixed main and residual row heights in pixels. + + Anchored to the reference three-row layout so the rows keep a + constant height regardless of which rows the figure shows. + """ plot_area_height = _composite_plot_area_height() - available_row_pixels = plot_area_height * _subplot_available_height_fraction(row_count) - baseline_bragg_pixels = _bragg_tick_symbol_height_pixels() if has_bragg_ticks else 0.0 - non_bragg_pixels = max(available_row_pixels - baseline_bragg_pixels, 1.0) + available_row_pixels = plot_area_height * _subplot_available_height_fraction(3) + non_bragg_pixels = max(available_row_pixels - _bragg_tick_symbol_height_pixels(), 1.0) + main_pixels = non_bragg_pixels / (1.0 + DEFAULT_RESIDUAL_HEIGHT_FRACTION) if not has_residual: - return non_bragg_pixels, None + return main_pixels, None - main_pixels = non_bragg_pixels / (1.0 + DEFAULT_RESIDUAL_HEIGHT_FRACTION) residual_pixels = main_pixels * DEFAULT_RESIDUAL_HEIGHT_FRACTION return main_pixels, residual_pixels +def _figure_cm_per_pixel() -> float: + """Return the fixed cm-per-pixel scale for fit-figure rows. + + Anchored so the reference three-row layout fills the nominal axis + stack height (axis width times the reference aspect ratio). + """ + reference_stack_cm = _FIGURE_AXIS_WIDTH_CM * _FIGURE_AXIS_HEIGHT_TO_WIDTH + return reference_stack_cm / _composite_plot_area_height() + + def _composite_plot_area_height() -> float: full_height = float(DEFAULT_HEIGHT * PLOTLY_HEIGHT_PER_UNIT) return max(full_height - COMPOSITE_MARGIN_TOP - COMPOSITE_MARGIN_BOTTOM, 1.0) @@ -270,8 +280,8 @@ def _bragg_row_height_pixels(tick_set_count: int) -> float: return float(tick_set_count) * _bragg_tick_symbol_height_pixels() -def _vertical_sep_cm(stack_height: float) -> float: - return stack_height * COMPOSITE_VERTICAL_SPACING +def _vertical_sep_cm(plot_area_cm: float) -> float: + return plot_area_cm * COMPOSITE_VERTICAL_SPACING def _display_tick_limit(raw_limit: float) -> float: diff --git a/tests/unit/easydiffraction/report/test_fit_plot.py b/tests/unit/easydiffraction/report/test_fit_plot.py index 0a231f1a8..898d825bf 100644 --- a/tests/unit/easydiffraction/report/test_fit_plot.py +++ b/tests/unit/easydiffraction/report/test_fit_plot.py @@ -72,3 +72,43 @@ def test_fit_plot_axis_styles_expose_shared_diagonal_color(): styles = fit_plot_axis_styles() assert styles['diag_rgb'] == '190,199,208' + + +def test_fit_plot_geometry_keeps_panel_heights_fixed_across_rows(): + from easydiffraction.report.fit_plot import _FIGURE_AXIS_HEIGHT_TO_WIDTH + from easydiffraction.report.fit_plot import _FIGURE_AXIS_WIDTH_CM + from easydiffraction.report.fit_plot import fit_plot_geometry + + def fit_data(*, phases: int, residual: bool) -> dict: + data = {'bragg_tick_sets': ['phase'] * phases} + data['series'] = {'diff': [0.0]} if residual else {} + return data + + def stack_height_cm(geometry: dict, row_count: int) -> float: + return ( + geometry['main_height_cm'] + + geometry['bragg_height_cm'] + + geometry['residual_height_cm'] + + (row_count - 1) * geometry['vertical_sep_cm'] + ) + + full = fit_plot_geometry(fit_data(phases=1, residual=True)) + main_bragg = fit_plot_geometry(fit_data(phases=1, residual=False)) + main_resid = fit_plot_geometry(fit_data(phases=0, residual=True)) + main_only = fit_plot_geometry(fit_data(phases=0, residual=False)) + two_phase = fit_plot_geometry(fit_data(phases=2, residual=True)) + + # The main panel keeps the same cm height in every layout. + assert main_bragg['main_height_cm'] == pytest.approx(full['main_height_cm']) + assert main_resid['main_height_cm'] == pytest.approx(full['main_height_cm']) + assert main_only['main_height_cm'] == pytest.approx(full['main_height_cm']) + # The residual panel keeps its height with or without Bragg ticks. + assert main_resid['residual_height_cm'] == pytest.approx(full['residual_height_cm']) + # The Bragg panel grows linearly with the phase count. + assert two_phase['bragg_height_cm'] == pytest.approx(2 * full['bragg_height_cm']) + # The reference three-row figure keeps its nominal height; reduced + # layouts are shorter and extra phases make it taller. + reference_cm = _FIGURE_AXIS_WIDTH_CM * _FIGURE_AXIS_HEIGHT_TO_WIDTH + assert stack_height_cm(full, 3) == pytest.approx(reference_cm) + assert stack_height_cm(main_only, 1) < reference_cm + assert stack_height_cm(two_phase, 3) > reference_cm From da7cb4c9fd2316928dd573a667bd9f82a462a28f Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 09:53:52 +0200 Subject: [PATCH 13/55] Store full canonical Wyckoff orbits via exact check --- .../dev/adrs/accepted/space-group-database.md | 34 ++++++---- docs/dev/plans/space-group-database.md | 59 ++++++++++-------- .../crystallography/space_groups.json.gz | Bin 108047 -> 112028 bytes 3 files changed, 55 insertions(+), 38 deletions(-) diff --git a/docs/dev/adrs/accepted/space-group-database.md b/docs/dev/adrs/accepted/space-group-database.md index ecc311217..e09bd7e1e 100644 --- a/docs/dev/adrs/accepted/space-group-database.md +++ b/docs/dev/adrs/accepted/space-group-database.md @@ -307,11 +307,18 @@ variable. cctbx's `unique_ops().as_xyz()` (the generator's raw output) emits **operator form** (e.g. `1/2*x-1/2*y`) for coupled special positions, which silently breaks `crystallography._fract_constrained_flags` so a refined special-position -coordinate drifts off its symmetry site. Canonical `coords_xyz` are -therefore re-sourced from cryspy's `wyckoff.dat` (the intended Wyckoff -source), matched by orbit equivalence; the invariant is enforced in the -unit tests and by `tools/check_packaged_db.py`, which rejects any -operator-form template in the packaged wheel. +coordinate drifts off its symmetry site. The **full** orbit is preserved +(`coords_xyz` length equals the ITA multiplicity): each cctbx orbit +element is re-spelled with cryspy's canonical integer direction — matched +by column space, since centering shifts only the offset, never the +direction — keeping the element's own offset. Every replacement is +verified **exactly**: symbolic orbit equivalence as rational affine point +sets (not sampled), plus a constraint check that `_fract_constrained_flags` +reports a free-axis count equal to the manifold's rank (which rejects both +operator form and non-minimal spellings such as `(x-y,-x+y,z)`). The +no-operator-form invariant is enforced by the post-process before it +writes, in the unit tests, and by `tools/check_packaged_db.py`, which +rejects any operator-form template in the packaged wheel. ## Consequences @@ -434,11 +441,14 @@ canonical-templates post-process then re-sources canonical ITA python tmp/space-groups/helper-tools/canonicalize_coords.py --write ``` -It matches each of the 288 coupled positions to the orbit-equivalent -cryspy position (one, IT 228 origin-1 `g`, is re-parametrised from -cctbx's own orbit), changes only `coords_xyz`, and asserts no -operator-form template remains. The `space_groups.json.gz` SHA-256 below -is **after** this correction. +It re-spells each of the 288 coupled positions' **full** orbit +(`coords_xyz` length equals the multiplicity) using cryspy's canonical +integer directions, matched by column space (one, IT 228 origin-1 `g`, +is re-parametrised from cctbx's own orbit). It changes only `coords_xyz`, +verifies every replacement **exactly** (symbolic orbit equivalence as +rational affine point sets plus a `_fract_constrained_flags` rank check), +and asserts no operator-form or fractional-coefficient template remains. +The `space_groups.json.gz` SHA-256 below is **after** this correction. Build environment: @@ -456,12 +466,12 @@ Generated and curation artifacts: - `src/easydiffraction/crystallography/space_groups.json.gz` (after the §9 canonical-`coords_xyz` correction): - `234a9aeb9579c67fcb1a924554714407498cbb34fa94c8562b4dd454e9503225` + `9ef3e34cc7f88997028789701ba05374fe0999f1d16a80b14f2a381c022bc358` - `tmp/space-groups/helper-tools/generate_space_groups.py`: `3aa5f03cd1a69bdfe0a280158c9343b65d5eaa4d75a6d58f2606fb5fbe3df83d` - `tmp/space-groups/helper-tools/canonicalize_coords.py` (§9 canonical-`coords_xyz` post-process): - `c6b2b1ac50d59f6546c9fc9eadebb49a637ac4d6fba589a2a4a1d80deeb10e37` + `1cd5b36542c034b530f6c90f30c7b4de0c291c16b7302c3d57730790570031d2` - `docs/dev/adrs/accepted/space-group-database/space_groups_overrides.yaml`: `7077eec25d0f3b852dd7096a24dc7ac438467f9cb594f91a65ce10cda0e0722a` - `tmp/space-groups/extracted-comparison/disagreements.md`: diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index d06b281cf..1f6143db5 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -320,20 +320,25 @@ cryspy's `wyckoff.dat`, already holds the canonical ITA form for them (`position.unique_ops().as_xyz()`, operator form) while cryspy's `wyckoff.dat` — the ADR's intended Wyckoff source — was read only for count-validation. A local tool loads the bundled DB and, for each - position, **matches the orbit-equivalent cryspy position** (orbit-based, - not by letter or block index, since cryspy and cctbx differ in letter - labelling and representative choice) and replaces `coords_xyz` with - cryspy's canonical orbit. Canonical form = each component a signed - single free variable (or an integer-coefficient ITA combination such as - `x-y`) plus an optional rational constant — **no fractional coefficient - on a variable** — with each genuine free DOF reduced to one canonical - variable so dependent axes' symbols are absent. A cctbx-free dry-run - verified 3512/3826 templates directly; the ~31 edge cases (rhombohedral - `r` settings + cryspy/cctbx letter/representative differences) are - resolved by the orbit-based match, with any residual ambiguity curated - against International Tables. _No cctbx re-run is needed (the dry-run - proved the post-process viable); the rejected alternative — fix the - generator + full cctbx re-run — adds a heavy install + reproducibility + cctbx orbit **element**, re-spells it with the cryspy **direction** + (canonical integer rotation) that shares its column space, keeping the + element's own offset. This **preserves the full (centered) orbit** — + `coords_xyz` length stays equal to the multiplicity, matching the #187 + baseline — while fixing only the spelling. (cctbx stores the full + centered orbit; cryspy lists only the **primitive** orbit, but + centering shifts a position's offset, never its direction, so every + full-orbit element's column space appears in the cryspy position.) + Canonical form = each component a signed single free variable (or an + integer-coefficient ITA combination such as `x-y`) plus an optional + rational constant — **no fractional coefficient on a variable** — with + each genuine free DOF reduced to one canonical variable so dependent + axes' symbols are absent. _Rejected alternative — replacing + `coords_xyz` with cryspy's orbit **directly** — silently reduces + centered orbits to primitive (cryspy's printed style), breaking the + `coords_xyz`-length-equals-multiplicity invariant; the review-1 + [Finding 2] exact check caught exactly that and the element-wise + re-spelling restores the full orbit. No cctbx re-run is needed; fixing + the generator + full cctbx re-run adds a heavy install + reproducibility risk for the same cryspy↔cctbx reconciliation._ 2. **Verify each replacement two ways** (review-1 [P1] plus the CT1 correctness gap): (a) **exact symbolic orbit equivalence** (`sympy`) — @@ -414,19 +419,21 @@ only ignored files, and no empty commits. - [x] **CT1 — Canonicalise the DB via the cctbx-free post-process.** Finish the local `tmp/space-groups/helper-tools/canonicalize_coords.py`: parse cryspy - `wyckoff.dat`, **match each DB position to the orbit-equivalent - cryspy position** (orbit-based, not by letter/index), replace - operator-form `coords_xyz` with cryspy's canonical orbit, and verify - per position — exact orbit equivalence (mod-1 membership) **and** - correct `_fract_constrained_flags()` (free-DOF count + dependent - axes). Curate against International Tables any case the orbit match - leaves ambiguous, recording it in `space_groups_overrides.yaml`. Run - it to rewrite + `wyckoff.dat`, then **re-spell each cctbx orbit element with the + cryspy canonical direction sharing its column space** (keeping the + element's own offset), preserving the **full** centered orbit + (`coords_xyz` length stays equal to the multiplicity). Verify per + element, **exactly** — symbolic orbit equivalence as rational affine + point sets (not sampled) **and** correct `_fract_constrained_flags()` + (free-axis count equals the manifold rank), rejecting operator form + and any fractional coefficient. Curate against International Tables + any case the directions leave ambiguous, recording it in + `space_groups_overrides.yaml`. Run it to rewrite `src/easydiffraction/crystallography/space_groups.json.gz` (R-3m `h` - → `(x,-x,z)`; all non-`coords_xyz` fields byte-identical). The tool - is local tooling (recorded by SHA in CT4); **this commit stages only - the regenerated `space_groups.json.gz`**. Commit: - `Canonicalize space-group coords_xyz templates` + → `(x,-x,z)`, 18-element full orbit; all non-`coords_xyz` fields + byte-identical). The tool is local tooling (recorded by SHA in CT4); + **this commit stages only the regenerated `space_groups.json.gz`**. + Commit: `Canonicalize space-group coords_xyz templates` - [x] **CT2 — Fix the generator's coords source for future rebuilds (local prep, no commit).** Update the local `tmp/space-groups/helper-tools/generate_space_groups.py` so diff --git a/src/easydiffraction/crystallography/space_groups.json.gz b/src/easydiffraction/crystallography/space_groups.json.gz index 135015187be0422126c03d35164c8a745b58d0af..9d9728d8c9806ff60b9f13aa1d8341d064496184 100644 GIT binary patch delta 75053 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 delta 71059 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 Date: Wed, 3 Jun 2026 09:54:35 +0200 Subject: [PATCH 14/55] Document two-stage canonical rebuild as invariant step --- .../dev/adrs/accepted/space-group-database.md | 15 ++++++++--- docs/dev/plans/space-group-database.md | 27 ++++++++++++------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/docs/dev/adrs/accepted/space-group-database.md b/docs/dev/adrs/accepted/space-group-database.md index e09bd7e1e..aef1042b9 100644 --- a/docs/dev/adrs/accepted/space-group-database.md +++ b/docs/dev/adrs/accepted/space-group-database.md @@ -432,10 +432,17 @@ pixi exec --spec cctbx --spec gemmi --spec sympy --spec pyyaml \ --print-summary ``` -**Canonical-`coords_xyz` correction (§9).** The run above emits cctbx -operator-form `coords_xyz` for coupled special positions. The -canonical-templates post-process then re-sources canonical ITA -`coords_xyz` from cryspy's `wyckoff.dat`: +**Canonical-`coords_xyz` correction (§9) — mandatory second stage.** +The rebuild has **two mandatory stages**, and the generator run above is +only the first. The generator emits cctbx operator-form `coords_xyz` for +coupled special positions and **cannot** emit canonical form itself: +cctbx always produces operator form, and the canonical ITA spelling lives +in cryspy's `wyckoff.dat`. The generator alone therefore does **not** +produce a shippable database. It **must** be followed by the +canonicalization post-process, which is the **invariant-enforcing step** +— it re-sources canonical ITA `coords_xyz` from cryspy's `wyckoff.dat` +and refuses to write unless every template is canonical (no operator +form, no fractional coefficient): ```bash python tmp/space-groups/helper-tools/canonicalize_coords.py --write diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index 1f6143db5..6db16a140 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -434,15 +434,24 @@ only ignored files, and no empty commits. byte-identical). The tool is local tooling (recorded by SHA in CT4); **this commit stages only the regenerated `space_groups.json.gz`**. Commit: `Canonicalize space-group coords_xyz templates` -- [x] **CT2 — Fix the generator's coords source for future rebuilds - (local prep, no commit).** Update the local - `tmp/space-groups/helper-tools/generate_space_groups.py` so - `_extract_wyckoff_positions` sources `coords_xyz` from cryspy's - canonical `wyckoff.dat` (not cctbx `unique_ops`), plus a - generation-time invariant rejecting operator-form leakage, so a - future rebuild stays canonical. **No re-run now** (CT1's - post-process already produced the canonical DB). Local curation - tooling — not committed; its updated SHA-256 is recorded in CT4. +- [x] **CT2 — Make the durable rebuild path two-stage with an + invariant-enforcing post-process (local prep, no commit).** The + generator (`generate_space_groups.py`) runs in a throwaway + cctbx-only env, and cctbx **always** emits operator-form coords for + coupled positions — so the generator cannot itself source canonical + coords or self-assert a no-operator-form invariant (the canonical + spelling lives in cryspy's `wyckoff.dat`, and the constraint check + needs `easydiffraction`, i.e. the project env). The durable rebuild + path is therefore **two mandatory stages**: (1) the generator + (cctbx env), then (2) `canonicalize_coords.py --write` (project + env), which is the **invariant-enforcing step** — it re-sources + canonical ITA coords, verifies each exactly, and refuses to write + unless every template is canonical (no operator form, no fractional + coefficient). The generator's `_extract_wyckoff_positions` docstring + directs to this mandatory post-process and the ADR _Build + Provenance_ documents both stages (review-1 [Finding 1]). **No + re-run now** (CT1 already produced the canonical DB). Local curation + tooling — not committed; its SHA-256 is recorded in CT4. - [x] **CT3 — Packaging assertion.** Extend the tracked `tools/check_packaged_db.py` to assert no packaged `coords_xyz` template is operator-form (catches future regression at the wheel From c27c23e896da897a378a720c938328a8a3e01ce9 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 10:30:36 +0200 Subject: [PATCH 15/55] Build full Wyckoff orbits from cryspy primitive and centering --- .../dev/adrs/accepted/space-group-database.md | 52 +++++++++------- docs/dev/plans/space-group-database.md | 58 ++++++++++-------- .../crystallography/space_groups.json.gz | Bin 112028 -> 113362 bytes 3 files changed, 61 insertions(+), 49 deletions(-) diff --git a/docs/dev/adrs/accepted/space-group-database.md b/docs/dev/adrs/accepted/space-group-database.md index aef1042b9..3978b598a 100644 --- a/docs/dev/adrs/accepted/space-group-database.md +++ b/docs/dev/adrs/accepted/space-group-database.md @@ -307,18 +307,25 @@ variable. cctbx's `unique_ops().as_xyz()` (the generator's raw output) emits **operator form** (e.g. `1/2*x-1/2*y`) for coupled special positions, which silently breaks `crystallography._fract_constrained_flags` so a refined special-position -coordinate drifts off its symmetry site. The **full** orbit is preserved -(`coords_xyz` length equals the ITA multiplicity): each cctbx orbit -element is re-spelled with cryspy's canonical integer direction — matched -by column space, since centering shifts only the offset, never the -direction — keeping the element's own offset. Every replacement is -verified **exactly**: symbolic orbit equivalence as rational affine point -sets (not sampled), plus a constraint check that `_fract_constrained_flags` -reports a free-axis count equal to the manifold's rank (which rejects both -operator form and non-minimal spellings such as `(x-y,-x+y,z)`). The -no-operator-form invariant is enforced by the post-process before it -writes, in the unit tests, and by `tools/check_packaged_db.py`, which -rejects any operator-form template in the packaged wheel. +coordinate drifts off its symmetry site. A Wyckoff orbit is a list of +**distinct point-functions** (one per symmetry-equivalent site), and the +DB stores the **full** (centered) orbit — `coords_xyz` length equals the +ITA multiplicity. cryspy lists only the **primitive** orbit, so the full +orbit is built by **expanding** each cryspy primitive element over the +group's centering translations (the identity-rotation symops): +`full = {primitive element + centering vector}`, yielding exactly +`multiplicity` distinct canonical templates. Every replacement is verified +**exactly**: `len == multiplicity` and `len(set) == multiplicity` (a +proper full orbit with distinct elements — no collapsed duplicates); no +operator form and no fractional coefficient; the representative's +`_fract_constrained_flags` free-axis count equals the manifold's rank +(rejecting non-minimal spellings such as `(x-y,-x+y,z)`); and +parametrization-independent geometric equivalence to the cctbx orbit +(every element on a cctbx manifold, every cctbx manifold covered). The +no-operator-form and no-duplicate invariants are enforced by the +post-process before it writes, in the unit tests, and (for operator form) +by `tools/check_packaged_db.py`, which rejects any operator-form template +in the packaged wheel. ## Consequences @@ -448,14 +455,15 @@ form, no fractional coefficient): python tmp/space-groups/helper-tools/canonicalize_coords.py --write ``` -It re-spells each of the 288 coupled positions' **full** orbit -(`coords_xyz` length equals the multiplicity) using cryspy's canonical -integer directions, matched by column space (one, IT 228 origin-1 `g`, -is re-parametrised from cctbx's own orbit). It changes only `coords_xyz`, -verifies every replacement **exactly** (symbolic orbit equivalence as -rational affine point sets plus a `_fract_constrained_flags` rank check), -and asserts no operator-form or fractional-coefficient template remains. -The `space_groups.json.gz` SHA-256 below is **after** this correction. +It rebuilds each of the 288 coupled positions' **full** orbit by +**expanding** the cryspy primitive orbit over the group's centering +translations — `coords_xyz` length equals the multiplicity and every +element is distinct. It changes only `coords_xyz`, verifies every +replacement **exactly** (distinct full orbit, canonical spelling, a +`_fract_constrained_flags` rank check, and parametrization-independent +geometric equivalence to the cctbx orbit), and asserts no operator-form +and no duplicate template remains. The `space_groups.json.gz` SHA-256 +below is **after** this correction. Build environment: @@ -473,12 +481,12 @@ Generated and curation artifacts: - `src/easydiffraction/crystallography/space_groups.json.gz` (after the §9 canonical-`coords_xyz` correction): - `9ef3e34cc7f88997028789701ba05374fe0999f1d16a80b14f2a381c022bc358` + `390f0e9d0ebe27a52ee5680a1bc686123ba84c8751302fed4dee4dfaf7edf7b4` - `tmp/space-groups/helper-tools/generate_space_groups.py`: `3aa5f03cd1a69bdfe0a280158c9343b65d5eaa4d75a6d58f2606fb5fbe3df83d` - `tmp/space-groups/helper-tools/canonicalize_coords.py` (§9 canonical-`coords_xyz` post-process): - `1cd5b36542c034b530f6c90f30c7b4de0c291c16b7302c3d57730790570031d2` + `8f2e94b130481d2a11de057fe200d8e5fd5d3d5eec7cdd39f5d4afd13f5cb8f2` - `docs/dev/adrs/accepted/space-group-database/space_groups_overrides.yaml`: `7077eec25d0f3b852dd7096a24dc7ac438467f9cb594f91a65ce10cda0e0722a` - `tmp/space-groups/extracted-comparison/disagreements.md`: diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index 6db16a140..3e0ef990c 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -319,27 +319,30 @@ cryspy's `wyckoff.dat`, already holds the canonical ITA form for them generator's `_extract_wyckoff_positions` built `coords_xyz` from cctbx (`position.unique_ops().as_xyz()`, operator form) while cryspy's `wyckoff.dat` — the ADR's intended Wyckoff source — was read only for - count-validation. A local tool loads the bundled DB and, for each - cctbx orbit **element**, re-spells it with the cryspy **direction** - (canonical integer rotation) that shares its column space, keeping the - element's own offset. This **preserves the full (centered) orbit** — - `coords_xyz` length stays equal to the multiplicity, matching the #187 - baseline — while fixing only the spelling. (cctbx stores the full - centered orbit; cryspy lists only the **primitive** orbit, but - centering shifts a position's offset, never its direction, so every - full-orbit element's column space appears in the cryspy position.) - Canonical form = each component a signed single free variable (or an + count-validation. A Wyckoff orbit is a list of **distinct + point-functions** (one per equivalent site), not a set of manifolds. A + local tool loads the bundled DB and, for each operator-form position, + builds the **full** canonical orbit by **expanding** the cryspy + primitive orbit over the group's centering translations (the + identity-rotation symops): each cryspy primitive element shifted by + each centering vector yields one canonical full-orbit element. This + **preserves the full (centered) orbit** — `coords_xyz` length stays + equal to the multiplicity, matching the #187 baseline — with + **distinct** elements. (cctbx stores the full centered orbit; cryspy + lists only the **primitive** orbit, with centering implicit.) Canonical + form = each component a signed single free variable (or an integer-coefficient ITA combination such as `x-y`) plus an optional rational constant — **no fractional coefficient on a variable** — with each genuine free DOF reduced to one canonical variable so dependent - axes' symbols are absent. _Rejected alternative — replacing - `coords_xyz` with cryspy's orbit **directly** — silently reduces - centered orbits to primitive (cryspy's printed style), breaking the - `coords_xyz`-length-equals-multiplicity invariant; the review-1 - [Finding 2] exact check caught exactly that and the element-wise - re-spelling restores the full orbit. No cctbx re-run is needed; fixing - the generator + full cctbx re-run adds a heavy install + reproducibility - risk for the same cryspy↔cctbx reconciliation._ + axes' symbols are absent. _Rejected alternatives: (a) replacing + `coords_xyz` with cryspy's orbit **directly** silently reduces centered + orbits to primitive, breaking the length-equals-multiplicity invariant + (review-1 [Finding 2]); (b) re-spelling each cctbx element by **column + space** collapses distinct point-functions sharing a manifold into + **duplicate** templates (review-2 [Finding 1]). The centering expansion + avoids both. No cctbx re-run is needed; fixing the generator + full + cctbx re-run adds a heavy install + reproducibility risk for the same + cryspy↔cctbx reconciliation._ 2. **Verify each replacement two ways** (review-1 [P1] plus the CT1 correctness gap): (a) **exact symbolic orbit equivalence** (`sympy`) — the cryspy canonical orbit and the cctbx operator-form orbit describe @@ -419,15 +422,16 @@ only ignored files, and no empty commits. - [x] **CT1 — Canonicalise the DB via the cctbx-free post-process.** Finish the local `tmp/space-groups/helper-tools/canonicalize_coords.py`: parse cryspy - `wyckoff.dat`, then **re-spell each cctbx orbit element with the - cryspy canonical direction sharing its column space** (keeping the - element's own offset), preserving the **full** centered orbit - (`coords_xyz` length stays equal to the multiplicity). Verify per - element, **exactly** — symbolic orbit equivalence as rational affine - point sets (not sampled) **and** correct `_fract_constrained_flags()` - (free-axis count equals the manifold rank), rejecting operator form - and any fractional coefficient. Curate against International Tables - any case the directions leave ambiguous, recording it in + `wyckoff.dat`, then build each operator-form position's **full** + canonical orbit by **expanding the cryspy primitive orbit over the + group's centering translations** (`coords_xyz` length equals the + multiplicity, all elements **distinct**). Verify per position, + **exactly** — `len(set) == multiplicity` (distinct full orbit), no + operator form, no fractional coefficient, correct + `_fract_constrained_flags()` (free-axis count equals the manifold + rank), and parametrization-independent geometric equivalence to the + cctbx orbit. Curate against International Tables any case the + cryspy match leaves ambiguous, recording it in `space_groups_overrides.yaml`. Run it to rewrite `src/easydiffraction/crystallography/space_groups.json.gz` (R-3m `h` → `(x,-x,z)`, 18-element full orbit; all non-`coords_xyz` fields diff --git a/src/easydiffraction/crystallography/space_groups.json.gz b/src/easydiffraction/crystallography/space_groups.json.gz index 9d9728d8c9806ff60b9f13aa1d8341d064496184..198668e13220fc50fabbdeaf608007839b896913 100644 GIT binary patch delta 76299 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%0D{n_es_#hT`tL<77m@ej^t$%)TQt- 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 delta 74899 zcmV(~K+nI@^#+{l2Cz$#f9N)|KHqeFZCXuDpbM;7%%24^`bIkRS+v03yP}{q*CV z<^9g`o|)yn_Q{`(K(~A;*G9}sk%{HKu4lyZ?%kMtEbnza6P92}v={fb+7jnJ2!5(B2RYZ}(cKFavLqCR3rqG{cO|+-Bm}36HxRa<7%U z9Dlz|cKq$M-Lq6b4u5`E)TZy3D6{rI6O^ag_B}47q{{rgN`H>1;$6Z2eyIHwV^$-@ zm_By+gsL3!V2O_5e&SIC^rZ_Epo?1a>1r%h&D8Jc3 zp<(7gmdUJI7-zrEqHGB$9{Z>eY&y7%*5G#`p!N3iQ$CEIkG&};G6J02j%5fr2s(Z$ zaVC)8$ja|y<#0TH7k#^^vuqa$?9SI6T+BPqF2^%!NI1rR1r@{ES{-D#j|r$+2yTY)O+Zc)DqaQ%{b6i(7je zz5r$r`mW>8%Nt+pgf6fcjG-9fh!d@8qgF@ZDYTkC9;U)iU@;-K0%V@KtwH}Pbu3}{Q$B`9^Wk% z?{4~)2ZJP@=SW8*O>_)jTEHU1edoIC?|YfPOFd>cfj~-8G}4figEC8kGiIGbhog*@v}O6Nj~Oh(^Vm>2H~J`BbBzMwCGk ze^BX7d0*8iq6=k4@=o(J;bm2*6e<3kjd!TtV>+eNss*&7(Rs3A zmhhVcsZh8s!{A=T)ennCwdPR@ND}H`e_;-kQ|52BvOHj|Bi;IOQ^H)eI2(ruzbzUh z;^t+kStbdGms$@4@1=|>WSP2wyOe}=%0Bs2>YXexKb zUK3;YYO%5@_UzBMyk~cNkpfKif86o2XP%>MX-(SzEXbZBIrbFCv1c%iY-vtK_Lol+ zsc6tG$6>9na^z)iVi)_(>uSGA%`*lJFM*6qWEM+qfQ_Rem*&LNj0u%ZvABP^A*L~E zm_ceX!YUSEpiOHGERZ4Q)cgN)lSej$RJnaM`v!Y`C(LvnAY#uOB^exzkbnLyixGJU%}mDzGqiI)-+JIF$i6{Y zv-;_DGf$OQeYMO4S-uIoe_%DGRgi%|@YN`YU$%c0ib?pK{fUJ!K56HRQ6yR3XLa`9 zyq8!-=ow$NFa#rImZxK|4Y>M^<{Sx#SY+2ZTrb<$Rd(Zzz6uTos3@#lhhy1)pDYkC z>8knly#xWg&{^S!<1bUAv=&&<0(F`mA^kihT5Eyw=+XPwIpCdKe}WtLP{o8s$zzWF z@+HN7>5G*L+A*UrQ@QOD9!5yAv(5%XwRsOaY%(m>JFrWrYd(ivGJ$YR_|D<5GUp(o zi_0SUbCy{oIa%mvBKqvTTQUP(yKG;7ZOv}Z$ufT?z-G;aeJ*>p%mmDH4vFKl^wvcL zxk~5TAT}?!5s^-Ee;iJ?KHQY(!!+4GIFC6HE#ZKtD0NCpWrNSmf9#tcl>Xe6fm$dM zPX6a@petr`5W~kXatMP*u=EG8WBo@afMf@;jFH7Z697nV;V_m1L2?U+vstEnJ>OE= z7rPbof9KKiOlf!(y%x;lprIw76+URJN+5v(I6gxY-G0x(e|fll_#Dl7=;IUeqdW}o z5rLY(gA>yoX7d+;=M9^flj<TaqCEAL?3j}Yg zNscg<%pc3f4-{H)M(ATodJ7hf$05&Vo**ZKkjJ@E!G&z;mCdoGZ<1{3o5Fj#i~C{G zf$)fXdo`E6f8EsuaeY>U_Vp(Bz8>k0;QRaJZi$z7x5xXsDSBTG-s`Km@AbZJir%+{ z_xL#K%1J0qtpc!M1f;&CrV!(BzNZP^{n9hHm^ZDxxHNg=A+|SS&o@JY{Q$YWPML| zaulw!OQL2MtjSj@E5Pg{#P4#a1eh2W&8qe#yj z{SZv7qU6Vuno=uZN`c58klkYHKaNI7vhN9ue-hBzH9Mxl>o8W|N*VDh(L@xd7#bz3 zzDF9)pB59?I2HHzWqkEM@r>#z@Jts!B z!h=ao7DK8^5KVF?GH@`Zx-n0Ks0@_&QfA>7$sQUsJJ!4c)lFhzeZ376tKVfb((VzD ze@c`J@MU5Jn09f|++B&CcM|z-K(VU^%;#B|DY{uUcLpJoP3gevXhlrdjJc9=r$6dg zcGz!MnfBXw&*iUd+bzNTIe0RQu|8<~WfBi3sdAES_{%MB!z$>_)AL!BE@28!=tays zB5Q0j(@i+e13H7f&dz(M3#J69);adNf9(}#7`oM&gh<8FhBdliT!);DmvrkowIXu2 z8q~r!s5%eB-QPE{L4mCWT#V|bxoCO9I0<-T#dkTz2~3#2_g|AS#)|J^(VJ*U#Uddb z5!luOBpm*|Rc)^CW!}b$ZFc^(Rrb?wbGN>~-U3YT%ba0)pJxN>+RO^p^)e&qf8G2c zW{){eubUL7*G=~0t3+TWBGGXEX@=u$3I~i((Ds^DUs3HgiTTz1#>Q=yuUI zPdUz%FDcHHDbY6LLuDs?VqkF3fA~v`q&;NzTN!)Mlxv&hu=(Sr51YM?GFLb~U-fu750F0a|mwVAADn-|J+ zD!a|Qk<%D%{+Q_CD z{xd-w;x;V0Jh{`KH8~V-po>dtNNu!17M@nYcxgL5`Lw1q&j0MLZ%ty79G4NeKB;Zx0=OP zb_#>fNzW7HB3bZdoh?q{OAZK}b&S;&Hc00YNgzq^D{^2pSo8x17ya1k`Ljwuv z1-4#y%7<-KB*DB^;vPvb11JA51`rTOaLO7Q)anFpf8&`(!)D3RjEDo+u+ih*6P)!f z$FH!O*-5N--b$K_{y$S4#f<2Fmp%1Kq5$3*K;kpKp=<7WMDokf*aca)|GyG`dgxbf zA^W`W-cXN?7C5umcWCcPfBm1yvXokox+L_JMVU*k2~BeHlXd8y|DGuBV>12f{Uhm{ z|0>Zpf4ik@Nr?f69hMZ>EfFjhsxSeWc?iAL9GL%EroXJ%TUP8VEB2HX`^n0^WTif` zau0Fu>Ayo7`OcNK!^{;a8CCAKAm`xl~-OIf#^FG!i(rEDr=@e;ymwF$! z_@6~1qfx2-Eb|_yqrHB25p(&g)caVm)sDaFe{wEACeH}<1Us0RJO~=)T5Y$5)L*`p zXk@7ROO$@jHa{ujmvZe3Cbo=F(CIo4T<2j%8J&>k*jy?)K8w1qoZaDXqF=Os(V-JeBof-ki|HMr4zGP0Kk2U< zfAW*UyjL%!<>36uw`j)~jeim$@kt7DV;bp9?Aiigm_78S^nI|f#E zDrsPC4Qhaxqv#T2{aFgfypp{LE8s;~0WX65djsleUWZCa@SF^r{0k@E-V<*p%Y zePTWqniehVymq;#c87C1nRDO$U5=hYJhrx|!00S!D_~WV1GMbwX)X*D&@gu4!~a>T zFRk2@mh__~y=XxnTF`?QfA^ooy*FR?%mSv9nbyN$vMl~~1tzknQq zik)cZVIyXSkW2-?`Tic@4--R3zRfl7C!N%!3DcU4%_X6IXDZJqzL**Ui_XRkDXMUV zpomnc+*RdEU&)GHe{s;;oP|V2<1LX<-GD@fkFV#(0T*`WaEow(jK?g1i(k<^A#Z?- zO-96pY&C02h8lwiHQSRQFa``F7Zir{J49j(7)H8ij4Vte3SJ@+lLDQZ5i`e1(*nQL zIkiPkPVg-%Q2VlieM!s=xi1^NFB^xx{5~Or#{yEtbnpQyZhN~kdMqF>%;jlKoWgto zOJ5C}lc@QEK<%|s7K;ZBS&#tbJS_hNf#EPa3RGn$3Z*B6JuFBdl|Ub6Vd;luZMfvH zOl|Gw^<&K?e}=Dl&gK%suW&oVc`}}|u!X)P5KBtPl7aXv45XVFh4m4?g-_ar1AS=6 zdKXeIM!%0}L{EN&;e~nAE=H#JpuaOvih?IhW8D9J6XAKzSYZ@<7KH0Lk40$Og(uBu z1X~868%@NL@v{K!C}Xqmqohbjb`e9)(YrH`W2CfPe@}M`YSVa^zF07rGip)%s^$^XSshz@h6eBuYiG_&xWX&vH$$-|ktdPbDy!L8<0&(z^W_&Emh#Ls~+-G$hF8AKwV$)x@*3E!1Q z-W0-+6{C&k8I&Ymojew@Clx%T56P;H7tlx%_HUEf$SG2Pw<);RKPAunJ!kO^Em349 z3mLx<{5!UeV={e@!N{S7EQ5ii3||EPe?4?kk<8vsUuVkd6`pX<=+!fNuiXZ7VEwt) z74R>ze$!^~o^p|K5_4iJ_}KAN15*j5xlDnM$kF}pp=|5CQ0=<{*6rI7iP^U+Y0N8> zIw?-&w*qYQu9Oc-PI-HMkOPPD^j0pgIl~FH@;+_GR<3A!hUv29dCJsQu0Kb(f1Z6j z2Wz)DoA&2-#im`vx`iptjT_ng%dJp;f0{Anw{Gb+HcK>k6H8P577hMYG8i0%$rTB& zjz@LInH3To9^z~Tf-AQmvB6Z;CM{KUQ0O)Qlbiaf)0oZQ-a*hfF=m$#VqHJ75LkVlZ#b=(}cq?KRgbU%gkd+2m z2UYqwLjBwJVH<58Y#wSqe;SX0hU0~%K7s0G;NkyxnHk(XDpCe-G@N*O4a<)g(xp315reYGt@W63mfp++mfL+S{qzstN6FeLrd zYqh!jv)uR~Ib3fQ<2X&HgySP>3j-x(FxxbO%OBIzqlSC|El#Ps-A1Q|79iF2=|_f5 z2y({Nd7N>Z=={~qL%qr5jT?vQU4grv`Kq4YI0wM4?3K%%pGy2?2?=pso-mD9?mutP zD+m2t0f5@*eAEc9oF|Z$dFTA|PyaPp{wW&wv?b!h*^hZVej94ydrP-H zeojql>`Pv(OR@NpB$LPN=ipUpVVbsU;_ySQg{J3Q%2UdG9V+=v~nokWLRN%OwEZs0rtv(q*6zolsPX?n5AQ{3RoU4rL%5uDtFVuO)=;Dgw8sPbCWK8=;^RqKxHB90K~ad3peB9 z+tdsRskjham=&BT8r*fLrc)-fjNBnyfy~G8N5#=%mC4ewOMo1j3g^%?yogljm&()N zX7sXrfAVnJrQu`Hs23dByp!mlc{_1xuYAHRAek}@6OA+RgsZpb)1=Ne7oVDk3SW?W zBbqlO-o0@k&e%NEFaE?CV~+uHYCxSeM^o$Ol4sRmxac<$9eEjo{$TPpSHypa#BEMwpLE9>O1l~3eCx#6b=8m;%gAM+PofQr~72=7h!aXsYGG=~GpVrh) z43+A~hr)GMR6mu*bW2t!O9^d*oEfV;SdCw?>hZrG>Vi-WFXkUg|H-`>DWMt*K_tMC zG78y9nVXaVG*KR=F|n89*E@h{L^2FHf6#)ucscSyG%yjUJ5?xwYWU|qZS&{z7&+BQ zn>YFe&S_1C%KzafNLNgpx6*^VtSIb6_Vrw0C%}VrMWw752^Y0g#o2wI)%nk>dHOu;-_V^Za}%`F6=XKb52B z=W{ur2TY#wNw;zXJ{E)-SdT7u zWkvh4fqhxQzHC@uHmonJ=~EG7QB{7Jt7ue}0=b&n2NsL>(@=fW^X}Nhs%TUDzpUaJ zamKr42CB^y6Ld$ZC3G+)01JL9W*JaNQN8zKBBQ^3ewpVf8s<3)nF_#QCx$kOydUoaZ@zc{jQ_ns^Ug!KayH^8K*QnKM{;RpWh{c>}HNcztnD@gY3A*f8a`3QK zZ)td6mr1C09c;(PJho#zmg3h#oj?1C&3Q7G*e?>}VrXQ1; z=iE3R+s0(lY16iVe{$0-vkpQs2*NWJ=ACuWig`L3R7XSdsPp3MgbF)~`^f>Olr8QW zsYnx{w&S2o^SOw5SB6<~7FPJ|5)S-?N`iq2(@Ckso5)XjC_1(Y$*|>OtiM0oiZ)Ej~-; zjq(=sR7VF%>qrYGi5mR3vXj6=peY2hg!)D{WKk-l~x%qsR*OK<>* z5~OFQ9O+ZG_a3H+d#ferHi?teV*y*_?exT~krirx#j>!(VR|b-U3N&@qLT(EwY@&9 zTR01w1PMEcz|WgF_C|eee#?qy0S??fd1)ag78XEKAR})CYvZJ!YcxYyBFnouQx!5 zWiH{B=|U?Ln=*gBqp(V%yf-2M$4r?#VHL;(A54MX>(y|&rxHNAP72eW=0~9+xn@Y= zL1Rzof85W~w|JpEP|dLM(}L|3!^1`1&cmD;8zxH^$v;I2(85;gE_`sMUi`qV7C=EZU;$KHY6a%c8$&))TX z25%$<(rOq)lrJPkEazJ$gAsvqoP&`FCXPC!+u zj|vLR&xh`*d{S$SN?T-BtHe*TlNn0IZ_zI0UjwpLQ9>*mgURx7-M$=k4s|aGR%1&u zL4a#9&#$pR&V$O#f$S{D1;J8tsU`{{EVtrLZNs;9^LA*_ZAl@c% z6mN`Zb!FfTWV3OM>KP$D)JcZ|vDFlf@{t%{V1$pw_ew|iP-Jg5sk`pcf4p;3_UHe} z7}d)PC3cJKZEq;DhhW1Y^rgwDgYxItvWTBT4K#h^&pSujGvcR3`{okq^VAM4msefH zAFm`V#)cs^h%e`g4A3cg-i z(V8pPsEWOg7O44AWMZ_CP{QMP@^j-uSK-B>pb|O6m3tIdAq<3`j31LnRXW?ErCYA0 zTeejqqqP!QrQ5OPfzg_WRc|)x5*jP<6K~Ts+VVtQR`HPnKOt_ef5V+p47@|Tl1ck~ zx`h2DaqbhymsQT^G z!}j5GMCjWr@-4y0}NMy^FiJzBs$eSV@DJks=@DZ6QhT-0xu zn`32WP}!lhJzldn!@6``TEszpdF0@U-3Jby$9=KK!^L{s&%3i*?l?Yc$PXxT2mL(egF$rg$O0}e+4XyAhB(_#ll{m>XP@POFmD2XOXlCG}wPb-&UIWfd%q6x!CNy7J)IrBXzFRc3{4_!76B_oi*ZURsZ3IynB`I6Z z#drH^tRANJv+Tz@l)RnEo`K`6Ih4QsEj#3n^*_n?pQ~@=$DeC|dwPTKeu9mAVzrxN zf5ou+%ga}&bx*8s&b8yNSzl^jj~yu9U}Z*Y zTo)&2Vl+g+!9nSqIy)=gR;>%!j@VzMHz_}s3*hieDH!xh@&MD-nrv$gkX)$A{$a`H zbH0_h}%sH#O!1d&eaYo`+42fG!h{SC;61Pc!#P#QnDUZPQ>Ei5qK&F3`Ip(GRBas;QPnd3{B>~w!_=vXM|a}qUKg7;MV(#Mxee?@pJ%0?gp zYZJK^lR!;3NuZ{iLReGTSLBU1Z7ANf%8NH0FhH9#5Wx>~+F;CSRT^`OJdlBi(=|n$ zHsukg{b@*)V>Ps?!D!P(S+r>uu4xC<=?r+Mzr6$Gse(ofN1rwh=+kN%^eIOih9gib z4T0Ls1A)rf0V2_-l>_>;f0+;Z6eE%2k*AG@Je@@@ZwD|~DS*L70SrDVfWbyV%{_5I zVZ{N3YYr%UQUHZ(1yEQifWozc>8m*4@QDKs8xAO3bHHF+E^t=bVoK@R*)A*u)?qNA z2fcA;A&2-sNJ{cD%NCT7J#7V&*1Me`BQjCFRGg@7=_5QA|DO-|^Ul+?6{&l9?M zEs83Um=f`4TNDZlN&D|b%wfjbp3p-zKJ(e|yi>TAr&_nz>qs&ei$@ z&()gE)hc+dJ|>>4|BN_*{WHx0tQX5`mb=Aa^Bc_R-J$HY4zcuz+Hc+*HbU|7$Kw^l zb^TahYvj_mdh27o*W&OmYQKE#mYJLu|LOD@@#D_#Q=S&bF2dg25rYkb86?#{nn&X& z4Q7+@q|uxbf1fm*SrO;GCgFK+DW68AzPOy3ldfn^@S6Y5v7)_hzW>{GNjrYbo%FZY zABwIG{W}WpuP+nruZNc&XED6~Jhip-2A^*Ozk#RZCr}gq5tx4@-q!^r*YbE-ck@4| zi>8I*g!yP(Dq8#8?*iWbJFcEyES~W zI8OJPLFwgAx%h0?E|~=;IS!W%LP_^ihm18hx7M*AhNZ>9vNRX~dE0_i2w*{etyxkB1|U zFjCdwkn<=Nz1;kFd(6^hRNE8cbN-}SiY z+`nu2u1ityiS;r2iPgiwcP=z8?mu*VS3l(le`k{aIaz+eN*?LUB*^2L^*vq7Z6_lW z?v{N{?v{;oNyRy4$!Xl|58OPvKK0q#kFz``y1RXIc%i;dU$?X2d6*@JoVTLM z{WmVS(eyr?DSS^ZK8pfwos-9Y>E^~S>eX@eE6&}s^Lu(|%|rDNg|2z1(|UI#ar)gL ze>J{6RAiEXP5T}L({>eQydVXvA{tGsYP7Fx!#9?{ZzjBfHMn4*F?e35of zC^NEB>av!J!s_cCq~(7VYPl8LZ9%K~miQz8=F))^2Zc4hPZ)W*T741v9Fs;~zDC6R zYtIpmB*shHmY9=ZnwDG*>N*>u-?uF`e;cH~o=23i%B8a;M}izp$_rQVBM1;2=!o{! zv^jAqQ9?*oX1&!>F%K>n>(w&cg1GrhLv;S~i>bE1sN+;J?-WIsI zrLNa;*e(#kPP%RIQs$5?taL})f8a69HuzM^q-msPqk#xsnXU$Bx+?jZZk1!X zi#*fSL1#Lbh3>k6SKv%n=Q-2W=meH(rITy?fM+`2rLNa;Ie`mV&%+GYS ze5R{XpXt`=*-;`6bpM<@K$V|b<(&8-r;DAFUQjyO6v<@g7X{g5=Y$rNPL?#8tPfRA ziRkhT0ebBa?=77yA_O=Y3yt*Qp`0_GP&TJ@GV$X?IcGeftXw)-_JFN4$w6 zPj_BPR@0)F^fC^29xD)!e;eJg)lz0Ym+5TJFf;0AkQa4)WBS>F3$EP^@}`az(5X+d zd+v#58BXc`@$NY#n)yb_%O#o#XZC3RuQ(^{|8~z1P*TmtsR8@LIb)EH_V(lChe*Aa zga^oXlWT@@0Z!vAZ8iHt4%)OBtgE2YQN0OB)?Y3Is`tBvOODd#fBf%b-~7~4W}lS? z^6mGJmwVRK^T|Cc0@`}afLGo|;+0Kmf6ysNGs-m^WvC_3Jv%=*I`?c?5#49DIegh) zZiia$*jI8i4y3B>bFI!>pGenUjC1Wllq;Va#CA4v5Zl@4L2UC2Lad*%WCCv^SL38> z@taR@?5Y<$^{Ln5f8&E=7vg>`96YhjunK>^l~wrAQNV``UC1#jTB220^wa=$wKi(u zE0cF|+Y91zh6Qnx;CQ;pay}iXwqJ0W_2`^>6)I1DR_$q^$DUW61=aJMSwG*}nN`$> zzRm-1c3sSXCq_->*IW5AgKU1im7gZeRD-Q^SW5G-%xof;f6`6*!{uNVJsmj)%jo&Q zkzpadHX_Mk(|rlea^T$D)PYl6KRYu39z18gIJqyOH@Y}I+64`_1?C74%shv({74N6$!V)d0Rd1s2b6~ei+#C;= zgbE+4493hR+L)Pz%euT}^Yq&zwrqNZ!xPrv&O(;We|r4XYt8FHdwcc16{cLo54g4V z@b_dvfee<;%gtFjF+qXZSUqAQMgLh+GRELZFdbtOt7nZ`)B9pIt0xZ8{#e4N7m%YM zj+Il20_>5XtvCJ*zllA=|4MX-A1%n&8y8oway#B=PuCwWn9m;JQC)EZ;AQ>>z_7DM zRShSFf3*JgrpDBv1sU(%dCxW?#879D503)ZnW=R)V#Qa>K>3&mXmnC|Xysf{DoY@i zYkySryAc1#q+pr>jQBHrgUAR*bhuWm)dkJ?SNI#3P+wV=&~f=us1Lk#T$XvYV7SoA zs+iCU<`xe@zkZ8Iy8CTgM#MD}eZFV&1Jr$kf0H-sd@&>kw)YsW{2=+4WsqLZreHHI zYNX940l1w9alT(e0+TQwn>?n;Cek$7WU)<#K+G#AdOfyL#;DCuJH?2oP$Q#4O(ZJR z)2#6KuE#uJ0^8-s&Dkz8ShO=&kqv`Trs?dMd>Gg7#ZLGua4uiLbNNa<<2InC2G(>a ze+fPlK29J6+&NQu93XAJlVz#n{(_v3Oaw^!Oa8Ybr_Y6G3P@Z~6jWXGzo`q#~zVUsbnCOfxgf1qUfQNsToj|GPqaj_N$FMN?RdKwDW4APt5 z%DjCXCu&md&ab!aqyBQMKI+c}eAH8lrf%n}n)<=Kzv~=_<4uCY@g~pdSkA;B{(d}2 zB=P^APaj6Ysv8NbUdaF3?~<%1XAckXw!G5$EKkqOmnxTD=WO^+-z<@>#RD|2`&ACu?r znV3vq^UsgutGs13uJgU@PFV4|U9jq#Vr)q-AU3*}-3co`w+mK151tw6e4j`MEtk(d zL#ihC@ivclmwS4b`-jkKlNM^Ze-`CY(xUwl2!Jw6(8=}awJ4907XO)08-0(+N}qo` zYZ`teHx4E3NmKGL`Cp?y$&>HtTg1e?m4IVG>B!qqrJP3a@@t`~Ryw*{P%`s2)HtUR z`iv2;%^!;H7rcHdY#gg&v2+(Gst!f4i;s7TcU_7yN!6ADDaaiR*5PA!e?6iO7Vmmw zOXT|4lclD@BrNLF(f9 zFhr=Ju2)GXskHS^3qpA_f7rxN$Vvk&nQ#H%w|RxSXA67bpb64s{K z&PT(#41)G42Vi3p4cPeL_}K}N9DP3Laj>vgK8W0j_m)6%RE(jzVhq()35M!%sBb;! zsbS=8-S6dI#7(@n0FuL0gjd^Cgjf4enBCUuo{#2+2hV`)_M8Ks> zt`At#`qygpYq9pTfBZ=(z0R^Hx%STFc%rpewDwA^{dh&Nxz1A)YSE}f)V1jpIw#T2l7Y)2c=bKI! zMMr?mA((Rbd*Dwy{Bzm4pz9R5Tz|aaCOsE^PbnWg{(1}1f8%kFjU&M0Neu#fy-Tx2 zmGuS}af?ka(_OeCB%eJXjHC}b)E(c`xWzBKZYI2@mzlk@yM;E+vaem#}=_0;m$Q|0@5)`4Ho`U8JGYx4C}$R#zYgKS&?^Ak>%Eu;Zt=jmXt7>trs>A%4$!z&L@Jv;I;4@WC z)~Py`Z!>4iB%Pyhkuz|T;@A{w$z>1?iwc++f9HtFd19Gyh{SlOeJ!sfoPjWoMOY^P z!YfTb$2#-(MC;7;-N8~~66BREcbbIC&+s$E*5mb&(yh#nc6w25(fO-P+bwFj1?{#G zqGCyw%1(eMNb~3WgnP~v@fyK*kQ)>nLor8D4v*eqsWI@Qv~7vW-%rz$D~LBHDL-vn ze{8lK{KuIHSUu*?zJE%uU)4P{cpucvgwPg-`E@%JIwj;MI1`RRw;|vfmwKpi`rEen zu`we&w;1Ne5r6A{jP*`Hjy}ddW<16o8;!jM%JJ6yOnexCxFhjnwj=Se7cA%la!__X zSs&is=2Gj;js%k&yav`|Kt)l<_EjlNQJJrxR@6y9w>WLI)Y;bwd8>5Tda&tGC&d4G zTUZggxnZ`%GRXMa6l|tNjm&0$JpMKl1zo>}gjyhv8DdkhCde$pQ%?4Xk)AR9*~2c$ zkam;f(IkIT_D-)VCHtLimld{MR`OtIsej+5Q^pM;`iNi|2|g~aN``y=&+(Dju&WYb zVpk>)hqozl485K;A%%nXU2TeVlR`m{R3PfzKOtq=7>99sRMF6}#a zR3aX^*heh2WB2-z9MOzqhfRtkRH~KglbISUy83@u*YISzjX0bBdawTT0F_qYatCaj z$lZRPh%!Z|;!)Y=_njgsyp!6a$T(1Y{myDS|4#bg??QcGLA$N^o{qobI#gMJpC#Vg zddVXKImKWAlt630vBo?RlPEnvgC!qQXb0ZoB=eQPLQ270io$fKZ!Yp-_k(>6 zxa?owO(cLnTd1%|q-{UkBa+d-H9&K$ewx(65hm|{n>n+Ve+Hxjttc0cw@Zh8Dg%Gi zI(na4pZBTiKc?ox;rmqOx=+>OK2`bbQ|l!A)H>xpwZ89D!ah}sz{h2uszUaun(R|m z=svZc$v)M9ed>wqQ)HuB!;K2gau{KJQbj|CpM2 z%734Ka@?cF50}GySLUf`-m8RmR5QQ*>F4xzR2iDAxcw<$Z$b@Z;XsvL=C5M*Qw{8= zM`%8Il%Tq<&z?3^f`WYVUUGWR+NT8XOSKjn{62AL&~H-~k7#iCbzkeZi4Et*@#GP5 zAh8j_m?9xUnF~+h%wnNJT%plv0Sm}@1k(b4dLbIY^=b!vo<(#~Tn~>V zS3|5$Vu;l#4YB%ehzW*RDGt!MfL1^-s|qp1>X{p2*xXwClwbpG_J$ZXw<@0!Y@p45 z-VpPP;;oS(R^6f@1}v`1`DYrzoWCJfV?(S8GQ?_Ph*h&T#5m`%ham+a#EVXm!;-P{LF+ z|-%16KukcKk_0Yg(~<2Wd)&F#w%;c!~bplS24eb~kkFqnDg7LXmIQAyyUbwV1l6qlO4?Tl!w^`1hUq2jk@v+n8(;zrqiq3z3blQc7 z-F+@s*4Bq_U=L1=d+}W8_$#jC_-pX4o#?$S7!~Pg;`*aOuWa*a)Ni-9s#3q5zfAph zn_sB@d6nS+uzA?T9soA8IRQvMrLh~#w36#;c=KsN9ut#ZeQQ}x2B8vrYF$&D5I%p< z69V=bA?KKBvExdvt}{X5sbLX+N0=}_1{d*lyGYL(2N+}25htQ@x!l3rI9W9nA1BmQ zd|u~>&uk)1-i^P_o0}~=!R}Yc79IvuVs|~K`aa^$H!Wj!mR&Hd&Age`c3gk}1TOHg zA#Y>1llO9$9WR@EcRS^FmqQrhVH;`SZ2~O3GW(skzjp!)5A9DW_qzLkJ~#0`m%tx9 zOA9ZJZ+L-tcS(t#k2rF-E9HF5X{JrPaiyn*H*cZIC>)*fAcuEUJ9XQ#yolX>Hnn!S z699H`!m6Y9?!JMac9Bz6Y>P6Fb)G%yUsLT-0g|Tv`%^fJd(>{$E_V=7$Is`#K4`RZ zJDIX96NAMHvRFU%Fj1g?ai5VLKT25^OTr=zS)?F)cz-LueGEf>qWEo$K0ly^-`=vQlIZ?3(ql7b`Pm_?sXFi-NZTlJ?x$hi0Tt_($8JoH_HUc4&sx3X{_F!8y zb!)QmuzR#6GZDLIO9GkLpPzHscbi!IZWChQEoAxF5Z`2+q2~~Pt!tNJ(@Y!fodo?6 zZ~Up%O=1B4J-q?wtr0uDA?O*tYnS9zoZNIjCzG#binCazc8Bt)jvXk{n@zfWmRSfRw8l^)gEd;ag9y`#pz|Q^$b~jZcDI$|#m25yX)5 zVHlz+0xgt7Php%7u61!UW?R2kGbUdgD}e7oCUuYlQyCD1KW{6Zb9z|7u)0ym*?R<4^1I&~u zbZ)(ySzhP%qs3Q#w|PvDO>BI{1NogJ!V+bKOq}71Ln5(;NgN+tHsj>SM~JZ`Hc}=? z`2BucF_zOyi$Rv-D+@($U3e#@3pp=N8GlF-UHS5^;t!vvjXxCdnWu2=7a*m(d(Gj| zHG`JTZ`(M3S~~MaOH-Vd&W}1-r%m>T6)h#8ksc1%joWzal0?}lrDFkuZjcFbLeJoV zmD9w`?y)=RiTuC$in6*{@||#MXg^x$1W2kSMp*g9Q+DXh&L3;ube`dq_A0wkF z#~#Fa#C};bI5ZO!fH_Vf7MUrOwez2a2FS|8W5M8mxF_?VXpwhR=r|-OSd=}5=wC$! zq9!?RZW(b}rra|4iGG=RzFB{f`HQIrpnT9T{95-G@JD4zp4=u9uk%Q#V@TSF6uiHS z^@5Dubw>J91aL?i-_J5{9vGl?`q|*2w^>0JIpe%>-pYL7itQxyluWD+3DspoTWqt@ zQo0C#h~$G?Y|}~4)kwW9Bj{qAMtaW5P0t3s@TRyfi@gZTRhZenD( ziHU`q__?ON`F5ioFpd9v`|kbU3<`ovnIL_Cok=2betz+w?B@9p_y7IQ-LWBFayzw; z{Aa|VB$4~9d_+A1`WB{Xr-;F$Qt^TXv^^ z(Q+29Gu{hz?dkbj;pVSU^H*|TG`O+`RTf9wu*xdSQyQ(hDwdN(e0s|ataYnWqRSfe zH4MBPfr@?nZJP;qnnbv&&Zi{p;84sU*4!LCijlzB&BJ8kRbigRaUK`)E+$0G8aao} zNL`WGvuGr`KT}??i#YsX23kt5qT54%rtvKPJ+WsoyXZ;0hY`8NxR6Iw)l5l0>e zc&etNJX_A6dhL6`6y|hLOka3tPU5}y<5&4Qi@eTIgxum*-A2rrG@Hys&51Ib%*3h4 z_%b?8l6ZBp`J5bFI_of(PK8}M^+SWbIh+4^`LTf<(slP{&5^Tz-EMb(U01^E4}Did z?}z=tVA}Prc>AsM!{L%$?}z>^hdR5r2+o$J%-2vm~esuUJ6QHmxn9E{b&h} zNN+#43@zSD1%}=tbbRZ71Tgp$BZRj5k9z4?#kiMF z4;}T=srf=LooX8Q()pI1STL^Y^6XJBojO&Do*!Qt6pW+topI}Z8P}Q7`$DcA-TzWL zL(}_WI)gm;aym7C^}nF*ExU0qjjHNByZ2>vrrt21e|>48;M};BcC2a5?sX*hufNXK zl>NiWlvPOgp6{k?yeT`1GB04VdT-GedguDlh`of12it(uYn?Au>^ly!+oz_X-d+HEyT3)D-UgKqwky=z3z^emuyw)SK6hxa zJA@;le4Ifm8Qr>)Vd{75D$Lg%N``n_*UMv1%vQyb5nW+HMaJtje z!_RM$26y4+yyC9U>Tzzq&ksyJzX5sgILOEy zIePG^zzbR2=425C2mkp~V*mM{;r{bKKZgIjYjld=k)0QDgxgBY4iH$lkDLu9G!*3kOYy@R=0Dn!6Bw>5Mgt9z%z!jm-OD;{0C2TbyRxq82d@2lT$y5B2@*X!KQOM}yRznrnlceGxfA|I+G*$57EwifyME#wx2H|d($&QP)waM-H?SlzCE}DOQh=`~_ zq$o9Q@F1bBgSQ{PZNJ9Rs|~wr$Y!~eSQir$Bqm`X2&$MJ(K<)5guaEp?@`LaQA$X1 zh+jx-417lQ8X$O=xiIp*2xZD~F z{AK|-64Dc}+hQcp#74O2Fr@RaL_Vavx8?iY+fv-y;(%{PrL=>1qHD=5Txoi(V?gsje<_tCK|9-6DcuNm)V9w~Vkyc~pmcGy7 z+N7>-f8#lVCjEYHRS9Im$Yf8AP>>#Qx1IO?oO5nj!EPDBz6^hne2Q)ie=_1U8R9|V z0C9i?O(D`mEW zRD1(syUA_pWF(B7MzC@jI>_0_4)U1aQ5!mPe;XM(7wW+2Y;8^l=4SoEtswssr?$0S zjYelH)YVWUmfz&oH_?8yA&g%WTinzr4dVQo*vfYBkAR8fU~AXO6+9vk_kY|G_j5J&i@hSkBH(uiy^eYpU=JYf0AUUQ-T+|@K= ze*&;95XXWrEC|1Xuq#O8$J|wI+*NHLUJ7HSFir|#q!2y|VWSW(3SpuU9tvTh5Dp4q zpmO_e1NDF=Pb_m23E~+HzdzogPWQyJw25VR$)xEdlZ;lo-Z30nr}Y~hPd;K4N~gf+ zB3%C*I!6cNE>Klcpvq{qyLAj~yi>ome-U9V1t!WNq8uI?5!T{!`z{A2;%wvPz&Jcw zgGOtxXy1^nKAwEUw2&vmKZelVl2odkK=3wd>FL92rw>NFfcpoRp)FF~e*)DF z(DIeq;%b%M&w{>VJD4i3Gqwu|z+GN^`w4>3*Ver;4gc%56L8qCtDrz~(pTvLA> z_M6$rVt!mf&UY>aI!h7KFA-4xe_1oy+(nr`vMBTC7^U&weCU6m$zj=%%cA3nm8&8a zhgg+GXEw`Du7E&VxWl4ziRA!XdT=JkW^fi%PRy`Ek_$mk%7mF)e6Je!Mvdo=8zMeJ zk!&Uk%gcGB?M5J^x8}XcId9EP={eW7Nsgxe9E_&^<3j%R`6G~jt&YyWf7Q{kxEg@a zPR988q5*{LeADToK2UA7l*>-H9IM?)_jRx6gW1lv4O`P|s@zhs&h8z{!Ta|*M=X>3 z?GEsE19+diw>kD#|;zDAsT&H0M)+>=_reauaWoMrnBx< z;@oSbJ-6wudzCo%8gb8UI_q8~&b>z3SDWs-S4nfP({GW4o9O71e-wP~`JCy2=-=)@ z^eH$u2a`lZ1`JN)BJN;tCYL}2{gXL(Qs;;(*U`OBLPzw^>hcwaJY{@t2mRK$PV#s5 z&+zgUtmp5*__DzGv0Z?_h3jsCzlG~Ag}w!R#n@he-@;|1MBf5#>)3*T-vWHf*qVUf zf^r4x`8$xlFpz#^f2Rn|A6Y9x2aRl&@p}#}7x1LcB$4arelz2d9NIGS6^1-zY}bH( z>wGigVH?^w@)fM-@4)-Q!26NigujJ`osmX16#5n#c19Z5Q}A18@EK`nTfuLkA!nq4 zodv&z2A_b2HW&I9x;-BZN4n!gr^1OYj!|d}a1bj5&RD?Ee`gI!?P-apaEBE_Aglnm z8P<8lc%Zi?c#RcCN~{o4;^W{)?RoiO7#R>Xx1h|P7CnqJK{djrTpI$wNDB(EEQ}Xz z(4@QewE%uP-3AKcsqSZw6YcmE*tc%TCA}*QtA$-MExPl3W?*KZA(!;7Fsv4K$&_f% zrZW%l7iP#Mf4wUVtA$-MCGNE8%!7*cL4&`ArZ*2N(g)p3f&qKgV-lXi^>5G1)1UE1 z_q=T6qV=h$k?&f|MNh9kKj8{b#nN4Cx#;cZ>i9=$#uF~8@Ut5Eu2W^wdsU|vR&r4z zKkL*4RAF`Qs9?NXq8U=*PJY6jT=4+~{ommJulSTx8HQ$!$9j#YT!ZJ;8qa((QOV42 z@K**ZyiAh^>s)`=pG*4!Dy!2iLt&NGSy*K?5>{Ca>p5R}EbR-Ztj@wJquu2IWoG>0U(UkmYt*RXGm3OgRre8jY75RD(hGsk!xbNMRj z5njg(;_mf$zFkInH3E+cSRH_kHPSbrzjHo|Rgj1M^EL-BX4Eq4#^gmnTchDpI40$|?x7ew z!lH0Y7RO^X=RK^^V(!H-iKA1!IFD7>U3WL+=skao$?Bi>#W_vF6AFTGeE#P^#A!%; z`4>04 z=sOtOAOx31zK5M&x)oTT#+p(}HUj6b_@!XABU=m>aU4yq74tW#X^16DFAm_0Z1x?3u z?d{j&w?J+q2n^7a7DYf0opqQHYaBTR=(>OB^U^|YrEnO~rUT>>q6aQuFc{61ceAI{ zi>%nK1lIwYbOx@$z;25QD%7*<>s%$bQjkrBdiK!TCmh#4_C1PtBdp|k&XQXRdhChy zEC5wprX?y|ORK7xavQ;4P=U8?4t+~j?n=@i2VRs3z|Nbv-a=trrUzbAH%4&plAOD zje?4zR7Rn9@(!AL3Wkx+K&PiWjsihZlCREb1jaLQY78R*1rgdif+}w~F`q(vN0|O9 zgzdNSRECu|T_U7Y1E?d*fJGWyz6gI-5g?pESNd~RHr}j|4exwH6i)aZDV(nMB5|Y? zbYT>Zaq{bFV08|#<|YVF{Nx4yed6%n3d2t?=iP%qIu<410e$>@sjk z<~8iQRb_rTKx5d;T?eo%$a9G6b?F9#9n|}Xj2IggAac*TolOHWu~^RuU7j6J^Y(g& z2-J;9O#kVGqKQ$^yEA)TVOP;FQKEnNdgm#~7RUZo=Yl@cRIXYdM19Js(^~I)X#j(j_!PaD zyA-OI6spsb<+Na_-wLhXVWq;Kk+w!Tu24{wlPnq9$~68og2VXSCHJnC&bmHy%E&;N zDf)~AjF~~#ADg5l!C}LyPN$FswVyz`DiBpdmjkUVKdmRCmqp~Lm|lODgCJF`-c!m! znpVbaq3FoaUWQ*y=bIt7szVeP6?sk+9{cc$MUQ;4`-qzbOZiNza8zehI8r9NgPVPw z*vd_J2IopEj?5UXoG*FbNPL*H3fTy35Z5$S`QGSuu?}h!WsPG;9X1V$Mm4 z_0WZXE$OFXA1Q~;C~<$@oKqEh?p1S6Htc7kcCH?}`mcBNQ?rk3#HN5dbvRtosPt-ZKAtc?+8y3blAIU51=J_HyTuJg19XQBQ?uCmN3wf|SyjR?F z1!?|i)|G>|D&oW#kJ!{%2q6QXrtqEpiFxEMQ-IX8LmxOf=23sUj6Vwc9fWP<(eW`k zLgP~uLgVG3-Xz6njI_HH%{Wo3P}GVW;WozlgiIe!)Fn)S<1l0Gv1L0v#2rs$BTR=G zo}|yUjj`@J2WfGdwWo#CoVmkN#ac%0t34vv0R06g{RwvjN7AP_V<@tCwhBKzPu^9kSaS&B zduXgVJb10enm-ljNE;Fzb_y{oaEY?syQk!V-_=9&P=~qi-fs5DuWH|p!@KUk_k)z8 z-O!D-8+ab~+HQSsSHFY&t+%)8U2u3W(|a+~?})<>rk`!q>ysVx8-G8iij^K;ef;ZQ zOpMscX82C@c(miE9lwoxCd{SoR=W7~r3r5-b@b`06CNoH?D-3%8{=OQki*&|jOe^58V%4@b#{4@k*%aao#wPgX=1VXNfI>Nf5+yP9!m6fK!_YspB(9jpI zefDYVY^%D+v298;+iFwRddZ8W* z1KnWGPKxI52`9vkAvksfF49Wqfo^SrNZCy~7`n-7dl?EMmv*~-2_Q0{`@7?|lc6iU zK~3qX7*D4-rvARtmaN|6RnPa#leQWdJ%-6|7v53)(F}=%-ut65fs_axN7!a{k={ zM3*j)g&GLWrFN{taA~6yhT3(N1ISSSEH>0wH>)$&a&LDAn{}9h9p0;bi6xI3O#=pw zxarOaEL*}RWTzW&18^U7WJUC0|7$|0(L%9l49tv%Ie+aC;K0(|r*b4YCer^XGDL)R zfco|pundkKK-qM*NjneH1=D-~$z87@>;rg^RQdr57UEx1De?smrh{+O=B+upUJ@zkaZYUz;q^72^IT+}al517jS! ziTXhy!GG}f`1(VTf_=o)nc(c$bikce;q)hY(o~x|9e}S1=aI=nUs6xZUh;clZ}lHB zAhtj5Ahx-K*t*H2V#Xhe9iX@Yj2WPK0f-ggIDweJijr4R0wvDhglVggm>i|7LPBy( zMh=rzK|XE zI3|i=g5-LTSPumhoLIPe#L7@K0SYF>v2gWRjG;gRii_fyD2j*TSSX5v;uvVk_~&7+ z?|%+T0`o;{|KSwu3Htp&bGRy)sV z=Q+_@!nTspu4ozXjCMuCK+`W!GTLd@^-c+*k8gC|&-jQC>p;0twQZteC4*ZJd3g6>V>5ROVNFcLFKzsIcSR-qs)%Ktr+kX7Z&TA4|uYc&LyC9{$ zPmHLQHCE|1uv~UGbf2>B3T5f~MK>6-xp+M>uuk64Ubh8y=H zkt5Ecd<(HE%UqOJz5_TWE%TxRB5axyP-ED9jgo6%kJUVrphkB=U_W)063S|l#sZ2U z3$U9jGC~2ZPQYWFAjhMm2ydQzl0Z(PX*F7;=}vQ8?SK7Z?^ib^~A?8}j~ zItGPLiTcB`eJ4@B4_UpC7_|MeZf(n9S?AYd)qUXXxwc{14Ra)&-`4EKt}t?Gx7(L; z2OH4+-ErHAWkw!Ulm~OZ=R&eEo+DS9h4CCYMFAUejvPaejW|b|bJfBe5z6lQF{7M@ zb1#~`*u_RJ-FL}B(k&Bn(q2Ee1)d7J`Fpj z>8wwKxz}{pr%{*P^JxZM)gACr7aO^B-=%$#2hM_k^;0{>>o&rs=MGl|1(vanEhK>wjJ)&%H+8bDPe(SIKj) zGg*@6<($5i-D2N85JZy`4$g%W=IeZ)EMI5T4e}Lx!sazTDvQ9*-hmmgX>}e3__W9s zADW!7e+Wl(XzZHtfgB8@p+h}7oP#S2n^HV~Xmngha~89^jgRhd&R!N_Bb>AF zihEvB>b#%h7BD>wokAny1zcg+R8{hmhUN_V78-Jv8JafmTWH8x zW?<&PZvkF$&s$2Kw=^`G@VC&AGt$t2!rwx}&PW4e3V(kK-Kjb;nzQ=t`Ow%psJyzAi!Hpq|57Y}I+j1tH@IFTT<~;# z0>0o0cH;HnOZ0^5+D74m%blQ!PrY%*7tkg)*I~jJT!&L`BOd2t`TAJChEs73-=XQf z!`20{VpJI+xdM z9<1fLy6&z?as}7+fzN4u?FD>6g~w@qovFA5Pi#rLPD5#+*4^(Bmg6^AcfW-SHeij{ zyz6&#T+@QluBj4h0YfsyQedA&H%|}dIm?28) zHL#Q-{|H{tD7Qg0FN6}ZzM(+AM#tyKeR@rgB}uF+oQb?3Kq1I2zhB z1pj!MD{5Zwilsn<9wqe}SgPPF30?id6XIz|$CyFS1f!6%rXh6Q)68kyy%IQmc`b>E z(SOg4l^ep-7P{_7<`g`QT#Mb;hS!oag`x8jEq24;G=`=--o(|@VxLm)3euDLQW~1h zJivVb(;AxYJg8V7G*0!0bR41At z74GB)cXER}xx!=pg!{k3^Xf?-nl+wRPk0)v@#G=j3z?{7=0D+22~_A}J-!ry+(V!^ zRa_7;55h1*eG=mslgw*1*EH+RF3BJ!6!4WQ5a0Z17I%w7;7(R-ms84)Za()(dY85zt9 zF*^MtsYjbP=JW&1VLxB?^gk1@r*j|nojv`|o*vDfKHNCowWRoPi=k*2ivA*K$nmD5 zAYUjFj3FaO+mM2SVW=<)gB)#43V$MoFjc=-S@Rz;Bn64It}9K-y3)k3drH!crX*ca zDQmMM@bHG{k4I@;JF0c7V%!m8*^YAFM$uSrG|BP^P4iAK(_U!Y-a#7&&_qqQ-C1$` zdx4MdPB568u{8x>W-JS7rrNc}kGeJ(f0<^o1AY0H>$ZDHskewLNSccbPJbZ6TL_Q< zfHJJBetS5pQUL8!ATt#K3|OwuZs=`6Fbp@2r>`;bn)l3HI2KQzObb3?Ev;&ixa!4o ztVvbB55~KNLOFzc^MVjs(1n7p2mH&{hUjy|5cz4@!zdWpwi+BsS`o>5N0EEWsKzX# zn*(<=nClF(%GJ5J$5KeJe}5G2F}j7Vyl4t*g?r0`t;-TpG7w|VBX}RlRTiyye_n=? z#a{pMuxi4CudjE1+I)VfKfUvwU~Z{6exJsle@x-?5ja(}D4si)Q~;-n7O@NC zlB)bURXC3s1Up7Z`9J4&@YJ zZ~}jBc)Gx4AqX;Qnt${rO%-L*ym(tQl`CUuMHovf!j@YRwp_-j+}tf1#8ApvA{)ZY z+)$QC#*WKbBAe6}&1hPtB#3N2tVL7#5sXzT!C0k|?Nut-o=yY8Vuu7j}P&5GHiGGdZQeiSicB$|6gUO|-g5M>ocNq1u@4<@A`N_eCR zxljYeMLMSOmVb_6$$UMh|5`GL*T*W?l0m#aHgqk9_|_!Ew^l=ZYbc`-lFX;3^7Zf1 z)A*z$KGzgJlEBv=Q$2YPna=Cuu&#Yf=bp2E?PWS&X9^Ve$YVNpQunS|fpfQ;-BS5} zOqR;$U^gcxsh@$}jERSx2)GFmJt5u(X@ZD+UMJfoq<{0dqI?cEvAg&}6D7W&rysf! zZAbcqN<_KSr61mXMLB#$-h|tc@{R*co!QU>N4-3SveE*C%^>VH~IANev}3ZzS*$d^gDqD;adRZ?Nk z^=D9aNS}0P&#hGU+{vJRK0&fF`FL+Dzxe$=9SX>LE9^DLrAdsqtxn)TaiKjlLSA^* zQf2ii2kco|0iLAFP7jw?zh|^eonA9CH!of4Bp9kj8>%%Lszx5FCp=UY9;ylt)ss9_ zjek_x6CSEHAF8#(P`wmLqYMi@SDemw&1s_7UXfrWeq2R^b)QQyH~Wzv6E`h z2Q<86YT4z5A~R74@HBi;p}%1zEZ%2U*MG2HN}%jtQvqd-Ow(y(PERBAM*{jtz(Hwb z%E}MR;Avz=Q<41C$o#1yeJY~qJaT#l^AGZq;?~1@+)GUZuK~udm1YrO$=N&pELI^l z4YZ*}ljZQr!O@vCNM28lD!{viXu1&b7U1cchL5XtU^4j@PQbC<`i+H`yc<>NqJLw8 zID6Et_*$kbtSf^N;6;)tln@J?jqsmwc_YI!Rjomrap&M^WGe zTksWceX|YGgb6l-Q?=$qrW0gEJ|?yz|A?|8|F~O`v$rBU{}kcPZ_kv)I$EG$a(IlW z{egrlc1R23ZR})`3;<+CAZDaSf`64rAbc4rkRa$XR35>qBM`I<)JDt>D7fro(U-Tm zBDQHS3&^ws;gIee!Xh@ir3|{>3v=lVqT2z%697Knjpx!u_fb||X@THM3qbJ@5Rc&S zEcwDYbNqsBm0|Eu#fBwhIA)GtzEL1)GoDN5Cx{&~8oA3*8(H}X%%x%eh=1v8Tp*>J z9TLxJf#ObYFX@XP070eR-qOXBf&>ewl;p%h(37cv>PS!-DUOApCprO@kdV^RUY1AN z0}(6J%F0(Q5YifpZ=I(=LQm=2G&j4$31P<0(mxVpNBsVHcb49rrD>g|!yieO!Qk8} z&J`xaLj`H}T#IJM1#bqYQh#Aik$eK4OTcA}GzlXmmq3v&;<*HhWRWIUq~sD%nWDkz zR+zKo-aQq$+B1EtcBnNpn$wyB*KWyjC-!h|_fEr5O^Ifl?9klqpO2BI7u9-dX|7CE zo{XL&7L+H`J5QrL8AXmu&l?NKlNp@0fkGFW+r5)Fka(luHZ%o$XMb^;Ax3q)q&>cO zI_FAZEtMJ*_Wu5Po$A#IXMyh7o#ufl5_H}z()&i8(GFw`b~e zd#XNYS|(rEQhh|EuXve&!Er>MK70@0Y60BQk0j-kotj#HG`XI8T6S6kP-L!-*g72q zTkls=+T3b~u~rigZGTzeUfVL1J-B5j2L(^Q4=AQp(^pd3+`1eLXjg*Ot!2AO%a`o_ ze$cXAtmRTad(UE8HGL(e&8^EOb?M4XnSp+A16jzjMS3N#B@LHGX^}9BK}kjc7~LZI z%9iQ5v`Bmf#Frgu0feJp!Ssu|S(uqOf zsRgX=Qj{wjZ#%gnVe59%M8(R1&_TXWJ9}}BL7pV%A{?j)4=U=0YI0J9yn{>b;1U-aOJV;|f|WEFPa+KC9YqOTvcNoxH>4x8RNsaJQAT@@64Yct zdv}6M7QEM)ES<LlIJ+ovAr`0shNog)y; zN6w-XESAvgl5pR8{a!*w3*zQ8wDc16Sdc=a4J@53+R78d5@%LkZr)nvV4l0-R-r^0cs%$&i` zV+D22Sb>rl@8J7?&O>YVE1cHsm!I?hrku>T8btUg4qj%>prT&WJ8Y9|HuGnHHPFt`3sk>jyhKGc(7{#d|T4zsJ#2@wL!b zWPj)B9&m7SSU619&7mTDWCpJv>`clmubsz4jWMl(eJ)ts!M>lzWUe2wMKs96Lu5v* zv+Jix;ADBs>j8tFBjSVtZY$`W>NuhDxJBGG2&^|AlKVJPzztJ)Me1f+pUCfdNcuM6 zBz>Pkd?GUIlE}Cuu`P*AOCrnC`v6K_@_+mVMlF#|OJLFxS+oQOEeBS=8}n=3+5T?E zU*^IB2si)%1E9?R2iX4*_urlQZwR)P=9SF*C$s*^oPQ$YAK?4*V*3MJe}L&v=J^9G ze~9Dn&hRG#v`2GB;P;c+{bX)Gk=YOM`ekADJ2mQ!*{`z#CUMPA&GPqsI+njn2Y(QT zE5dF?n5_t_6=AfxyV!>=cF4+u8F?@p4<>fNEIi(SK^)<4Yn2ig7z)1MQ|-+#A=OvMD0Q4VxL3V%Y2>5Bk&6J&@=MjZtytuS$w zFWVF)yOLiY5>$mScU4NuNS7H%x7A|SC(1R&#%BS;Ob!fJlvgV`=@umk<1}EQd|fJq zm=iY{t(eYH#y>_*7!{q!6`aUAu~_?Tx3q$Qbl zVW38WU*tDI<};8M8Jo=4)Y$=8jLi)*xkcwNaiG=Gmyxd|m@JsvPazI$-BPSu%u2{1 zaHz#u*aQ`-!j^MDLl#29K!1qY2fNIJalD0Iq=@bHHG;u{^(rA+&^lw`D0(g=8x#Q0 zKqjboH8{3gIR{iZ`ZNdzNfDBu!p0LfNFkalue99;zbecDhR{)(R2wT_oMt$h?NYTkze$Db?VdYuH;2`wrl{5N83IaeuHvT13fPYs_v6 zn-Rxu`kVyFN~l{2{VXA^B~-Vrgs)xh9gcVd&i5 zhqhgY_W1B&VdrjFqS;H^->O^>=F(}n*M~~igO|A8^V-sN|0OzQ!#BLlu(dEb&f8D)69)-@d0E6AFNgnJ@O_KL$u)oQdbZQEr z#_jERa^UYe*?;86^cpF@P45c1N4oPKOx)pqSjqjGh#J?47S|hXsUXsPXmGtzK5o>v z5N+8RpS`>~4fawnQP>JM+E>Rf*_n>=ay;5&v$;_H$U4xz0sVQf6V6^1xeq(*mqnpD=$<2$s}hY=gGTB}8>tG9)RR0?4H~I68>t45)LI^? zN`4L)sWl&|Cp=OP?%gUmDd+aV1PgMRe>`{zat-CThWcDX$tg3?oH7HAs-c9{jWSFO z6~)X*bZjV7W=1+?W+1<1M*3VvYFPn&G$VEMpnubZejkkFaOB#-#2F0JaOlSqaq#b* zFapWN(ZW50qrsCre5cX#@e+pA%bbN>mtabE(qB_K3uWyoS*S|ZLo%Wuk`X19Wc8&F zo9rx$a~YuJCF_A1AP8ne?I{C=aiUtGTdgz*R+^$#o}gBqo>r;=Oiih^ zR-Bd=O-jL`FHT6ilz){cqm`$kMHA7=)6hx-w-d)$nSg&45zsn*wL9?9I{&_dYoqx4 z4lX)iaZFJQYRshz$YA^^G8k4G3M+QFg~MRQ_qO7U-$}o^)#`D-+yJX~`u9Q-a(_N* zfjIpSrt5)pT{9bD#B0uIFsa4d#mLg6{T-VZoM29)o2%{CYr@i`Xs>iqIEUof)y-KB zP8m(s71lLr9b~S8fZ$7%A!M(O~#uV%U3b)kn=g%r+=0v3*jTW zF$I@0p5>kS8C2dWTH?tI%P$2q{U`M4k+o}$A9Zc8&oWiY&E0+MFA+Q+ZCXaCr>Paw z+sJyZQxt~F)#gm0nVBQrKMkf7|6amcJh}LSJ@P!9wwkX)e*T=Y?mEYx%jCiU0=0&# z^;Sr&HxUD0gSqRh7Y`jF41Xllaj{at)CXc3kHHCJwDPCOsvIe@oJqVYM`EoAvEfx+ z=M9rBi-fEq#D-T*J*nET5I(A0!bf$U@X=ec*Qba2W#gCcHRP{q1p(2$phsy0>0Beo z?(PH)LoKX?lpU4$#GY{_L6)v~m03*(1#l=8HTc~2^oxi7u&$)z{T*6CGz>#Z{wp1RJhLc=E zNj~z5diV%S*SUs`uuSfZ!bJzZHz|g)x&%SwG9+=kTOz)~T7NFvT@}N9pO%=;9w3cAW0&l1aq_v83AEn>7nD{K7MvN=hAtN_hO5 zJj#_%1dUwI9MOMy)_256UY7haX=hLDR7X_pA)%`jH3*~mwdHfUtu?$ff2QxE1{x^$c}Gf0e#%5w8)l}4 zouqCgSphk5)3)?MoeDDqP$Fj=rzfT`zx0GE?QqI7vi*y{nE)nO>VpKU`K|I`eDYhz zt979RwAjh0&{qlQ4=2$HsM3)Mg*Olk{}J@Sie4%>)$&McZ}#Y1 z14C7XdZo`EG_iuFLELO|5vvM5Bwwt@Y(+IFdLnU`GhT(gzSwgt)x zH{Oh^8SD7`=k4$9npY{?OGn+>CABztnC#D`Jm!8@Cm6D(XvkA%H}Y0ZuEnZz)$So_ zm(kw6ON3um9jaaA!=uvq=!DDkotx0C6WrIa*?c*e`HVmc>Y87<)xQ!?dwhymdyM%e z-b(uw93Gsie>n|HM{HTC6x3X@GGu@KY_wI%$Sy(m(hBVVmNpw*Q^vODN)02|3c{C3 zGL~BSNi{CxHu?KQ-7-OPok|W@nTwa#O8s%Ul2(Y4 zddgnM%hW1J(T~cHg|jZFfs77yf-W63i^?!3qJV`vLm6RxLwE1g4u6b<-@-X1+}QjM zfqXlC%7syOJSmC;l&Adj8$q&iruU0iohlwMyvBc%6iZc9ae*?< zjDt6|T1=KUUejGrk(v2#`H&0QL9;ezn^UCOj!%#14Af|YiofZL8;^+{t0CZ=aWEe) zhno>t0nX9yItngOu(t|3NNEbi84N}6yzeHB4Z-V76q;1T$dorifRJAV>YHAn6;tFE z3oP>FGJDAd(7H9TnrbJ&S@A(TPq1iY%wx)1o>LTz)uHLb#zFS17^8G}WwlG=a{l!rr4B4qFu0foPv%zcU7>I{VzIx2f)HWR+B@q)4ls3qfQH0+5axB>lPA-& zfrhqlTi7n$FLM4fiy(RV%VMw7Y?pTJIe`do7h#k6O2uqr$EuiwbQGiC@k?A=)O$zx z$u}WUz(+J#C0iRN6z-g!z~#T`fPuXO`bZ1cX$*{rnlX1=T;k*v9^TlHy~1}w`5K@m z1-2^T1)01&z2;7CKCziTX-_QoHrT0{1bJn7DODfqp=kN?+8hoo^EtlUQHNrDOzeLA_Gp@ldWxsd`^H&EQ}&Eq>Xv(M3A z)#(H>(E5&)c|m&kVjRb?m0aJ^b(uvE)&+5seH6kT58;u)Lm2ci$Zz(`$|j%EX?l&& zw-jIde&fHff~P7v2gu+Hs)dSEu#RTJDGnACitcN^3#xe#A1hIN?2(EqB03RsG|c2* z4X#|>;1~`=bC!~KEWatO0yP*q@DahElgUuVj=2HGueizEw6tI-)b-QgPkgy=Tt%px z$S_8Cm>EM%akVUP_TiM0n`?Qg+idXsZ1RC&9l@^fr6ZJr9bo67y!G-I3?(>`1zA?ucyIDyG9~dwRo`#Kk$m#5WamxuUzTu`nav0e8e&TAZ-3Rsy+x=u7nx_wl)a8#*X%h zk#8aLj9(Dp5Jb4wE;1DUU*O=TLp}q5cB8<(c~{Ik718_uK>(jrWJS}tA%R&ykaPP2 z1%B7y|0}_-i?P!|_EsHy+5LyQ)1t^cD27i7ur}96pB$v0^z&xpo7&95NhpEg;vtNG zeC3GJ+U?ffc2mS)S;AEGul8@p?~SzH)6eu(7_(!w#RX@x`I1;9XsQxXUNLc1$on%@ z1YhD@&aGatU^{_CR9hP=%RQ?f(Iv{0>2L0^@5KYW<#qDbG0E2aVWn}u>ttzKRop~t zVz4vv3MxtN#>dvEo7<&(Nxo7PpQJ*)m`M$S8|BVqli#4~%HVJ&Hw^EjwZFo|w`3Mn ze(`cmzf{(JI+yO`^S0N(!5m`EmEFOUE{Ok~Qi@bf=U4$g7x$AFwRLgPz*p2m(#G_| z>eLOOSJi>r!1sR)FLiN?Ev3?~(^$6@c)7_ZqsU{IwXcgGuKlR$&t^(*gpfE~D|bov z2T{dHqusv)XR8U3S+Pr{2t^e>xXbD!B%Yp~UR%=&`Wtr?>V3@f{2B18RC@w-Q>no& zy(fT%s7)34Lx7zQamwS$N0n=#bL4IsXPeF4BX&(si9#V8X=+FIl)dPoW5YBAZN#c( z-XQ`=@!e2AQTp=gpi^sNWfjPz7Z0m-am`REy*9jpI+pwQmHyLVJ(!Z9F8kW-qXlX7 zRl?NK<7=*LL+8*Rvoq;-RK*QM4kuvYkHpb}jWh_bYH6<)UB7-FN7~8OpO0RhQqa<9 z^5*>Y33p0pV*1nP@}*kyVsX|AK#j=i53TMtNgJwBcAx%kT8(G=b*RA z<_i7eb9nnmbAQTXzC=^)P?I;>YKiGTxoQ7NX(~uOs)PTF91P^Je9^&Td75A7@1nLs z>;kI8mT5Dg+mQtIM>(lvm`^@X|M(&ZOZ@5m zGX_B`QArQRpov3gSQ5AqX+nphkPr}8QowbNo?$+RFUtTbEJ{vTEnZ{=f}~y^QgGC2 zGAA2;!$JWH3K*90I?Nckzz>>cwUwcqjss3}iRU*+h*9J3p+=j0*<4_?PSV?Jp-L14PflG&$9&{knO7Lm|$2D+PWC%)3;ai!xevq2h_ zA5WuN6YV0C&q1+08MY5Df6pcM0la1Y_PaxKje)U@<^A!k_AU;5vm^+DPvtqI&jkwd zFkeqH1nI=6Aa}C-!N&?B&;(=ycM8n3zx=|@p-Ee%zfZI9r$GeUG&~1Hsy%}f;57YJ zMm%kK6jlGF3AP4vnQGkAbMZmdc<^LA)tg%g$hW6f>Tep(8}WE)wP!Q)Npq8lPxI8_ zH;(4W_~v0N7A=p-heNQemS|f8tDF94I&n2SCSs()J$OauwWw4RK2IQk{FKpvLDTIh zVyDk_TqK6~(l(5(N>twnb+-lF{oE*5Ux@>DP1@i18H-j|)l0Wtj;+z>+a4QYr!n(Lrf3t$#*b9z? zA{4$LJD|Zx53-3)4N{88d)d)k4r)YIU6KeEN0AG{qNt~$K(rumGdE>=uu@IdCn!|# z$ChJ}6N*Zhx@@;j`A`=^ck7&#U$B;97B^MvUsP)Qw^J8N#rt1Ovhpv)RZP-*6k6Bz zKio@}>S;+riqgb^PG-yBti^`|dpF_0yIbu3>s{WkePO_C+ z)Sv*{#fh$DRrHO7UH_!W(~xVUvt7mFHX5wJj8){_qmfW4E+MK^KK=c)zx(0okcx@K4xoM!9b>>?qT-`1Qf3 z$ss5K`sM*@aObX9^kWx7m($zDNOX&ScXCM3C=*J4p$`-;n=&vN-?1bBDHS#f3=w-b z00i*`xD)Xu*VyYfzC-?)MeeWCuuaisEE zz<0>pN5I}@?aw;&pzZc~X;97)HK_n?$8+pNY0ffte@E?<(&mslE2Z8dFUTr&q0R7l z_==;Uj4eeLJ1n)_1dq%rcASye?QwNzJj=)fo?2~ke40yc^YT1XE}RuZsHOm?SR&Ml>FQnv)>odPFT_Vw6Y) z#Av`?r50}E+<<#c`Ee-W?r9ueLys>mIld<~zPC?9&R`nar5`m>GN_8RgGIOyZMC1S z-={dlB!oXdn1atwcoR9c2hWyG62{Wx7>6GBV~;7sF${4!p`QsOnjvN%*{dW!lG(VMf%)Y0um}|l02jvArT}s z3uz?%9d4hVC23x-E%l8Qai z$FW?+4he(M)C|Qe4Z##P+|$0vgMX5N2k&P_UWK;CbVyJq#IXREJOc;by!b?e6@tKU z$j(CA8RBvNj1!Q&gW`xVZgctqHc|keLpB<&@}OdcT0sd2SJ9l0*{Rjy$(ijzekBn- zCgHe6_n_E+Zjap7)FhCG`41(;ml_!~+mcgJFMsj@u=o}L)b*+~ zOu}Ydxf*HrhX^0uzxa27?dI?c@Mzx^c0Klt$sHZHE8V*0_Q z2@$&@#Q`n>@~QQa?Hvi*a9+KT)n*wI2k%co<9BfGqn6eYl{^XQm!JqwVAF5M<+q0Qf z57ktwap3&@%YapLbN|SzqpZ(g;})ALs>Q*%^js6g;vr+Xzjp)xSt8Fohh8gUH<2J~&#* z$<8FgO4-U1%@DA|^rAj_!D=avSK|VIrido=?~^*;*+jA(NcWURVC~UTgOb=8z=aQw z^_LA#XE?bGN0C(|7!!Lw6{=C^Cy0BzGrm;UTI21_8xhTw~r-$c5+(tuZqcZ z0eGsm00R@~eO5zQe_yf-J~HDa9el1kJ@M%;2k^Y_Z`$Ae?c(EEUq&sM%u0 z*9LCXXN3(K^0+S;uG+2G<04cSWDh|w>CS4@(yB<+__SEWBkZ7V)Q|rDUrbPI z+jxOUj8{S{Xl=)MKJhiK0jrayHhR)_=|D#(Xfh zMrO&@6@ThFjE&hKWcty!##iOnm7)MQz?nNJp5`7|M$YwR&RvEiHfp-RXQpx~ywAfsyJakw{2`su_b|>jS(_MzI$8~GWpXZi*DsD7B zOIvRRKb!$hyuoC)EOr86e~KcIp(@$=eCMe3Nqx|=DO+c6~zEJ(zUU9sa;`(c&&?e0fM$CFLh zqa)}cvuY2z#)nyd%N_sjO=mgiMi@7uxha0$)l`Q*SsQa?-!?sHWQ(m?xFhm~yMo^MSp{XFdX7#$feuqqp5MHO> z&zx=!7<{T!r(#LI60Cr}sajI(QyPM(vn@n@*_Y;qEX@slgn!e+i26DgL6F`<2=}#{ zX3dLha+{Zn)!g=9An|~{2oBFRY$Al&Jj<8od>>g5nGeS!!WU&E-wddpAra^>U)TJA zCy0qQhrvOJwx62f@i_RbeSV<+!u3bx^}wSd6S%JLtH(HmM!SCf&fGJ*oPcY%)CDhb z2|VFbqJoQf#XAY=XR=>!D1Scwb4SPQ2{rg7+&-M%!5lVGT)v->wkGUfjge6bM}s=e zM;yYOe82uXZ;Q~x)2%`D0(fK{FiGlvgQ;KR0ot#(5BNkggP%_L$lLl{@sMx8fKZP% zeV(uIw(ZXM^#LT!)sT(ul@o8TZuyp*rw^OEw<}-2QU3l*ks&DeR)apG)qeS|&llWJ zVJ{o9+rV=UAvBNgIS(SkEK7&M5CKO#`Hoo6?2>lefADc+v7KvfG?D-uCXJkJ_FJ=o zqC@WK`SS<^Pb%C|6Hx+-Dbtertr2 zd!|KOv@Q?M^x})huv^96c*o@x-vffZ3B0$Fj}6$DVC1Nkk4~Z^ockv5kN>&wN6ZW4 z##KjG^l1@+E=o2bNlW~YP~YImGL$lreS55hj~|xwUzpa1uiUS%e${zaw_NKp?A}yT zBx|nOLZUhnaVbYoMBByKk3@hRC|`a;2=@o%u_wifKyV(93l35o&>XTZb$~w|sTi9- zT#Iyu^=h>~RbJlaHNOoA+@;ICbB1cN{T2BAxPmQT8-78Tv9^=jDd~`&S%w3~*^|ycZ>9O4 zWWp%^IQaxJ_i+c&wZt?vIeh1w3=L+D6BjzJFd3C*Q{Azl7nS!OQmUz;SO`P&B3}}V2yGDjVu^4M&3^fw$ z9YHgo%+x&|tvn^IN_0s<3-b|ATV+i!Lqf&bF9C_Otz)I?j<*BjJS6Eaze)%) znQSb_lI(cACNXgfW#NK0b#yywe?S^AOxw|kZ+Y}MzI`M(`Shq_4fX6rl`wrqdVe+d1N7G2+t;n0+7X6N#M(B!Jo8M>wl8V@o=&Qza>iZSSw5dz z)PP0uR#0JktC(r+9KQKXGc7E}{kj`27d)fQ1am9i<&q+*6yr@8o-M~uVz;*M;|nIG z^nf4TgtVI8IqjGzltvRvCoKpAxy$J{9UV)EkXSsYXz4CIK_BxM%ZR^Aa2p9x$ex-A z6K!=u@aeG&9p+Bo=D;-IvBfd!<+sEQhk&gV(5BEL+cj#f>h{zvOo1Yh$Oom^#0Ddh zhfK#+CtWcj(^^acovH`T7jLDu;(g{pPLOSzVixiVE8IS2VpTS+9^-*lI<9};ZvwSy zE?1SI57uF2H~PrxZ z)~K0`m;};5s-ABLahp$}o#zIKP!f-%8PTMt6*tDjWNha%2q_7Z73+~NxnTr05})3)@Oo;SHocG@p#mV{Vh7XP)OsE3yHIn)f2RO}&kV|RMF#wm#J^j$ zxa2kv;i!eWC$p(nHQ8xylv(;lRZUIQat@WSf-5|CV#KrM*}|byo4?E#W+n5|I^Na- zm&TOzc| z<#;bXmX_dI&6n{@q6aoc2bc-q{_-*4FUhDg^@N_NE!oS5Fnw+5Ne-B4FqG_Q!%XrR zOMvupHTBVO#Q`LaALjFyg@8M0N9qiRyXf2~Z!Gtftp(EcCRkvtFE6&DhKE?(wlQ1l zJf~hk4po>D$D>THSFSNI+6ZZj7`#xdXoqQ>4^?z)=lsxWCUZ*H1qO?OTduV4vUuV` zvadhFjyO;Fws$bvf_|jQq~cCYq`$(7tZUlSBi+)8jyS9!p(|=ouw=Uv zivrx~iv@3Ao)Bj%g^3b{CTx{A0~8{RCQyT6!EQepjE1RSSrfVHWvsvUedk+;Bdp1~Q zfUGrP(NY0h<{Z9AaV*02WnwE<-f)%qW(W5QPVbfAUVjbQAXjHXm=_Lfqv=sx;e;gGq08l({0px#`kwqta|~S3DZ32;J~TuWa#Y19=8V z0rfUy|LAuD1c!=K(l|YUJVP+4wC%-Aei?z!)E%|w{K{qF&E55?WxNbLUT#3183?`I zxW%ec1uNeJp3^x^YS#>i4j=46N#Jb~(gvg&p}PI63kIc^VPnX*SQYp(Ji}I#^^2C? zP4_?)U46q;j5#5SyJ>C*(`+U%0M+hduEji)&|`<+~+pjF4`OkfZP0 zeVqBkB1W(+h_$3R3Od?bbUIgcJ2N|DzKn1HHP2@StmT6lIN!J|0QIpIv0yd0ZZ93? zr}dJBjOyg)^YY^TV8MJMw=b~T>4l`!IIg{#KKY_fA7m`l&FS z-huE3tJfDqz(qEGLq9&vkuXg*-h&^^hu2ZBZiVn?@{{LreLK-#Z~WGG8~DB)4A{h4G~dNLCiE8r!<*sSF!jY>P;;a3mU#HAD|f_@Vfy)C zvEfMgBk^f`PVH%h=fM&2*d}#1BLhs2NL@n02s{Je?uQ1*^nTVV4fO{?t%wS+M3fr+ z9BE#Uyo1B2AhA%Rqn&6Bt<%I3I!Vc*<}aOKc{t?ERf{2NL>k4o?dWmT4;LSCZMu8_ z8vhWH8rDum4Ji+bZhjFlHqq0bk6zxrEmk(kaD=@DAYK|KHtUsSszjENKu7oLPgr~* zBDkJ{?zt*OaUl~ba%a1NE^1HLpd$9+`6D$T>p0xq`9T|5UZ0OL|G56?BrI_qv z+Ekd3ri-+Z07S_P5+O-eWxzu?@Zq;P=f5p%6_|HLVHo+5 zHkM`;{b$oC&SZkcCko|T+P+J`%4i|O`=3Rho1U7N9+p+VyO{A~)-gjRnnjns^bR)R zgn$x+rB5I0sh;Jk-F0Yhdf3G*a-1hOeewZIM0VRtB)rvE1MH;<0Ni*yh`6-YU9BnU zbKeTD*8}>mck!z!Je5=D8TjqhpwreUh~%eBv4Yn6aGUSH67Cx=&_0X9!~HUkr5P9W|j}i6hx+)0~3h^ zWB?J)81)>%X$lK=V@kG0eAX)IOiF~$!D|^o>H&WT_D%?g9C(JSPd#R2BQB<2?iSO* zEveG?J=y)vG`mgWuRj%SES7nAa6U)7TadwfuV~eZY&tFs%(SH z6(mPR6ffEr2mF0M7?HK6MT-nn19&kbLq}`l^3<&bMB>U*G|I@;G-??fT|K*)kYO6eX zS?G$R9cqpZvE#YuLw%$1maZF8d*0!a`F5ObYM;6J?;zJeO# zn1u%qyNec61lAj1L5&zQuW3>q_1DYVL&7Bxz?Q+UI-(&Z@!`CqcO{s66IxnYD5-=* zvALo3L4+DEvc0&>NrGsW`e;dSYbG7-;o0KDz(o>7H}T$L9*I^V!MEN7^eJoHrUn7w zNn_ByxkZP%{1lN>sU~D0qhLQphJFQ-;9(g;e~I>g{L%a}o6TfqH9Y`B09|_(LjVn? zM)i*k`vJkW`0aIBSI10+ZH_6C^`u_ggM)#Ob4L+|zb7C^^VAgv@F-X_wnrtsFVGI~< z;`W(J(V_jdaTB%YAB>)Qw^$$(uM_N=j;<5TzGMP}+;<}k?t4q(3~ov*2%M){ZFfrk zLn4W(%KUrmP!T+MV6xF0!8{+05!0c>gi9}AWdD~MAubQ{Dvsc;IhdoZhNlEDKrpx4 zYqvjBYzkT2A&55!j9DuW737g}&cwe0ju;b3r{7`;p~Q!*EUyaK){iJ2J~rH)xyVPctX>$=y@Vv?B;{k+~1%n z5wBi>f&-u|G&7+~xHyvxH8U~t_ZYL~vGPwZe+L~G!1ig_v+XVTgiB!i7T~ihg@pIU zA+mW6(5rA20sH!0%-b(J4K4o-B|-s$t35G!-ck0ELo7(hax6TF!JdH-^_s{}S0fVS z-_5I-X%&SzY`9lhG?-_b*TTS=@aRa84(nZa5=doF*oRw;s7yBvSo!R@;G|He0wow>qbxE%Q(< z^Mx%KJFNuM879x8IV+rL%2b!d_6(s;459pW!bHF3MQKaQX<}V|bjy`IuxlAHT!*y7 zGm>wqfD2fnt>i&PaxZ}C{HqOqAUjLdH>D3(y%_(ym>q#R{X*sCRZri{Da5`>ckKhq+JWfD zsCEa?+Dtb&ioUG+d9yfF%2y>+YB65_etzIF4FQt~Wp`d?2N)KtW6AGRoh9nl-rpJ& zP-&}z#!Ke({wbg_K@LGZzfp2`*TE4L1M)y%DO!PpnsCPiqCXaYpY&%mfP}~W!= zJ)db_l{5})=oX0O3&TwvIYRkI(wkZ>V{3tH45VPF&qaw>s4g~av!n8+7Icm=erh)q zX*mM{>dqnvNcnvnMhd!V$Y)8zDw_@0DM$JQ6Wy-ro>{bA@Tw2W3n;03X@)3#9sZyj zEIE}gi{K3|G+nzpxX}jP7%nEBa}AxzX3wG%c0Q>ajBEC|56X-XH-lj%Af*8y9Yr7M zCqKRzsA_n`ri-SgaPb4|4-4VxKsrib)$@U�d?5Q$OXeHQPNr^SOgtC1PFrp`!Ye zA#|eh@suODTMWI<#k!5BxUQU^NvtE;XO<@OvBqsCGSnwT#p+kEXDK8=(V+uK$(78t zQ$NlqXEtGbxmH#wr!6bATDn&STaqRpq0&=Xs#8HzjB9UMKVygL9tMQncZ?GUtcHP9 z$T$}eJY27>WkI#3-!G_H3~&Sa)cDvm(Ww4Xx#?4;?Ga-pNu_m|Cvd+V`(g`1Hn7b; z^~d{z%aKG3=@pIVU~eiWV;BHtg$zLT#r>!fV&@z*35kjlnja18F>FVyx~bJfO8qT% z*#XKxYcWD8n#W8m7aX4IB{^bO2MWZVilxe2Ds&Lkr2{~ik(AXT(ZrS7w5`GPn%sK8 zTL;{N7vWBGLFJez0n(@2*-6q9Cje`38U`_-wk=FZvY#-HlLmJ?V1YD~t?t+y*4<7; zmk6zGI65D?I-5%VAX;JG>$!5lCyn&>BbfhE6)}yE#ay$l)J8+VLxL zXcDh`(60?`b>Km!zspSLqsR6Z&JseK^^+cQU{WzBBW=t3J|n};aCE0`XvY{6^E@d)T3~0JeS3!(?snCTy2}+jcnfD!tu`L8R|3b_ zl?jQh|MAiEdc9J12K;&+f4dv-a{syi6jzrGK7(3M_Y=c!G+RFvZadgJrmYLy`ywec zJpZp9!!C9UcZb@-j1#_-7Yypg(ccr{4bGvX66m0<-WHhOcN!}*IX8N^*= zzwPijjISvw@bV#W?|7p!$2@Pt(d+l#PQ2I3u;E=bkHP7Ero%Tev3Mfqw70by*X>U`n$N=T zw&IAmkwP4|*Mhdqp6 zG?dRU4W7D6Yq{GhlC1hIbn!)X%u@|U*M~wD_(6?_j?G_-j7>lXAt^*3p8lvk{<-O| zJ!eH%T5Ti-XG<@T5QnISJavJQiFnDJOB!cdP+sjFZZZ!2gBph^bMRiGd(m_I%n#3; zP6qsg=9)%d#dAF=*`**ONz9yA1-i2c5-$_p7_38nf%z0NetkHo@f(c6)sp)3A@9}l zYhPlgKaZAt4@baoBtv+N@zv0PMZkWZds+n(zFQY&T%}xcm!7j+Q?=blUmK{#X3%2- z4R9Wjp&3@0O_jU7`w&+W6JSlxky)jaP-$>XL8jifv=l{KP5>Ho z45RyD77&HnOPDiks>@{5^j6)mOwgXSWb>!{yCWFtA`5h5_>EE5ygAj#&ko%)f=eOY~8o#vz5bw3TGB;M@?Fd;wLGa+6S`}45 z;K`tKdgbQmT1a6WS7T{4{_;Z7O{m71_D|mB8^~dEOUWV)$1id1jW{}4jo8oi)$kT08hAaLzFw2qb88_tVN4)oYBo-uShbVew!A>FhFIwc{HFJp({5 zum~L!x%LhR(@(`)2L-DKn{<%eK2Yk|;wb{gk12X%;tLoLkTP~p23O;I)nN<sw_Z>&U&wmCWT#ZFni|W&b^B$hvs`~QfR=Vm_ zng<~byM|%W?y@8CN;Gzwk}XoM(~c1>vx0!9@=ysKojQ}>9_f&vh ztK0%@oYH#(3caiE>NF%ncF%gCuy;oEI$mY_6IQOGzS9b*#81eq0u?ZzLQl?e(4*eS zW0}7*w2@OZ;R>D0A@($(3ir=-UY9@H3E^j9MadWq>W`vqK)9F&YjZ|c!gkMv`ZThE6$#NJ%}MdS(mB;}6DF#R zDG|4yGPK$AJp^Z1xBOOs`;mj_KKWE}!)T+;8|rpZp0-1hgOlEWkCcz8sHU!rHPFWtGMLH5I@ zyb-dRtagoP_v%vi>zG2F+l(47>a@bmGBT>gGb>w*F3l#={Vtj0EQZTnt6V5ENWy*{*l z@dTnmuWVT~{4F@LZY@jjD~(K{sUhM@jqp}TT#yn|v<(t)R^vA12?oV7@G>9OUC2TX zj3aEY!9>E9YMN}dm8Zs`77f0D@WyntA-O;tJK6?nH~J>)GRUwU1KMrYi+eVj05D5( z-HI{VeyE@9F1FL~4xV{~hgh!ajMggtlX8nA^-_hlT7if6RGK%T^;N0xhoKiXTsO=X zH)d}t{6aC%Tt6X3n8N2R3^u&d9xL#hGs^UB5xtEd$!xY`U*AF6Z;f@>NGsdDo~wXiY;qp8Hg;>6?*DdgpeTzW2JC z!Q36YoMfFV`ErjonZ6Dx-rl}VcQ2$9w%OCyHMiN*wc%$$!>Pez4+EsvWgd+J=&bjB zZ%?10lC^b2%jFy_7R7wrRH4n`91dr8u5I?1Tg^XoLpfMz&4-CGlld1x`H4Kax0>Ec zIv&ixPUmwm>SiHmxrqff`Wf7cRm2{XrpNLos}1 zhOGNZd@6IL914Y)Ds^8?Wppzo3`?x4%O;x)1h{0CEDpee+UkXl2@^x6F`=AIykcrI z=Bm-c`^&_dKwyBvO)e%PM+vC@IP=A>c?mt*_^Xp$vJV^Zg6@h!JSnWE0VC4QDx#CW zf9*+-%jD;wpYI$t#V~sS0oH2}7)kFSljchjR;^JUL2p14RNsKVy8aKpzBv|7r&H7x zcsZlsAkp%qL#*?Dzwo#GZr3_*Uh5scnb6*9E9Pa*?@5zr$4AeDrTVw{rE3MRzSo;z!R&nc3u+8`z5YR)e1nld9p@7Ucecf*ZyC) zL@$rEHIp|k7UpBy4ip&|e!DlL6XYN(5dZB~6#wHN0uxv;2{$~Yxf0SzU~r^9{5Km_ zGLY33*+li*#F#@XXRmM`-6A03l7td*@p`W7#NL<)L_--1ic9&B18Eb0Y3kA;z}|65 zd>w@kC#rb$^a7eM;nX@GVwpjt=N3qq!Xw}faoU9{vR;7oQcIX_R6rEwhuIPhgl+NA zE5+WIp16?8Ff{z7-M(WWZ&{!z_tXvD&8+K`s!YHeKuxqDJ=E+`;wx5OgP5 z5}g&kNryPWFz_Y9^>MD5YpkF&0CT>ZUBKveJ~Y7N#2SlqAvPE)q^!p|v@uAy_8TN+ z*8B<+)Y^YBJSh& zY30Fd3cg6rNe&L~J?JL-_!Y6kw^J1iZr1rs`yD%H1#>QLn(**8i#%f@79H~UL!jp! z@DTUZ-fd_`N29$Lj!y)gGt>ANI{6C()%(tC)0w;;Y6N@sVh?}CN3<1j#0&lfG*bj! zqG_fUlL)Orve`M#wGiO|f1hu&KH~+1g8;?(_8wjH5A^<>EL^fNA0zqh?g(WLAl3#B zGB7YGZmug&WW{tjLOUFv0&92?Df9V!N~HqPZ6+^U?N+TfPF8;T;TU@XllQYgC1i<=~*i8Uv6pN*y`aZdAlI<66g% z3Rij#ht36Ka}53oGoj*sPf;hMPRInJ<#I=_9$=!_^xJslHGy@*Ko)$ z(|2uiW&jI%3B5eZZ;NUW!l27Cuh7)MmyVFjz10ut}#70~-T~ zs7gfdl;Ccv9$_gR7HQL6=D*%x^(*IORB8?Luy!-s=S684$!TZ*eXMAbM4MkezL8@$ zkA_cfv~vCej{UI6i4w|(*e1`bkxFU9oF6nxO!)SuG346NvsQwsB1jR;6;f$9Rm^JT zh=)j&{rF*hR(qIfF@`adK#SUV#aPY`p(}=;irr*2SUH?8*YEZDL5z`gHYLKysM}HK zGmR??2tE}LQwUkl=NqRQo_0J<4x30|MbYZzb?@&1mW=&ymFaMv&Tx^uF}9~JL4~xi zXn0@!8{W$C+z4azgHivr4)Vxcodl=C_Y3d6p|@RuDnWFbLDCs4m2DiYE;k-VvvvVFt}%dj}Ypj|V#LxA8CoZwDy zcXtWy5Zs-{3GVLh5Zv9}-Q9I?-JEat+q1{_$Mkh~y-&T}|E6cEx*pd>=TF0{)o1oh zK5o5=DJ+x${iw_;7hr|^vw}m5r4PS8FZ)zMyX@}Xab^;*2413-VmU1a^d~DA_%~9u zliQGP=jgk5JdUN45eZw@i2EkF9vvUo`k0Qr+P13BnzH~ew;GW3kam-m9q-nEEzzrlZV7N2>|<^Ti1W2C^;Yvz6O zn(b5vuWI&URYxHlm|=jIdo$HGO^;bv+(J*aYP6?FSH{E})jzXslR3oAY;d`l6by0Z zc3hqbu}S1~c;nh4OjmU&1CB54>sO#5auMgugCum>6D5)HYNIEP~(oL0q#u?1HgoKlBtHYTx% z=#iVJ9bErD$g{^YrIA6n3?3iK`Y{Ur9bw_sKM&jAq-S8DHnd zHNkWOIlRM%5CdUV&OL%^-+4Wkkg^8^O`mc}+B%T=wwF(Ynq0)py!RwPYC<%DBs(ju@OCg9zi#-yK2WKpF($>KqVookh~85E$$>9=Z7(r zlIbIiFzL+$1c{q32*XZaG@rV$9Ez!2Od<=y@x1DE9hkXQY-`u@N8DiP9ZCiA>ctPu zCnwOF=iTZR6@h!_){pK@04{syZRs94a_<0|n-!&Xs%w)8q>m6%Gbc-)VXn12)^@oD zy&T=42PWH{|Cjf@Hz^aQN$>Bv@UKQJfOcsx>3s6Nx1rFE#CpZu!4hTzCP}BZYKaaX zYD~6&P1IC$+2P7^tmeq4Cy(!(JzJB-_9EvsXRUkNyonW0Q8uJ{o+h}?CyFb#>CDkh zI#Ouz3_}>cDV$r3EIL7;DIW70iIiA%~ACRMPsTNU27$wxbI2#4BEscRC~4^ zG_!@`N;bEqmdcErm77L!oOqUeHDLV=fXIEmBRB##6W2;uziBK+7>^Ry=sdcJx~pVQ z&ik@&=L&3$=sayK8WhCIH#-FZ@Th5Un2Yn9 zYeg?l3yy4ae?4*h{>5i; zqjPb)y=aEBd^#1=Z)IjcOG)H@i@G=_^sWA$@=q75MnJ=vTOMP79C_rP7W*4xm8(+7(*?srFC@=8Pj|k3 z?6=eCW%$G=ER`5=7gIjNN$BysaEun#bpG2IKkbHD9>C7UsjCpnLEZgbpV})-gWhb; zu*vre50T)g80l*Fv>bIS-P77bcT}&9*E5eZrJr7&5yqPqB>lyuzc{3 zGE*T<_;v^XIq@i+%?v4f8L>#Z9lSC1P)!_R`v#ixue_ix{W_`yQEcF%%7i#T$iq4U zuZY`3o+l*TFF%s>Cng{P^$uLc&Bg#56>qiB;Wve4zr1U^80^UEfB}Z9lp;BAVe=GQ zZ^fJ@s>un^D5fEEFKs4Pp+t*r$n-=K^zLbO_WJpoS(BM>t3z`~`|HoW!oGDs`&he^ z5)zD*@A>j#{5q3lt@q8D(GqRLg1=|5V=zdtBJx9HM^aCtH5o9WbaFcmF~d+HjaEc= zJrKjnw2c4CU@Kf1C%VPjaZ|gM{*{R}jD^+1Gj}!w6he4StvOC8SNgTQTE`mv<|v_s z8}3%^B4wMK8g>?Yjb8%yP?7gM3z&%H>P|QEKE=~a{DVy>naQI{#va-7CkNA>ydG(w zLuAK?%f6~3$3M5mPM7`R^?jw{!ar?yz>nqw-_0ena1^i(*I<|o7p2%y=0E6E`Nrsw ztJ$^#+$ZUhNT8c5TzQ;`_D<8WN=A#X&68M!mT)+e44|Q6GMx~~-NEiC?)JZ;C5^z} z?CDf}^=F-d`AW|qo8qZWjJVYqgJF2oDD?MI9GBD(qfO$^rFh;z9%rpp^e&o7pUq(`fHW^V3#~wjljqeI#h-^YhEyze&E1~# zC8mDkP#9anvTov;@??_ZSGtb{P?+K$IXIL*I$rJSlf;h}!Rl2m5}Y1c`8X6SG|3c; z?{q#*pt{(6P!7aw4lnCN*HZaXKS2d~8YrIP{e_kE+}A3Zr~fm#*c)Eh@rqy{pjkr) ztZjmgQ=iCE+utY9GD&zcbzWd^^|CrC)BPw9cD`?(xKI`CT#I!|x<+#osM}9I(tCH` zGRQMf6&rU4$}rOrtvCCytjH><<06AEOhvPlm572s2Yf7qZ&|-qcTIMeha}(Mt_f zX)g5XpiLb{jeT}bq2?K3K?ElkFYvfW6VQw6@C2KYj7mkNLL&vgB`I>h@oC+{ik8nx zW2a~Q7zn=>;g=Isl59SyL~HjnWH)N}QOe#8P3PI{n|ka73k!`%?TU^K3Hn|vn9yG6 zM(G{>d%e~-jvVay=!-0->5~z#Xloz<9U~4tjcBVUD>|}twr{Hoe<|+&li?}IF(+*ITQOprSlVLeoV7ncaKCWaVmu*_GIJ?%ZaU(^{?xWj-nLc&88HE-! zgYl>iBU14$-ACaae}AzjTf>1ifhKz%>5G=vcw8lgxl(1{qm>j zTc;iY=#+Sg0acMYP?mG0{Be)B)1w`96cO|5d?CD_#XBRcBF1=4OSIEFjxH_X%*D!@ zg32uW$`w5!V&-jYSe1wM!UH*_{`VS6jrg|#1}bWyZ}WOe-_p+4ng0?sjd^Rlji4xt zB)uhKJ$G~i$#KnH@}F{mZVTKVDSXTE)0z;>kHK7PU~*unm{Wt^X^kIK_z8=?VGPi# z@KxMV+Ie3SI)H-LuzO#vuSUg?1KdEgyfpW7wvMcW9BcS2l;pOH#RI9+w5?#kGOEKthNm;In*tMA~-v@n_PGRVaD0I z&DQQMdh*Y}K7iK$-71o`B-FG_iH{J8wFG4%;Xb4T*Zla9e2p$H13rl=3QDgXwfA;K zKh~F3ChIJSu~Yl%o}*1+Lw?V1pi7c z2QO7pYkM5Lwikrxg0QGRWzeLLX%s(T1C~M9bYa!A(Hm&Ctb%UGfNs3(q7j7)5G94#Fq=3620z+%q-d|C_(0k1#(}a7Mp5({xS1BkO`3@L90C zrG^~hr`MNFr6~vRZ=p}5^LDdgdh3LFrxNU5l%m`%OQLMx=+H0u=~_pBBAwLb)M4$TgfBu<=s~mp^9lp*yBLc zV}Lbu)5bV&H;e*TEB9C`uD8$#Y|rjRE3<*%Wv*{Im#6%^EaMAzLf55#$K(uh;j8g= zzw}zJ(CNe8a_+x-S*DF}Dq3xE{aIh5mU+NGs%^xO=x@&P@15T1e4KfYLm|#gG~92a zDK!MRc<3OOF7-1oE%CxrOz5ZF-Vql?q2*8==*NVO6Byfq7G0pl zsKU>1J}~&=?Y;Bd5oh5w^)3qII*p&D*&zbvbHrJWdk{Tn_wE$NaPw?}H+=+!8E6O= z0@Fcbsd*GF#A$g+x@f{qQm=El^FXT>t3@rYcfpEVSouUo?DGlOx%^S@)yGW%;XQ<7 z9lv_a*qq`@QZyw-Y(lg?u$eW=IAzR?CK3=Jw!|U81|i7GVdWGlq@3KyuPNg{<2Fm? zaIx1PU-W}6T>|!=o*vIKj5*}S=jcgNdTF-kqqzJW>>0DQJ-J(I8hOtCbjNnASYHeavSJnAuUw+o$(+1`%~e|5^r2CwDRCj zoYDNlH(FDw5G6CInf#E+UH~8C%kJGQys#+&(uJmsQZTQawfS{w#2EU7LDVl!9BLBz z-v*BJw<8LEno64Kxium;FjB#W7IlXPak+fWsks*arH((VC#0m9wtr0?!nIK<>I-#0b7tdoEA;}eL?r8lWT;NS+@ILeqkv#Gb zmd@VtJgtx<1gY544{A0oRuwU|WADH?W?woGV{QTWPnrbYQF)5ss-mAF1Nm>gJ0vk; z#Vj)EyB%gx?sD!+1#fSRXr*p(dK^GtqV&~*hE9!m-#c)fub^}zqde9eD-;3({!nv;JO~NdtdmA*6hbL zWP?U)S2pZTy&YZBR#Ms3@C`rbyz;*8uR;janFWnq6!dbZl4m3wp)}zJ?7FW+H&@D3 z6s?<+-fH1BC!8BYNEe>9NEc+BZWrd*h%BoMllMO;S69S@WPtrkv5l)57mmR-|Q#-4!gjbaMmrFxuO~-DIVx zh@iAg*EVnejY)J9ic8zM3u~&!hM~>5x5v7Ohgx{+Z>kiYskwOO%v(dXkE=2tugiT< zvHiP|J}t&~?PS-hLQi5wyWFw!%1-hXahT|*2D?TeE9gg$5~NCBMwb-ZI)|Ltsrp=k z%nS%AzzZXdV=P#VeY%a9V|$ z62w%Orf?|c`nC6tW0kQ?=7ClC=d^KWw#h}u zLHyi9jv!e&l|%g)tK=#JnC9xAAi04Ty~YMfhgIl{KT*#xkLf_jYpu#UKMKuI&8N4J z2jS>_ZDy!M+IuV+hUbX8gK^| z&8lBG*%c3HiIo%#^VZs*tO(B41aK@%gs!=m;SsesRx7mguJ*0i{a4dL9+N>_fFiOQ zPIlluT6WL@MUYIZVf0!&2kBW&VNA}#TJ`Rx{HkEVx$oc;2lTwRz_)pqD@*yvM# zUUJGf$xwsmt~2+2TIHGZ^smg0LT{LmsFmtD;E3ZKWzTulI@QPBH18?ub6fPK8u(mV z>iT%UuWrI>mie6R2r#1RLrt;)w2QgDm5WvEa zF{ey7dq2|SdbpOmMhFMWsk^y}bjKpa?-?!yLYJk&ZXX!GF(O$8uFtE zT(TA{j8|KVOWAPpHGVQaMWsGa*hs0ROwJu~>Z-G>wd}O4th}u1e*u$wWn3nJLudQz z|6W&C&J|sL8d%}BV)<6>QFdBdR$P`<_CEs__cFQbs`t9!&;O<5zhrZT7PlfGd}8EC znZN^j&YwQ$@(()2N^ED%x}3k6CTVW8a*-?6Di2)^SxPuA&xdt~oTz&>8sc-y9uJF>LNaHhkOL4eFaEqe|YNRthSm#*nLJy#fJR zX@%gyQHk(+Nj&1Q1B+0}$tAttzf;<`jFC}ny8GQYwc3`gnDhF7NAs1^WO{Ll%L%{&Ber6P~%B2pfdu&qvvdn2pSWVeE0D$U|&qh!+ z=Tu7-r#}`sE+?_AeBvO=bd&g27L1pt6*H;&7NNH%;l+hyH|tEYxL($fmpfX4=IK~I z!xTh2PogBy{$dn1d?n8!>f<_T(q>k9oQR)Ya$Rkbwx@-St&6|;nc*4p91XzDPe!*u zr=pY_YXB-Pr_Tk|RRD`t$3LCnC6Jdd5a|nL3B0#IsYJ)0ibIVCL(1<~q;61% zQf8BE7Vqr@y@8S!xx6`klP(T%k>dDpP#DkPBZ6Wxy7DhXzVFp4m6|OE5pq;E@9t67 zAxH?tKM9zpy~(Gk_Xk=sM6M-rT_J}FCY{(74`E|CiX!DuV%QxL*np352RawF7)?%6 zrBORQ&(D-GMheW?IujY%u7PKoJB+nWTI}%pRH*QJIcWEn#(jFjV@f#6-`<(R9Ow$( z^?GQ>^&CnW?D5JUKVTxgDE3}Nx+YoF2o3d@m=R(imf&h-;uUWGSu6cpVA3r55GZo~ zdSu0~jyE!}7|Hd(42a_)bx5a#I`(+Et6RGIYX5PK5i^(HBX}A+@7x4qs1~;H{;ioA zGtV+4{CW3f(=XhMUg8MO7{q_bxevMTkECFBenPV?G_$`=;P#7+$!p72Q72wM>UPtg8=meuIBKuVK~mSQ zraSxgMA$*@0Bm;}A9qXU;#0sBciSDhu!}=S5M__Vf;pBLFuTBS^CV>YQ}a3>96`$U zOeu3iDMO*j0@$&2M#}U53IdBE&U2ZwA@>JY&XboDQ*xI`wrNeG%4}r6NA{9vy<4~X z-ggW8x)pu}iDLEq47U**3?3Pd@%QPH-AYy_NQ<;x1VSB)eBcHo*3Q(W@51H4=Jk$F z#;EF{UrYrCY_CF;e$sh1v~O@MFTJH$y8YVLl=ua;yTtiI@7=7?y<+7dx;=*PDZP5V z&|Np%!h0u6edQY9GVZbhUhWpk&~l#e%9&l&FK>1;r}^e&qB0XU!Q&TrmavmP<;aVQ z<KVD;x+W!u)TbghyoVL-qeCQzgu~{i;PJ8w7(vsN$xuBly1t zFn9o^Mzu)wf3NzF4d{CVWT%qfG6dY8cqpB+7NMIRb{yx?_#0bv2|6BB=fr2K7naq>`1_@_foyoV?$v zT<}KP!b*~$$`}N@eSXxUW_3gIZ=G!*+J2&pe&g3EpZeFoG~$WEc-(Oy16neXbp&JV z*N-%uaI(#r{bI?gnASB^RG&MpfhcETz+azgnHfXP;D}v|w;BU%d@&XesWRfAopLJu z&^6tHCSm)ETDIFP|CQ=nEoY$w@9c!+Ps)u9C&&K+#RcigVNYKFdHNr5sa8&MSi^-5 z$w!KfbSK-{e^6B5sq8Po@Smsu5f58VZ#2jw#6rFqQ@+1@xWjB4 z;t!Liu*`l@)?Z?Zg@0r1fXL^k1MkmDw2SVm^6OTYO}|peoOkdK~l&jh;i>K&E>0nD9kA)M`ww zc>DR}*!g!ukdKzt=hyUyGs7}L`}fz`&T3*jv&Gc&b_a%wqu*iklnfv%H;3r)dXWD| zjO*qG>nR8{=jfm5`kjGaFFIVTIOoLVc+GY|YG#jnqKh0Dk%`jXaN)QeW||Z%RZ?xL zezLl!a?JN`5T?ineDc%~D1#`-P4E1d27IS31w zX?Nq>H$5*Mdi(e}%DjPyIyvR#Ju`zW#64FO@0bjAB)3hjqT|f+oXJ-wI)@F6{l(F{ zs$%3Eu6_dfIySd9(REbJuo8c;e1XY8$zva|=xwKe3#XHwwFHwP!2p<`}iMhMq9 zZ8*F{2DI)9!dE}@-^FijP#UtP`HY+NmU$|Li}+&36t9&&P&^Ikt0~hh-mdWAr=`Jtzu>GyW8j8sFTNTIq8zA=A9gqVgBOqAJwX4H z&{f536vZnR)Dw3$v$Pwf`m{3(IUe*Koe_&qc2paifC)AB3)z8LYJOQ?>j?JAb^aX5 zy`?U|w&_*?;VlOhfQT(6UyJ_tPf0jg1@!4Y98dfnddK9A2%@kbA-oMDOE>KTr6F3- z7AIIdZL5G!zEu~~#37!qT+03VLV8Ke-JLV|e6Kv50zx*0C|$&)K2tY}cFGOyqxYK5 z5>7n6>95((!tObc2Jc6Qr3KCmDPTAnba$;6qTM*U@HLte287sgaxc~C+i+=o)h(gLi zrjn}+LwHc?RQ1b-Cx9|qmFK6UBEce+BnC^*J|}WN7wUI1<0i?RiorQjz6s&zKS>(N zu&~_PmpW$1rB7668x-(LvAP}|#Tyg~z^0a;A@;$&A#__LLbG8e+Tab3cnc1pbB$b} z0Njc-+HmNNZ-o3DI5XNw7|Re?*8KoCk-gWbcQzcQy-eXx3Ru>0t+_n;VfN>5qYk-_ z70PJhrYmM{Swmc?N22Ry?C1&tK5}16oIE zB_5fUd{vIV37kKM2iNzk(1x=yRzM~!mQr%%m^PwFbhkxc zWS)We4Cmo04ccTW$|C~K3Q-0j-U^hNZ=2YTC-%y~_GvBjF6++aIdSR`aFce>srk^= zQtxLj5*75Qsmct&^ipto1nGChFOUC(jMV4fgsp=iy2wcTci_1A$02(2R>fJkManQ^ z29pmz(8tK-tH+3lfYrt%qVDt$Mr;t5Fp_08+;k-F!FS#*Z32T(S@3=opcV6F=a-aqcr(jyh?bqlk{r3@_Be0oD0WEi#3@kj3~@KF>`x1 zX9?bS%_iwFc=!gM2?MaSyL74`Rznq7X80WOK+xTDKfH10Tl$zyHNNr$c&=Q66uS28 zp{?7dl$E-SY~PbUXkYHWQTE-w@!Vgy?%paw*BNk1gUFj$P8ETp>Fnc9#!__Em+G%C z?`z=+4~U*mzi0jh^)04qL#pv#yw^@Xw=>W83PQi*c?}OA|Hk{+M#;!*Py=(+mmsui zf`&LAis@kKDP23Wf0U_nEy{sx0`dA>8At7LT{*vPju4EkOoI9^GuLl2E_kM#JSiPz zmT*$W;*tVu*MV##lxA0llmp!(vQ6#*qmCV#1h=b%=tt;kwcQS7zC*lrhv%zIU)wns zv>U|p5y4lx{Zd#CwPqx^7ff$m=d;m3Pcwgr(51c0RKu$XVVycpifhphdFle*e@($z zl$gC)prO*c#Zf9bKiRh0)286$hCmc8p5zge{j=^9;pd&W`_#K+!BilNVu=z> zq}um?{)?G^$s~C&ykBN5YfeyR5VI#B2bTCKB}|`qXb1?nyfKRNCjGBDp*%ZY6-DQ^ z(ogfzQk`uCHq*7aez$JlsnjN=pzVOtNJR-ke5yql$1~D17-V(+$fo6v>%oIR&j)=d zDGaNJ{%kRS2RZuto=>sF4f{b-U3w|U1;`a!3;_~{!f_qegV%@WkBtRx4r;cJ>mN$` z0lJO@iF;q?Py8h2498OKGuw-dsplW5<2$V5TI13$Sh)`P(0X6oZT4N8^+OLvHTy?F z^7tqNUiR)F;ckA)l6cSWU$4J`o0i2Txck?pns>E9nmjhtCy>MbT%!_ce6L{?PGj@X zRRCN9SD_mkPZAng=wHuc1HZ_cL7N?Q2o=MaQ7UfbSz;Z+CyVuJd2O^5ZqFjGyjiFn zL&DFD%{ih4nVU8{1*!xF<=rtWwlV5`tQpItP5KyQ1+r#}aD_==Po)ly`=?#S4e|(% zo~OL%4UXbP)!2TZw*o{-x4qF_XwuZsf(rey_NYoc^RJ6r0jhY0UIDP$G_Zd8-a{D+nWV6yw3H;+)H3*l#5sn9-Jv@#vdZ;2M` z>U?@}w(IFfy0rK6|8LPA_>ZbR=sqkI7D9TNl7g9nQ!_hdm?yQs8_lsQ`>(hRHE&HA zZMl9Pb#0l^{ z>htw`Jba|Kz2=nEsWE32NdwMJvb2l3yd7V0k zl74X)zA>kmu2q%sHbj`WO25wYv^5dxx;dpRkp`>oYRxc_2H~l|YD22H_@z|?;~4xS zvlOhup)MTIDglt4z&=LR{B&Dh1iFIxRd-rzmR(;DZ?FF54)G@+0YjjRH#)mgD_iXI z(E|5oC7*xw-JZfTN0>J8ifldA#Omxuxl1;3%Un$s?(k5%Vzh>@3HGk&&{;>P!T}zP z%}O^zjN2+B=;sSi%2+ZwjLtpt{|x~DcgWG9Cj*;+9OYg0eM zV|Xu>nY%~MZ%zGc4T42n&)cahB7*e%m^W(CL7qedS~9))$P8BA9qc=jT-sJMAAK8* zTentq+}GJI5^2|~7xy`c+FNHb>e zNjE#kT?c&boG|$^oqbw0*O~R_bvH2VFf?DBUybuP-`2F{)obO|dyDJV=Om4OhNPQ9 z(qOcHIoogVQK`}#Xd>jP%q^g^F!9P9O7!KcalQ+EbZlUm?Z_NptBaa^okhkaW!C7- zB(_-A&jgnk@?B)7kL|MK)NS=jLUVf6D$3aFM%S4+LYx1BY-Vw(?W*Q!~1&$_@Xz z@%vsjXd`pkb!AO@dE<5JHYdVwn&>Z=S*w;|W1CMuH40u2>|URBs(>RggLW5qr@A+7 z+TG$E?^gavTA@#z&h$=q#!FT7YB*O0HqXYcs#E$isME52_E$d#-XI?*x`OhL59>03M4xwSI)mM%s zdcgAbk>4ZjR?C?+vcMv;nHVowE*k`Y)SWZGS!VfvF&+W0$`G9CPvCsA+}TBh)0ch z*D}yNvANkp`wF{IBE>31twp?0L+Z$5$!^5iBfgZ(+wKv4b6%O{`rvLxHmF#du!tD% znDv#cV+e@Q_XYN+LkysXnQ6LlA$>+Cl-Bcnpbi#MATGNTHp~p+N=cuw8ATW}xH7!E zTRHvTkM{P$uh=}KSi$!D#&#`6`@KYV8SoU@j1C6)3z_V0>o=5y^!|QPux9=P5G2^c zU+wVmvqT|~`g%;XKD^=@_-)RbQ4GMeZ37rmwm%tM^;{p@qOYN%Gc~#(smP+hC%fSD!6FQsrvmC;oLzK$qg{z(F4^Bn;e3^g!N9kDj7e=bYRv@VbjD zo$`}ms?|39<@{qc{7pm;3t84cSS=5n!$*tJHvsPJ4=m}6b5Xlh4C++D%%i}UyQW?I zToui`?HNQ5#sI=G4&M1QFGBOb8(rDT_Kct*U(YfmL0`Y4mUcIO6xM#vRZe$#uP;v@ z8-R!00q?&@x%+{Tv_;R~%HG6MfYmYi{a@+6uAfxxl+y(Xo67U@C6D_jy!W1Xru894 zoy<2`Je7PD{ahi83MkU@uzZs}o@MX1$In(aj~N%XsqQTtkDF{mA7{Hqm&)${CIB6r zjMkvvqEGDbHfWY(GUX5v$~PwjJUYp_K}DM?oTVaYy2(>q&KvU|ahkIMfN%K`j?qDE zW}4q)f7LDV=A1a?RcN%0x4Va&sG`qH^yJ8#bxr2HCkdJz_uER}vS;3>Plr7CRj7os z>;-Sod!UEB!6v%Q!o?)(KCivHqaPWJhPTYy@$F`Oav`ON8vO+?6I{PRX_?LGXA@$F zc811zT*3=mAImyx)}<{c;L)lW(caQd8H3^#(4z(mjX<9`qv>PueeyrsnBoH-za`E$ zX0r&@rSW?(JRnYSw5N`F$nTW;1wP)%7o)L)#4g=$BMt5dGO4f?{evg5wR7&qWlYTK z_Yv_NhfKaw(6RNIpqcLSG8NK;k7{!e-+XG+_lpX+BT)JRK7WJd%8<-i%u|1N)dvD{kda?fIoFw`z>v;Y<%IcUcl=MIR&$3|-a52CM0j5ty0W zMQ-6xlTs66LXjUcPGqR5JwWbq0;sUONOT0kZt8{h4%LT<7oegxXq9I~-XHH;}<5_h3^p5{HDmp8cf(D%w2+?z6L~6QVN`rQ36>+o=kh;RYW<;T^jDJpeFqo|`6h2AHh7w}cZkM^ zctY*bRvKj-_)NM;DHe=<|1|=Z`)?i^t9iey(qowu;81NE{vJ-7)}wleNSozH<20!) zLTX(oHxs0~pv2=+yEQsb@<(`Ynj(69 zJjRFJkyUzx(VXE+U0M}Fi%E~QI z`6w|o5HnO>Jx6?@cSPrey0w(_P6&|So&g;0O?32{VSpQ5O18&*dMpBkkL;sB_aZG;vO4)mi0SH4u z+;{VQLtQXF@2sBtXBi>DDgcQ_z&hw`yu^|TD2V`|KZ;y2iV`Z@*pJ48?=3z$%z7}W zG>C`aCnkt8w#RK@eW}-o(n z(C}v^KGceqr*;1!jFh;icdZ-;TQXLggU>UI)|02O04tFx8qSU*xpQQwH@w8D#<)hF zg-M*fQBC3lQ+7S1W#Ls)R%H^OF1T0OpxnfTpCV0@{wCtgrU(9j+5*xZH;4l&R2Z&POYD zAAC)jTjPR(yYy5AuemDE#%YYOqU$pm?_8NBJ=g#P!tcmOgA>shEj}6hU$5^Qv(oXJ zPwny&Hh%2cA!RVI^urJ7DjR!WX+o_9KC{!dpx@$XW<>vjL8$U4o$vMzIVpbX0$Akj z6)ERV!MC*z6WUu0QXZO2P-)n!V`U+ju$w=VNfiH0T{DA&7uBFEh|%Hffm<7U?R<-~ zQb*=C+N)J2$t!geHQg+s)})uj)H(Q6MyaQ1qhcw|uhjmQc3e`v1l98;6A}Cj0_NCM zoVJrDndd=&pumdxI6&2l>!<*393W129&D=}J4|Q2Jm~vYO!7(^LOD~FLAD#@n6+^$ zYQK;0kXby6chILCH^}w+Ilp%?s8nbVHnEp3Pc1qqL0GS>dvfOQUf6U#gAwqHL7%V8 z>Ys_;I75d?Y*os50r+9zsQhEC_D6a@T(;1kEVrKzQ=o8#Dt@_mvpe1%8{kdFTRz6L z9@mt)`(l}Uql8l3aqULiLVV9Glk6V$bNo%~W@&vkT21K?k?D+NE~fugF|sw=DYKwd zLb~XDJCB9Y+Ki3!g__wpga!q2)-@v>nl8Q9h*^F+wR7IY>&vM({tJvW&i7&t{U;yR z>{)Di#bSgiO&;Q61i2NSx_|R$Wil7`o>)+fc_O(7f3{IRsPu4;QIhV3jszNT&-a@? z)21W!sYXEJFqMZ2{)DSFRJ)%3Vmeq+%bev8f%>qLPQeg9Tpd4yAXpMR0~M3!^stn@a`Bx zsiLGf)sFV27^2Io5rGFt@@bkF$iTtmhSn$%LHn3x`_GMJxnUT{1#Xl+z)xMw$8x ze_@CC{F}J9d59JIIig$q%hT+nc)trn4M=7>{G2}pYw`5fZ2;rT0xnW^Pe4|{g`s^< zlTxQjaB}F{)SVr4Lw1Wo@M2>6fD0;9u=E-|Nh)LH#qG?9%Z_}_W?bMG9joN1QwOcL zL%+@)&#xp?$3w4-5gcnl5|^2XA4zwV-=~r!5&hyX;mLDTNZh+jze4tlyu`dS5-ZXA zc{lbBDIKS^L;!}+jS(WOMbFG)=%kPo`J zT8G(kP+mv8!cq`SeGk%%?TA8_N5M%GkhGrWS_3yuFsoE>#3tYsE~7cR{Q4Kr?3vK< zg1*Bo`DC;!$?j70RwYqGBl}onIGm$4rTf*I;3K`*x&TWy&a=P>39KbcCPpIdog7+F z){&+0Nc{8cGIgOnv)UmKD|}`4{-`skG<(0_F}>Yq79YRK3daTqA1&y5P3Y`L5dPN# z{fdlIQy2ldd?qR+2=$SZ99Rck3&J&L#xVubb7xJtbVNT%y?HYSt_T!X3UnjUZKANb zWA`j{S^(25WnP0SGa_+CE|etl8#2sQKr8xuLh4u7_)@A%{@lUPf;^GDa~_q1aXD}E zfgLHqkX~>{qI%7b{h_7fR(m^(fOGb=a6C$}5~{rs_qLyVB8`(t(b}jrG49xu;2TWC z9M1|-5%JW7Uz-0t|ACEcWg{qlkNQxJlbY8)4gR)7G1O^2j!{W5Kyi?I*)_#BzK*n+S)Z4P(9WFddcA8s<$V0->B6BcJMI3auQmcL9*Z@ZD?)Hd`GgwoFrwl!5BKzbWb=0CiZg0vj4SN*3H(uwRzPBRrvKka z=%Wz7+($>M*a6Q;>RDb^0oqYJ^^ts;!(d4UeUGgWkM6NW_TI*G(LmPA`w{*rEJt%- zNXa=Aw8*eiup9N+ogb~r@P@7N2H8wX74qkkrJpw?PjuBJa6b3j+uRt=XI z6u*j(mHiv9Ywr^xwb=V$mmJwD7J?XM{dvOuuQ1m+?u`3 zCtvh$n&DCNpNFoiv?_AnMLnSQZo@Yl3RUI0(+_^z7bz41V={@RGMSy^b?u{Y2(pX^ zR25!S2#M%w>Av?=v;Z+eBEZ7jV9u|H7jTx`IbKKty;!0ncOXMJhNDyVq0F2JBAlNf zhNLcNh259r+(3ALVpSC%bTF!`3IX3&JZ~4a2gQe_-|SKhrNJ}!kqFfAT>4zgaJhsS zzaR1B!IqVU!{_y^qtG7oUbieT&ibC1%l)wDTKrtv2$!K5q@wFy0Q}!=nBHz@i8GYL z`usmGbzn<8=S&7BBt>^HXm8L|tV+7L=oxI{D*o2?!S|K0q%jQo4;`oXZ1Lx;^7n4u zm=zgDz*S(}i3futdePxOJZv4IS!%Mmr^R&Ja>CEhlvr?Fcac;cLF~{GZ9SwpuH0Lk%pTqCHk~Y!Lz#!MDcPh6 zAH2^4=GCp*cwzM)_AMYAkW|SK!4HM}p5uQ${t#fI=!P4zcDI&az`x zjWVA_XZum7X|%Mqwr@2^qBwYw5=nvUW((y92P~}_9>w+smri8lvlOq_19PzXf3JwS}-Y!qMrm|*FD}A(1zSB`!*MKv;4Gc*qS6AC0UC_+Xl&t0;tJqcy6h8H27Jm~h zrqsSm*HY#{ncI!(63Igd1$jB11G0uEd zB4(qHj#kVBMy|RTmE&Zn{3eW8GOgc zJPfJ(NCV+_8%v~C?Uc-+gA0*F`wIFXXLUKw6;0p;bUXlm50Ay`tM zKIbe~Bf75u3UM4X8k1bkT(mwDK`aN9+D>QKIQVqzgvI1Ju6}uPva!TZ?MVlffYlymw+TLT1wKWVeO8C4jI^HN$9u-z z3dRFy7(mhu^Gy%YG-nP6q)?vl;fzme)e<1Wtl`X~rMC{8ZM4z1j$9Z&%)U?24-CAV z05`0g$y9@WOorLt?x>epzgc z$q!lzzBA^Zn?^3(+S($p@d(lKs>b=>-Ij&tY`~d{1V4$m#ZJrS-*lSWwDqNKOD z`oDzJ+tuAjwrw3xQ*k(W2y#{x1`{Y0t~qsMh3IswBE`mvA4^=7rvLB|&n4v`r;cqo z;xxl7JPCHyiTADutsk85gTssk%t|>x-9J2J68&xj+=kPT@CVz!cXRg02(oit!lf56 zla%paJ~H~486k;$9ECA z$0uhvTzWWBy&HM}r||7XFl246^^5|ymk}~+&(t;a4-LC*r8I_!pG~>x)0K=|B-1XY zThDd~l&y28cv8rL@$03Q9Aht$=E(9^xMv3Wv1U!{)+BVY4g}>u)5Df8S5HR;rzDT6q2`(CaO*lTPD#MMmzI7DUipN2aK___4>O+!Qf|h#$Kuzbx)k z`mfmi#5w2Hbt$h*g5u7-^M!$?TOlj>(a`zr!R3Y^fT8pAGO+HXsZFk~5341IywSk* zKF(4~W@%W@Msu`DZFJ~YoiOoH(ebE@UC-!1bw&7fQ6F~-rGTcQ0*^Q#JKqC(lm2+h zJAV*P?~gGGG!4yr$vvqpe3IbWA+P#7r}Xma{776egiVu8(Zj>EVX!EEjP3U~R$7Z| zY#d5QXiEz7LF`b+y`+g9v_%a?gH-3AiUUOyz`2lBqfwaH{eKv$hSDTN>aj!bcK{8} zWUek;F7$<=7yl!1c~`JZnXGD8>H8Q4{PVcKCNV4YJFu1_Zm_zRbMe*= zzaN%XcnS1uJ#`dD2&YH?oshmh&^!KG=_S*=GX68JYnR2MS|c@%cWm#YUW2$PH+D~k zMpZ80i6!$Q_Zf-Nvp4LgezJ?$Z+U?l&mQxDWTJ6__fwT63D9gX&@(3%+4=a@gR-GX zGT|hs06)YTsfM_4)^~l6O7OJOl|lY*s|ma?#1pa1kP)Z@2RatEYd?M=gc$HlW^Lm zng$UDi`J?k8M)=Xa$o%g6_L6I5i^;GOpyDeUK%G3+U=SQB7?{s?1_Tg>46-wGVS02 zXc#abWS=0qUp<0ppN0}!;NEV}_|T@@pjbSOGeaJ2hd=kOcd%i+{uL@3;x#hbU}-y4 zE#9P6DU#$vrzk6-QS?Gb5?y0K@x?KXN(x&ON(s#s%qA$J(S;Oz7#g?Yw^tB}s8-b$ z1UO;1pB)=EgG(Z-)vDM7`R(;KaYb1asR4thi6O-1-aipLsO%=4q9d8#J^djv=3R^D zs%XX^Jj8G5fD#JHNxypaDnR@S6FYt-5aTmeJZE5%EI5-QIS!N>N2CO1Q2?7J`XM=o z3dVdV-;Ax#NN-vja;m&s4<5NrfE1GhZ%aEiLF$^ikG~n{!Mj)=ywT}eMS|j8paG7U zCpHFOOoogBM=DgY(c zfVfTtj3pK-$$uX8uPF|NpsjL`E3S~fr_5Z3T+ zN_)-Prup=z^o2?4Cf7QI^i;mSXpKv+9#i*d= zzY|k&3XuutiQIY2(S`DbTm`+^%)tLqe+v98E^A#?`dlfWe|!Jw^Iv-+^0?Ftm>lt* zcs!g&iJH#7x$82x+h4z>eQR5*O2U$V?3Y>#;k=)`vW1^ANO{VZh)^#87GeW%9qFUn zC5wu@IS)-m;F?zG4nE6L4c7aC{q(>O5DudNnZI}3Qm#kYD1LL78rKxji52$w$B^yh zt(qC|pe?-_=*N07J*c zQAop6aJVBqe>-G;3Fk5Y2R|R9=7Xbea-Z7O!ktqp*lG*UIL6U7p(*PP?W=SMg!mK> zm{5?qj4E3EVAxPDU*wFASQxr^^`cl?_08o~ZXnaU$}ba0h8Qy-cN)LMfx7C_ZksS z{#3E*pUH%N4lz7rqLIoaxlfH&#C-|E&xIhjcgg2Kl7X5DX16yYV&D4h_>6HG%JUTw zLPyp#6HZuCIAT#QNpy6>&*fqJtF?R)v>UrMJn)C5PP@EOI6UzE5xIi-|>5%cyXxoSn zDL=Tw?(1tO?2A91U0}gZtoR>m+zpE6@yFeRhY4E>L`nK?@4T4}#EZ^7st6(aNlnZp z0O=NiiL#D5X*Og!y_z*CLeT)3eL=37BVn7s_hs8uhCZN`$6;>3Z7yQ9^x03(sJvd$ zU`wHGIglHtk9D6~u!E06?DqIHnab>B!VN<-#gs$ot)vOWPHDf^T3>F>IVs z2GfCsnr-~O2hNbZt;$yhY(vuM1u#XD8gr;*t9n_uT5b`UjJ`yz7^`l@rv+2E9@ zN&G&&Z8QcHaT0m#IwdyFNGg*QbQFiGTyIk>J(sgC;h!jE5Jc=dUv+qo`4!Kg%Y7o` zsQLIb93A8M#H!aPGJ?v4**l4?NG*9I7fZQ#t4VwN0L!y@q0wjAaK+)*x{VI{{z{2s zhq$$9KmMKbYVb%}Ng^y~f5YW*jP=Zbo|Dj|_c?(2kj*nS9G>$FoqoDmsr~CvS-d)o zBl);Bl&h~xRrPe$u2HnObQ$zovE)!*D5*Bg>?E_5rkV}-!sy{Nnd)L~ zgFw|@$K!QgcR;yjy$s$*gxmXJs!*S=xQWkco@vp^KU-;IHI;k%U7R&HlEW^)qZO~S zKEL`MlX+Lk5=cu~@6`Vhjwi z4Ow?oZHx)miK~T3Q1aZ9B2QL6W{IRMS^G@`uMm}T7h4Jwr~8J0{aDZdfB zLq5YF|9^#l6Ey9)KJmfE79*WKK8+EjOn8i=7rpg8L+?oT-hD6^kA}Zvx$zhJZ(hk? z>3PGw`h6JBKE;kiV5%`QYC}pF^SY;v=TlsN@|Kas&_Pc6d_Tyt0axPt0`fUAh3jd{ z;|c~^v!La#Ji_lfqcz%mO>RH(iR%oEvLSrs(Qa{xV!`Sa0b4)KQnw`NULj1atd@Ho zhNA?1rGdgQI+M?z&O;6-D~7V-V)5%x7kr{-6Z62ObwV2lDaVQGBL073Sx?8;;biDL zprl-TiTof%(Zc>%bFhAbj@%vjAaKkU@C5GhU68sCgfw_WXdkX8@3uX)i=I&m&a$@Q zU}btLzP40o=MZw4j^DR+C#_<8y(+J%tzLnqtvTv{*U{s@(Kn}H)>643##+CbLEmV% z&2o%kEZu8zNLx5M!$Y?0`i88kgy!-6t7?@k^5%HnryA-xYf+ej#J!+)dzWBk&2>wo za|-!T+WA}DX!_Lb;4XDlRs1;&NqN36QS?7ej(ww((Q2CY^#MG4KZu+(0D?fr)vAWF+IFU5`ZBo#b;HFr}4jA}bp zErs)Lb~+pG)f6T-r{3)8?bduUd#|$Yx*Vi2*hX1~FoOoePH+l~eCxEXXTrd8>1b7v zkz|$2TuW+AFQDac<1s+Da6Mny$aOcV(YZ}>p#PXhcdpug-{wpv>=itXuAz1?M6B<8 zI5j!8w?v!KJyLg6N={vuHHNhb5R05+*hVcRaL+PEc>1;D9BVmiAqP{jbIYL3QG%b~ zu8XIm9t$UV81=+L+FDSlvE}r5JEDj!_T#9}8^_){^CAYZ=zc;xKZxqTr!1Dc`;x5* z-x3-;z?olAncCssB~!j|I>gcY%~=r)-QT73Ks~`p-E{cGI$_20yd^XlP-yB_EBm55 z@oNWsIp;*!Fb~bv)foMv%L~=jK;Zs?sk^6RbLss>x8v0pkkJ%0Sy#ivW(wL|JZEY< zrPf@`5Tv936=vltdh7;Bl6b?_LRa`3OEJa#!$?mX6P zo-?(XQmfF_$gSJ~1M+sNXGE^5YS~~|?QUNdN7j2gmE+Q^^PsG@@W9uGaV1quu_f%z z_+LK5S!SOgy_XI8T8^KT`vS#v{R@vZc5|tKJQ3gFZ^~Nkk(r*PhmkRfJO*1Y26-{q zkxdlUa8>sNKU~YB0<+TqS%N@p``6`dTN#G^16zI5Enf@sE#SruJ1ofZmPA8BHB{#j z`fz7lUMv=!MbzjTK7ZgYcFW)5Tdnjlb)TV3=~-}whCt(snS!!{%x}T)G^A~}@+<4f zDfjXZ@DL~7{)qa4z#ODc?Tj`xP9@YaN279Q@7b zyMO4`EfRp?!oIXW=#IeHj6$TdJveP4k^q;;FDak7B>R|Pn{LubU8IAtZ@iL1_ghn< zw%#l_?g^}yl87(BS|F~a$&fXB^}+VwTjf}%4~IvS(n#N43mA1bccE&Ucp8IhSV4=S zs#K{d133|SCYFcx!}OBLN;@>*$JOT4CaF(oO&9<;lV3ZUDxiG(6`RYHt;QbLOZa8G zG7X0JD{WML(rIoxU*Z>8+=Au%ob``%Hwz`QqSj=3<`J14y5!=kjmBk&Bp{Mnhdr#7P+nf)qnoUaPbZGn=REiFO3fd;u8_D^*j zKj!=mtj9h;@3_?FOs+B0_x3KEs8d?QqD_H1%HfB*B9Gf!edl&BZsrH#E|sOSdT>;e zqh(>Em4>kh??vKf-sZqiP~PNuFaT&#B>$RjjGPRfC8pL(Ef=3s*@3@OF47UB%B-Cx zenzTMF>IkwDeR0DdNSL%B$_!Qwm;WOZECv3jhR(}=ILa)Hd}+{G}-Pr<1c)kt^)Yo z;Rqjf>vxl-u&FAI1TOfWW1Eq~c*-+C{`U^Ooy$A}P4@)w#hpRIru3G^S#$DDsr#(y=Pu&}ilAUoLA{nwFcVhkPQBe?S4J%kTE zgv9YaB+P$%#HzLC!(IisB$(BGCR{Jpz3f3gO6n256}r7p?WoQ&QkfTzX#Jqu8+;`L zlOFxw&@fo&FGN*@(1rbl0=EnR%c?h{UkaN9%gi2ONxEj9?=w^M%yu=&HGqmxcUdR;mlH!>v=@L2xnb1nClhRoJ(bv@VT6>9~w^^l*+-tp>#vpc8rGG|j=uxd+= zz9j_{cteeIPEOttJ;G6}3t8!D%%wdd8^V-3yr;l`h7I?%)m}kqW;>u`Xw$t4p+W8l zWk0+O-VzGjf;9&)`7f=}oC<%Y!i-?Rgbj=O8?@RzdKrqMw)w9dO6J=gE0NG+y0f;{ zk!&`E**%TjmoJX@!4O>*My;lARhh#KPL@Dwe8JvI^Wt#A`sdHr|bnDXal~~TBV4nCz!B^uhHlw zxQp-XHfD7A+-w#F_pqHw6zi+31SoU#DtOF5KpC1ZtD3Wh&mg543GJ3O&KaW36Wga^ z#f?RkyD(FHrWwU7cQCc_Jzly$DK6eYQBK^*t%)prQsUEMJuo@mJT{zYu27MC!<{F- zk-bXLU?K&3S;l}B0ZtK ze;(%P-Dv{2L=>0~SM=*UA5{hMl$-rb`j?`b)~nFew2OC%)GuzHxSs@c z5jczr0-Yx3QTe(?WI6}^3Xr|?&>&rKt9w$!VdIeGoVCOEg&iH^i@gF}SNoNkQ{x;= z`1eI>XI^aGVq;6`H>hzt^6&O5yJvsionZDa^tpyl=#eeX^Hz?K29<##>uj&>HH(fO zM*z7{%$+9#!wwgt((Q(e7Xyppi7TW#%N)+){tIlB8w~^RT$eU!_W5eI_MO;jZ_d|? zrNogmQT`xMexq0gAM_FB4+2>?itFuZd651iM%jpqy*-X>q?PrRoYm5Y$GW7ml3dK^mqnnN6V$;ju^bR^kjI3s`p#gFKLOp7FO8UEoU zF{89Mzo;_CpkCBq!g-fe6bk2%d;Auon6Hk^{B=4Xytpp+wW33CH|s8hsFQnsSam>J zXTgWtmy#%)t%--51hkLkLZcG8$>Ro%kL z@x?JoT za`2>a|2i3+pnORrRmKPcVHMinSY+Eot1OA`(*I2^=d1$yLgiu7zmeK`4L{9qv2XpG z7qGSL@fk520rE*7lK`B<)PIBLqJ(}n?9`uURDI~7OM;L7H_QoWIVzI>w{7`@K1O9v kL7wq%^6it9(Fu1rGX9Otxc~K9+5>_Oo&maH7}b;i1>AQw`~Uy| From dcbd90164519ff37f2a92730249238e4dc55d6d4 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 10:31:18 +0200 Subject: [PATCH 16/55] Fix plan references to obsolete generator coords source --- docs/dev/plans/space-group-database.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index 3e0ef990c..a6b66b1d2 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -362,10 +362,13 @@ cryspy's `wyckoff.dat`, already holds the canonical ITA form for them `wyckoff.dat` + `numpy`/`sympy` (already project deps); `cctbx` is not used at all (it stays generation-only, relevant only if the generator is ever fully re-run). -5. **Guard both sides:** a generation-time invariant in the generator, a +5. **Guard the output:** the canonicalize post-process is the + invariant-enforcing step — it refuses to write unless every template is + canonical and the orbit is distinct — backed by a `tools/check_packaged_db.py` assertion rejecting operator-form leakage - in the packaged wheel, and a unit data-invariant over loaded - `SPACE_GROUPS`. + in the packaged wheel and a unit data-invariant over loaded + `SPACE_GROUPS`. (The generator stays cctbx extraction and cannot + self-assert this; see Decision 1 and CT2.) 6. **Record it in the ADR:** add the canonical-`coords_xyz` invariant as a decision and update _Build Provenance_ with the new DB SHA-256 and the transform's SHA-256. @@ -386,9 +389,11 @@ cryspy's `wyckoff.dat`, already holds the canonical ITA form for them `_fract_constrained_flags`) → rewrite `coords_xyz` (all other fields byte-identical). - `tmp/space-groups/helper-tools/generate_space_groups.py` — **local, - ignored** future-proofing (CT2): `_extract_wyckoff_positions` sources - `coords_xyz` from cryspy (not cctbx) + a generation-time invariant - rejecting operator-form leakage. Not re-run now. + ignored**: stays cctbx extraction; it **cannot** self-canonicalize + (cctbx always emits operator form, and the canonical spelling + checks + need the project env — see CT2). Its `_extract_wyckoff_positions` + docstring directs to the mandatory `canonicalize_coords.py` second + stage. Not re-run now. - `docs/dev/adrs/accepted/space-group-database/space_groups_overrides.yaml` — record any position the orbit match leaves ambiguous (curated vs International Tables). From 92c41124beef9ad157527eb7e134e81fb2631f3c Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 10:55:10 +0200 Subject: [PATCH 17/55] Validate canonical coords_xyz and coupled constraints --- .../dev/adrs/accepted/space-group-database.md | 38 +-- docs/dev/plans/space-group-database.md | 224 +++++++++--------- .../display/plotters/plotly.py | 10 +- src/easydiffraction/report/fit_plot.py | 13 +- .../test_crystallography_wyckoff.py | 25 ++ .../crystallography/test_space_groups.py | 23 ++ 6 files changed, 195 insertions(+), 138 deletions(-) diff --git a/docs/dev/adrs/accepted/space-group-database.md b/docs/dev/adrs/accepted/space-group-database.md index 3978b598a..6b35a77b5 100644 --- a/docs/dev/adrs/accepted/space-group-database.md +++ b/docs/dev/adrs/accepted/space-group-database.md @@ -314,18 +314,18 @@ ITA multiplicity. cryspy lists only the **primitive** orbit, so the full orbit is built by **expanding** each cryspy primitive element over the group's centering translations (the identity-rotation symops): `full = {primitive element + centering vector}`, yielding exactly -`multiplicity` distinct canonical templates. Every replacement is verified -**exactly**: `len == multiplicity` and `len(set) == multiplicity` (a -proper full orbit with distinct elements — no collapsed duplicates); no -operator form and no fractional coefficient; the representative's -`_fract_constrained_flags` free-axis count equals the manifold's rank -(rejecting non-minimal spellings such as `(x-y,-x+y,z)`); and -parametrization-independent geometric equivalence to the cctbx orbit -(every element on a cctbx manifold, every cctbx manifold covered). The -no-operator-form and no-duplicate invariants are enforced by the -post-process before it writes, in the unit tests, and (for operator form) -by `tools/check_packaged_db.py`, which rejects any operator-form template -in the packaged wheel. +`multiplicity` distinct canonical templates. Every replacement is +verified **exactly**: `len == multiplicity` and +`len(set) == multiplicity` (a proper full orbit with distinct elements — +no collapsed duplicates); no operator form and no fractional +coefficient; the representative's `_fract_constrained_flags` free-axis +count equals the manifold's rank (rejecting non-minimal spellings such +as `(x-y,-x+y,z)`); and parametrization-independent geometric +equivalence to the cctbx orbit (every element on a cctbx manifold, every +cctbx manifold covered). The no-operator-form and no-duplicate +invariants are enforced by the post-process before it writes, in the +unit tests, and (for operator form) by `tools/check_packaged_db.py`, +which rejects any operator-form template in the packaged wheel. ## Consequences @@ -439,13 +439,13 @@ pixi exec --spec cctbx --spec gemmi --spec sympy --spec pyyaml \ --print-summary ``` -**Canonical-`coords_xyz` correction (§9) — mandatory second stage.** -The rebuild has **two mandatory stages**, and the generator run above is +**Canonical-`coords_xyz` correction (§9) — mandatory second stage.** The +rebuild has **two mandatory stages**, and the generator run above is only the first. The generator emits cctbx operator-form `coords_xyz` for coupled special positions and **cannot** emit canonical form itself: -cctbx always produces operator form, and the canonical ITA spelling lives -in cryspy's `wyckoff.dat`. The generator alone therefore does **not** -produce a shippable database. It **must** be followed by the +cctbx always produces operator form, and the canonical ITA spelling +lives in cryspy's `wyckoff.dat`. The generator alone therefore does +**not** produce a shippable database. It **must** be followed by the canonicalization post-process, which is the **invariant-enforcing step** — it re-sources canonical ITA `coords_xyz` from cryspy's `wyckoff.dat` and refuses to write unless every template is canonical (no operator @@ -479,8 +479,8 @@ Build environment: Generated and curation artifacts: -- `src/easydiffraction/crystallography/space_groups.json.gz` - (after the §9 canonical-`coords_xyz` correction): +- `src/easydiffraction/crystallography/space_groups.json.gz` (after the + §9 canonical-`coords_xyz` correction): `390f0e9d0ebe27a52ee5680a1bc686123ba84c8751302fed4dee4dfaf7edf7b4` - `tmp/space-groups/helper-tools/generate_space_groups.py`: `3aa5f03cd1a69bdfe0a280158c9343b65d5eaa4d75a6d58f2606fb5fbe3df83d` diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index a6b66b1d2..6a2d50c0a 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -294,84 +294,86 @@ above is complete._ ### Problem The bundled `space_groups.json.gz` stores cctbx **operator-form** -`coords_xyz` — e.g. R-3m (IT 166) `h` is `(1/2*x-1/2*y,-1/2*x+1/2*y,z)` — -for the coupled special positions (verified: 3826 templates; per the +`coords_xyz` — e.g. R-3m (IT 166) `h` is `(1/2*x-1/2*y,-1/2*x+1/2*y,z)` +— for the coupled special positions (verified: 3826 templates; per the wyckoff plan's Decision 15, 288 positions across 117 IT numbers). -`_fract_constrained_flags()` (`crystallography.py:221`) decides which axis -is constrained purely by **which variable symbol is absent** from the -representative: canonical `(x,-x,z)` has `y` absent → `fract_y` constrained -→ slaved to `-x`; but operator-form `(1/2*x-1/2*y,…)` makes **both `x` and -`y` appear** → `fract_y` is wrongly "free" and the `y=-x` coupling is -lost, so a refined special-position coordinate drifts off its symmetry -site (the `ed-6` fit-3 → fit-4 regression). `_apply_fract_constraints()` -(`:250`) and `_parse_rotation_matrix()` (`:350`, which does -`int(coeff_str)`) share the same expectation. The constraint **code** is -correct; only the **data** spelling is wrong. **Root cause:** the -generator emitted cctbx operator-form `coords_xyz` for these positions -instead of cryspy's canonical form; the ADR's intended Wyckoff source, -cryspy's `wyckoff.dat`, already holds the canonical ITA form for them -(verified — R-3m gives `(x,x,1/2)`, `(x,-x,1/2)`, …). +`_fract_constrained_flags()` (`crystallography.py:221`) decides which +axis is constrained purely by **which variable symbol is absent** from +the representative: canonical `(x,-x,z)` has `y` absent → `fract_y` +constrained → slaved to `-x`; but operator-form `(1/2*x-1/2*y,…)` makes +**both `x` and `y` appear** → `fract_y` is wrongly "free" and the `y=-x` +coupling is lost, so a refined special-position coordinate drifts off +its symmetry site (the `ed-6` fit-3 → fit-4 regression). +`_apply_fract_constraints()` (`:250`) and `_parse_rotation_matrix()` +(`:350`, which does `int(coeff_str)`) share the same expectation. The +constraint **code** is correct; only the **data** spelling is wrong. +**Root cause:** the generator emitted cctbx operator-form `coords_xyz` +for these positions instead of cryspy's canonical form; the ADR's +intended Wyckoff source, cryspy's `wyckoff.dat`, already holds the +canonical ITA form for them (verified — R-3m gives `(x,x,1/2)`, +`(x,-x,1/2)`, …). ### Decisions (this phase) 1. **Produce canonical `coords_xyz` via a cctbx-free post-process that re-sources from cryspy's `wyckoff.dat`.** The root cause is that the - generator's `_extract_wyckoff_positions` built `coords_xyz` from cctbx - (`position.unique_ops().as_xyz()`, operator form) while cryspy's - `wyckoff.dat` — the ADR's intended Wyckoff source — was read only for - count-validation. A Wyckoff orbit is a list of **distinct - point-functions** (one per equivalent site), not a set of manifolds. A - local tool loads the bundled DB and, for each operator-form position, - builds the **full** canonical orbit by **expanding** the cryspy - primitive orbit over the group's centering translations (the + generator's `_extract_wyckoff_positions` built `coords_xyz` from + cctbx (`position.unique_ops().as_xyz()`, operator form) while + cryspy's `wyckoff.dat` — the ADR's intended Wyckoff source — was read + only for count-validation. A Wyckoff orbit is a list of **distinct + point-functions** (one per equivalent site), not a set of manifolds. + A local tool loads the bundled DB and, for each operator-form + position, builds the **full** canonical orbit by **expanding** the + cryspy primitive orbit over the group's centering translations (the identity-rotation symops): each cryspy primitive element shifted by each centering vector yields one canonical full-orbit element. This **preserves the full (centered) orbit** — `coords_xyz` length stays equal to the multiplicity, matching the #187 baseline — with **distinct** elements. (cctbx stores the full centered orbit; cryspy - lists only the **primitive** orbit, with centering implicit.) Canonical - form = each component a signed single free variable (or an + lists only the **primitive** orbit, with centering implicit.) + Canonical form = each component a signed single free variable (or an integer-coefficient ITA combination such as `x-y`) plus an optional - rational constant — **no fractional coefficient on a variable** — with - each genuine free DOF reduced to one canonical variable so dependent - axes' symbols are absent. _Rejected alternatives: (a) replacing - `coords_xyz` with cryspy's orbit **directly** silently reduces centered - orbits to primitive, breaking the length-equals-multiplicity invariant - (review-1 [Finding 2]); (b) re-spelling each cctbx element by **column - space** collapses distinct point-functions sharing a manifold into - **duplicate** templates (review-2 [Finding 1]). The centering expansion - avoids both. No cctbx re-run is needed; fixing the generator + full - cctbx re-run adds a heavy install + reproducibility risk for the same - cryspy↔cctbx reconciliation._ + rational constant — **no fractional coefficient on a variable** — + with each genuine free DOF reduced to one canonical variable so + dependent axes' symbols are absent. _Rejected alternatives: (a) + replacing `coords_xyz` with cryspy's orbit **directly** silently + reduces centered orbits to primitive, breaking the + length-equals-multiplicity invariant (review-1 [Finding 2]); (b) + re-spelling each cctbx element by **column space** collapses distinct + point-functions sharing a manifold into **duplicate** templates + (review-2 [Finding 1]). The centering expansion avoids both. No cctbx + re-run is needed; fixing the generator + full cctbx re-run adds a + heavy install + reproducibility risk for the same cryspy↔cctbx + reconciliation._ 2. **Verify each replacement two ways** (review-1 [P1] plus the CT1 - correctness gap): (a) **exact symbolic orbit equivalence** (`sympy`) — - the cryspy canonical orbit and the cctbx operator-form orbit describe - the same point set as rational affine forms, not merely agree at - sampled parameters; **and** (b) **constraint correctness** — the - canonical representative's free-symbol set produces the right + correctness gap): (a) **exact symbolic orbit equivalence** (`sympy`) + — the cryspy canonical orbit and the cctbx operator-form orbit + describe the same point set as rational affine forms, not merely + agree at sampled parameters; **and** (b) **constraint correctness** — + the canonical representative's free-symbol set produces the right `_fract_constrained_flags()` (free-DOF count matches the orbit's true - dimensionality; dependent axes constrained). Orbit equivalence alone is - insufficient: a non-minimal form like `(x-y,-x+y,z)` would pass it yet - leave `fract_y` wrongly free. _Rejected alternative — a blind `sympy` - re-parametrise of the existing operator strings — risks exactly that - non-minimal failure mode and re-derives the ITA convention cryspy - already encodes._ + dimensionality; dependent axes constrained). Orbit equivalence alone + is insufficient: a non-minimal form like `(x-y,-x+y,z)` would pass it + yet leave `fract_y` wrongly free. _Rejected alternative — a blind + `sympy` re-parametrise of the existing operator strings — risks + exactly that non-minimal failure mode and re-derives the ITA + convention cryspy already encodes._ 3. **No constraint-code change.** `_fract_constrained_flags()` / `_apply_fract_constraints()` are correct as-is. 4. **No new dependency, no cctbx.** The post-process uses `cryspy`'s - `wyckoff.dat` + `numpy`/`sympy` (already project deps); `cctbx` is not - used at all (it stays generation-only, relevant only if the generator - is ever fully re-run). + `wyckoff.dat` + `numpy`/`sympy` (already project deps); `cctbx` is + not used at all (it stays generation-only, relevant only if the + generator is ever fully re-run). 5. **Guard the output:** the canonicalize post-process is the - invariant-enforcing step — it refuses to write unless every template is - canonical and the orbit is distinct — backed by a - `tools/check_packaged_db.py` assertion rejecting operator-form leakage - in the packaged wheel and a unit data-invariant over loaded + invariant-enforcing step — it refuses to write unless every template + is canonical and the orbit is distinct — backed by a + `tools/check_packaged_db.py` assertion rejecting operator-form + leakage in the packaged wheel and a unit data-invariant over loaded `SPACE_GROUPS`. (The generator stays cctbx extraction and cannot self-assert this; see Decision 1 and CT2.) -6. **Record it in the ADR:** add the canonical-`coords_xyz` invariant as a - decision and update _Build Provenance_ with the new DB SHA-256 and the - transform's SHA-256. +6. **Record it in the ADR:** add the canonical-`coords_xyz` invariant as + a decision and update _Build Provenance_ with the new DB SHA-256 and + the transform's SHA-256. ### Open questions (this phase) @@ -383,11 +385,11 @@ cryspy's `wyckoff.dat`, already holds the canonical ITA form for them - `src/easydiffraction/crystallography/space_groups.json.gz` — rewritten with canonical `coords_xyz`; all other fields unchanged. -- `tmp/space-groups/helper-tools/canonicalize_coords.py` — **new**, local - ignored cctbx-free post-process: load DB → orbit-match each position to - cryspy's canonical orbit → verify (mod-1 orbit membership + - `_fract_constrained_flags`) → rewrite `coords_xyz` (all other fields - byte-identical). +- `tmp/space-groups/helper-tools/canonicalize_coords.py` — **new**, + local ignored cctbx-free post-process: load DB → orbit-match each + position to cryspy's canonical orbit → verify (mod-1 orbit + membership + `_fract_constrained_flags`) → rewrite `coords_xyz` (all + other fields byte-identical). - `tmp/space-groups/helper-tools/generate_space_groups.py` — **local, ignored**: stays cctbx extraction; it **cannot** self-canonicalize (cctbx always emits operator form, and the canonical spelling + checks @@ -418,58 +420,60 @@ cryspy's `wyckoff.dat`, already holds the canonical ITA form for them Per-step commit discipline as in Phase 1, **with the same deliberate exception** that `tmp/space-groups/helper-tools/*` are local curation -tooling, not branch deliverables (review-1 [P1]). The local transform and -generator changes are therefore **not their own commits**: each tracked -commit stages only the tracked deliverable it produces, and the local -tools are recorded by SHA-256 in the ADR provenance (CT4). No step commits -only ignored files, and no empty commits. +tooling, not branch deliverables (review-1 [P1]). The local transform +and generator changes are therefore **not their own commits**: each +tracked commit stages only the tracked deliverable it produces, and the +local tools are recorded by SHA-256 in the ADR provenance (CT4). No step +commits only ignored files, and no empty commits. - [x] **CT1 — Canonicalise the DB via the cctbx-free post-process.** Finish the local - `tmp/space-groups/helper-tools/canonicalize_coords.py`: parse cryspy - `wyckoff.dat`, then build each operator-form position's **full** - canonical orbit by **expanding the cryspy primitive orbit over the - group's centering translations** (`coords_xyz` length equals the - multiplicity, all elements **distinct**). Verify per position, - **exactly** — `len(set) == multiplicity` (distinct full orbit), no - operator form, no fractional coefficient, correct + `tmp/space-groups/helper-tools/canonicalize_coords.py`: parse + cryspy `wyckoff.dat`, then build each operator-form position's + **full** canonical orbit by **expanding the cryspy primitive orbit + over the group's centering translations** (`coords_xyz` length + equals the multiplicity, all elements **distinct**). Verify per + position, **exactly** — `len(set) == multiplicity` (distinct full + orbit), no operator form, no fractional coefficient, correct `_fract_constrained_flags()` (free-axis count equals the manifold - rank), and parametrization-independent geometric equivalence to the - cctbx orbit. Curate against International Tables any case the + rank), and parametrization-independent geometric equivalence to + the cctbx orbit. Curate against International Tables any case the cryspy match leaves ambiguous, recording it in `space_groups_overrides.yaml`. Run it to rewrite - `src/easydiffraction/crystallography/space_groups.json.gz` (R-3m `h` - → `(x,-x,z)`, 18-element full orbit; all non-`coords_xyz` fields - byte-identical). The tool is local tooling (recorded by SHA in CT4); - **this commit stages only the regenerated `space_groups.json.gz`**. - Commit: `Canonicalize space-group coords_xyz templates` + `src/easydiffraction/crystallography/space_groups.json.gz` (R-3m + `h` → `(x,-x,z)`, 18-element full orbit; all non-`coords_xyz` + fields byte-identical). The tool is local tooling (recorded by SHA + in CT4); **this commit stages only the regenerated + `space_groups.json.gz`**. Commit: + `Canonicalize space-group coords_xyz templates` - [x] **CT2 — Make the durable rebuild path two-stage with an invariant-enforcing post-process (local prep, no commit).** The generator (`generate_space_groups.py`) runs in a throwaway - cctbx-only env, and cctbx **always** emits operator-form coords for - coupled positions — so the generator cannot itself source canonical - coords or self-assert a no-operator-form invariant (the canonical - spelling lives in cryspy's `wyckoff.dat`, and the constraint check - needs `easydiffraction`, i.e. the project env). The durable rebuild - path is therefore **two mandatory stages**: (1) the generator - (cctbx env), then (2) `canonicalize_coords.py --write` (project - env), which is the **invariant-enforcing step** — it re-sources - canonical ITA coords, verifies each exactly, and refuses to write - unless every template is canonical (no operator form, no fractional - coefficient). The generator's `_extract_wyckoff_positions` docstring - directs to this mandatory post-process and the ADR _Build - Provenance_ documents both stages (review-1 [Finding 1]). **No - re-run now** (CT1 already produced the canonical DB). Local curation - tooling — not committed; its SHA-256 is recorded in CT4. + cctbx-only env, and cctbx **always** emits operator-form coords + for coupled positions — so the generator cannot itself source + canonical coords or self-assert a no-operator-form invariant (the + canonical spelling lives in cryspy's `wyckoff.dat`, and the + constraint check needs `easydiffraction`, i.e. the project env). + The durable rebuild path is therefore **two mandatory stages**: + (1) the generator (cctbx env), then (2) + `canonicalize_coords.py --write` (project env), which is the + **invariant-enforcing step** — it re-sources canonical ITA coords, + verifies each exactly, and refuses to write unless every template + is canonical (no operator form, no fractional coefficient). The + generator's `_extract_wyckoff_positions` docstring directs to this + mandatory post-process and the ADR _Build Provenance_ documents + both stages (review-1 [Finding 1]). **No re-run now** (CT1 already + produced the canonical DB). Local curation tooling — not + committed; its SHA-256 is recorded in CT4. - [x] **CT3 — Packaging assertion.** Extend the tracked `tools/check_packaged_db.py` to assert no packaged `coords_xyz` template is operator-form (catches future regression at the wheel layer). Commit: `Assert canonical coords_xyz in packaged DB check` -- [x] **CT4 — ADR invariant + provenance.** Add the canonical-`coords_xyz` - invariant as a decision in +- [x] **CT4 — ADR invariant + provenance.** Add the + canonical-`coords_xyz` invariant as a decision in `docs/dev/adrs/accepted/space-group-database.md`, and update its - _Build Provenance_ with the new `space_groups.json.gz` SHA-256, the - `canonicalize_coords.py` transform SHA-256, **and the updated + _Build Provenance_ with the new `space_groups.json.gz` SHA-256, + the `canonicalize_coords.py` transform SHA-256, **and the updated `generate_space_groups.py` SHA-256** plus the canonical-invariant step in the rebuild path (review-1 [P2]). Commit: `Record canonical coords_xyz invariant and provenance` @@ -491,8 +495,8 @@ pixi run script-tests > /tmp/easydiffraction-script.log 2>&1; script_tests_exit_ ``` Then the packaging regression from #187's Phase 2 (build the wheel + -`python tools/check_packaged_db.py dist/*.whl`), which now also exercises -the new operator-form assertion. +`python tools/check_packaged_db.py dist/*.whl`), which now also +exercises the new operator-form assertion. ### Suggested Pull Request — canonical-templates fix @@ -500,10 +504,10 @@ the new operator-form assertion. **Description:** A refined atom on certain special positions (sites with linked coordinates, like `(x, -x, z)`) could drift off its symmetry -position during a fit, because the bundled space-group table stored those -coordinate templates in an internal operator form the symmetry-constraint -code didn't recognise. This change rewrites every affected template into -the standard International Tables form so the constraints hold, adds -guards so the table can't silently regress, and fixes the related `ed-6` -tutorial refinement. It also unblocks automatic Wyckoff-position -detection, which builds on these canonical templates. +position during a fit, because the bundled space-group table stored +those coordinate templates in an internal operator form the +symmetry-constraint code didn't recognise. This change rewrites every +affected template into the standard International Tables form so the +constraints hold, adds guards so the table can't silently regress, and +fixes the related `ed-6` tutorial refinement. It also unblocks automatic +Wyckoff-position detection, which builds on these canonical templates. diff --git a/src/easydiffraction/display/plotters/plotly.py b/src/easydiffraction/display/plotters/plotly.py index 383ac7b14..8bfed31a4 100644 --- a/src/easydiffraction/display/plotters/plotly.py +++ b/src/easydiffraction/display/plotters/plotly.py @@ -2308,11 +2308,12 @@ def _baseline_non_bragg_row_heights( *, has_residual: bool, ) -> tuple[float, float | None]: - """Return fixed main and residual row heights in pixels. + """ + Return fixed main and residual row heights in pixels. Anchored to the reference three-row layout so the main and - residual rows keep their pixel height regardless of which - rows are shown; ``_composite_figure_height`` adapts instead. + residual rows keep their pixel height regardless of which rows + are shown; ``_composite_figure_height`` adapts instead. """ baseline_height = cls._base_composite_height_pixels(plot_spec) plot_area_height = cls._composite_plot_area_height(baseline_height) @@ -2358,7 +2359,8 @@ def _get_powder_composite_rows(plot_spec: PowderMeasVsCalcSpec) -> PowderComposi @classmethod def _composite_figure_height(cls, layout: PowderCompositeRows) -> float: - """Return figure height matching the row pixel heights. + """ + Return figure height matching the row pixel heights. Each entry in ``layout.row_heights`` is an absolute pixel target. Plotly distributes the plot area across rows by diff --git a/src/easydiffraction/report/fit_plot.py b/src/easydiffraction/report/fit_plot.py index cfa0c5756..3ffe55df0 100644 --- a/src/easydiffraction/report/fit_plot.py +++ b/src/easydiffraction/report/fit_plot.py @@ -105,12 +105,13 @@ def fit_plot_ranges(fit_data: dict[str, Any]) -> dict[str, float]: def fit_plot_geometry(fit_data: dict[str, Any]) -> dict[str, float]: - """Return Plotly-matched pgfplots axis geometry. + """ + Return Plotly-matched pgfplots axis geometry. Row heights are anchored to the reference three-row layout so the main and residual panels keep a fixed centimetre height; the axis - stack grows or shrinks with the rows shown, matching the - interactive composite figure. + stack grows or shrinks with the rows shown, matching the interactive + composite figure. """ bragg_tick_sets = fit_data.get('bragg_tick_sets') or [] has_bragg_ticks = bool(bragg_tick_sets) @@ -236,7 +237,8 @@ def _has_residual(fit_data: dict[str, Any]) -> bool: def _non_bragg_row_heights(*, has_residual: bool) -> tuple[float, float | None]: - """Return fixed main and residual row heights in pixels. + """ + Return fixed main and residual row heights in pixels. Anchored to the reference three-row layout so the rows keep a constant height regardless of which rows the figure shows. @@ -254,7 +256,8 @@ def _non_bragg_row_heights(*, has_residual: bool) -> tuple[float, float | None]: def _figure_cm_per_pixel() -> float: - """Return the fixed cm-per-pixel scale for fit-figure rows. + """ + Return the fixed cm-per-pixel scale for fit-figure rows. Anchored so the reference three-row layout fills the nominal axis stack height (axis width times the reference aspect ratio). diff --git a/tests/unit/easydiffraction/crystallography/test_crystallography_wyckoff.py b/tests/unit/easydiffraction/crystallography/test_crystallography_wyckoff.py index 377ed7f2f..c01661492 100644 --- a/tests/unit/easydiffraction/crystallography/test_crystallography_wyckoff.py +++ b/tests/unit/easydiffraction/crystallography/test_crystallography_wyckoff.py @@ -54,6 +54,20 @@ def test_valid_applies_constraints(self): result = apply_atom_site_symmetry_constraints(atom, 'P m -3 m', '1', 'a') assert result is not None + def test_coupled_special_position_slaves_dependent_axis(self): + from easydiffraction.crystallography.crystallography import ( + apply_atom_site_symmetry_constraints, + ) + + # R -3 m (IT 166), coord_code='h', Wyckoff 'h' = (x,-x,z): editing + # fract_x slaves fract_y to -fract_x while fract_x/fract_z stay free + # (the ed-6 coupled-position regression). + atom = {'fract_x': 0.3, 'fract_y': 0.0, 'fract_z': 0.5} + result = apply_atom_site_symmetry_constraints(atom, 'R -3 m', 'h', 'h') + assert result['fract_x'] == 0.3 + assert result['fract_y'] == -0.3 + assert result['fract_z'] == 0.5 + class TestAtomSiteSymmetryConstrainedFlags: def test_special_position_all_fixed(self): @@ -74,6 +88,17 @@ def test_general_position_all_free(self): flags = atom_site_symmetry_constrained_flags('P 1', '1', 'a') assert flags == {'fract_x': False, 'fract_y': False, 'fract_z': False} + def test_coupled_special_position_constrains_dependent_axis(self): + from easydiffraction.crystallography.crystallography import ( + atom_site_symmetry_constrained_flags, + ) + + # R -3 m (IT 166), Wyckoff 'h' = (x,-x,z): fract_y is slaved to -x, + # so only fract_y is constrained. Operator-form coords_xyz would + # wrongly mark fract_y free (the canonical-templates regression). + flags = atom_site_symmetry_constrained_flags('R -3 m', 'h', 'h') + assert flags == {'fract_x': False, 'fract_y': True, 'fract_z': False} + def test_invalid_returns_all_false(self, monkeypatch): from easydiffraction.crystallography.crystallography import ( atom_site_symmetry_constrained_flags, diff --git a/tests/unit/easydiffraction/crystallography/test_space_groups.py b/tests/unit/easydiffraction/crystallography/test_space_groups.py index 37eab7235..0ecb1656a 100644 --- a/tests/unit/easydiffraction/crystallography/test_space_groups.py +++ b/tests/unit/easydiffraction/crystallography/test_space_groups.py @@ -2,6 +2,8 @@ # SPDX-License-Identifier: BSD-3-Clause """Unit tests for the space-group reference-data loader.""" +import re + from easydiffraction.crystallography.space_groups import SPACE_GROUPS _EXPECTED_RECORD_KEYS = { @@ -24,6 +26,11 @@ # runtime coordinate-code aliases. A deliberate regeneration updates this. _EXPECTED_RECORD_COUNT = 816 +# Canonical coords_xyz forbids operator form (``1/2*x``) and fractional +# coefficients (``5/4x``); integer coefficients (``2x``) and rational +# constants (``x+1/2``) are allowed. +_NONCANONICAL_COORD = re.compile(r'[0-9.]\s*\*\s*[xyz]|[xyz]\s*\*|\d+/\d+\s*[xyz]') + def test_module_import(): import easydiffraction.crystallography.space_groups as MUT @@ -72,3 +79,19 @@ def test_every_record_has_the_expected_schema(): assert isinstance(position['multiplicity'], int) assert isinstance(position['coords_xyz'], list) assert position['coords_xyz'] + + +def test_coords_xyz_are_canonical_distinct_full_orbits(): + """Every Wyckoff coords_xyz is a canonical, distinct, full orbit. + + Regression guard for the canonical-templates fix: no operator-form or + fractional-coefficient spelling, no duplicate template, and a length + equal to the multiplicity (the full centered orbit). + """ + for key, record in SPACE_GROUPS.items(): + for letter, position in record['Wyckoff_positions'].items(): + coords = position['coords_xyz'] + for template in coords: + assert not _NONCANONICAL_COORD.search(template), (key, letter, template) + assert len(set(coords)) == len(coords), (key, letter) + assert len(coords) == position['multiplicity'], (key, letter) From 3053cca9f762290a972596f9b8562d50b0524321 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 11:03:42 +0200 Subject: [PATCH 18/55] Note plotting-module docstring fix for Phase 2 review --- docs/dev/plans/space-group-database.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index 6a2d50c0a..263f9e8d2 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -498,6 +498,17 @@ Then the packaging regression from #187's Phase 2 (build the wheel + `python tools/check_packaged_db.py dist/*.whl`), which now also exercises the new operator-form assertion. +**Verification note (for `/review-impl-2`).** Phase 2's `pixi run fix` +also reformatted docstrings in +`src/easydiffraction/display/plotters/plotly.py` and +`src/easydiffraction/report/fit_plot.py` — **pre-existing** debt from +this branch's plotting commits (`bb817a5fd`, `176e6e682`, `bec2f5e73`), +surfaced by the recently-enabled `format-docstring` hook and required +for `pixi run check` to pass. It is **unrelated** to canonical-templates +and was folded into the verification commit `92c41124b` (authored +manually); drop or move it if this branch is split from the plotting +stream. + ### Suggested Pull Request — canonical-templates fix **Title:** Store space-group Wyckoff coordinates in canonical form From f7948c93ce3857fda126c1cd9a443841b26bdd30 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 11:11:58 +0200 Subject: [PATCH 19/55] Mark Phase 2 verification complete --- docs/dev/plans/space-group-database.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index 263f9e8d2..b4ca81729 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -289,7 +289,7 @@ above is complete._ - [x] Phase 1 — Implementation (data + tooling + docs) - [x] Phase 1 review gate -- [ ] Phase 2 — Verification (tests + checks) +- [x] Phase 2 — Verification (tests + checks) ### Problem From 833df9ac3cb21864ca5e9e4851c9551f33de8acb Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 11:18:35 +0200 Subject: [PATCH 20/55] Assert R-3m special positions stay on-site after fit --- .../test_powder-diffraction_constant-wavelength.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/integration/fitting/test_powder-diffraction_constant-wavelength.py b/tests/integration/fitting/test_powder-diffraction_constant-wavelength.py index d4c22b857..17f84be3d 100644 --- a/tests/integration/fitting/test_powder-diffraction_constant-wavelength.py +++ b/tests/integration/fitting/test_powder-diffraction_constant-wavelength.py @@ -478,6 +478,20 @@ def test_fit_neutron_pd_cwl_hs() -> None: decimal=1, ) + # ed-6 regression: O and H sit on R-3m 'h' = (x,-x,z), so after freeing + # and refining fract_x, fract_y must stay slaved to -fract_x (on-site). + # Operator-form coords_xyz wrongly freed fract_y and let them drift. + assert_almost_equal( + model.atom_sites['O'].fract_y.value, + desired=-model.atom_sites['O'].fract_x.value, + decimal=6, + ) + assert_almost_equal( + model.atom_sites['H'].fract_y.value, + desired=-model.atom_sites['H'].fract_x.value, + decimal=6, + ) + def test_single_fit_neutron_pd_cwl_lbco_with_constraints_from_project(tmp_path) -> None: import easydiffraction as ed From d4cb540bba73b0fdedd32c4eb3986f3808063d6b Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 11:28:39 +0200 Subject: [PATCH 21/55] Confirm wyckoff letter detection ADR gate --- docs/dev/plans/wyckoff-letter-detection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index 11b115ec7..df461e285 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -249,7 +249,7 @@ before moving to the next step or the Phase 1 review gate**, per The ADR commit + design-phase review/reply cleanup are handled by `/draft-impl-1` Phase A before P1.1. -- [ ] **P1.0 — Verify the ADR gate and the §10 prerequisite.** No code. +- [x] **P1.0 — Verify the ADR gate and the §10 prerequisite.** No code. Ensure `git branch --show-current` is `wyckoff-letter-detection`; if not, stop before editing and ask the user to switch to the target branch outside the shortcut. Confirm the ADR on disk From 16896f36c49a03c3ef8521b94bb03b66bb69e7cd Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 11:47:32 +0200 Subject: [PATCH 22/55] Add Wyckoff orbit detection to crystallography module --- docs/dev/plans/wyckoff-letter-detection.md | 2 +- .../crystallography/__init__.py | 4 + .../crystallography/crystallography.py | 211 +++++++++++++++++- 3 files changed, 215 insertions(+), 2 deletions(-) diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index df461e285..16a81e673 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -264,7 +264,7 @@ The ADR commit + design-phase review/reply cleanup are handled by remains, **stop**: the space-group-database prerequisite must land before this plan's detection and snapping can be implemented. Commit: `Confirm wyckoff letter detection ADR gate` -- [ ] **P1.1 — Orbit matcher in the crystallography submodule.** Add to +- [x] **P1.1 — Orbit matcher in the crystallography submodule.** Add to `crystallography.py`: frozen `WyckoffPosition(letter, multiplicity, site_symmetry, coord_template)`, `_WYCKOFF_DETECTION_TOL = 1e-3`, `_normalize_coord_code()`, diff --git a/src/easydiffraction/crystallography/__init__.py b/src/easydiffraction/crystallography/__init__.py index 4e798e209..080e2094d 100644 --- a/src/easydiffraction/crystallography/__init__.py +++ b/src/easydiffraction/crystallography/__init__.py @@ -1,2 +1,6 @@ # SPDX-FileCopyrightText: 2026 EasyScience contributors # SPDX-License-Identifier: BSD-3-Clause + +from easydiffraction.crystallography.crystallography import WyckoffPosition +from easydiffraction.crystallography.crystallography import detect_wyckoff_position +from easydiffraction.crystallography.crystallography import wyckoff_position_info diff --git a/src/easydiffraction/crystallography/crystallography.py b/src/easydiffraction/crystallography/crystallography.py index 8359d551a..da340fea2 100644 --- a/src/easydiffraction/crystallography/crystallography.py +++ b/src/easydiffraction/crystallography/crystallography.py @@ -1,6 +1,8 @@ # SPDX-FileCopyrightText: 2025 EasyScience contributors # SPDX-License-Identifier: BSD-3-Clause +import itertools +from dataclasses import dataclass from fractions import Fraction from typing import Any @@ -16,6 +18,56 @@ from easydiffraction.crystallography.space_groups import SPACE_GROUPS from easydiffraction.utils.logging import log +# Maximum residual (in fractional units) for a coordinate to be considered +# on a Wyckoff orbit during detection. +_WYCKOFF_DETECTION_TOL = 1e-3 + + +@dataclass(frozen=True) +class WyckoffPosition: + """A resolved Wyckoff position and the orbit representative matched. + + Parameters + ---------- + letter : str + Wyckoff letter (e.g. ``'h'``). + multiplicity : int + Site multiplicity (the full orbit size). + site_symmetry : str + International Tables site-symmetry symbol. + coord_template : str | None + Nearest matched orbit representative (e.g. ``'(x,-x,z)'``), or + ``None`` for a table lookup made without coordinates. This is what + coordinate snapping and constrained-axis flags consume. + """ + + letter: str + multiplicity: int + site_symmetry: str + coord_template: str | None + + +def _normalize_coord_code(coord_code: str | None) -> str | None: + """Normalize a coordinate-system code to the ``SPACE_GROUPS`` key form. + + The empty string (used by consumers for groups with no coordinate + code, e.g. triclinic P1/P-1) maps to ``None``, which is how those + settings are keyed in ``SPACE_GROUPS``. + + Parameters + ---------- + coord_code : str | None + Incoming coordinate-system code. + + Returns + ------- + str | None + ``None`` for the empty string, otherwise ``coord_code`` unchanged. + """ + if coord_code == '': + return None + return coord_code + def apply_cell_symmetry_constraints( cell: dict[str, float], @@ -202,6 +254,7 @@ def _get_wyckoff_exprs( log.error(f"Failed to get IT_number for name_H-M '{name_hm}'") return None + coord_code = _normalize_coord_code(coord_code) if coord_code is None: log.error('IT_coordinate_system_code is not set') return None @@ -415,7 +468,7 @@ def _get_general_position_ops( list[tuple[np.ndarray, np.ndarray]] | None List of (rotation, translation) pairs, or ``None`` on failure. """ - key = (it_number, coord_code) + key = (it_number, _normalize_coord_code(coord_code)) if key not in SPACE_GROUPS: # Not in the local SPACE_GROUPS table (e.g. P 1, where cryspy # reports no coordinate-system codes). The caller falls back to @@ -430,6 +483,162 @@ def _get_general_position_ops( return [_parse_rotation_matrix(c) for c in general_coords] +def _orbit_template_residual(point: np.ndarray, rot: np.ndarray, trans: np.ndarray) -> float: + """Return the mod-1 distance from ``point`` to an orbit template. + + The template manifold is ``{rot·v + trans}``; the point lies on it for + some free ``v`` when the residual is ~0. Integer lattice shifts account + for unit-cell periodicity. + + Parameters + ---------- + point : np.ndarray + Fractional coordinate reduced into the unit cell. + rot : np.ndarray + (3, 3) rotation part of the template. + trans : np.ndarray + (3,) translation part of the template. + + Returns + ------- + float + Smallest residual over the candidate lattice shifts. + """ + rot_float = rot.astype(float) + base = point - trans + best = np.inf + for shift in itertools.product((-1.0, 0.0, 1.0), repeat=3): + rhs = base - np.array(shift) + solution, *_ = np.linalg.lstsq(rot_float, rhs, rcond=None) + residual = float(np.linalg.norm(rot_float @ solution - rhs)) + best = min(best, residual) + return best + + +def _nearest_orbit_template(point: np.ndarray, coords_xyz: list[str]) -> tuple[str, float]: + """Return the orbit template nearest to ``point`` and its residual. + + On near-ties (e.g. centering copies that share a manifold mod 1) the + earlier, canonical representative is kept for deterministic output; the + free-parameter-solving snap downstream is correct for any of them. + """ + best_template = coords_xyz[0] + best_residual = np.inf + for template in coords_xyz: + rot, trans = _parse_rotation_matrix(template) + residual = _orbit_template_residual(point, rot, trans) + if residual < best_residual - 1e-9: + best_residual = residual + best_template = template + return best_template, best_residual + + +def detect_wyckoff_position( + name_hm: str, + coord_code: str | None, + fract_xyz: tuple[float, float, float], + tol: float = _WYCKOFF_DETECTION_TOL, +) -> WyckoffPosition | None: + """ + Detect the Wyckoff position a fractional coordinate occupies. + + Tests the coordinate for membership in every Wyckoff orbit of the + resolved space group and returns the matched position with its nearest + representative template. The winner is chosen by multiplicity + ascending, then residual ascending (the most special site first); a + rare same-multiplicity tie within ``tol`` is reported with a warning. + + Parameters + ---------- + name_hm : str + Hermann-Mauguin symbol of the space group. + coord_code : str | None + Coordinate-system code. + fract_xyz : tuple[float, float, float] + Fractional coordinate to classify. + tol : float, default _WYCKOFF_DETECTION_TOL + Maximum residual for orbit membership. + + Returns + ------- + WyckoffPosition | None + The matched position, or ``None`` when the space group is absent + from ``SPACE_GROUPS``. + """ + it_number = get_it_number_by_name_hm_short(name_hm) + if it_number is None: + return None + key = (it_number, _normalize_coord_code(coord_code)) + if key not in SPACE_GROUPS: + return None + + point = np.asarray(fract_xyz, dtype=float) % 1.0 + matches = [] + for letter, position in SPACE_GROUPS[key]['Wyckoff_positions'].items(): + template, residual = _nearest_orbit_template(point, position['coords_xyz']) + if residual <= tol: + matches.append( + (int(position['multiplicity']), residual, letter, position['site_symmetry'], template), + ) + + if not matches: + return None + matches.sort(key=lambda match: (match[0], match[1])) + multiplicity, _residual, letter, site_symmetry, template = matches[0] + ties = [match for match in matches[1:] if match[0] == multiplicity] + if ties: + others = ', '.join(repr(match[2]) for match in ties) + log.warning( + f"Wyckoff detection tie for {name_hm!r}: chose {letter!r} over {others} (same multiplicity)", + ) + return WyckoffPosition(letter, multiplicity, site_symmetry, template) + + +def wyckoff_position_info( + name_hm: str, + coord_code: str | None, + letter: str, + fract_xyz: tuple[float, float, float] | None = None, +) -> WyckoffPosition | None: + """ + Look up a known Wyckoff letter, optionally selecting a representative. + + Parameters + ---------- + name_hm : str + Hermann-Mauguin symbol of the space group. + coord_code : str | None + Coordinate-system code. + letter : str + Wyckoff letter to look up. + fract_xyz : tuple[float, float, float] | None, default None + When given, the nearest orbit representative for ``letter`` is + selected as ``coord_template``; otherwise ``coord_template`` is + ``None``. + + Returns + ------- + WyckoffPosition | None + The position record, or ``None`` when the group or letter is + absent. + """ + it_number = get_it_number_by_name_hm_short(name_hm) + if it_number is None: + return None + key = (it_number, _normalize_coord_code(coord_code)) + if key not in SPACE_GROUPS: + return None + positions = SPACE_GROUPS[key]['Wyckoff_positions'] + if letter not in positions: + return None + position = positions[letter] + template = None + if fract_xyz is not None: + point = np.asarray(fract_xyz, dtype=float) % 1.0 + template, _residual = _nearest_orbit_template(point, position['coords_xyz']) + return WyckoffPosition(letter, int(position['multiplicity']), position['site_symmetry'], template) + + def _site_stabilizer_rotations( ops: list[tuple[np.ndarray, np.ndarray]], site_coords: tuple[float, float, float], From abed076040e8a25645fb2e0d107c0ec5cc66c788 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 11:48:47 +0200 Subject: [PATCH 23/55] Record free-param-solving Wyckoff snap decision for P1.6 --- docs/dev/plans/wyckoff-letter-detection.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index 16a81e673..58213a958 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -325,8 +325,16 @@ The ADR commit + design-phase review/reply cleanup are handled by stored letter. For supported keys, refresh letter, multiplicity, and selected representative; for unsupported keys, preserve stored letters as unvalidated values, set multiplicity to `None`, skip - constraints, and warn. Use the selected `coord_template` for - snapping and constrained-axis flags. Warn when coordinate or + constraints, and warn. Snap by **solving the free parameters** — + least-squares project the coordinate onto the selected + `coord_template`'s manifold, then set every axis to that manifold + point — so centering copies and off-canonical-slot representatives + (e.g. 6e `(0,x,0)`) snap correctly; derive constrained-axis flags + from the same representative. This free-parameter-solving snap + **replaces the positional `_apply_fract_constraints` substitution** + (a deliberate deviation from ADR §5's "existing constraint step", + decided during P1.1; reflect it in ADR §5 at the P1.9 promotion). + Warn when coordinate or supported space-group edits move the letter, when a user letter-set snaps coordinates, and when a same-letter coordinate edit snaps coordinates. Honour `called_by_minimizer=True`; From 01ca0daf00e4db1f29a931b85dda41788380540a Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 12:01:18 +0200 Subject: [PATCH 24/55] Add derived space group Wyckoff category --- docs/dev/plans/wyckoff-letter-detection.md | 2 +- .../crystallography/crystallography.py | 27 +++ .../space_group_wyckoff/__init__.py | 9 + .../categories/space_group_wyckoff/default.py | 154 ++++++++++++++++++ .../categories/space_group_wyckoff/factory.py | 17 ++ 5 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/__init__.py create mode 100644 src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py create mode 100644 src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/factory.py diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index 58213a958..b75cbb9e1 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -276,7 +276,7 @@ The ADR commit + design-phase review/reply cleanup are handled by Export new public names via `crystallography/__init__.py` if public. Commit: `Add Wyckoff orbit detection to crystallography module` -- [ ] **P1.2 — Derived `space_group_wyckoff` category.** Add the +- [x] **P1.2 — Derived `space_group_wyckoff` category.** Add the `space_group_wyckoff` package with a `SpaceGroupWyckoff` item keyed by `id` (`_space_group_Wyckoff.id`) and read-only descriptors for `id`, `letter`, `multiplicity`, `site_symmetry`, diff --git a/src/easydiffraction/crystallography/crystallography.py b/src/easydiffraction/crystallography/crystallography.py index da340fea2..9ef9fe161 100644 --- a/src/easydiffraction/crystallography/crystallography.py +++ b/src/easydiffraction/crystallography/crystallography.py @@ -639,6 +639,33 @@ def wyckoff_position_info( return WyckoffPosition(letter, int(position['multiplicity']), position['site_symmetry'], template) +def space_group_wyckoff_table(name_hm: str, coord_code: str | None) -> dict[str, dict] | None: + """ + Return the Wyckoff-position table for a space group, or ``None``. + + Parameters + ---------- + name_hm : str + Hermann-Mauguin symbol of the space group. + coord_code : str | None + Coordinate-system code. + + Returns + ------- + dict[str, dict] | None + Mapping of Wyckoff letter to its ``multiplicity``, + ``site_symmetry``, and ``coords_xyz`` record, or ``None`` when the + space group is absent from ``SPACE_GROUPS``. + """ + it_number = get_it_number_by_name_hm_short(name_hm) + if it_number is None: + return None + key = (it_number, _normalize_coord_code(coord_code)) + if key not in SPACE_GROUPS: + return None + return SPACE_GROUPS[key]['Wyckoff_positions'] + + def _site_stabilizer_rotations( ops: list[tuple[np.ndarray, np.ndarray]], site_coords: tuple[float, float, float], diff --git a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/__init__.py b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/__init__.py new file mode 100644 index 000000000..3808d3075 --- /dev/null +++ b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/__init__.py @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause + +from easydiffraction.datablocks.structure.categories.space_group_wyckoff.default import ( + SpaceGroupWyckoff, +) +from easydiffraction.datablocks.structure.categories.space_group_wyckoff.default import ( + SpaceGroupWyckoffCollection, +) diff --git a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py new file mode 100644 index 000000000..e7949c803 --- /dev/null +++ b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py @@ -0,0 +1,154 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +""" +Derived space-group Wyckoff category. + +Defines :class:`SpaceGroupWyckoff` items and the read-only +:class:`SpaceGroupWyckoffCollection`. Rows are derived from the bundled +space-group table for the structure's current space group; they are not +user-edited. ``Structure`` rebuilds the collection when the space group +changes via :meth:`SpaceGroupWyckoffCollection._replace_from_space_group`. +""" + +from __future__ import annotations + +from easydiffraction.core.category import CategoryCollection +from easydiffraction.core.category import CategoryItem +from easydiffraction.core.display_handler import DisplayHandler +from easydiffraction.core.metadata import TypeInfo +from easydiffraction.core.validation import AttributeSpec +from easydiffraction.core.variable import IntegerDescriptor +from easydiffraction.core.variable import StringDescriptor +from easydiffraction.crystallography import crystallography as ecr +from easydiffraction.datablocks.structure.categories.space_group_wyckoff.factory import ( + SpaceGroupWyckoffFactory, +) +from easydiffraction.io.cif.handler import CifHandler + +_READ_ONLY_MESSAGE = ( + 'space_group_wyckoff is derived from the space group and is read-only; ' + 'it is rebuilt automatically when the space group changes.' +) + + +class SpaceGroupWyckoff(CategoryItem): + """A single Wyckoff position of the space group (all fields read-only).""" + + _category_code = 'space_group_Wyckoff' + _category_entry_name = 'id' + + def __init__(self) -> None: + """Initialise an empty Wyckoff-position row.""" + super().__init__() + + self._id = StringDescriptor( + name='id', + description='Identifier of the Wyckoff position.', + display_handler=DisplayHandler(display_name='ID', latex_name='ID'), + value_spec=AttributeSpec(default=''), + cif_handler=CifHandler(names=['_space_group_Wyckoff.id']), + ) + self._letter = StringDescriptor( + name='letter', + description='Wyckoff letter of the position.', + display_handler=DisplayHandler(display_name='Letter', latex_name='Letter'), + value_spec=AttributeSpec(default=''), + cif_handler=CifHandler(names=['_space_group_Wyckoff.letter']), + ) + self._multiplicity = IntegerDescriptor( + name='multiplicity', + description='Multiplicity of the Wyckoff position.', + display_handler=DisplayHandler(display_name='Multiplicity', latex_name='Multiplicity'), + value_spec=AttributeSpec(default=0), + cif_handler=CifHandler(names=['_space_group_Wyckoff.multiplicity']), + ) + self._site_symmetry = StringDescriptor( + name='site_symmetry', + description='Site-symmetry symbol of the Wyckoff position.', + display_handler=DisplayHandler(display_name='Site symmetry', latex_name='Site symmetry'), + value_spec=AttributeSpec(default=''), + cif_handler=CifHandler(names=['_space_group_Wyckoff.site_symmetry']), + ) + self._coords_xyz = StringDescriptor( + name='coords_xyz', + description='Coordinates of the Wyckoff orbit.', + display_handler=DisplayHandler(display_name='Coordinates', latex_name='Coordinates'), + value_spec=AttributeSpec(default=''), + cif_handler=CifHandler(names=['_space_group_Wyckoff.coords_xyz']), + ) + + @property + def id(self) -> StringDescriptor: + """Read-only Wyckoff-position identifier.""" + return self._id + + @property + def letter(self) -> StringDescriptor: + """Read-only Wyckoff letter.""" + return self._letter + + @property + def multiplicity(self) -> IntegerDescriptor: + """Read-only multiplicity.""" + return self._multiplicity + + @property + def site_symmetry(self) -> StringDescriptor: + """Read-only site-symmetry symbol.""" + return self._site_symmetry + + @property + def coords_xyz(self) -> StringDescriptor: + """Read-only orbit coordinates.""" + return self._coords_xyz + + +@SpaceGroupWyckoffFactory.register +class SpaceGroupWyckoffCollection(CategoryCollection): + """Read-only collection of Wyckoff positions, derived from the space group.""" + + type_info = TypeInfo( + tag='default', + description='Derived space-group Wyckoff table', + ) + + def __init__(self) -> None: + """Initialise an empty derived Wyckoff collection.""" + super().__init__(item_type=SpaceGroupWyckoff) + + def add(self, item: object) -> None: + """Reject public mutation; the collection is derived (read-only).""" + raise TypeError(_READ_ONLY_MESSAGE) + + def create(self, **kwargs: object) -> None: + """Reject public mutation; the collection is derived (read-only).""" + raise TypeError(_READ_ONLY_MESSAGE) + + def remove(self, name: str) -> None: + """Reject public mutation; the collection is derived (read-only).""" + raise TypeError(_READ_ONLY_MESSAGE) + + def _replace_from_space_group(self) -> None: + """ + Rebuild the rows from the parent structure's current space group. + + Clears all rows, then repopulates from the bundled Wyckoff table. + Leaves the collection empty for an absent/untabulated space group. + """ + self._items.clear() + structure = getattr(self, '_parent', None) + if structure is None: + return + name_hm = structure.space_group.name_h_m.value + coord_code = structure.space_group.it_coordinate_system_code.value + positions = ecr.space_group_wyckoff_table(name_hm, coord_code) + if not positions: + return + for letter, position in positions.items(): + row = self._item_type() + row._id.value = letter + row._letter.value = letter + row._multiplicity.value = int(position['multiplicity']) + row._site_symmetry.value = str(position['site_symmetry']) + row._coords_xyz.value = ' '.join(position['coords_xyz']) + self._items.append(row) diff --git a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/factory.py b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/factory.py new file mode 100644 index 000000000..7ad4eec0b --- /dev/null +++ b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/factory.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Space-group Wyckoff factory — delegates entirely to ``FactoryBase``.""" + +from __future__ import annotations + +from typing import ClassVar + +from easydiffraction.core.factory import FactoryBase + + +class SpaceGroupWyckoffFactory(FactoryBase): + """Create space-group Wyckoff collections by tag.""" + + _default_rules: ClassVar[dict] = { + frozenset(): 'default', + } From 31d1278ccff713f42a90b24707c8443cf79bc713 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 12:05:53 +0200 Subject: [PATCH 25/55] Wire derived Wyckoff table into Structure --- docs/dev/plans/wyckoff-letter-detection.md | 2 +- .../datablocks/structure/item/base.py | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index b75cbb9e1..eba068a24 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -284,7 +284,7 @@ The ADR commit + design-phase review/reply cleanup are handled by mutation methods raising and a private `_replace_from_space_group` rebuild method that creates/adopts rows from `SPACE_GROUPS[key]`. Commit: `Add derived space group Wyckoff category` -- [ ] **P1.3 — Wire `space_group_wyckoff` into `Structure`.** Add it as +- [x] **P1.3 — Wire `space_group_wyckoff` into `Structure`.** Add it as a read-only sibling category on `Structure`, rebuild it when structure categories update so it tracks the current space group, keep it empty for absent groups, and exclude it from project CIF diff --git a/src/easydiffraction/datablocks/structure/item/base.py b/src/easydiffraction/datablocks/structure/item/base.py index 8d8d27928..84c74cb5f 100644 --- a/src/easydiffraction/datablocks/structure/item/base.py +++ b/src/easydiffraction/datablocks/structure/item/base.py @@ -19,6 +19,12 @@ from easydiffraction.datablocks.structure.categories.geom.factory import GeomFactory from easydiffraction.datablocks.structure.categories.space_group import SpaceGroup from easydiffraction.datablocks.structure.categories.space_group.factory import SpaceGroupFactory +from easydiffraction.datablocks.structure.categories.space_group_wyckoff import ( + SpaceGroupWyckoffCollection, +) +from easydiffraction.datablocks.structure.categories.space_group_wyckoff.factory import ( + SpaceGroupWyckoffFactory, +) from easydiffraction.utils.logging import console from easydiffraction.utils.utils import render_cif @@ -43,6 +49,8 @@ def __init__( self._atom_site_aniso = AtomSiteAnisoFactory.create(self._atom_site_aniso_type) self._geom_type: str = GeomFactory.default_tag() self._geom = GeomFactory.create(self._geom_type) + self._space_group_wyckoff_type: str = SpaceGroupWyckoffFactory.default_tag() + self._space_group_wyckoff = SpaceGroupWyckoffFactory.create(self._space_group_wyckoff_type) self._identity.datablock_entry_name = lambda: self.name # ------------------------------------------------------------------ @@ -180,6 +188,11 @@ def geom(self, new: Geom) -> None: """ self._geom = new + @property + def space_group_wyckoff(self) -> SpaceGroupWyckoffCollection: + """Read-only Wyckoff table derived from the current space group.""" + return self._space_group_wyckoff + # ------------------------------------------------------------------ # Private methods # ------------------------------------------------------------------ @@ -230,6 +243,7 @@ def _update_categories( if not called_by_minimizer and not self._need_categories_update: return + self._space_group_wyckoff._replace_from_space_group() self._sync_atom_site_aniso() for category in self.categories: @@ -237,6 +251,14 @@ def _update_categories( self._need_categories_update = False + def _serializable_categories(self) -> list: + """Project-CIF categories (excludes the derived Wyckoff table).""" + return [ + category + for category in self.categories + if not isinstance(category, SpaceGroupWyckoffCollection) + ] + # ------------------------------------------------------------------ # Public methods # ------------------------------------------------------------------ From 1bb7aea348cb8d5f5d74d7a2d76dd87ea671ac18 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 12:09:50 +0200 Subject: [PATCH 26/55] Add read-only multiplicity to AtomSite --- docs/dev/plans/wyckoff-letter-detection.md | 2 +- .../categories/atom_sites/default.py | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index eba068a24..6117dddb9 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -294,7 +294,7 @@ The ADR commit + design-phase review/reply cleanup are handled by reads `SPACE_GROUPS` through the crystallography helpers rather than depending on this collection. Commit: `Wire derived Wyckoff table into Structure` -- [ ] **P1.4 — Read-only multiplicity + detection mutator on +- [x] **P1.4 — Read-only multiplicity + detection mutator on `AtomSite`.** Add only `multiplicity` as a read-only derived descriptor on `AtomSite` with `CifHandler` for `_atom_site.site_symmetry_multiplicity`, empty form `None`, and no diff --git a/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py b/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py index 6f7169c9f..8dea87942 100644 --- a/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py +++ b/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py @@ -22,6 +22,7 @@ from easydiffraction.core.validation import RangeValidator from easydiffraction.core.validation import RegexValidator from easydiffraction.core.variable import EnumDescriptor +from easydiffraction.core.variable import IntegerDescriptor from easydiffraction.core.variable import Parameter from easydiffraction.core.variable import StringDescriptor from easydiffraction.crystallography import crystallography as ecr @@ -133,6 +134,17 @@ def __init__(self) -> None: ] ), ) + self._multiplicity = IntegerDescriptor( + name='multiplicity', + description='Site multiplicity derived from the Wyckoff ' + 'position; None for an untabulated space group.', + display_handler=DisplayHandler( + display_name='Mult.', + latex_name='Mult.', + ), + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=['_atom_site.site_symmetry_multiplicity']), + ) self._occupancy = Parameter( name='occupancy', description='Occupancy of the atom site, representing the ' @@ -446,6 +458,26 @@ def wyckoff_letter(self) -> StringDescriptor: def wyckoff_letter(self, value: str) -> None: self._wyckoff_letter.value = value + @property + def multiplicity(self) -> IntegerDescriptor: + """ + Read-only site multiplicity derived from the Wyckoff position. + + Populated by Wyckoff detection; ``value`` is ``None`` when the + space group is untabulated. There is no public setter. + """ + return self._multiplicity + + def _set_wyckoff_letter_detected(self, letter: str) -> None: + """ + Set the auto-detected Wyckoff letter, bypassing membership validation. + + Modelled on ``_set_value_from_minimizer``: detection supplies a + trusted letter, written directly rather than re-validated against + the (dynamic) allowed-letters set. + """ + self._wyckoff_letter._set_value_from_minimizer(letter) + @property def fract_x(self) -> Parameter: """ From 0f1db8e49c0152ef0ac0c370ceb4357a2792d629 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 12:18:22 +0200 Subject: [PATCH 27/55] Derive allowed Wyckoff letters from the space group --- docs/dev/plans/wyckoff-letter-detection.md | 2 +- src/easydiffraction/core/validation.py | 28 +++++++++ .../categories/atom_sites/default.py | 59 +++++++++++++++---- 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index 6117dddb9..9a8cde392 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -301,7 +301,7 @@ The ADR commit + design-phase review/reply cleanup are handled by public setter. Add `_set_wyckoff_letter_detected()` modelled on `_set_value_from_minimizer`. Do not add `site_symmetry` to `AtomSite`. Commit: `Add read-only multiplicity to AtomSite` -- [ ] **P1.5 — Dynamic allowed letters + unsupported-group validation.** +- [x] **P1.5 — Dynamic allowed letters + unsupported-group validation.** Make `_wyckoff_letter_allowed_values` return `['', *list(SPACE_GROUPS[key]['Wyckoff_positions'])]` for a supported group and `[]` for an absent one. Add the diff --git a/src/easydiffraction/core/validation.py b/src/easydiffraction/core/validation.py index 546719fe9..d2a0408fb 100644 --- a/src/easydiffraction/core/validation.py +++ b/src/easydiffraction/core/validation.py @@ -252,6 +252,34 @@ def validated( # ====================================================================== +class PermissiveMembershipValidator(MembershipValidator): + """ + Membership validator that accepts any value when no choices are allowed. + + Used where the allowed set is derived dynamically and may legitimately + be empty (for example a Wyckoff letter under an untabulated space + group, or before a parent context is available): an empty allowed set + stores the value verbatim instead of rejecting it. A non-empty allowed + set validates membership as usual. + """ + + def validated( + self, + value: object, + name: str, + default: object = None, + current: object = None, + ) -> object: + """Accept any value when allowed is empty; otherwise check membership.""" + allowed_values = self.allowed() if callable(self.allowed) else self.allowed + if not allowed_values: + return value + return super().validated(value, name, default=default, current=current) + + +# ====================================================================== + + class RegexValidator(ValidatorBase): """Ensure that a string matches a given regular expression.""" diff --git a/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py b/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py index 8dea87942..eee3d6b49 100644 --- a/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py +++ b/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py @@ -19,6 +19,7 @@ from easydiffraction.core.metadata import TypeInfo from easydiffraction.core.validation import AttributeSpec from easydiffraction.core.validation import MembershipValidator +from easydiffraction.core.validation import PermissiveMembershipValidator from easydiffraction.core.validation import RangeValidator from easydiffraction.core.validation import RegexValidator from easydiffraction.core.variable import EnumDescriptor @@ -45,6 +46,10 @@ class AtomSite(CategoryItem): def __init__(self) -> None: """Initialise the atom site with default descriptor values.""" super().__init__() + # Set when a Wyckoff letter is assigned without a parent context + # (e.g. create() before the atom is added); the update flow then + # validates it once the parent structure is available. + self._wyckoff_letter_needs_validation = False self._label = StringDescriptor( name='label', @@ -124,7 +129,9 @@ def __init__(self) -> None: ), value_spec=AttributeSpec( default=self._wyckoff_letter_default_value, - validator=MembershipValidator(allowed=self._wyckoff_letter_allowed_values), + validator=PermissiveMembershipValidator( + allowed=lambda: self._wyckoff_letter_allowed_values, + ), ), cif_handler=CifHandler( names=[ @@ -208,21 +215,39 @@ def _type_symbol_allowed_values(self) -> list[str]: """ return list({key[1] for key in DATABASE['Isotopes']}) + def _resolve_structure_space_group(self) -> object | None: + """ + Return the parent structure's space-group category, or ``None``. + + Walks ``AtomSite`` → atom-sites collection → structure; returns + ``None`` when any link is missing (no parent context yet). + """ + collection = getattr(self, '_parent', None) + structure = getattr(collection, '_parent', None) if collection is not None else None + return getattr(structure, 'space_group', None) if structure is not None else None + @property def _wyckoff_letter_allowed_values(self) -> list[str]: """ - Return allowed Wyckoff-letter symbols. + Allowed Wyckoff letters for the current space group. Returns ------- list[str] - Currently a hard-coded placeholder list. - """ - # TODO: Need to now current space group. How to access it? Via - # parent Cell? Then letters = - # list(SPACE_GROUPS[62, 'cab']['Wyckoff_positions'].keys()) - # Temporarily return hardcoded list: - return ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'] + ``['', *letters]`` for a tabulated space group (empty first, so + an unset letter is valid); ``[]`` when there is no parent + context or the space group is untabulated. + """ + space_group = self._resolve_structure_space_group() + if space_group is None: + return [] + positions = ecr.space_group_wyckoff_table( + space_group.name_h_m.value, + space_group.it_coordinate_system_code.value, + ) + if positions is None: + return [] + return ['', *positions] @property def _wyckoff_letter_default_value(self) -> str: @@ -232,10 +257,11 @@ def _wyckoff_letter_default_value(self) -> str: Returns ------- str - First element of the allowed values list. + The first allowed value (empty string), or ``''`` when no + letters are allowed. """ - # TODO: What to pass as default? - return self._wyckoff_letter_allowed_values[0] + allowed = self._wyckoff_letter_allowed_values + return allowed[0] if allowed else '' def _convert_adp_values(self, old_type: str, new_type: str) -> None: """ @@ -456,7 +482,14 @@ def wyckoff_letter(self) -> StringDescriptor: @wyckoff_letter.setter def wyckoff_letter(self, value: str) -> None: - self._wyckoff_letter.value = value + if self._resolve_structure_space_group() is None: + # No parent context yet (e.g. create() before the atom is + # added): store the raw value and defer validation to the + # update flow, which resolves it once context is available. + self._wyckoff_letter_needs_validation = True + self._wyckoff_letter._set_value_from_minimizer(value) + else: + self._wyckoff_letter.value = value @property def multiplicity(self) -> IntegerDescriptor: From 138c44d6df3f78eb2c054d377db27fb98e307b82 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 12:46:46 +0200 Subject: [PATCH 28/55] Add Wyckoff coordinate snap helper to crystallography module --- docs/dev/plans/wyckoff-letter-detection.md | 26 ++++++ .../crystallography/crystallography.py | 84 +++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index 9a8cde392..6c361cec2 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -342,6 +342,32 @@ The ADR commit + design-phase review/reply cleanup are handled by Site-symmetry display data comes from `structure.space_group_wyckoff`, not from `AtomSite`. Commit: `Detect and track Wyckoff letters in the update flow` + + _P1.6 implementation decisions (in progress):_ + + - **Snap = slot-aware free-parameter-solving** + (`crystallography.snap_to_wyckoff_template`, already committed): solve + the free params from the **free (refinable) axes**, keep those axes, + and derive the constrained axes. **Not** manifold projection — that + averaged/moved the free axis and fought the minimizer. Handles + off-canonical reps like 6e `(0,x,0)` (keep `fract_y`, set + `fract_x=fract_z=0`); matches the old substitution for canonical + sites, so the fit is unaffected. Per-axis constraint flags are + slot-based (first-occurrence), not symbol-based. + - **Warning gating (per the chosen option):** pass + `called_by_minimizer=True` **only at the per-iteration minimizer + objective** — `analysis/fit_helpers/metrics.py:181` (residual calc; + verify `analysis/fitting.py:382` too) — and **leave** the fit-setup + (`fitting.py:209`) and flush (`analysis.py:174`) sites `False` so + detection still runs there. Gate re-detection **and** the + "adjusted"/"moved-letter" warnings on `not called_by_minimizer`, so + they never fire per fit step. + - **Remaining:** rewrite `_apply_atomic_coordinates_symmetry_constraints` + (per atom: resolve the `_wyckoff_letter_needs_validation` marker → + decide detect/trigger → snap → set `multiplicity` + constrained flags + → refresh baselines), thread `called_by_minimizer` through + `AtomSites._update`, change the objective call site(s), then **verify + by running `test_fit_neutron_pd_cwl_hs`** and smoke tests. - [ ] **P1.7 — Calculator consumes model multiplicity.** Replace the `SPACE_GROUPS` lookup in `cryspy._update_atom_multiplicity` with `atom_site.multiplicity.value`; when it is `None`, leave the diff --git a/src/easydiffraction/crystallography/crystallography.py b/src/easydiffraction/crystallography/crystallography.py index 9ef9fe161..94fd992e8 100644 --- a/src/easydiffraction/crystallography/crystallography.py +++ b/src/easydiffraction/crystallography/crystallography.py @@ -533,6 +533,90 @@ def _nearest_orbit_template(point: np.ndarray, coords_xyz: list[str]) -> tuple[s return best_template, best_residual +def _wyckoff_template_constrained_flags(rot: np.ndarray) -> dict[str, bool]: + """ + Return per-axis symmetry-constraint flags for a parsed template. + + An axis is **free** when its coordinate is the first (in x, y, z order) + to introduce a free parameter, and **constrained** otherwise (a + constant, or a coordinate slaved to an earlier axis's parameter). This + is slot-based, so it is correct for off-canonical representatives such + as ``(0,x,0)`` (``fract_x`` constrained, ``fract_y`` free) where the + symbol-presence test would be wrong. + + Parameters + ---------- + rot : np.ndarray + (3, 3) rotation part from :func:`_parse_rotation_matrix`. + + Returns + ------- + dict[str, bool] + Mapping ``'fract_x'/'fract_y'/'fract_z'`` to ``True`` if the axis + is fully fixed by site symmetry. + """ + claimed: set[int] = set() + flags: dict[str, bool] = {} + for axis, name in enumerate(('fract_x', 'fract_y', 'fract_z')): + used = {col for col in range(3) if rot[axis, col] != 0} + if used - claimed: + flags[name] = False + claimed |= used + else: + flags[name] = True + return flags + + +def snap_to_wyckoff_template( + coord_template: str, + fract_xyz: tuple[float, float, float], +) -> tuple[tuple[float, float, float], dict[str, bool]]: + """ + Project a coordinate onto a Wyckoff orbit-representative manifold. + + Solves the free Wyckoff parameters from the **free (refinable) axes** + only — keeping those axes' values, so a minimizer's refined free + coordinate is preserved — then derives the constrained axes from the + template. Replaces per-axis symbol substitution: it handles coupled + axes (e.g. ``(x,-x,z)``: keep ``fract_x``, set ``fract_y=-fract_x``) + and off-canonical representatives (e.g. ``(0,x,0)``: keep ``fract_y``, + set ``fract_x=fract_z=0``). + + Parameters + ---------- + coord_template : str + Selected orbit representative, e.g. ``'(x,-x,z)'`` or ``'(0,x,0)'``. + fract_xyz : tuple[float, float, float] + Current fractional coordinate. + + Returns + ------- + tuple[tuple[float, float, float], dict[str, bool]] + The snapped ``(x, y, z)`` (free axes kept, constrained axes derived; + not reduced mod 1), and the per-axis constraint flags. + """ + rot, trans = _parse_rotation_matrix(coord_template) + rot_float = rot.astype(float) + point = np.asarray(fract_xyz, dtype=float) + axes = ('fract_x', 'fract_y', 'fract_z') + flags = _wyckoff_template_constrained_flags(rot) + free_rows = [axis for axis, name in enumerate(axes) if not flags[name]] + if free_rows: + solution, *_ = np.linalg.lstsq( + rot_float[free_rows, :], + point[free_rows] - trans[free_rows], + rcond=None, + ) + else: + solution = np.zeros(3) + derived = rot_float @ solution + trans + snapped = tuple( + float(point[axis]) if not flags[name] else float(derived[axis]) + for axis, name in enumerate(axes) + ) + return snapped, flags + + def detect_wyckoff_position( name_hm: str, coord_code: str | None, From 838d7890312a40729fc7333716b2ad3bf97fefa1 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 12:59:38 +0200 Subject: [PATCH 29/55] Detect and track Wyckoff letters in the update flow --- docs/dev/plans/wyckoff-letter-detection.md | 4 +- src/easydiffraction/analysis/fitting.py | 7 +- .../categories/atom_sites/default.py | 164 +++++++++++++----- 3 files changed, 132 insertions(+), 43 deletions(-) diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index 6c361cec2..d4d01a608 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -314,7 +314,7 @@ The ADR commit + design-phase review/reply cleanup are handled by "needs context validation" marker instead of treating missing context as an unsupported group. Commit: `Derive allowed Wyckoff letters from the space group` -- [ ] **P1.6 — Detection triggers in the atom-site update flow.** In +- [x] **P1.6 — Detection triggers in the atom-site update flow.** In `_update(*, called_by_minimizer=False)`, implement fill-if-empty, re-detect-on-coordinate-change, and re-detect-on-space-group-key change with per-atom coordinate and `(name_hm, coord_code)` @@ -343,7 +343,7 @@ The ADR commit + design-phase review/reply cleanup are handled by `structure.space_group_wyckoff`, not from `AtomSite`. Commit: `Detect and track Wyckoff letters in the update flow` - _P1.6 implementation decisions (in progress):_ + _P1.6 implementation decisions (implemented):_ - **Snap = slot-aware free-parameter-solving** (`crystallography.snap_to_wyckoff_template`, already committed): solve diff --git a/src/easydiffraction/analysis/fitting.py b/src/easydiffraction/analysis/fitting.py index 7dd8c731d..a861ea25a 100644 --- a/src/easydiffraction/analysis/fitting.py +++ b/src/easydiffraction/analysis/fitting.py @@ -377,9 +377,12 @@ def _residual_function( # Update categories to reflect new parameter values # Order matters: structures first (symmetry, structure), - # then analysis (constraints), then experiments (calculations) + # then analysis (constraints), then experiments (calculations). + # Pass called_by_minimizer so the per-iteration Wyckoff snap runs + # silently (no re-detection or warnings); detection already ran at + # fit setup. for structure in structures: - structure._update_categories() + structure._update_categories(called_by_minimizer=True) if analysis is not None: analysis._update_categories(called_by_minimizer=True) diff --git a/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py b/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py index eee3d6b49..17d954b73 100644 --- a/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py +++ b/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py @@ -30,6 +30,7 @@ from easydiffraction.datablocks.structure.categories.atom_sites.enums import AdpTypeEnum from easydiffraction.datablocks.structure.categories.atom_sites.factory import AtomSitesFactory from easydiffraction.io.cif.handler import CifHandler +from easydiffraction.utils.logging import log class AtomSite(CategoryItem): @@ -50,6 +51,10 @@ def __init__(self) -> None: # (e.g. create() before the atom is added); the update flow then # validates it once the parent structure is available. self._wyckoff_letter_needs_validation = False + # Wyckoff-detection baselines (None until first detection); compared + # in the update flow to decide whether to re-detect. + self._wyckoff_coord_baseline: tuple[float, float, float] | None = None + self._wyckoff_key_baseline: tuple[str, str | None] | None = None self._label = StringDescriptor( name='label', @@ -617,47 +622,129 @@ def __init__(self) -> None: # Private helper methods # ------------------------------------------------------------------ - def _apply_atomic_coordinates_symmetry_constraints(self) -> None: + def _apply_atomic_coordinates_symmetry_constraints(self, *, called_by_minimizer: bool = False) -> None: """ - Apply symmetry rules to fractional coordinates of every site. + Detect Wyckoff letters and snap fractional coordinates to symmetry. - Uses the parent structure's space-group symbol, IT coordinate - system code and each atom's Wyckoff letter. Atoms without a - Wyckoff letter are silently skipped. Coordinates fully - determined by site symmetry are flagged as - ``symmetry_constrained`` so they cannot be marked refinable. + For each atom: resolve any pending no-context Wyckoff letter; + (re)detect the letter when it is empty or the coordinates / + space-group key changed (skipped under a minimizer); snap + coordinates to the selected orbit representative; and record the + multiplicity and constrained-axis flags. Atoms in an untabulated + space group keep their stored letter unvalidated, with no + multiplicity or constraints. + + Parameters + ---------- + called_by_minimizer : bool, default=False + When True (per fit iteration), skip re-detection and warnings; + only the silent coordinate snap runs. """ structure = self._parent - space_group_name = structure.space_group.name_h_m.value - space_group_coord_code = structure.space_group.it_coordinate_system_code.value + name_hm = structure.space_group.name_h_m.value + coord_code = structure.space_group.it_coordinate_system_code.value + supported = ecr.space_group_wyckoff_table(name_hm, coord_code) is not None for atom in self._items: - wl = atom.wyckoff_letter.value - if not wl: - # TODO: Decide how to handle this case - self._clear_fract_symmetry_constrained(atom) - continue - dummy_atom = { - 'fract_x': atom.fract_x.value, - 'fract_y': atom.fract_y.value, - 'fract_z': atom.fract_z.value, - } - ecr.apply_atom_site_symmetry_constraints( - atom_site=dummy_atom, - name_hm=space_group_name, - coord_code=space_group_coord_code, - wyckoff_letter=wl, + if atom._wyckoff_letter_needs_validation: + self._resolve_pending_wyckoff_letter(atom, name_hm) + if supported: + self._detect_and_snap_atom(atom, name_hm, coord_code, called_by_minimizer=called_by_minimizer) + else: + self._mark_atom_untabulated(atom, (name_hm, coord_code), called_by_minimizer=called_by_minimizer) + + @staticmethod + def _resolve_pending_wyckoff_letter(atom: AtomSite, name_hm: str) -> None: + """Validate a deferred no-context Wyckoff letter; raise if invalid.""" + stored = atom.wyckoff_letter.value + allowed = atom._wyckoff_letter_allowed_values + if allowed and stored not in allowed: + msg = ( + f'Invalid Wyckoff letter {stored!r} for space group ' + f'{name_hm!r}; allowed letters: {allowed}' ) - constrained_flags = ecr.atom_site_symmetry_constrained_flags( - name_hm=space_group_name, - coord_code=space_group_coord_code, - wyckoff_letter=wl, + raise ValueError(msg) + atom._wyckoff_letter_needs_validation = False + + def _mark_atom_untabulated( + self, + atom: AtomSite, + key: tuple[str, str | None], + *, + called_by_minimizer: bool, + ) -> None: + """Handle an atom whose space group is absent from the table.""" + atom._multiplicity.value = None + self._clear_fract_symmetry_constrained(atom) + if atom.wyckoff_letter.value and not called_by_minimizer: + log.warning( + f'Wyckoff letter of {atom.label.value} is stored but not ' + f'validated because the space group is untabulated' ) - atom.fract_x.value = dummy_atom['fract_x'] - atom.fract_y.value = dummy_atom['fract_y'] - atom.fract_z.value = dummy_atom['fract_z'] - atom._fract_x._set_symmetry_constrained(value=constrained_flags['fract_x']) - atom._fract_y._set_symmetry_constrained(value=constrained_flags['fract_y']) - atom._fract_z._set_symmetry_constrained(value=constrained_flags['fract_z']) + atom._wyckoff_coord_baseline = (atom.fract_x.value, atom.fract_y.value, atom.fract_z.value) + atom._wyckoff_key_baseline = key + + def _detect_and_snap_atom( + self, + atom: AtomSite, + name_hm: str, + coord_code: str | None, + *, + called_by_minimizer: bool, + ) -> None: + """Detect (if triggered) and snap one atom to its Wyckoff position.""" + key = (name_hm, coord_code) + letter_before = atom.wyckoff_letter.value + coords = (atom.fract_x.value, atom.fract_y.value, atom.fract_z.value) + coords_changed = atom._wyckoff_coord_baseline is None or any( + abs(a - b) > ecr._WYCKOFF_DETECTION_TOL + for a, b in zip(coords, atom._wyckoff_coord_baseline) + ) + detect = (not called_by_minimizer) and ( + not letter_before or coords_changed or atom._wyckoff_key_baseline != key + ) + if detect: + position = ecr.detect_wyckoff_position(name_hm, coord_code, coords) + if position is not None and letter_before and position.letter != letter_before: + log.warning( + f'change moved the Wyckoff letter of {atom.label.value} ' + f'from {letter_before} to {position.letter}' + ) + if position is not None: + atom._set_wyckoff_letter_detected(position.letter) + elif letter_before: + position = ecr.wyckoff_position_info(name_hm, coord_code, letter_before, fract_xyz=coords) + else: + position = None + + if position is None or position.coord_template is None: + atom._multiplicity.value = None + self._clear_fract_symmetry_constrained(atom) + atom._wyckoff_coord_baseline = coords + atom._wyckoff_key_baseline = key + return + + atom._multiplicity.value = position.multiplicity + snapped, flags = ecr.snap_to_wyckoff_template(position.coord_template, coords) + atom.fract_x.value = snapped[0] + atom.fract_y.value = snapped[1] + atom.fract_z.value = snapped[2] + atom._fract_x._set_symmetry_constrained(value=flags['fract_x']) + atom._fract_y._set_symmetry_constrained(value=flags['fract_y']) + atom._fract_z._set_symmetry_constrained(value=flags['fract_z']) + moved = any(abs(s - c) > ecr._WYCKOFF_DETECTION_TOL for s, c in zip(snapped, coords)) + if moved and not called_by_minimizer: + if not detect: + log.warning( + f'coordinates of {atom.label.value} did not fit letter ' + f'{position.letter} and were adjusted' + ) + elif letter_before and position.letter == letter_before: + log.warning( + f'coordinates of {atom.label.value} were adjusted to satisfy ' + f'Wyckoff letter {position.letter}' + ) + atom._wyckoff_coord_baseline = snapped + atom._wyckoff_key_baseline = key @staticmethod def _clear_fract_symmetry_constrained(atom: AtomSite) -> None: @@ -747,11 +834,10 @@ def _update( Parameters ---------- called_by_minimizer : bool, default=False - Whether the update was triggered by the fitting minimizer. - Currently unused. + Whether the update was triggered by the fitting minimizer. When + True, Wyckoff re-detection and warnings are skipped; only the + silent coordinate snap runs. """ - del called_by_minimizer - - self._apply_atomic_coordinates_symmetry_constraints() + self._apply_atomic_coordinates_symmetry_constraints(called_by_minimizer=called_by_minimizer) self._apply_adp_symmetry_constraints() self._sync_iso_from_aniso() From 582e12d972958311d4a02ff627afa65f7a3551e7 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 13:04:08 +0200 Subject: [PATCH 30/55] Read multiplicity from the model in the cryspy calculator --- docs/dev/plans/wyckoff-letter-detection.md | 2 +- .../analysis/calculators/cryspy.py | 27 ++++++------------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index d4d01a608..c540ad1f2 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -368,7 +368,7 @@ The ADR commit + design-phase review/reply cleanup are handled by → refresh baselines), thread `called_by_minimizer` through `AtomSites._update`, change the objective call site(s), then **verify by running `test_fit_neutron_pd_cwl_hs`** and smoke tests. -- [ ] **P1.7 — Calculator consumes model multiplicity.** Replace the +- [x] **P1.7 — Calculator consumes model multiplicity.** Replace the `SPACE_GROUPS` lookup in `cryspy._update_atom_multiplicity` with `atom_site.multiplicity.value`; when it is `None`, leave the backend's inferred multiplicity in place. Commit: diff --git a/src/easydiffraction/analysis/calculators/cryspy.py b/src/easydiffraction/analysis/calculators/cryspy.py index c39db75d5..16fcd818b 100644 --- a/src/easydiffraction/analysis/calculators/cryspy.py +++ b/src/easydiffraction/analysis/calculators/cryspy.py @@ -489,36 +489,25 @@ def _update_atom_multiplicity( structure: Structure, ) -> None: """ - Update cryspy atom multiplicities. + Update cryspy atom multiplicities from the model. CrysPy normalizes fractional coordinates into the ``[0, 1)`` interval while parsing CIF. For sites such as ``(x, -x, z)``, that can turn ``-x`` into ``1 - x`` before the Wyckoff multiplicity is inferred, making special positions look like - general positions. EasyDiffraction already stores the intended - Wyckoff letter, so keep the calculator dictionary aligned with - that model state. + general positions. EasyDiffraction's Wyckoff detection already + stores the correct per-site multiplicity, so use it; when a site + has no detected multiplicity (untabulated space group), keep the + backend's inferred value. """ if cryspy is None: return - from cryspy.A_functions_base.function_2_space_group import ( # noqa: PLC0415 - get_it_number_by_name_hm_short, - ) - - from easydiffraction.crystallography.space_groups import SPACE_GROUPS # noqa: PLC0415 - - it_number = get_it_number_by_name_hm_short(structure.space_group.name_h_m.value) - coord_code = structure.space_group.it_coordinate_system_code.value - if it_number is None or (it_number, coord_code) not in SPACE_GROUPS: - return - - positions = SPACE_GROUPS[it_number, coord_code]['Wyckoff_positions'] multiplicity = cryspy_model_dict['atom_multiplicity'] for idx, atom_site in enumerate(structure.atom_sites): - wyckoff_letter = atom_site.wyckoff_letter.value - if wyckoff_letter in positions: - multiplicity[idx] = positions[wyckoff_letter]['multiplicity'] + site_multiplicity = atom_site.multiplicity.value + if site_multiplicity is not None: + multiplicity[idx] = site_multiplicity @staticmethod def _update_aniso_beta( From 2819bb693c361bdc316d510e45f418553b560793 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 13:38:37 +0200 Subject: [PATCH 31/55] Serialize Wyckoff multiplicity and report Wyckoff table --- docs/dev/plans/wyckoff-letter-detection.md | 30 +++++++++++- .../categories/space_group_wyckoff/default.py | 12 +++++ src/easydiffraction/io/cif/iucr_writer.py | 47 +++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index c540ad1f2..4d912ab68 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -373,7 +373,7 @@ The ADR commit + design-phase review/reply cleanup are handled by `atom_site.multiplicity.value`; when it is `None`, leave the backend's inferred multiplicity in place. Commit: `Read multiplicity from the model in the cryspy calculator` -- [ ] **P1.8 — CIF and report output.** Ensure project CIF writes +- [x] **P1.8 — CIF and report output.** Ensure project CIF writes `_atom_site.Wyckoff_symbol` and `_atom_site.site_symmetry_multiplicity` but excludes the derived `space_group_Wyckoff` loop. Ensure read ignores incoming @@ -385,6 +385,34 @@ The ADR commit + design-phase review/reply cleanup are handled by `_space_group_Wyckoff.{id,letter,multiplicity,site_symmetry,coords_xyz}` loop. Commit: `Serialize Wyckoff multiplicity and report Wyckoff table` + + _P1.8 implementation decisions (implemented):_ + - **Project-CIF write of `_atom_site.site_symmetry_multiplicity`** + is already automatic: P1.4 added the `multiplicity` descriptor + with that CIF handler, and it is part of `AtomSite.parameters`, + so the atom-site loop emits it (value `?` for untabulated + sites). The `_space_group_Wyckoff` loop exclusion is already + provided by P1.3's `Structure._serializable_categories` + override. No new write-side code was needed in P1.8. + - **Read ignore of incoming `_space_group_Wyckoff.*`** is done by + a no-op `SpaceGroupWyckoffCollection.from_cif` override (the + structure read loop iterates *all* categories, including the + derived one). A hand-edited `_space_group_Wyckoff` loop is + discarded; the table is rebuilt from the space group on update. + - **Read ignore of incoming `_atom_site.site_symmetry_multiplicity`** + relies on re-derivation: the value is parsed into the + descriptor but overwritten by detection on the next + `_update_categories` (verified: file value `777` → re-derived + `1`). No extra read-side code. + - **Report `_space_group_Wyckoff.coords_xyz` = representative + coordinate only** (first orbit member, e.g. `(x,x,z)`), not the + full orbit. The collection stores the full centred orbit (up to + ~3551 chars for multiplicity-192 cubic positions), but the IUCr + report loop formatter rejects loop cells > 80 chars. Emitting + the representative keeps every space group's report valid and + matches the conventional ITA "Coordinates" entry. Decision + confirmed with the user during P1.8. The full orbit remains + available on the in-memory `space_group_wyckoff` category. - [ ] **P1.9 — Promote ADR, close #51, remove stale TODOs.** `git mv` `wyckoff-letter-detection.md` from `suggestions/` to `accepted/`, set `**Status:** Accepted`, flip its `docs/dev/adrs/index.md` row diff --git a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py index e7949c803..cf191a2ac 100644 --- a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py +++ b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py @@ -128,6 +128,18 @@ def remove(self, name: str) -> None: """Reject public mutation; the collection is derived (read-only).""" raise TypeError(_READ_ONLY_MESSAGE) + def from_cif(self, block: object) -> None: + """ + Ignore incoming CIF values for this derived category. + + The Wyckoff table is derived from the structure's space group and + is never read back from a CIF file: any ``_space_group_Wyckoff.*`` + loop in incoming CIF (for example a hand-edited project file) is + discarded and the table is rebuilt from the space group on the + next update. + """ + return + def _replace_from_space_group(self) -> None: """ Rebuild the rows from the parent structure's current space group. diff --git a/src/easydiffraction/io/cif/iucr_writer.py b/src/easydiffraction/io/cif/iucr_writer.py index b0d5d9513..593f25ae5 100644 --- a/src/easydiffraction/io/cif/iucr_writer.py +++ b/src/easydiffraction/io/cif/iucr_writer.py @@ -171,6 +171,7 @@ def _write_sc_block( _write_cell_section(lines, structure) _write_space_group_section(lines, structure) _write_symmetry_operations_section(lines, structure) + _write_space_group_wyckoff_section(lines, structure) _write_diffrn_section(lines, experiment) _write_wavelength_section(lines, experiment) _write_atom_site_sections(lines, structure) @@ -222,6 +223,49 @@ def _write_symmetry_operations_section(lines: list[str], structure: object) -> N _write_loop(lines, loop.tags, loop.rows) +def _write_space_group_wyckoff_section(lines: list[str], structure: object) -> None: + """Append the derived space-group Wyckoff-position loop. + + This loop is report-only: it summarises every Wyckoff position of the + structure's space group. ``coords_xyz`` reports the representative + orbit coordinate (the first orbit member) to keep loop cells compact. + """ + positions = list(_collection_values(getattr(structure, 'space_group_wyckoff', None))) + if not positions: + return + + rows = [ + ( + _attribute_descriptor(position, 'id'), + _attribute_descriptor(position, 'letter'), + _attribute_descriptor(position, 'multiplicity'), + _attribute_descriptor(position, 'site_symmetry'), + _wyckoff_representative_coord(position), + ) + for position in positions + ] + _section(lines, 'Wyckoff positions') + _write_loop( + lines, + ( + '_space_group_Wyckoff.id', + '_space_group_Wyckoff.letter', + '_space_group_Wyckoff.multiplicity', + '_space_group_Wyckoff.site_symmetry', + '_space_group_Wyckoff.coords_xyz', + ), + rows, + ) + + +def _wyckoff_representative_coord(position: object) -> str: + """Return the representative (first) orbit coordinate of a position.""" + coords = _attribute_value(position, 'coords_xyz') + if not coords: + return '?' + return str(coords).split()[0] + + def _write_diffrn_section(lines: list[str], experiment: object) -> None: """Append diffraction metadata.""" diffrn = getattr(experiment, 'diffrn', None) @@ -449,6 +493,7 @@ def _write_powder_phase_block(phase: _PowderPhase) -> str: _write_cell_section(lines, phase.structure) _write_space_group_section(lines, phase.structure) _write_symmetry_operations_section(lines, phase.structure) + _write_space_group_wyckoff_section(lines, phase.structure) _write_atom_site_sections(lines, phase.structure) _write_atom_site_aniso_sections(lines, phase.structure) _write_powder_phase_reference_section(lines, phase) @@ -874,6 +919,7 @@ def _atom_site_tags(family: str) -> tuple[str, ...]: '_atom_site.ADP_type', f'_atom_site.{family}_iso_or_equiv', '_atom_site.Wyckoff_symbol', + '_atom_site.site_symmetry_multiplicity', ) @@ -889,6 +935,7 @@ def _atom_site_row(atom_site: object) -> tuple[object, ...]: _attribute_descriptor(atom_site, 'adp_type'), _attribute_descriptor(atom_site, 'adp_iso'), _attribute_descriptor(atom_site, 'wyckoff_letter'), + _attribute_descriptor(atom_site, 'multiplicity'), ) From 3dcf0fa2a7c6faa59a2cee42db0d793c77023813 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 13:44:21 +0200 Subject: [PATCH 32/55] Promote wyckoff-letter-detection ADR and close issue #51 --- .../dev/adrs/accepted/space-group-database.md | 10 ++++---- .../wyckoff-letter-detection.md | 2 +- docs/dev/adrs/index.md | 2 +- docs/dev/issues/closed.md | 11 +++++++++ docs/dev/issues/open.md | 19 --------------- docs/dev/plans/space-group-database.md | 4 ++-- docs/dev/plans/wyckoff-letter-detection.md | 24 ++++++++++++++++--- 7 files changed, 41 insertions(+), 31 deletions(-) rename docs/dev/adrs/{suggestions => accepted}/wyckoff-letter-detection.md (99%) diff --git a/docs/dev/adrs/accepted/space-group-database.md b/docs/dev/adrs/accepted/space-group-database.md index 6b35a77b5..89fe9dc58 100644 --- a/docs/dev/adrs/accepted/space-group-database.md +++ b/docs/dev/adrs/accepted/space-group-database.md @@ -8,7 +8,7 @@ Structure model. > This ADR follows [`AGENTS.md`](../../../../AGENTS.md). It was a > prerequisite for -> [`wyckoff-letter-detection.md`](../suggestions/wyckoff-letter-detection.md): +> [`wyckoff-letter-detection.md`](wyckoff-letter-detection.md): > Wyckoff detection can only resolve letters for space groups present in > the bundled table, which this ADR's implementation completed for all > 230 groups. @@ -103,7 +103,7 @@ Coordinates and operators stay **strings** (e.g. `'(x,1/2,0)'`, `sympify`) in `crystallography.py` and to keep the file JSON-native (§2). Triclinic no-setting groups keep the `None` coordinate code, as today (see the `''`→`None` normalisation in -[`wyckoff-letter-detection.md`](../suggestions/wyckoff-letter-detection.md) +[`wyckoff-letter-detection.md`](wyckoff-letter-detection.md) §2). **Query surface preserved.** On disk the JSON is a list of setting @@ -286,7 +286,7 @@ coordinate-system code": EasyDiffraction's `SpaceGroup` category uses the empty string `''`, while the table key uses `None`. The database keeps `(1, None)` and `(2, None)`; callers normalise `''` to `None` at lookup boundaries, as specified in -[`wyckoff-letter-detection.md`](../suggestions/wyckoff-letter-detection.md). +[`wyckoff-letter-detection.md`](wyckoff-letter-detection.md). This is the least surprising solution because it keeps "no setting" distinct from any real coordinate-code string without inventing a sentinel value. @@ -376,7 +376,7 @@ which rejects any operator-form template in the packaged wheel. early when `coord_code is None` and `_get_general_position_ops()` indexes the raw key, so they need the `''`→`None` normalisation defined in - [`wyckoff-letter-detection.md`](../suggestions/wyckoff-letter-detection.md) + [`wyckoff-letter-detection.md`](wyckoff-letter-detection.md) §2 (which also updates these call sites). This ADR delivers the data; that ADR delivers the `None`-code consumer handling. @@ -571,7 +571,7 @@ respectively. ## Related ADRs -- [`wyckoff-letter-detection.md`](../suggestions/wyckoff-letter-detection.md) +- [`wyckoff-letter-detection.md`](wyckoff-letter-detection.md) — the dependent feature; its `''`→`None` coordinate-code normalisation and its "unsupported group" handling both build on this database. - [`iucr-cif-tag-alignment.md`](../accepted/iucr-cif-tag-alignment.md) — diff --git a/docs/dev/adrs/suggestions/wyckoff-letter-detection.md b/docs/dev/adrs/accepted/wyckoff-letter-detection.md similarity index 99% rename from docs/dev/adrs/suggestions/wyckoff-letter-detection.md rename to docs/dev/adrs/accepted/wyckoff-letter-detection.md index a838598e1..47df620bc 100644 --- a/docs/dev/adrs/suggestions/wyckoff-letter-detection.md +++ b/docs/dev/adrs/accepted/wyckoff-letter-detection.md @@ -1,6 +1,6 @@ # ADR: Automatic Wyckoff Position Detection -**Status:** Proposed **Date:** 2026-06-01 +**Status:** Accepted **Date:** 2026-06-01 ## Group diff --git a/docs/dev/adrs/index.md b/docs/dev/adrs/index.md index f14cb0be0..eea0d1af1 100644 --- a/docs/dev/adrs/index.md +++ b/docs/dev/adrs/index.md @@ -46,7 +46,7 @@ folders. | Quality | Accepted | Lint Complexity Thresholds | Treats ruff PLR complexity limits as design guardrails that should not be bypassed. | [`lint-complexity-thresholds.md`](accepted/lint-complexity-thresholds.md) | | Quality | Accepted | Test Strategy | Defines layered unit, functional, integration, script, and notebook testing. | [`test-strategy.md`](accepted/test-strategy.md) | | Structure model | Accepted | Type-Neutral ADP Parameters | Keeps ADP parameter object identities stable across B/U and iso/ani switches. | [`type-neutral-adp-parameters.md`](accepted/type-neutral-adp-parameters.md) | -| Structure model | Suggestion | Automatic Wyckoff Position Detection | Detects Wyckoff letter, multiplicity, and site symmetry from space group and coordinates; calculators consume them. | [`wyckoff-letter-detection.md`](suggestions/wyckoff-letter-detection.md) | +| Structure model | Accepted | Automatic Wyckoff Position Detection | Detects Wyckoff letter, multiplicity, and site symmetry from space group and coordinates; calculators consume them. | [`wyckoff-letter-detection.md`](accepted/wyckoff-letter-detection.md) | | Structure model | Accepted | Complete Space-Group Reference Database | One-time build of a complete space_groups.json.gz (all 230 groups) from cctbx, verified against multiple sources. | [`space-group-database.md`](accepted/space-group-database.md) | | User-facing API | Accepted | Crystal Structure 3D Visualization | Adds a renderer-neutral scene model drawn by ASCII and interactive Three.js engines for viewing crystal structures. | [`crysview-structure-visualization.md`](accepted/crysview-structure-visualization.md) | | User-facing API | Accepted | Display UX Facade | Defines `project.display` and `project.rendering` responsibilities and display method names. | [`display-ux.md`](accepted/display-ux.md) | diff --git a/docs/dev/issues/closed.md b/docs/dev/issues/closed.md index c3574c2f2..e6b000055 100644 --- a/docs/dev/issues/closed.md +++ b/docs/dev/issues/closed.md @@ -4,6 +4,17 @@ Issues that have been fully resolved. Kept for historical reference. --- +## 51. Access Space Group from `AtomSites` for Wyckoff Letters + +Closed by the Wyckoff-letter-detection implementation. `AtomSite` now +derives its allowed Wyckoff letters from the parent structure's space +group (via `_resolve_structure_space_group`) instead of a hardcoded +list, and the missing-letter case is handled explicitly: untabulated +space groups leave the Wyckoff letter and multiplicity unset, while +tabulated groups detect and fill them during the update flow. + +--- + ## 103. Make `_sync_engine_from_minimizer_category` Skip-Keys Declarative Closed by the emcee minimizer implementation. Minimizer categories now diff --git a/docs/dev/issues/open.md b/docs/dev/issues/open.md index d1d400759..89434ef8f 100644 --- a/docs/dev/issues/open.md +++ b/docs/dev/issues/open.md @@ -996,24 +996,6 @@ generation. --- -## 51. 🟢 Access Space Group from `AtomSites` for Wyckoff Letters - -**Type:** Design - -`AtomSite` needs the current space group to determine allowed Wyckoff -letters but currently returns a hardcoded list. Also, a missing Wyckoff -letter case needs a decision. - -**TODOs:** - -- [default.py](src/easydiffraction/datablocks/structure/categories/atom_sites/default.py#L163) -- [default.py](src/easydiffraction/datablocks/structure/categories/atom_sites/default.py#L179) -- [default.py](src/easydiffraction/datablocks/structure/categories/atom_sites/default.py#L353) - -**Depends on:** nothing. - ---- - ## 52. 🟢 Rename Line-Segment Background `y` to `intensity` **Type:** Naming @@ -1951,7 +1933,6 @@ only render the index column when no explicit id column is present. | 48 | Fix CrysPy TOF instrument default | 🟢 Low | Bug workaround | | 49 | Automate space group CIF name variants | 🟢 Low | Maintainability | | 50 | Clarify `Cell._update` minimizer param | 🟢 Low | Cleanup | -| 51 | Access space group for Wyckoff letters | 🟢 Low | Design | | 52 | Rename line-segment `y` to `intensity` | 🟢 Low | Naming | | 53 | Move `show()` to `CategoryCollection` | 🟢 Low | Maintainability | | 54 | Add `point_id` to excluded regions | 🟢 Low | Completeness | diff --git a/docs/dev/plans/space-group-database.md b/docs/dev/plans/space-group-database.md index b4ca81729..814b36e0b 100644 --- a/docs/dev/plans/space-group-database.md +++ b/docs/dev/plans/space-group-database.md @@ -26,7 +26,7 @@ This plan owns the ADR [`docs/dev/adrs/accepted/space-group-database.md`](../adrs/accepted/space-group-database.md) (drafted via `/draft-adr`, review cycle closed). It is a **prerequisite** for -[`wyckoff-letter-detection`](../adrs/suggestions/wyckoff-letter-detection.md): +[`wyckoff-letter-detection`](../adrs/accepted/wyckoff-letter-detection.md): this plan delivers the complete data; that feature delivers the `''`→`None` consumer handling so the triclinic groups use it. @@ -279,7 +279,7 @@ previously-missing groups now get correct symmetry handling. _Added after #187 shipped — a second, standalone cycle of this ADR's implementation. It is the **prerequisite** that -[`wyckoff-letter-detection`](../adrs/suggestions/wyckoff-letter-detection.md) +[`wyckoff-letter-detection`](../adrs/accepted/wyckoff-letter-detection.md) §10 / Decision 15 depends on and gates on at its P1.0, and it ships on its **own PR** (separate from #187). When implementing this phase, treat the `CT` checklist below as the active Phase 1 steps — the #187 Phase 1 diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index 4d912ab68..d3cc2d764 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -1,7 +1,7 @@ # Plan: Automatic Wyckoff Position Detection This plan follows [`AGENTS.md`](../../../AGENTS.md) and implements the -[`wyckoff-letter-detection`](../adrs/suggestions/wyckoff-letter-detection.md) +[`wyckoff-letter-detection`](../adrs/accepted/wyckoff-letter-detection.md) ADR. No deliberate exception to `AGENTS.md` is taken. ## Status @@ -14,7 +14,7 @@ ADR. No deliberate exception to `AGENTS.md` is taken. ## ADR This plan implements the -[`wyckoff-letter-detection`](../adrs/suggestions/wyckoff-letter-detection.md) +[`wyckoff-letter-detection`](../adrs/accepted/wyckoff-letter-detection.md) ADR. Earlier ADR review cycles closed at review 10 and then review 16 (adding the derived `space_group_Wyckoff` category and space-group-key re-detection); that text was committed as `0f3bc269c` @@ -413,13 +413,31 @@ The ADR commit + design-phase review/reply cleanup are handled by matches the conventional ITA "Coordinates" entry. Decision confirmed with the user during P1.8. The full orbit remains available on the in-memory `space_group_wyckoff` category. -- [ ] **P1.9 — Promote ADR, close #51, remove stale TODOs.** `git mv` +- [x] **P1.9 — Promote ADR, close #51, remove stale TODOs.** `git mv` `wyckoff-letter-detection.md` from `suggestions/` to `accepted/`, set `**Status:** Accepted`, flip its `docs/dev/adrs/index.md` row to `Accepted`, and fix links with `git grep -n`. Move issue #51 from `open.md` to `closed.md` and delete the resolved TODOs in `default.py` (~200–211, ~225, ~569). Commit: `Promote wyckoff-letter-detection ADR and close issue #51` + + _P1.9 notes (implemented):_ + - ADR moved with `git mv` to `accepted/`, `**Status:** Accepted`, + `index.md` row flipped to `Accepted` with the `accepted/` link. + - Inbound links to the old `suggestions/` path fixed in + `accepted/space-group-database.md` (5) and + `plans/space-group-database.md` (2), plus this plan's own ADR + cross-references. The ADR's `../../../../` root paths are + depth-invariant and its `../accepted/` sibling links still + resolve, so they were left unchanged (minimal diff). + - #51 moved from `open.md` (detailed section + summary-table row) + to `closed.md`. + - The `default.py` TODOs #51 referenced (old lines ~163/179/353, + about the hardcoded allowed-letter list and the missing-letter + case) were **already removed** when P1.5/P1.6 rewrote those + methods to resolve #51, so there is no `default.py` change in + this step. The only remaining TODO (label-regex/dict-key, line + ~68) is unrelated to #51 and was intentionally left. - [ ] **P1.10 — Phase 1 review gate.** No code. Mark this `[x]`, commit the checklist update alone, then stop for the Phase 1 review. Commit: `Reach Phase 1 review gate` From 8dd072cc0ce63a5baaa8a9b9d47ab6279efc5d18 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 13:44:34 +0200 Subject: [PATCH 33/55] Reach Phase 1 review gate --- docs/dev/plans/wyckoff-letter-detection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index d3cc2d764..ac23466dc 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -438,7 +438,7 @@ The ADR commit + design-phase review/reply cleanup are handled by methods to resolve #51, so there is no `default.py` change in this step. The only remaining TODO (label-regex/dict-key, line ~68) is unrelated to #51 and was intentionally left. -- [ ] **P1.10 — Phase 1 review gate.** No code. Mark this `[x]`, commit +- [x] **P1.10 — Phase 1 review gate.** No code. Mark this `[x]`, commit the checklist update alone, then stop for the Phase 1 review. Commit: `Reach Phase 1 review gate` From 7cdb2d22dea0c17d88b6b97da83969b976c1cfaf Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 13:58:23 +0200 Subject: [PATCH 34/55] Preserve explicit Wyckoff letter until a later edit --- .../structure/categories/atom_sites/default.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py b/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py index 17d954b73..7f3d81f63 100644 --- a/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py +++ b/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py @@ -695,13 +695,19 @@ def _detect_and_snap_atom( key = (name_hm, coord_code) letter_before = atom.wyckoff_letter.value coords = (atom.fract_x.value, atom.fract_y.value, atom.fract_z.value) - coords_changed = atom._wyckoff_coord_baseline is None or any( + # A ``None`` baseline marks the first population (create/load), not a + # later edit. Treat coordinates or the space-group key as "changed" + # only against an existing baseline, so an explicit initial letter is + # preserved (routed to ``wyckoff_position_info`` below) instead of + # being overwritten by all-letter detection. The ADR requires a + # user-supplied letter to persist until a genuine later coordinate or + # space-group-key edit. + coords_changed = atom._wyckoff_coord_baseline is not None and any( abs(a - b) > ecr._WYCKOFF_DETECTION_TOL for a, b in zip(coords, atom._wyckoff_coord_baseline) ) - detect = (not called_by_minimizer) and ( - not letter_before or coords_changed or atom._wyckoff_key_baseline != key - ) + key_changed = atom._wyckoff_key_baseline is not None and atom._wyckoff_key_baseline != key + detect = (not called_by_minimizer) and (not letter_before or coords_changed or key_changed) if detect: position = ecr.detect_wyckoff_position(name_hm, coord_code, coords) if position is not None and letter_before and position.letter != letter_before: From f97f5833bc839ad530a29df095b0b45652f730bd Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 13:59:14 +0200 Subject: [PATCH 35/55] Build space-group Wyckoff id from multiplicity and letter --- .../structure/categories/space_group_wyckoff/default.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py index cf191a2ac..66e74e397 100644 --- a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py +++ b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py @@ -157,10 +157,11 @@ def _replace_from_space_group(self) -> None: if not positions: return for letter, position in positions.items(): + multiplicity = int(position['multiplicity']) row = self._item_type() - row._id.value = letter + row._id.value = f'{multiplicity}{letter}' row._letter.value = letter - row._multiplicity.value = int(position['multiplicity']) + row._multiplicity.value = multiplicity row._site_symmetry.value = str(position['site_symmetry']) row._coords_xyz.value = ' '.join(position['coords_xyz']) self._items.append(row) From 55a0656a27ec59c6aec89232c371f5241caf645b Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 14:00:17 +0200 Subject: [PATCH 36/55] Rebuild Wyckoff index and parent links on replace --- .../categories/space_group_wyckoff/default.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py index 66e74e397..306134b44 100644 --- a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py +++ b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py @@ -144,18 +144,23 @@ def _replace_from_space_group(self) -> None: """ Rebuild the rows from the parent structure's current space group. - Clears all rows, then repopulates from the bundled Wyckoff table. - Leaves the collection empty for an absent/untabulated space group. + Repopulates from the bundled Wyckoff table and adopts the new + rows via ``_adopt_items``, which rebuilds the name index and + parent links so a stale key lookup cannot survive a space-group + change. Leaves the collection empty for an absent/untabulated + space group. """ - self._items.clear() structure = getattr(self, '_parent', None) if structure is None: + self._adopt_items([]) return name_hm = structure.space_group.name_h_m.value coord_code = structure.space_group.it_coordinate_system_code.value positions = ecr.space_group_wyckoff_table(name_hm, coord_code) if not positions: + self._adopt_items([]) return + rows = [] for letter, position in positions.items(): multiplicity = int(position['multiplicity']) row = self._item_type() @@ -164,4 +169,5 @@ def _replace_from_space_group(self) -> None: row._multiplicity.value = multiplicity row._site_symmetry.value = str(position['site_symmetry']) row._coords_xyz.value = ' '.join(position['coords_xyz']) - self._items.append(row) + rows.append(row) + self._adopt_items(rows) From 68fb0d980f5598a89c2869eb4423e5a756ad3d3c Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 14:00:52 +0200 Subject: [PATCH 37/55] Reject item assignment and deletion on Wyckoff collection --- .../structure/categories/space_group_wyckoff/default.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py index 306134b44..4690384c4 100644 --- a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py +++ b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py @@ -128,6 +128,14 @@ def remove(self, name: str) -> None: """Reject public mutation; the collection is derived (read-only).""" raise TypeError(_READ_ONLY_MESSAGE) + def __setitem__(self, name: str, item: object) -> None: + """Reject item assignment; the collection is derived (read-only).""" + raise TypeError(_READ_ONLY_MESSAGE) + + def __delitem__(self, name: str) -> None: + """Reject item deletion; the collection is derived (read-only).""" + raise TypeError(_READ_ONLY_MESSAGE) + def from_cif(self, block: object) -> None: """ Ignore incoming CIF values for this derived category. From 32371a8bd2ac8329f7f6bf04831acf3edd22b1e8 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 14:02:28 +0200 Subject: [PATCH 38/55] Resolve None-coord-code groups in Wyckoff constraint helper --- .../crystallography/crystallography.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/easydiffraction/crystallography/crystallography.py b/src/easydiffraction/crystallography/crystallography.py index 94fd992e8..b4a76c855 100644 --- a/src/easydiffraction/crystallography/crystallography.py +++ b/src/easydiffraction/crystallography/crystallography.py @@ -255,14 +255,12 @@ def _get_wyckoff_exprs( return None coord_code = _normalize_coord_code(coord_code) - if coord_code is None: - log.error('IT_coordinate_system_code is not set') - return None - if (it_number, coord_code) not in SPACE_GROUPS: - # Space group is not in the local SPACE_GROUPS table (e.g. P 1, - # where cryspy reports no coordinate-system codes). Treat as - # "no symmetry constraints to apply". + # Space group / coordinate-system combination is absent from the + # local SPACE_GROUPS table. Treat as "no symmetry constraints to + # apply". Triclinic groups are keyed ``(it_number, None)`` and + # resolve normally through this lookup, so a ``None`` code is not + # treated as unset. return None entry = SPACE_GROUPS[it_number, coord_code] From 91dd4d672c0482b8beac2303281f59a988816714 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 14:02:58 +0200 Subject: [PATCH 39/55] Sync top-level plan status with completed Phase 1 --- docs/dev/plans/wyckoff-letter-detection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index ac23466dc..bff476a05 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -7,8 +7,8 @@ ADR. No deliberate exception to `AGENTS.md` is taken. ## Status - [x] ADR review gate closed -- [ ] Phase 1 — Implementation (code + docs) -- [ ] Phase 1 review gate +- [x] Phase 1 — Implementation (code + docs) +- [x] Phase 1 review gate - [ ] Phase 2 — Verification (tests + `pixi` checks) ## ADR From 34d99f154051899e9b229248e543c8e1dafd48e2 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 14:08:57 +0200 Subject: [PATCH 40/55] Raise ValueError for Wyckoff read-only mutation per ADR --- .../categories/space_group_wyckoff/default.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py index 4690384c4..1a3cfac79 100644 --- a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py +++ b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py @@ -118,23 +118,23 @@ def __init__(self) -> None: def add(self, item: object) -> None: """Reject public mutation; the collection is derived (read-only).""" - raise TypeError(_READ_ONLY_MESSAGE) + raise ValueError(_READ_ONLY_MESSAGE) def create(self, **kwargs: object) -> None: """Reject public mutation; the collection is derived (read-only).""" - raise TypeError(_READ_ONLY_MESSAGE) + raise ValueError(_READ_ONLY_MESSAGE) def remove(self, name: str) -> None: """Reject public mutation; the collection is derived (read-only).""" - raise TypeError(_READ_ONLY_MESSAGE) + raise ValueError(_READ_ONLY_MESSAGE) def __setitem__(self, name: str, item: object) -> None: """Reject item assignment; the collection is derived (read-only).""" - raise TypeError(_READ_ONLY_MESSAGE) + raise ValueError(_READ_ONLY_MESSAGE) def __delitem__(self, name: str) -> None: """Reject item deletion; the collection is derived (read-only).""" - raise TypeError(_READ_ONLY_MESSAGE) + raise ValueError(_READ_ONLY_MESSAGE) def from_cif(self, block: object) -> None: """ From 7abbffe34e072f35471ca6754b36112a08208aea Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 14:52:26 +0200 Subject: [PATCH 41/55] Remove wyckoff_letter from tutorial examples --- docs/docs/tutorials/ed-10.py | 1 - docs/docs/tutorials/ed-11.py | 1 - docs/docs/tutorials/ed-12.py | 2 -- docs/docs/tutorials/ed-13.py | 6 ------ docs/docs/tutorials/ed-16.py | 1 - docs/docs/tutorials/ed-17.py | 6 ------ docs/docs/tutorials/ed-2.py | 4 ---- docs/docs/tutorials/ed-20.py | 2 -- docs/docs/tutorials/ed-3.py | 4 ---- docs/docs/tutorials/ed-4.py | 5 ----- docs/docs/tutorials/ed-5.py | 6 ------ docs/docs/tutorials/ed-6.py | 5 ----- docs/docs/tutorials/ed-8.py | 6 ------ docs/docs/tutorials/ed-9.py | 5 ----- 14 files changed, 54 deletions(-) diff --git a/docs/docs/tutorials/ed-10.py b/docs/docs/tutorials/ed-10.py index 1b5077fb8..751831508 100644 --- a/docs/docs/tutorials/ed-10.py +++ b/docs/docs/tutorials/ed-10.py @@ -39,7 +39,6 @@ fract_x=0.0, fract_y=0.0, fract_z=0.0, - wyckoff_letter='a', adp_iso=0.5, ) diff --git a/docs/docs/tutorials/ed-11.py b/docs/docs/tutorials/ed-11.py index e8d878f27..e08e81d63 100644 --- a/docs/docs/tutorials/ed-11.py +++ b/docs/docs/tutorials/ed-11.py @@ -47,7 +47,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.5, ) diff --git a/docs/docs/tutorials/ed-12.py b/docs/docs/tutorials/ed-12.py index 2e38828ea..3add79927 100644 --- a/docs/docs/tutorials/ed-12.py +++ b/docs/docs/tutorials/ed-12.py @@ -52,7 +52,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=1.0, ) project.structures['nacl'].atom_sites.create( @@ -61,7 +60,6 @@ fract_x=0.5, fract_y=0.5, fract_z=0.5, - wyckoff_letter='b', adp_iso=1.0, ) diff --git a/docs/docs/tutorials/ed-13.py b/docs/docs/tutorials/ed-13.py index 454f82502..888c41d48 100644 --- a/docs/docs/tutorials/ed-13.py +++ b/docs/docs/tutorials/ed-13.py @@ -496,7 +496,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.89, ) @@ -1030,7 +1029,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.95, occupancy=0.5, ) @@ -1040,7 +1038,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.95, occupancy=0.5, ) @@ -1050,7 +1047,6 @@ fract_x=0.5, fract_y=0.5, fract_z=0.5, - wyckoff_letter='b', adp_iso=0.80, ) project_2.structures['lbco'].atom_sites.create( @@ -1059,7 +1055,6 @@ fract_x=0, fract_y=0.5, fract_z=0.5, - wyckoff_letter='c', adp_iso=1.66, ) @@ -1411,7 +1406,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.89, ) diff --git a/docs/docs/tutorials/ed-16.py b/docs/docs/tutorials/ed-16.py index 2ede48cfb..89e60625f 100644 --- a/docs/docs/tutorials/ed-16.py +++ b/docs/docs/tutorials/ed-16.py @@ -52,7 +52,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.2, ) diff --git a/docs/docs/tutorials/ed-17.py b/docs/docs/tutorials/ed-17.py index e1879bd20..eb3605e9d 100644 --- a/docs/docs/tutorials/ed-17.py +++ b/docs/docs/tutorials/ed-17.py @@ -68,7 +68,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.3, ) struct.atom_sites.create( @@ -77,7 +76,6 @@ fract_x=0.279, fract_y=0.25, fract_z=0.985, - wyckoff_letter='c', adp_iso=0.3, ) struct.atom_sites.create( @@ -86,7 +84,6 @@ fract_x=0.094, fract_y=0.25, fract_z=0.429, - wyckoff_letter='c', adp_iso=0.34, ) struct.atom_sites.create( @@ -95,7 +92,6 @@ fract_x=0.091, fract_y=0.25, fract_z=0.771, - wyckoff_letter='c', adp_iso=0.63, ) struct.atom_sites.create( @@ -104,7 +100,6 @@ fract_x=0.448, fract_y=0.25, fract_z=0.217, - wyckoff_letter='c', adp_iso=0.59, ) struct.atom_sites.create( @@ -113,7 +108,6 @@ fract_x=0.164, fract_y=0.032, fract_z=0.28, - wyckoff_letter='d', adp_iso=0.83, ) diff --git a/docs/docs/tutorials/ed-2.py b/docs/docs/tutorials/ed-2.py index 5ede4537b..008ca5d0f 100644 --- a/docs/docs/tutorials/ed-2.py +++ b/docs/docs/tutorials/ed-2.py @@ -56,7 +56,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.5, occupancy=0.5, ) @@ -66,7 +65,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.5, occupancy=0.5, ) @@ -76,7 +74,6 @@ fract_x=0.5, fract_y=0.5, fract_z=0.5, - wyckoff_letter='b', adp_iso=0.5, ) structure.atom_sites.create( @@ -85,7 +82,6 @@ fract_x=0, fract_y=0.5, fract_z=0.5, - wyckoff_letter='c', adp_iso=0.5, ) diff --git a/docs/docs/tutorials/ed-20.py b/docs/docs/tutorials/ed-20.py index b54a090b3..5b4b6fe03 100644 --- a/docs/docs/tutorials/ed-20.py +++ b/docs/docs/tutorials/ed-20.py @@ -41,7 +41,6 @@ fract_x=0.0, fract_y=0.0, fract_z=0.0, - wyckoff_letter='a', adp_type='Biso', adp_iso=1.0, ) @@ -63,7 +62,6 @@ fract_x=0.0, fract_y=0.0, fract_z=0.0, - wyckoff_letter='a', adp_type='Biso', adp_iso=1.0, ) diff --git a/docs/docs/tutorials/ed-3.py b/docs/docs/tutorials/ed-3.py index dff71180b..6b1c06dc1 100644 --- a/docs/docs/tutorials/ed-3.py +++ b/docs/docs/tutorials/ed-3.py @@ -112,7 +112,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.5, occupancy=0.5, ) @@ -122,7 +121,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.5, occupancy=0.5, ) @@ -132,7 +130,6 @@ fract_x=0.5, fract_y=0.5, fract_z=0.5, - wyckoff_letter='b', adp_iso=0.5, ) project.structures['lbco'].atom_sites.create( @@ -141,7 +138,6 @@ fract_x=0, fract_y=0.5, fract_z=0.5, - wyckoff_letter='c', adp_iso=0.5, ) diff --git a/docs/docs/tutorials/ed-4.py b/docs/docs/tutorials/ed-4.py index 39ea4b150..0e974893a 100644 --- a/docs/docs/tutorials/ed-4.py +++ b/docs/docs/tutorials/ed-4.py @@ -55,7 +55,6 @@ fract_x=0.1876, fract_y=0.25, fract_z=0.167, - wyckoff_letter='c', adp_iso=1.37, ) structure.atom_sites.create( @@ -64,7 +63,6 @@ fract_x=0.0654, fract_y=0.25, fract_z=0.684, - wyckoff_letter='c', adp_iso=0.3777, ) structure.atom_sites.create( @@ -73,7 +71,6 @@ fract_x=0.9082, fract_y=0.25, fract_z=0.5954, - wyckoff_letter='c', adp_iso=1.9764, ) structure.atom_sites.create( @@ -82,7 +79,6 @@ fract_x=0.1935, fract_y=0.25, fract_z=0.5432, - wyckoff_letter='c', adp_iso=1.4456, ) structure.atom_sites.create( @@ -91,7 +87,6 @@ fract_x=0.0811, fract_y=0.0272, fract_z=0.8086, - wyckoff_letter='d', adp_iso=1.2822, ) diff --git a/docs/docs/tutorials/ed-5.py b/docs/docs/tutorials/ed-5.py index 1e1c27dda..942444d25 100644 --- a/docs/docs/tutorials/ed-5.py +++ b/docs/docs/tutorials/ed-5.py @@ -53,7 +53,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.5, ) structure.atom_sites.create( @@ -62,7 +61,6 @@ fract_x=0.279, fract_y=0.25, fract_z=0.985, - wyckoff_letter='c', adp_iso=0.5, ) structure.atom_sites.create( @@ -71,7 +69,6 @@ fract_x=0.094, fract_y=0.25, fract_z=0.429, - wyckoff_letter='c', adp_iso=0.5, ) structure.atom_sites.create( @@ -80,7 +77,6 @@ fract_x=0.091, fract_y=0.25, fract_z=0.771, - wyckoff_letter='c', adp_iso=0.5, ) structure.atom_sites.create( @@ -89,7 +85,6 @@ fract_x=0.448, fract_y=0.25, fract_z=0.217, - wyckoff_letter='c', adp_iso=0.5, ) structure.atom_sites.create( @@ -98,7 +93,6 @@ fract_x=0.164, fract_y=0.032, fract_z=0.28, - wyckoff_letter='d', adp_iso=0.5, ) diff --git a/docs/docs/tutorials/ed-6.py b/docs/docs/tutorials/ed-6.py index b57c56952..f2968b774 100644 --- a/docs/docs/tutorials/ed-6.py +++ b/docs/docs/tutorials/ed-6.py @@ -50,7 +50,6 @@ fract_x=0, fract_y=0, fract_z=0.5, - wyckoff_letter='b', adp_iso=0.5, ) structure.atom_sites.create( @@ -59,7 +58,6 @@ fract_x=0.5, fract_y=0, fract_z=0, - wyckoff_letter='e', adp_iso=0.5, ) structure.atom_sites.create( @@ -68,7 +66,6 @@ fract_x=0.21, fract_y=-0.21, fract_z=0.06, - wyckoff_letter='h', adp_iso=0.5, ) structure.atom_sites.create( @@ -77,7 +74,6 @@ fract_x=0, fract_y=0, fract_z=0.197, - wyckoff_letter='c', adp_iso=0.5, ) structure.atom_sites.create( @@ -86,7 +82,6 @@ fract_x=0.13, fract_y=-0.13, fract_z=0.08, - wyckoff_letter='h', adp_iso=0.5, ) diff --git a/docs/docs/tutorials/ed-8.py b/docs/docs/tutorials/ed-8.py index 09917e35c..d875c3998 100644 --- a/docs/docs/tutorials/ed-8.py +++ b/docs/docs/tutorials/ed-8.py @@ -51,7 +51,6 @@ fract_x=0.4663, fract_y=0.0, fract_z=0.25, - wyckoff_letter='b', adp_iso=0.92, ) structure.atom_sites.create( @@ -60,7 +59,6 @@ fract_x=0.2521, fract_y=0.2521, fract_z=0.2521, - wyckoff_letter='a', adp_iso=0.73, ) structure.atom_sites.create( @@ -69,7 +67,6 @@ fract_x=0.0851, fract_y=0.0851, fract_z=0.0851, - wyckoff_letter='a', adp_iso=2.08, ) structure.atom_sites.create( @@ -78,7 +75,6 @@ fract_x=0.1377, fract_y=0.3054, fract_z=0.1195, - wyckoff_letter='c', adp_iso=0.90, ) structure.atom_sites.create( @@ -87,7 +83,6 @@ fract_x=0.3625, fract_y=0.3633, fract_z=0.1867, - wyckoff_letter='c', adp_iso=1.37, ) structure.atom_sites.create( @@ -96,7 +91,6 @@ fract_x=0.4612, fract_y=0.4612, fract_z=0.4612, - wyckoff_letter='a', adp_iso=0.88, ) diff --git a/docs/docs/tutorials/ed-9.py b/docs/docs/tutorials/ed-9.py index 083bde68f..4fe451af2 100644 --- a/docs/docs/tutorials/ed-9.py +++ b/docs/docs/tutorials/ed-9.py @@ -48,7 +48,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.2, occupancy=0.5, ) @@ -58,7 +57,6 @@ fract_x=0, fract_y=0, fract_z=0, - wyckoff_letter='a', adp_iso=0.2, occupancy=0.5, ) @@ -68,7 +66,6 @@ fract_x=0.5, fract_y=0.5, fract_z=0.5, - wyckoff_letter='b', adp_iso=0.2567, ) structure_1.atom_sites.create( @@ -77,7 +74,6 @@ fract_x=0, fract_y=0.5, fract_z=0.5, - wyckoff_letter='c', adp_iso=1.4041, ) @@ -110,7 +106,6 @@ fract_x=0.0, fract_y=0.0, fract_z=0.0, - wyckoff_letter='a', adp_iso=0.0, ) From 25b212b7dad434a261467bae8d2abe36c8460300 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 14:58:28 +0200 Subject: [PATCH 42/55] Apply pixi run fix auto-fixes --- .../dev/adrs/accepted/space-group-database.md | 30 +++++++------ docs/dev/package-structure/full.md | 9 ++++ docs/dev/package-structure/short.md | 4 ++ docs/dev/plans/wyckoff-letter-detection.md | 42 ++++++++++--------- .../categories/space_group_wyckoff/factory.py | 4 +- .../datablocks/structure/item/base.py | 8 +++- src/easydiffraction/io/cif/iucr_writer.py | 14 ++++--- 7 files changed, 67 insertions(+), 44 deletions(-) diff --git a/docs/dev/adrs/accepted/space-group-database.md b/docs/dev/adrs/accepted/space-group-database.md index 89fe9dc58..fdaf8e1f1 100644 --- a/docs/dev/adrs/accepted/space-group-database.md +++ b/docs/dev/adrs/accepted/space-group-database.md @@ -8,10 +8,10 @@ Structure model. > This ADR follows [`AGENTS.md`](../../../../AGENTS.md). It was a > prerequisite for -> [`wyckoff-letter-detection.md`](wyckoff-letter-detection.md): -> Wyckoff detection can only resolve letters for space groups present in -> the bundled table, which this ADR's implementation completed for all -> 230 groups. +> [`wyckoff-letter-detection.md`](wyckoff-letter-detection.md): Wyckoff +> detection can only resolve letters for space groups present in the +> bundled table, which this ADR's implementation completed for all 230 +> groups. ## Context @@ -103,8 +103,7 @@ Coordinates and operators stay **strings** (e.g. `'(x,1/2,0)'`, `sympify`) in `crystallography.py` and to keep the file JSON-native (§2). Triclinic no-setting groups keep the `None` coordinate code, as today (see the `''`→`None` normalisation in -[`wyckoff-letter-detection.md`](wyckoff-letter-detection.md) -§2). +[`wyckoff-letter-detection.md`](wyckoff-letter-detection.md) §2). **Query surface preserved.** On disk the JSON is a list of setting records, each carrying the canonical `IT_number` and @@ -286,10 +285,9 @@ coordinate-system code": EasyDiffraction's `SpaceGroup` category uses the empty string `''`, while the table key uses `None`. The database keeps `(1, None)` and `(2, None)`; callers normalise `''` to `None` at lookup boundaries, as specified in -[`wyckoff-letter-detection.md`](wyckoff-letter-detection.md). -This is the least surprising solution because it keeps "no setting" -distinct from any real coordinate-code string without inventing a -sentinel value. +[`wyckoff-letter-detection.md`](wyckoff-letter-detection.md). This is +the least surprising solution because it keeps "no setting" distinct +from any real coordinate-code string without inventing a sentinel value. ### 8. The database file is generated, not hand-edited @@ -376,9 +374,9 @@ which rejects any operator-form template in the packaged wheel. early when `coord_code is None` and `_get_general_position_ops()` indexes the raw key, so they need the `''`→`None` normalisation defined in - [`wyckoff-letter-detection.md`](wyckoff-letter-detection.md) - §2 (which also updates these call sites). This ADR delivers the data; - that ADR delivers the `None`-code consumer handling. + [`wyckoff-letter-detection.md`](wyckoff-letter-detection.md) §2 (which + also updates these call sites). This ADR delivers the data; that ADR + delivers the `None`-code consumer handling. ## Alternatives Considered @@ -571,8 +569,8 @@ respectively. ## Related ADRs -- [`wyckoff-letter-detection.md`](wyckoff-letter-detection.md) - — the dependent feature; its `''`→`None` coordinate-code normalisation - and its "unsupported group" handling both build on this database. +- [`wyckoff-letter-detection.md`](wyckoff-letter-detection.md) — the + dependent feature; its `''`→`None` coordinate-code normalisation and + its "unsupported group" handling both build on this database. - [`iucr-cif-tag-alignment.md`](../accepted/iucr-cif-tag-alignment.md) — consumes space-group and Wyckoff data on export. diff --git a/docs/dev/package-structure/full.md b/docs/dev/package-structure/full.md index cad676efe..de4e69ac5 100644 --- a/docs/dev/package-structure/full.md +++ b/docs/dev/package-structure/full.md @@ -244,6 +244,7 @@ │ │ ├── 🏷️ class TypeValidator │ │ ├── 🏷️ class RangeValidator │ │ ├── 🏷️ class MembershipValidator +│ │ ├── 🏷️ class PermissiveMembershipValidator │ │ ├── 🏷️ class RegexValidator │ │ └── 🏷️ class AttributeSpec │ └── 📄 variable.py @@ -262,6 +263,7 @@ ├── 📁 crystallography │ ├── 📄 __init__.py │ ├── 📄 crystallography.py +│ │ └── 🏷️ class WyckoffPosition │ └── 📄 space_groups.py ├── 📁 datablocks │ ├── 📁 experiment @@ -464,6 +466,13 @@ │ │ │ │ │ └── 🏷️ class SpaceGroup │ │ │ │ └── 📄 factory.py │ │ │ │ └── 🏷️ class SpaceGroupFactory +│ │ │ ├── 📁 space_group_wyckoff +│ │ │ │ ├── 📄 __init__.py +│ │ │ │ ├── 📄 default.py +│ │ │ │ │ ├── 🏷️ class SpaceGroupWyckoff +│ │ │ │ │ └── 🏷️ class SpaceGroupWyckoffCollection +│ │ │ │ └── 📄 factory.py +│ │ │ │ └── 🏷️ class SpaceGroupWyckoffFactory │ │ │ └── 📄 __init__.py │ │ ├── 📁 item │ │ │ ├── 📄 __init__.py diff --git a/docs/dev/package-structure/short.md b/docs/dev/package-structure/short.md index 23c0e68b8..61c705dd4 100644 --- a/docs/dev/package-structure/short.md +++ b/docs/dev/package-structure/short.md @@ -222,6 +222,10 @@ │ │ │ │ ├── 📄 __init__.py │ │ │ │ ├── 📄 default.py │ │ │ │ └── 📄 factory.py +│ │ │ ├── 📁 space_group_wyckoff +│ │ │ │ ├── 📄 __init__.py +│ │ │ │ ├── 📄 default.py +│ │ │ │ └── 📄 factory.py │ │ │ └── 📄 __init__.py │ │ ├── 📁 item │ │ │ ├── 📄 __init__.py diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index bff476a05..3a5e83baf 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -331,25 +331,23 @@ The ADR commit + design-phase review/reply cleanup are handled by point — so centering copies and off-canonical-slot representatives (e.g. 6e `(0,x,0)`) snap correctly; derive constrained-axis flags from the same representative. This free-parameter-solving snap - **replaces the positional `_apply_fract_constraints` substitution** - (a deliberate deviation from ADR §5's "existing constraint step", - decided during P1.1; reflect it in ADR §5 at the P1.9 promotion). - Warn when coordinate or - supported space-group edits move the letter, when a user - letter-set snaps coordinates, and when a same-letter coordinate - edit snaps coordinates. Honour `called_by_minimizer=True`; - populate `multiplicity` from `wyckoff_position_info`. - Site-symmetry display data comes from + **replaces the positional `_apply_fract_constraints` + substitution** (a deliberate deviation from ADR §5's "existing + constraint step", decided during P1.1; reflect it in ADR §5 at the + P1.9 promotion). Warn when coordinate or supported space-group + edits move the letter, when a user letter-set snaps coordinates, + and when a same-letter coordinate edit snaps coordinates. Honour + `called_by_minimizer=True`; populate `multiplicity` from + `wyckoff_position_info`. Site-symmetry display data comes from `structure.space_group_wyckoff`, not from `AtomSite`. Commit: `Detect and track Wyckoff letters in the update flow` _P1.6 implementation decisions (implemented):_ - - **Snap = slot-aware free-parameter-solving** - (`crystallography.snap_to_wyckoff_template`, already committed): solve - the free params from the **free (refinable) axes**, keep those axes, - and derive the constrained axes. **Not** manifold projection — that - averaged/moved the free axis and fought the minimizer. Handles + (`crystallography.snap_to_wyckoff_template`, already committed): + solve the free params from the **free (refinable) axes**, keep those + axes, and derive the constrained axes. **Not** manifold projection — + that averaged/moved the free axis and fought the minimizer. Handles off-canonical reps like 6e `(0,x,0)` (keep `fract_y`, set `fract_x=fract_z=0`); matches the old substitution for canonical sites, so the fit is unaffected. Per-axis constraint flags are @@ -362,12 +360,14 @@ The ADR commit + design-phase review/reply cleanup are handled by detection still runs there. Gate re-detection **and** the "adjusted"/"moved-letter" warnings on `not called_by_minimizer`, so they never fire per fit step. - - **Remaining:** rewrite `_apply_atomic_coordinates_symmetry_constraints` - (per atom: resolve the `_wyckoff_letter_needs_validation` marker → - decide detect/trigger → snap → set `multiplicity` + constrained flags - → refresh baselines), thread `called_by_minimizer` through - `AtomSites._update`, change the objective call site(s), then **verify - by running `test_fit_neutron_pd_cwl_hs`** and smoke tests. + - **Remaining:** rewrite + `_apply_atomic_coordinates_symmetry_constraints` (per atom: resolve + the `_wyckoff_letter_needs_validation` marker → decide + detect/trigger → snap → set `multiplicity` + constrained flags → + refresh baselines), thread `called_by_minimizer` through + `AtomSites._update`, change the objective call site(s), then + **verify by running `test_fit_neutron_pd_cwl_hs`** and smoke tests. + - [x] **P1.7 — Calculator consumes model multiplicity.** Replace the `SPACE_GROUPS` lookup in `cryspy._update_atom_multiplicity` with `atom_site.multiplicity.value`; when it is `None`, leave the @@ -413,6 +413,7 @@ The ADR commit + design-phase review/reply cleanup are handled by matches the conventional ITA "Coordinates" entry. Decision confirmed with the user during P1.8. The full orbit remains available on the in-memory `space_group_wyckoff` category. + - [x] **P1.9 — Promote ADR, close #51, remove stale TODOs.** `git mv` `wyckoff-letter-detection.md` from `suggestions/` to `accepted/`, set `**Status:** Accepted`, flip its `docs/dev/adrs/index.md` row @@ -438,6 +439,7 @@ The ADR commit + design-phase review/reply cleanup are handled by methods to resolve #51, so there is no `default.py` change in this step. The only remaining TODO (label-regex/dict-key, line ~68) is unrelated to #51 and was intentionally left. + - [x] **P1.10 — Phase 1 review gate.** No code. Mark this `[x]`, commit the checklist update alone, then stop for the Phase 1 review. Commit: `Reach Phase 1 review gate` diff --git a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/factory.py b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/factory.py index 7ad4eec0b..2e3ea0980 100644 --- a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/factory.py +++ b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/factory.py @@ -1,6 +1,8 @@ # SPDX-FileCopyrightText: 2026 EasyScience contributors # SPDX-License-Identifier: BSD-3-Clause -"""Space-group Wyckoff factory — delegates entirely to ``FactoryBase``.""" +""" +Space-group Wyckoff factory — delegates entirely to ``FactoryBase``. +""" from __future__ import annotations diff --git a/src/easydiffraction/datablocks/structure/item/base.py b/src/easydiffraction/datablocks/structure/item/base.py index 84c74cb5f..704a98c9c 100644 --- a/src/easydiffraction/datablocks/structure/item/base.py +++ b/src/easydiffraction/datablocks/structure/item/base.py @@ -190,7 +190,9 @@ def geom(self, new: Geom) -> None: @property def space_group_wyckoff(self) -> SpaceGroupWyckoffCollection: - """Read-only Wyckoff table derived from the current space group.""" + """ + Read-only Wyckoff table derived from the current space group. + """ return self._space_group_wyckoff # ------------------------------------------------------------------ @@ -252,7 +254,9 @@ def _update_categories( self._need_categories_update = False def _serializable_categories(self) -> list: - """Project-CIF categories (excludes the derived Wyckoff table).""" + """ + Project-CIF categories (excludes the derived Wyckoff table). + """ return [ category for category in self.categories diff --git a/src/easydiffraction/io/cif/iucr_writer.py b/src/easydiffraction/io/cif/iucr_writer.py index 593f25ae5..6db8aae8f 100644 --- a/src/easydiffraction/io/cif/iucr_writer.py +++ b/src/easydiffraction/io/cif/iucr_writer.py @@ -224,11 +224,13 @@ def _write_symmetry_operations_section(lines: list[str], structure: object) -> N def _write_space_group_wyckoff_section(lines: list[str], structure: object) -> None: - """Append the derived space-group Wyckoff-position loop. + """ + Append the derived space-group Wyckoff-position loop. - This loop is report-only: it summarises every Wyckoff position of the - structure's space group. ``coords_xyz`` reports the representative - orbit coordinate (the first orbit member) to keep loop cells compact. + This loop is report-only: it summarises every Wyckoff position of + the structure's space group. ``coords_xyz`` reports the + representative orbit coordinate (the first orbit member) to keep + loop cells compact. """ positions = list(_collection_values(getattr(structure, 'space_group_wyckoff', None))) if not positions: @@ -259,7 +261,9 @@ def _write_space_group_wyckoff_section(lines: list[str], structure: object) -> N def _wyckoff_representative_coord(position: object) -> str: - """Return the representative (first) orbit coordinate of a position.""" + """ + Return the representative (first) orbit coordinate of a position. + """ coords = _attribute_value(position, 'coords_xyz') if not coords: return '?' From 7c901dfc43c402992c8268dbb332c4f4049a7928 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 14:58:34 +0200 Subject: [PATCH 43/55] Resolve ruff lint findings in Wyckoff Phase 1 code --- src/easydiffraction/analysis/fitting.py | 6 +- src/easydiffraction/core/validation.py | 16 ++- .../crystallography/crystallography.py | 120 ++++++++++-------- .../categories/atom_sites/default.py | 75 ++++++----- .../categories/space_group_wyckoff/default.py | 55 +++++--- 5 files changed, 167 insertions(+), 105 deletions(-) diff --git a/src/easydiffraction/analysis/fitting.py b/src/easydiffraction/analysis/fitting.py index a861ea25a..5b55f34df 100644 --- a/src/easydiffraction/analysis/fitting.py +++ b/src/easydiffraction/analysis/fitting.py @@ -378,9 +378,9 @@ def _residual_function( # Update categories to reflect new parameter values # Order matters: structures first (symmetry, structure), # then analysis (constraints), then experiments (calculations). - # Pass called_by_minimizer so the per-iteration Wyckoff snap runs - # silently (no re-detection or warnings); detection already ran at - # fit setup. + # Pass called_by_minimizer so the per-iteration Wyckoff snap + # runs silently (no re-detection or warnings); detection + # already ran at fit setup. for structure in structures: structure._update_categories(called_by_minimizer=True) diff --git a/src/easydiffraction/core/validation.py b/src/easydiffraction/core/validation.py index d2a0408fb..680edd82e 100644 --- a/src/easydiffraction/core/validation.py +++ b/src/easydiffraction/core/validation.py @@ -254,13 +254,13 @@ def validated( class PermissiveMembershipValidator(MembershipValidator): """ - Membership validator that accepts any value when no choices are allowed. + Membership validator accepting any value when choices are empty. - Used where the allowed set is derived dynamically and may legitimately - be empty (for example a Wyckoff letter under an untabulated space - group, or before a parent context is available): an empty allowed set - stores the value verbatim instead of rejecting it. A non-empty allowed - set validates membership as usual. + Used where the allowed set is derived dynamically and may + legitimately be empty (for example a Wyckoff letter under an + untabulated space group, or before a parent context is available): + an empty allowed set stores the value verbatim instead of rejecting + it. A non-empty allowed set validates membership as usual. """ def validated( @@ -270,7 +270,9 @@ def validated( default: object = None, current: object = None, ) -> object: - """Accept any value when allowed is empty; otherwise check membership.""" + """ + Accept any value when allowed is empty, else check membership. + """ allowed_values = self.allowed() if callable(self.allowed) else self.allowed if not allowed_values: return value diff --git a/src/easydiffraction/crystallography/crystallography.py b/src/easydiffraction/crystallography/crystallography.py index b4a76c855..e00aa03f5 100644 --- a/src/easydiffraction/crystallography/crystallography.py +++ b/src/easydiffraction/crystallography/crystallography.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: BSD-3-Clause import itertools +import operator from dataclasses import dataclass from fractions import Fraction from typing import Any @@ -18,14 +19,15 @@ from easydiffraction.crystallography.space_groups import SPACE_GROUPS from easydiffraction.utils.logging import log -# Maximum residual (in fractional units) for a coordinate to be considered -# on a Wyckoff orbit during detection. +# Maximum residual (in fractional units) for a coordinate to be +# considered on a Wyckoff orbit during detection. _WYCKOFF_DETECTION_TOL = 1e-3 @dataclass(frozen=True) class WyckoffPosition: - """A resolved Wyckoff position and the orbit representative matched. + """ + A resolved Wyckoff position and the orbit representative matched. Parameters ---------- @@ -37,8 +39,8 @@ class WyckoffPosition: International Tables site-symmetry symbol. coord_template : str | None Nearest matched orbit representative (e.g. ``'(x,-x,z)'``), or - ``None`` for a table lookup made without coordinates. This is what - coordinate snapping and constrained-axis flags consume. + ``None`` for a table lookup made without coordinates. This is + what coordinate snapping and constrained-axis flags consume. """ letter: str @@ -48,7 +50,8 @@ class WyckoffPosition: def _normalize_coord_code(coord_code: str | None) -> str | None: - """Normalize a coordinate-system code to the ``SPACE_GROUPS`` key form. + """ + Normalize a coordinate-system code to the ``SPACE_GROUPS`` key form. The empty string (used by consumers for groups with no coordinate code, e.g. triclinic P1/P-1) maps to ``None``, which is how those @@ -62,9 +65,10 @@ def _normalize_coord_code(coord_code: str | None) -> str | None: Returns ------- str | None - ``None`` for the empty string, otherwise ``coord_code`` unchanged. + ``None`` for the empty string, otherwise ``coord_code`` + unchanged. """ - if coord_code == '': + if not coord_code: return None return coord_code @@ -256,11 +260,11 @@ def _get_wyckoff_exprs( coord_code = _normalize_coord_code(coord_code) if (it_number, coord_code) not in SPACE_GROUPS: - # Space group / coordinate-system combination is absent from the - # local SPACE_GROUPS table. Treat as "no symmetry constraints to - # apply". Triclinic groups are keyed ``(it_number, None)`` and - # resolve normally through this lookup, so a ``None`` code is not - # treated as unset. + # Space group / coordinate-system combination is absent + # from the local SPACE_GROUPS table. Treat as "no symmetry + # constraints to apply". Triclinic groups are keyed + # ``(it_number, None)`` and resolve normally through this + # lookup, so a ``None`` code is not treated as unset. return None entry = SPACE_GROUPS[it_number, coord_code] @@ -482,11 +486,12 @@ def _get_general_position_ops( def _orbit_template_residual(point: np.ndarray, rot: np.ndarray, trans: np.ndarray) -> float: - """Return the mod-1 distance from ``point`` to an orbit template. + """ + Return the mod-1 distance from ``point`` to an orbit template. - The template manifold is ``{rot·v + trans}``; the point lies on it for - some free ``v`` when the residual is ~0. Integer lattice shifts account - for unit-cell periodicity. + The template manifold is ``{rot·v + trans}``; the point lies on it + for some free ``v`` when the residual is ~0. Integer lattice shifts + account for unit-cell periodicity. Parameters ---------- @@ -514,11 +519,13 @@ def _orbit_template_residual(point: np.ndarray, rot: np.ndarray, trans: np.ndarr def _nearest_orbit_template(point: np.ndarray, coords_xyz: list[str]) -> tuple[str, float]: - """Return the orbit template nearest to ``point`` and its residual. + """ + Return the orbit template nearest to ``point`` and its residual. On near-ties (e.g. centering copies that share a manifold mod 1) the - earlier, canonical representative is kept for deterministic output; the - free-parameter-solving snap downstream is correct for any of them. + earlier, canonical representative is kept for deterministic output; + the free-parameter-solving snap downstream is correct for any of + them. """ best_template = coords_xyz[0] best_residual = np.inf @@ -535,12 +542,12 @@ def _wyckoff_template_constrained_flags(rot: np.ndarray) -> dict[str, bool]: """ Return per-axis symmetry-constraint flags for a parsed template. - An axis is **free** when its coordinate is the first (in x, y, z order) - to introduce a free parameter, and **constrained** otherwise (a - constant, or a coordinate slaved to an earlier axis's parameter). This - is slot-based, so it is correct for off-canonical representatives such - as ``(0,x,0)`` (``fract_x`` constrained, ``fract_y`` free) where the - symbol-presence test would be wrong. + An axis is **free** when its coordinate is the first (in x, y, z + order) to introduce a free parameter, and **constrained** otherwise + (a constant, or a coordinate slaved to an earlier axis's parameter). + This is slot-based, so it is correct for off-canonical + representatives such as ``(0,x,0)`` (``fract_x`` constrained, + ``fract_y`` free) where the symbol-presence test would be wrong. Parameters ---------- @@ -550,8 +557,8 @@ def _wyckoff_template_constrained_flags(rot: np.ndarray) -> dict[str, bool]: Returns ------- dict[str, bool] - Mapping ``'fract_x'/'fract_y'/'fract_z'`` to ``True`` if the axis - is fully fixed by site symmetry. + Mapping ``'fract_x'/'fract_y'/'fract_z'`` to ``True`` if the + axis is fully fixed by site symmetry. """ claimed: set[int] = set() flags: dict[str, bool] = {} @@ -572,26 +579,27 @@ def snap_to_wyckoff_template( """ Project a coordinate onto a Wyckoff orbit-representative manifold. - Solves the free Wyckoff parameters from the **free (refinable) axes** - only — keeping those axes' values, so a minimizer's refined free - coordinate is preserved — then derives the constrained axes from the - template. Replaces per-axis symbol substitution: it handles coupled - axes (e.g. ``(x,-x,z)``: keep ``fract_x``, set ``fract_y=-fract_x``) - and off-canonical representatives (e.g. ``(0,x,0)``: keep ``fract_y``, - set ``fract_x=fract_z=0``). + Solves the free Wyckoff parameters from the **free (refinable) + axes** only — keeping those axes' values, so a minimizer's refined + free coordinate is preserved — then derives the constrained axes + from the template. Replaces per-axis symbol substitution: it handles + coupled axes (e.g. ``(x,-x,z)``: keep ``fract_x``, set + ``fract_y=-fract_x``) and off-canonical representatives (e.g. + ``(0,x,0)``: keep ``fract_y``, set ``fract_x=fract_z=0``). Parameters ---------- coord_template : str - Selected orbit representative, e.g. ``'(x,-x,z)'`` or ``'(0,x,0)'``. + Selected orbit representative, e.g. ``'(x,-x,z)'`` or + ``'(0,x,0)'``. fract_xyz : tuple[float, float, float] Current fractional coordinate. Returns ------- tuple[tuple[float, float, float], dict[str, bool]] - The snapped ``(x, y, z)`` (free axes kept, constrained axes derived; - not reduced mod 1), and the per-axis constraint flags. + The snapped ``(x, y, z)`` (free axes kept, constrained axes + derived; not reduced mod 1), and the per-axis constraint flags. """ rot, trans = _parse_rotation_matrix(coord_template) rot_float = rot.astype(float) @@ -625,10 +633,11 @@ def detect_wyckoff_position( Detect the Wyckoff position a fractional coordinate occupies. Tests the coordinate for membership in every Wyckoff orbit of the - resolved space group and returns the matched position with its nearest - representative template. The winner is chosen by multiplicity - ascending, then residual ascending (the most special site first); a - rare same-multiplicity tie within ``tol`` is reported with a warning. + resolved space group and returns the matched position with its + nearest representative template. The winner is chosen by + multiplicity ascending, then residual ascending (the most special + site first); a rare same-multiplicity tie within ``tol`` is reported + with a warning. Parameters ---------- @@ -638,7 +647,7 @@ def detect_wyckoff_position( Coordinate-system code. fract_xyz : tuple[float, float, float] Fractional coordinate to classify. - tol : float, default _WYCKOFF_DETECTION_TOL + tol : float, default=_WYCKOFF_DETECTION_TOL Maximum residual for orbit membership. Returns @@ -660,18 +669,25 @@ def detect_wyckoff_position( template, residual = _nearest_orbit_template(point, position['coords_xyz']) if residual <= tol: matches.append( - (int(position['multiplicity']), residual, letter, position['site_symmetry'], template), + ( + int(position['multiplicity']), + residual, + letter, + position['site_symmetry'], + template, + ), ) if not matches: return None - matches.sort(key=lambda match: (match[0], match[1])) + matches.sort(key=operator.itemgetter(0, 1)) multiplicity, _residual, letter, site_symmetry, template = matches[0] ties = [match for match in matches[1:] if match[0] == multiplicity] if ties: others = ', '.join(repr(match[2]) for match in ties) log.warning( - f"Wyckoff detection tie for {name_hm!r}: chose {letter!r} over {others} (same multiplicity)", + f'Wyckoff detection tie for {name_hm!r}: chose {letter!r} ' + f'over {others} (same multiplicity)', ) return WyckoffPosition(letter, multiplicity, site_symmetry, template) @@ -683,7 +699,7 @@ def wyckoff_position_info( fract_xyz: tuple[float, float, float] | None = None, ) -> WyckoffPosition | None: """ - Look up a known Wyckoff letter, optionally selecting a representative. + Look up a Wyckoff letter and optionally its representative. Parameters ---------- @@ -693,7 +709,7 @@ def wyckoff_position_info( Coordinate-system code. letter : str Wyckoff letter to look up. - fract_xyz : tuple[float, float, float] | None, default None + fract_xyz : tuple[float, float, float] | None, default=None When given, the nearest orbit representative for ``letter`` is selected as ``coord_template``; otherwise ``coord_template`` is ``None``. @@ -718,7 +734,9 @@ def wyckoff_position_info( if fract_xyz is not None: point = np.asarray(fract_xyz, dtype=float) % 1.0 template, _residual = _nearest_orbit_template(point, position['coords_xyz']) - return WyckoffPosition(letter, int(position['multiplicity']), position['site_symmetry'], template) + return WyckoffPosition( + letter, int(position['multiplicity']), position['site_symmetry'], template + ) def space_group_wyckoff_table(name_hm: str, coord_code: str | None) -> dict[str, dict] | None: @@ -736,8 +754,8 @@ def space_group_wyckoff_table(name_hm: str, coord_code: str | None) -> dict[str, ------- dict[str, dict] | None Mapping of Wyckoff letter to its ``multiplicity``, - ``site_symmetry``, and ``coords_xyz`` record, or ``None`` when the - space group is absent from ``SPACE_GROUPS``. + ``site_symmetry``, and ``coords_xyz`` record, or ``None`` when + the space group is absent from ``SPACE_GROUPS``. """ it_number = get_it_number_by_name_hm_short(name_hm) if it_number is None: diff --git a/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py b/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py index 7f3d81f63..7db19694c 100644 --- a/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py +++ b/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py @@ -51,8 +51,8 @@ def __init__(self) -> None: # (e.g. create() before the atom is added); the update flow then # validates it once the parent structure is available. self._wyckoff_letter_needs_validation = False - # Wyckoff-detection baselines (None until first detection); compared - # in the update flow to decide whether to re-detect. + # Wyckoff-detection baselines (None until first detection); + # compared in the update flow to decide whether to re-detect. self._wyckoff_coord_baseline: tuple[float, float, float] | None = None self._wyckoff_key_baseline: tuple[str, str | None] | None = None @@ -239,8 +239,8 @@ def _wyckoff_letter_allowed_values(self) -> list[str]: Returns ------- list[str] - ``['', *letters]`` for a tabulated space group (empty first, so - an unset letter is valid); ``[]`` when there is no parent + ``['', *letters]`` for a tabulated space group (empty first, + so an unset letter is valid); ``[]`` when there is no parent context or the space group is untabulated. """ space_group = self._resolve_structure_space_group() @@ -508,11 +508,11 @@ def multiplicity(self) -> IntegerDescriptor: def _set_wyckoff_letter_detected(self, letter: str) -> None: """ - Set the auto-detected Wyckoff letter, bypassing membership validation. + Set the auto-detected Wyckoff letter, bypassing validation. Modelled on ``_set_value_from_minimizer``: detection supplies a - trusted letter, written directly rather than re-validated against - the (dynamic) allowed-letters set. + trusted letter, written directly rather than re-validated + against the (dynamic) allowed-letters set. """ self._wyckoff_letter._set_value_from_minimizer(letter) @@ -622,9 +622,11 @@ def __init__(self) -> None: # Private helper methods # ------------------------------------------------------------------ - def _apply_atomic_coordinates_symmetry_constraints(self, *, called_by_minimizer: bool = False) -> None: + def _apply_atomic_coordinates_symmetry_constraints( + self, *, called_by_minimizer: bool = False + ) -> None: """ - Detect Wyckoff letters and snap fractional coordinates to symmetry. + Detect Wyckoff letters and snap coordinates to symmetry. For each atom: resolve any pending no-context Wyckoff letter; (re)detect the letter when it is empty or the coordinates / @@ -637,8 +639,8 @@ def _apply_atomic_coordinates_symmetry_constraints(self, *, called_by_minimizer: Parameters ---------- called_by_minimizer : bool, default=False - When True (per fit iteration), skip re-detection and warnings; - only the silent coordinate snap runs. + When True (per fit iteration), skip re-detection and + warnings; only the silent coordinate snap runs. """ structure = self._parent name_hm = structure.space_group.name_h_m.value @@ -648,13 +650,19 @@ def _apply_atomic_coordinates_symmetry_constraints(self, *, called_by_minimizer: if atom._wyckoff_letter_needs_validation: self._resolve_pending_wyckoff_letter(atom, name_hm) if supported: - self._detect_and_snap_atom(atom, name_hm, coord_code, called_by_minimizer=called_by_minimizer) + self._detect_and_snap_atom( + atom, name_hm, coord_code, called_by_minimizer=called_by_minimizer + ) else: - self._mark_atom_untabulated(atom, (name_hm, coord_code), called_by_minimizer=called_by_minimizer) + self._mark_atom_untabulated( + atom, (name_hm, coord_code), called_by_minimizer=called_by_minimizer + ) @staticmethod def _resolve_pending_wyckoff_letter(atom: AtomSite, name_hm: str) -> None: - """Validate a deferred no-context Wyckoff letter; raise if invalid.""" + """ + Validate a deferred no-context Wyckoff letter; raise if invalid. + """ stored = atom.wyckoff_letter.value allowed = atom._wyckoff_letter_allowed_values if allowed and stored not in allowed: @@ -691,20 +699,23 @@ def _detect_and_snap_atom( *, called_by_minimizer: bool, ) -> None: - """Detect (if triggered) and snap one atom to its Wyckoff position.""" + """ + Detect (if triggered) and snap one atom to its Wyckoff position. + """ key = (name_hm, coord_code) letter_before = atom.wyckoff_letter.value coords = (atom.fract_x.value, atom.fract_y.value, atom.fract_z.value) - # A ``None`` baseline marks the first population (create/load), not a - # later edit. Treat coordinates or the space-group key as "changed" - # only against an existing baseline, so an explicit initial letter is - # preserved (routed to ``wyckoff_position_info`` below) instead of - # being overwritten by all-letter detection. The ADR requires a - # user-supplied letter to persist until a genuine later coordinate or - # space-group-key edit. + # A ``None`` baseline marks the first population + # (create/load), not a later edit. Treat coordinates or the + # space-group key as "changed" only against an existing + # baseline, so an explicit initial letter is preserved (routed + # to ``wyckoff_position_info`` below) instead of being + # overwritten by all-letter detection. The ADR requires a + # user-supplied letter to persist until a genuine later + # coordinate or space-group-key edit. coords_changed = atom._wyckoff_coord_baseline is not None and any( abs(a - b) > ecr._WYCKOFF_DETECTION_TOL - for a, b in zip(coords, atom._wyckoff_coord_baseline) + for a, b in zip(coords, atom._wyckoff_coord_baseline, strict=True) ) key_changed = atom._wyckoff_key_baseline is not None and atom._wyckoff_key_baseline != key detect = (not called_by_minimizer) and (not letter_before or coords_changed or key_changed) @@ -718,7 +729,9 @@ def _detect_and_snap_atom( if position is not None: atom._set_wyckoff_letter_detected(position.letter) elif letter_before: - position = ecr.wyckoff_position_info(name_hm, coord_code, letter_before, fract_xyz=coords) + position = ecr.wyckoff_position_info( + name_hm, coord_code, letter_before, fract_xyz=coords + ) else: position = None @@ -737,7 +750,9 @@ def _detect_and_snap_atom( atom._fract_x._set_symmetry_constrained(value=flags['fract_x']) atom._fract_y._set_symmetry_constrained(value=flags['fract_y']) atom._fract_z._set_symmetry_constrained(value=flags['fract_z']) - moved = any(abs(s - c) > ecr._WYCKOFF_DETECTION_TOL for s, c in zip(snapped, coords)) + moved = any( + abs(s - c) > ecr._WYCKOFF_DETECTION_TOL for s, c in zip(snapped, coords, strict=True) + ) if moved and not called_by_minimizer: if not detect: log.warning( @@ -840,10 +855,12 @@ def _update( Parameters ---------- called_by_minimizer : bool, default=False - Whether the update was triggered by the fitting minimizer. When - True, Wyckoff re-detection and warnings are skipped; only the - silent coordinate snap runs. + Whether the update was triggered by the fitting minimizer. + When True, Wyckoff re-detection and warnings are skipped; + only the silent coordinate snap runs. """ - self._apply_atomic_coordinates_symmetry_constraints(called_by_minimizer=called_by_minimizer) + self._apply_atomic_coordinates_symmetry_constraints( + called_by_minimizer=called_by_minimizer + ) self._apply_adp_symmetry_constraints() self._sync_iso_from_aniso() diff --git a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py index 1a3cfac79..3c6256567 100644 --- a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py +++ b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py @@ -7,11 +7,14 @@ :class:`SpaceGroupWyckoffCollection`. Rows are derived from the bundled space-group table for the structure's current space group; they are not user-edited. ``Structure`` rebuilds the collection when the space group -changes via :meth:`SpaceGroupWyckoffCollection._replace_from_space_group`. +changes via +:meth:`SpaceGroupWyckoffCollection._replace_from_space_group`. """ from __future__ import annotations +from typing import override + from easydiffraction.core.category import CategoryCollection from easydiffraction.core.category import CategoryItem from easydiffraction.core.display_handler import DisplayHandler @@ -32,7 +35,9 @@ class SpaceGroupWyckoff(CategoryItem): - """A single Wyckoff position of the space group (all fields read-only).""" + """ + A single Wyckoff position of the space group (all fields read-only). + """ _category_code = 'space_group_Wyckoff' _category_entry_name = 'id' @@ -65,7 +70,9 @@ def __init__(self) -> None: self._site_symmetry = StringDescriptor( name='site_symmetry', description='Site-symmetry symbol of the Wyckoff position.', - display_handler=DisplayHandler(display_name='Site symmetry', latex_name='Site symmetry'), + display_handler=DisplayHandler( + display_name='Site symmetry', latex_name='Site symmetry' + ), value_spec=AttributeSpec(default=''), cif_handler=CifHandler(names=['_space_group_Wyckoff.site_symmetry']), ) @@ -105,7 +112,9 @@ def coords_xyz(self) -> StringDescriptor: @SpaceGroupWyckoffFactory.register class SpaceGroupWyckoffCollection(CategoryCollection): - """Read-only collection of Wyckoff positions, derived from the space group.""" + """ + Read-only collection of derived Wyckoff positions. + """ type_info = TypeInfo( tag='default', @@ -116,41 +125,57 @@ def __init__(self) -> None: """Initialise an empty derived Wyckoff collection.""" super().__init__(item_type=SpaceGroupWyckoff) + @override def add(self, item: object) -> None: - """Reject public mutation; the collection is derived (read-only).""" + """ + Reject public mutation; the collection is derived (read-only). + """ raise ValueError(_READ_ONLY_MESSAGE) + @override def create(self, **kwargs: object) -> None: - """Reject public mutation; the collection is derived (read-only).""" + """ + Reject public mutation; the collection is derived (read-only). + """ raise ValueError(_READ_ONLY_MESSAGE) + @override def remove(self, name: str) -> None: - """Reject public mutation; the collection is derived (read-only).""" + """ + Reject public mutation; the collection is derived (read-only). + """ raise ValueError(_READ_ONLY_MESSAGE) + @override def __setitem__(self, name: str, item: object) -> None: - """Reject item assignment; the collection is derived (read-only).""" + """ + Reject item assignment; the collection is derived (read-only). + """ raise ValueError(_READ_ONLY_MESSAGE) + @override def __delitem__(self, name: str) -> None: - """Reject item deletion; the collection is derived (read-only).""" + """ + Reject item deletion; the collection is derived (read-only). + """ raise ValueError(_READ_ONLY_MESSAGE) + @override def from_cif(self, block: object) -> None: """ Ignore incoming CIF values for this derived category. - The Wyckoff table is derived from the structure's space group and - is never read back from a CIF file: any ``_space_group_Wyckoff.*`` - loop in incoming CIF (for example a hand-edited project file) is - discarded and the table is rebuilt from the space group on the - next update. + The Wyckoff table is derived from the structure's space group + and is never read back from a CIF file: any + ``_space_group_Wyckoff.*`` loop in incoming CIF (for example a + hand-edited project file) is discarded and the table is rebuilt + from the space group on the next update. """ return def _replace_from_space_group(self) -> None: """ - Rebuild the rows from the parent structure's current space group. + Rebuild rows from the parent structure's space group. Repopulates from the bundled Wyckoff table and adopts the new rows via ``_adopt_items``, which rebuilds the name index and From b170d0d0be1f0304618cd546455b7329278c04e2 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 15:05:09 +0200 Subject: [PATCH 44/55] Update tests for Wyckoff detection behavior changes --- .../analysis/calculators/test_cryspy.py | 5 +++++ .../crystallography/test_crystallography_wyckoff.py | 10 ++++++---- .../structure/categories/test_atom_sites.py | 12 +++++++++--- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/tests/unit/easydiffraction/analysis/calculators/test_cryspy.py b/tests/unit/easydiffraction/analysis/calculators/test_cryspy.py index 6cebe4c33..c2a268c95 100644 --- a/tests/unit/easydiffraction/analysis/calculators/test_cryspy.py +++ b/tests/unit/easydiffraction/analysis/calculators/test_cryspy.py @@ -101,6 +101,11 @@ def test_update_structure_restores_wyckoff_multiplicity_after_coordinate_wrappin wyckoff_letter='h', adp_iso=0.5, ) + # The calculator reads the per-site multiplicity from the model, so + # run the update flow to populate it via Wyckoff detection (R-3m 'h' + # has multiplicity 18). + structure._update_categories() + assert structure.atom_sites['O'].multiplicity.value == 18 cryspy_model_dict = { 'unit_cell_parameters': [6.86, 6.86, 14.14, np.pi / 2, np.pi / 2, 2 * np.pi / 3], diff --git a/tests/unit/easydiffraction/crystallography/test_crystallography_wyckoff.py b/tests/unit/easydiffraction/crystallography/test_crystallography_wyckoff.py index c01661492..bd71e490d 100644 --- a/tests/unit/easydiffraction/crystallography/test_crystallography_wyckoff.py +++ b/tests/unit/easydiffraction/crystallography/test_crystallography_wyckoff.py @@ -14,13 +14,15 @@ def test_invalid_name_hm_returns_none(self, monkeypatch): assert result is None monkeypatch.setattr(Logger, '_reaction', Logger.Reaction.RAISE, raising=True) - def test_none_coord_code_returns_none(self, monkeypatch): + def test_none_coord_code_resolves_triclinic(self): from easydiffraction.crystallography.crystallography import _get_wyckoff_exprs - monkeypatch.setattr(Logger, '_reaction', Logger.Reaction.WARN, raising=True) + # Triclinic groups are keyed ``(IT_number, None)``: P 1 (IT 1) + # resolves through the ``None`` coordinate code to its general + # position (x, y, z) rather than being treated as unset. result = _get_wyckoff_exprs('P 1', None, 'a') - assert result is None - monkeypatch.setattr(Logger, '_reaction', Logger.Reaction.RAISE, raising=True) + assert result is not None + assert len(result) == 3 def test_valid_returns_three_expressions(self): from easydiffraction.crystallography.crystallography import _get_wyckoff_exprs diff --git a/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py b/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py index 17d0dd5f5..aa424606e 100644 --- a/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py +++ b/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py @@ -112,10 +112,16 @@ def test_type_symbol_allowed_values(self): assert 'Fe' in allowed def test_wyckoff_letter_allowed_values(self): - from easydiffraction.datablocks.structure.categories.atom_sites.default import AtomSite + from easydiffraction.datablocks.structure.item.base import Structure - site = AtomSite() - allowed = site._wyckoff_letter_allowed_values + # Allowed letters are derived from the parent structure's space + # group, so the atom must live inside a structure with a + # tabulated space group; a parentless AtomSite has no allowed + # letters. + structure = Structure(name='s') + structure.space_group.name_h_m = 'P m -3 m' + structure.atom_sites.create(label='X', type_symbol='O', adp_iso=0.5) + allowed = structure.atom_sites['X']._wyckoff_letter_allowed_values assert 'a' in allowed def test_uses_iucr_casing_with_legacy_aliases(self): From 7265ece69aca376852d3a9d48ff7a23f91b75cfc Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 15:06:31 +0200 Subject: [PATCH 45/55] Add tests for derived space_group_wyckoff category --- .../categories/test_space_group_wyckoff.py | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 tests/unit/easydiffraction/datablocks/structure/categories/test_space_group_wyckoff.py diff --git a/tests/unit/easydiffraction/datablocks/structure/categories/test_space_group_wyckoff.py b/tests/unit/easydiffraction/datablocks/structure/categories/test_space_group_wyckoff.py new file mode 100644 index 000000000..3f8d0e638 --- /dev/null +++ b/tests/unit/easydiffraction/datablocks/structure/categories/test_space_group_wyckoff.py @@ -0,0 +1,136 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Tests for the derived space_group_wyckoff category (default + factory).""" + +import pytest + +from easydiffraction.crystallography import crystallography as ecr +from easydiffraction.datablocks.structure.item.base import Structure + + +def _cubic_structure(): + """Return a structure on the tabulated cubic group P m -3 m.""" + structure = Structure(name='s') + structure.space_group.name_h_m = 'P m -3 m' + structure._update_categories() + return structure + + +class TestSpaceGroupWyckoffFactory: + def test_supported_tags(self): + from easydiffraction.datablocks.structure.categories.space_group_wyckoff.factory import ( + SpaceGroupWyckoffFactory, + ) + + assert 'default' in SpaceGroupWyckoffFactory.supported_tags() + + def test_create_default(self): + from easydiffraction.datablocks.structure.categories.space_group_wyckoff.default import ( + SpaceGroupWyckoffCollection, + ) + from easydiffraction.datablocks.structure.categories.space_group_wyckoff.factory import ( + SpaceGroupWyckoffFactory, + ) + + obj = SpaceGroupWyckoffFactory.create('default') + assert isinstance(obj, SpaceGroupWyckoffCollection) + + +class TestDerivedRows: + def test_auto_populates_from_space_group(self): + structure = _cubic_structure() + table = ecr.space_group_wyckoff_table('P m -3 m', '1') + assert len(structure.space_group_wyckoff) == len(table) + for row in structure.space_group_wyckoff: + entry = table[row.letter.value] + assert row.multiplicity.value == entry['multiplicity'] + assert row.site_symmetry.value == str(entry['site_symmetry']) + + def test_uses_id_keys_of_multiplicity_plus_letter(self): + structure = _cubic_structure() + row = structure.space_group_wyckoff['1a'] + assert row.id.value == '1a' + assert row.letter.value == 'a' + assert row.multiplicity.value == 1 + + def test_preserves_site_symmetry_verbatim(self): + # Site-symmetry strings (including any dots) are stored exactly + # as the bundled table provides them, not normalised. + structure = _cubic_structure() + table = ecr.space_group_wyckoff_table('P m -3 m', '1') + for row in structure.space_group_wyckoff: + assert row.site_symmetry.value == str(table[row.letter.value]['site_symmetry']) + + def test_rebuilds_on_space_group_change(self): + structure = _cubic_structure() + assert '1a' in {r.id.value for r in structure.space_group_wyckoff} + structure.space_group.name_h_m = 'F m -3 m' + structure._update_categories() + ids = {r.id.value for r in structure.space_group_wyckoff} + # Fm-3m has no multiplicity-1 'a'; the stale Pm-3m key is gone. + assert '1a' not in ids + assert '4a' in ids + with pytest.raises(KeyError): + _ = structure.space_group_wyckoff['1a'] + + def test_empty_for_absent_group(self, monkeypatch): + structure = _cubic_structure() + assert len(structure.space_group_wyckoff) > 0 + monkeypatch.setattr(ecr, 'space_group_wyckoff_table', lambda *a, **k: None) + structure.space_group_wyckoff._replace_from_space_group() + assert len(structure.space_group_wyckoff) == 0 + + +class TestReadOnly: + def test_rejects_all_public_mutation(self): + structure = _cubic_structure() + wy = structure.space_group_wyckoff + row = wy['1a'] + with pytest.raises(ValueError): + wy.add(row) + with pytest.raises(ValueError): + wy.create() + with pytest.raises(ValueError): + wy.remove('1a') + with pytest.raises(ValueError): + wy['1a'] = row + with pytest.raises(ValueError): + del wy['1a'] + + def test_from_cif_ignores_incoming_loop(self): + # A hand-edited _space_group_Wyckoff loop must be discarded; the + # table is derived from the space group, not read from CIF. + from easydiffraction.datablocks.structure.item.factory import StructureFactory + + cif = ( + "data_x\n" + "_space_group.name_H-M_alt 'P m -3 m'\n" + '_space_group.IT_coordinate_system_code 1\n' + 'loop_\n' + '_space_group_Wyckoff.id\n' + '_space_group_Wyckoff.letter\n' + '_space_group_Wyckoff.multiplicity\n' + '_space_group_Wyckoff.site_symmetry\n' + '_space_group_Wyckoff.coords_xyz\n' + ' BOGUS bogus 999 zzz (9,9,9)\n' + ) + structure = StructureFactory.from_cif_str(cif) + assert all(r.id.value != 'BOGUS' for r in structure.space_group_wyckoff) + + +class TestSerialization: + def test_omitted_from_project_cif(self): + structure = _cubic_structure() + assert '_space_group_Wyckoff' not in structure.as_cif + + def test_appears_in_report_output(self): + from easydiffraction.io.cif import iucr_writer + + structure = _cubic_structure() + lines: list[str] = [] + iucr_writer._write_space_group_wyckoff_section(lines, structure) + body = '\n'.join(lines) + assert '_space_group_Wyckoff.id' in body + assert '_space_group_Wyckoff.coords_xyz' in body + # Representative coordinate only (compact), never the full orbit. + assert max(len(line) for line in lines) < 80 From daded8002039b44fabdeb6cdbbdfd26af571d513 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 15:07:59 +0200 Subject: [PATCH 46/55] Add detection and lookup tests for Wyckoff crystallography --- .../test_crystallography_wyckoff.py | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/tests/unit/easydiffraction/crystallography/test_crystallography_wyckoff.py b/tests/unit/easydiffraction/crystallography/test_crystallography_wyckoff.py index bd71e490d..386b4cb55 100644 --- a/tests/unit/easydiffraction/crystallography/test_crystallography_wyckoff.py +++ b/tests/unit/easydiffraction/crystallography/test_crystallography_wyckoff.py @@ -111,3 +111,91 @@ def test_invalid_returns_all_false(self, monkeypatch): flags = atom_site_symmetry_constrained_flags('NOT REAL', None, 'a') assert flags == {'fract_x': False, 'fract_y': False, 'fract_z': False} monkeypatch.setattr(Logger, '_reaction', Logger.Reaction.RAISE, raising=True) + + +class TestDetectWyckoffPosition: + def test_general_position(self): + from easydiffraction.crystallography.crystallography import detect_wyckoff_position + + # A generic point in P m -3 m is the general position 'n' (48). + position = detect_wyckoff_position('P m -3 m', '1', (0.12, 0.23, 0.34)) + assert position.letter == 'n' + assert position.multiplicity == 48 + + def test_special_position(self): + from easydiffraction.crystallography.crystallography import detect_wyckoff_position + + position = detect_wyckoff_position('P m -3 m', '1', (0.0, 0.0, 0.0)) + assert position.letter == 'a' + assert position.multiplicity == 1 + + def test_multiplicity_tie_break_prefers_most_special(self): + from easydiffraction.crystallography.crystallography import detect_wyckoff_position + + # (1/2,0,0) lies on both 'e' = (x,0,0) (mult 6) and the more + # special 'd' = (1/2,0,0) (mult 3); detection prefers 'd'. + position = detect_wyckoff_position('P m -3 m', '1', (0.5, 0.0, 0.0)) + assert position.letter == 'd' + assert position.multiplicity == 3 + + def test_non_first_orbit_representative(self): + from easydiffraction.crystallography.crystallography import detect_wyckoff_position + + # (0,y,0) is on the 'e' orbit via a non-first representative + # ((0,x,0), not the tabulated first rep (x,0,0)). + position = detect_wyckoff_position('P m -3 m', '1', (0.0, 0.3, 0.0)) + assert position.letter == 'e' + + def test_rounded_input_matches_within_tolerance(self): + from easydiffraction.crystallography.crystallography import detect_wyckoff_position + + # x = 0.3333 ~ 1/3 is still on 'e' = (x,0,0) at the 1e-3 tolerance. + position = detect_wyckoff_position('P m -3 m', '1', (0.3333, 0.0, 0.0)) + assert position.letter == 'e' + + def test_empty_coord_code_normalises_to_none(self): + from easydiffraction.crystallography.crystallography import detect_wyckoff_position + + # P 1 is keyed (1, None); an empty coordinate code resolves there. + position = detect_wyckoff_position('P 1', '', (0.1, 0.2, 0.3)) + assert position is not None + assert position.letter == 'a' + + def test_absent_group_returns_none(self, monkeypatch): + from easydiffraction.crystallography.crystallography import detect_wyckoff_position + + monkeypatch.setattr(Logger, '_reaction', Logger.Reaction.WARN, raising=True) + assert detect_wyckoff_position('NOT A REAL SG', None, (0.1, 0.2, 0.3)) is None + monkeypatch.setattr(Logger, '_reaction', Logger.Reaction.RAISE, raising=True) + + +class TestWyckoffPositionInfo: + def test_without_coords_has_no_template(self): + from easydiffraction.crystallography.crystallography import wyckoff_position_info + + position = wyckoff_position_info('P m -3 m', '1', 'e') + assert position.letter == 'e' + assert position.multiplicity == 6 + assert position.coord_template is None + + def test_selects_nearest_representative_not_first(self): + from easydiffraction.crystallography.crystallography import ( + snap_to_wyckoff_template, + wyckoff_position_info, + ) + + # 'e' first rep is (x,0,0); for a point near the (0,x,0) member the + # nearest representative must be chosen so the snap keeps fract_y + # free near 0.3 instead of collapsing onto (x,0,0) -> (0,0,0). + position = wyckoff_position_info('P m -3 m', '1', 'e', fract_xyz=(0.0, 0.3, 0.0)) + assert position.coord_template is not None + snapped, _flags = snap_to_wyckoff_template(position.coord_template, (0.0, 0.3, 0.0)) + assert abs(snapped[0]) < 1e-6 + assert abs(snapped[1] - 0.3) < 1e-6 + assert abs(snapped[2]) < 1e-6 + + def test_absent_letter_returns_none(self): + from easydiffraction.crystallography.crystallography import wyckoff_position_info + + # P m -3 m has no Wyckoff letter 'z'. + assert wyckoff_position_info('P m -3 m', '1', 'z') is None From e59fb8f788eef70a2146c6f7327ccb0c84961fde Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 15:12:00 +0200 Subject: [PATCH 47/55] Assert canonical Wyckoff representative templates in data --- .../crystallography/test_space_groups.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/unit/easydiffraction/crystallography/test_space_groups.py b/tests/unit/easydiffraction/crystallography/test_space_groups.py index 0ecb1656a..4d085a8b1 100644 --- a/tests/unit/easydiffraction/crystallography/test_space_groups.py +++ b/tests/unit/easydiffraction/crystallography/test_space_groups.py @@ -95,3 +95,35 @@ def test_coords_xyz_are_canonical_distinct_full_orbits(): assert not _NONCANONICAL_COORD.search(template), (key, letter, template) assert len(set(coords)) == len(coords), (key, letter) assert len(coords) == position['multiplicity'], (key, letter) + + +def test_representative_template_has_no_self_axis_coupling(): + """Every Wyckoff representative is in canonical parametric form. + + For the representative ``coords_xyz[0]``, no component may couple its + own axis variable with another axis (e.g. an x-slot term ``x+y``): + that is operator-form leakage, the ed-6 regression that the + canonical-templates fix removed. The slot-based constraint logic in + crystallography.py relies on this canonical form, so it is asserted + from the data side to block a silent reintroduction on a future + table regeneration. Non-first orbit members are genuine symmetry + images and may legitimately couple, so only the representative is + checked. + """ + from easydiffraction.crystallography.crystallography import _parse_rotation_matrix + + for key, record in SPACE_GROUPS.items(): + for letter, position in record['Wyckoff_positions'].items(): + representative = position['coords_xyz'][0] + rot, _trans = _parse_rotation_matrix(representative) + for axis_index in range(3): + references_own_axis = rot[axis_index, axis_index] != 0 + couples_other_axis = any( + rot[axis_index, other] != 0 for other in range(3) if other != axis_index + ) + assert not (references_own_axis and couples_other_axis), ( + key, + letter, + representative, + axis_index, + ) From bd83195714c1604f0805e4e617db60e6bc14331b Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 15:20:12 +0200 Subject: [PATCH 48/55] Add atom-site Wyckoff detection behavior tests --- .../structure/categories/test_atom_sites.py | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py b/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py index aa424606e..9c7a7e213 100644 --- a/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py +++ b/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py @@ -268,3 +268,152 @@ def test_uani_as_b_converts(self): structure.atom_sites['Si'].adp_type = 'Uani' expected_b = u_val * 8.0 * math.pi**2 assert math.isclose(structure.atom_sites['Si'].adp_iso_as_b, expected_b, rel_tol=1e-10) + + +# ------------------------------------------------------------------ +# Wyckoff letter detection / multiplicity +# ------------------------------------------------------------------ + + +class TestAtomSiteWyckoffDetection: + @staticmethod + def _structure(name_hm='P m -3 m'): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='s') + structure.space_group.name_h_m = name_hm + return structure + + def test_fill_if_empty_on_update(self): + structure = self._structure() + structure.atom_sites.create(label='A', type_symbol='O', adp_iso=0.5) + structure._update_categories() + atom = structure.atom_sites['A'] + assert atom.wyckoff_letter.value == 'a' + assert atom.multiplicity.value == 1 + + def test_redetect_via_property_setter(self): + structure = self._structure() + structure.atom_sites.create(label='A', type_symbol='O', adp_iso=0.5) + structure._update_categories() + structure.atom_sites['A'].fract_x = 0.3 + structure._update_categories() + assert structure.atom_sites['A'].wyckoff_letter.value == 'e' + + def test_redetect_via_descriptor_value(self): + structure = self._structure() + structure.atom_sites.create(label='A', type_symbol='O', adp_iso=0.5) + structure._update_categories() + structure.atom_sites['A'].fract_x.value = 0.3 + structure._update_categories() + assert structure.atom_sites['A'].wyckoff_letter.value == 'e' + + def test_explicit_letter_preserved_on_first_update(self): + # (0.5,0,0) lies on both 'e' = (x,0,0) and the more special + # 'd' = (1/2,0,0); an explicit 'e' must be kept, not detected 'd'. + structure = self._structure() + structure.atom_sites.create( + label='E', + type_symbol='O', + fract_x=0.5, + fract_y=0.0, + fract_z=0.0, + adp_iso=0.5, + wyckoff_letter='e', + ) + structure._update_categories() + atom = structure.atom_sites['E'] + assert atom.wyckoff_letter.value == 'e' + assert atom.multiplicity.value == 6 + + def test_invalid_explicit_letter_raises_on_update(self): + import pytest + + structure = self._structure() + structure.atom_sites.create(label='Z', type_symbol='O', adp_iso=0.5, wyckoff_letter='z') + with pytest.raises(ValueError): + structure._update_categories() + + def test_same_letter_edit_snaps_off_orbit_coordinate(self): + # 'e' = (x,0,0): a small off-orbit nudge in fract_y (within the + # detection tolerance) keeps the letter 'e' and snaps fract_y back + # to 0 while fract_x stays free. + structure = self._structure() + structure.atom_sites.create( + label='E', + type_symbol='O', + fract_x=0.3, + fract_y=0.0, + fract_z=0.0, + adp_iso=0.5, + ) + structure._update_categories() + assert structure.atom_sites['E'].wyckoff_letter.value == 'e' + structure.atom_sites['E'].fract_x.value = 0.4 + structure.atom_sites['E'].fract_y.value = 0.0005 + structure._update_categories() + atom = structure.atom_sites['E'] + assert atom.wyckoff_letter.value == 'e' + assert abs(atom.fract_x.value - 0.4) < 1e-6 + assert abs(atom.fract_y.value) < 1e-6 + + def test_space_group_change_redetects(self): + structure = self._structure() + structure.atom_sites.create(label='A', type_symbol='O', adp_iso=0.5) + structure._update_categories() + assert structure.atom_sites['A'].multiplicity.value == 1 # Pm-3m 'a' + structure.space_group.name_h_m = 'F m -3 m' + structure._update_categories() + atom = structure.atom_sites['A'] + assert atom.wyckoff_letter.value == 'a' + assert atom.multiplicity.value == 4 # Fm-3m 'a' + + def test_minimizer_path_keeps_letter_fixed(self): + structure = self._structure() + structure.atom_sites.create( + label='E', + type_symbol='O', + fract_x=0.3, + fract_y=0.0, + fract_z=0.0, + adp_iso=0.5, + ) + structure._update_categories() + # A minimizer step varies the free axis; the letter stays fixed + # (no re-detection) and the free coordinate is preserved. + structure.atom_sites['E'].fract_x.value = 0.4 + structure._update_categories(called_by_minimizer=True) + assert structure.atom_sites['E'].wyckoff_letter.value == 'e' + assert abs(structure.atom_sites['E'].fract_x.value - 0.4) < 1e-6 + + def test_untabulated_group_preserves_letter_without_multiplicity(self, monkeypatch): + from easydiffraction.crystallography import crystallography as ecr + + monkeypatch.setattr(ecr, 'space_group_wyckoff_table', lambda *a, **k: None) + structure = self._structure() + structure.atom_sites.create(label='X', type_symbol='O', adp_iso=0.5, wyckoff_letter='a') + structure._update_categories() + atom = structure.atom_sites['X'] + assert atom.wyckoff_letter.value == 'a' + assert atom.multiplicity.value is None + + def test_no_record_contract_clears_multiplicity(self, monkeypatch): + from easydiffraction.crystallography import crystallography as ecr + + monkeypatch.setattr(ecr, 'space_group_wyckoff_table', lambda *a, **k: None) + structure = self._structure() + structure.atom_sites.create(label='X', type_symbol='O', adp_iso=0.5) + structure._update_categories() + assert structure.atom_sites['X'].multiplicity.value is None + assert '_atom_site.site_symmetry_multiplicity' in structure.as_cif + + def test_cif_round_trip_redrives_letter(self): + from easydiffraction.datablocks.structure.item.factory import StructureFactory + + structure = self._structure() + structure.atom_sites.create(label='A', type_symbol='O', adp_iso=0.5) + structure._update_categories() + reloaded = StructureFactory.from_cif_str(structure.as_cif) + reloaded._update_categories() + assert reloaded.atom_sites['A'].wyckoff_letter.value == 'a' + assert reloaded.atom_sites['A'].multiplicity.value == 1 From 692f17075bb8a35a3269f28bbcc7129cd1a8b03a Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 15:22:22 +0200 Subject: [PATCH 49/55] Add tutorial-corpus Wyckoff detection regression --- .../test_wyckoff_tutorial_corpus.py | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 tests/functional/test_wyckoff_tutorial_corpus.py diff --git a/tests/functional/test_wyckoff_tutorial_corpus.py b/tests/functional/test_wyckoff_tutorial_corpus.py new file mode 100644 index 000000000..7375216fb --- /dev/null +++ b/tests/functional/test_wyckoff_tutorial_corpus.py @@ -0,0 +1,96 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Tutorial-corpus regression for Wyckoff-letter detection. + +The tutorials declare explicit Wyckoff letters for known structures, so +each declared letter is ground truth. This test re-derives the letter +from the site's coordinates and space group and asserts it matches the +declared one -- broad, real-world coverage that also guards against +regressions whenever the tutorials change. It parses the tutorial +sources statically (no execution / fitting), so it stays fast and does +not depend on a calculation engine. +""" + +import ast +import pathlib + +from easydiffraction.crystallography import crystallography as ecr + +_TUTORIALS_DIR = pathlib.Path(__file__).resolve().parents[2] / 'docs' / 'docs' / 'tutorials' + + +def _string_assignment(tree, attr_name): + """Return the unique str assigned to ``*.`` or ``None``. + + Returns ``None`` when the attribute is assigned zero or several + times, so callers can skip ambiguous (multi-structure) tutorials. + """ + values = [] + for node in ast.walk(tree): + if not isinstance(node, ast.Assign): + continue + for target in node.targets: + if ( + isinstance(target, ast.Attribute) + and target.attr == attr_name + and isinstance(node.value, ast.Constant) + and isinstance(node.value.value, str) + ): + values.append(node.value.value) + if len(values) == 1: + return values[0] + return None + + +def _wyckoff_declarations(tree): + """Yield ``(label, letter, (x, y, z))`` for create() calls with a letter.""" + for node in ast.walk(tree): + if not (isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute)): + continue + if node.func.attr != 'create': + continue + kwargs = { + kw.arg: kw.value.value + for kw in node.keywords + if kw.arg is not None and isinstance(kw.value, ast.Constant) + } + if 'wyckoff_letter' not in kwargs: + continue + coords = ( + float(kwargs.get('fract_x', 0.0)), + float(kwargs.get('fract_y', 0.0)), + float(kwargs.get('fract_z', 0.0)), + ) + yield kwargs.get('label', '?'), kwargs['wyckoff_letter'], coords + + +def _corpus(): + """Collect ``(tutorial, name_hm, code, label, letter, coords)`` rows.""" + rows = [] + for path in sorted(_TUTORIALS_DIR.glob('*.py')): + tree = ast.parse(path.read_text(encoding='utf-8')) + name_hm = _string_assignment(tree, 'name_h_m') + if name_hm is None: + # No structure, or several structures we cannot unambiguously + # associate with create() calls: skip this tutorial. + continue + code = _string_assignment(tree, 'it_coordinate_system_code') + for label, letter, coords in _wyckoff_declarations(tree): + rows.append((path.name, name_hm, code, label, letter, coords)) + return rows + + +def test_tutorial_declared_letters_are_reproduced_by_detection(): + rows = _corpus() + # Guard against a silently empty corpus (e.g. parser drift): the + # tutorials are known to declare explicit Wyckoff letters. + assert rows, 'no tutorial Wyckoff-letter declarations were found' + + mismatches = [] + for tutorial, name_hm, code, label, letter, coords in rows: + detected = ecr.detect_wyckoff_position(name_hm, code, coords) + if detected is None or detected.letter != letter: + found = None if detected is None else detected.letter + mismatches.append((tutorial, label, name_hm, coords, letter, found)) + + assert not mismatches, mismatches From 821e67372693acd07d401cd281d0fe2e36e2e301 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 15:40:38 +0200 Subject: [PATCH 50/55] Satisfy pydoclint and ruff for Wyckoff Phase 2 tests --- .../crystallography/crystallography.py | 2 +- .../test_wyckoff_tutorial_corpus.py | 21 ++++++++----------- .../structure/categories/test_atom_sites.py | 2 +- .../categories/test_space_group_wyckoff.py | 12 +++++------ 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/easydiffraction/crystallography/crystallography.py b/src/easydiffraction/crystallography/crystallography.py index e00aa03f5..e75569a4b 100644 --- a/src/easydiffraction/crystallography/crystallography.py +++ b/src/easydiffraction/crystallography/crystallography.py @@ -29,7 +29,7 @@ class WyckoffPosition: """ A resolved Wyckoff position and the orbit representative matched. - Parameters + Attributes ---------- letter : str Wyckoff letter (e.g. ``'h'``). diff --git a/tests/functional/test_wyckoff_tutorial_corpus.py b/tests/functional/test_wyckoff_tutorial_corpus.py index 7375216fb..cdd8752d2 100644 --- a/tests/functional/test_wyckoff_tutorial_corpus.py +++ b/tests/functional/test_wyckoff_tutorial_corpus.py @@ -25,18 +25,15 @@ def _string_assignment(tree, attr_name): Returns ``None`` when the attribute is assigned zero or several times, so callers can skip ambiguous (multi-structure) tutorials. """ - values = [] - for node in ast.walk(tree): - if not isinstance(node, ast.Assign): - continue - for target in node.targets: - if ( - isinstance(target, ast.Attribute) - and target.attr == attr_name - and isinstance(node.value, ast.Constant) - and isinstance(node.value.value, str) - ): - values.append(node.value.value) + values = [ + node.value.value + for node in ast.walk(tree) + if isinstance(node, ast.Assign) + and isinstance(node.value, ast.Constant) + and isinstance(node.value.value, str) + for target in node.targets + if isinstance(target, ast.Attribute) and target.attr == attr_name + ] if len(values) == 1: return values[0] return None diff --git a/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py b/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py index 9c7a7e213..2958fa494 100644 --- a/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py +++ b/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py @@ -331,7 +331,7 @@ def test_invalid_explicit_letter_raises_on_update(self): structure = self._structure() structure.atom_sites.create(label='Z', type_symbol='O', adp_iso=0.5, wyckoff_letter='z') - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='Invalid Wyckoff letter'): structure._update_categories() def test_same_letter_edit_snaps_off_orbit_coordinate(self): diff --git a/tests/unit/easydiffraction/datablocks/structure/categories/test_space_group_wyckoff.py b/tests/unit/easydiffraction/datablocks/structure/categories/test_space_group_wyckoff.py index 3f8d0e638..16716343c 100644 --- a/tests/unit/easydiffraction/datablocks/structure/categories/test_space_group_wyckoff.py +++ b/tests/unit/easydiffraction/datablocks/structure/categories/test_space_group_wyckoff.py @@ -86,15 +86,15 @@ def test_rejects_all_public_mutation(self): structure = _cubic_structure() wy = structure.space_group_wyckoff row = wy['1a'] - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='read-only'): wy.add(row) - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='read-only'): wy.create() - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='read-only'): wy.remove('1a') - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='read-only'): wy['1a'] = row - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='read-only'): del wy['1a'] def test_from_cif_ignores_incoming_loop(self): @@ -103,7 +103,7 @@ def test_from_cif_ignores_incoming_loop(self): from easydiffraction.datablocks.structure.item.factory import StructureFactory cif = ( - "data_x\n" + 'data_x\n' "_space_group.name_H-M_alt 'P m -3 m'\n" '_space_group.IT_coordinate_system_code 1\n' 'loop_\n' From ddcd720d78042b683623b93f059fcf9b5b389254 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 16:00:30 +0200 Subject: [PATCH 51/55] Fix ed-13 Si to the 8a diamond position --- docs/docs/tutorials/ed-13.ipynb | 20 +++++++------------- docs/docs/tutorials/ed-13.py | 14 +++++++------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/docs/docs/tutorials/ed-13.ipynb b/docs/docs/tutorials/ed-13.ipynb index 1ac483d2c..9a84c90cd 100644 --- a/docs/docs/tutorials/ed-13.ipynb +++ b/docs/docs/tutorials/ed-13.ipynb @@ -710,7 +710,7 @@ "_atom_site.occupancy\n", "_atom_site.ADP_type\n", "_atom_site.B_iso_or_equiv\n", - "Si Si 0 0 0 a 1.0 Biso 0.89\n", + "Si Si 0.125 0.125 0.125 a 1.0 Biso 0.89\n", "```" ] }, @@ -838,10 +838,9 @@ "project_1.structures['si'].atom_sites.create(\n", " label='Si',\n", " type_symbol='Si',\n", - " fract_x=0,\n", - " fract_y=0,\n", - " fract_z=0,\n", - " wyckoff_letter='a',\n", + " fract_x=0.125,\n", + " fract_y=0.125,\n", + " fract_z=0.125,\n", " adp_iso=0.89,\n", ")" ] @@ -1805,7 +1804,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.95,\n", " occupancy=0.5,\n", ")\n", @@ -1815,7 +1813,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.95,\n", " occupancy=0.5,\n", ")\n", @@ -1825,7 +1822,6 @@ " fract_x=0.5,\n", " fract_y=0.5,\n", " fract_z=0.5,\n", - " wyckoff_letter='b',\n", " adp_iso=0.80,\n", ")\n", "project_2.structures['lbco'].atom_sites.create(\n", @@ -1834,7 +1830,6 @@ " fract_x=0,\n", " fract_y=0.5,\n", " fract_z=0.5,\n", - " wyckoff_letter='c',\n", " adp_iso=1.66,\n", ")" ] @@ -2517,10 +2512,9 @@ "project_2.structures['si'].atom_sites.create(\n", " label='Si',\n", " type_symbol='Si',\n", - " fract_x=0,\n", - " fract_y=0,\n", - " fract_z=0,\n", - " wyckoff_letter='a',\n", + " fract_x=0.125,\n", + " fract_y=0.125,\n", + " fract_z=0.125,\n", " adp_iso=0.89,\n", ")\n", "\n", diff --git a/docs/docs/tutorials/ed-13.py b/docs/docs/tutorials/ed-13.py index 888c41d48..82970780f 100644 --- a/docs/docs/tutorials/ed-13.py +++ b/docs/docs/tutorials/ed-13.py @@ -438,7 +438,7 @@ # _atom_site.occupancy # _atom_site.ADP_type # _atom_site.B_iso_or_equiv -# Si Si 0 0 0 a 1.0 Biso 0.89 +# Si Si 0.125 0.125 0.125 a 1.0 Biso 0.89 # ``` # %% [markdown] @@ -493,9 +493,9 @@ project_1.structures['si'].atom_sites.create( label='Si', type_symbol='Si', - fract_x=0, - fract_y=0, - fract_z=0, + fract_x=0.125, + fract_y=0.125, + fract_z=0.125, adp_iso=0.89, ) @@ -1403,9 +1403,9 @@ project_2.structures['si'].atom_sites.create( label='Si', type_symbol='Si', - fract_x=0, - fract_y=0, - fract_z=0, + fract_x=0.125, + fract_y=0.125, + fract_z=0.125, adp_iso=0.89, ) From 74f9354e300a58acd3546f499e194d48199d95dd Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 16:15:38 +0200 Subject: [PATCH 52/55] Regenerate tutorial notebooks after Wyckoff letter removal --- docs/docs/tutorials/ed-10.ipynb | 1 - docs/docs/tutorials/ed-11.ipynb | 1 - docs/docs/tutorials/ed-12.ipynb | 2 -- docs/docs/tutorials/ed-16.ipynb | 1 - docs/docs/tutorials/ed-17.ipynb | 6 ------ docs/docs/tutorials/ed-2.ipynb | 4 ---- docs/docs/tutorials/ed-20.ipynb | 2 -- docs/docs/tutorials/ed-3.ipynb | 4 ---- docs/docs/tutorials/ed-4.ipynb | 5 ----- docs/docs/tutorials/ed-5.ipynb | 6 ------ docs/docs/tutorials/ed-6.ipynb | 5 ----- docs/docs/tutorials/ed-8.ipynb | 6 ------ docs/docs/tutorials/ed-9.ipynb | 5 ----- 13 files changed, 48 deletions(-) diff --git a/docs/docs/tutorials/ed-10.ipynb b/docs/docs/tutorials/ed-10.ipynb index e2b947d23..3815f24ea 100644 --- a/docs/docs/tutorials/ed-10.ipynb +++ b/docs/docs/tutorials/ed-10.ipynb @@ -112,7 +112,6 @@ " fract_x=0.0,\n", " fract_y=0.0,\n", " fract_z=0.0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.5,\n", ")" ] diff --git a/docs/docs/tutorials/ed-11.ipynb b/docs/docs/tutorials/ed-11.ipynb index 13f867925..b5d03cf56 100644 --- a/docs/docs/tutorials/ed-11.ipynb +++ b/docs/docs/tutorials/ed-11.ipynb @@ -139,7 +139,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.5,\n", ")" ] diff --git a/docs/docs/tutorials/ed-12.ipynb b/docs/docs/tutorials/ed-12.ipynb index 4724b20b6..ed2c0a0b5 100644 --- a/docs/docs/tutorials/ed-12.ipynb +++ b/docs/docs/tutorials/ed-12.ipynb @@ -144,7 +144,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='a',\n", " adp_iso=1.0,\n", ")\n", "project.structures['nacl'].atom_sites.create(\n", @@ -153,7 +152,6 @@ " fract_x=0.5,\n", " fract_y=0.5,\n", " fract_z=0.5,\n", - " wyckoff_letter='b',\n", " adp_iso=1.0,\n", ")" ] diff --git a/docs/docs/tutorials/ed-16.ipynb b/docs/docs/tutorials/ed-16.ipynb index 92092f299..09c816f05 100644 --- a/docs/docs/tutorials/ed-16.ipynb +++ b/docs/docs/tutorials/ed-16.ipynb @@ -137,7 +137,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.2,\n", ")" ] diff --git a/docs/docs/tutorials/ed-17.ipynb b/docs/docs/tutorials/ed-17.ipynb index 0c69f1348..351290746 100644 --- a/docs/docs/tutorials/ed-17.ipynb +++ b/docs/docs/tutorials/ed-17.ipynb @@ -177,7 +177,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.3,\n", ")\n", "struct.atom_sites.create(\n", @@ -186,7 +185,6 @@ " fract_x=0.279,\n", " fract_y=0.25,\n", " fract_z=0.985,\n", - " wyckoff_letter='c',\n", " adp_iso=0.3,\n", ")\n", "struct.atom_sites.create(\n", @@ -195,7 +193,6 @@ " fract_x=0.094,\n", " fract_y=0.25,\n", " fract_z=0.429,\n", - " wyckoff_letter='c',\n", " adp_iso=0.34,\n", ")\n", "struct.atom_sites.create(\n", @@ -204,7 +201,6 @@ " fract_x=0.091,\n", " fract_y=0.25,\n", " fract_z=0.771,\n", - " wyckoff_letter='c',\n", " adp_iso=0.63,\n", ")\n", "struct.atom_sites.create(\n", @@ -213,7 +209,6 @@ " fract_x=0.448,\n", " fract_y=0.25,\n", " fract_z=0.217,\n", - " wyckoff_letter='c',\n", " adp_iso=0.59,\n", ")\n", "struct.atom_sites.create(\n", @@ -222,7 +217,6 @@ " fract_x=0.164,\n", " fract_y=0.032,\n", " fract_z=0.28,\n", - " wyckoff_letter='d',\n", " adp_iso=0.83,\n", ")" ] diff --git a/docs/docs/tutorials/ed-2.ipynb b/docs/docs/tutorials/ed-2.ipynb index b2ca221f2..9b1872b5b 100644 --- a/docs/docs/tutorials/ed-2.ipynb +++ b/docs/docs/tutorials/ed-2.ipynb @@ -145,7 +145,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.5,\n", " occupancy=0.5,\n", ")\n", @@ -155,7 +154,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.5,\n", " occupancy=0.5,\n", ")\n", @@ -165,7 +163,6 @@ " fract_x=0.5,\n", " fract_y=0.5,\n", " fract_z=0.5,\n", - " wyckoff_letter='b',\n", " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", @@ -174,7 +171,6 @@ " fract_x=0,\n", " fract_y=0.5,\n", " fract_z=0.5,\n", - " wyckoff_letter='c',\n", " adp_iso=0.5,\n", ")" ] diff --git a/docs/docs/tutorials/ed-20.ipynb b/docs/docs/tutorials/ed-20.ipynb index 4c32724d0..6dc22803e 100644 --- a/docs/docs/tutorials/ed-20.ipynb +++ b/docs/docs/tutorials/ed-20.ipynb @@ -90,7 +90,6 @@ " fract_x=0.0,\n", " fract_y=0.0,\n", " fract_z=0.0,\n", - " wyckoff_letter='a',\n", " adp_type='Biso',\n", " adp_iso=1.0,\n", ")" @@ -124,7 +123,6 @@ " fract_x=0.0,\n", " fract_y=0.0,\n", " fract_z=0.0,\n", - " wyckoff_letter='a',\n", " adp_type='Biso',\n", " adp_iso=1.0,\n", ")" diff --git a/docs/docs/tutorials/ed-3.ipynb b/docs/docs/tutorials/ed-3.ipynb index 8076de33a..cce439297 100644 --- a/docs/docs/tutorials/ed-3.ipynb +++ b/docs/docs/tutorials/ed-3.ipynb @@ -267,7 +267,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.5,\n", " occupancy=0.5,\n", ")\n", @@ -277,7 +276,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.5,\n", " occupancy=0.5,\n", ")\n", @@ -287,7 +285,6 @@ " fract_x=0.5,\n", " fract_y=0.5,\n", " fract_z=0.5,\n", - " wyckoff_letter='b',\n", " adp_iso=0.5,\n", ")\n", "project.structures['lbco'].atom_sites.create(\n", @@ -296,7 +293,6 @@ " fract_x=0,\n", " fract_y=0.5,\n", " fract_z=0.5,\n", - " wyckoff_letter='c',\n", " adp_iso=0.5,\n", ")" ] diff --git a/docs/docs/tutorials/ed-4.ipynb b/docs/docs/tutorials/ed-4.ipynb index 2bc849990..c45ed29cf 100644 --- a/docs/docs/tutorials/ed-4.ipynb +++ b/docs/docs/tutorials/ed-4.ipynb @@ -142,7 +142,6 @@ " fract_x=0.1876,\n", " fract_y=0.25,\n", " fract_z=0.167,\n", - " wyckoff_letter='c',\n", " adp_iso=1.37,\n", ")\n", "structure.atom_sites.create(\n", @@ -151,7 +150,6 @@ " fract_x=0.0654,\n", " fract_y=0.25,\n", " fract_z=0.684,\n", - " wyckoff_letter='c',\n", " adp_iso=0.3777,\n", ")\n", "structure.atom_sites.create(\n", @@ -160,7 +158,6 @@ " fract_x=0.9082,\n", " fract_y=0.25,\n", " fract_z=0.5954,\n", - " wyckoff_letter='c',\n", " adp_iso=1.9764,\n", ")\n", "structure.atom_sites.create(\n", @@ -169,7 +166,6 @@ " fract_x=0.1935,\n", " fract_y=0.25,\n", " fract_z=0.5432,\n", - " wyckoff_letter='c',\n", " adp_iso=1.4456,\n", ")\n", "structure.atom_sites.create(\n", @@ -178,7 +174,6 @@ " fract_x=0.0811,\n", " fract_y=0.0272,\n", " fract_z=0.8086,\n", - " wyckoff_letter='d',\n", " adp_iso=1.2822,\n", ")" ] diff --git a/docs/docs/tutorials/ed-5.ipynb b/docs/docs/tutorials/ed-5.ipynb index 6aa0fedb2..391ca3651 100644 --- a/docs/docs/tutorials/ed-5.ipynb +++ b/docs/docs/tutorials/ed-5.ipynb @@ -138,7 +138,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", @@ -147,7 +146,6 @@ " fract_x=0.279,\n", " fract_y=0.25,\n", " fract_z=0.985,\n", - " wyckoff_letter='c',\n", " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", @@ -156,7 +154,6 @@ " fract_x=0.094,\n", " fract_y=0.25,\n", " fract_z=0.429,\n", - " wyckoff_letter='c',\n", " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", @@ -165,7 +162,6 @@ " fract_x=0.091,\n", " fract_y=0.25,\n", " fract_z=0.771,\n", - " wyckoff_letter='c',\n", " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", @@ -174,7 +170,6 @@ " fract_x=0.448,\n", " fract_y=0.25,\n", " fract_z=0.217,\n", - " wyckoff_letter='c',\n", " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", @@ -183,7 +178,6 @@ " fract_x=0.164,\n", " fract_y=0.032,\n", " fract_z=0.28,\n", - " wyckoff_letter='d',\n", " adp_iso=0.5,\n", ")" ] diff --git a/docs/docs/tutorials/ed-6.ipynb b/docs/docs/tutorials/ed-6.ipynb index 488690968..561afb750 100644 --- a/docs/docs/tutorials/ed-6.ipynb +++ b/docs/docs/tutorials/ed-6.ipynb @@ -136,7 +136,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0.5,\n", - " wyckoff_letter='b',\n", " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", @@ -145,7 +144,6 @@ " fract_x=0.5,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='e',\n", " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", @@ -154,7 +152,6 @@ " fract_x=0.21,\n", " fract_y=-0.21,\n", " fract_z=0.06,\n", - " wyckoff_letter='h',\n", " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", @@ -163,7 +160,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0.197,\n", - " wyckoff_letter='c',\n", " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", @@ -172,7 +168,6 @@ " fract_x=0.13,\n", " fract_y=-0.13,\n", " fract_z=0.08,\n", - " wyckoff_letter='h',\n", " adp_iso=0.5,\n", ")" ] diff --git a/docs/docs/tutorials/ed-8.ipynb b/docs/docs/tutorials/ed-8.ipynb index e564ca387..7e02e5770 100644 --- a/docs/docs/tutorials/ed-8.ipynb +++ b/docs/docs/tutorials/ed-8.ipynb @@ -136,7 +136,6 @@ " fract_x=0.4663,\n", " fract_y=0.0,\n", " fract_z=0.25,\n", - " wyckoff_letter='b',\n", " adp_iso=0.92,\n", ")\n", "structure.atom_sites.create(\n", @@ -145,7 +144,6 @@ " fract_x=0.2521,\n", " fract_y=0.2521,\n", " fract_z=0.2521,\n", - " wyckoff_letter='a',\n", " adp_iso=0.73,\n", ")\n", "structure.atom_sites.create(\n", @@ -154,7 +152,6 @@ " fract_x=0.0851,\n", " fract_y=0.0851,\n", " fract_z=0.0851,\n", - " wyckoff_letter='a',\n", " adp_iso=2.08,\n", ")\n", "structure.atom_sites.create(\n", @@ -163,7 +160,6 @@ " fract_x=0.1377,\n", " fract_y=0.3054,\n", " fract_z=0.1195,\n", - " wyckoff_letter='c',\n", " adp_iso=0.90,\n", ")\n", "structure.atom_sites.create(\n", @@ -172,7 +168,6 @@ " fract_x=0.3625,\n", " fract_y=0.3633,\n", " fract_z=0.1867,\n", - " wyckoff_letter='c',\n", " adp_iso=1.37,\n", ")\n", "structure.atom_sites.create(\n", @@ -181,7 +176,6 @@ " fract_x=0.4612,\n", " fract_y=0.4612,\n", " fract_z=0.4612,\n", - " wyckoff_letter='a',\n", " adp_iso=0.88,\n", ")" ] diff --git a/docs/docs/tutorials/ed-9.ipynb b/docs/docs/tutorials/ed-9.ipynb index 8722b614e..8d1ecdfee 100644 --- a/docs/docs/tutorials/ed-9.ipynb +++ b/docs/docs/tutorials/ed-9.ipynb @@ -133,7 +133,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.2,\n", " occupancy=0.5,\n", ")\n", @@ -143,7 +142,6 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.2,\n", " occupancy=0.5,\n", ")\n", @@ -153,7 +151,6 @@ " fract_x=0.5,\n", " fract_y=0.5,\n", " fract_z=0.5,\n", - " wyckoff_letter='b',\n", " adp_iso=0.2567,\n", ")\n", "structure_1.atom_sites.create(\n", @@ -162,7 +159,6 @@ " fract_x=0,\n", " fract_y=0.5,\n", " fract_z=0.5,\n", - " wyckoff_letter='c',\n", " adp_iso=1.4041,\n", ")" ] @@ -243,7 +239,6 @@ " fract_x=0.0,\n", " fract_y=0.0,\n", " fract_z=0.0,\n", - " wyckoff_letter='a',\n", " adp_iso=0.0,\n", ")" ] From 04a6721308e5bce36e6d1916db97c5d24de0c9ed Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 16:20:34 +0200 Subject: [PATCH 53/55] Restore tutorial-corpus coverage with explicit ground-truth table --- .../test_wyckoff_tutorial_corpus.py | 103 +++++++++++++++--- 1 file changed, 88 insertions(+), 15 deletions(-) diff --git a/tests/functional/test_wyckoff_tutorial_corpus.py b/tests/functional/test_wyckoff_tutorial_corpus.py index cdd8752d2..45bf5d4e3 100644 --- a/tests/functional/test_wyckoff_tutorial_corpus.py +++ b/tests/functional/test_wyckoff_tutorial_corpus.py @@ -2,13 +2,22 @@ # SPDX-License-Identifier: BSD-3-Clause """Tutorial-corpus regression for Wyckoff-letter detection. -The tutorials declare explicit Wyckoff letters for known structures, so -each declared letter is ground truth. This test re-derives the letter -from the site's coordinates and space group and asserts it matches the -declared one -- broad, real-world coverage that also guards against -regressions whenever the tutorials change. It parses the tutorial -sources statically (no execution / fitting), so it stays fast and does -not depend on a calculation engine. +Each tutorial structure has a known Wyckoff letter for every site, so the +letter is ground truth. This test re-derives the letter from the site's +coordinates and space group and asserts it matches the known one -- broad, +real-world coverage that also guards against regressions whenever the +tutorials change. + +Coverage comes from two sources: + +1. Tutorials that still declare ``wyckoff_letter`` explicitly are parsed + statically (no execution / fitting) and checked directly. +2. Many tutorials were switched to rely on auto-detection (the explicit + letters were removed from the source). Their original declarations are + preserved here as an explicit ``_GROUND_TRUTH`` table so the regression + still exercises those structures -- including the R-3m coupled special + position ``(x, -x, z)`` from ed-6 that motivated the canonical-template + work. """ import ast @@ -18,6 +27,58 @@ _TUTORIALS_DIR = pathlib.Path(__file__).resolve().parents[2] / 'docs' / 'docs' / 'tutorials' +# Known (space group, coordinate code, fractional coordinates, Wyckoff +# letter) for tutorial sites that no longer declare the letter in source +# (they now exercise auto-detection). Detection must reproduce each letter. +_GROUND_TRUTH = [ + ('F d -3 m', '1', (0.0, 0.0, 0.0), 'a'), + ('F m -3 m', '1', (0.0, 0.0, 0.0), 'a'), + ('F m -3 m', '1', (0.5, 0.5, 0.5), 'b'), + ('I 21 3', '1', (0.0851, 0.0851, 0.0851), 'a'), + ('I 21 3', '1', (0.1377, 0.3054, 0.1195), 'c'), + ('I 21 3', '1', (0.2521, 0.2521, 0.2521), 'a'), + ('I 21 3', '1', (0.3625, 0.3633, 0.1867), 'c'), + ('I 21 3', '1', (0.4612, 0.4612, 0.4612), 'a'), + ('I 21 3', '1', (0.4663, 0.0, 0.25), 'b'), + ('P m -3 m', '1', (0.0, 0.0, 0.0), 'a'), + ('P m -3 m', '1', (0.0, 0.5, 0.5), 'c'), + ('P m -3 m', '1', (0.5, 0.5, 0.5), 'b'), + ('P n m a', 'abc', (0.0, 0.0, 0.0), 'a'), + ('P n m a', 'abc', (0.0654, 0.25, 0.684), 'c'), + ('P n m a', 'abc', (0.0811, 0.0272, 0.8086), 'd'), + ('P n m a', 'abc', (0.091, 0.25, 0.771), 'c'), + ('P n m a', 'abc', (0.094, 0.25, 0.429), 'c'), + ('P n m a', 'abc', (0.164, 0.032, 0.28), 'd'), + ('P n m a', 'abc', (0.1876, 0.25, 0.167), 'c'), + ('P n m a', 'abc', (0.1935, 0.25, 0.5432), 'c'), + ('P n m a', 'abc', (0.279, 0.25, 0.985), 'c'), + ('P n m a', 'abc', (0.448, 0.25, 0.217), 'c'), + ('P n m a', 'abc', (0.9082, 0.25, 0.5954), 'c'), + ('R -3 m', 'h', (0.0, 0.0, 0.197), 'c'), + ('R -3 m', 'h', (0.0, 0.0, 0.5), 'b'), + ('R -3 m', 'h', (0.13, -0.13, 0.08), 'h'), + ('R -3 m', 'h', (0.21, -0.21, 0.06), 'h'), + ('R -3 m', 'h', (0.5, 0.0, 0.0), 'e'), +] + + +def _const(node): + """Return a literal value for a Constant or a negated Constant. + + Returns ``None`` for any other node so non-literal arguments are + ignored. Handles negative numeric literals such as ``-0.21``, which + parse as ``UnaryOp(USub, Constant)`` rather than a bare ``Constant``. + """ + if isinstance(node, ast.Constant): + return node.value + if ( + isinstance(node, ast.UnaryOp) + and isinstance(node.op, ast.USub) + and isinstance(node.operand, ast.Constant) + ): + return -node.operand.value + return None + def _string_assignment(tree, attr_name): """Return the unique str assigned to ``*.`` or ``None``. @@ -26,11 +87,9 @@ def _string_assignment(tree, attr_name): times, so callers can skip ambiguous (multi-structure) tutorials. """ values = [ - node.value.value + _const(node.value) for node in ast.walk(tree) - if isinstance(node, ast.Assign) - and isinstance(node.value, ast.Constant) - and isinstance(node.value.value, str) + if isinstance(node, ast.Assign) and isinstance(_const(node.value), str) for target in node.targets if isinstance(target, ast.Attribute) and target.attr == attr_name ] @@ -47,9 +106,9 @@ def _wyckoff_declarations(tree): if node.func.attr != 'create': continue kwargs = { - kw.arg: kw.value.value + kw.arg: _const(kw.value) for kw in node.keywords - if kw.arg is not None and isinstance(kw.value, ast.Constant) + if kw.arg is not None and _const(kw.value) is not None } if 'wyckoff_letter' not in kwargs: continue @@ -79,8 +138,8 @@ def _corpus(): def test_tutorial_declared_letters_are_reproduced_by_detection(): rows = _corpus() - # Guard against a silently empty corpus (e.g. parser drift): the - # tutorials are known to declare explicit Wyckoff letters. + # Guard against a silently empty corpus (e.g. parser drift): some + # tutorials still declare explicit Wyckoff letters. assert rows, 'no tutorial Wyckoff-letter declarations were found' mismatches = [] @@ -91,3 +150,17 @@ def test_tutorial_declared_letters_are_reproduced_by_detection(): mismatches.append((tutorial, label, name_hm, coords, letter, found)) assert not mismatches, mismatches + + +def test_ground_truth_letters_are_reproduced_by_detection(): + # Structures whose explicit letters were removed in favour of + # auto-detection are covered here so the regression still exercises + # them (notably the R-3m coupled special position). + mismatches = [] + for name_hm, code, coords, letter in _GROUND_TRUTH: + detected = ecr.detect_wyckoff_position(name_hm, code, coords) + if detected is None or detected.letter != letter: + found = None if detected is None else detected.letter + mismatches.append((name_hm, code, coords, letter, found)) + + assert not mismatches, mismatches From 70c32c74a8d4f365de0c3f1057f5d4e89cad1912 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 16:28:33 +0200 Subject: [PATCH 54/55] Match Fd-3m corpus ground truth to corrected ed-13 Si site --- tests/functional/test_wyckoff_tutorial_corpus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/test_wyckoff_tutorial_corpus.py b/tests/functional/test_wyckoff_tutorial_corpus.py index 45bf5d4e3..08306c269 100644 --- a/tests/functional/test_wyckoff_tutorial_corpus.py +++ b/tests/functional/test_wyckoff_tutorial_corpus.py @@ -31,7 +31,7 @@ # letter) for tutorial sites that no longer declare the letter in source # (they now exercise auto-detection). Detection must reproduce each letter. _GROUND_TRUTH = [ - ('F d -3 m', '1', (0.0, 0.0, 0.0), 'a'), + ('F d -3 m', '2', (0.125, 0.125, 0.125), 'a'), ('F m -3 m', '1', (0.0, 0.0, 0.0), 'a'), ('F m -3 m', '1', (0.5, 0.5, 0.5), 'b'), ('I 21 3', '1', (0.0851, 0.0851, 0.0851), 'a'), From 38b3c1c03519e455ac7afd066a227441c517cd03 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 3 Jun 2026 16:29:36 +0200 Subject: [PATCH 55/55] Mark Phase 2 verification complete in plan --- docs/dev/plans/wyckoff-letter-detection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index 3a5e83baf..2bfcb4bc5 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -9,7 +9,7 @@ ADR. No deliberate exception to `AGENTS.md` is taken. - [x] ADR review gate closed - [x] Phase 1 — Implementation (code + docs) - [x] Phase 1 review gate -- [ ] Phase 2 — Verification (tests + `pixi` checks) +- [x] Phase 2 — Verification (tests + `pixi` checks) ## ADR