finesse.analysis.actions package

Submodules

finesse.analysis.actions.axes module

Axes Actions such as xaxis, noaxais, etc.

class finesse.analysis.actions.axes.Noxaxis(pre_step=None, post_step=None, name='noxaxis')

Bases: Sweep

class finesse.analysis.actions.axes.X2axis(parameter1, mode1, start1, stop1, steps1, parameter2, mode2, start2, stop2, steps2, relative=False, *, pre_step=None, post_step=None, name='x2axis')

Bases: XNaxis

class finesse.analysis.actions.axes.X3axis(parameter1, mode1, start1, stop1, steps1, parameter2, mode2, start2, stop2, steps2, parameter3, mode3, start3, stop3, steps3, relative=False, *, pre_step=None, post_step=None, name='x3axis')

Bases: XNaxis

class finesse.analysis.actions.axes.XNaxis(*args, relative=False, pre_step=None, post_step=None, name='XNaxis')

Bases: Sweep

class finesse.analysis.actions.axes.Xaxis(parameter, mode, start, stop, steps, relative=False, *, pre_step=None, post_step=None, name='xaxis')

Bases: XNaxis

finesse.analysis.actions.base module

Base level Actions utilities and classes.

class finesse.analysis.actions.base.Action(name, analysis_state_manager=False)

Bases: object

Base class for all actions

property analysis_state_manager
get_requests(model)
property name
plan(previous=None)

Returns an expected plan for the actions that will be run in a tree form. This may not be exactly what is ran.

Returns

plan : TreeNode

class finesse.analysis.actions.base.AnalysisState(model, name='AnalysisState', parent=None, simulation_type=None, simulation_options=None)

Bases: TreeNode

property action_workspaces

Actions can use their id, id(self), to generate a key to store simulation specific data and reuse it each time run is called.

apply(action)
build_model(changing_params, extra_input_nodes, extra_output_nodes)
finished()
property model
property previous_solution
property sim
finesse.analysis.actions.base.convert_str_to_parameter(model, attr)

Converts names component.parameter or component to a parameter object. Will return default parameter when component name is given.

Parameters

modelModel

Model object to look for parameter in

attr[str | Parameter]

String value for the name of an element or a parameters full name. If a Parameter is given its full name will be used to grab the equivalent parameter in this Model.

Returns

parameter

The equivalent Parameter object for the attr provided

finesse.analysis.actions.base.request_dict_reduction(A, B)

finesse.analysis.actions.beam module

Collection of Actions that involve beam tracing.

class finesse.analysis.actions.beam.ABCD(name='abcd', **kwargs)

Bases: Action

Computation of an ABCD matrix over a path.

See compute_abcd() for details.

class finesse.analysis.actions.beam.BeamTrace(name='beam_trace', **kwargs)

Bases: Action

Full beam tracing on a complete model.

See Model.beam_trace() for details.

class finesse.analysis.actions.beam.PropagateAstigmaticBeam(name='astig_propagation', **kwargs)

Bases: Action

Propagation of a beam, in both planes, through a given path.

See Model.propagate_beam_astig() for details.

class finesse.analysis.actions.beam.PropagateBeam(name='propagation', **kwargs)

Bases: Action

Propagation of a beam, in a single plane, through a given path.

See Model.propagate_beam() for details.

finesse.analysis.actions.dc module

class finesse.analysis.actions.dc.DCFields(*, name='dcfields')

Bases: Action

An action that saves the DC (carrier) fields at all nodes, frequencies, and higher order modes for the current state of the simulation.

Parameters

namestr, optional

Name of the solution generated by this action

class finesse.analysis.actions.dc.DCFieldsSolutions

Bases: BaseSolution

Contains the result of a DCFields action. The returned fields are the internal description of the carrier are all nodes, modes, and frequencies. Fields are defined as P=|E|^2.

Attributes

homslist

The Hermite-Gaussian higher order mode indices at each node, of each frequency.

nodestuple[str]

Name of nodes the fields were extracted at

frequenciesarray_like[dtype=float]

Values of the optical frequencies at each node

fieldsarray_like

Field data array with shape [nodes, frequencies, HOMs.shape[0]]

Notes

The fields attribute will contain all the required information with its ordering defined by the nodes, frequencies, and homs array. For easier indexing you can access the solution directly with node names.

Select all the frequencies and modes at l1.p1.i: >>> sol[‘l1.p1.i’]

Select all the first modes at all frequencies and modes at l1.p1.i: >>> sol[‘l1.p1.i’, :, 0]

Select all the frequencies and modes at two nodes: >>> sol[(‘l1.p1.i’, ‘l1.p1.o’)]

The same nodes can be selected directly with the OpticalNodes: >>> sol[(model.l1.p1.i, model.l1.p1.o)]

Select all the HG02 modes at every node and frequency >>> sol[:, :, sol.homs.index([0, 2]))]

Select all the HG02 modes at every output node and every frequency >>> idx = np.array([node.split(“.”)[-1] == “o” for node in sol.nodes]) >>> sol[idx, :, sol.homs.index([0, 2])]

The frequency and mode selection must be a slice or an array of integer or boolean values.

fields = None
frequencies = None
homs = None
nodes = None
selector(key)

finesse.analysis.actions.debug module

class finesse.analysis.actions.debug.Debug(name='Debug')

Bases: Action

An action that will start an IPython debug shell.

To access the current model use state.model.

class finesse.analysis.actions.debug.SaveMatrix(*, name='savematrix')

Bases: Action

An action that will save the current state of the matrix being used by the simulation.

Not something that should be used lightly in loops or multiple times in a large simulation. Using this in something like a full LIGO model with many HOMs and sidebands will quickly fill up memory.

class finesse.analysis.actions.debug.SaveMatrixSolution

Bases: BaseSolution

Attributes

carriercoo_matrix

A Scipy coo_matrix of the carrier simulation matrix. None if the matrix was not available.

signalcoo_matrix

A Scipy coo_matrix of the signal simulation matrix. None if the matrix was not available.

finesse.analysis.actions.folder module

Folder Action.

class finesse.analysis.actions.folder.Folder(name, action, solution)

Bases: Action

A Folder action collects a new solution every time the action is called.

An example of this is the ‘post step’ for the xaxis. A folder action is made called post_step and is passed to a function which will do it multiple times. After each step the specificed action is called and its solution will be added to the folder.

finesse.analysis.actions.locks module

Lock Actions.

class finesse.analysis.actions.locks.DragLocks(*locks, parameters, stop_points, relative=False, method='proportional', scale_factor=1, num_steps=11, never_optimize_phase=None, exception_on_fail=True, max_recursions=5, max_iterations=1000, display_progress=False, show_progress_bar=False, name='drag locks')

Bases: Action

An action that incrementally changes model parameter values, reaching lock at each step, until lock is reached at the desired final parameter values.

Parameters

*lockslist, optional

A list of locks to use in each finesse.analysis.actions.locks.RunLocks step. Acts like the *locks parameter in finesse.analysis.actions.locks.RunLocks: if not provided, all locks in model are used.

parameterslist

A list of strings. Each element should correspond to a parameter in the model.

stop_pointslist

The final parameter values that locks move towards incrementally.

relativeboolean

If true, stop_points are relative to the initial parameter values.

max_recursionsint

The number of times that the step size is allowed to decreased by a factor of ten when locks fail.

methodstr, either “newton” or “proportional”

The method to use in each locking step.

scale_factorfloat

Factor by which to multiply all DOF changes. Should be set below 1 if it is desired to minimize overshooting.

num_stepsint

Number of steps to calculate, starting at the initial point and ending at the stop point.

never_optimize_phaseboolean

Deprecated: When true, never optimize readout phases. When false, phases will be optimized anytime the previous step required more than 10 iterations.

exception_on_failboolean

When true, raise exception if max_recursions is surpassed.

max_iterationsint

The maximum number of locking steps in each execution of RunLocks. If surpassed, step size is decreased.

display_progressboolean

When true, displays the status of the lock dragging.

namestr

Name of the action.

class finesse.analysis.actions.locks.RunLocks(*locks, method='proportional', scale_factor=1, sensing_matrix=None, max_iterations=10000, display_progress=False, optimize_phase=None, d_dof_phase=1e-09, set_gains=True, d_dof_gain=1e-09, exception_on_fail=True, no_warning=False, pre_step=None, show_progress_bar=None, name='run locks')

Bases: Action

An action that iteratively moves the system to lock. Currently, lock error signals must be readouts, not detectors, for use in this action.

Parameters

*lockslist, optional

A list of locks to use in each RunLocks step. If not provided, all locks in model are used.

methodstr, either “newton” or “proportional”

Which method to use in the locking iterations.

scale_factorfloat

Factor by which to multiply all DOF changes. Should be set below 1 if it is desired to minimize overshooting.

sensing_matrixSensingMatrixSolution or None

