Phase configuration settings

Warning

For physically correct results use the phase 0 or phase 2 options, which can be set with model.phase_config(zero_k00=False, zero_tem00_gouy=False) and model.phase_config(zero_k00=False, zero_tem00_gouy=True) respectively.

Note

Since version 3.0a28 the default phase setting is now model.phase_config(zero_k00=False, zero_tem00_gouy=True).

The finesse.model.Model.phase_config() method can be used to switch on/off some simplifications when dealing with the phase of the light field. This is to aid in simulating systems more easily.

In previous versions of Finesse this was done using the phase command. It was a bitflag setting that switched two options for running simple simulations quickly without having to set up a sensing and control scheme - which was laborious in previous versions of Finesse. With the new actions available in Finesse 3 you can more easily put optical systems at sensible operating points, therefore these phase options are less useful as models are not tuned by hand to be at a particular operating point.

These options were referred to in previous versions of Finesse as:

  • phase 0: No simplification. This means for example that the Gouy phase of a TEM00 is not zero and thus a space of arbitrary length is in general not resonant to the carrier field.

  • phase 1: The phase of coupling coefficients is shifted such that the phase of k00 is 0. The phases of all coupling coefficients knm for one field coupling, for example a reflection at one side of a mirror, are changed by the same amount. To some effect that resembles the movement of the optical surface. However, since this is independently applied to all coupling coefficients of the surface (i.e. two reflections and two transmissions), this does not describe a physically realistic situation. In fact, it might invalidate energy conservation or produce other weird effects.

  • phase 2: The phase accumulated in a space component is adjusted such that the phase of TEM00 is 0 (irrespective of the value of the Gouy phase). Effectively the “macroscopic length” of a space is no longer an integer multiple of the wavelength.

  • phase 3: Both of the above (phase 1 and phase 2)

In Finesse 3 these are now set using the finesse.model.Model.phase_config() method, accepting keyword arguments which are easier to remember than the bitflag input:

  • phase 3 == zero_k00=True, zero_tem00_gouy=True

  • phase 2 == zero_k00=False, zero_tem00_gouy=True

  • phase 1 == zero_k00=True, zero_tem00_gouy=False

  • phase 0 == zero_k00=False, zero_tem00_gouy=False

Users performing complex simulations should ensure they only use zero_k00=False. However, this will mean that values used to tune optic positions for common operating points will differ from what one would expect naively. For example, resonating a Fabry-Perot cavity for HG00 with phase 3 will use mirrors with phi=0, however this is likely not the case with phase 2 or phase 0 where it becomes necessary to always ensure you use some locking routine or optimiser to find the correct operating point.

Removing the TEM00 Gouy phase: phase 2

Removing the Gouy phase using the zero_tem00_gouy=True does not have a detrimental effect on the accuracy of the simulations. Using this flag will ensure that the HG00 mode, when propagating along a space, will accumulate no Gouy phase. Physically this is like every space is tuned microscopically to remove the Gouy phase. The following example shows how the resonance condition of a cavity is shifted when the Gouy phase is not zeroed.

import finesse
import matplotlib.pyplot as plt

finesse.init_plotting()

model = finesse.script.parse(
    """
    laser l1
    m m1 R=0.99 T=0.01 Rc=100
    m m2 R=0.99 T=0.01 Rc=100
    link(l1, m1.p2, m1.p1, 80, m2.p1)
    cav cavity m1.p1.o
    pd CIRC m1.p1.o
    modes(even, maxtem=10)
    """
)

model.beam_trace()

q_mismatch = finesse.BeamParam.overlap_contour(model.l1.p1.o.q, 0.1, 0)
model.l1.p1.o.q = q_mismatch

action = 'xaxis(m2.phi, lin, -180, 180, 1000, True, name="xaxis")'

labels = [f"phase {i}" for i in range(4)]
lss = ["-", "--", "-", "--"]
model.phase_config(zero_k00=False, zero_tem00_gouy=False)
out0 = model.run(action)
model.phase_config(zero_k00=True, zero_tem00_gouy=False)
out1 = model.run(action)
model.phase_config(zero_k00=False, zero_tem00_gouy=True)
out2 = model.run(action)
model.phase_config(zero_k00=True, zero_tem00_gouy=True)
out3 = model.run(action)


for out, lbl, ls in zip([out0, out1, out2, out3], labels, lss):
    plt.semilogy(out.x[0], out["CIRC"], ls=ls, label=lbl)

plt.legend()
plt.xlabel("End mirror tuning [deg]")
plt.ylabel("Power [W]")
plt.title("Circulating power vs phase configuration")
Text(0.5, 1.0, 'Circulating power vs phase configuration')
../../_images/phase_configurations_0_1.svg

Example of errors zeroing scattering matrix TEM00 coupling: phase 1

Below is an example where using zero_k00=True causes an unwanted error in the calculations. The example is a mode mismatched Fabry-Perot cavity. It demonstrates how using zero_k00=True returns an incorrect reflected field and total power in the simulation is no longer conserved. The pseudo_lock_cavity action is used to easily find the correct operating point in each case to compare the scenarios fairly.

model = finesse.script.parse(
    """
    laser l1
    m m1 R=0.99 T=0.01 Rc=100
    m m2 R=0.99 T=0.01 Rc=100
    link(l1, m1.p2, m1.p1, 80, m2.p1)
    cav cavity m1.p1.o
    pd REFL m1.p2.o
    pd CIRC m1.p1.o
    pd TRAN m2.p2.o
    modes(even, maxtem=10)
    """
)

model.beam_trace()

q_mismatch = finesse.BeamParam.overlap_contour(model.l1.p1.o.q, 0.1, 0)
model.l1.p1.o.q = q_mismatch

action = 'series(pseudo_lock_cavity(cavity), xaxis(m2.phi, lin, -2, 2, 100, True, name="xaxis"))'

labels = [f"phase {i}" for i in range(4)]
lss = ["-", "-", "--", "--"]
model.phase_config(zero_k00=False, zero_tem00_gouy=False)
out0 = model.run(action)
model.phase_config(zero_k00=True, zero_tem00_gouy=False)
out1 = model.run(action)
model.phase_config(zero_k00=False, zero_tem00_gouy=True)
out2 = model.run(action)
model.phase_config(zero_k00=True, zero_tem00_gouy=True)
out3 = model.run(action)


fig, axs = plt.subplots(4, 1, sharex=True, figsize=(6, 8))
for out, lbl, ls in zip([out0, out1, out2, out3], labels, lss):
    plt.sca(axs[0])
    plt.plot(out["xaxis"].x[0], out["xaxis"]["REFL"], label=lbl, ls=ls)
    plt.sca(axs[1])
    plt.plot(out["xaxis"].x[0], out["xaxis"]["CIRC"], ls=ls)
    plt.sca(axs[2])
    plt.plot(out["xaxis"].x[0], out["xaxis"]["TRAN"], ls=ls)
    plt.sca(axs[3])
    total = out["xaxis"]["REFL"] + out["xaxis"]["TRAN"]
    plt.plot(out["xaxis"].x[0], total, ls=ls)


plt.sca(axs[0])
plt.legend()
plt.title("Reflected")
plt.ylabel("Power [W]")
plt.sca(axs[1])
plt.title("Circulating")
plt.ylabel("Power [W]")
plt.sca(axs[2])
plt.title("Transmitted")
plt.ylabel("Power [W]")
plt.sca(axs[3])
plt.title("REFL + TRANS")
plt.ylabel("Power [W]")
plt.xlabel("End mirror tuning [deg]")
plt.tight_layout()
../../_images/phase_configurations_1_0.svg