Reach point of modelling HOQI in Finesse with polarisation
What does this MR do and why?
This merge request should bring polarisation features to the point of being able to model the HOQI interferometer, which is just plane wave, no optical cavity with polarisation.
-
Merge in Luise's code for the Jones matrices, separate module in -
finesse.utitilies.jones.matrices
for matrices -
finesse.utitilies.jones.visualization
for visualization (could be moved to plotting) -
finesse.utitilies.jones.detectors
some utilities for interpreting jones vectors (maybe unnecessary?)
-
-
New components/detectors -
Add quarter-wave plate -
PBS -
Fix optical_equations to allow pol specific coupling equations
-
-
Polarisers -
Add polarimeter detector
-
-
Fix power detector calculations to loop over both polarisations when enabled, see POL_IDX
placeholder in the code -
Add example/test of HOQI -
Fix tests/validation/graph/test_single_cavity.py
which requires fixing the graph solver to work with no polarisation again -
Add a new 'physics of Finesse' page for polarisation, in this should be a page on definitions of coordinate systems and minus signs, whether any circular polarisation is defined looking into or with the beam, etc.
Math sources
Are being collected here https://gitlab.nikhef.nl/finesse/polarisation (you might need permission to access). Contains math sources for jones matrices mentioned in the docstrings, Luise's original Jones library and some mockup finesse code that we hope to run when this branch is finished.
Testing guide
New optical elements:
-
hwp
(halfwaveplate) -
qwp
(quarterwaveplate) -
lpol
(linear polarizer)
All elements have a Jones matrix associated with them in their optical_equations
method, the matrices are defined in finesse.utilities.jones.matrices.py
All these elements have a parameter theta
, which is a rotation angle measured from the horizontal (S) plane.
Our current definition seems to be that the Jones vector is (Ex, Ey) / (S, P) !
Laser set up
Either l l1 pol=s
or l l1 pol=p
. You can not use polarization components if you do not specify the laser polarization (should be a check for this)
Measuring
Power detectors measure the combined s and p fields.
You have to use amplitude detectors with kwargs f=0 pol=s
or f=0 pol=p
to measure either S or P field
Visualization
I added a convenience method Model.add_pol_detector(node)
which adds two amplitude detectors with an autogenerated names at the selected node. Their output is available in the solution object under sol.jones(node)
which provides the array of (S, P) vectors for every point of the action used. This can serve as direct input for Luise's visualization methods draw_jones_animated
and draw_jones_field
Examples:
Remove all signal with a linear polarizer orthogonal to the laser polarization
import finesse
model = finesse.script.parse(
f"""
l l1 pol=p
lpol lp1 theta=0
ad P lp1.p2.o f=0 pol=p
ad S lp1.p2.o f=0 pol=s
link(l1, lp1)
"""
)
sol = model.run()
assert sol['S'] == 0
assert sol['P'] == 0
Rotating a linear polarizer
import finesse
from matplotlib import pyplot as plt
from finesse.analysis.actions import Xaxis
model = finesse.script.parse(
f"""
l l1 pol=s
lpol lp1 theta=0
link(l1, lp1)
ad P lp1.p2.o f=0 pol=p
ad S lp1.p2.o f=0 pol=s
"""
)
sol = model.run(Xaxis(model.lp1.theta, "lin", 0, 360, 360))
sol.plot()
inspecting polarization state after halfwaveplate
from finesse.utilities.jones import draw_jones_field, draw_jones_animated
from matplotlib import pyplot as plt
model = finesse.script.parse(
f"""
l l1 pol=s
hwp hwp1
link(l1, hwp1)
"""
)
node = "hwp1.p2.o"
model.add_pol_detector(node)
sol = model.run()
draw_jones_field(sol.jones[node])
plt.show()
producing circular polarization with a quarterwaveplate
from finesse.utilities.jones import draw_jones_field, draw_jones_animated
from matplotlib import pyplot as plt
model = finesse.script.parse(
f"""
l l1 pol=s
qwp qwp1 theta=45
link(l1, qwp1)
"""
)
node = "qwp1.p2.o"
model.add_pol_detector(node)
sol = model.run()
# can be made interactive by adding '%matplotlib widget' to the top of your notebook
draw_jones_field(sol.jones[node])
plt.show()
# can also directly be displayed in jupyer environment
anim = draw_jones_animated(sol.jones[node])
anim.save("circular.mp4")
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
-
Includes tests for added/modified code -
Added or modified the documentation if relevant -
Docstrings added/modified for new/modified functions -
Committer/reviewer has ran the documentation stage when ready to merge