Defining the modal basis

Using the correct modal basis (via beam parameters) at each point in the model configuration is important for computing couplings through Scattering matrices and other quantities such as the spatial distribution \(u_{nm}\) used for, e.g., calculating beam profiles. For these reasons, it is necessary to understand how Finesse sets beam parameters at nodes and how you can use this information to model the systems that you are investigating.

Complete details on the beam tracing algorithm of Finesse are included in Tracing the beam, this page will focus on how to use cavities and manual setting of beam parameters.

Using cavity objects

It is important in any analysis involving cavities that HOM couplings are computed using a (propagated) cavity eigenmode as the basis. If the beam parameters at nodes inside a cavity get set to values which are not equal to the corresponding cavity eigenmode then we can get mismatches where there shouldn’t be any and / or matches where there should be mismatches.

A key role of the Cavity object is to prevent this from happening by influencing the beam tracing algorithm when instances of this class are present in a model. The eigenmodes of all cavities in a model are computed upon adding it to the model and these are then used to set beam parameters in the rest of the model via propagating them through the ABCD matrix formalism, see Transformation of the beam parameter for details on this.

Adding cavities to a model

Cavity objects can be added to a model in the standard way via a call to Model.add() using the Python API. The constructor of the Cavity class requires a name for the cavity and the source node (i.e. starting point) of the cavity; with an optional via node if the cavity path should traverse via a specific node.

For simple cavities where the surfaces are not bounded (on the inside of the cavity path) by AR / HR coating surfaces, you only ever need to specify the source node. The cavity path will then be determined automatically from just this node. An example of this is shown below, using a simple Fabry-Perot type cavity model:

import finesse
import finesse.components as components

model = finesse.Model()
model.parse("""
l L0 P=1
s s0 L0.p1 ITM.p1

m ITM R=0.99 T=0.01 Rc=-2.5
s sCAV ITM.p2 ETM.p1 L=1
m ETM R=0.99 T=0.01 Rc=2.5
""")

# add the Cavity object with source node as second
# port output node
model.add(components.Cavity("FP", model.ITM.p2.o))

# showing the cavity path
print(model.FP.path)
╒═════════════════════════════════════════╤═══════════════════════════════════╕
│ From optical node                       │ Into component                    │
╞═════════════════════════════════════════╪═══════════════════════════════════╡
│ <OpticalNode ITM.p2.o @ 0x7fd01b327c70> │ <'sCAV' @ 0x7fd01b2a9460 (Space)> │
├─────────────────────────────────────────┼───────────────────────────────────┤
│ <OpticalNode ETM.p1.i @ 0x7fd01b2a9070> │ <'ETM' @ 0x7fd01b3278b0 (Mirror)> │
├─────────────────────────────────────────┼───────────────────────────────────┤
│ <OpticalNode ETM.p1.o @ 0x7fd01b2a90a0> │ <'sCAV' @ 0x7fd01b2a9460 (Space)> │
├─────────────────────────────────────────┼───────────────────────────────────┤
│ <OpticalNode ITM.p2.i @ 0x7fd01b327c40> │ <'ITM' @ 0x7fd01b327940 (Mirror)> │
╘═════════════════════════════════════════╧═══════════════════════════════════╛

If you have a model with AR / HR coatings at surfaces then you will need to specify the via node argument in order for the cavity path to include the surface itself. See the example below:

model = finesse.Model()
model.parse("""
l L0 P=1
s l0 L0.p1 PRM.p1 L=1

m PRM T=0.046 L=37.5u

s lpr1 PRM.p2 BS.p1 L=9

bs BS T=0.5 L=37.5u alpha=60

s ly BS.p2 ITMAR.p1 L=100

# Y arm input mirror with AR surface
m ITMAR R=0 L=20u
s ITMsub ITMAR.p2 ITM.p1 L=0.2 nr=&nsilica
m ITM T=7000u L=37.5u Rc=-5580

lambda 1550n
var nsilica 1.44963098985906
""")

# INCORRECT -- doesn't include ITM
model.add(components.Cavity("PRC_wrong", model.PRM.p2.o))

print(model.PRC_wrong.path)
╒═══════════════════════════════════════════╤════════════════════════════════════════╕
│ From optical node                         │ Into component                         │
╞═══════════════════════════════════════════╪════════════════════════════════════════╡
│ <OpticalNode PRM.p2.o @ 0x7fd01b26e070>   │ <'lpr1' @ 0x7fd01b20f250 (Space)>      │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode BS.p1.i @ 0x7fd01b26e430>    │ <'BS' @ 0x7fd03c23a9a0 (Beamsplitter)> │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode BS.p2.o @ 0x7fd01b26e4f0>    │ <'ly' @ 0x7fd01b20f490 (Space)>        │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode ITMAR.p1.i @ 0x7fd01b26e8b0> │ <'ITMAR' @ 0x7fd03c23aa00 (Mirror)>    │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode ITMAR.p1.o @ 0x7fd01b26e8e0> │ <'ly' @ 0x7fd01b20f490 (Space)>        │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode BS.p2.i @ 0x7fd01b26e4c0>    │ <'BS' @ 0x7fd03c23a9a0 (Beamsplitter)> │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode BS.p1.o @ 0x7fd01b26e460>    │ <'lpr1' @ 0x7fd01b20f250 (Space)>      │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode PRM.p2.i @ 0x7fd01b26e040>   │ <'PRM' @ 0x7fd01b252d60 (Mirror)>      │
╘═══════════════════════════════════════════╧════════════════════════════════════════╛

