optics-rs
Rust port of the EPICS synApps optics module for synchrotron beamline optical device control.
Overview
optics-rs provides record types, state machine controllers, and device drivers for monochromators, slits, filters, diffractometer tables, beam position monitors, and other optical components.
| Component | Rust module | Original |
|---|---|---|
| 6-DOF optical table | records::table |
tableRecord.c |
| 3x3 matrix math | math::matrix3 |
matrix3.c |
| 4-circle orientation | math::orient |
orient.c |
| X-ray absorption data | data::chantler |
chantler.c |
| Kohzu monochromator | snl::kohzu_ctl |
kohzuCtl.st |
| Kohzu (soft motors) | snl::kohzu_ctl_soft |
kohzuCtl_soft.st |
| HR analyzer crystal | snl::hr_ctl |
hrCtl.st |
| Multi-layer mono | snl::ml_mono_ctl |
ml_monoCtl.st |
| 4-circle diffractometer | snl::orient |
orient_st.st |
| Auto filter selection | snl::filter_drive |
filterDrive.st |
| XIA PF4 dual filter | snl::pf4 |
pf4.st |
| Ion chamber I0 | snl::io |
Io.st |
| Coarse+fine flexure | snl::flex_combined_motion |
flexCombinedMotion.st |
| HSC-1 slit controller | drivers::hsc |
xiahsc.st / xia_slit.st |
| Quad X-ray BPM | drivers::qxbpm |
sncqxbpm.st |
Architecture
The original C module mixed three concerns into SNL (State Notation Language) programs: device I/O, control logic, and physics calculations. This Rust port separates them:
records/ Pure EPICS record types (table)
math/ Physics calculations (matrix3, orient)
data/ Reference data tables (chantler X-ray absorption)
snl/ Control logic as async state machines (epics-ca-rs)
drivers/ Device I/O as asyn port drivers (SimHsc, SimQxbpm)
db/ 36 database templates from the original module
State machines (snl/) monitor PVs and drive motors. They contain no I/O
code and no EPICS record logic, only the control algorithm.
Port drivers (drivers/) own the hardware protocol. Each has a simulation
backend for testing without hardware.
Usage in st.cmd
State machines (control logic)
Start with seqStart, the Rust equivalent of the C EPICS seq command:
# Kohzu double-crystal monochromator
)
# High-resolution analyzer
)
# Multi-layer monochromator
)
# 4-circle diffractometer
)
# Automatic filter selection (8 filters)
)
# XIA PF4 dual filter bank
)
# Ion chamber intensity
)
# Coarse+fine flexure stage
)
Serial device drivers
HSC-1 slit controller
# Simulation (no hardware)
)
# Real hardware
)
# Load slit database
)
Quad X-ray BPM
# Simulation (beam at center)
)
# Real hardware
)
# Load BPM database
)
Table record
The 6-DOF optical table record is registered as a record type:
// In your IOC binary
use TableRecord;
app = app.register_record_type;
# st.cmd
)
Switching from simulation to real hardware
Simulation and real hardware use the same driver, database, and state
machines. Only the Create command changes:
# Development / testing
)
)
)
# Production (same DB, same seqStart, different drivers)
# motorCreate("dcm_theta", "/dev/ttyUSB0", ...)
# hscCreate("HSC1", "/dev/ttyUSB1", 9600, 100)
# qxbpmCreate("QXBPM1", "/dev/ttyUSB2", 9600, 100)
Available seqStart programs
| Program | Required macros | Optional macros |
|---|---|---|
kohzuCtl |
P, M_THETA, M_Y, M_Z | GEOM |
kohzuCtl_soft |
P, M_THETA, M_Y, M_Z | MONO, GEOM |
hrCtl |
P, M_PHI1, M_PHI2 | N |
ml_monoCtl |
P, M_THETA | M_THETA2, M_Y, M_Z, Y_OFFSET, GEOM |
orient |
P, PM, mTTH, mTH, mCHI, mPHI | |
filterDrive |
P, R | N |
pf4 |
P, B | H |
Io |
P | MONO, VSC |
flexCombinedMotion |
P, M, FM, CM | CAP |
Database templates
36 templates are bundled in the db/ directory. Key templates:
| Template | Description |
|---|---|
kohzuSeq.db |
Kohzu DCM (60 records: energy, wavelength, Bragg angle) |
table.db |
6-DOF optical table |
2slit.db |
Two-blade slit (gap/center) |
orient.db |
Crystal orientation matrix |
hrSeq.db |
High-resolution monochromator |
ml_monoSeq.db |
Multi-layer monochromator |
filterDrive.db |
Filter selection |
pf4bank.db / pf4common.db |
XIA PF4 filter banks |
fb_epid.db |
Feedback PID loop |
xiahsc.db |
XIA HSC-1 slit |
xia_slit.db |
XIA slit with scan support |
qxbpm.db |
Quad BPM |
bragg.db |
Simple Bragg angle calculation |
Io.db |
Ion chamber |
SGM.db |
Spherical grating monochromator |
Testing
362 tests covering:
- Golden tests (46): Rust output compared against values from the original
C
tableRecord.c, compiled and executed independently. Tolerance: 1e-10. - Matrix/orient (10): Round-trip verification against published crystallographic data (Si, Be, VO2) from the original optics test suite.
- Chantler (8): X-ray absorption coefficients for 22 elements.
- State machines (127): Physics calculations for each controller.
- Serial protocol (111): Command formatting, response parsing, coordinate math for HSC-1 and QXBPM.
- Port drivers (23): SimHsc and SimQxbpm parameter updates and poll loops.
- Table record (32): Field access, geometry modes, process logic.
- seq_runner (3): Macro parsing, program dispatch.
Quick Start: Kohzu DCM Simulation
Build and run the mini-beamline IOC with a simulated Kohzu double-crystal monochromator:
In another terminal, set the DCM to Auto mode and change energy:
# Switch to Auto mode (Manual mode calculates but doesn't move motors)
# Set energy to 8.0 keV — the theta motor moves to the Bragg angle
Monitor the DCM motor and readback PVs:
# Watch the theta motor position (SimMotor moves in real time)
# Read back the computed values
Change energy and watch the motor track:
Key PVs
| PV | Type | Description |
|---|---|---|
mini:BraggEAO |
ao | Energy setpoint (keV) |
mini:BraggERdbkAO |
ao | Energy readback (keV) |
mini:BraggLambdaAO |
ao | Wavelength setpoint (A) |
mini:BraggLambdaRdbkAO |
ao | Wavelength readback (A) |
mini:BraggThetaAO |
ao | Theta setpoint (deg) |
mini:BraggThetaRdbkAO |
ao | Theta readback (deg) |
mini:KohzuModeBO |
bo | Manual(0) / Auto(1) |
mini:KohzuMoving |
busy | Moving indicator |
mini:KohzuSeqMsg1SI |
stringin | Status message |
mini:dcm:theta |
motor | Theta motor record |
mini:dcm:theta.RBV |
motor | Theta motor readback |
mini:dcm:y |
motor | Y motor record |
mini:dcm:z |
motor | Z motor record |
Crystal parameters
Default: Si (111), lattice constant a = 5.43102 A
# Change to Si (220)
# Check the 2d spacing