Source code for finesse.detectors.math_detector

from finesse.detectors.general import Detector
from finesse.detectors.workspace import DetectorWorkspace
from finesse.utilities import OrderedSet


[docs]class MathDetectorWorkspace(DetectorWorkspace): """MathDetectorWorkspace.""" def __init__(self, owner, sim): from finesse.components.readout import ReadoutDetectorOutput from finesse.symbols import Symbol, Constant, Variable self.expression = owner.expression if not isinstance(self.expression, Symbol): self.expression = Constant(self.expression) # Get all the detectors in the expression self.detectors = [ # will select constants, whose value is a detector a for a in self.expression.all( lambda a: isinstance(a, (Constant, Variable)) and isinstance(a.value, (Detector, ReadoutDetectorOutput)) ) ] out_wss = OrderedSet( # workspaces can be in both lists (*sim.readout_workspaces, *sim.detector_workspaces) ) # find the workspaces for the detectors self.dws = [] for det in self.detectors: for ws in out_wss: if ws.oinfo.name == det.value.name: self.dws.append(ws) self.set_output_fn(self.__output) needs_carrier = any(_.needs_carrier for _ in self.dws) needs_signal = any(_.needs_signal for _ in self.dws) needs_noise = any(_.needs_noise for _ in self.dws) needs_modal_update = any(_.needs_modal_update for _ in self.dws) needs_simulation = ( needs_carrier or needs_signal or needs_noise or needs_modal_update ) super().__init__( owner, sim, needs_carrier=needs_carrier, needs_signal=needs_signal, needs_noise=needs_noise, needs_modal_update=needs_modal_update, needs_simulation=needs_simulation, ) def __output(self, ws): subs = {a: ws.get_output() for a, ws in zip(self.detectors, self.dws)} return ws.expression.eval(subs=subs)
# IMPORTANT: renaming this class impacts the katscript spec and should be avoided!
[docs]class MathDetector(Detector): """A detector that performs some math operation and outputs the result. Parameters ---------- name : str Name of detector expression : Symbol Symbolic expression to evaluate as the detectors output dtype : numpy.dtype, optional The expected data type when evaluating expression. Defaults to "O". dtype_shape : tuple The expected array shape when evaluating `expression`. Defaults to an empty tuple. This must be an empty tuple if `dtype` is a scalar type or "O". unit : str The unit of the output for plotting. Defaults to "arb." label : str or None How to label the axis when plotting this detector. Defaults to `None`. Notes ----- If `dtype` does not match the result when `expression` is evaluated the values will be silently cast to `dtype`. `dtype_shape` is used to create a numpy array in which the results are written, if this doesn't match this should raise some Exception when running a simulation, but this is not guaranteed. If one isn't sure of what type `expression` will produce, one should leave the default "O", the generic numpy type `object`, and convert the data after inspecting the result. When using the default type, some functions like `Solution.plot` might not be able to convert the data to an appropiate type internally, in which case they cannot be used. Examples -------- KatScript example: l l1 P=1 pd P l1.p1.o fd E l1.p1.o f=l1.f bp qx l1.p1.o q x modes(maxtem=3) gauss g1 l1.p1.o w0=1m z=0 mathd Y1 P*2 mathd Y2 P**2 mathd Y3 cos(1+P**2) mathd Y4 E*2 mathd Y5 qx+1 """
[docs] def __init__( self, name, expression, dtype="O", dtype_shape=tuple(), unit="arb.", label=None ): super().__init__(name, dtype=dtype) self._expression = expression self._update_dtype_shape(dtype_shape) self._update_unit(unit) self._update_label(label)
@property def needs_fields(self): return False @property def needs_trace(self): return False
[docs] def set_expression( self, expression, dtype="O", dtype_shape=tuple(), unit="arb.", label=None ): self._expression = expression self._update_dtype(dtype) self._update_dtype_shape(dtype_shape) self._update_unit(unit) self._update_label(label)
@property def expression(self): return self._expression def _get_workspace(self, sim): return MathDetectorWorkspace(self, sim)