{ "cells": [ { "cell_type": "markdown", "id": "0", "metadata": {}, "source": [ "This page is a notebook. You can download it: {download}`a_first_finesse_example.ipynb `" ] }, { "cell_type": "markdown", "id": "1", "metadata": {}, "source": [ "# A first Finesse example" ] }, { "cell_type": "markdown", "id": "2", "metadata": {}, "source": [ "In this example notebook, we will look at a so-called dual-recycled Michelson Fabry–Perot interferometer, similar to the configuration used in Advanced LIGO. The key learning goals of this notebook should be:\n", "\n", "1. Understanding how to build a Finesse model and define the components in Finesse.\n", "2. Learning how to analyse/study the model using detectors.\n", "3. Learning how to perform analyses and actions using Finesse.\n", "\n", "The purpose of this notebook is to introduce a recommended workflow structure for building your models and to give an overview of the basic functionalities of Finesse. The structure we follow here is the one we recommend adopting for your future Finesse models. By the end of this notebook, you should be able to construct your own Finesse model." ] }, { "cell_type": "code", "execution_count": null, "id": "3", "metadata": {}, "outputs": [], "source": [ "import finesse\n", "# if you want to do make custom plots you would import matplotlib \n", "#import matplotlib.pyplot as plt\n", "from finesse.analysis.actions import Xaxis\n", "finesse.init_plotting()" ] }, { "cell_type": "markdown", "id": "4", "metadata": {}, "source": [ "## Building a Finesse model with KatScript\n", "\n", "The Finesse model and the various components/optics (building blocks) are defined below in a string with KatScript syntax." ] }, { "cell_type": "code", "execution_count": null, "id": "5", "metadata": {}, "outputs": [], "source": [ "# Model\n", "# --------------------------------------------------------------\n", "# Creating the basic Finesse model object\n", "base = finesse.Model() \n", "\n", "# Building an optical layout into the model\n", "base.parse(\"\"\" \n", "l LI P=125\n", "s s0 LI.p1 eom1.p1 L=0.1\n", "mod eom1 f=6e6 midx=0.2\n", "s s1 eom1.p2 PRM.p1 L=0.1\n", "\n", "# Power recycling mirror\n", "m PRM T=0.03 L=37.5u phi=90\n", "s prc PRM.p2 bs1.p1 L=53\n", "\n", "# Central beamsplitter\n", "bs bs1 R=0.5 T=0.5 phi=0 alpha=45\n", "\n", "# X-arm\n", "s sx bs1.p3 ITMX.p1 L=4.5\n", "m ITMX T=0.014 L=37.5u phi=89.997\n", "s Lx ITMX.p2 ETMX.p1 L=3995\n", "m ETMX T=0.01 L=37.5u phi=89.997\n", "\n", "# Y-arm\n", "s sy bs1.p2 ITMY.p1 L=4.45\n", "m ITMY T=0.014 L=37.5u phi=3m\n", "s Ly ITMY.p2 ETMY.p1 L=3995\n", "m ETMY T=0.01 L=37.5u phi=3m\n", "\n", "# Signal recycling mirror\n", "s src bs1.p4 SRM.p1 L=50.525\n", "m SRM T=0.2 L=37.5u phi=-90\n", "\n", "\"\"\") " ] }, { "cell_type": "markdown", "id": "6", "metadata": {}, "source": [ "## Adding detectors in Finesse\n", "\n", "Now we need to think what we want to do with the interferometer. It can be helpful to ask this question in the form of: 'what plot should I make?'. Then you can define what detector to add to the simulation (what is on the y-axis) and which parameter to tune (what is on the x-axis). " ] }, { "cell_type": "code", "execution_count": null, "id": "7", "metadata": {}, "outputs": [], "source": [ "# creating a 'deep' copy of the base model.\n", "# This is recommended as changes made to this model does not effect the base model. This \n", "# is a good practise as it helps in debugging and stuyding different aspects of your model.\n", "\n", "base2 = base.deepcopy() \n", "\n", "# Adding detectors to the model\n", "base2.parse(\n", "\"\"\" \n", "# photodiodes (DC)\n", "pd b1 ETMX.p2.o \n", "pd b2 ETMY.p2.o\n", "# amplitude detector measuring the amplitude of light at a given frequency\n", "ad b4ad PRM.p1.i f=eom1.f \n", "\"\"\"\n", ")\n", "\n", "# We run the model to test the outputs of the detector for the current configuration\n", "sol = base2.run()\n", "print(f\"Power transmitted through the end mirrors, ETMX: {sol['b1']:.4} W, ETMY: {sol['b2']:.4} W\")\n", "print(f\"Complex amplitude of one RF field component entering the interferometer: {sol['b4ad']:.4}\")" ] }, { "cell_type": "markdown", "id": "8", "metadata": {}, "source": [ "## Actions, Analyses, & Solutions\n", "\n", "In order to do a plot we rely on syntax that we call 'actions'. To change a parameter we use an 'Xaxis' action." ] }, { "cell_type": "code", "execution_count": null, "id": "9", "metadata": {}, "outputs": [], "source": [ "# making a copy of the model with detectors\n", "base3 = base2.deepcopy() \n", "\n", "# scanning the laser power and plotting the output of the detectors\n", "sol1 = base3.run(Xaxis(base3.LI.P, 'lin', 100, 150, 50))\n", "sol1.plot();" ] }, { "cell_type": "markdown", "id": "10", "metadata": {}, "source": [ "As expected, the power and amplitude on all detectors increase proportionally with the laser power. The built-in plot command provides easy access to a basic plot. You can also access the data in the sol1 object to create a customised plot.\n", "\n", "As a second example, we move an end mirror of the Michelson interferometer. The movement (scan) is microscopic — we change what is called the tuning of the mirror, which is specified in degrees, with 360° corresponding to a change in mirror position of one wavelength of light." ] }, { "cell_type": "code", "execution_count": null, "id": "11", "metadata": {}, "outputs": [], "source": [ "# making a copy of the model with detectors\n", "base4 = base2.deepcopy() \n", "\n", "# scanning the microscopic position (phi) of end test mass (ETMX) \n", "sol2 = base4.run(Xaxis(base4.ETMX.phi, 'lin', -200, 200, 400, relative=True))\n", "# only plotting the detector on transmission for ETMX\n", "sol2.plot(\"b1\", logy=True); " ] }, { "cell_type": "markdown", "id": "12", "metadata": {}, "source": [ "In this case, we plot only the data from one photodiode. This shows the change in power in the interferometer, which is determined by a combination of the resonance condition in the so-called power-recycled cavity and the interference condition in the Michelson interferometer. The triple peaks arise because the EOM generates two RF sidebands with a frequency offset from the laser’s input field." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.14.0" } }, "nbformat": 4, "nbformat_minor": 5 }