# EME: TFLN Ring Resonator

A racetrack ring resonator in x-cut thin-film lithium niobate: the through-port spectrum over a few
free spectral ranges, with the free spectral range, extinction and loaded quality factor of each
resonance, and the field around the ring on resonance.

The ring is a straight coupler, where the bus and the ring run side by side, two half-circle
`bend_section`s and a straight back side, closed on itself with `connect_ports`. Windowed ports
give the coupler’s bus and ring arms their own ports, so the ring can be closed while the bus stays
open. `check_layout()` confirms the loop closes before anything is solved.

The crystal is fixed on the chip, so along each bend the guide sees it turn: the extraordinary axis
lies across the guide at the ends of a half circle and along it in the middle. Each bend is sliced
along its heading and every slice is solved in its own frame. The crystal turns in steps from slice
to slice, which costs a little power in each half circle, so the bends are refined more finely than
the default (`overlap_variation=0.003`).

The spectrum comes from `sweep(method='interpolated')`: the circuit is refined once, its
cross-sections are solved at a few wavelengths, and the S-matrix at each of the 2000 wavelengths is
rebuilt from them, so the sweep costs a few solves rather than 2000. The resonance wavelengths agree
with the same refined circuit solved directly to better than 0.001 nm. The depth of a resonance is more
sensitive, since near critical coupling it amplifies small differences in the coupling and the
round-trip loss.

The circuit is then refined and solved directly at the middle resonance, with the wavelength set on
both labeled profiles, and `plot(view='layout')` draws the field of each section where the layout
places it: the light the bus couples in builds up around the ring. Refined at that wavelength, the
circuit’s resonance moves by about 0.02 nm, a quarter of its width, so the ring is close to its peak.

*This code example is licensed under the* [BSD 3-Clause License](../_static/LICENSE.html).

Python

