Source code for finesse.utilities.components

"""Utility functions related to component objects."""
import os


[docs]def refractive_index(port, symbolic=False): """Obtains the refractive index of the space attached to the port/node `port`. Parameters ---------- port : :class:`.Port` or :class:`.Node` Port or node. Returns ------- nr : float The refractive index of the space attached to the port / node. Returns unity if no space is present. """ get_nr = lambda space, symbol: space.nr.ref if symbol else space.nr.eval() space = port.space if space is not None: nr = get_nr(space, symbolic) else: from finesse.components import Beamsplitter # If we're at a beamsplitter then get nr # of port on same surface if isinstance(port.component, Beamsplitter): adj_port = port.component.get_adjacent_port(port) space = adj_port.space if space is None: # FIXME (sjr) This should probably raise an exception but parsing # (at least for legacy files) means that both spaces # can be None initially somehow when symbolising # Beamsplitter ABCD matrices nr = 1 else: nr = get_nr(space, symbolic) else: nr = 1 return nr
[docs]def names_to_nodes(model, names, default_hints=()): """Attempts to convert a list of node/dof/ports into nodes. This is to provide a way for actions to convert string names into nodes for simulation use. It attempts to provide useful default behaviours, and can accept "hints" on how to select nodes. Parameters ---------- names : iterable[str|(str, iterable[str])] A collection of names to convert. A (name, hint) pair can also be provided where hint is an iterable of strings. default_hints : iterable[str] Default hint to use with particular set of names if no hints are provided. Notes ----- Posible hints when name is a Port or DOF: - `input` : try and select a singular input node - `output` : try and select a singular output node Examples -------- Selecting various nodes from a model with and without hinting: >>> import finesse >>> from finesse.utilities.components import names_to_nodes >>> model = finesse.Model() >>> model.parse(''' ... l l1 P=100k ... mod mod1 f=10M midx=0.1 order=1 mod_type=pm ... m m1 R=1-m1.T T=0.014 Rc=-1984 xbeta=0n ... m m2 R=1 T=0 Rc=2245 xbeta=0n phi=0 ... link(l1, mod1, m1, 3994, m2) ... dof DARM m1.dofs.z -1 m2.dofs.z +1 ... ''') >>> names_to_nodes(model, ('m1.p1', 'DARM.AC'), default_hints=('output')) [<OpticalNode m1.p1.o @ 0x7f92c9a5c880>, <SignalNode DARM.AC.o @ 0x7f92c9a0e5b0>] >>> names_to_nodes(model, ('m1.p1', 'DARM.AC'), default_hints=('input')) [<OpticalNode m1.p1.i @ 0x7f92c9a5ca60>, <SignalNode DARM.AC.i @ 0x7f92c9a0e460>] >>> names_to_nodes(model, ('m1.p1.o', 'DARM.AC.i')) [<OpticalNode m1.p1.o @ 0x7f92c9a5c880>, <SignalNode DARM.AC.i @ 0x7f92c9a0e460>] Hints do not insist on a particular output. For example, this is valid: >>> names_to_nodes(model, ('m1.p1.o', ('DARM.AC.o', "input"))) """ from finesse.components import Port, Node, DegreeOfFreedom rtn = [] for name in names: # Actions can provide hints on how to select nodes try: name, hints = name except Exception: hints = default_hints obj = model.get(name) is_port = isinstance(obj, Port) is_node = isinstance(obj, Node) is_dof = isinstance(obj, DegreeOfFreedom) # Grab the AC port by default for DOFs if is_dof: obj = obj.AC is_port = True is_dof = False if is_port: N = len(obj.nodes) if N == 1: # select only single node from port obj = obj.nodes[0] elif "input" in hints: is_input_node = tuple(_.is_input for _ in obj.nodes) if is_input_node.count(True) == 1: idx = is_input_node.index(True) obj = obj.nodes[idx] else: raise ValueError( f"Port {repr(obj)} does not have a single input node so you must specify which to use. It has \n{ os.linesep.join((repr(_) for _ in obj.nodes)) }" ) elif "output" in hints: is_output_node = tuple(not _.is_input for _ in obj.nodes) if is_output_node.count(True) == 1: idx = is_output_node.index(True) obj = obj.nodes[idx] else: raise ValueError( f"Port {repr(obj)} does not have a single output node so you must specify which to use. It has \n{ os.linesep.join((repr(_) for _ in obj.nodes)) }" ) else: raise ValueError( f"Port {repr(obj)} does not have a single node to select from, so you must specify which to use. It has: \n{ os.linesep.join((repr(_) for _ in obj.nodes)) }" ) elif not (is_node or is_port): raise ValueError(f"Value {repr(obj)} was neither a Port nor a Node") rtn.append(obj) return rtn