Finesse includes a built-in definition language called KatScript that provides an alternative way to build models without using the Python API. It is concise, simple, and easy to use. The following contains a brief introduction to KatScript syntax and the available instructions.
Supported elements, commands and analyses are described in their corresponding sections. There are also command, element and analysis indices for quick reference.
KatScript in Finesse 3 is different to that of Finesse 2, however the most common syntax is also supported via a separate legacy parser. There is also a migration guide.
A quick example¶
KatScript models are built by specifying components, detectors, commands and other types of statement on separate lines:
# Example of 10 W of laser power incident upon a Fabry-Perot cavity. l l1 P=10 s s1 l1.p1 m1.p1 m m1 R=0.99 T=0.01 s s2 m1.p2 m2.p1 m m2 R=0.99 T=0.01 pd pd1 m2.p1.i modes(even, maxtem=10)
Each line above specifies a component, detector or command. Most of the statements are
formed from a series of space-delimited values; these represent elements of the model.
Elements always have unique names, which must be specified after the element type, which
is often, but not always, represented by a short one or two character name. The last
line is a command which sets some properties of the model or simulation. In this case,
it’s setting the higher order modes to simulate. The arguments following the
element names are used to customise the element, such as to set the reflectivity and
transmissivity in the case of the mirrors. The comma-delimited parameters inside the
parentheses of the
modes command serve a similar purpose.
Whitespace and comments¶
Whitespace can be simple spaces, tabs and newlines. Comments start with
Everything including and after
# on the same line is ignored by the parser.
# This is a comment!
Whitespace is sometimes important in KatScript, for instance between parameters of elements.
Types, names and keywords¶
Component types (like
mirror), names (like
m1) and keywords (like
lin) are written directly, without quotation marks:
mirror m1 # A mirror named 'm1'.
User-defined names have to start with a letter, but can otherwise contain integer numbers and underscores.
Numbers can use integer, floating point, scientific and complex notation. The imaginary
j. SI prefices are also supported, but cannot be combined with scientific
notation. For example:
# Typical number forms. 1 1. 1.2 -3.141 6.5+2.0j # Scientific notation. 1.1e7 7.6e-2.1 # SI prefices. Any of p, n, u, m, k, M, G, and T are supported. 1m # equivalent to 1e-3 1k # equivalent to 1e3
Components and detectors¶
Component and detector definitions, collectively referred to as elements, mirror their
Python API signatures for the most part. Both positional and keyword arguments are
supported. Elements can be referred to using either their full name or an abbreviated
short form. They are defined using syntax of the form
element name arg1 arg2
# Definition with positional arguments (Finesse 2 style): a mirror named "m1" with # reflectivity R=0.99 and transmissivity T=0.01. mirror m1 0.99 0.01 # Definition with keyword arguments. # Note that only two of "R", "T" and "L" are required, and the third is calculated # from the first two. You can still specify all three, but they must all add up to # 1. mirror m2 R=0.99 T=0.01 # You can mix positional and keyword arguments as long as they make sense. Like in # Python, positional arguments must always come before keyword arguments. mirror m3 1 0 Rc=[1, 1.1] # Rcx and Rcy defined together.
Element definitions cannot span multiple lines.
Most components and detectors will have alias’ that can be used instead of longer names.
m can be used instead of
bs instead of
Commands and analyses¶
Commands set some special behaviour in the model. Analyses define one or more procedures
to perform on the model defined in the script. Both commands and analyses are defined
using syntax in the form
command(arg1, arg2, ...):
# Command used to set the higher order modes to simulate. modes(maxtem=3) # The `modes` command supports various different types of input. You can for example # specify individual modes... modes([[1, 0], [0, 1], [2, 0]]) # ...or odd modes up to 9. modes(odd, maxtem=9)
The arguments inside the parentheses in command and analysis definitions can span across multiple lines, and may contain comments:
modes( even, # Set maximum mode. maxtem=10 )
Some analyses can contain other analyses; this is used for example to build a set of nested procedures to perform on the model:
# Xaxis function to perform a linear sweep over the value of m1.phi. xaxis(m1.phi, lin, 0, 10k, 500) # A nested action tree. series( # First sweep m1.R... xaxis(m1.R, lin, 0, 1, 10), # ...then L0.P. xaxis(L0.P, lin, 10, 100, 20) )
Ports and nodes¶
Some components define ports which act as reference points in the model to which detectors and other components may be connected or certain properties such as beam sizes may be defined. Ports themselves contain nodes which provide access to the underlying directions. 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
Elements and their attributes and parameters can be addressed elsewhere in models using
their path. Elements are simply referred to by their name; for example, a
mirror named m1 has path
m1. Attribute and parameter paths are
formed by combining their owner’s path with the attribute or parameter name, separated
.; for example, a mirror’s phi model parameter has path
m1.phi. Ports and
nodes are also addressable this way: the mirror’s first port has path
m1.p1 and the
incoming node of that port has path
m1.p1.i. Commands and analyses do not have names
and can thus not be addressed this way.
Paths are mainly useful when specifying spaces, detectors and analyses. Spaces can be used to connect components by referring to the paths of their ports:
m m1 R=0.99 T=0.01 m m2 R=0.99 T=0.01 s s1 m1.p2 m2.p1 L=10 # Connect port 2 of m1 to port 1 of m2.
Detectors can “look at” a particular port or node in a model:
l l1 P=10 m m1 R=0.99 T=0.01 s s1 l1.p1 m1.p1 pd pd1 m1.p1.i # Look at the power incident on m1 on the port 1 side pd pd2 m1.p2.o # Look at the power outgoing from m1 on the port 2 side ad a m1.p2.o f=0
The syntax of Finesse 3 detector code has changed the order of arguments compared to version 2. The nodes are now specified after the name of the detector, rather than at the end of the command. This is because we can now allow keyword-arguments and other optional parameters which are easier to parse when all the required arguments are first.
Certain analyses can sweep model parameters:
l l1 P=1 m m1 R=0.99 T=0.01 m m2 R=0.99 T=0.01 s s1 m1.p2 m2.p1 L=10 xaxis(l1.P, lin, 0, 10, 100) # Sweep l1's power from 0 to 10 W over 100 points.
Expressions and references¶
Parameter values can contain expressions:
m m2 R=0.5 T=0.5 phi=cos(2*pi)
When used in element definitions, expressions cannot contain spaces. Spaces are allowed when the expression is enclosed in parentheses, either inside a function or parentheses:
# Allowed: l l2 P=(&l1.P / 10) # Functions also work: l l2 P=cos(&l1.P / 10) # NOT allowed: # l l2 P=&l1.P / 10
The following operators are supported:
Supported expression functions¶
The following mathematical functions are supported:
Degrees to radians
Radians to degrees
Functions that require multiple arguments (currently only
arctan2) should have those
arguments separated by a comma:
Expressions in KatScript can make references to model parameters by prefixing the
parameter’s address with an ampersand (
&). This allows the value of the target model
parameter to be used inside expressions. Since expressions can themselves be the value
of other model parameters, this lets model parameters be linked:
m m1 0.99 0.01 m m2 R=&m1.R T=&m1.T # m2's R and T parameters take their values from those of m1.
References can be included within larger expressions:
l l1 P=1 l l2 P=2*&l1.P # Set l2's power to twice that of l1.
References can also refer to other parameters within the same element:
m m1 R=1-&m1.T T=0.01 # Set R to ensure R + T = 1.
Model parameter values containing references (either directly or via expressions) get updated on each step of simulations, allowing for a single axis sweep to update many parameters indirectly. This is a powerful feature of KatScript, allowing for compact descriptions of complex models.
The following keywords exist in KatScript and serve special purposes. These do not need to be specified in quotes when used as element or function arguments:
Used to represent null.
Used to represent higher order mode sets.
Used to represent scales.
Used to represent modulation types.
Used to represent filter types.
Cavity and beam properties.
Some parameters, like the
Rc parameter of a
mirror or the
modes command support arrays as inputs. Arrays in KatScript are defined
using comma-delimited lists of values contained within square brackets:
m m1 R=1 T=0 Rc=[1, 1.1] # Radius of curvature in tangential (x) and sagittal (y) planes.
Arrays can also contain expressions:
m m1 R=1 T=0 Rc=[1, 1.1] m m2 R=1 T=0 Rc=[&m1.Rcx, 1.2]
Arrays can also contain other arrays. This can be useful for defining the modes to simulate:
modes([[1, 0], [0, 1], [2, 0]]) # Simulate only these higher order modes.
Generating KatScript from a model¶
Once you’ve parsed a script into a model, you can continue to make changes using the
Python API. If you wish to then regenerate KatScript for the updated model, you
Model.unparse_file(). Note that this does not
(yet) preserve the original parse order.
from finesse import Model model = Model() # Parse a simple model. model.parse( """ l l1 P=10 s s1 l1.p1 m1.p1 m m1 R=0.995 T=1-&m1.R s s2 m1.p2 m2.p1 L=10 m m2 R=0.9999 T=1-&m2.R pd pd1 m2.p1.i pd pd2 m2.p2.o """ ) # Change the cavity length. model.spaces.s2.L = 9 # Unparse the model. print(model.unparse())
laser l1 P=10.0 f=0.0 phase=0.0 mirror m1 R=0.995 T=(1-&m1.R) L=none phi=0.0 Rc=[inf, inf] xbeta=0.0 ybeta=0.0 misaligned=false space s1 portA=l1.p1 portB=m1.p1 L=0.0 nr=1.0 gouy_x=0.0 gouy_y=0.0 mirror m2 R=0.9999 T=(1-&m2.R) L=none phi=0.0 Rc=[inf, inf] xbeta=0.0 ybeta=0.0 misaligned=false space s2 portA=m1.p2 portB=m2.p1 L=9.0 nr=1.0 gouy_x=0.0 gouy_y=0.0 power_detector_dc pd1 node=m2.p1.i pdtype=none power_detector_dc pd2 node=m2.p2.o pdtype=none lambda(1.064e-06)
KatScript generation is an experimental feature and likely contains bugs. It is not (yet!) guaranteed to generate KatScript that parses back to the same model state. Use it with care!