Noise floor of overlap integrals#
The overlap integral between neighboring waveguides is one way to determine the coupling between neighboring waveguides. As the modes decay exponentially outside the core after a certain distance, the overlap integral also decays in good approximation exponentially. In order to see how good the estimation of the overlap integral is and to see at which distance the coupling is too weak to be estimated precisely using this methodology, we calculate the coupling as a function of the distance in the following.
For this example we chose two silicon nitride waveguides with a width of 1μm and a thickness of 0.3μm. Those waveguides are ontop of a silicon dioxide layer and air-clad.
Show code cell source
using PyCall
all_distances = 1:1.0:30
distances = Float64[]
overlaps = Float64[]
mode_1 = nothing
mode_2 = nothing
Ω = nothing
for distance in all_distances
println(distance)
py"""
import numpy as np
import shapely
import shapely.geometry
import shapely.affinity
from shapely.ops import clip_by_rect, unary_union
from collections import OrderedDict
from femwell.mesh import mesh_from_OrderedDict
distance = $distance
wg_width = 1
wg_thickness = 0.3
core = shapely.geometry.box(-wg_width / 2, 0, +wg_width / 2, wg_thickness)
core1 = shapely.affinity.translate(core, xoff=distance/2)
core2 = shapely.affinity.translate(core, xoff=-distance/2)
env = unary_union([core1, core2]).buffer(max(5,distance), quad_segs = 2)
polygons = OrderedDict(
core1=core1,
core2=core2,
box = clip_by_rect(env, -np.inf, -np.inf, np.inf, 0),
clad = clip_by_rect(env, -np.inf, 0, np.inf, np.inf),
)
resolutions = {f"core{i}": {"resolution": 0.05, "distance": 1} for i in [1,2]}
mesh = mesh_from_OrderedDict(
polygons,
resolutions,
default_resolution_max = 1,
filename = "mesh.msh"
)
"""
using Gridap
using Gridap.Geometry
using Gridap.Visualization
using Gridap.ReferenceFEs
using GridapGmsh
using GridapMakie, CairoMakie
using Femwell.Maxwell.Waveguide
order = 1
CairoMakie.inline!(true)
model = GmshDiscreteModel("mesh.msh")
Ω = Triangulation(model)
labels = get_face_labeling(model)
τ = CellField(get_face_tag(labels, num_cell_dims(model)), Ω)
fig = plot(Ω)
fig.axis.aspect = DataAspect()
wireframe!(Ω, color = :black, linewidth = 1)
display(fig)
epsilons = ["core1" => 1.9963^2, "core2" => 1.444^2, "box" => 1.444^2, "clad" => 1.0^2]
ε(tag) = Dict(get_tag_from_name(labels, u) => v for (u, v) in epsilons)[tag]
@time modes_1 = calculate_modes(model, ε ∘ τ, λ = 1.55, num = 1, order = order)
println(n_eff(modes_1[1]))
if length(distances) == 0
push!(distances, 0)
push!(overlaps, overlap(modes_1[1], modes_1[1]))
end
epsilons = ["core1" => 1.444^2, "core2" => 1.9963^2, "box" => 1.444^2, "clad" => 1.0^2]
ε(tag) = Dict(get_tag_from_name(labels, u) => v for (u, v) in epsilons)[tag]
modes_2 = calculate_modes(model, ε ∘ τ, λ = 1.55, num = 1, order = order)
println(n_eff(modes_2[1]))
overlap_integral = overlap(modes_1[1], modes_2[1])
println(overlap_integral)
push!(distances, distance)
push!(overlaps, abs(overlap_integral))
if distance == last(all_distances)
plot_mode(modes_1[1])
plot_mode(modes_2[1])
end
end
Show code cell output
1.0
WARNING: Method definition (::Main.var"#ε#3"{labels})(Any) in module Main at In[1]:70 overwritten at In[1]:80.
Precompiling
Femwell
? GridapODEs
✗ GLMakie
Info Given Femwell was explicitly requested, output will be shown live
WARNING: Method definition evaluate(Gridap.FESpaces.TrialFESpace{S} where S, Nothing) in module TransientFETools at /home/runner/.julia/packages/Gridap/dKMpW/src/ODEs/TransientFETools/TransientFESpaces.jl:56 overwritten in module TransientFETools at /home/runner/.julia/packages/GridapODEs/puj9L/src/TransientFETools/TransientFESpaces.jl:56.
ERROR: Method overwriting is not permitted during Module precompilation. Use `__precompile__(false)` to opt-out of precompilation.
? Femwell
0 dependencies successfully precompiled in 18 seconds. 435 already precompiled.
2 dependencies failed but may be precompilable after restarting julia
2 dependencies had output during precompilation:
┌ Femwell
│ [Output was shown above]
└
┌ GridapODEs
│ WARNING: Method definition evaluate(Gridap.FESpaces.TrialFESpace{S} where S, Nothing) in module TransientFETools at /home/runner/.julia/packages/Gridap/dKMpW/src/ODEs/TransientFETools/TransientFESpaces.jl:56 overwritten in module TransientFETools at /home/runner/.julia/packages/GridapODEs/puj9L/src/TransientFETools/TransientFESpaces.jl:56.
│ ERROR: Method overwriting is not permitted during Module precompilation. Use `__precompile__(false)` to opt-out of precompilation.
└
The following 1 direct dependency failed to precompile:
GLMakie [e9467ef8-e4e7-5192-8a1a-b1aee30e663a]
Failed to precompile GLMakie [e9467ef8-e4e7-5192-8a1a-b1aee30e663a] to "/home/runner/.julia/compiled/v1.10/GLMakie/jl_KGUeBe".
┌ Warning: OpenGL/GLFW wasn't loaded correctly or couldn't be initialized.
│ This likely means, you're on a headless server without having OpenGL support setup correctly.
│ Have a look at the troubleshooting section in the readme:
│ https://github.com/MakieOrg/Makie.jl/tree/master/GLMakie#troubleshooting-opengl.
└ @ GLMakie ~/.julia/packages/GLMakie/TH3rf/src/gl_backend.jl:4
ERROR: LoadError: InitError: Exception[GLFW.GLFWError(65550, "X11: The DISPLAY environment variable is missing"), ErrorException("glfwInit failed")]
Stacktrace:
[1] __init__()
@ GLFW ~/.julia/packages/GLFW/wmoTL/src/GLFW.jl:35
[2] run_module_init(mod::Module, i::Int64)
@ Base ./loading.jl:1134
[3] register_restored_modules(sv::Core.SimpleVector, pkg::Base.PkgId, path::String)
@ Base ./loading.jl:1122
[4] _include_from_serialized(pkg::Base.PkgId, path::String, ocachepath::String, depmods::Vector{Any})
@ Base ./loading.jl:1067
[5] _require_search_from_serialized(pkg::Base.PkgId, sourcepath::String, build_id::UInt128)
@ Base ./loading.jl:1581
[6] _require(pkg::Base.PkgId, env::String)
@ Base ./loading.jl:1938
[7] __require_prelocked(uuidkey::Base.PkgId, env::String)
@ Base ./loading.jl:1812
[8] #invoke_in_world#3
@ ./essentials.jl:926 [inlined]
[9] invoke_in_world
@ ./essentials.jl:923 [inlined]
[10] _require_prelocked(uuidkey::Base.PkgId, env::String)
@ Base ./loading.jl:1803
[11] macro expansion
@ ./loading.jl:1790 [inlined]
[12] macro expansion
@ ./lock.jl:267 [inlined]
[13] __require(into::Module, mod::Symbol)
@ Base ./loading.jl:1753
[14] #invoke_in_world#3
@ ./essentials.jl:926 [inlined]
[15] invoke_in_world
@ ./essentials.jl:923 [inlined]
[16] require(into::Module, mod::Symbol)
@ Base ./loading.jl:1746
[17] top-level scope
@ ~/.julia/packages/GLMakie/TH3rf/src/gl_backend.jl:2
[18] include(mod::Module, _path::String)
@ Base ./Base.jl:495
[19] include(x::String)
@ GLMakie ~/.julia/packages/GLMakie/TH3rf/src/GLMakie.jl:1
[20] top-level scope
@ ~/.julia/packages/GLMakie/TH3rf/src/GLMakie.jl:87
[21] include
@ ./Base.jl:495 [inlined]
[22] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt128}}, source::Nothing)
@ Base ./loading.jl:2222
[23] top-level scope
@ stdin:3
during initialization of module GLFW
in expression starting at /home/runner/.julia/packages/GLMakie/TH3rf/src/gl_backend.jl:1
in expression starting at /home/runner/.julia/packages/GLMakie/TH3rf/src/GLMakie.jl:1
in expression starting at stdin:
Stacktrace:
[1] pkgerror(msg::String)
@ Pkg.Types /opt/hostedtoolcache/julia/1.10.3/x64/share/julia/stdlib/v1.10/Pkg/src/Types.jl:70
[2] precompile(ctx::Pkg.Types.Context, pkgs::Vector{Pkg.Types.PackageSpec}; internal_call::Bool, strict::Bool, warn_loaded::Bool, already_instantiated::Bool, timing::Bool, _from_loading::Bool, kwargs::@Kwargs{io::IJulia.IJuliaStdio{Base.PipeEndpoint}})
@ Pkg.API /opt/hostedtoolcache/julia/1.10.3/x64/share/julia/stdlib/v1.10/Pkg/src/API.jl:1659
[3] precompile(pkgs::Vector{Pkg.Types.PackageSpec}; io::IJulia.IJuliaStdio{Base.PipeEndpoint}, kwargs::@Kwargs{_from_loading::Bool})
@ Pkg.API /opt/hostedtoolcache/julia/1.10.3/x64/share/julia/stdlib/v1.10/Pkg/src/API.jl:159
[4] precompile
@ /opt/hostedtoolcache/julia/1.10.3/x64/share/julia/stdlib/v1.10/Pkg/src/API.jl:147 [inlined]
[5] #precompile#114
@ /opt/hostedtoolcache/julia/1.10.3/x64/share/julia/stdlib/v1.10/Pkg/src/API.jl:146 [inlined]
[6] #invokelatest#2
@ ./essentials.jl:894 [inlined]
[7] invokelatest
@ ./essentials.jl:889 [inlined]
[8] _require(pkg::Base.PkgId, env::String)
@ Base ./loading.jl:1963
[9] __require_prelocked(uuidkey::Base.PkgId, env::String)
@ Base ./loading.jl:1812
[10] #invoke_in_world#3
@ ./essentials.jl:926 [inlined]
[11] invoke_in_world
@ ./essentials.jl:923 [inlined]
[12] _require_prelocked(uuidkey::Base.PkgId, env::String)
@ Base ./loading.jl:1803
[13] macro expansion
@ ./loading.jl:1790 [inlined]
[14] macro expansion
@ ./lock.jl:267 [inlined]
[15] __require(into::Module, mod::Symbol)
@ Base ./loading.jl:1753
[16] #invoke_in_world#3
@ ./essentials.jl:926 [inlined]
[17] invoke_in_world
@ ./essentials.jl:923 [inlined]
[18] require(into::Module, mod::Symbol)
@ Base ./loading.jl:1746
[19] top-level scope
@ ./In[1]:53
Show code cell source
f = Figure()
ax = Axis(
f[1, 1],
title = "Overlap integral between neighboring waveguides",
xlabel = "Distance / μm",
ylabel = "Overlap integral / dB",
)
lines!(ax, distances, 10 * log10.(overlaps))
plot!(ax, distances, 10 * log10.(overlaps))
display(f)