plesty.fss.analyzer =================== .. py:module:: plesty.fss.analyzer .. autoapi-nested-parse:: The :class:`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. :class:`~plesty.lib.analyzer.SpectrumFit` fits every line in every frame, frames taken in angle order so each fit seeds the next. 2. :func:`~plesty.fss.sine.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. .. code-block:: python 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 ---------- .. autoapisummary:: plesty.fss.analyzer._MICRO Classes ------- .. autoapisummary:: plesty.fss.analyzer.FineStructure Functions --------- .. autoapisummary:: plesty.fss.analyzer._angles_deg plesty.fss.analyzer._nanometres plesty.fss.analyzer._splitting_uev Module Contents --------------- .. py:data:: _MICRO :value: 1000000.0 .. py:class:: FineStructure(angle: str = 'hwp_deg', rotator: str = 'hwp', fit_options: Mapping[str, Any] | None = None) Bases: :py:obj:`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 (:data:`~plesty.fss.sine.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`` — :class:`~plesty.fss.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 :class:`~plesty.lib.data.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. :param angle: Name of the spectrum coordinate holding the rotator angle. :param rotator: ``"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). :param fit_options: Keyword arguments of :class:`~plesty.lib.analyzer.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. .. py:attribute:: input_schema name → schema entry. :type: Declared inputs of :meth:`analyze` .. py:attribute:: output_schema name → schema entry. :type: Declared outputs of :meth:`analyze` .. py:method:: analyze(spectrum: plesty.lib.data.SpectrumData) -> dict[str, Any] Fit every line in every frame, then each line's centre against the angle. :param spectrum: 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. .. py:method:: 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 :mod:`plesty.fss.report`. Only ``fine_structure`` and ``fit`` are read, so a report can be rebuilt from the two saved outputs. :param outputs: What calling the analyzer returned, or at least its ``fine_structure`` and ``fit``. :returns: The report, stamped with this analyzer's provenance. .. py:function:: _angles_deg(spectrum: plesty.lib.data.SpectrumData, name: str) -> numpy.ndarray Return the rotator angle of every frame, in degrees. .. py:function:: _nanometres(unit: str | None) -> float Return the factor converting the wavelength unit to nanometres. .. py:function:: _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 :data:`~plesty.fss.sine.CONTRAST`. The error propagates the full covariance of ``(mean, a, b)``.