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