Source code for finesse.detectors.bpdetector

import numpy as np

from finesse.detectors.general import Detector
from finesse.detectors.compute.gaussian import BPDetectorWorkspace, BeamProperty


# Map of beam property keywords to enum fields.
BP_KEYWORDS = {
    "w": BeamProperty.SIZE,
    "w0": BeamProperty.WAISTSIZE,
    "z": BeamProperty.DISTANCE,
    "zr": BeamProperty.RAYLEIGH,
    "gouy": BeamProperty.GOUY,
    "div": BeamProperty.DIVERGENCE,
    "rc": BeamProperty.ROC,
    "s": BeamProperty.DEFOCUS,
    "q": BeamProperty.Q,
}

property_to_label = {
    BeamProperty.SIZE: "Beam size",
    BeamProperty.WAISTSIZE: "Beam waist-size",
    BeamProperty.DISTANCE: "Distance to beam waist",
    BeamProperty.RAYLEIGH: "Rayleigh range",
    BeamProperty.GOUY: "Gouy phase",
    BeamProperty.DIVERGENCE: "Divergence angle",
    BeamProperty.ROC: "Beam radius of curvature",
    BeamProperty.DEFOCUS: "Beam defocus",
    BeamProperty.Q: "Beam parameter",
}


# IMPORTANT: renaming this class impacts the katscript spec and should be avoided!
[docs]class BeamPropertyDetector(Detector): r"""Probe for detecting the properties of a beam at a given node. The valid values for `prop` are: * ``"w"``: beam size at `node` [metres], * ``"w0"``: waist size as measured at `node` [metres], * ``"z"``: distance to the waist from `node` [metres], * ``"zr"``: the Rayleigh range [metres], * ``"gouy"``: the Gouy phase of the beam at `node` [radians], * ``"div"``: divergence angle of the beam at `node` [radians], * ``"rc"``: radius of curvature of wavefront at `node` [metres], * ``"s"``: curvature of wavefront at `node` [1 / metres], * ``"q"``: beam parameter at `node`. .. note:: The ``"gouy"`` target property here detects the Gouy phase as derived from the beam parameter :math:`q` at the specified node, i.e: .. math:: \psi = \arctan{\left(\frac{\myRe{q}}{\myIm{q}}\right)}. It does **not** compute any Gouy phase accumulation. Use :class:`.Gouy` to detect the accumulated Gouy phase over a path. Parameters ---------- name : str Name of newly created detector. node : :class:`.OpticalNode` Node to read output from. prop : str or :class:`.BeamProperty` The property of the beam to detect. See above for options. direction : str, optional; default: 'x' Plane to detect in - 'x' for tangential, 'y' for sagittal. q_as_bp : bool, optional; default: False If detecting q, should the detector output return :class:`.BeamParam` object instead of just a complex number. """ def __init__(self, name, node, prop, direction="x", q_as_bp=False): if isinstance(prop, str): if prop.casefold() not in BP_KEYWORDS: raise ValueError( f"Unrecognised property: {prop}, expected " f"one of: {list(BP_KEYWORDS.keys())}" ) prop = BP_KEYWORDS[prop.casefold()] if prop == BeamProperty.Q: if q_as_bp: dtype = object else: dtype = np.complex128 units = "" else: dtype = np.float64 if prop == BeamProperty.GOUY or prop == BeamProperty.DIVERGENCE: units = "radians" elif prop == BeamProperty.DEFOCUS: units = "1/m" else: units = "m" Detector.__init__( self, name, node, dtype=dtype, unit=units, label=property_to_label[prop] ) self.__prop = prop self.direction = direction self.q_as_bp = q_as_bp @property def prop(self): return self.__prop @property def needs_fields(self): return False @property def needs_trace(self): return True @property def detecting(self): """The property of the beam which is being detected. :getter: Returns the detected property (read-only). """ return self.__prop def _get_workspace(self, sim): ws = BPDetectorWorkspace(self, sim) ws.q_as_bp = self.q_as_bp return ws def _set_plotting_variables(self, trace_info): # Can't pickle enum so cast to int, which works the same trace_info["detecting"] = int(self.detecting)