|
|
import numpy as np |
|
|
import matplotlib |
|
|
matplotlib.use("Agg") |
|
|
|
|
|
import matplotlib.pyplot as plt |
|
|
import tempfile |
|
|
|
|
|
import gradio as gr |
|
|
|
|
|
from bpm.refractive_index import ( |
|
|
generate_waveguide_n_r2, |
|
|
generate_MMI_n_r2 |
|
|
) |
|
|
from bpm.mode_solver import slab_mode_source |
|
|
from bpm.core import run_bpm |
|
|
from bpm.pml import generate_sigma_x |
|
|
|
|
|
def run_waveguide(w, l, L_bend, n_WG, wavelength, ind_m): |
|
|
|
|
|
domain_size = 50.0 |
|
|
z_total = 500.0 |
|
|
Nx, Nz = 256, 2000 |
|
|
|
|
|
x = np.linspace(-domain_size/2, domain_size/2, Nx) |
|
|
z = np.linspace(0, z_total, Nz) |
|
|
n0 = 1.0 |
|
|
|
|
|
|
|
|
n_r2 = generate_waveguide_n_r2(x, z, l, L_bend, w, n_WG, n0) |
|
|
|
|
|
|
|
|
E0 = slab_mode_source(x, w, n_WG, n0, wavelength, ind_m, x0=0) |
|
|
E = np.zeros((Nx, Nz), dtype=np.complex128) |
|
|
E[:, 0] = E0 |
|
|
|
|
|
|
|
|
dx = domain_size / Nx |
|
|
dz = z[1] - z[0] |
|
|
sigma_x = generate_sigma_x(x, dx, wavelength, domain_size) |
|
|
E_out = run_bpm(E, n_r2, x, z, dx, dz, n0, sigma_x, wavelength) |
|
|
|
|
|
|
|
|
fig, ax = plt.subplots(figsize=(8,6)) |
|
|
im = ax.imshow( |
|
|
np.abs(E_out)**2, |
|
|
extent=[x[0], x[-1], z[0], z[-1]], |
|
|
origin='lower', |
|
|
aspect='auto', |
|
|
cmap='inferno' |
|
|
) |
|
|
ax.set_title("Waveguide S-bend BPM Propagation") |
|
|
ax.set_xlabel("x (µm)") |
|
|
ax.set_ylabel("z (µm)") |
|
|
fig.colorbar(im, ax=ax, label="Intensity") |
|
|
|
|
|
|
|
|
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".npz") |
|
|
np.savez(tmp.name, E_out=E_out, x=x, z=z) |
|
|
tmp.close() |
|
|
|
|
|
return fig, tmp.name |
|
|
|
|
|
def run_mmi(z_start, L_MMI, w_MMI, w_wg, d, n_WG, wavelength, ind_m): |
|
|
|
|
|
domain_size = 50.0 |
|
|
z_total = 250.0 |
|
|
Nx, Nz = 256, 1024 |
|
|
|
|
|
x = np.linspace(-domain_size/2, domain_size/2, Nx) |
|
|
z = np.linspace(0, z_total, Nz) |
|
|
n0 = 1.0 |
|
|
|
|
|
|
|
|
n_MMI = n_WG |
|
|
|
|
|
|
|
|
n_r2 = generate_MMI_n_r2( |
|
|
x, z, |
|
|
z_MMI_start = z_start, |
|
|
L_MMI = L_MMI, |
|
|
w_MMI = w_MMI, |
|
|
w_wg = w_wg, |
|
|
d = d, |
|
|
n_WG = n_WG, |
|
|
n_MMI = n_MMI, |
|
|
n0 = n0 |
|
|
) |
|
|
|
|
|
|
|
|
E0 = slab_mode_source(x, w_wg, n_WG, n0, wavelength, ind_m, x0=-d/2) |
|
|
E = np.zeros((Nx, Nz), dtype=np.complex128) |
|
|
E[:,0] = E0 |
|
|
|
|
|
|
|
|
dx = domain_size / Nx |
|
|
dz = z[1] - z[0] |
|
|
sigma_x = generate_sigma_x(x, dx, wavelength, domain_size) |
|
|
E_out = run_bpm(E, n_r2, x, z, dx, dz, n0, sigma_x, wavelength) |
|
|
|
|
|
|
|
|
fig, ax = plt.subplots(figsize=(8,6)) |
|
|
im = ax.imshow( |
|
|
np.abs(E_out)**2, |
|
|
extent=[x[0], x[-1], z[0], z[-1]], |
|
|
origin='lower', |
|
|
aspect='auto', |
|
|
cmap='inferno' |
|
|
) |
|
|
ax.set_title("MMI Splitter BPM Propagation") |
|
|
ax.set_xlabel("x (µm)") |
|
|
ax.set_ylabel("z (µm)") |
|
|
fig.colorbar(im, ax=ax, label="Intensity") |
|
|
|
|
|
|
|
|
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".npz") |
|
|
np.savez(tmp.name, E_out=E_out, x=x, z=z) |
|
|
tmp.close() |
|
|
|
|
|
return fig, tmp.name |
|
|
|
|
|
def run_dispatcher( |
|
|
sim_type, |
|
|
|
|
|
w, l, L_bend, |
|
|
|
|
|
z_start, L_MMI, w_MMI, w_wg, d, |
|
|
|
|
|
n_WG, wavelength, ind_m |
|
|
): |
|
|
if sim_type == "Waveguide S-bend": |
|
|
return run_waveguide(w, l, L_bend, n_WG, wavelength, ind_m) |
|
|
else: |
|
|
return run_mmi(z_start, L_MMI, w_MMI, w_wg, d, n_WG, wavelength, ind_m) |
|
|
|
|
|
with gr.Blocks() as demo: |
|
|
gr.Markdown("## BPM Simulation Dashboard") |
|
|
|
|
|
|
|
|
sim_type = gr.Radio( |
|
|
choices=["Waveguide S-bend", "MMI Splitter"], |
|
|
value="Waveguide S-bend", |
|
|
label="Simulation Type" |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
|
|
|
with gr.Column(visible=True) as waveguide_panel: |
|
|
w_slider = gr.Slider(0.1, 5.0, value=1.0, step=0.1, label="Waveguide width w (µm)") |
|
|
l_slider = gr.Slider(0.0, 10.0, value=5.0, step=0.1, label="Lateral offset l (µm)") |
|
|
Lb_slider = gr.Slider(50.0, 500.0,value=200.0,step=10.0,label="S-bend length L (µm)") |
|
|
|
|
|
|
|
|
with gr.Column(visible=False) as mmi_panel: |
|
|
z0_slider = gr.Slider(0.0, 200.0, value=50.0, step=1.0, label="MMI start z₀ (µm)") |
|
|
Lmmi_slider = gr.Slider(10.0, 300.0,value=130.0,step=5.0, label="MMI length L (µm)") |
|
|
wmmi_slider = gr.Slider(2.0, 20.0, value=8.0, step=0.5, label="MMI width w_MMI (µm)") |
|
|
wwg_slider = gr.Slider(0.5, 5.0, value=2.0, step=0.1, label="I/O waveguide width w_wg (µm)") |
|
|
d_slider = gr.Slider(1.0, 20.0, value=4.0, step=0.5, label="Waveguide separation d (µm)") |
|
|
|
|
|
|
|
|
with gr.Column(scale=1): |
|
|
n_WG_slider = gr.Slider(1.0, 2.0, value=1.1, step=0.01, label="Core refractive index n_WG") |
|
|
wavelength_slider= gr.Slider(0.4, 1.6, value=0.532,step=0.01, label="Wavelength λ (µm)") |
|
|
ind_m_slider = gr.Slider(0, 4, value=0, step=1, label="Mode index ind_m") |
|
|
|
|
|
run_button = gr.Button("Run BPM") |
|
|
download_button = gr.DownloadButton(label="Download data") |
|
|
|
|
|
|
|
|
with gr.Column(scale=2): |
|
|
plot_output = gr.Plot() |
|
|
|
|
|
|
|
|
sim_type.change( |
|
|
fn=lambda choice: ( |
|
|
gr.update(visible=(choice=="Waveguide S-bend")), |
|
|
gr.update(visible=(choice=="MMI Splitter")) |
|
|
), |
|
|
inputs=sim_type, |
|
|
outputs=[waveguide_panel, mmi_panel] |
|
|
) |
|
|
|
|
|
|
|
|
all_inputs = [ |
|
|
sim_type, |
|
|
w_slider, l_slider, Lb_slider, |
|
|
z0_slider, Lmmi_slider, wmmi_slider, wwg_slider, d_slider, |
|
|
n_WG_slider, wavelength_slider, ind_m_slider |
|
|
] |
|
|
run_button.click( |
|
|
fn=run_dispatcher, |
|
|
inputs=all_inputs, |
|
|
outputs=[plot_output, download_button] |
|
|
) |
|
|
for inp in all_inputs: |
|
|
inp.change( |
|
|
fn=run_dispatcher, |
|
|
inputs=all_inputs, |
|
|
outputs=[plot_output, download_button] |
|
|
) |
|
|
|
|
|
demo.launch() |
|
|
|