Sensing matrix of gains used in locking, of the type that would be returned by state.apply(SensingMatrixDC(lock_dof_names, readout_names) If None, the sensing matrix is recalculated. Recommended to be None except when locking multiple times in a row, e.g. with DragLocks.

max_iterationsint

The maximum number of locking steps in each execution of RunLocks.

display_progressboolean

When true, displays the status of the error signals during locking iterations.

optimize_phaseboolean

Deprecated: Use an action like OptimiseRFReadoutPhaseDC instead.

d_dof_phasefloat

Step size to use when optimizing the demodulation phase for each error signal/DOF pair.

set_gainsboolean

Only applies if method is “proportional”. If true, sets the gains for each error signal/DOF pair. If false, uses pre-set gains.

d_dof_gainfloat

Step size to use when calculating the gain for every pair of error signals and DOFs.

exception_on_failboolean

When true, raise exception if maximum iterations are surpassed.

no_warningboolean

When true, don’t even raise a warning if maximum iterations are reached. Recommended to be false unless repeatedly testing locking.

pre_stepAction

Action to apply on each step of the lock

show_progress_barboolean

Will enable the progress bar when true.

namestr

Name of the action.

complete_pbar()
init_pbar(locks)
update_pbar()
update_pbar_lock(lock_name, is_locked)
class finesse.analysis.actions.locks.RunLocksSolution(*args, **kwargs)

Bases: BaseSolution

Solution from applying the RunLocks action.

Attributes

itersint

Number of steps lock has required

max_iterationsint

Maximum number of iterations this lock can do

error_signalsarray_like

error signals during locking steps, shape [num_locks, max_iterations]

control_signalsarray_like

Control signals during locking steps, shape [num_locks, max_iterations]

lock_namestuple[str]

Names of locks being controlled, shape [num_locks]

feedback_namestuple[str]

Names of feedback for each lock, shape [num_locks]

feedback_namestuple[str]

Names of error signals for each lock, shape [num_locks]

finalarrary_like

Final control signals, shape [num_locks]

sensing_matrixSensingMatrixSolution, optional

The sensing matrix used when running the locks with Newton’s method.

plot(ax=None)

Plots how the error signals vary during this lock attempt.

Parameters

axMatplotlib.Axes, optional

Axes to plot on, if no current axis is set then a new one is generated

plot_control_signals(ax=None)

Plots how the controls signals vary during this lock attempt. If 0 gaps will be shown when no change has been made to that degree of freedom for that step (As it was within the locks accuracy setting).

Parameters

axMatplotlib.Axes, optional

Axes to plot on, if no current axis is set then a new one is generated

plot_error_signals(ax=None)

Plots how the error signals vary during this lock attempt.

Parameters

axMatplotlib.Axes, optional

Axes to plot on, if no current axis is set then a new one is generated

class finesse.analysis.actions.locks.SetLockGains(*locks, d_dof_gain=1e-10, gain_scale=1, name='set gains', optimize_phase=None, verbose=False)

Bases: Action

An action that computes the optimal lock gains using the sensing matrix found with SensingMatrixDC. This action computes the error signal gradient for each lock with respect to its drive and sets the gain as -gain_scale/sensing.

Parameters

*lockslist, optional

A list of locks for which to set the gain. If none provided, all enabled locks in model are used. Disabled locks that are explicitly listed will have their gains set.

d_dof_gainfloat, optional

Step size to use when calculating the gain for each error signal/DOF pair.

gain_scalefloat, optional

Extra gain scaling factor applied to the gain calculation: -gain_scale/sensing In multiple lock models where the locks are cross coupled using a gain_scale < 1 can improve the stability of the locking algorithm to stop excessively large steps.

optimize_phasebool, optional,

Deprecated feature: Use OptimiseRFReadoutPhaseDC instead

namestr

Name of the action.

verbosebool

If True this will print the name of the enabled locks and their gains.

finesse.analysis.actions.lti module

Collection of Actions that deal linear time invariant (LTI) modelling tasks.

class finesse.analysis.actions.lti.FrequencyResponse(f, inputs, outputs, *, open_loop=False, name='frequency_response')

Bases: Action

Computes the frequency response of a signal injected at various nodes to compute transfer functions to multiple output nodes. Inputs and outputs should be electrical or mechanical nodes. It does this in an efficient way by using the same model and solving for multiple RHS input vectors.

This action does not alter the model state. This action will ignore any currently definied signal generator elements in the model.

Produces an output transfer matrix from each input node to some readout output. The shape of the output matrix is:

[frequencies, inputs, outputs]

To inject into optical nodes please see FrequencyResponse2 and FrequencyResponse3. To readout optical nodes please see FrequencyResponse3 and FrequencyResponse4.

Parameters

farray, double

Frequencies to compute the transfer functions over

inputsiterable[str or Element]

Mechanical or electrical node to inject signal at

outputsiterable[str or Element]

Mechanical or electrical nodes to measure output at

open_loopbool, optional

Computes open loop transfer functions if the system has closed

namestr, optional

Solution name

Examples

Here we measure a set of transfer functions from DARM and CARM to four readouts for a particular model,

>>> sol = model.run(FrequencyResponse(np.geomspace(0.1, 50000, 100),
...         ('DARM', 'CARM'),
...         ('AS.DC', 'AS45.I', 'AS45.Q', 'REFL9.I'),
... ))

Single inputs and outputs can also be specified

>>> model.run(FrequencyResponse(np.geomspace(0.1, 50000, 100), 'DARM', AS.DC'))

The transfer functions can then be accessed like a 2D array by name, the ordering of inputs to outputs does not matter.

>>> sol['DARM'] # DARM to all outputs
>>> sol['DARM', 'AS.DC'] # DARM to AS.DC
>>> sol['DARM', ('AS.DC', 'AS45.I')]
>>> sol['AS.DC'] # All inputs to AS.DC readout
class finesse.analysis.actions.lti.FrequencyResponse2(f, inputs, outputs, *, name='frequency_response2')

Bases: Action

Computes the frequency response of a signal injected at an optical port at a particular optical frequency. This differs from FrequencyResponse in the way the inputs and outputs are prescribed. For FrequencyResponse2 you specify optical input nodes and a signal output node.

This action does not alter the model state. This action will ignore any currently definied signal generator elements in the model.

Produces an output transfer matrix from each HOM at a particular frequency and optical node to some readout output. The shape of the output matrix is:

[frequencies, outputs, inputs, HOMs]

It should be noted that when exciting a lower signal sideband frequency it will actually return the operator for propagating the conjugate of the lower sideband. This is because FINESSE is internally solving for the conjugate of the lower sideband to linearise non-linear optical effects.

To inject into mechanical and electrical nodes please see FrequencyResponse and FrequencyResponse4. To readout optical nodes please see FrequencyResponse3 and FrequencyResponse4.

Parameters

farray, double

Frequencies to compute the transfer functions over

inputsiterable[tuple[str or Node, Frequency]]

Optical node and frequency tuple to inject at. A symbolic refence to the model’s fsig.f parameter should always be used when defining a frequency to look at.

outputsiterable[str or Element]

Mechanical or electrical (signal)nodes to measure output to

namestr, optional

Solution name

Examples

It is advisable to use always use a reference to the symbolic reference to the signal frequency model.fsig.f.ref instead of a fixed number incase it changes. This action will look for an initial frequency bin of X Hz to track during the frequency response analysis. A symbolic reference will always ensure the right bin is used, in cases such as looking at RF signal sidebands, 10e6+model.fsig.f.ref and 10e6-model.fsig.f.ref will always look at the upper and lower signal sideband around the +10MHz sideband.

>>> import finesse
>>> from finesse.analysis.actions import FrequencyResponse2
>>> model = finesse.script.parse('''
... l l1
... bs bs1 R=1 T=0 xbeta=1e-6 ybeta=1e-9
... readout_dc A
... link(l1, bs1, A)
... fsig(1)
... modes(maxtem=1)
... gauss g1 l1.p1.o w=1m Rc=inf
... ''')
>>> sol = model.run(
...     FrequencyResponse2(
...         [1, 10, 100],
...         [
...             ('bs1.p2.o', +model.fsig.f.ref),
...             ('bs1.p2.o', -model.fsig.f.ref)
...         ],
...         ['A.DC']
...     )
... )
class finesse.analysis.actions.lti.FrequencyResponse3(f, inputs, outputs, *, name='frequency_response3')

Bases: Action

Computes the frequency response of a signal injected at an optical port at a particular optical frequency. This differs from FrequencyResponse in the way the inputs and outputs are prescribed. For FrequencyResponse3 you specify optical input nodes and optical output nodes.

This action does not alter the model state. This action will ignore any currently definied signal generator elements in the model.

Produces an output transfer matrix from each HOM at a particular frequency and optical node to some other optical node and frequency. The shape of the output matrix is:

[frequencies, outputs, inputs, HOMs, HOMs]

It should be noted that when exciting a lower signal sideband frequency it will actually return the operator for propagating the conjugate of the lower sideband. This is because FINESSE is internally solving for the conjugate of the lower sideband to linearise non-linear optical effects.

To inject into mechanical and electrical nodes please see FrequencyResponse and FrequencyResponse4. To readout mechanical and electrical nodes please see FrequencyResponse and FrequencyResponse2.

Parameters

farray, double

Frequencies to compute the transfer functions over

inputsiterable[tuple[str or Node, Frequency]]

Optical node and frequency tuple to inject at. A symbolic reference to the model’s fsig.f parameter should always be used when defining a frequency to look at.

outputsiterable[tuple[str or Node, Frequency]]

Optical node and frequency tuple to measure output at. A symbolic reference to the model’s fsig.f parameter should always be used when defining a frequency to look at.

namestr, optional

Solution name

Examples

It is advisable to use always use a reference to the symbolic reference to the signal frequency model.fsig.f.ref instead of a fixed number incase it changes. This action will look for an initial frequency bin of X Hz to track during the frequency response analysis. A symbolic reference will always ensure the right bin is used, in cases such as looking at RF signal sidebands, 10e6+model.fsig.f.ref and 10e6-model.fsig.f.ref will always look at the upper and lower signal sideband around the +10MHz sideband.

>>> import finesse
>>> from finesse.analysis.actions import FrequencyResponse3
>>> model = finesse.script.parse('''
... l l1
... bs bs1 R=1 T=0 xbeta=1e-6 ybeta=1e-9
... readout_dc A
... link(l1, bs1, A)
... fsig(1)
... modes(maxtem=1)
... gauss g1 l1.p1.o w=1m Rc=inf
... ''')
>>> sol = model.run(
...     FrequencyResponse3(
...         [1, 10, 100],
...         [
...             ('bs1.p2.o', +model.fsig.f.ref),
...             ('bs1.p2.o', -model.fsig.f.ref)
...         ],
...         [
...             ('A.p1.i', +model.fsig.f.ref),
...             ('A.p1.i', -model.fsig.f.ref)
...         ]
...     )
... )
class finesse.analysis.actions.lti.FrequencyResponse4(f, inputs, outputs, *, name='frequency_response4')

Bases: Action

Computes the frequency response of a signal injected at an electrical or mechanical port. This differs from FrequencyResponse in the way the inputs and outputs are prescribed. For FrequencyResponse4 you specify signal input nodes and optical output nodes.

This action does not alter the model state. This action will ignore any currently defined signal generator elements in the model.

Produces an output transfer matrix from each signal node to each HOM at a particular frequency and optical node. The shape of the output matrix is:

[frequencies, outputs, inputs, HOMs]

It should be noted that when exciting a lower signal sideband frequency it will actually return the operator for propagating the conjugate of the lower sideband. This is because FINESSE is internally solving for the conjugate of the lower sideband to linearise non-linear optical effects.

To inject into optical nodes please see FrequencyResponse2 and FrequencyResponse3. To readout mechanical and electrical nodes please see FrequencyResponse and FrequencyResponse2.

Parameters

farray, double

Frequencies to compute the transfer functions over

inputsiterable[str or Element]

Mechanical or electrical node to inject signal at

outputsiterable[tuple[str or Node, Frequency]]

Optical node and frequency tuple to measure output at. A symbolic reference to the model’s fsig.f parameter should always be used when defining a frequency to look at.

namestr, optional

Solution name

Examples

It is advisable to use always use a reference to the symbolic reference to the signal frequency model.fsig.f.ref instead of a fixed number incase it changes. This action will look for an initial frequency bin of X Hz to track during the frequency response analysis. A symbolic reference will always ensure the right bin is used, in cases such as looking at RF signal sidebands, 10e6+model.fsig.f.ref and 10e6-model.fsig.f.ref will always look at the upper and lower signal sideband around the +10MHz sideband.

>>> sol = model.run(
...     FrequencyResponse(
...         [1, 10, 100],
...         [model.ETM.mech.z],
...         [
...             (model.ITM.p2.o, +model.fsig.f.ref),
...             (model.ITM.p2.o, -model.fsig.f.ref)
...         ]
...     )
... )
class finesse.analysis.actions.lti.FrequencyResponseSolution

Bases: BaseSolution

A solution from running a FrequencyResponse action on a model. This solution contains the frequency vector and potentially multiple input and output transfer function matrix.

Attributes

farray_like

Frequency vector [Hz]

inputsarray_like

The input names injected into for this analysis

outputsarray_like

The output names read out for this analysis

outarrray_like[dtype=np.complex128]

A matrix of transfer functions for each input to every output over the array of frequencies requested. Depending on which frequency response action was run will decide what shape this output matrix actually is. The shape of out is dependent on the analysis done:

  • FrequencyResponse - (N_f, N_outputs, N_inputs)

  • FrequencyResponse2 - (N_f, N_outputs, N_inputs, N_hom)

  • FrequencyResponse3 - (N_f, N_outputs, N_inputs, N_hom, N_hom)

  • FrequencyResponse4 - (N_f, N_outputs, N_inputs, N_hom)

typetype

Type of FrequencyResponse that was used to generate this solution

Examples

Note that the name indexing below is only available when used with the FrequencyResponse action, the other frequency-response actions must be accessed using the out attribute.

Results from a FrequencyResponseSolution can be retrieved in two ways, first through the FrequencyResponseSolution.out array or by name using [outputs, inputs]. As an example we will create a fake solution:

>>> from finesse.analysis.actions.lti import FrequencyResponseSolution
>>> sol = FrequencyResponseSolution("name")
>>> sol.inputs = ("A", "B", "C")
>>> sol.outputs = ("D", "E", "F", "G")
>>> sol.out = np.random.rand(3, len(sol.outputs), len(sol.inputs))

The names will map to those provided in the FrequencyResponse action you called to generate the solution.

The following will work to select single transfer functions between some input and output by name:

>>> sol["D", "A"] # Select A -> D
>>> sol["D", "C"] # Select C -> D
>>> sol["F", "C"] # Select C -> F

Transfer function matrices can be extracted by providing multiple

>>> sol["F", ("C", "A")]
>>> sol[("F", "G"), ("C", "A")]

Slicing can also be used:

>>> sol["D", :]   # Select all inputs to "D"
>>> sol["D", ::2] # Select every other input to "D"
>>> sol[:, "B"]   # Select "B" to all outputs
>>> sol[1:, "B"]  # Select "B" to all but the first output
outputs_inputs_indices(outputs: List[str], inputs: List[str], *, reversed: bool = False) Tuple[int, int]

Returns the indices to use for selecting certain inputs and outputs from the out attribute of this solution object.

Parameters

outputsList[str]

List of names of outputs, see outputs attribute for options

inputsList[str]

List of names of inputs, see inputs attribute for options

reversedbool, optional

Should not be used by the user, this is an internal flag used for checking if the reverse case should be tried, ie. inputs specified first rather than outputs. This is for backwards compatibility before FrequencyResponse was fixed.

Returns

output_index, input_index

Indices for the outputs and inputs

Raises

KeyError

Raised when no input or output name can be found.

plot(*inputs, axs=None, max_width=12, show_unity=False, **kwargs)

Plot all transfer functions on a NxM grid with a max_width.

Parameters

inputs*,

Names of inputs for each subplot

axs_type_, optional

Matplotlib axes to draw on

max_widthint, optional

Maximum number of subplots in width

show_unitybool, optional

Plot a line where unity is

Returns

figure, axes

Matplotlib figure and axes to plot on

plot_inputs(*inputs, axs=None, max_width=12, show_unity=False, **kwargs)

Plot all transfer functions on a NxM grid with a max_width.

Parameters

inputs*,

Names of inputs for each subplot

axs_type_, optional

Matplotlib axes to draw on

max_widthint, optional

Maximum number of subplots in width

show_unitybool, optional

Plot a line where unity is

Returns

figure, axes

Matplotlib figure and axes to plot on

plot_outputs(*outputs, axs=None, max_width=12, **kwargs)

Plot all transfer functions on a NxM grid with a max_width.

Parameters

outputs*,

Names of outputs for each subplot

axs_type_, optional

Matplotlib axes to draw on

max_widthint, optional

Maximum number of subplots in width

show_unitybool, optional

Plot a line where unity is

Returns

figure, axes

Matplotlib figure and axes to plot on

finesse.analysis.actions.noise module

Actions to compute noise projections and budgets.

class finesse.analysis.actions.noise.NoiseProjection(f, *output_nodes, scaling=None, name='loop')

Bases: Action

class finesse.analysis.actions.noise.NoiseProjectionSolution

Bases: BaseSolution

plot(self, *args, show=True, **kwargs)

Plot solution(s).

If the solution contains child solutions, they are plotted in order. Solutions without plot arguments are skipped. Positional arguments passed to this method are assumed to be dict and are unpacked into calls to each child’s plot method. Global arguments to be passed to all plot methods can be specified directly as keyword arguments. Duplicate arguments specified in a positional argument dictionaries take precendence over global arguments.

Parameters

showbool, optional

Show the figures.

Other Parameters

*args

Sequence of dict to use as parameters for the call to each child solution’s plot method.

**kwargs

Keyword arguments supported by the child solution(s).

Notes

If the Nth solution contains no plot method, it still consumes the Nth positional argument passed to this method.

finesse.analysis.actions.operator module

Operator based Actions to extract operators and perform operator based analyes, such as calculating eigenmodes.

class finesse.analysis.actions.operator.Eigenmodes(cavity: Cavity, frequency, *, name='eigenmodes')

Bases: Action

For a given Cavity defined in a model, this action will compute the roundtrip operator and calculate the eigen-values and -vectors of the cavity. This will not give correct solutions for coupled cavities as these need to include additional effects.

This can be used to determine what modes combination of modes are resonating in a cavity and the required tuning to make that mode resonate.

Parameters

cavitystr or Cavity

cavity name or Cavity instance

frequencyfloat

Optical carrier or signal frequency to use for calculating the operators

namestr, optional

Name of the solution generated by this action

class finesse.analysis.actions.operator.EigenmodesSolution

Bases: BaseSolution

Contains the result of an Eigenmodes action. The start node is defined by the Cavity starting point.

Attributes

connectionstuple((Node, Node))

Node connections used in the round trip propagator

roundtrip_matrixarray

Combined round trip matrix operator for the cavity

matriceslist[array]

A list of operators for each connection

eigvalues, eigvectorsarray, array

Eigen values and vectors of the round trip matrix

cavity_planewave_lossfloat

Round trip loss for a planewave

homsarray_like

Array of HOMs used in the model at the time this was computed

loss(remove_planewave_loss=False)

Computes the round trip loss of all the eigenmodes of the cavity. Eigenmodes are ordered by loss. Lowest loss may not be the fundamental mode.

Parameters

remove_planewave_lossbool, optional

Whether to remove the roundtrip loss a plane wave would experience to see the loss induced from HOM effects.

Returns

indexarray_like

Indicies of ordering for the eigvalues and eigvectors of this solution

lossarray_like

Roundtrip loss of modes

plot_field(mode_idx, *, x=None, y=None, samples=100, scale=3, ax=None, colorbar=True, **kwargs)

Plots a 2D optical field for one of the eigenmodes.

x and y dimensions can be specified if required, otherwise it will return an area of scale times the spot sizes. When x and y are provided scale and samples will not do anything.

Parameters

mode_idxint

index of the mode to plot

x, yndarray, optional

Specify x and y coordinates to plot beam

samplesint, optional

Number of sample points to use in x and y

scalefloat, optional

Number of sample points to use in x and y

axAxis, optional

A Matplotlib axis to put the image on. If None, a new figure will be made.

colorbarbool

When True the colorbar will be added

**kwargs

Extra keyword arguments will be passed to the pcolormesh plotting function.

plot_phase(scale=None, ax=None, **kwargs)

Plots the eigenmode phases.

Parameters

scalefloat

Scale of scatter point size

axMatplotlib.Axis, optional

The axis to plot on to, if None a new figure is made

**kwargs

Keyword arguments passed to matplotlib.pyplot.scatter for styling trace

plot_roundtrip_loss(remove_planewave_loss=False, ax=None, **kwargs)

Plots the roundtrip loss of the cavity for each eigenmode.

Parameters

remove_planewave_lossbool, optional

If True, remove the loss a planewave would experience to just see the effects from higher order modes.

axMatplotlib.Axis, optional

The axis to plot on to, if None a new figure is made

**kwargs

Keyword arguments passed to matplotlib.pyplot.semilogy for styling trace

class finesse.analysis.actions.operator.Operator(start_node, end_node, via=None, frequency=0, *, name='operator')

Bases: Action

This action can be used to extract operators out from a simulation for external use. The operators are defined by a path in the network between two nodes (via some other if more direction is required).

The model.path method can be used to test which nodes are traversed before using this to extract operators if needed.

Parameters

start_nodestr

Start node name

end_nodestr

End node name

viastr, optional

Via node to use to specify a path with multiple options

frequencyfloat, optional

Optical carrier or signal frequency to use for calculating the operators

namestr, optional

Name of the solution generated by this action

class finesse.analysis.actions.operator.OperatorSolution

Bases: BaseSolution

connections: tuple[tuple[str, str], ...]
operator: ndarray

Contains solution to the Operator action. The main result is the operator attribute which describes the operator taking the field from start to end node.

Attributes

connections[(Node, Node)]

A list of node pairs describing the connections traversed to compute this operator

operatorndarray(ndim=2, dtype=complex)

The operator describing the propagation from start to end node.

finesse.analysis.actions.optimisation module

Collection of Actions that deal linear time invariant (LTI) modelling tasks.

class finesse.analysis.actions.optimisation.Maximize(detector, parameter, name='maximize', *args, **kwargs)

Bases: Optimize

An action that maximizes some detector output by applying some feedback to multiple targets in a model. Extra keyword arguments are passed on to the Scipy method:

minimize

This action offers a simplified interface that allows an optimization to be done during a simulation. By default the the Nelder-Mead optimization method is used but can be overridden. The user should read the Scipy documentation to determine which options should be used which are method dependant.

Notes

Default optimizer used is nelder-mead. To set the absolute and relative error targets use (From the scipy documentation: https://docs.scipy.org/doc/scipy/reference/optimize.minimize-neldermead.html)

xatolfloat, optional

Absolute error in xopt between iterations that is acceptable for convergence. Defaults to 1e-4.

fatolfloat, optional

Absolute error in func(xopt) between iterations that is acceptable for convergence. Defaults to 1e-4.

These can be set as keyword arguments to the action.

Parameters

detectorstr

The name of the detector output to maximize / minimize.

parameter[Parameter | str | tuple]

The parameter or name of the parameter to optimize, or a tuple of parameters when using multiple targets to optimize over.

boundslist, optional

A pair of (lower, upper) bounds on the parameter value. Requires a method that uses bounds.

offsetfloat, optional

An offset applied to the detector output when optimizing, defaults to 0.

kindstr, optional

Either ‘max’ for maximization or ‘min’ for minimization, defaults to ‘max’.

max_iterationsint, optional

Maximum number of solver iterations, defaults to 10000.

methodstr, optional

Optimisation method to use, see Scipy documentation for options.

namestr, optional

The name of this action, defaults to ‘maximize’.

update_mapsbool, optional

If you are changing some parameter or variable that a Map depends on then setting this flag to True will recompute the Map data for each iteration of the optimiser.

pre_stepAction, optional

Action to run on each step of the optimisation.

kwargs

Optional parameters passed to the Scipy optimisation routine as the options input. See Scipy method documentation to determine what is available.

Examples

Simple example that maximizes the power in a coupled cavity solution by moving multiple mirrors

model = finesse.Model()
model.parse('''
l l1 P=1
m m1 R=0.98 T=0.02 phi=10
m m2 R=0.99 T=0.01
m m3 R=1 T=0 phi=-20
link(l1, m1, m2, m3)
pd P m3.p1.i
''')
sol = model.run("maximize(P, [m1.phi, m3.phi], xatol=1e-7)")
print(sol.result)
class finesse.analysis.actions.optimisation.Minimize(detector, parameter, name='minimize', *args, **kwargs)

Bases: Optimize

An action that minimizes some detector output by applying some feedback to multiple targets in a model. Extra keyword arguments are passed on to the Scipy method:

minimize

This action offers a simplified interface that allows an optimization to be done during a simulation. By default the the Nelder-Mead optimization method is used but can be overridden. The user should read the Scipy documentation to determine which options should be used which are method dependant.

Notes

Default optimizer used is nelder-mead. To set the absolute and relative error targets use (From the scipy documentation: https://docs.scipy.org/doc/scipy/reference/optimize.minimize-neldermead.html)

xatolfloat, optional

Absolute error in xopt between iterations that is acceptable for convergence. Defaults to 1e-4.

fatolfloat, optional

Absolute error in func(xopt) between iterations that is acceptable for convergence. Defaults to 1e-4.

These can be set as keyword arguments to the action.

Parameters

detectorstr

The name of the detector output to maximize / minimize.

parameter[Parameter | str | tuple]

The parameter or name of the parameter to optimize, or a tuple of parameters when using multiple targets to optimize over.

boundslist, optional

A pair of (lower, upper) bounds on the parameter value. Requires a method that uses bounds.

offsetfloat, optional

An offset applied to the detector output when optimizing, defaults to 0.

kindstr, optional

Either ‘max’ for maximization or ‘min’ for minimization, defaults to ‘max’.

max_iterationsint, optional

Maximum number of solver iterations, defaults to 10000.

methodstr, optional

Optimisation method to use, see Scipy documentation for options.

namestr, optional

The name of this action, defaults to ‘maximize’.

update_mapsbool, optional

If you are changing some parameter or variable that a Map depends on then setting this flag to True will recompute the Map data for each iteration of the optimiser.

pre_stepAction, optional

Action to run on each step of the optimisation.

kwargs

Optional parameters passed to the Scipy optimisation routine as the options input. See Scipy method documentation to determine what is available.

Examples

Simple example that minimizes some measured power by feeding back to the laser power

model = finesse.Model()
model.parse('''
l l1 P=1
pd P l1.p1.o
''')
sol = model.run("minimize(P, l1.P)")
print(sol.result)
exception finesse.analysis.actions.optimisation.OptimizationWarning

Bases: RuntimeWarning

class finesse.analysis.actions.optimisation.Optimize(detector, parameters, bounds=None, offset=0, kind='max', max_iterations=10000, tol=None, verbose=False, method='nelder-mead', opfunc=None, update_maps=False, pre_step=None, name='optimize', **kwargs)

Bases: Action

property parameter_names
class finesse.analysis.actions.optimisation.OptimizeSolution(*args, **kwargs)

Bases: BaseSolution

Solution for an optimization action.

Attributes

resultscipy.optimize.optimize.OptimizeResult

Result from the scipy optimization method that contains the results and some extra data about the process and any errors that might happen.

parameters[Parameter | tuple]

Name or names of parameters that were optimized over

x[numeric | ndarray]

The final minimized values for the parameters requested.

finesse.analysis.actions.parallel module

Parallel Action.

class finesse.analysis.actions.parallel.Parallel(*actions)

Bases: Action

class finesse.analysis.actions.parallel.ParallelSolution

Bases: BaseSolution

finesse.analysis.actions.pseudolock module

class finesse.analysis.actions.pseudolock.PseudoLockCavity(cavity, *, mode=None, lowest_loss=False, feedback=None, name='pseudo_lock_cavity')

Bases: Action

An action that locks a cavity defined by a Cavity element to a specific mode without using any radio-frequency sensing scheme. This will only work on simple cavities that are not coupled in any way. You can specify whether to try and lock to a particular HG mode with the mode=[n,m] keyword argument, or just pick the lowest loss mode, lowest_loss=True.

Parameters

cavityCavity

Cavity element describing some Fabry-Perot like optical cavity

mode(n, m), optional

HG mode to try and lock to, default is [0,0]

lowest_lossbool, optional

Select the eigenmode which has the lowest loss, most likely the fundamental mode of the cavity. Using lowest loss will override the mode selection.

feedbackParameter optional

If None the required cavity tuning to lock to the calculated mode will be determined from the cavity objects source node element, and the relevant phi parameter will be used. Alternatively you can specify which tuning parameter is used instead. Which should be a phi of some mirror in the cavity or a DegreeOfFreedom which controls the cavity length.

namestr, optional

Name of the solution generated by this action

Examples

A Fabry-Perot based on aLIGO cavities:

>>> import finesse
>>> model = finesse.Model()
>>> model.parse('''
... l l1 P=1
... m ITM T=0.014 L=0 Rc=-1945
... s sARM ITM.p2 ETM.p1 L=3994
... m ETM R=1 L=0 Rc=2145
... link(l1, ITM)
... cav arm ETM.p1.o
... modes(maxtem=1)
... ''')

The cavity source node is on the ETM so the pseudo-lock will use that node and component phi parameter to feedback to. In this case the ETM.phi will be corrected to match the ITM.phi which will make the HG00 resonant.

>>> model.ITM.phi = 0
>>> model.ETM.phi = 10
>>> model.run("pseudo_lock_cavity(arm)")
>>> print(model.ITM.phi, model.ETM.phi)
0.0 degrees 0.0 degrees
>>> model.ITM.phi = 10
>>> model.ETM.phi = 0
>>> model.run("pseudo_lock_cavity(arm)")
>>> print(model.ITM.phi, model.ETM.phi)
10.0 degrees 10.0 degrees

This lock will also handle any misalignments, mismatches, or maps applied to the cavity.

>>> model.ITM.xbeta = 5e-8
>>> model.ITM.phi = 11
>>> model.ETM.phi = 0
>>> model.run("pseudo_lock_cavity(arm)")
>>> print(model.ITM.phi, model.ETM.phi)
11.0 degrees 10.984168676865762 degrees

We can also lock to other HG modes:

>>> sol = model.run("series(pseudo_lock_cavity(arm, mode=[1,0]), noxaxis())")
>>> print(model.ITM.phi, model.ETM.phi)
>>> print(model.homs)
>>> print(sol['noxaxis']['Ecirc'])
11.0 degrees 28.663091273523214 degrees
[[0 0]
[1 0]
[0 1]]
[-0.16465261-0.11468501j  0.41262682-0.27112167j  0.        +0.j        ]
class finesse.analysis.actions.pseudolock.PseudoLockCavitySolution

Bases: BaseSolution

Solution to the PseudoLockCavity action.

Attributes

operatorOperatorSolution

Solution of the operator action that is used to compute the roundtrip operator in the cavity

warray_like

2D Eigenvector array

varray_like

1D Eigenvalue array

v_idxint

Index of the eigenmode being locked to

phasefloat

Phase in degrees of the eigenmode that is being locked to. This is what is used to set the operating point of the cavity

cavitystr

Which cavity is being locked

lowest_lossbool

If False, the target mode attribute is used. Otherwise

modearray_like

[n, m] target mode to try and lock to

class finesse.analysis.actions.pseudolock.PseudoLockDRFPMI(frequency=0, *, apply_tunings=True, name='operator_lock')

Bases: Action

Pseudo-locking is attempting to find an operating point for a LIGO like model without needing to use RF sidebands and readouts. Although it is not physically accurate it does provide a useful tool for analysing detectors from a more theoretical basis. This generates a PseudoLockDRFPMISolution solution containing various operators and results.

This action is hardcoded to work with a LIGO like model. Mirrors should be named with ITMX, ETMX, PRM, etc.

This currently action only really works for finding the lock points for the PRC, SRC, XARM, and YARM – which all have defined cavity roundtrips which allow eigendecomposition of roundtrip operators. The eigenvectors describe the HOM mix for each resonant mode in a cavity and the eigenvalues the roundtrip phase and loss of the mode. This code looks for eigenvectors with the largest HG00 content and then uses the eigenvalues to compute what cavity tunings need to make this mode resonant.

The corner is the most complicated here as the PRC and SRC are coupled via the beamsplitter. The eigendecomposition is performed on the 2x2 operator matrix for the PRC, SRC, and the coupling matrices between them. When the coupling is small the results are the same as performing the decomposition on each SRC and PRC separately.

Note that the only degree of freedom that this does not handle currently is MICH. MICH is awkward because it is not a cavity. It is essentially the beamsplitter position that makes the anti-symmetric port dark.

Parameters

frequencyfloat, optional

Frequency to use for calculating the operators

apply_tuningsbool, optional

When True the action will modify the model tunings

namestr, optional

Name of the solution generated by this action

class finesse.analysis.actions.pseudolock.PseudoLockDRFPMISolution

Bases: BaseSolution

TODO: needs updating for all the various attributes this stores.

plot_PRC_SRC_eigenvectors()

finesse.analysis.actions.random module

Random collection of Actions that do no warrant a separate module.

class finesse.analysis.actions.random.Change(change_dict=None, *, relative=False, name='change', **kwargs)

Bases: Action

Changes a model Parameter to some value during an analysis.

Parameters

change_dictdict, optional

Dictionary of parameter:value pairs to change.

relativebool, optional

Whether to increment from the parameters current value or not

namestr, optional

Name of action

**kwargs

Alternative method to specify parameter:value pairs to change

Examples

A simple change of a parameter between running two noxaxis analyses:

>>> model = finesse.script.parse("l L1 P=1")
>>> model.run('series(noxaxis(), change(L1.P=2), noxaxis())')

Or increment from the current value: >>> model.run(‘series(noxaxis(), change(L1.P=1, relative=True), noxaxis())’)

property change_kwargs
class finesse.analysis.actions.random.Execute(do_fn, parameters=None, name='execute')

Bases: Action

An action that will execute the function passed to it when it is run.

Parameters

do_fnfunction

A function that takes an AnalysisState, and the name of the Exec action as its only arguments. If this function returns a finesse.solutions.base.BaseSolution object then it will be added to the simulations solution to return to the user.

parameterslist, optional

A list of parameters that will be changed by do_fn, if any.

namestr

The name to give this action.

Examples

A simple function to execute might use a pattern such as this, which generates a Solution that is returned back to the user.

>>> from finesse.solutions import SimpleSolution
>>> def my_action(state, name):
...     sol = SimpleSolution(name)
...     return sol

The finesse.solutions.simple.SimpleSolution object is just an object you can store anything you want in. You can extract any state information about the simulation or model and store it here. This allows you to probe and store details that might not be available as a detector, for example.

class finesse.analysis.actions.random.LogModelAttribute(*attrs)

Bases: Action

class finesse.analysis.actions.random.MakeTransparent(surfaces, name='make transparent')

Bases: Action

Action to make all provided surfaces transparent. Simply sets the reflectivity to zero and transmitivity to one.

Parameters

surfaceslist

A list of surface component names to be made transparent.

class finesse.analysis.actions.random.Plot(name='abcd')

Bases: Action

class finesse.analysis.actions.random.PrintModel(name='print_model')

Bases: Action

An action that prints the model object being currently used to run actions.

class finesse.analysis.actions.random.PrintModelAttr(*args, eval=True, prefix='')

Bases: Action

Prints an attribute of the model being currently used.

Parameters

*args(str,)

Strings input for the attribute to print

evalbool, optional

When True symbolic expressions will be evaluated before printing. Defaults to True.

prefixstr, optional

Optional string to print before the attributes

Examples

You can print the current value of parameters and such using:

>>> PrintModelAttr("m1.R", "bs.phi")
class finesse.analysis.actions.random.Printer(*args, name='printer', eval=True)

Bases: Action

class finesse.analysis.actions.random.SaveModelAttrSolution

Bases: BaseSolution

Attributes

valuesdict

Dictionary of model attribute values

class finesse.analysis.actions.random.Scale(scales: dict, **kwargs)

Bases: Action

Action for scaling simulation outputs by some fixed amount. Included for compatibility with legacy Finesse code. New users should apply any desired scalings manually from Python.

Parameters

detectorsdict

A dictionary of detector name: scaling factor mappings.

class finesse.analysis.actions.random.StoreModelAttr(*args)

Bases: Action

class finesse.analysis.actions.random.UpdateMaps(name='update_maps', *args, **kwargs)

Bases: Action

Update any maps that might be changing in the simulation.

finesse.analysis.actions.sensing module

Collection of Actions that deal with sensing tasks such as computing sensing matrices, optimising RF readouts, etc.

class finesse.analysis.actions.sensing.CheckLinearity(*locks, num_points=10, plot_results=True, xlim=None, name='run locks')

Bases: Action

An action that shows the relationships between all DOFs and all error signals, to check whether they are related linearly. Plotted for DOFs starting at their initial values and up until their initial values + 2*gain*intial error signal.

Parameters

*lockslist, optional

A list of locks to use in each finesse.analysis.actions.locks.RunLocks step. Acts like *locks parameter in finesse.analysis.actions.locks.RunLocks: if not provided, all locks in model are used.

num_pointsint

Number of points to plot in the DOF range.

plot_resultsboolean

Whether or not to plot results (requires matplotlib)

xlimlist or None

Defines (half of) the range of DOF values over which to plot the error signals. If not specified, gains are used to find a useful range of DOF values to plot over.

namestr

Name of the action.

class finesse.analysis.actions.sensing.CheckLinearitySolution(*args, **kwargs)

Bases: BaseSolution

class finesse.analysis.actions.sensing.GetErrorSignals(*locks, name='get error signals')

Bases: Action

An action that quickly calculates the current error signals for all or a subset of locks in a model.

Parameters

*lockslist, optional

A list of lock names to compute the error signals for. If not provided, all locks in model are used.

namestr

Name of the action.

class finesse.analysis.actions.sensing.GetErrorSignalsSolution(*args, **kwargs)

Bases: BaseSolution

class finesse.analysis.actions.sensing.OptimiseRFReadoutPhaseDC(*args, d_dof=1e-10, name='optimise_demod_phases_dc')

Bases: Action

This optimises the demodulation phase of ReadoutRF elements relative to some DegreeOfFreedom or driven Parameter in the model. The phases are optimised by calculating the DC response of the readouts. This Action changes the state of the model by varying the readout demodulation phases. If no arguments are given it will try to automatically optimise any lock element in the model that is using an RF readout with respect to the lock feedback parameter.

Parameters

args

Pairs of DegreeOfFreedom or Parameter and ReadoutRF elements, or pairs of their names. If none are provided OptimiseRFReadoutPhaseDC will automatically search for Lock elements which have ReadoutRF error signal and optimise them.

d_doffloat, optional

A small offset applied to the DOFs to compute the gradients of the error signals

Examples

Take a typicaly Pound-Drever-Hall lock of a cavity. Here is some KatScript to setup such a model:

>>> import finesse
>>> from finesse.analysis.actions import OptimiseRFReadoutPhaseDC
>>>
>>> model = finesse.Model()
>>> model.parse('''
>>> l l1
>>> mod mod1 10M 0.1 mod_type=pm
>>> readout_rf PD f=mod1.f phase=33 output_detectors=True optical_node=m1.p1.o
>>> m m1 R=0.99 T=0.01
>>> m m2 R=1 T=0
>>> link(l1, mod1, m1, 1, m2)
>>> lock cav_lock PD_I m2.phi 0.01 1e-3
>>> ''')

We have defined a lock above using the I quadrature RF demodulation and feeding back to the m2 mirror position. We can optimise this demodulation phase by running. Here we manually provied which drives and readouts to use:

>>> sol = model.run(OptimiseRFReadoutPhaseDC("m2.phi", 'PD_I'))
>>> print(sol.phases)
{'PD': 181.3535303754581}
>>> print(model.PD.phase)
181.3535303754581

Alternatively, PD_Q could also be optimised for above. You can also just optimise all locks that are using RF readouts by providing no arguments:

>>> sol = model.run(OptimiseRFReadoutPhaseDC())
>>> print(sol.phases)
{'PD': 181.3535303754581}

To tell what was optimised, see the sol.phases dictionary.

class finesse.analysis.actions.sensing.OptimiseRFReadoutPhaseDCSolution

Bases: BaseSolution

class finesse.analysis.actions.sensing.SensingMatrixAC(dofs, readouts, f=0.001, name='sensing_matrix_ac')

Bases: Action

Computes the sensing matrix elements for various degrees of freedom and readouts that should be present in the model. The solution object for this action then contains all the information on the sensing matrix. This can be plotted in polar coordinates, displayed in a table, or directly accessed.

The sensing gain is computed by calculating the gradient of each readout signal, which means it is a DC measurement. This will not include any suspension or radiation pressure effects.

This action does not modify the states model.

Parameters

dofsiterable[str]

String names of degrees of freedom

readoutsiterable[str]

String names of readouts

ffloat

Frequency to measure sensing matrix at

class finesse.analysis.actions.sensing.SensingMatrixDC(dofs, readouts, d_dof=1e-09, name='sensing_matrix_dc')

Bases: Action

Computes the sensing matrix elements for various degrees of freedom and readouts that should be present in the model. The solution object for this action then contains all the information on the sensing matrix. This can be plotted in polar coordinates, displayed in a table, or directly accessed.

The sensing gain is computed by calculating the gradient of each readout signal, which means it is a DC measurement. This will not include any suspension or radiation pressure effects.

This action does not modify the states model.

Parameters

dofsiterable[str]

String names of degrees of freedom

readoutsiterable[str]

String names of readouts

d_doffloat, optional

Small step used to compute derivative

class finesse.analysis.actions.sensing.SensingMatrixSolution

Bases: BaseSolution

Sensing matrix solution.

The raw sensing matrix information can be accessed using the SensingMatrixSolution.out member. This is a complex-valued array with dimensions (DOFs, Readouts), which are accessible via SensingMatrixSolution.dofs and SensingMatrixSolution.readouts.

A table can be printed using SensingMatrixSolution.display().

Polar plot can be generated using SensingMatrixSolution.plot()

Printing SensingMatrixSolution will show an ASCII table of the data.

display(dofs=None, readouts=None, tablefmt='pandas', numfmt='{:.2G}', highlight=None, highlight_color='#808080')

Displays a HTML table of the sensing matrix, optionally highlighting the largest absolute value for each readout or dof.

Notes

Only works when called from an IPython environment with the display method available. Pandas is required for highlighting.

Parameters

dofsiterable[str], optional

Names of degrees of freedom to show, defaults to all if None

readoutsiterable[str], optional

Names of readouts to show, defaults to all if None

tablefmtstr, optional

Either ‘pandas’ for pandas formatting, or anything else to use finesse.utilities.tables.Table. Defaults to ‘pandas’ if available.

numfmtstr or func or array, optional

Either a function to format numbers or a formatting string. The function must return a string. Can also be an array with one option per row, column or cell. Defaults to ‘{:.2G}’.

highlightstr or None, optional

Either ‘dof’ to highlight the readout that gives the largest output for each dof, or ‘readout’ to highlight the dof for which each readout gives the largest output. Defaults to None (no highlighting).

highlight_colorstr, optional

Color to highlight the maximum values with. Pandas is required for this to have an effect. Defaults to pale orange.

matrix_data(dofs=None, readouts=None)

Generates a sensing matrix table.

Parameters

dofsiterable[str], optional

Names of degrees of freedom to show, defaults to all if None

readoutsiterable[str], optional

Names of readouts to show, defaults to all if None

Returns

matrix : 2D numpy array, complex dofs : list of str readouts: list of str

plot(self, *args, show=True, **kwargs)

Plot solution(s).

If the solution contains child solutions, they are plotted in order. Solutions without plot arguments are skipped. Positional arguments passed to this method are assumed to be dict and are unpacked into calls to each child’s plot method. Global arguments to be passed to all plot methods can be specified directly as keyword arguments. Duplicate arguments specified in a positional argument dictionaries take precendence over global arguments.

Parameters

showbool, optional

Show the figures.

Other Parameters

*args

Sequence of dict to use as parameters for the call to each child solution’s plot method.

**kwargs

Keyword arguments supported by the child solution(s).

Notes

If the Nth solution contains no plot method, it still consumes the Nth positional argument passed to this method.

finesse.analysis.actions.sensing.get_readout_workspace(readouts, output, readout_workspaces)

Return the readout workspaces for a particular readout’s quadrature outputs.

Parameters

readoutsiterable

ReadoutRF elements

outputstr

Quadrature output to try and select, ‘I’, ‘Q’, ‘DC’

readout_workspacesdict

Workspaces of the readouts in the simulation

finesse.analysis.actions.series module

Serial Action.

class finesse.analysis.actions.series.For(param, values, *actions)

Bases: Action

An action changes a parameter value and runs a set of actions for each value in the array. Essentially the same as Series combined with Change. The parameter value is not reset to its original value once this action has finished.

Generates a ForSolution output when run.

Examples

A simple example printing some a varied laser power output.

>>> import finesse
>>> model = finesse.Model()
>>> model.parse('''
... l l1
... pd P l1.p1.o
... ''')
>>> sol = model.run('for(l1.P, [0, 1, 2, 3], print(l1.P))')
0.0 W
1.0 W
2.0 W
3.0 W
>>> print(sol.values)
[0, 1, 2, 3]

Parameters

paramstr|Parameter

Parameter to change in the model

valuesarray_like

Array of values to use for the parameter

*actionstuple(Action)

Actions to run for each parameter value.

class finesse.analysis.actions.series.ForSolution

Bases: BaseSolution

Solution generated by a For Action.

Attributes

parameterobject | str

Model parameter that was varied by the For action

valuesarray_like

Array of values that were iterated over

Examples

A simple example printing some a varied laser power output:

>>> import finesse
>>> model = finesse.Model()
>>> model.parse('''
... l l1
... pd P l1.p1.o
... ''')
>>> sol = model.run('for(l1.P, [0, 1, 2, 3], print(l1.P))')
0.0 W
1.0 W
2.0 W
3.0 W
>>> print(sol.values)
[0, 1, 2, 3]
class finesse.analysis.actions.series.Series(*actions, flatten=True, name=None)

Bases: Action

A sequential series of actions to apply during a simulation.

Parameters

actionsAction

A collection of Actions to run in series

flattenbool

When True, each action will be stored in the top level of the solution tree. When False, each action will be a child of the previous solution generated.

namestr

Optional name for the solution generated by these actions

class finesse.analysis.actions.series.SeriesSolution

Bases: BaseSolution

SeriesSolution is a solution object that contains the results from running the requested actions by a Series. You can see what solutions are contained by printing this object or by inspecting the children attribute.

finesse.analysis.actions.squeezing module

Collection of actions to perform analysis on squeezing.

class finesse.analysis.actions.squeezing.AntiSqueezing(f, squeezer, readout, *, signal=None, name='antisqueezing')

Bases: Action

Computes the amount of anti-squeezing at an output from a squeezing element.

Notes

This will only works in cases where the HG00 is squeezed and is used after a filtering component, like a cavity to select only the HG00. The calculation does not use the usual internal quantum noise solver in Finesse. Instead it computes how much loss and rotation from a squeezer happens by calculating the upper and lower sideband transfer functions from the squeezer to some readout. From this the relevant squeezing outputs can be calculated.

Parameters

farray_like

Signal frequencies to compute the anti-squeezing over

squeezerstr

Name of squeezing component

readoutstr

Name of readout port to compute squeezing at

signalstr

Name of signal drive to calculate a the signal transfer function of. This is returned in sol.signal and can be used to scale the noise into equivalent units of some signal.

property f
class finesse.analysis.actions.squeezing.AntiSqueezingSolution

Bases: BaseSolution

finesse.analysis.actions.sweep module

Sweep Action.

class finesse.analysis.actions.sweep.Sweep(*args, pre_step=None, post_step=None, reset_parameter=True, name='sweep')

Bases: Action

An action that sweeps N number of parameters through the values in N arrays.

Parameters

args[Parameter, str], array, boolean

Expects 3 arguments per axis. The first is a full name of a Parameter or a Parameter object. The second is an array of values to step this parameter over, and lastly a boolean value to say whether this is a relative step from the parameters initial value.

pre_stepAction, optional

An action to perform before the step is computed

post_stepAction, optional

An action to perform after the step is computed

reset_parameterboolean, optional

When true this action will reset the all the parameters it changed to the values before it ran.

namestr

Name of the action, used to find the solution in the final output.

finesse.analysis.actions.sweep.get_sweep_array(start: float, stop: float, steps: int, mode='lin')

finesse.analysis.actions.temporary module

Temporary actions allow for temporary state changes to perform some chosen set of actions with, then returning to the original state.

class finesse.analysis.actions.temporary.Temporary(temp_action, *actions)

Bases: Action

Make the first action in a series of actions temporary, i.e. restore its parameters after the rest of the actions are complete.

class finesse.analysis.actions.temporary.TemporaryParameters(action, *, include=None, exclude=None)

Bases: Action

An action that will revert any changed parameters back to their values before this action was called. Options exist to include or exclude certain Parameters from this reversion. This action does not generate any Solution.

Parameters

actionfinesse.analysis.actions.base.Action

Action to perform followed by reverting requested Parameters in the model

include[iterable|str], optional

Parameters that should be included.

If a single string is given it can be a Unix file style wildcard (See fnmatch). A value of None means everything is included.

If an iterable is provided it must be a list of names or Parameter objects.

exclude[iterable|str], optional

Parameters that should not be included.

If a single string is given it can be a Unix file style wildcard (See fnmatch). A value of None means nothing is excluded.

If an iterable is provided it must be a list of names or Parameter objects.

finesse.analysis.actions.temporary.temporary(action)

Converts an action into a temporary action.

This function takes a target action, and returns an action that takes multiple actions as arguments. When the returned action is run, it will first run the target action, then all actions passed to it, then restore the changes made by the target action, e.g.

temporary(Change({'m1.phi': 10}))(
    Xaxis(l1.P, 'lin', 0, 10, 100)
)

will first set the parameter m1.phi to 10, then run a sweep of l1.P, then restore m1.phi to its previous value.

Parameters

actionAction

The action to make temporary.

Returns

action

An action that temporarily applies the passed action when run.

finesse.analysis.actions.utils module

finesse.analysis.actions.utils.elements_to_name(x)

Module contents

class finesse.analysis.actions.ABCD(name='abcd', **kwargs)

Bases: Action

Computation of an ABCD matrix over a path.

See compute_abcd() for details.

class finesse.analysis.actions.Action(name, analysis_state_manager=False)

Bases: object

Base class for all actions

property analysis_state_manager
get_requests(model)
property name
plan(previous=None)

Returns an expected plan for the actions that will be run in a tree form. This may not be exactly what is ran.

Returns

plan : TreeNode

class finesse.analysis.actions.AntiSqueezing(f, squeezer, readout, *, signal=None, name='antisqueezing')

Bases: Action

Computes the amount of anti-squeezing at an output from a squeezing element.

Notes

This will only works in cases where the HG00 is squeezed and is used after a filtering component, like a cavity to select only the HG00. The calculation does not use the usual internal quantum noise solver in Finesse. Instead it computes how much loss and rotation from a squeezer happens by calculating the upper and lower sideband transfer functions from the squeezer to some readout. From this the relevant squeezing outputs can be calculated.

Parameters

farray_like

Signal frequencies to compute the anti-squeezing over

squeezerstr

Name of squeezing component

readoutstr

Name of readout port to compute squeezing at

signalstr

Name of signal drive to calculate a the signal transfer function of. This is returned in sol.signal and can be used to scale the noise into equivalent units of some signal.

property f
class finesse.analysis.actions.BeamTrace(name='beam_trace', **kwargs)

Bases: Action

Full beam tracing on a complete model.

See Model.beam_trace() for details.

class finesse.analysis.actions.Change(change_dict=None, *, relative=False, name='change', **kwargs)

Bases: Action

Changes a model Parameter to some value during an analysis.

Parameters

change_dictdict, optional

Dictionary of parameter:value pairs to change.

relativebool, optional

Whether to increment from the parameters current value or not

namestr, optional

Name of action

**kwargs

Alternative method to specify parameter:value pairs to change

Examples

A simple change of a parameter between running two noxaxis analyses:

>>> model = finesse.script.parse("l L1 P=1")
>>> model.run('series(noxaxis(), change(L1.P=2), noxaxis())')

Or increment from the current value: >>> model.run(‘series(noxaxis(), change(L1.P=1, relative=True), noxaxis())’)

property change_kwargs
class finesse.analysis.actions.CheckLinearity(*locks, num_points=10, plot_results=True, xlim=None, name='run locks')

Bases: Action

An action that shows the relationships between all DOFs and all error signals, to check whether they are related linearly. Plotted for DOFs starting at their initial values and up until their initial values + 2*gain*intial error signal.

Parameters

*lockslist, optional

A list of locks to use in each finesse.analysis.actions.locks.RunLocks step. Acts like *locks parameter in finesse.analysis.actions.locks.RunLocks: if not provided, all locks in model are used.

num_pointsint

Number of points to plot in the DOF range.

plot_resultsboolean

Whether or not to plot results (requires matplotlib)

xlimlist or None

Defines (half of) the range of DOF values over which to plot the error signals. If not specified, gains are used to find a useful range of DOF values to plot over.

namestr

Name of the action.

class finesse.analysis.actions.DCFields(*, name='dcfields')

Bases: Action

An action that saves the DC (carrier) fields at all nodes, frequencies, and higher order modes for the current state of the simulation.

Parameters

namestr, optional

Name of the solution generated by this action

class finesse.analysis.actions.Debug(name='Debug')

Bases: Action

An action that will start an IPython debug shell.

To access the current model use state.model.

class finesse.analysis.actions.DragLocks(*locks, parameters, stop_points, relative=False, method='proportional', scale_factor=1, num_steps=11, never_optimize_phase=None, exception_on_fail=True, max_recursions=5, max_iterations=1000, display_progress=False, show_progress_bar=False, name='drag locks')

Bases: Action

An action that incrementally changes model parameter values, reaching lock at each step, until lock is reached at the desired final parameter values.

Parameters

*lockslist, optional

A list of locks to use in each finesse.analysis.actions.locks.RunLocks step. Acts like the *locks parameter in finesse.analysis.actions.locks.RunLocks: if not provided, all locks in model are used.

parameterslist

A list of strings. Each element should correspond to a parameter in the model.

stop_pointslist

The final parameter values that locks move towards incrementally.

relativeboolean

If true, stop_points are relative to the initial parameter values.

max_recursionsint

The number of times that the step size is allowed to decreased by a factor of ten when locks fail.

methodstr, either “newton” or “proportional”

The method to use in each locking step.

scale_factorfloat

Factor by which to multiply all DOF changes. Should be set below 1 if it is desired to minimize overshooting.

num_stepsint

Number of steps to calculate, starting at the initial point and ending at the stop point.

never_optimize_phaseboolean

Deprecated: When true, never optimize readout phases. When false, phases will be optimized anytime the previous step required more than 10 iterations.

exception_on_failboolean

When true, raise exception if max_recursions is surpassed.

max_iterationsint

The maximum number of locking steps in each execution of RunLocks. If surpassed, step size is decreased.

display_progressboolean

When true, displays the status of the lock dragging.

namestr

Name of the action.

class finesse.analysis.actions.Eigenmodes(cavity: Cavity, frequency, *, name='eigenmodes')

Bases: Action

For a given Cavity defined in a model, this action will compute the roundtrip operator and calculate the eigen-values and -vectors of the cavity. This will not give correct solutions for coupled cavities as these need to include additional effects.

This can be used to determine what modes combination of modes are resonating in a cavity and the required tuning to make that mode resonate.

Parameters

cavitystr or Cavity

cavity name or Cavity instance

frequencyfloat

Optical carrier or signal frequency to use for calculating the operators

namestr, optional

Name of the solution generated by this action

class finesse.analysis.actions.Execute(do_fn, parameters=None, name='execute')

Bases: Action

An action that will execute the function passed to it when it is run.

Parameters

do_fnfunction

A function that takes an AnalysisState, and the name of the Exec action as its only arguments. If this function returns a finesse.solutions.base.BaseSolution object then it will be added to the simulations solution to return to the user.

parameterslist, optional

A list of parameters that will be changed by do_fn, if any.

namestr

The name to give this action.

Examples

A simple function to execute might use a pattern such as this, which generates a Solution that is returned back to the user.

>>> from finesse.solutions import SimpleSolution
>>> def my_action(state, name):
...     sol = SimpleSolution(name)
...     return sol

The finesse.solutions.simple.SimpleSolution object is just an object you can store anything you want in. You can extract any state information about the simulation or model and store it here. This allows you to probe and store details that might not be available as a detector, for example.

class finesse.analysis.actions.For(param, values, *actions)

Bases: Action

An action changes a parameter value and runs a set of actions for each value in the array. Essentially the same as Series combined with Change. The parameter value is not reset to its original value once this action has finished.

Generates a ForSolution output when run.

Examples

A simple example printing some a varied laser power output.

>>> import finesse
>>> model = finesse.Model()
>>> model.parse('''
... l l1
... pd P l1.p1.o
... ''')
>>> sol = model.run('for(l1.P, [0, 1, 2, 3], print(l1.P))')
0.0 W
1.0 W
2.0 W
3.0 W
>>> print(sol.values)
[0, 1, 2, 3]

Parameters

paramstr|Parameter

Parameter to change in the model

valuesarray_like

Array of values to use for the parameter

*actionstuple(Action)

Actions to run for each parameter value.

class finesse.analysis.actions.FrequencyResponse(f, inputs, outputs, *, open_loop=False, name='frequency_response')

Bases: Action

Computes the frequency response of a signal injected at various nodes to compute transfer functions to multiple output nodes. Inputs and outputs should be electrical or mechanical nodes. It does this in an efficient way by using the same model and solving for multiple RHS input vectors.

This action does not alter the model state. This action will ignore any currently definied signal generator elements in the model.

Produces an output transfer matrix from each input node to some readout output. The shape of the output matrix is:

[frequencies, inputs, outputs]

To inject into optical nodes please see FrequencyResponse2 and FrequencyResponse3. To readout optical nodes please see FrequencyResponse3 and FrequencyResponse4.

Parameters

farray, double

Frequencies to compute the transfer functions over

inputsiterable[str or Element]

Mechanical or electrical node to inject signal at

outputsiterable[str or Element]

Mechanical or electrical nodes to measure output at

open_loopbool, optional

Computes open loop transfer functions if the system has closed

namestr, optional

Solution name

Examples

Here we measure a set of transfer functions from DARM and CARM to four readouts for a particular model,

>>> sol = model.run(FrequencyResponse(np.geomspace(0.1, 50000, 100),
...         ('DARM', 'CARM'),
...         ('AS.DC', 'AS45.I', 'AS45.Q', 'REFL9.I'),
... ))

Single inputs and outputs can also be specified

>>> model.run(FrequencyResponse(np.geomspace(0.1, 50000, 100), 'DARM', AS.DC'))

The transfer functions can then be accessed like a 2D array by name, the ordering of inputs to outputs does not matter.

>>> sol['DARM'] # DARM to all outputs
>>> sol['DARM', 'AS.DC'] # DARM to AS.DC
>>> sol['DARM', ('AS.DC', 'AS45.I')]
>>> sol['AS.DC'] # All inputs to AS.DC readout
class finesse.analysis.actions.FrequencyResponse2(f, inputs, outputs, *, name='frequency_response2')

Bases: Action

Computes the frequency response of a signal injected at an optical port at a particular optical frequency. This differs from FrequencyResponse in the way the inputs and outputs are prescribed. For FrequencyResponse2 you specify optical input nodes and a signal output node.

This action does not alter the model state. This action will ignore any currently definied signal generator elements in the model.

Produces an output transfer matrix from each HOM at a particular frequency and optical node to some readout output. The shape of the output matrix is:

[frequencies, outputs, inputs, HOMs]

It should be noted that when exciting a lower signal sideband frequency it will actually return the operator for propagating the conjugate of the lower sideband. This is because FINESSE is internally solving for the conjugate of the lower sideband to linearise non-linear optical effects.

To inject into mechanical and electrical nodes please see FrequencyResponse and FrequencyResponse4. To readout optical nodes please see FrequencyResponse3 and FrequencyResponse4.

Parameters

farray, double

Frequencies to compute the transfer functions over

inputsiterable[tuple[str or Node, Frequency]]

Optical node and frequency tuple to inject at. A symbolic refence to the model’s fsig.f parameter should always be used when defining a frequency to look at.

outputsiterable[str or Element]

Mechanical or electrical (signal)nodes to measure output to

namestr, optional

Solution name

Examples

It is advisable to use always use a reference to the symbolic reference to the signal frequency model.fsig.f.ref instead of a fixed number incase it changes. This action will look for an initial frequency bin of X Hz to track during the frequency response analysis. A symbolic reference will always ensure the right bin is used, in cases such as looking at RF signal sidebands, 10e6+model.fsig.f.ref and 10e6-model.fsig.f.ref will always look at the upper and lower signal sideband around the +10MHz sideband.

>>> import finesse
>>> from finesse.analysis.actions import FrequencyResponse2
>>> model = finesse.script.parse('''
... l l1
... bs bs1 R=1 T=0 xbeta=1e-6 ybeta=1e-9
... readout_dc A
... link(l1, bs1, A)
... fsig(1)
... modes(maxtem=1)
... gauss g1 l1.p1.o w=1m Rc=inf
... ''')
>>> sol = model.run(
...     FrequencyResponse2(
...         [1, 10, 100],
...         [
...             ('bs1.p2.o', +model.fsig.f.ref),
...             ('bs1.p2.o', -model.fsig.f.ref)
...         ],
...         ['A.DC']
...     )
... )
class finesse.analysis.actions.FrequencyResponse3(f, inputs, outputs, *, name='frequency_response3')

Bases: Action

Computes the frequency response of a signal injected at an optical port at a particular optical frequency. This differs from FrequencyResponse in the way the inputs and outputs are prescribed. For FrequencyResponse3 you specify optical input nodes and optical output nodes.

This action does not alter the model state. This action will ignore any currently definied signal generator elements in the model.

Produces an output transfer matrix from each HOM at a particular frequency and optical node to some other optical node and frequency. The shape of the output matrix is:

[frequencies, outputs, inputs, HOMs, HOMs]

It should be noted that when exciting a lower signal sideband frequency it will actually return the operator for propagating the conjugate of the lower sideband. This is because FINESSE is internally solving for the conjugate of the lower sideband to linearise non-linear optical effects.

To inject into mechanical and electrical nodes please see FrequencyResponse and FrequencyResponse4. To readout mechanical and electrical nodes please see FrequencyResponse and FrequencyResponse2.

Parameters

farray, double

Frequencies to compute the transfer functions over

inputsiterable[tuple[str or Node, Frequency]]

Optical node and frequency tuple to inject at. A symbolic reference to the model’s fsig.f parameter should always be used when defining a frequency to look at.

outputsiterable[tuple[str or Node, Frequency]]

Optical node and frequency tuple to measure output at. A symbolic reference to the model’s fsig.f parameter should always be used when defining a frequency to look at.

namestr, optional

Solution name

Examples

It is advisable to use always use a reference to the symbolic reference to the signal frequency model.fsig.f.ref instead of a fixed number incase it changes. This action will look for an initial frequency bin of X Hz to track during the frequency response analysis. A symbolic reference will always ensure the right bin is used, in cases such as looking at RF signal sidebands, 10e6+model.fsig.f.ref and 10e6-model.fsig.f.ref will always look at the upper and lower signal sideband around the +10MHz sideband.

>>> import finesse
>>> from finesse.analysis.actions import FrequencyResponse3
>>> model = finesse.script.parse('''
... l l1
... bs bs1 R=1 T=0 xbeta=1e-6 ybeta=1e-9
... readout_dc A
... link(l1, bs1, A)
... fsig(1)
... modes(maxtem=1)
... gauss g1 l1.p1.o w=1m Rc=inf
... ''')
>>> sol = model.run(
...     FrequencyResponse3(
...         [1, 10, 100],
...         [
...             ('bs1.p2.o', +model.fsig.f.ref),
...             ('bs1.p2.o', -model.fsig.f.ref)
...         ],
...         [
...             ('A.p1.i', +model.fsig.f.ref),
...             ('A.p1.i', -model.fsig.f.ref)
...         ]
...     )
... )
class finesse.analysis.actions.FrequencyResponse4(f, inputs, outputs, *, name='frequency_response4')

Bases: Action

Computes the frequency response of a signal injected at an electrical or mechanical port. This differs from FrequencyResponse in the way the inputs and outputs are prescribed. For FrequencyResponse4 you specify signal input nodes and optical output nodes.

This action does not alter the model state. This action will ignore any currently defined signal generator elements in the model.

Produces an output transfer matrix from each signal node to each HOM at a particular frequency and optical node. The shape of the output matrix is:

[frequencies, outputs, inputs, HOMs]

It should be noted that when exciting a lower signal sideband frequency it will actually return the operator for propagating the conjugate of the lower sideband. This is because FINESSE is internally solving for the conjugate of the lower sideband to linearise non-linear optical effects.

To inject into optical nodes please see FrequencyResponse2 and FrequencyResponse3. To readout mechanical and electrical nodes please see FrequencyResponse and FrequencyResponse2.

Parameters

farray, double

Frequencies to compute the transfer functions over

inputsiterable[str or Element]

Mechanical or electrical node to inject signal at

outputsiterable[tuple[str or Node, Frequency]]

Optical node and frequency tuple to measure output at. A symbolic reference to the model’s fsig.f parameter should always be used when defining a frequency to look at.

namestr, optional

Solution name

Examples

It is advisable to use always use a reference to the symbolic reference to the signal frequency model.fsig.f.ref instead of a fixed number incase it changes. This action will look for an initial frequency bin of X Hz to track during the frequency response analysis. A symbolic reference will always ensure the right bin is used, in cases such as looking at RF signal sidebands, 10e6+model.fsig.f.ref and 10e6-model.fsig.f.ref will always look at the upper and lower signal sideband around the +10MHz sideband.

>>> sol = model.run(
...     FrequencyResponse(
...         [1, 10, 100],
...         [model.ETM.mech.z],
...         [
...             (model.ITM.p2.o, +model.fsig.f.ref),
...             (model.ITM.p2.o, -model.fsig.f.ref)
...         ]
...     )
... )
class finesse.analysis.actions.GetErrorSignals(*locks, name='get error signals')

Bases: Action

An action that quickly calculates the current error signals for all or a subset of locks in a model.

Parameters

*lockslist, optional

A list of lock names to compute the error signals for. If not provided, all locks in model are used.

namestr

Name of the action.

class finesse.analysis.actions.Maximize(detector, parameter, name='maximize', *args, **kwargs)

Bases: Optimize

An action that maximizes some detector output by applying some feedback to multiple targets in a model. Extra keyword arguments are passed on to the Scipy method:

minimize

This action offers a simplified interface that allows an optimization to be done during a simulation. By default the the Nelder-Mead optimization method is used but can be overridden. The user should read the Scipy documentation to determine which options should be used which are method dependant.

Notes

Default optimizer used is nelder-mead. To set the absolute and relative error targets use (From the scipy documentation: https://docs.scipy.org/doc/scipy/reference/optimize.minimize-neldermead.html)

xatolfloat, optional

Absolute error in xopt between iterations that is acceptable for convergence. Defaults to 1e-4.

fatolfloat, optional

Absolute error in func(xopt) between iterations that is acceptable for convergence. Defaults to 1e-4.

These can be set as keyword arguments to the action.

Parameters

detectorstr

The name of the detector output to maximize / minimize.

parameter[Parameter | str | tuple]

The parameter or name of the parameter to optimize, or a tuple of parameters when using multiple targets to optimize over.

boundslist, optional

A pair of (lower, upper) bounds on the parameter value. Requires a method that uses bounds.

offsetfloat, optional

An offset applied to the detector output when optimizing, defaults to 0.

kindstr, optional

Either ‘max’ for maximization or ‘min’ for minimization, defaults to ‘max’.

max_iterationsint, optional

Maximum number of solver iterations, defaults to 10000.

methodstr, optional

Optimisation method to use, see Scipy documentation for options.

namestr, optional

The name of this action, defaults to ‘maximize’.

update_mapsbool, optional

If you are changing some parameter or variable that a Map depends on then setting this flag to True will recompute the Map data for each iteration of the optimiser.

pre_stepAction, optional

Action to run on each step of the optimisation.

kwargs

Optional parameters passed to the Scipy optimisation routine as the options input. See Scipy method documentation to determine what is available.

Examples

Simple example that maximizes the power in a coupled cavity solution by moving multiple mirrors

model = finesse.Model()
model.parse('''
l l1 P=1
m m1 R=0.98 T=0.02 phi=10
m m2 R=0.99 T=0.01
m m3 R=1 T=0 phi=-20
link(l1, m1, m2, m3)
pd P m3.p1.i
''')
sol = model.run("maximize(P, [m1.phi, m3.phi], xatol=1e-7)")
print(sol.result)
class finesse.analysis.actions.Minimize(detector, parameter, name='minimize', *args, **kwargs)

Bases: Optimize

An action that minimizes some detector output by applying some feedback to multiple targets in a model. Extra keyword arguments are passed on to the Scipy method:

minimize

This action offers a simplified interface that allows an optimization to be done during a simulation. By default the the Nelder-Mead optimization method is used but can be overridden. The user should read the Scipy documentation to determine which options should be used which are method dependant.

Notes

Default optimizer used is nelder-mead. To set the absolute and relative error targets use (From the scipy documentation: https://docs.scipy.org/doc/scipy/reference/optimize.minimize-neldermead.html)

xatolfloat, optional

Absolute error in xopt between iterations that is acceptable for convergence. Defaults to 1e-4.

fatolfloat, optional

Absolute error in func(xopt) between iterations that is acceptable for convergence. Defaults to 1e-4.

These can be set as keyword arguments to the action.

Parameters

detectorstr

The name of the detector output to maximize / minimize.

parameter[Parameter | str | tuple]

The parameter or name of the parameter to optimize, or a tuple of parameters when using multiple targets to optimize over.

boundslist, optional

A pair of (lower, upper) bounds on the parameter value. Requires a method that uses bounds.

offsetfloat, optional

An offset applied to the detector output when optimizing, defaults to 0.

kindstr, optional

Either ‘max’ for maximization or ‘min’ for minimization, defaults to ‘max’.

max_iterationsint, optional

Maximum number of solver iterations, defaults to 10000.

methodstr, optional

Optimisation method to use, see Scipy documentation for options.

namestr, optional

The name of this action, defaults to ‘maximize’.

update_mapsbool, optional

If you are changing some parameter or variable that a Map depends on then setting this flag to True will recompute the Map data for each iteration of the optimiser.

pre_stepAction, optional

Action to run on each step of the optimisation.

kwargs

Optional parameters passed to the Scipy optimisation routine as the options input. See Scipy method documentation to determine what is available.

Examples

Simple example that minimizes some measured power by feeding back to the laser power

model = finesse.Model()
model.parse('''
l l1 P=1
pd P l1.p1.o
''')
sol = model.run("minimize(P, l1.P)")
print(sol.result)
class finesse.analysis.actions.NoiseProjection(f, *output_nodes, scaling=None, name='loop')

Bases: Action

class finesse.analysis.actions.Noxaxis(pre_step=None, post_step=None, name='noxaxis')

Bases: Sweep

class finesse.analysis.actions.Operator(start_node, end_node, via=None, frequency=0, *, name='operator')

Bases: Action

This action can be used to extract operators out from a simulation for external use. The operators are defined by a path in the network between two nodes (via some other if more direction is required).

The model.path method can be used to test which nodes are traversed before using this to extract operators if needed.

Parameters

start_nodestr

Start node name

end_nodestr

End node name

viastr, optional

Via node to use to specify a path with multiple options

frequencyfloat, optional

Optical carrier or signal frequency to use for calculating the operators

namestr, optional

Name of the solution generated by this action

class finesse.analysis.actions.OptimiseRFReadoutPhaseDC(*args, d_dof=1e-10, name='optimise_demod_phases_dc')

Bases: Action

This optimises the demodulation phase of ReadoutRF elements relative to some DegreeOfFreedom or driven Parameter in the model. The phases are optimised by calculating the DC response of the readouts. This Action changes the state of the model by varying the readout demodulation phases. If no arguments are given it will try to automatically optimise any lock element in the model that is using an RF readout with respect to the lock feedback parameter.

Parameters

args

Pairs of DegreeOfFreedom or Parameter and ReadoutRF elements, or pairs of their names. If none are provided OptimiseRFReadoutPhaseDC will automatically search for Lock elements which have ReadoutRF error signal and optimise them.

d_doffloat, optional

A small offset applied to the DOFs to compute the gradients of the error signals

Examples

Take a typicaly Pound-Drever-Hall lock of a cavity. Here is some KatScript to setup such a model:

>>> import finesse
>>> from finesse.analysis.actions import OptimiseRFReadoutPhaseDC
>>>
>>> model = finesse.Model()
>>> model.parse('''
>>> l l1
>>> mod mod1 10M 0.1 mod_type=pm
>>> readout_rf PD f=mod1.f phase=33 output_detectors=True optical_node=m1.p1.o
>>> m m1 R=0.99 T=0.01
>>> m m2 R=1 T=0
>>> link(l1, mod1, m1, 1, m2)
>>> lock cav_lock PD_I m2.phi 0.01 1e-3
>>> ''')

We have defined a lock above using the I quadrature RF demodulation and feeding back to the m2 mirror position. We can optimise this demodulation phase by running. Here we manually provied which drives and readouts to use:

>>> sol = model.run(OptimiseRFReadoutPhaseDC("m2.phi", 'PD_I'))
>>> print(sol.phases)
{'PD': 181.3535303754581}
>>> print(model.PD.phase)
181.3535303754581

Alternatively, PD_Q could also be optimised for above. You can also just optimise all locks that are using RF readouts by providing no arguments:

>>> sol = model.run(OptimiseRFReadoutPhaseDC())
>>> print(sol.phases)
{'PD': 181.3535303754581}

To tell what was optimised, see the sol.phases dictionary.

class finesse.analysis.actions.Optimize(detector, parameters, bounds=None, offset=0, kind='max', max_iterations=10000, tol=None, verbose=False, method='nelder-mead', opfunc=None, update_maps=False, pre_step=None, name='optimize', **kwargs)

Bases: Action

property parameter_names
class finesse.analysis.actions.Parallel(*actions)

Bases: Action

class finesse.analysis.actions.Plot(name='abcd')

Bases: Action

class finesse.analysis.actions.PrintModel(name='print_model')

Bases: Action

An action that prints the model object being currently used to run actions.

class finesse.analysis.actions.PrintModelAttr(*args, eval=True, prefix='')

Bases: Action

Prints an attribute of the model being currently used.

Parameters

*args(str,)

Strings input for the attribute to print

evalbool, optional

When True symbolic expressions will be evaluated before printing. Defaults to True.

prefixstr, optional

Optional string to print before the attributes

Examples

You can print the current value of parameters and such using:

>>> PrintModelAttr("m1.R", "bs.phi")
class finesse.analysis.actions.Printer(*args, name='printer', eval=True)

Bases: Action

class finesse.analysis.actions.PropagateAstigmaticBeam(name='astig_propagation', **kwargs)

Bases: Action

Propagation of a beam, in both planes, through a given path.

See Model.propagate_beam_astig() for details.

class finesse.analysis.actions.PropagateBeam(name='propagation', **kwargs)

Bases: Action

Propagation of a beam, in a single plane, through a given path.

See Model.propagate_beam() for details.

class finesse.analysis.actions.PseudoLockCavity(cavity, *, mode=None, lowest_loss=False, feedback=None, name='pseudo_lock_cavity')

Bases: Action

An action that locks a cavity defined by a Cavity element to a specific mode without using any radio-frequency sensing scheme. This will only work on simple cavities that are not coupled in any way. You can specify whether to try and lock to a particular HG mode with the mode=[n,m] keyword argument, or just pick the lowest loss mode, lowest_loss=True.

Parameters

cavityCavity

Cavity element describing some Fabry-Perot like optical cavity

mode(n, m), optional

HG mode to try and lock to, default is [0,0]

lowest_lossbool, optional

Select the eigenmode which has the lowest loss, most likely the fundamental mode of the cavity. Using lowest loss will override the mode selection.

feedbackParameter optional

If None the required cavity tuning to lock to the calculated mode will be determined from the cavity objects source node element, and the relevant phi parameter will be used. Alternatively you can specify which tuning parameter is used instead. Which should be a phi of some mirror in the cavity or a DegreeOfFreedom which controls the cavity length.

namestr, optional

Name of the solution generated by this action

Examples

A Fabry-Perot based on aLIGO cavities:

>>> import finesse
>>> model = finesse.Model()
>>> model.parse('''
... l l1 P=1
... m ITM T=0.014 L=0 Rc=-1945
... s sARM ITM.p2 ETM.p1 L=3994
... m ETM R=1 L=0 Rc=2145
... link(l1, ITM)
... cav arm ETM.p1.o
... modes(maxtem=1)
... ''')

The cavity source node is on the ETM so the pseudo-lock will use that node and component phi parameter to feedback to. In this case the ETM.phi will be corrected to match the ITM.phi which will make the HG00 resonant.

>>> model.ITM.phi = 0
>>> model.ETM.phi = 10
>>> model.run("pseudo_lock_cavity(arm)")
>>> print(model.ITM.phi, model.ETM.phi)
0.0 degrees 0.0 degrees
>>> model.ITM.phi = 10
>>> model.ETM.phi = 0
>>> model.run("pseudo_lock_cavity(arm)")
>>> print(model.ITM.phi, model.ETM.phi)
10.0 degrees 10.0 degrees

This lock will also handle any misalignments, mismatches, or maps applied to the cavity.

>>> model.ITM.xbeta = 5e-8
>>> model.ITM.phi = 11
>>> model.ETM.phi = 0
>>> model.run("pseudo_lock_cavity(arm)")
>>> print(model.ITM.phi, model.ETM.phi)
11.0 degrees 10.984168676865762 degrees

We can also lock to other HG modes:

>>> sol = model.run("series(pseudo_lock_cavity(arm, mode=[1,0]), noxaxis())")
>>> print(model.ITM.phi, model.ETM.phi)
>>> print(model.homs)
>>> print(sol['noxaxis']['Ecirc'])
11.0 degrees 28.663091273523214 degrees
[[0 0]
[1 0]
[0 1]]
[-0.16465261-0.11468501j  0.41262682-0.27112167j  0.        +0.j        ]
class finesse.analysis.actions.PseudoLockDRFPMI(frequency=0, *, apply_tunings=True, name='operator_lock')

Bases: Action

Pseudo-locking is attempting to find an operating point for a LIGO like model without needing to use RF sidebands and readouts. Although it is not physically accurate it does provide a useful tool for analysing detectors from a more theoretical basis. This generates a PseudoLockDRFPMISolution solution containing various operators and results.

This action is hardcoded to work with a LIGO like model. Mirrors should be named with ITMX, ETMX, PRM, etc.

This currently action only really works for finding the lock points for the PRC, SRC, XARM, and YARM – which all have defined cavity roundtrips which allow eigendecomposition of roundtrip operators. The eigenvectors describe the HOM mix for each resonant mode in a cavity and the eigenvalues the roundtrip phase and loss of the mode. This code looks for eigenvectors with the largest HG00 content and then uses the eigenvalues to compute what cavity tunings need to make this mode resonant.

The corner is the most complicated here as the PRC and SRC are coupled via the beamsplitter. The eigendecomposition is performed on the 2x2 operator matrix for the PRC, SRC, and the coupling matrices between them. When the coupling is small the results are the same as performing the decomposition on each SRC and PRC separately.

Note that the only degree of freedom that this does not handle currently is MICH. MICH is awkward because it is not a cavity. It is essentially the beamsplitter position that makes the anti-symmetric port dark.

Parameters

frequencyfloat, optional

Frequency to use for calculating the operators

apply_tuningsbool, optional

When True the action will modify the model tunings

namestr, optional

Name of the solution generated by this action

class finesse.analysis.actions.RunLocks(*locks, method='proportional', scale_factor=1, sensing_matrix=None, max_iterations=10000, display_progress=False, optimize_phase=None, d_dof_phase=1e-09, set_gains=True, d_dof_gain=1e-09, exception_on_fail=True, no_warning=False, pre_step=None, show_progress_bar=None, name='run locks')

Bases: Action

An action that iteratively moves the system to lock. Currently, lock error signals must be readouts, not detectors, for use in this action.

Parameters

*lockslist, optional

A list of locks to use in each RunLocks step. If not provided, all locks in model are used.

methodstr, either “newton” or “proportional”

Which method to use in the locking iterations.

scale_factorfloat

Factor by which to multiply all DOF changes. Should be set below 1 if it is desired to minimize overshooting.

sensing_matrixSensingMatrixSolution or None

Sensing matrix of gains used in locking, of the type that would be returned by state.apply(SensingMatrixDC(lock_dof_names, readout_names) If None, the sensing matrix is recalculated. Recommended to be None except when locking multiple times in a row, e.g. with DragLocks.

max_iterationsint

The maximum number of locking steps in each execution of RunLocks.

display_progressboolean

When true, displays the status of the error signals during locking iterations.

optimize_phaseboolean

Deprecated: Use an action like OptimiseRFReadoutPhaseDC instead.

d_dof_phasefloat

Step size to use when optimizing the demodulation phase for each error signal/DOF pair.

set_gainsboolean

Only applies if method is “proportional”. If true, sets the gains for each error signal/DOF pair. If false, uses pre-set gains.

d_dof_gainfloat

Step size to use when calculating the gain for every pair of error signals and DOFs.

exception_on_failboolean

When true, raise exception if maximum iterations are surpassed.

no_warningboolean

When true, don’t even raise a warning if maximum iterations are reached. Recommended to be false unless repeatedly testing locking.

pre_stepAction

Action to apply on each step of the lock

show_progress_barboolean

Will enable the progress bar when true.

namestr

Name of the action.

complete_pbar()
init_pbar(locks)
update_pbar()
update_pbar_lock(lock_name, is_locked)
class finesse.analysis.actions.SensingMatrixAC(dofs, readouts, f=0.001, name='sensing_matrix_ac')

Bases: Action

Computes the sensing matrix elements for various degrees of freedom and readouts that should be present in the model. The solution object for this action then contains all the information on the sensing matrix. This can be plotted in polar coordinates, displayed in a table, or directly accessed.

The sensing gain is computed by calculating the gradient of each readout signal, which means it is a DC measurement. This will not include any suspension or radiation pressure effects.

This action does not modify the states model.

Parameters

dofsiterable[str]

String names of degrees of freedom

readoutsiterable[str]

String names of readouts

ffloat

Frequency to measure sensing matrix at

class finesse.analysis.actions.SensingMatrixDC(dofs, readouts, d_dof=1e-09, name='sensing_matrix_dc')

Bases: Action

Computes the sensing matrix elements for various degrees of freedom and readouts that should be present in the model. The solution object for this action then contains all the information on the sensing matrix. This can be plotted in polar coordinates, displayed in a table, or directly accessed.

The sensing gain is computed by calculating the gradient of each readout signal, which means it is a DC measurement. This will not include any suspension or radiation pressure effects.

This action does not modify the states model.

Parameters

dofsiterable[str]

String names of degrees of freedom

readoutsiterable[str]

String names of readouts

d_doffloat, optional

Small step used to compute derivative

class finesse.analysis.actions.Series(*actions, flatten=True, name=None)

Bases: Action

A sequential series of actions to apply during a simulation.

Parameters

actionsAction

A collection of Actions to run in series

flattenbool

When True, each action will be stored in the top level of the solution tree. When False, each action will be a child of the previous solution generated.

namestr

Optional name for the solution generated by these actions

class finesse.analysis.actions.SetLockGains(*locks, d_dof_gain=1e-10, gain_scale=1, name='set gains', optimize_phase=None, verbose=False)

Bases: Action

An action that computes the optimal lock gains using the sensing matrix found with SensingMatrixDC. This action computes the error signal gradient for each lock with respect to its drive and sets the gain as -gain_scale/sensing.

Parameters

*lockslist, optional

A list of locks for which to set the gain. If none provided, all enabled locks in model are used. Disabled locks that are explicitly listed will have their gains set.

d_dof_gainfloat, optional

Step size to use when calculating the gain for each error signal/DOF pair.

gain_scalefloat, optional

Extra gain scaling factor applied to the gain calculation: -gain_scale/sensing In multiple lock models where the locks are cross coupled using a gain_scale < 1 can improve the stability of the locking algorithm to stop excessively large steps.

optimize_phasebool, optional,

Deprecated feature: Use OptimiseRFReadoutPhaseDC instead

namestr

Name of the action.

verbosebool

If True this will print the name of the enabled locks and their gains.

class finesse.analysis.actions.StoreModelAttr(*args)

Bases: Action

class finesse.analysis.actions.Sweep(*args, pre_step=None, post_step=None, reset_parameter=True, name='sweep')

Bases: Action

An action that sweeps N number of parameters through the values in N arrays.

Parameters

args[Parameter, str], array, boolean

Expects 3 arguments per axis. The first is a full name of a Parameter or a Parameter object. The second is an array of values to step this parameter over, and lastly a boolean value to say whether this is a relative step from the parameters initial value.

pre_stepAction, optional

An action to perform before the step is computed

post_stepAction, optional

An action to perform after the step is computed

reset_parameterboolean, optional

When true this action will reset the all the parameters it changed to the values before it ran.

namestr

Name of the action, used to find the solution in the final output.

class finesse.analysis.actions.Temporary(temp_action, *actions)

Bases: Action

Make the first action in a series of actions temporary, i.e. restore its parameters after the rest of the actions are complete.

class finesse.analysis.actions.TemporaryParameters(action, *, include=None, exclude=None)

Bases: Action

An action that will revert any changed parameters back to their values before this action was called. Options exist to include or exclude certain Parameters from this reversion. This action does not generate any Solution.

Parameters

actionfinesse.analysis.actions.base.Action

Action to perform followed by reverting requested Parameters in the model

include[iterable|str], optional

Parameters that should be included.

If a single string is given it can be a Unix file style wildcard (See fnmatch). A value of None means everything is included.

If an iterable is provided it must be a list of names or Parameter objects.

exclude[iterable|str], optional

Parameters that should not be included.

If a single string is given it can be a Unix file style wildcard (See fnmatch). A value of None means nothing is excluded.

If an iterable is provided it must be a list of names or Parameter objects.

class finesse.analysis.actions.UpdateMaps(name='update_maps', *args, **kwargs)

Bases: Action

Update any maps that might be changing in the simulation.

class finesse.analysis.actions.X2axis(parameter1, mode1, start1, stop1, steps1, parameter2, mode2, start2, stop2, steps2, relative=False, *, pre_step=None, post_step=None, name='x2axis')

Bases: XNaxis

class finesse.analysis.actions.X3axis(parameter1, mode1, start1, stop1, steps1, parameter2, mode2, start2, stop2, steps2, parameter3, mode3, start3, stop3, steps3, relative=False, *, pre_step=None, post_step=None, name='x3axis')

Bases: XNaxis

class finesse.analysis.actions.Xaxis(parameter, mode, start, stop, steps, relative=False, *, pre_step=None, post_step=None, name='xaxis')

Bases: XNaxis