Orient-a-Laue - Help & Theory

Core Functionality

  1. Simulation: Define a lattice and detector to predict a Laue pattern (virtual goniometer + polychromatic beam).
  2. Indexing: Load a real image, pick peaks, and solve the unknown crystal orientation; then simulate and overlay spots for verification.
  3. Orientation: Calculate the goniometer angles required to geometrically align a specific (h,k,l) plane normal with the detector normal, and apply them on demand.

The controls are organized into five tabs — System, Sample, Measure, Search, Orient — reflecting the order you'd typically move through a real experiment. The left panel is resizable (drag its right edge) and the app supports both dark and light themes (toggle icon, top right).

Two Orientations: how rotations are applied

Base Orientation (unknown): The sample's as-mounted orientation found by the search. Selecting a solution in the Search tab sets this as the internal base matrix, and also unlocks the Orient tab.

Goniometer Angles (knobs): The X,Y,Z sliders in the System tab. They rotate on top of the Base Orientation and also respond to canvas drag. A Reset button next to the label zeros all three at once.

Total rotation used in simulation = Base then Goniometer (XYZ Euler). After you select a solution, the sliders are reset to 0 so the display shows the solved orientation. Moving a slider then offsets from that base.

The Orient tab's "Calculate Goniometer Angles" only previews the X/Y/Z needed to reach a target (h,k,l) — it does not move anything. The goniometer only changes when you press Set Orientation.

Typical workflow (indexing)

  1. Sample tab. Choose the Bravais lattice and enter cell parameters. The Calc. Spot Size slider controls how big simulated (yellow) spots are drawn — set it to 0 to hide them entirely.
  2. System tab. Set the X-ray source band (λ_min–λ_max) and the detector Angle / Distance to match your experiment. The Goniometer Angles here start at 0,0,0 (use Reset to return to that at any time).
  3. Measure → Load Image. The file name appears below the button. Loading a new image resets everything — center, scale, peaks, solutions, and the Orient tab all clear. If spots are white on black, check Invert Image.
  4. 1. Set Center. Click the beam center on the image.
  5. Set Scale. Drag the blue crosshair to a known reference point and enter its real U (mm), V (mm) relative to the center.
  6. Experimental Peaks. Click Find Peaks for automatic detection, or + Add Peaks… to place them by hand — the cursor becomes a crosshair, the button itself turns into Cancel, and you can keep clicking to add multiple points before pressing Cancel to stop. Peak Threshold (20–90%) sets how faint a spot can be and still count; dragging it live-reruns Find Peaks. Peak Marker Size is purely visual (mm, 0 = hidden) and doesn't affect detection.
  7. Search tab. Search Orientation enables once an image is loaded with center, scale, and at least 4 peaks. The first search after loading an image (or changing lattice/Bravais type) takes a few seconds to build an internal reflection library; later searches reuse it. Click a row in the results to select it — this sets the Base Orientation and unlocks the Orient tab.
  8. Orient tab (optional). Only usable after selecting a solution. Enter a target (h,k,l) and click Calculate Goniometer Angles to preview the X/Y/Z needed to align that plane's normal with the detector normal. Click Set Orientation to actually apply those angles to the System tab's goniometer.
  9. Report. The printer icon (top right, next to the theme toggle and help button) saves a PDF with parameters, the peak table, the best solution's matches, and a summary of all solutions.

UI reference (tabs)

System

Sample

Measure

Search

Orient

Mathematical model

1) Unit cell → reciprocal basis

Given cell a,b,c and angles α,β,γ, direct vectors are

// direct basis (Å)
a = (a, 0, 0)
b = (b cosγ, b sinγ, 0)
c = (c cosβ, c (cosα − cosβ cosγ)/sinγ, V/(a b sinγ))

V = a b c √(1 − cos²α − cos²β − cos²γ + 2 cosα cosβ cosγ)

Reciprocal basis vectors (Å⁻¹) are

a* = (b × c)/V ,  b* = (c × a)/V ,  c* = (a × b)/V

Any reflection (h,k,l) maps to g₀ = h a* + k b* + l c*.

2) Systematic absences (Bravais rules)

TypeCondition
Pall (h,k,l) allowed
Ih + k + l even
Fh, k, l all even or all odd
Ch + k even
R−h + k + l ≡ 0 (mod 3)

3) Orientation stacking

Reflections are rotated first by the Base Orientation U (from the solver), then by the goniometer Euler rotation R(X,Y,Z). The goniometer rotations are mathematically applied in the sequence: first around X, then around Y, and finally around Z.

g = R(X,Y,Z) · U · g₀

4) Laue condition, wavelength band, and detector hit

Beam points along +X. With unit wavevectors k̂_in = (1,0,0) and k̂_out, define the (normalized) scattering vector ĝ = k̂_out − k̂_in. For a given lattice vector g (Å⁻¹), elastic diffraction requires

