Finesse 3’s kat syntax is similar in style to that seen in Finesse 2, however there are many changes to the details. Here, we show the changes made in the new syntax, and example usages.

Component Definitions

Component definitions now mirror their Python constructor signatures. Both positional and keyword arguments are supported. Additionally, any components which had shortened names in Finesse 2 syntax (e.g. m for mirror) can now also be created via the full name of the component. Component parameters can now also be enclosed in parentheses, to allow splitting the definition over multiple lines. Some examples are shown below:

# Old-style one-line definition with positional arguments
# Mirror named "m1" with reflectivity R=0.99 and transmissivity T=0.01
m m1 0.99 0.01

# Mult-line definition with keyword arguments.
# Requires brackets as delimiters.
mirror m2 (
    R=0.99  # Comments are allowed anywhere

mirror m3 ( R=0.99 T=0.01  # New lines don't matter if you use parentheses

# One-line with brackets also works.
mirror m4 (R=1 T=0)

# Positional and keyword arguments.
m m5 (
    1 # Positional arguments must always come before keyword arguments
    Rcy=1 # keyword arguments

Ports and Nodes

Users of Finesse 2 may have noticed that none of the example component definitions above mention which nodes they are connected to. This is due to a reworking of the node system in Finesse 2; components now own ‘ports’, which are similar to nodes in Finesse 2. These can be accessed directly via the component, eliminating the need to give them specific names. For a full explanation, see The Port and Node System. Some brief examples are shown below:

# Spaces connect directly to component's ports
l l1 P=1
s s1 l1.p1 m1.p1 L=1
m m1 0.99 0.01
s s1 m1.p2 m2.p1 L=1
m m2 0.99 0.01

# Detectors connect to the nodes within ports,
# allowing the direction to detect to be specified
pd circ m2.p1.i  # Incoming beam at port p1
pd trans m2.p2.o  # Outgoing beam at port p2

Variables, Constants and References

In Finesse 2, in order to make a parameter of one component track another, a combination of set and put commands would have to be used:

m m1 0.99 0.01 0 n1 n2
m m2 0.5 0.5 0 n3 n4

set refl m1 R
set trans m1 T
put m2 R $refl
put m2 T $trans

In Finesse 3, we can take references to a parameter by prefixing it with an ampersand (&), transforming the above into:

m m1 0.99 0.01
m m2 (

Additionally, parameters can be used in expressions, removing the need for the func command from Finesse 2:

m m2 (
    R=&m1.R * 0.5


Finesse 3 also supports defining groups of components in a sub-model file, from which ports and parameters can be defined. For example, take the following file, saved as cav.kat:

var R 0.99
var T 1-&R

mirror m1 R=&R T=&T
space s1 m1.p2 m2.p1 L=1
mirror m2 R=&R T=&T

extern(m1.p1 p1)
extern(m2.p2 p2)
extern(&R R)
extern(&s1.L L)

This defines a lossless, impedance-matched cavity, with tunable mirror reflectivity R and length L, and ports p1 and p2. This can then be imported into another model:

laser l1 P=1
space s1 l1.p1 ic1.p1 L=1
ic1 = cav.kat
space s2 ic1.p2 m1.p1 L=2 * &ic1.L
mirror m1 &ic1.R T=0

Here, we import the model described in cav.kat as ic1. We can then access the ports and parameters we exported, and use them as normal. We also don’t need to worry about name clashes between the two components called s1 and m1; internally these components have their name prefixed with the imported name:

>>> print(list(ifo.model.elements.keys()))
['fsig', 'ic_R', 'ic_T', 'ic_m1', 'ic_m2', 'ic_s1', 'l1', 'm1', 's1', 's2']