plesty.pol_pl

Polarization-dependent photoluminescence experiment module.

Submodules

Classes

Experiment

Measure the polarization sweep of every catalogued quantum dot and analyse it.

PolPlRig

Half-wave-plate rotation stage + spectrometer as one instrument.

Functions

load_config(→ dict[str, Any])

Load the packaged module configuration (constants and running defaults).

Package Contents

class plesty.pol_pl.Experiment(devices: plesty.pol_pl.rig.PolPlRig | None = None, config: dict[str, Any] | None = None, run_root: str | pathlib.Path | None = None, **kwargs: Any)

Bases: plesty.lib.experiment.Experiment

Measure the polarization sweep of every catalogued quantum dot and analyse it.

Configuration comes from a plain dict (loaded from config/*.yaml by __main__) and is frozen into the plan, so a resumed run refuses a changed configuration. Instruments are reached exclusively through the PolPlRig composite passed at construction.

Initialize and validate the plan-shaping configuration.

The configuration is checked here, before anything connects, so a malformed sweep fails at the prompt rather than halfway through a run. What only a hardware run needs — the shared data disk — is checked by validate_hardware_config(), so --dry-run works without it.

Parameters:
  • devices (Optional[plesty.pol_pl.rig.PolPlRig]) – The instrument rig; None for plan-only inspection.

  • config (Optional[dict[str, Any]]) – Measurement configuration (see config/default.yaml); missing sections take the defaults of this module.

  • run_root (str | pathlib.Path | None) – Directory under which each run creates its data directory; a relative one is under PLESTY_DATA (the share) — RUN_ROOT for a run started by the command line.

  • **kwargs (Any) – Forwarded to the base Experiment (name, max_retries, retry_sleep, data_root).

Raises:

ValueError – If the configuration is malformed.

config
rig = None
_grating_center_nm: float | None = None
build_plan() → plesty.lib.experiment.Plan

Expand the configuration into one step per dot per angle, plus one analysis per dot.

Absolute angles, so no error accumulates along the sweep; resume granularity is the single angle.

Returns:

The frozen schedule. Step ids look like qd[QD-01]-hwp[004.00] and qd[QD-01]-analysis.

Return type:

plesty.lib.experiment.Plan

record_rig() → dict[str, Any]

Record the instrument identities, so a run is replayable from its records.

Returns:

Each device’s identity and the UTC time it was recorded.

Return type:

dict[str, Any]

measure_spectrum(sample: str, qd: str, x_um: float, y_um: float, angle_deg: float, exposure_ms: float, frames: int, settle_s: float = 0.0) → dict[str, Any]

Rotate the half-wave plate to one angle and take one spectrum.

Parameters:
  • sample (str) – Sample identifier.

  • qd (str) – Quantum-dot identifier from the catalogue.

  • x_um (float) – Catalogued chip X coordinate in micrometres.

  • y_um (float) – Catalogued chip Y coordinate in micrometres.

  • angle_deg (float) – Commanded absolute half-wave-plate angle in degrees.

  • exposure_ms (float) – Exposure time in milliseconds.

  • frames (int) – Frames stored in the spectrum file.

  • settle_s (float) – Pause after the plate has settled, before the exposure.

Returns:

identifiers, coordinates, commanded and reported angle, the spectrum file relative to the shared point, the exposure window and the grating centre wavelength.

Return type:

The spectrum record

Raises:
  • RuntimeError – If no rig is attached or the spectrometer wrote no file.

  • TimeoutError – If the file does not appear on this host’s mount.

analyze_qd(qd: str) → dict[str, Any]

Analyse one quantum dot’s polarization sweep with plesty.fss.FineStructure.

Reads the dot’s spectra back from this run’s records, fits every line in every spectrum and each line’s position against the angle, and saves the analyzer’s fine_structure and fit outputs under <run_dir>/analysis/, where the run viewer (viz) finds them, with the analyzer’s report of them beside them (<qd>.report.json). Warnings the analyzer raises — a line whose fit moved onto a different line, a splitting that cannot be read from a line — are logged and kept in the record.

Parameters:

qd (str) – Quantum-dot identifier.

Returns:

position, fine-structure splitting ± σ in µeV, whether the splitting is valid, and polarization axis; plus the analyzer warnings and where the full results were saved.

Return type:

Per emission line

Raises:
  • RuntimeError – If the run has not started.

  • ValueError – If the run holds no spectrum of this dot.

async setup() → None

Check the configuration, connect, route the frames, home the plate.

Raises:
  • ValueError – If the hardware configuration is incomplete.

  • RuntimeError – If this machine is not told where the Plesty share is.

Return type:

None

async teardown() → None

Park the half-wave plate at 0° (best effort), then disconnect.

Return type:

None

classmethod validate_plan_config(config: dict[str, Any]) → None

Validate everything that shapes the plan.

Parameters:

config (dict[str, Any]) – The measurement configuration, defaults merged in.

Raises:

ValueError – If a value is missing, of the wrong kind or out of range.

Return type:

None

classmethod validate_hardware_config(config: dict[str, Any], data_root: str | None) → None

Validate what a hardware run needs beyond a valid plan.

The spectra are written by the spectrometer and read back here — to confirm each file arrived and to analyse the sweep — so this machine’s view of the shared disk is required.

Parameters:
  • config (dict[str, Any]) – The measurement configuration.

  • data_root (Optional[str]) – The shared disk as this machine sees it.

Raises:

ValueError – If the plan configuration is invalid or the shared disk is not configured.

Return type:

None

_base_filename(qd: str, angle_deg: float) → str

Build the spectrometer file-name stem, e.g. pol_pl_QD-01_hwp004p00.

Parameters:
  • qd (str)

  • angle_deg (float)

Return type:

str

_grating_center() → float | None

Return the grating centre wavelength, queried once per process.

A value the spectrometer cannot report is recorded as None with one warning; metadata must not abort a sweep whose spectra are fine.

Return type:

Optional[float]

_local_raw_path(data_file: str) → pathlib.Path

A recorded spectrum file, relative to the shared point, on this machine.

The folder is the run’s own (raw_file()); only the name came from the spectrometer, and it is checked rather than trusted — it becomes a path this process reads — so it must name a spectrum.

Raises:
  • RuntimeError – If the run has no data root.

  • ValueError – If the spectrometer’s file is not a spectrum.

Parameters:

data_file (str)

Return type:

pathlib.Path

_wait_for_file(path: pathlib.Path) → None

Wait for a written spectrum to become visible on this machine’s mount.

Raises:

TimeoutError – If it does not appear within spectra.file_visibility_timeout_s.

Parameters:

path (pathlib.Path)

Return type:

None

_require_rig() → plesty.pol_pl.rig.PolPlRig

Return the rig.

Raises:

RuntimeError – If the experiment was built without one.

Return type:

plesty.pol_pl.rig.PolPlRig

class plesty.pol_pl.PolPlRig(devices: collections.abc.Mapping[str, Any] | None = None, env: plesty.lib.utils.settings.EnvSettings | None = None, env_prefix: str | None = None)

Bases: plesty.lib.device.composite_device.CompositeDevice

Half-wave-plate rotation stage + spectrometer as one instrument.

Connect the rig’s instruments, each on its own thread.

Addresses are not arguments: each is read from <NAME>_ADDRESS in the environment (HWP_ADDRESS, SPEC_ADDRESS), so a deployment is configured by its .env.

Parameters:
  • devices (Optional[collections.abc.Mapping[str, Any]]) – Sub-device overrides in the form CompositeDevice accepts; defaults to the devices block of the packaged config.yaml.

  • env (Optional[plesty.lib.utils.settings.EnvSettings]) – Environment source for the address lookups.

  • env_prefix (Optional[str]) – Deployment prefix for the derived variable names.

Raises:
  • ValueError – If a sub-device’s address is neither configured nor in the environment.

  • RuntimeError – If a device server cannot be reached.

init_state() → None

Reset what this rig remembers about its instruments.

Per rig, not per process: a run builds its own rig, so a fresh run rewrites every setting and never inherits another run’s idea of them.

Return type:

None

home_hwp() → bool

Home the rotation stage and return its homed status.

Return type:

bool

set_hwp(angle_deg: float) → float

Move the half-wave plate to an absolute angle and return where it settled.

Small steps from a known position run under a short window; larger or first moves keep the full mechanical budget. The stage answers only once it has stopped, so the reported angle is the one the spectrum is measured at. It is checked against the target: on a mismatch beyond position_tolerance_deg the move is issued once more, and a second mismatch raises, so the step is retried instead of recording a spectrum at the wrong angle.

Parameters:

angle_deg (float) – Target angle in degrees (applied modulo 360).

Returns:

The stage-reported angle in degrees.

Raises:

RuntimeError – If the stage settles away from the target twice.

Return type:

float

configure_spectrum(exposure_ms: float, frames: int, base_name: str) → None

Push one acquisition’s settings to the spectrometer, writing only what changed.

The file name is part of the settings rather than of the acquire call: LightField generates it from the base name.

Parameters:
  • exposure_ms (float) – Exposure time in milliseconds.

  • frames (int) – Frames stored in the one .spe file.

  • base_name (str) – File-name stem LightField generates from.

Return type:

None

center_wavelength_nm() → float

Return the grating centre wavelength currently set on the spectrometer.

Return type:

float

acquire_spectrum(exposure_ms: float, frames: int) → dict[str, Any]

Expose the spectrometer once and return the file it wrote.

The path is compared with the one reported before the exposure, because LightField answers with its most recent file whether or not this acquisition produced one.

Parameters:
  • exposure_ms (float) – Exposure time in milliseconds (sizes the call window).

  • frames (int) – Frames stored by the acquisition.

Returns:

{"data_file": str, "started_at": datetime, "ended_at": datetime} — the path as the spectrometer host sees it, and the UTC bounds of the exposure.

Raises:

RuntimeError – If the spectrometer reports no new file.

Return type:

dict[str, Any]

_write_spec(key: str, value: Any) → None

Push one spectrometer setting under the configured write budget.

Parameters:
  • key (str)

  • value (Any)

Return type:

None

plesty.pol_pl.load_config() → dict[str, Any]

Load the packaged module configuration (constants and running defaults).

Returns:

The parsed config.yaml shipped with this module.

Return type:

dict[str, Any]