```python
import sys
import numpy as np
import emodeconnection as emc
from emodeconnection import MaterialSpec, Port, Bounds
from matplotlib import pyplot as plt

## Set simulation parameters
wavelength = 1550  # [nm] center wavelength
dx, dy = 50, 50  # [nm] resolution
h_film = 600  # [nm] lithium niobate film thickness
etch = 400  # [nm] ridge etch depth
w_core = 1200  # [nm] ridge width
h_box = 1000  # [nm] buried oxide
window_height = 2600  # [nm]
gap = 300  # [nm] bus to ring gap
radius = 30e3  # [nm] bend radius
coupler_length = 20e3  # [nm] straight coupling length
num_modes = 4  # [-]

## The ring is a racetrack: a straight coupler where the bus and the ring
## run side by side, two half-circle bends and a straight back side. The
## x-cut crystal stays fixed on the chip, so along each bend the guide sees
## it turn, and every slice of a bend is solved in its own frame.
em = emc.EMode(emode_cmd=sys.argv[1:], simulation_name='tfln_ring')

x_cut = MaterialSpec(material='LN_MgO', theta=np.pi / 2)

em.settings(
    wavelength=wavelength, x_resolution=dx, y_resolution=dy,
    window_width=4000, window_height=window_height,
    num_modes=num_modes, boundary_condition='00',
    background_material='Air')

em.shape(name='BOX', material='SiO2', height=h_box)
em.shape(name='core', material=x_cut, height=h_film, etch_depth=etch, mask=w_core)
em.label_profile(name='ring')

## The coupler's cross-section holds both guides, each centered in its own
## half of the window
d = (gap + w_core) / 2  # [nm] each guide's distance from the center
em.settings(window_width=4 * d + 2000, num_modes=2 * num_modes)
em.shape(name='core', mask=[w_core, w_core], mask_offset=[-d, d])
em.label_profile(name='pair')

## A window on each side of the coupler gives the bus and the ring their own
## ports, so the ring can be closed while the bus stays open
window = lambda x: Bounds(window_width=2 * d, window_height=window_height, offset=(x, 0.0))
em.straight_section(
    name='coupler', profile='pair', length=coupler_length,
    ports=[Port(name='bus_in', side='left', window=window(-d)),
           Port(name='ring_in', side='left', window=window(d)),
           Port(name='bus_out', side='right', window=window(-d)),
           Port(name='ring_out', side='right', window=window(d))])

## The bends are refined more finely than the default: the crystal turns in
## steps from slice to slice, and the default slicing loses about 1.6 % of
## the power in each half circle to that staircase
bend_settings = {'overlap_variation': 0.003}
em.bend_section(name='bend_1', profile='ring', radius=radius,
                sweep_angle=np.pi, settings=bend_settings)
em.straight_section(name='back', profile='ring', length=coupler_length)
em.bend_section(name='bend_2', profile='ring', radius=radius,
                sweep_angle=np.pi, settings=bend_settings)

em.connect_ports(pairs=[('coupler.ring_out', 'bend_1.left'),
                        ('bend_1.right', 'back.left'),
                        ('back.right', 'bend_2.left'),
                        ('bend_2.right', 'coupler.ring_in')])

## The loop has to close on itself before anything is solved
report = em.check_layout()
distance, angle = report.max_closure()
print(f'the loop closes to {distance:.1e} nm and {angle:.1e} rad')

em.EME()

## The through-port spectrum over a few free spectral ranges. The circuit is
## refined once, its cross-sections are solved at a few wavelengths, and the
## S-matrix at every wavelength below is rebuilt from them.
wavelengths = np.arange(1546.0, 1556.0, 0.005)  # [nm]
data = em.sweep(key='wavelength', values=wavelengths, result='S_matrix',
                method='interpolated', num_nodes=6,
                wavelength_range=(wavelengths[0], wavelengths[-1]))
T = np.array([np.abs(S.block('coupler.bus_out', 'coupler.bus_in')[0, 0]) ** 2
              for S in data['S_matrix']])

## The resonances, their spacing, depth and loaded quality factor
dips = np.where((T[1:-1] < T[:-2]) & (T[1:-1] < T[2:]) & (T[1:-1] < 0.9))[0] + 1
fsr = np.mean(np.diff(wavelengths[dips]))
print(f'free spectral range: {fsr:.2f} nm')
for k in dips:
    half = (1 + T[k]) / 2
    lo, hi = k, k
    while lo > 0 and T[lo] < half:
        lo -= 1
    while hi < len(T) - 1 and T[hi] < half:
        hi += 1
    width = wavelengths[hi] - wavelengths[lo]
    print(f'resonance at {wavelengths[k]:.3f} nm: extinction {-10 * np.log10(T[k]):.1f} dB, '
          f'loaded Q {wavelengths[k] / width:.0f}')

## The field around the ring on its middle resonance, solved there directly
## and drawn where the layout places each section. The sections are built on
## the labeled profiles, so the wavelength is set on each of them.
resonance = wavelengths[dips[len(dips) // 2]]
for name in ('ring', 'pair'):
    em.settings(profile=name, wavelength=resonance)
em.EME()
em.plot(component='Ex', plot_function='abs', plane='z-x', view='layout',
        file_name='tfln_ring_field', file_type='png')

em.close()

plt.figure(figsize=(7, 3.5))
plt.plot(wavelengths, 10 * np.log10(T))
plt.xlabel('Wavelength (nm)')
plt.ylabel('Through port (dB)')
plt.grid(True, alpha=0.3)
plt.savefig('tfln_ring_spectrum.png', dpi=300, bbox_inches='tight')
```

Console output:

```default
EMode3D 1.0.8 - email
the loop closes to 7.3e-12 nm and 0.0e+00 rad

Solving S-matrices...
Solving section: coupler... completed in 0.0 sec
Solving section: bend_1... completed in 14.8 sec
Solving section: back... completed in 0.0 sec
Solving section: bend_2... completed in 14.3 sec
 completed in 30.0 sec

Solving S-matrices...
Solving section: coupler... completed in 0.0 sec
Solving section: bend_1... completed in 0.7 sec
Solving section: back... completed in 0.0 sec
Solving section: bend_2... completed in 0.7 sec
 completed in 1.8 sec
free spectral range: 4.49 nm
resonance at 1546.565 nm: extinction 1.5 dB, loaded Q 20621
resonance at 1551.045 nm: extinction 1.3 dB, loaded Q 20681
resonance at 1555.550 nm: extinction 1.3 dB, loaded Q 20741

Solving S-matrices...
Solving section: coupler... completed in 0.0 sec
Solving section: bend_1... completed in 15.8 sec
Solving section: back... completed in 0.0 sec
Solving section: bend_2... completed in 15.7 sec
 completed in 32.4 sec
Exited EMode
```

Figures:

![image](examples/Figures/EME_TFLN_Ring/tfln_ring_field.png)![image](examples/Figures/EME_TFLN_Ring/tfln_ring_spectrum.png)
