Files
AareDAQ/docs/configurable_values_inventory.md
T
perl_d ff00a33806
CI / lint (push) Skipped
CI / test (3.12) (push) Skipped
CI / test (3.13) (push) Skipped
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
docs: add inventory of config values for moving to managed config
2026-10-13 14:45:16 +02:00

20 KiB
Raw Blame History

Inventory of user-configurable values (aaredaq + aarecommon)

Everything that behaves like a setting but is fixed in code, plus a map of the configuration surfaces that already exist and how well the code actually lines up with them. Line numbers are from the working tree on 2026-10-13.

Scope: aaredaq/src, aarecommon/src. Pydantic request/response model defaults are excluded per the brief; the handful of settings models whose defaults are the live policy are listed in §6.


1. Configuration surfaces that already exist

Surface Mechanism Where
Per-beamline YAML cfg_get("dotted.key", default) → BeamlineYAMLConfig aarecommon/config/beamline.py:61, files in aarecommon/config/beamline_configs/{x10sa,x06da,x06sa,simulated}.yaml
Local-contact Redis config LocalContactConfigModel stored at <BL>:local_contact_config aaredaq/daq/config_model.py, read config.py:1203
Operator-set Redis state <BL>:auto_params (SimpleScanParameters), <BL>:settings, <BL>:simple_input_params, <BL>:runtime:simulate:<dev> config.py:963, :630, :948, :1050
Environment BEAMLINE, JWT_AAREDAQ_KEY, AAREDB_SHARED_PASSWORD, AAREDB_USERNAME/AAREDB_PASSWORD, AARE_RECOVERY_CODE, AARE_BEAMLINE, USER aarecommon/config/beamline.py:30; beamline_dispatch/default/beamline_dispatch.py:20; aaredb.py:65,132,152,331,335,407,411; server.py:179; gui/threads/daq_worker.py:1249; aarecommon/models/auth.py:67
Beam-centre calibration data beam_centres.json aarecommon/config/beamline_configs/beam_centres.json

1.1 LocalContactConfigModel — the only Redis-backed, UI-editable policy today

Field Default Bounds
mount_to_center_sleep_s 0.0 0–120
line_scan_loop_face_y_padding_fraction_each_side 0.5 0–5
line_scan_loop_all_y_padding_fraction_each_side 0.5 0–5

Three fields. Almost everything in §3–§5 is a candidate to join them.

1.2 Keys the YAMLs define

x10sa.yaml / x06da.yaml share a nested schema (gui.*, shared.*, daq.hardware.*, daq.data_collection_settings.*, daq.auto_raster.*). simulated.yaml is a flat, unrelated schema (redis_host, smargon_base, tell_url, …) — see §2.3.


2. Config-integrity findings (code vs YAML)

Produced by diffing every cfg_get("…") key in code against the flattened YAMLs.

2.1 Keys read in code that no YAML defines — the code default always wins

Key read Where Falls back to Likely intended key
daq.data_collection_settings.default_rotation_settings.incr_omega_deg daq.py:2334 0.2 YAML has increment_omega_deg
daq.data_collection_settings.default_raster_settings.{dtz,exp_time_s,transmission} gui/scan_logic/raster_grid_manager.py:143-149 200.0 / 0.01 / 1.0 YAML has default_raster_scan_settings
daq.data_collection_settings.default_screening_settings.exp_time_s gui/panels/rotation_data_collection.py:116 0.1 no screening block exists in any YAML
daq.auto_raster.exclude_pin_x_overlap operations/common/ml_bounding_box.py:475 True —
daq.auto_raster.exclude_pin_max_overlap_fraction operations/common/ml_bounding_box.py:480 0.75 —
daq.hardware.jfjoch_url aarecommon/config/beamline.py:45-49 per-beamline host YAML has shared.jfjoch.jfjoch_url, which beamline.py:77 reads — two readers, two keys
endpoints.smargon_base, epics.pv_prefix aarecommon/config/beamline.py:64-65 None legacy

2.2 Keys defined in a YAML that nothing reads — dead config

File Key Note
x06da daq.detector_limit_modifier = 2.0 Code reads daq.detector_distance_limit_modifier (daq/devices.py:51). x10sa spells it right. x06da silently runs with modifier 1.0.
x06da daq.auto_raster.line_scan_y_padding_fraction = 0.15 Superseded by the two *_each_side fields in LocalContactConfigModel
x06da daq.hardware.zoom_min = 1, zoom_max = 1000 never read
x06da daq.hardware.sam_cam = 'white_balance_ratio = 1.233' never read
both daq.db.aaredb_url aaredb.py:44 hard-codes the host as a default arg instead
both daq.maximum_flux never read
both beamline_id never read

