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 aspace
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')
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()