Skip to content

EBSD phase viewer and pattern center solved from the scan's own patterns - #246

Open
CSSFrancis wants to merge 12 commits into
mainfrom
feat/phase-viewer
Open

CSSFrancis wants to merge 12 commits into
mainfrom
feat/phase-viewer

Conversation

@CSSFrancis

Copy link
Copy Markdown
Member

Clicking a phase in the Composition dock now pops an EBSD phase viewer out beside the sidebar. It shows the master pattern on a sphere with the detector outline, the unit cell, and the detector pattern, all turning together as you drag. The Composition dock also shows a phase's Kikuchi band sphere.

Beneath the views are the microscope geometry (read from and written back to the signal's metadata) and a choice between kinematic bands and a full dynamical master pattern. Several open phases stack.

For an EBSD scan, "Solve from data" fits the scan's pattern center from patterns read across the scan itself, and writes it only when the fit is good enough to trust. Pieces of that:

  • the detector's static background is subtracted before the center is seeded
  • the search is global, so it finds the center from anywhere rather than only from close by
  • patterns are read from a line scan as readily as from a map
  • orientations are sampled once and reused across the search, which brings a solve down from minutes to about 25 s
  • simulated bands now account for the sample and detector tilt, and fcc and bcc {200} and {220} bands are kept when reflectors come from a CIF

The pattern center's three coordinates share one row in the UI.

Clicking a phase's structure expands the phase to show its kinematic master
pattern on a sphere, with the detector's outline on it, beside the pattern
the detector records at that orientation. Dragging the sphere turns the
crystal under the fixed detector and repaints the pattern. It is part of the
phase's setup, so it lives in the dock (a host:"phase" figure, routed like a
report cell's) rather than opening a window that reads as a dataset.

The sphere and the preview are the same band profile sampled at different
directions: band_intensity is factored out of simulate_patterns, which the
EBSD wizard's dictionary and live overlay already use, so the three cannot
disagree. The preview is pinned to simulate_patterns at the matching Bunge
angles; matrix_to_euler is added beside euler_to_matrix for the readout.

Geometry is read the way the EBSD wizard reads it: pattern centre from
_resolve_pc, voltage from the signal's beam energy (20 kV otherwise), and
the detector shape from the signal's frames. One viewer per phase is kept
on the tree, so expanding again re-shows it without recomputing.

Needs anyplotlib with Plot3D.set_rotation / set_drag_mode / add_patch
(CSSFrancis/anyplotlib#80, #81).
reflectors_from_phase removed Friedel duplicates by LINE alone, keeping the
first reflector along each direction. (100), (200) and (400) share a line,
and for fcc the extinct (100) is listed first, so the real {200} band was
dropped for a weightless one; {220} went the same way behind (110). [001],
a 4-fold zone axis, ended up on no band at all, and every dictionary the
EBSD wizard built from an fcc or bcc CIF lacked its second- and third-
strongest band families.

Extinct reflections are now removed before the dedupe, and only true
Friedel pairs (same line AND same d) are merged, so a higher order along a
line stays as its own, wider band. The hkl labels were also truncated with
astype(int) (0.9999 -> 0) and are now rounded.
…ector

Clicking a phase's structure in the Composition dock pops out a card beside
the sidebar with three linked panes: the master pattern on a sphere (with the
detector's outline fixed to the microscope), the unit cell, and the detector
pattern. Dragging either 3-D pane turns the crystal in both and repaints the
detector. Several open phases stack. It is part of the phase's set-up, so it
is a host:"phase" figure in the pop-out, never a window.

Under the panes:
- SEM / TEM, with that microscope's set-up (spyde/ebsd/microscope.py): each
  field reads its metadata key, shows whether the value came from metadata,
  the data, or a default, and writes back when edited. SEM uses the sample
  and detector tilts (the sample normal 90 - tilt + detector tilt off the
  screen normal, above the pattern centre); TEM uses camera length, screen
  width and stage tilts.
- Kinematic bands or the full dynamical master pattern from de_ebsd when it
  is installed (SEM only: it is a backscatter master pattern). Both are
  sampled at the same directions; de_ebsd's crystal frame was checked against
  orix's (best match at zero offset).
- Kinematic diffraction spots on the detector in TEM (spyde/ebsd/spots.py).

The preview is pinned to simulate_patterns at the composed orientation, both
untilted and at 70 degrees. PhaseViewerCard takes only the set-up, the figure
and a change callback, so another host (Autopilot) can mount it as is.
There is no SEM/TEM switch: an EBSD scan or SEM metadata is SEM, anything
else TEM. The geometry is only needed to match real data, so it sits
folded under the master-pattern choice with a one-line summary and a count
of fields still on defaults.

SEM geometry now has all four of kikuchipy's angles (sample tilt, detector
tilt, azimuthal, twist), with the sample-to-detector rotation ported from
kikuchipy and pinned against it to 1e-12. A kikuchipy EBSD signal's own
detector supplies the angles and pattern centre as recorded data.

The 3-D panes are drawn in the detector frame, looking straight at the
screen with its own up, so the sphere reads like the screen whatever the
angles; the crystal is kept in the sample frame, so moving the detector
turns it as the detector sees it rather than turning the crystal.
The pattern centre is one point, so x, y and z sit in a single labelled row under the detector angles instead of scattered through the grid.
A "Solve from data" button beside the pattern centre reads 25 patterns
spread over the scan, seeds their orientations by dictionary indexing
against the phase's dynamical master pattern, and fits one shared centre
with de_ebsd. The centre is written to the metadata only when the fit
reaches 0.2: kikuchipy's 60x60 nickel scan reaches 0.08 while wandering
0.05 from its recorded centre, and a weak fit must not overwrite a good
guess. The crystal turns to the centre pattern's orientation.

Needs de_ebsd's coarse-to-fine centre fit; with it, noisy synthetic Ag
patterns recover a centre 0.03 off to 0.0002.
…olve

On kikuchipy's real Ni calibration patterns (nine, 480x480), the dictionary
seeds were right for only 5 of 9 patterns at the true centre, and 0 of 9
from 0.03 off, with just the per-pattern background removed; the centre fit
then had nothing to refine. Subtracting the mean of the calibration
patterns as a static background makes them 9 of 9 (8 of 9), the same as
the background recorded with the scan.

With it, the solve lands within 0.002 of kikuchipy's own refined centre
from four starts up to 0.05 off, at fits of 0.35-0.46. Failures stop near
0.08, so the 0.2 trust gate separates them.
A line scan got five patterns, too few to average their bands away into a
static background; it now gets the 25 a map does.
The band geometry dotted detector-frame rays with sample-frame plane
normals, which is the identity sample-to-detector rotation: every
simulated pattern, dictionary entry and drawn band line was ~20° off a
real 70° set-up, while all three still agreed with one another.

simulate_patterns, band_lines, zone_axis_points, BandSimulator,
simulate_dictionary and refine_orientations now take sample_tilt,
detector_tilt, azimuthal and twist (defaults 70, 0, 0, 0, the SEM
defaults in microscope.FIELDS) and apply kikuchipy's sample-to-detector
rotation: rays are carried into the sample frame for the per-pixel
simulators, normals into the detector frame for the closed-form lines.
The EBSD wizard reads the angles from the scan's microscope set-up and
passes them to the dictionary, the refinement and the band overlay; the
synthetic EBSD scan is rendered at the default 70° tilt.

Against kikuchipy patterns of ferrite (60x60, PC 0.5/0.3/0.6, 20 kV) the
NCC at the true orientation goes from -0.10..0.19 to 0.74..0.82; on
de-twin's duplex-steel patterns from -0.01 to 0.74 mean.
The centre fit only polishes, moving the centre a few hundredths: from
the usual (0.5, 0.5, 0.55) it cannot reach kikuchipy's Ni scan's
(0.42, 0.21, 0.50) or de-twin's (0.5, 0.3, 0.6), and stops near a fit of
0.1. search_pattern_centre first ranks centres on a coarse grid and two
finer ones by how far each pattern's best dictionary match stands above
its other matches, then fits from the two best and keeps the better fit.
The raw best correlation cannot rank them: it rises with the screen
distance and peaks at the edge of any grid.

From (0.5, 0.5, 0.55) it lands within 0.0001 of the Ni centre (fit
0.46) and 0.005 of de-twin's (fit 0.23), in about 3.5 minutes on a
TITAN X. solve_pattern_centre is unchanged.
Every centre the search scored sampled the orientation fundamental zone
again: 0.8 s on the CPU, eight times the projection of the centre's
dictionary, redone for ~160 centres. The search now samples once and
scores each centre with one projection and one match, and the fits share
one sampling of the seeding dictionary. Same centres: kikuchipy's Ni
calibration patterns solve to within 0.0001 from the defaults in 26 s
(was ~3.5 min); de-twin's camera frames to (0.5003, 0.2991, 0.5995) in
22 s (was 143 s).

This branch has not been deployed

No deployments
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