plesty.fss.analyzer

The FineStructure analyzer: fine structure from a polarization sweep.

A polarization-resolved PL sweep records one spectrum per rotator angle. Two stages turn it into the fine structure of each line:

  1. SpectrumFit fits every line in every frame, frames taken in angle order so each fit seeds the next.

  2. fit_sine() fits each line’s centre against the angle with a sine; the peak-to-peak amplitude of that oscillation is the fine-structure splitting — twice it behind a quarter-wave plate, which shows the doublet at half the contrast.

from plesty.lib.data import SpectrumData
from plesty.fss import FineStructure

spectrum = SpectrumData.from_run(run, coordinates=("hwp_deg",))
outputs = FineStructure(angle="hwp_deg", rotator="hwp")(spectrum=spectrum)
outputs["fine_structure"]["fss"]          # µeV, one per line

Attributes

_MICRO

Classes

FineStructure

Fine-structure splitting of every line in a polarization sweep.

Functions

_angles_deg(→ numpy.ndarray)

Return the rotator angle of every frame, in degrees.

_nanometres(→ float)

Return the factor converting the wavelength unit to nanometres.

_splitting_uev(→ tuple[float, float])

Return the splitting 2·A / contrast as a photon-energy difference in µeV, ± σ.

Module Contents

plesty.fss.analyzer._MICRO = 1000000.0
class plesty.fss.analyzer.FineStructure(angle: str = 'hwp_deg', rotator: str = 'hwp', fit_options: Mapping[str, Any] | None = None)

Bases: plesty.lib.analyzer.Analyzer

Fine-structure splitting of every line in a polarization sweep.

The spectrum must carry the rotator angle of each frame as a coordinate (SpectrumData.from_run(run, coordinates=("hwp_deg",))). Frames whose line fit fails are left out of that line’s sweep fit.

The splitting is the peak-to-peak amplitude of the oscillation of each line’s fitted position with the rotator angle, divided by the rotator’s contrast (CONTRAST: 1 for a half-wave plate or a polarizer, ½ for a quarter-wave plate). That measures a doublet only while its two orthogonally polarized components are closer than the linewidth and appear as one line. A line whose position oscillates by as much as its linewidth or more is marked fss_valid = 0 and named in a warning: its fit followed a different line from frame to frame, and its fss is not a splitting.

Outputs:

  • fine_structure — FineStructureData, one entry per line: the splitting in µeV and as a wavelength, the polarization axis and the mean position, each ± σ, with the linewidth and the fss_valid flag.

  • fit — the SpectrumFitData of the line fits.

  • curve — the fitted position at each fitted frame’s angle, shaped like fit["center"] so the two plot against each other directly.

Validate and store the sweep parameters.

Parameters:
  • angle (str) – Name of the spectrum coordinate holding the rotator angle.

  • rotator (str) – "hwp" (half-wave plate, 90° period), "polarizer" (180° period), or "qwp" (quarter-wave plate in front of a fixed polarizer, 90° period at half the contrast, so the splitting is twice the oscillation).

  • fit_options (Mapping[str, Any] | None) – Keyword arguments of SpectrumFit (peaks, model, window, center_tolerance, …). Without order, frames are fitted in angle order.

Raises:

ValueError – If the rotator is unknown or a fit option is invalid.

input_schema

name → schema entry.

Type:

Declared inputs of analyze()

output_schema

name → schema entry.

Type:

Declared outputs of analyze()

analyze(spectrum: plesty.lib.data.SpectrumData) → dict[str, Any]

Fit every line in every frame, then each line’s centre against the angle.

Parameters:

spectrum (plesty.lib.data.SpectrumData) – The polarization sweep.

Returns:

fine_structure, fit and curve, see the class description.

Raises:

ValueError – If the angle coordinate is missing or not an angle, or the wavelength unit is not a length.

Return type:

dict[str, Any]

report(outputs: Mapping[str, Any]) → plesty.lib.report.Report

Say what the sweep found: a sentence, a table of the lines, and the sweep drawn.

See plesty.fss.report. Only fine_structure and fit are read, so a report can be rebuilt from the two saved outputs.

Parameters:

outputs (Mapping[str, Any]) – What calling the analyzer returned, or at least its fine_structure and fit.

Returns:

The report, stamped with this analyzer’s provenance.

Return type:

plesty.lib.report.Report

plesty.fss.analyzer._angles_deg(spectrum: plesty.lib.data.SpectrumData, name: str) → numpy.ndarray

Return the rotator angle of every frame, in degrees.

Parameters:
  • spectrum (plesty.lib.data.SpectrumData)

  • name (str)

Return type:

numpy.ndarray

plesty.fss.analyzer._nanometres(unit: str | None) → float

Return the factor converting the wavelength unit to nanometres.

Parameters:

unit (str | None)

Return type:

float

plesty.fss.analyzer._splitting_uev(sweep: plesty.fss.sine.SineFit, to_nm: float, contrast: float = 1.0) → tuple[float, float]

Return the splitting 2·A / contrast as a photon-energy difference in µeV, ± σ.

ΔE = hc·Δλ/λ² with Δλ = 2·A / contrast at the mean position λ, both in nanometres; contrast is the rotator’s CONTRAST. The error propagates the full covariance of (mean, a, b).

Parameters:
Return type:

tuple[float, float]