You can see from this cavity path that the cavity “end” point is ITMAR, not ITM, as by default the cavity will find the shortest path back to the source node. To correct this, you must use the via node:

# CORRECT -- now we specify that the path must traverse via ITM
model.add(components.Cavity("PRC", model.PRM.p2.o, model.ITM.p1.i))

print(model.PRC.path)
╒═══════════════════════════════════════════╤════════════════════════════════════════╕
│ From optical node                         │ Into component                         │
╞═══════════════════════════════════════════╪════════════════════════════════════════╡
│ <OpticalNode PRM.p2.o @ 0x7fd01b26e070>   │ <'lpr1' @ 0x7fd01b20f250 (Space)>      │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode BS.p1.i @ 0x7fd01b26e430>    │ <'BS' @ 0x7fd03c23a9a0 (Beamsplitter)> │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode BS.p2.o @ 0x7fd01b26e4f0>    │ <'ly' @ 0x7fd01b20f490 (Space)>        │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode ITMAR.p1.i @ 0x7fd01b26e8b0> │ <'ITMAR' @ 0x7fd03c23aa00 (Mirror)>    │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode ITMAR.p2.o @ 0x7fd01b26e970> │ <'ITMsub' @ 0x7fd03c23ab20 (Space)>    │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode ITM.p1.i @ 0x7fd01b26edf0>   │ <'ITM' @ 0x7fd01b26eb80 (Mirror)>      │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode ITM.p1.o @ 0x7fd01b26ee20>   │ <'ITMsub' @ 0x7fd03c23ab20 (Space)>    │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode ITMAR.p2.i @ 0x7fd01b26e940> │ <'ITMAR' @ 0x7fd03c23aa00 (Mirror)>    │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode ITMAR.p1.o @ 0x7fd01b26e8e0> │ <'ly' @ 0x7fd01b20f490 (Space)>        │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode BS.p2.i @ 0x7fd01b26e4c0>    │ <'BS' @ 0x7fd03c23a9a0 (Beamsplitter)> │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode BS.p1.o @ 0x7fd01b26e460>    │ <'lpr1' @ 0x7fd01b20f250 (Space)>      │
├───────────────────────────────────────────┼────────────────────────────────────────┤
│ <OpticalNode PRM.p2.i @ 0x7fd01b26e040>   │ <'PRM' @ 0x7fd01b252d60 (Mirror)>      │
╘═══════════════════════════════════════════╧════════════════════════════════════════╛

Showing the importance of including Cavity objects

Below is an example highlighting the importance of including Cavity objects in a model for HOM modelling. In this example, the detuning of the input mirror of a Fabry-Perot cavity is scanned whilst the power on transmission is detected.

import finesse

model = finesse.Model()
# define a configuration with no Cavity object present
model.parse("""
l L0 P=1
s s0 L0.p1 ITM.p1

m ITM R=0.99 T=0.01 Rc=-2.5
s sCAV ITM.p2 ETM.p1 L=1
m ETM R=0.99 T=0.01 Rc=2.5

# set a beam parameter with w0 = 1 mm, z-z0 = -0.3 m at the laser
gauss gL0 L0.p1.o w0=1m z=-0.3

maxtem 4

# detect the transmitted power
pd trns ETM.p2.o

xaxis &ETM.phi lin -180 180 500
""")

out_no_cav = model.run()

Now we add a Cavity object to the model and run it again, we also display the mismatches that are now present in the system due to the manually set beam parameter at the laser and the beam parameters automatically set in the cavity based on its eigenmode. See Creating and detecting mode mismatches for details on the Model.print_mismatches() method and more.

# source node is output of second port of ITM
# -> cavity path is then determined automatically from this
model.add(finesse.components.Cavity("FP", model.ITM.p2.o))

model.print_mismatches()

out_cav = model.run()
╒══════════════════════╤════════════════╤════════════════╕
│ Coupling             │   Mismatch (x) │   Mismatch (y) │
╞══════════════════════╪════════════════╪════════════════╡
│ ITM.p1.i -> ITM.p1.o │       0.543728 │       0.543728 │
├──────────────────────┼────────────────┼────────────────┤
│ ITM.p2.i -> ITM.p2.o │       0.543728 │       0.543728 │
├──────────────────────┼────────────────┼────────────────┤
│ ETM.p1.i -> ETM.p1.o │       0.50515  │       0.50515  │
├──────────────────────┼────────────────┼────────────────┤
│ ETM.p2.i -> ETM.p2.o │       0.50515  │       0.50515  │
╘══════════════════════╧════════════════╧════════════════╛

And then plot the results of each to show the difference:

import matplotlib.pyplot as plt
finesse.init_plotting()

fig = plt.figure()
plt.semilogy(out_no_cav.x1, out_no_cav["trns"], label="No cavity tracing")
plt.semilogy(out_cav.x1, out_cav["trns"], label="With cavity tracing")
plt.xlabel("ETM phi [deg]")
plt.ylabel("Transmitted power [W]")
plt.legend();
../../_images/modal_basis_5_0.svg

From this plot you can see that with the cavity included we get the expected resonance peaks corresponding to the fundamental (TEM00) mode and the 02/20 and 04/40 modes; the latter arising due to the mismatch present within the system. Without the cavity object present, the transmitted power trace obtained is nonsensical.

Defining manual beam parameters

Todo

Document using gauss commands and setting qs at nodes via python API