lens.py 6.24 KB
 1 2 3 4 """ Transmissive optical components which focus or disperse light beams. """  Samuel Rowlinson committed Aug 16, 2019 5 import logging  Samuel Rowlinson committed Jul 10, 2019 6   Samuel Rowlinson committed Nov 21, 2018 7 import numpy as np  8   Samuel Rowlinson committed May 12, 2020 9 from finesse.components.modal.lens import (  10  LensWorkspace  Samuel Rowlinson committed May 12, 2020 11 )  Samuel Rowlinson committed Dec 24, 2020 12 from finesse.components.general import Connector, InteractionType  Samuel Rowlinson committed Jul 01, 2019 13 from finesse.components.node import NodeDirection, NodeType  Samuel Rowlinson committed Oct 21, 2020 14 from finesse.parameter import model_parameter, Rebuild  Phil Jones committed Mar 04, 2020 15 from finesse.utilities import refractive_index  Samuel Rowlinson committed Jul 12, 2019 16   Samuel Rowlinson committed Aug 16, 2019 17 18 LOGGER = logging.getLogger(__name__)  Samuel Rowlinson committed Nov 21, 2018 19   Samuel Rowlinson committed May 12, 2020 20 @model_parameter(  21 22 23 24 25 26 27  "f", "Focal length", np.inf, Rebuild.HOM, validate="_check_f", units="m", is_geometric=True,  Samuel Rowlinson committed May 12, 2020 28 )  Samuel Rowlinson committed Nov 21, 2018 29 class Lens(Connector):  Sean Leavey committed Apr 05, 2020 30 31  """Represents a thin lens optical component with an associated focal length.  Sean Leavey committed Apr 07, 2020 32 33 34 35  Notes ----- The specified focal length f is only accurate when the lens is attached to spaces with index of refraction close to 1. This component exists so that one can use the intuitive focal length  Sean Leavey committed Oct 21, 2020 36  parameter instead of having to set radii of curvature as with e.g. :class:.Mirror.  Sean Leavey committed Apr 07, 2020 37   Sean Leavey committed Apr 05, 2020 38 39 40 41 42 43  Parameters ---------- name : str Name of newly created lens. f : float, optional  Sean Leavey committed Apr 07, 2020 44  Focal length of the lens in metres; defaults to infinity.  Samuel Rowlinson committed Nov 21, 2018 45  """  Samuel Rowlinson committed Dec 16, 2019 46   47  def __init__(self, name, f=np.inf):  48  super().__init__(name)  Samuel Rowlinson committed Nov 21, 2018 49 50 51  self.f = f  Samuel Rowlinson committed Jun 24, 2019 52  self._add_port("p1", NodeType.OPTICAL)  Samuel Rowlinson committed Dec 16, 2019 53 54  self.p1._add_node("i", NodeDirection.INPUT) self.p1._add_node("o", NodeDirection.OUTPUT)  Samuel Rowlinson committed Nov 21, 2018 55   Samuel Rowlinson committed Jun 24, 2019 56  self._add_port("p2", NodeType.OPTICAL)  Samuel Rowlinson committed Dec 16, 2019 57 58  self.p2._add_node("i", NodeDirection.INPUT) self.p2._add_node("o", NodeDirection.OUTPUT)  Samuel Rowlinson committed Nov 21, 2018 59   Samuel Rowlinson committed Nov 26, 2018 60  # optic to optic couplings  Samuel Rowlinson committed Dec 16, 2019 61  self._register_node_coupling(  Daniel Brown committed Apr 18, 2020 62 63 64 65  "P1i_P2o", self.p1.i, self.p2.o, interaction_type=InteractionType.TRANSMISSION,  Samuel Rowlinson committed Dec 16, 2019 66 67  ) self._register_node_coupling(  Daniel Brown committed Apr 29, 2020 68  "P2i_P1o",  Daniel Brown committed Apr 18, 2020 69 70 71  self.p2.i, self.p1.o, interaction_type=InteractionType.TRANSMISSION,  Samuel Rowlinson committed Dec 16, 2019 72  )  Samuel Rowlinson committed Nov 21, 2018 73   Samuel Rowlinson committed Jul 12, 2019 74  def _check_f(self, value):  75  if value == 0:  Samuel Rowlinson committed Jul 12, 2019 76  raise ValueError("Focal length of lens must be non-zero.")  77   Samuel Rowlinson committed Jul 12, 2019 78 79  return value  Daniel Brown committed Dec 16, 2020 80 81 82 83  def _resymbolise_ABCDs(self): self.__symbolise_ABCDs("x") self.__symbolise_ABCDs("y")  84 85 86  def __symbolise_ABCDs(self, direction): # TODO (sjr) Not using direction currently but will split # into fx, fy soon to support astigmatic lenses  Samuel Rowlinson committed May 12, 2020 87 88  M_sym = np.array([[1.0, 0.0], [-1.0 / self.f.ref, 1.0]]) M_num = np.array(M_sym, dtype=np.float64)  Daniel Brown committed Dec 16, 2020 89  key = (self.p1.i, self.p2.o, direction)  Samuel Rowlinson committed Dec 24, 2020 90  self._abcd_matrices[key] = (M_sym, M_num)  Daniel Brown committed Dec 16, 2020 91  key = (self.p2.i, self.p1.o, direction)  Samuel Rowlinson committed Dec 24, 2020 92  self._abcd_matrices[key] = (M_sym, M_num)  Samuel Rowlinson committed Jul 20, 2020 93   94 95 96 97 98 99 100 101  @property def abcdx(self): """Numeric ABCD matrix in the tangential plane. Equivalent to lens.ABCD(1, 2, "x") and lens.ABCD(2, 1, "x"). :getter: Returns a copy of the (numeric) ABCD matrix for this coupling (read-only). """  Daniel Brown committed Dec 16, 2020 102  _, M = self._abcd_matrices[(self.p1.i, self.p2.o, "x")]  103 104 105 106 107 108 109 110 111 112  return M.copy() @property def abcdy(self): """Numeric ABCD matrix in the sagittal plane. Equivalent to lens.ABCD(2, 1, "y") and lens.ABCD(2, 1, "y"). :getter: Returns a copy of the (numeric) ABCD matrix for this coupling (read-only). """  Daniel Brown committed Dec 16, 2020 113  _, M = self._abcd_matrices[(self.p1.i, self.p2.o, "y")]  114 115  return M.copy()  Samuel Rowlinson committed Jul 20, 2020 116  def ABCD(  Samuel Rowlinson committed Dec 05, 2020 117 118 119 120 121 122 123  self, from_node, to_node, direction="x", symbolic=False, copy=True, retboth=False,  Samuel Rowlinson committed Jul 20, 2020 124  ):  125  r"""Returns the ABCD matrix of the lens for the specified coupling.  Samuel Rowlinson committed Mar 12, 2020 126 127 128 129 130 131  .. _fig_abcd_lens_transmission: .. figure:: ../images/abcd_lenst.* :align: center This is given by,  Samuel Rowlinson committed Nov 21, 2018 132 133 134 135 136 137 138 139 140  .. math:: M = \begin{pmatrix} 1 & 0 \\ -\frac{1}{f} & 1 \end{pmatrix}, where :math:f is the focal length of the lens.  141 142  See :meth:.Connector.ABCD for descriptions of parameters, return values and possible exceptions.  Samuel Rowlinson committed Nov 21, 2018 143  """  Daniel Brown committed Dec 16, 2020 144  return super().ABCD(from_node, to_node, direction, symbolic, copy, retboth)  Samuel Rowlinson committed Nov 21, 2018 145   Samuel Rowlinson committed Nov 16, 2020 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175  def actuate_f(self, dioptres, direction=("x", "y")): r"""Actuate on the focal length of the lens with a specified dioptre shift. Sets the focal length to a new value, :math:f_2, via, .. math:: f_2 = \frac{1}{d + \frac{1}{f_1}}, where :math:f_1 is the current focal length and :math:d is the dioptre shift (i.e. the dioptre argument). By default, both focal planes are shifted. To shift, e.g., only the tangential plane, specify direction="x". Parameters ---------- dioptres : float Shift in lens focal length in dioptres. direction : tuple or str, optional; default: ("x", "y") Focal plane to shift, defaults to both tangential and sagittal. """ fnew = lambda x: 1 / (dioptres + 1 / x) if "x" in direction: # TODO (sjr) Change to fx self.f = fnew(self.f.value) if "y" in direction: # TODO (sjr) Change to fy self.f = fnew(self.f.value)  Daniel Brown committed Apr 29, 2020 176 177 178  def _fill_matrix(self, ws): for freq in ws.sim.frequencies: with ws.sim.component_edge_fill3(  179  ws.owner_id, ws.connections.P1i_P2o_idx, freq.index, freq.index,  Daniel Brown committed Apr 29, 2020 180  ) as mat:  Daniel Brown committed Apr 10, 2020 181  mat[:] = ws.K12.data  Daniel Brown committed Apr 29, 2020 182 183  with ws.sim.component_edge_fill3(  184  ws.owner_id, ws.connections.P2i_P1o_idx, freq.index, freq.index,  Daniel Brown committed Apr 29, 2020 185  ) as mat:  Daniel Brown committed Apr 10, 2020 186 187  mat[:] = ws.K21.data  Daniel Brown committed Apr 29, 2020 188 189  def _get_workspace(self, sim): _, is_changing = self._eval_parameters()  Samuel Rowlinson committed Jun 09, 2020 190  refill = self in sim.trace_forest.changing_components or len(is_changing)  Daniel Brown committed Apr 29, 2020 191 192  ws = LensWorkspace(self, sim, refill)  Samuel Rowlinson committed May 13, 2020 193 194 195 196  # This assumes that nr1/nr2 cannot change during a simulation ws.nr1 = refractive_index(self.p1) or 1 ws.nr2 = refractive_index(self.p2) or 1  Daniel Brown committed Apr 29, 2020 197 198  ws.set_fill_fn(self._fill_matrix)  Samuel Rowlinson committed May 12, 2020 199  if sim.is_modal:  Daniel Brown committed Dec 16, 2020 200 201 202 203  key = (self.p1.i, self.p2.o, "x") _, ws.abcd_x = self._abcd_matrices[key] key = (self.p1.i, self.p2.o, "y") _, ws.abcd_y = self._abcd_matrices[key]  Samuel Rowlinson committed May 12, 2020 204   Daniel Brown committed Apr 29, 2020 205  return ws