2 k_in · g + |g|² = 0 ,  with k_in = (1/λ, 0, 0)

Solving for the required wavenumber gives

k = − |g|² / (2 gₓ)

The diffracted ray is k_out = g + (k,0,0). The detector plane is defined by its angle φ (0° to 180°) and distance D.

// Detector plane normal and u-axis (horizontal)
n̂ = (cosφ, sinφ, 0)
û = (-sinφ, cosφ, 0)

The intersection P_hit is found by solving t for the ray P(t) = t · k_out and the plane P · n̂ = D.

v = P_hit_z   // Vertical coordinate is the Z component
u = P_hit · û   // Horizontal coordinate
(x₂d, y₂d) = (u, v) // These are the plotted (mm) coordinates

5) Experimental geometry → scattering vectors

From a measured spot at detector coordinates (u_mm, v_mm) relative to the center, we reconstruct the 3D scattering vector.

// φ is the detector angle, D is distance
n̂ = (cosφ, sinφ, 0)
û = (-sinφ, cosφ, 0)
v̂ = (0, 0, 1)

// Reconstruct 3D spot position from (u,v)
P_center = D · n̂
P_hit = P_center + (u_mm · û) + (v_mm · v̂)

k̂_out = normalize( P_hit )
ĝ_exp = normalize( k̂_out − (1,0,0) )  // used for orientation solving

6) Pixel ↔ millimeter conversion

After you click the beam center (pixels) and place a scale point with known (mm), the app sets independent scale factors for U and V:

pixels_per_mm_x = (x_px − x0_px) / U_mm
pixels_per_mm_y = −(y_px − y0_px) / V_mm   // minus because image Y is down

Orientation search (what "Search Orientation" does)

The search uses a Hough-transform-style voting scheme: it looks for a single rotation that explains many picked peaks simultaneously, rather than trusting any one pair of spots.

  1. Build a direction library (cached). Every (h,k,l) with indices up to ±8 — filtered by the Bravais systematic-absence rule — is converted to a unit reciprocal-space direction. Building and sorting this library is the slow part, so it's cached and only rebuilt when the lattice or Bravais type changes. Expect the first search after loading an image (or changing the lattice) to take a few seconds; later searches reuse the cache and are much faster.
  2. Reconstruct experimental directions. Each picked peak's detector position is converted to a scattering-vector direction ĝ_exp — direction only, since the specific wavelength that produced any given spot isn't known (see §5 of the Mathematical Model).
  3. Vote. A handful of peaks are tried in turn as a "reference" spot. For each candidate library direction as that spot's hypothesized (h,k,l), the exact rotation angle that would align every other picked peak to some library direction is computed directly from geometry (a closed-form calculation, not a scan). Hypotheses where enough distinct peaks agree on the same angle become candidate orientations.
  4. Refine. Each candidate is polished ICP-style: simulate the full pattern, match it against all picked peaks, refit the rotation using every matched pair (not just the original two), and repeat until it converges.
  5. Score, cluster, and rank. Refined candidates are scored by RMS position error and fraction of peaks matched. The algorithm then clusters solutions by comparing their simulated diffraction patterns. Solutions that produce identical spot patterns (e.g., due to symmetry) or are within ~3° of an already-kept solution are merged into a single cluster. The top 10 unique clusters are listed.
Why not just check every pair of low-index reflections?

An earlier version of this tool did exactly that — seeding candidates from pairs of low-index reflections (|h,k,l| ≤ 2) ranked by "simplicity." It worked for generic orientations but failed for patterns near a symmetric zone axis: thousands of spurious low-index pairs coincidentally matched the observed angles and crowded out the true match, which was often higher-index. Requiring several spots to agree on the same rotation, rather than trusting a single coincidental pair, is what fixes this.

Symmetry-equivalent solutions are clustered. A cubic lattice has 24 proper rotations indistinguishable from diffraction data alone. Because the algorithm compares the simulated spot patterns of candidate solutions, it recognizes when different Euler angles produce the same physical pattern on the detector and compacts these degenerate solutions into a single cluster.

Peak count matters. At least 4 peaks are required to enable a search, but the vote is far more reliable with 8–20, spread across different quadrants of the pattern rather than clustered together.

Peak finder details

Report contents

Click the printer icon (top right) to generate the report.

  1. Detector snapshot with overlays.
  2. Simulation + analysis parameters (lattice, λ band, D, Angle, center/scale).
  3. Experimental peak list in (U, V) mm (+ raw pixels).
  4. Best solution details: each peak's assigned (h,k,l), simulated (U, V) and error (mm).
  5. All solutions summary.

Troubleshooting

No or poor solutions

Clicking "Calculate Goniometer Angles" doesn't move anything

A spot doesn't appear after orienting to (h,k,l)

Conventions & hints