Noise floor of overlap integrals

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.

Hide 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
Hide 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. 429 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_sM7O8k".
 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/o5Nad/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/o5Nad/src/gl_backend.jl:2
 [18] include(mod::Module, _path::String)
    @ Base ./Base.jl:495
 [19] include(x::String)
    @ GLMakie ~/.julia/packages/GLMakie/o5Nad/src/GLMakie.jl:1
 [20] top-level scope
    @ ~/.julia/packages/GLMakie/o5Nad/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/o5Nad/src/gl_backend.jl:1
in expression starting at /home/runner/.julia/packages/GLMakie/o5Nad/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
Hide 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)