Introduction

Welcome to the first notebook! This notebook is broken down into two sections. The first section aims to get you started with Finesse. It contains some basic tasks how to use two of the most important components in an interferometer, a mirror and a laser. The second section involves building up a Fabry-Perot cavity.

In [1]:
%run pykat_notebook_defaults.py
pykat.init_pykat_plotting()
                                              ..-
    PyKat 1.0.19          _                  '(
                          \`.|\.__...-""""-_." )
       ..+-----.._        /  ' `            .-'
   . '            `:      7/* _/._\    \   (
  (        '::;;+;;:      `-"' =" /,`"" `) /
  L.        \`:::a:f            c_/     n_'
  ..`--...___`.  .    ,  
   `^-....____:   +.      www.gwoptics.org/pykat

Imported matplotlib.pyplot as plt
Imported numpy as np
You can now use 'print(kat)' to display the Finesse code of a 'kat' object

Beams and mirrors

These first tasks are designed to get you accquainted with some of the basic features of how Finesse works. Here we will look just purely at a laser and mirror component and how the optical field behaves. These tasks will expand on what you already learned about theoretically in the lectures previous to this.

Tasks

These tasks will involve several steps each. This will usually be looking up how to write Finesse commands, forming a Finesse model, running the simulation with Pykat, and then relating the results you see back to the theory from the lectures.

Remember, these tasks are meant to get you thinking and comparing to the theory you learned in the lectures. Talk to your fellow students and ask lots of questions!

Task 1: Laser and a mirror

Write the Finesse code to model a laser outputting 10W of power that is incident on a mirror 1m away. The mirror should reflect 80% of the light and transmit 20%. You'll find the following references useful:

You should write your Finesse code in a multi-line string variable, for example:

code = """
This
is a
multi-line
string
"""

Each line should contain one Finesse command.

In [2]:
code = """
l l1 10 0 n0
s s1 1 n0 n1
m m1 0.8 0.2 0 n1 n2
"""

Task 2: Laser and a mirror kat object

(a) Create a kat object and add the Finesse code you created in Task 1 to it using the kat.parseCommands function.

(b) Add two photo diodes to measure the optical power reflected and transmitted at the mirror.

In [3]:
kat = finesse.kat()
kat.parseCommands(code)
kat.parseCommands("""
pd Prefl n1
pd Ptran n2
""")

Task 3: Power conservation

Using the kat object above, set kat.noxaxis = True. This tells Finesse to compute just one data point for our model and not change any parameters. You can also set kat.verbose = False to stop it from printing information when the simulation is running.

(a) Run this kat object to get the simulation output.

(b) Does the reflected and transmitted power match up with the input power?

In [4]:
kat.noxaxis = True
kat.verbose = False

out = kat.run()

print("Calculated powers")
print(out['Prefl'], out['Ptran'])

# Total power adds up to 10W
Calculated powers
8.0 2.0

Task 4: Complex fields

The optical field has both an amplitude and a phase. We can output this in Finesse using the amplitude detector (ad).

(a) For this task you should look up the syntax for the ad detector. Hint: the frequency given in the ad detector is relative to the default optical frequency $f = c/1064$nm. You can see what the default wavelength is using kat.lambda0.

(b) Add three amplitude detectors: one looking at the beam going into the mirror, one looking at the reflected field, and another looking at the transmitted field. Add the command yaxis abs:deg to output a complex number from Finesse so we can get the magnitude and phase of the field.

(c) Run the kat object and print the magnitude and phases of the optical fields. What is the difference in phase from the incident field to the reflected field and incident field to tranmitted field? Why is the phase different on transmission?

(d) What units do the pd and ad detector outputs in Finesse have?

In [5]:
# ad detector syntax
# ad name frequency node

kat = finesse.kat()
kat.parseCommands(code)
kat.parseCommands("""
ad aI 0 n1*
ad aR 0 n1
ad aT 0 n2
yaxis abs:deg
""")

kat.noxaxis = True
kat.verbose = False

out = kat.run()

out.info()

# We can see from the output that the reflected and incident field have the same phase
# but on transmission it is 90 degrees extra. This is due to the phase relationship at
# a surface to conserve energy.
--- Output info ---

Run date and time: 2017-07-11 10:03:25.421229
Detectors used: aI, aR, aT

No xaxis used
aI Abs         : min = 3.162277660168380e+00 max = 3.162277660168380e+00
aI Phase [Deg] : min = 0.000000000000000e+00 max = 0.000000000000000e+00
aR Abs         : min = 2.828427124746190e+00 max = 2.828427124746190e+00
aR Phase [Deg] : min = 0.000000000000000e+00 max = 0.000000000000000e+00
aT Abs         : min = 1.414213562373090e+00 max = 1.414213562373090e+00
aT Phase [Deg] : min = 9.000000000000000e+01 max = 9.000000000000000e+01
In [6]:
# The units of the pd detectors are Watts, the ad detectors is
# sqrt{Watt}, as Finesse scales the electric field so that |E|^2 = Power

Task 5: Mirror positions, or tunings

One of the most crucial aspects in optical interferometery is accurately positioning mirrors. The optical wavelengths we use in gravitational wave detectors is $\lambda=1064nm$. Typically we are interested in either macroscopic positioning, such as a mirror is 1m, 1cm, 1mm, etc. away, or in microscopic positions which are fractions of $\lambda$. The resonance condition of a Fabry-Perot cavity requires its length to be an integer number of half-wavelengths. For the light of an Nd:YAG laser, length differences $\ll \lambda=1064$nm are of interest. Some orders of magnitude:

  • LIGO peak senitivity in meters: $\sim 10^{-20}$ m
  • LIGO cavity mirror postion control accuracy: $< 10^{-12}$ m
  • LIGO arm cavity length: $\sim 10^3$ m
  • Relative numerical accuracy of floating point numbers: $10^{-15}$

As we can see there are many orders of magnitude difference between the lengths of cavities and the types of signal we might measure. With such a large dynamic range typical floating point variables used in computers cannot represent this. Thus we break lengths up into macroscopic and microscopic lengths. The length given by the space component are macroscopic and are always rounded to the nearest interger number of $\lambda$.

We change the microscopic length differences in Finesse by changing the mirrors tuning value. Tuning is usually refered to in units of degrees, 360 degrees $= \lambda$. So a tuning of 180 degrees means we have moved the mirror by half a wavelength. You can read more about this in the Living Review, section 2.5, "Lengths and tunings: numerical accuracy of distances".

The aim of this tasks is to think about the phase relationships Finesse uses, as this is important to grasp for later tasks.

(a) Using your kat object from before, change the mirror tuning by 90 degrees. How did the phase of the reflected and transmitted fields change relative to the incident field?

(b) If you change the tuning by 360 degrees, do the amplitudes of the optical fields change?

(c) If you change the length of the space between the mirror and laser, does it affect the phase?

In [7]:
kat = finesse.kat()
kat.parseCommands(code)
kat.parseCommands("""
ad aI 0 n1*
ad aR 0 n1
ad aT 0 n2
yaxis abs:deg
""")

kat.m1.phi += 90

kat.noxaxis = True
kat.verbose = False

out = kat.run()

out.info()

# The phase relationship on transmission has stayed the same, just 90 degrees, as the shifting position does not affect
# the phase accumulated on propagation. On reflection though the beam had to take a longer path than before, so it is now
# 180 degrees out of phase with the incident.
--- Output info ---

Run date and time: 2017-07-11 10:03:26.414553
Detectors used: aI, aR, aT

No xaxis used
aI Abs         : min = 3.162277660168380e+00 max = 3.162277660168380e+00
aI Phase [Deg] : min = 0.000000000000000e+00 max = 0.000000000000000e+00
aR Abs         : min = 2.828427124746190e+00 max = 2.828427124746190e+00
aR Phase [Deg] : min = 1.800000000000000e+02 max = 1.800000000000000e+02
aT Abs         : min = 1.414213562373090e+00 max = 1.414213562373090e+00
aT Phase [Deg] : min = 9.000000000000000e+01 max = 9.000000000000000e+01
In [8]:
kat.s1.L += 10

kat.run().info()

# The phases don't change when the length changes as Finesse defines that a space always has an integer number
# of wavelengths for the default frequency.
--- Output info ---

Run date and time: 2017-07-11 10:03:27.176711
Detectors used: aI, aR, aT

No xaxis used
aI Abs         : min = 3.162277660168380e+00 max = 3.162277660168380e+00
aI Phase [Deg] : min = 0.000000000000000e+00 max = 0.000000000000000e+00
aR Abs         : min = 2.828427124746190e+00 max = 2.828427124746190e+00
aR Phase [Deg] : min = 1.800000000000000e+02 max = 1.800000000000000e+02
aT Abs         : min = 1.414213562373090e+00 max = 1.414213562373090e+00
aT Phase [Deg] : min = 9.000000000000000e+01 max = 9.000000000000000e+01

Task 6: Scanning parameters

So far we have just run a single data point in our simulations. Usually we want to change some thing and see how the outputs vary, and we will be doing this a lot in the coming notebooks. In Finesse we vary parameters in a simulation using the xaxis command, this changes some parameter from one value to another and computes it for $N$ steps between them.

(a) Look up the syntax for the xaxis command.

(b) Add an xaxis command to change the input laser power from 1W to 10W in 20 steps.

(c) Plot the reflected and transmitted powers.

(d) Does the sum of reflected and transmitted power always equal the input power?

In [9]:
# xaxis command
# xaxis component parameter lin/log upper lower steps

kat = finesse.kat()
kat.parseCommands(code)
kat.parseCommands("""
pd Prefl n1
pd Ptran n2
yaxis abs:deg
xaxis l1 P lin 1 10 20
""")

kat.verbose = False

out = kat.run()

plt.plot(out.x, out['Prefl'], label="Refl")
plt.plot(out.x, out['Ptran'], label="Tran")
plt.plot(out.x, out['Prefl'] + out['Ptran'], label="Total")
plt.xlabel(out.xlabel)
plt.ylabel("Power [W]")
plt.legend()
plt.tight_layout()