Make the first-grid y padding asymmetric: the bottom (far end of the n_y scan)
can be padded more than the top via daq.auto_raster.grid_padding_fraction_y_
bottom (defaults to grid_padding_fraction_y, so symmetric unless set higher).
The top padding still shifts smargon_top_left; the extra bottom padding only
grows n_y.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the loop_face-only box padding with a single grid padding applied to
the first auto-center grid scan for any loop box (loop_all or loop_face). It
pads each side by a fraction of the grid size (daq.auto_raster.grid_padding_
fraction_x / _y, default 0.15), with a minimum of one cell per side, and
extends *before* cell 0 too so smargon_top_left shifts outward. Manual grid
(get_ml_bounding_box) is unchanged (grid_padding defaults off).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The 2nd-stage vertical line scan (n_x=1, height from the ML box) padded its
height by a hardcoded 0.10 each side (20% total), which was often too short to
cover the whole loop. Read the per-side fraction from
daq.auto_raster.line_scan_y_padding_fraction (default 0.15) so it can be tuned
per beamline.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The play/pause toggle ran its start-time checks (beamline state, busy, baton,
maintenance) before the pause branch, so when running you could be blocked from
pausing if the beamline was in the wrong state or busy.
Handle the pause toggle first and return immediately (unconditional), and run
the start-condition gates only when starting/resuming from paused.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Before the first auto-center raster, zoom so the loop fills at most 1/3 of the
frame, pad loop_face grids, and optionally extend the grid to cover crystals
outside the loop.
- ml_bounding_box: add build_ml_raster_plan() (single prediction via
predict_all_best) returning the grid request + raw loop_all/loop_face boxes +
image size. Grid box is loop_face (else loop_all); loop_face is padded by
daq.auto_raster.loop_face_padding_fraction (15% default); when
daq.auto_raster.include_crystal is set, the grid is unioned with any crystal
boxes lying beyond the loop. get_ml_bounding_box (manual button / endpoint)
is unchanged.
- config: add zoom_for_pixel_to_mm(), the inverse of pixel_to_mm.
- raster service execute_auto_center: after the first detection (reused, no
re-predict), pick loop_all if detected and not clipped at the frame edge else
loop_face, compute the zoom that makes its larger side 1/3 of the frame, clamp
to daq.hardware.zoom_min/max, set zoom and re-expose.
- x06da.yaml: zoom_min/max + daq.auto_raster block.
- tests for box selection, padding, crystal union and the clipped-loop_all rule.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- promote crystal score to its own RasterGridMetric.RASTER_SCORE; first and
default metric in the GUI dropdown; restore PR to original "Profile Radius"
- send per-cell raster score to AareDB via RasterPayloadModel
- split raster_highest_score (compute_crystal_score_array) from
raster_centre_of_mass (restored to ndimage.center_of_mass); use score-based
targeting for where-to-collect in both simulation and real mode
- add tests covering compute_crystal_score_array and raster_highest_score
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The detector_distance_mm sent to JFJoch and written to the DB came from the
live detector readback (diffraction.dtz_mm) captured before the detector
finished moving, so a scan requested at e.g. 100 mm could be recorded at the
old position (e.g. 800 mm).
- JFJoch + DB now read the validated request target (request.dtz) instead of
the live diffraction.dtz_mm; diffraction.dtz_mm stays live for the
local-contact readout.
- jfjoch: raise if request.dtz is unset (setup_datacollection must validate it
first) instead of silently falling back to the live readback.
- raster + rotation services: wait for the detector to reach request.dtz
(set_dtz wait=True) right before triggering the scan, since the sa2dc move is
non-blocking. (Raster setup-before-measure reorder landed earlier in daq.py.)
- tests: request.dtz now required in jfjoch/aaredb tests; xtal-snapshot exposure
assertion updated to 1 ms.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
BeamlineBusyException / TellCommandWhileBusyException fire when a user triggers
an action while the beamline or robot is busy. These are blocking-but-benign
("you can't do that right now"), so route them to the log + status bar instead
of a modal pop-up (and without the defensive automation pause), regardless of
the exception's critical flag. Genuine failures (e.g. No Pin in Gripper) still
get the modal.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Commit 071b4ab made mount() return SUCCESS as soon as it saw the intermediate
TELL "state"/Busy event, before the later "Gripper detection" event is read,
so an empty-gripper mount completed silently with no MountingFailed/pop-up.
check_command_ok blocks (wait_not_busy) until the mount sequence finishes, so
after it returns the robot's own record is authoritative: if get_mounted_sample()
is None the gripper was empty -> return NO_PIN_IN_GRIPPER, which the mounting
service maps to MountingFailed("No Pin in Gripper"). Covers manual and automation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fix the GUI pop-up path and add personnel-safety-system (PSS) gating so
door-open / beam-down / shutter-closed conditions are surfaced and acted on.
- exception pop-ups: connect the previously-orphaned http_error signal;
failed user operations now raise a modal dialog, background/polling errors
a non-modal banner.
- PSS device (devices/pss_state.py) reading EH1-PSYS PROHIBITED-STATE /
ALARM-STATE; new critical DoorSafetyError + DOOR_SAFETY_ERROR code.
- mounting service blocks mount/unmount when the hutch is not prohibited or
an alarm is active; /status now publishes pss_prohibited / pss_alarm.
- GUI blocks manual mount/unmount and the automation Run button immediately
(pop-up) on door-open, and shows a warning banner while an alarm is active.
- centralise per-action precondition checks (ring current, safety shutter,
hutch door) into one combined "continue?" dialog with a session-global
"don't ask again for 1 hour" snooze, applied to all data-collection buttons.
- live automation pauses and auto-resumes on bad conditions (beam, shutter,
door, robot) with continue-now / stop overrides, gated by a default-on
"Pause on bad conditions" checkbox replacing the dead CHECK_ENABLED constant.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add DbOverrideLineEdit: a numeric field holding both a database value and
the user's value, driven by a per-tab Database/User-values toggle. The
user's value persists across samples, can be reverted to the database
value, and recovered again - replacing the clunky per-field checkboxes.
Fix the dtz<->resolution coupling so editing one updates the other in both
Database and User modes (previously it broke whenever a value was
overridden). Wire resolution, detector distance, transmission, exposure,
rotation total/image angle and the raster grid element size through the
new widget; other panels are untouched.
Add tests covering persist/revert/recover, the toggle's downstream emit,
the dtz/resolution coupling in both modes, and cross-sample persistence.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>