plesty.pow_pl.experiment
Power-dependent photoluminescence of quantum dots.
The atomic step of the experiment is one excitation-power setting: rotate the half-wave plate (K10CR1 rotation stage) to the next angle of the series (2° increments by default) — the plate angle sets the excitation power — then acquire one spectrometer row and one powermeter reading simultaneously. The power sample covers the exposure window, so every row of the power series carries the excitation power it was actually measured at.
The power reference is optional: a configuration without a powermeter
block plans spectra-only rows — rotate, expose, record the frame path — and
the rig is built without the powermeter (with_powermeter=False), so no
PM_ADDRESS is needed and no powermeter server has to run.
The product is the power series itself. Quantities derived from it are an analyzer’s job, not this module’s.
All data lands on the shared disk, and frames never cross the network. A run
is <PLESTY_DATA>/pow-pl/<run_id>; at setup it routes the spectrometer once
to the run’s raw/spec folder, a path relative to the shared point that the
spectrometer’s bench resolves under its own view of the disk. Each row names
its frame <sample>_<qd>_hwp<angle>deg_exp<ms>ms_<HHMMSS>, no spaces, and
its record keeps the frame as pow-pl/<run_id>/raw/spec/<file> — the same
path on every machine once joined to its PLESTY_DATA. The framework commits
each row’s record (one line of records.jsonl) the moment the step
completes, and an interrupted sweep resumes at the exact angle it stopped
(run(resume=<run_id>)).
Positioning is not yet automated: the steps assume the target dot is already localized (stage on target, signal on the spectrometer). The chip coordinates from the catalogue are recorded in every result for the upcoming localization stage (AMC300 positioner, DMK camera, PI steering mirror).
Attributes
Classes
Measure the power-dependent spectral series of every catalogued QD. |
Functions
|
Return the name a row's frame is saved under. |
|
Return the configured exposure(s) in seconds as a non-empty list. |
|
Return the inclusive HWP angle series without float accumulation drift. |
Module Contents
- plesty.pow_pl.experiment.RUN_ROOT = 'pow-pl'
- plesty.pow_pl.experiment.SPEC = 'spec'
- plesty.pow_pl.experiment._DEFAULT_QDS
- plesty.pow_pl.experiment._UNSAFE
- plesty.pow_pl.experiment.frame_stem(sample: str, qd: str, angle_deg: float, at: datetime.datetime | None = None, exposure_s: float | None = None) str
Return the name a row’s frame is saved under.
Sample, dot, wave-plate angle and exposure — what tells one row’s file from another’s without its record — then the local time of the acquisition, which keeps a retaken row from meeting the name of its failed attempt (LightField would stop on an “already exists” dialog). Parts are joined with
_; any character a file name should not carry becomes-.- Parameters:
sample (str) – Sample identifier.
qd (str) – Quantum-dot identifier.
angle_deg (float) – Commanded wave-plate angle in degrees.
at (Optional[datetime.datetime]) – Time of the acquisition; now when
None.exposure_s (Optional[float]) – Exposure in seconds, named in whole milliseconds; left out of the name when
None.
- Returns:
For example
D104-C_QD01_hwp004.00deg_exp500ms_143512.- Return type:
str
- plesty.pow_pl.experiment._exposures(value: Any) list[float]
Return the configured exposure(s) in seconds as a non-empty list.
- Parameters:
value (Any) –
spectrum.exposure_s— one number, or a list of numbers.- Returns:
The exposures in the order given.
- Raises:
ValueError – If the list is empty or an exposure is not positive.
- Return type:
list[float]
- plesty.pow_pl.experiment._angle_series(start_deg: float, stop_deg: float, step_deg: float) list[float]
Return the inclusive HWP angle series without float accumulation drift.
- Parameters:
start_deg (float) – First angle in degrees.
stop_deg (float) – Last angle in degrees (included when reachable by whole steps).
step_deg (float) – Angle increment in degrees; must be positive.
- Returns:
The list of commanded angles in degrees.
- Raises:
ValueError – If
step_degis not positive.- Return type:
list[float]
- class plesty.pow_pl.experiment.Experiment(devices: plesty.pow_pl.rig.PowPlRig | None = None, config: dict[str, Any] | None = None, run_root: str | pathlib.Path | None = None, **kwargs: Any)
Bases:
plesty.lib.experiment.ExperimentMeasure the power-dependent spectral series of every catalogued QD.
Configuration comes from a plain dict (loaded from
config/*.yamlby__main__) and is frozen into the plan, so a resumed run refuses a changed configuration. Instruments are accessed exclusively through thePowPlRigcomposite passed at construction.Initialize the experiment.
- Parameters:
devices (Optional[plesty.pow_pl.rig.PowPlRig]) – The instrument rig (HWP stage, spectrometer, powermeter); may be
Nonefor plan-only inspection.config (Optional[dict[str, Any]]) – Measurement configuration (see
config/default.yaml); recorded in the plan.run_root (str | pathlib.Path | None) – Directory under which each run creates its data directory —
RUN_ROOTunderPLESTY_DATAfor a run started by the command line.**kwargs (Any) – Forwarded to the base
Experiment(name,max_retries,retry_sleep,data_root).
- rig = None
- config
- _announced_qd: str | None = None
- _configured: tuple | None = None
- _grating_center_nm: float | None = None
- _rows_done = 0
- _rows_total = 0
- build_plan() plesty.lib.experiment.Plan
Expand the configuration into one atomic step per QD per HWP angle.
Each step commands one absolute angle (absolute targets, so no drift accumulates over the series) and one simultaneous spectrometer + powermeter acquisition; resume granularity is the single angle. With a list of exposures, every angle gets one step per exposure, in the order listed, before the plate moves on.
- Returns:
The frozen measurement schedule; step ids look like
qd[QD-01]-hwp[004.00], orqd[QD-01]-hwp[004.00]-exp[0.500s]with several exposures.- Raises:
KeyError – If a catalogue entry has no
id.ValueError – If the HWP sweep configuration is invalid.
- Return type:
plesty.lib.experiment.Plan
- record_rig() dict[str, Any]
Record the instrument identities for replayability.
- Returns:
Each device’s identity string (model, serial, firmware) and the UTC time it was recorded.
- Raises:
RuntimeError – If the experiment was constructed without a rig.
- Return type:
dict[str, Any]
- measure_row(sample: str, qd: str, x_um: float, y_um: float, angle_deg: float, exposure_s: float, frames: int, pm_wavelength_nm: float | None = None, pm_averaging: int | None = None, pm_delay_s: float = 0.4, settle_s: float = 0.0) dict[str, Any]
Rotate the HWP to one angle, then acquire the row.
With powermeter parameters (a plan from a config with a
powermeterblock) the spectrum and the power are acquired together; without them the row is the spectrum alone. Settings are pushed to the instruments once per process — on the first row, or whenever a step carries different values — so a resumed run configures itself without rewriting identical settings on every row.- Parameters:
sample (str) – Sample identifier, recorded in the result.
qd (str) – Quantum-dot identifier from the catalogue.
x_um (float) – Catalogued chip-frame X coordinate in micrometres.
y_um (float) – Catalogued chip-frame Y coordinate in micrometres.
angle_deg (float) – Commanded absolute HWP angle in degrees.
exposure_s (float) – Spectrometer exposure in seconds.
frames (int) – Frames stored per acquisition (row is frame 0).
pm_wavelength_nm (Optional[float]) – Powermeter correction wavelength in nanometres (written once per configure);
Nonemeasures the spectrum without a power reference.pm_averaging (Optional[int]) – Powermeter samples per reading (~3 ms each).
pm_delay_s (float) – Delay before the power sample so it lands inside the exposure window.
settle_s (float) – Pause after the completed step — breathing room for the instrument stacks between rows (defaults to 0 for plans frozen before the knob existed).
- Returns:
identifiers, coordinates, commanded and reported HWP angle, the shared-disk path of the saved frame, the grating center wavelength, and — when measured — the simultaneous optical power.
- Return type:
A JSON-serializable record
- Raises:
RuntimeError – If the experiment was constructed without a rig, or if the plan carries power parameters but the rig has no powermeter.
- analyze_qd(qd: str) dict[str, Any]
Analyse one dot’s power series and save the results beside the run.
Reads the dot’s spectra back from this run’s records, then the two analyses of
analysis: the integrated counts and every line’s fitted area against the power. The line fit is saved asanalysis/<qd>_line_fitand the report asanalysis/<qd>.report.json, which the bench’s run report shows without importing this module.- Parameters:
qd (str) – Quantum-dot identifier.
- Returns:
Each line’s position and exponent, the integrated exponent, the saturation power when the data constrain it, the line fit’s warnings, and where the results were saved.
- Raises:
RuntimeError – If the run has not started.
- Return type:
dict[str, Any]
- _grating_center() float | None
Return the grating center wavelength, queried once per process.
The spectrometer’s LightField IPC link is the fragile part of the rig — static settings are read (and written) once, not per row. A value the spectrometer cannot report (empty or non-numeric) is recorded as
Nonewith one warning; metadata must not abort a sweep whose frames and power are fine.- Return type:
Optional[float]
- _ensure_at_qd(qd: str, x_um: float, y_um: float) None
Positioning placeholder — the dot is assumed to be localized.
Logs once per dot, not per angle. The upcoming localization stage will move the AMC300 to the catalogue coordinates, verify via the DMK camera, and fine-steer the PI mirror before the sweep starts.
- Parameters:
qd (str)
x_um (float)
y_um (float)
- Return type:
None
- async setup() None
Connect the instruments, route the frames into
raw/spec, home the wave plate.The frame directory is set through the device’s own data path rather than by writing a vendor parameter: the spectrometer resolves it under its bench’s folder on the Plesty share, creates it, and answers with that folder from the share, where each frame is recorded (
route()). Only the spectrometer is routed — the stage and the powermeter write nothing.- Raises:
RuntimeError – If this machine is not told where the Plesty share is, so it could not read the frames back.
- Return type:
None
- async teardown() None
Park the wave plate at 0 deg (best effort), then disconnect.
- Return type:
None