2.3 Per-beamline gaps

  • x10sa has no daq.auto_raster.* block, so grid padding (0.15/0.15/=top) and include_crystal=False come from code (ml_bounding_box.py:277-279, 455). May be intentional; it is invisible.
  • gui.cameras.secondary_beamline_camera_url exists only in x06da and its only reader is commented out (gui/main_window.py:520).
  • Under BEAMLINE=SIMULATED every cfg_get misses because simulated.yaml uses a different schema, so the simulated beamline runs entirely on the in-code fallbacks in §3.

2.4 Same concept, different fallbacks

Concept Values Where
Default raster dtz 200 · 250 · 200.0 daq.py:2093, daq.py:2318, raster_grid_manager.py:149
Default rotation dtz 250 (daq) · 110 (dispatch) · 150 (SimpleScanParameters) daq.py:2330, beamline_dispatch/default:60, aarecommon/models/models.py:700
Face-detection sweep model default steps=14, step_size=15 vs inline steps=7, step_size=30 operations/face_detection/models.py:14-16 vs daq.py:2501

3. Hard-coded values — automation & beamline policy

These are the strongest candidates for LocalContactConfigModel or YAML.

3.1 Automation sequence (daq.py)

Value Location Note
MIN_SPOTS_LOW_RES_THRESHOLD = 10.0 daq.py:280 crystal-present threshold
AUTOMATION_BUSY_TIMEOUT_S = 600 daq.py:281
MANUAL_RASTER_BUSY_TIMEOUT_S = 600 daq.py:282
AUTO_RASTER_MAX_IMAGES = 4500 daq.py:283 grid is scaled down to fit (ml_bounding_box.py:132)
AUTO_RASTER_MIN_CELL_SIZE_MM = 0.005 daq.py:284
AUTO_RASTER_SKIP_IF_EXCEED_MAX_IMAGE_THRESHOLD = True daq.py:285 behaviour flag
_sample_sync_min_interval_s = 2.0 daq.py:305 TELL sync rate limit
smargon trace path /sls/mx/applications/logs/smargon_trace.csv daq.py:301 (also gui/panels/smargon_trace_panel.py:520)
rotation min_exp_time = 0.0011 daq.py:1446 silently clamps the request
resolution fudge new_res = 1/((1/res) + 0.01) daq.py:1666 spreadsheet target-resolution → dtz
omega sanity bound -2000 < val < 2000 daq.py:1702
face detection steps=7, step_size=30, face_min_ratio=0.3 daq.py:2501 overrides the model defaults
run token secrets.token_hex(3) daq.py:2518 6 hex chars shared by raster+rotation
auto-raster seed grid = beam_size × 0.5 daq.py:2534
autofocus settle_time_s = 1.0 daq.py:1901
screenshot settle_time_s = 0.2 daq.py:2262, :2272; operations/screenshot/service.py:61, :67
mount-to-centre, unmount waits sleep(2), sleep(0.2) daq.py:1980, :2574, :1740, :1749
smargon_wait(timeout=180) daq.py:2016; raster/service.py:534
default dtz min/max fallback 100 / 1000 daq.py:3028-3029 YAML overrides exist
raster/rotation default fallbacks daq.py:2312-2337 see §2.4

3.2 Mounting (operations/mounting/service.py)

Value Location
DRY_AFTER_FAIL_COUNT = 3 :14
STOP_AFTER_FAIL_COUNT = 5 :15
mount timeout=360.0 :83
unmount timeout=60.0 :65, :154, :173, :186
magnet-sensor check timeout=10.0 (default 1.0) :146 (def :33)
TELL post-mount sleep(0.1) :41

3.3 Raster (operations/raster/service.py, models.py)

Value Location Note
Y re-target threshold beam_size.y × 2.0 :302; and max(beam.y×2.0, cell.y×4.0) :736
line-scan cell height beam_size.y × 0.25 :730
per-row overhead n_y × 0.3 s :441 time estimate
total-time cap > 1200 s :446 refuses long rasters
detector timeout expected × 1.1 + 60 :428
wait_till_running(timeout=60.0) :506; rotation/service.py:35
aerotech wait_till_done(timeout=60) :438
wait_for_screenshot_s = 0.3 raster/models.py:26
sleep(0.2) settle :644

3.4 Auto-raster bounding box (operations/common/ml_bounding_box.py)

Value Location Note
grid padding x / y / y_bottom 0.15 / 0.15 / =y :277-279 YAML-overridable (x06da only)
include_crystal = False :455 YAML-overridable (x06da only)
exclude_pin_x_overlap = True :475 no YAML key anywhere
exclude_pin_max_overlap_fraction = 0.75 :480 no YAML key anywhere
line-scan cell = beam_size × 0.8 :258
line-scan exp_time_s=0.01, transmission=1.0 :378-379 fixed regardless of beamline defaults
image-count scale (count/max)**0.5 :132
sleep(0.2) :163, :414

3.5 Loop centering & face detection

Value Location Note
overlap_with_pin = 0.5 operations/loop_centering/models.py:36 settings-model default
zoom_value = 200.0 :38
max_attempts = 2 :39
target_tolerance_um = 500.0 :40
sleep(0.2) loop_centering/service.py:100
face detection steps=14, step_size=15, face_min_ratio=0.3 face_detection/models.py:14-16 overridden at daq.py:2501
angle wrap < 720 face_detection/service.py:91
centre-correction tolerance=0.2 :129 (def :51)
MAD outlier k=3.5 face_detection/utils.py:39, :69
enlargement_factor = 2 beamcenterfit.py:44 comment says 50%
ML inference conf=0.4 aarecommon/lc_infer_wrapper.py:60 detection confidence floor
RETRY_COUNT = 3, RETRY_SLEEP_S = 0.1 mlbox.py:46-47

3.6 Per-beamline dispatch defaults (aaredaq/beamline_dispatch/)

Value Location
rotation {exp_time_s: 0.04, dtz: 110, incr_omega_deg: 0.2} default/beamline_dispatch.py:60
auto-raster {exp_time_s: 0.04, transmission: 1.0, dtz: 200} default/beamline_dispatch.py:65
x10sa rotation transmission: 0.1; raster {0.02, 0.1, 200} x10sa/beamline_dispatch.py:129, :134
x06da rotation transmission: 1.0; raster {0.04, 1.0, 150} x06da/beamline_dispatch.py:126, :130
x06da detector tilt poni_rot1 = -0.001396263, poni_rot2 = -0.003839724 x06da/beamline_dispatch.py:109-110 (also aarecommon/math/diffraction_geometry.py:83-84)
x06da flux-vs-energy tables x06da/beamline_dispatch.py:10, :25

These duplicate the YAML default_*_settings blocks with different numbers (§2.4).


4. Hard-coded values — hardware, calibration, network

4.1 Lamp brightness — three disagreeing encodings

Encoding Front light Back light Location
EPICS PV predefs off 1.49 · half 2.0 · max 3.0 off 0 · half 0.98 · max 1.2 daq/devices.py:57-70
% ↔ raw conversion 0 % at ≤1.0, 100 % at ≥2.5, linear /1.5 100 % at 3.0, linear /3.0 daq.py:1767-1792
BEC device YAML userParameter on 3.0 · off 0.0 on 1.3 · off 0.0 pxii_bec/…/pxii-devices.yaml (out of scope, for comparison)

Back light "max" is 1.2 in one place, 3.0 in another, 1.3 in the third.

4.2 Other hardware constants

Value Location Note
CHI_ZERO_TOLERANCE_DEG = 1e-3 daq/devices.py:31
dtz_mod default 1.0 daq/devices.py:51 x06da YAML key misspelled (§2.2)
PV timeout=10.0 ×4 daq/devices.py:60, :67, :77, :90
det_z(..., timeout=60) daq/devices.py:305
smargon_wait(timeout=10.0) daq/devices.py:364, :371
DEFAULT_LENS_MAGNIFICATION = 10.0 config.py:53 YAML-overridable
ABR_POS_MOUNT, ABR_OMEGA_MOUNT = 0.0 config.py:47-52
SMARGON_HOME (z=18), AERO_HOME devices/smargon.py:19-20; devices/aerotech.py:10; gui/panels/smargon_trace_panel.py:33-35 three copies
SAFE_POSITION = 600 daq/workflows.py:13 detector safe dtz
dtz_safe_position fallback 300.0 config.py:1246 x06da YAML has None
area detector gain=15, expo=0.025 devices/area_detector.py:113
MIN_DTZ = 108.0 # beamline dependent gui/panels/scan_settings_panel.py:122 its own comment says so
MAX_OMEGA_SPEED_DEG_S = 500.0 gui/panels/rotation_data_collection.py:19
MIN_EXP_TIME_S = {X06DA: 1/900, X10SA: 1/120} rotation_data_collection.py:21 detector frame-rate limits
STRATEGY_MIN_EXP_TIME_S = {X06DA: 0.002}, DEFAULT_MIN_EXP_TIME_S = 0.0005, FIXED_FRAME_RATE_HZ = 100.0 gui/panels/smart_rotation_panel.py:41-48

4.3 Hosts, URLs, paths (code fallbacks)

Value Location Note
Redis port=6379, db=0 config.py:105 host is YAML-overridable, port/db are not
{bl}-redis.psi.ch, {bl}-bec-001.psi.ch config.py:104; devices/bec_worker.py:97
smargon http://{x06da,x10sa}-smargopolo.psi.ch:3000 devices/smargon.py:25, :28
aerotech http://mx-{bl}-queue-01.psi.ch:5234 devices/aerotech.py:20-26; config.py:1178
TELL http://{bl}-tell.psi.ch:22222 / http://PC17488:22222 devices/tell_backend.py:90, :92 x10sa points at a PC hostname
JFJoch sls-gpu-001/002:8080, frontends aarecommon/config/beamline.py:45-49; config.py:1184-1186
aaredb https://mx-aaredb-dmz-01.psi.ch/dispatcher aaredb.py:44; spreadsheetupdater.py:144, :168; tellupdater.py:382 YAML key exists but is unread (§2.2)
data root /sls/mx/data server.py:2366; gui/panels/file_path_panel.py:121; gui/threads/jfjoch_viewer.py:69; operations/screenshot/service.py:41 four copies
logs /sls/mx/applications/logs operations/screenshot/service.py:40; daq.py:301
BEC log path /tmp/logs devices/bec_worker.py:99
BEC device-config path template devices/bec_worker.py:346
uvicorn host="127.0.0.1", port=5210, workers=4 server.py:2625-2629 workers matters for the queue-loop design
GUI per-beamline fallbacks (DAQ URL, cert path, camera hosts, gonio id) gui/gui.py:51-97 all YAML-overridable
axis camera MJPEG params 1280x720&fps=20 gui/threads/axis_video_thread.py:34

4.4 JFJoch dataset settings (devices/jfjoch.py)

Value Location Note
pgroup fallback "p16371", sample "unknown_sample" :142-143 writes into a real pgroup when sample is unknown
data_folder routing raw/raster, raw/screening, raw :152-169 see docs/rotation_filename_path.md §6.1
max_spot_count = 1000 :198
detect_ice_rings = True :199
polarization_factor = 1.0 :204
grid snake = True, vertical = False :211, :214
omega axis vector = [-1, 0, 0] :226
wait_till_running(timeout=60) :293

5. Timeouts, polling, sessions, auth

Value Location Note
ACCESS_TOKEN_EXPIRE_MINUTES = 24*60*7 daq/auth.py:30 JWT lifetime 1 week
SESSION_EXPIRE_SECONDS = 600 auth.py:31; config.py:96 (GUI_SESSION_EXPIRE_SECONDS) duplicated
BATON_REQUEST_TIMEOUT_SECONDS = 30; refusal re-arm timeout_sec=10 auth.py:32, :423; config.py:431 default 30, +5 grace :439
grace_seconds = 60 config.py:208
STAFF_GROUP = "unx-sls_mx_bs", SUPER_USERS = [...] auth.py:34-35 identity policy in code
ALGORITHM = "HS256" auth.py:29
Redis lock timeout=10 config.py:349, :361, :383, :393, :479, :640, :645 hardware lock has no timeout (config.py:106)
_ALL_PGROUPS_TTL_S = 60.0 server.py:76
SSE poll 0.15 s; spreadsheet/ref-tools SSE 10 s; baton 0.5 s; 0.2 s server.py:283, :303; :1295, :1313; :2262; :2534, :2537
SSE_RECONNECT_DELAY_S = 5 daq/tellupdater.py:64
spreadsheet updater sleep(5) spreadsheetupdater.py:187
aaredb HTTP timeout=30 aaredb.py:338, :414
TELL command timeout=360.0; ready 30.0; probe 1.0; poll 0.01; lazy retry 2.0 devices/tell_client.py:82, :87, :202, :367; :386; tell_backend.py:65; :172; :336
smargon REST timeout=2.0; initialize(360.0) / (30.0); wait(60, tol 0.01, poll 0.01) devices/smargon.py:43, :77; :111, :235; :214, :222
aerotech wait_till_done(60) devices/aerotech.py:114
fluorimeter timeout_s=30.0 devices/fluorimeter.py:65, :91, :98, :114
ZMQ timeout_ms=2000 devices/zmq_client.py:27
motor timeout=5.0 / 300.0, poll_rate=0.01 devices/my_motor.py:9, :63, :84, :94
filter transmission timeout=60.0, fail_on_timeout=True devices/filter_transmission.py:8
wait_position(timeout=60.0) devices/workflow_tools.py:6
workflow waits 60, sleep(10.0) daq/workflows.py:163, :175, :289
BEC sleep(1) devices/bec_worker.py:566

6. Analysis thresholds (aarecommon)

Value Location Note
autofocus threshold median × 3.0 math/autofocus.py:20
ice veto spots_ice > spots × 0.8 math/find_xtal.py:147 comment says 50 %
min_efficiency = 1.0 find_xtal.py:178
min_low_res_spots = 10.0 find_xtal.py:344 same number as MIN_SPOTS_LOW_RES_THRESHOLD
mask n_sigma = 0.5; n_clusters = 3; percentile = 60.0 find_xtal.py:507, :568, :587-590
coordinate equality tol = 0.1 / 0.01 math/coordinate.py:91, :115
exception DEFAULT_CRITICALITY flags errors/exception_handler.py:14, 77, 82, 90, 133, 146, 159, 168, 177, 182, 249, 275, 299, 349, 370, 375 decide 503 vs 422 per exception class
logger levels (all DEBUG) config/logger.py:63-88 no env/YAML override

7. GUI behaviour and UX policy

Value Location Note
LOW_CURRENT_THRESHOLD = 360.0 mA gui/widgets/message_box.py:11; used panels/sample_queue_panel.py:226 gates automation start/pause
SNOOZE_SECONDS = 3600.0 message_box.py:12
TELL-warning recovery pause 600 × 1000 ms sample_queue_panel.py:59
DEFAULT_SAMPLE_ESTIMATE_S = 150.0 panels/automation_panel.py:43 ETA before data exists
dose model KDOSE_1A_PH_UM2_GY = 2000.0, GLASS_TRANSITION_K = 200.0 panels/smart_rotation_panel.py:29, :36
resolution UI VISIBLE_RES_{MIN,MAX,DEFAULT}_A = 0.8 / 10.0 / 2.0, DAQ_RES_EPS_A = 0.001, DTZ_STEP_MM = 10.0, EXP_TIME_STEP_S = 0.001 smart_rotation_panel.py:51-59
DEFAULT_ABR_STEP_UM = 5 panels/abr_tweak_panel.py:12
READBACK_GRACE_S = 1.5 panels/illumination_panel.py:11
ENERGY_AT_TARGET_TOL_KEV = 0.001 panels/monochromator_panel.py:19
filename templates "{date}/{puck}/{pos}", "{sample}"; run range 1-999 panels/file_path_panel.py:64, :77, :92 {pos} bug, see rotation_filename_path.md §6.6
status poll 500 ms; SPREADHSEET_FREQUENCY = 25 ticks (≈5 s); baton tick 1000 ms; stream restarts 1000 ms gui/threads/daq_worker.py:158, :58, :217, :1897, :2077, :2351
idle timer 60_000 ms; remote-close 1000 ms gui/main_window.py:880, :885
status message clear 5000 ms gui/widgets/status_bar.py:155
automation refresh 1000 ms panels/automation_panel.py:53
MAX_FRAMES_IN_FLIGHT = 2 gui/threads/prediction_subscriber.py:28
TABLE_MAX_ROWS = 20 panels/smargon_trace_panel.py:36

8. Settings-model defaults (pydantic, listed for completeness)

Excluded from the inventory proper, but these are the live policy when nothing overrides them:

  • SimpleScanParameters (aarecommon/models/models.py:698-716) — schema of <BL>:auto_params; dtz=150, exp_time_s=0.02, incr_omega_deg=0.2, steps=1800, transmission=1.0.
  • LoopCenteringSettings (operations/loop_centering/models.py:36-40) — §3.5.
  • FaceDetectionSettings (operations/face_detection/models.py:14-16) — §3.5, overridden inline.
  • RasterSettings.wait_for_screenshot_s = 0.3 (operations/raster/models.py:26).
  • DiffractionGeometry field bounds (aarecommon/math/diffraction_geometry.py:12-14) — validation limits on energy/dtz/pixel size.