Running the Experiment
Installation
git clone https://gitlab.com/plesty/hub/experiments/plesty-pow-pl.git
cd plesty-pow-pl
uv sync
Deployment: setup.yaml and .env
setup.yaml says what the run is made of: the bench that serves the
wave-plate stage (hwp), the spectrometer (spec) and the powermeter (pm),
and the package each runs. It names no lab — every value is a variable,
set in .env (copy .env.example):
LOCAL_DATA— where this machine sees the shared data disk;BENCH_OPTICS_DATA,BENCH_OPTICS_HOST,BENCH_OPTICS_TOKEN— that bench’s view of the same disk, where its bench agent listens, and its token.
The bench gives the run each device’s address (HWP_ADDRESS,
SPEC_ADDRESS, PM_ADDRESS) and gives the spectrometer DEVICE_DATA_PATH,
its own view of the disk. Against servers started without a bench, set the
three addresses and PLESTY_DATA in .env by hand.
Every run goes to <PLESTY_DATA>/pow-pl/<run_id> (or under --run-root),
and its spectra to pow-pl/<run_id>/raw/spec under the spectrometer’s bench
folder on the Plesty share (platform-a/pow-pl/<run_id>/raw/spec), named
<sample>_<qd>_hwp<angle>deg_exp<ms>ms_<HHMMSS>.spe — for example
D104-C_QD01_hwp004.00deg_exp500ms_143512.spe. The time keeps a retaken row from
meeting the name of its failed attempt; nothing in a name is a space.
Start, watch, resume
# Preview the plan without touching devices
uv run python -m plesty.pow_pl --dry-run
# Run (checkpoints under <PLESTY_DATA>/pow-pl/<run_id>/)
uv run python -m plesty.pow_pl --config config/default.yaml
# Resume an interrupted run at the exact angle it stopped
uv run python -m plesty.pow_pl --resume <run_id>
Every completed row is persisted immediately, so an interruption loses at most the row in flight. The plan is frozen with the run: resuming with a changed configuration is refused rather than silently measuring something else.
What the console shows
The run logs every phase to the console and to logs/pow_pl_<timestamp>.log:
the config summary, the rig connect (Connecting hwp @ tcp://… (timeout 5000 ms) …, Connected hwp @ tcp://… in 0.4 s, PowPlRig ready in 1.2 s: hwp=…, spec=…, pm=…), the run id and run dir with the step count, homing,
and then per row: Step 12/47 qd[QD-01]-hwp[022.00] (measure_row), the
stage move (HWP -> 22.00 deg, HWP settled at 22.0000 deg after 1.1 s),
the acquisition (Acquiring 1 frame(s) x 1.00 s + power …, Acquired in 2.3 s: <frame>, power … uW) and Row 11/46 done in 3.4 s: ….
When a device server is not there
The start is a preflight (plesty-lib connect_rig): every server must
answer within connect_deadline_s (10 s) and be the device its slot
requires (requires in config.yaml — a wrong port connects fine but is
not the stage). On a failure the run does not start; you are told which
device, at which address, from which .env variable, and asked:
The rig is not ready — 1 device(s) failed the preflight:
- pm: Sub-device 'pm' unreachable at tcp://127.0.0.1:5557 after 10.1 s: …
address tcp://127.0.0.1:5557 (from PM_ADDRESS in .env / the environment)
Check that the pm server(s) are running and that PM_ADDRESS point at them
(a wrong port connects fine but is not the expected device).
[r] retry (after fixing .env or starting the server) [a] abort [s] continue without pm
>
r rebuilds the rig (start the server or fix .env first), a aborts,
s — offered only when the powermeter is the failing device — runs
spectra-only (the powermeter block is dropped from the run, so the rows
carry no power column; a --resume of a run planned with power will refuse
that). Without a terminal (a service, CI) nothing waits: the diagnosis is
logged and the process exits with RigNotReadyError.
The HWP angle is verified
The K10CR1 server answers a move only once the stage has physically stopped
(plesty-k10cr1#2), so the angle it reports is the angle the row is measured
at and is stored as hwp_reported_deg. set_hwp checks it against the
target (position_tolerance_deg, 0.01°): a mismatch re-issues the move once,
a second mismatch fails the step — it is then retried by the run’s retry
ladder rather than recorded at a wrong angle.