Skip to content

feat: Orientation from Euler angles, dot, dotOuter and distanceMatrix - #44

Merged
Paullo9 merged 4 commits into
mainfrom
issue-13-orientation-api
Oct 31, 2026
Merged

Paullo9 merged 4 commits into
mainfrom
issue-13-orientation-api

Conversation

@Paullo9

@Paullo9 Paullo9 commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

Requested by Paul · project thread

Part of #13. Stacked on #43 (its two commits are included here; merge #43 first). Remaining on the
issue: the orientation (Rodrigues) fundamental zone, and dot products across two different groups (see below).

New public API (additive, no migration)

Each is the orix 0.15.0 function of the same name, on Orientation:

  • Orientation(euler:symmetry:direction:) with Orientation.EulerDirection (labToCrystal, the default and Bunge
    convention, or crystalToLab): orix from_euler, Bunge radians through eu2qu. Throws invalidRotation for a
    non-finite angle.
  • dot(_:): orix Orientation.dot, the largest |<other * self^-1, s>| over the proper operators.
  • Orientation.dotOuter(_:_:): orix dot_outer, [i][j] = a[i].dot(b[j]).
  • Orientation.distanceMatrix(_:): orix get_distance_matrix, arccos(2 d^2 - 1) with the dot rounded to 12 decimals
    and clamped, as orix kernel does (an equivalent pair is exactly 0).

The three dot functions throw differentSymmetry for two different groups, as angle(with:) already does. orix allows
it, but its two-group dot searches sym1.outer(sym2), which with equivalents S * M is the inverse of the set it needs:
for 432 with 622 and 23 with 3 it differs from the largest dot over equivalent pairs by up to 0.08 (200-draw check). This
is the same cause as the Misorientation.reduce disagreement in #43, so it is listed as not held rather than copied.

Tests

  • tools/pins/orix/orientation-api-pins.py (orix 0.15.0): 36 Bunge triplets with the gimbal-lock and half-turn edges, in
    both directions; the 12 class/setting entries, six and five orientations each, with symmetry-equivalent pairs.
  • OrixOrientationAPITests (unit target, so the per-push gate runs it): red before the API existed (did not compile),
    green after. orix tolerances: from_euler atol 1e-4 (test_from_euler_symmetry), the rest np.allclose defaults.
    Measured worst: matrix 3.3e-16, dot 4.4e-16, distance 8.9e-16.
  • swift test -c release --skip DiffractoKitParityTests green; tools/consumer-check/run.sh 730 of 730, including the
    new calls.
  • docs/parity.md Orientation row updated; docs/open-items.md keeps the fundamental zone and the two-group case.

🤖 Generated with Claude Code

Paullo9 and others added 3 commits October 31, 2026 02:48
The orix misorientation pins gain orderedZoneAngle and orderedZoneReduced per draw: orix 0.15.0 runs its own
Misorientation.reduce loop with OrientationRegion.from_symmetry(end, start) instead of (start, end). The script
asserts that this returns the smallest angle on every draw. Every existing field of the fixture is unchanged
(same seed, same draws); the file only gains the two fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
orix 0.15.0 takes end * M * start and stops at the first one inside OrientationRegion.from_symmetry(start, end),
whose distinguished points are start . end. The smallest angle of end * M * start lies in the Voronoi cell of the
identity among end . start, the inverse set. The two agree only when the product set is a group; for 432 with 622
and 23 with 3 the zone holds no equivalent on some draws and the loop falls through to its last pair. With the zone
built as from_symmetry(end, start) the same orix loop returns the smallest angle on every draw.

The kit already returns the smallest angle; the parity test now compares it with that orix loop on every draw
(angle atol 1e-4, the orix test tolerance; reduced matrix 1e-9 where the minimum is unique) instead of falling back
to brute force where orix is not minimal. The DEVIATION note and docs/open-items.md name the cause.

Done: the reduce disagreement is diagnosed and pinned. Next: the Orientation API gaps of the same issue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (orix 0.15.0)

New public API on Orientation, each the orix 0.15.0 function of the same name:
- Orientation(euler:symmetry:direction:) and Orientation.EulerDirection: orix Orientation.from_euler, Bunge radians
  through eu2qu, labToCrystal (default) or crystalToLab.
- dot(_:): orix Orientation.dot, the largest |<other * self^-1, s>| over the proper operators.
- Orientation.dotOuter(_:_:): orix dot_outer.
- Orientation.distanceMatrix(_:): orix get_distance_matrix, arccos(2 d^2 - 1) with the dot rounded to 12 decimals and
  clamped as orix kernel does.
All three dot functions refuse two different groups with differentSymmetry, as angle(with:) does: orix two-group dot
searches sym1.outer(sym2), the inverse of the set its equivalents need, the same cause as the Misorientation.reduce
DEVIATION.

Pins: tools/pins/orix/orientation-api-pins.py (36 Euler triplets with the gimbal-lock and half-turn edges, both
directions; the 12 class/setting entries with symmetry-equivalent pairs). OrixOrientationAPITests holds them at orix
tolerances (from_euler atol 1e-4, the rest np.allclose defaults); measured worst 3.3e-16 and 8.9e-16. The consumer
check calls the new API from outside the package.

Done: from_euler, dot, dot_outer and get_distance_matrix for one group are held. Next: the orientation (Rodrigues)
fundamental zone of the same issue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Paullo9 Paullo9 self-assigned this Oct 31, 2026
#43 landed on main as a squash. docs/open-items.md conflicted on the orix API gaps item: kept this branch rewrite (from_euler, dot, dotOuter and distanceMatrix for one group are held). The diff against main equals the diff this PR had against #43.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Paullo9
Paullo9 merged commit c6c65a9 into main Oct 31, 2026
6 checks passed
@Paullo9
Paullo9 deleted the issue-13-orientation-api branch October 31, 2026 10:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant