Repository files navigation

modesolverpy

Photonic mode solver with a nice interface and output.

The documentation for this project can be found here.

Installation

It is recommend to install modesolverpy either via:

Ubuntu/Mint/Debian:

pip3 install modesolverpy
apt install gnuplot

Arch Linux:

yaourt -S python-modesolverpy

Dependencies

If installing using the Arch Linux AUR package or pip, dependencies will be automatically downloaded and installed, if not, one should ensure the following dependencies are installed:

Either Gnuplot or Matplotlib can be used for plotting; I am a Gnuplot user to the code was written with it in mind. If both Gnuplot and Matplotlib are installed, the code will default to Gnuplot.

Plotting

EITHER:

OR:

Features

The main reasons to consider this library include:

  • semi-vectorial and fully vectorial options,
  • simple structure drawing,
  • automated data saving and plotting via Gnuplot,
  • some limited (at this stage) data processing (finding MFD of fundamental mode), and
  • easily extensible library.

Example 1: Semi-vectorial mode solving of a ridge waveguide

The following example finds the first two modes of a waveguide with the following, arbitrary, parameters:

  • thin-film thickness: 500nm
  • waveguide height: 400nm,
  • waveguide width: 500nm,
  • refractive index of waveguide: 3,
  • refractive index of substrate: 1.4,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportnumpyasnp# All units are relative. [um] were chosen in this case.x_step=0.02y_step=0.02wg_height=0.4wg_width=0.5sub_height=0.5sub_width=2.clad_height=0.5n_sub=1.4n_wg=3.n_clad=1.film_thickness=0.5wavelength=1.55angle=75.structure=st.RidgeWaveguide(wavelength,
x_step,
y_step,
wg_height,
wg_width,
sub_height,
sub_width,
clad_height,
n_sub,
n_wg,
angle,
n_clad,
film_thickness)
structure.write_to_file('example_structure_1.dat')
mode_solver=ms.ModeSolverSemiVectorial(2, semi_vectorial_method='Ey')
mode_solver.solve(structure)
mode_solver.write_modes_to_file('example_modes_1.dat')

Structure

Modes

Example 2: Fully vectorial mode solving of anisotropic material

The following looks at a contrived ridge waveguide in Z-cut KTP.

The simulation outputs:

  • 5 plots for each refractive index axis (n_xx, n_xy, n_yx, n_yy and n_zz),
  • 48 plots for Ex, Ey, Ez, Hx, Hy and Hz,
  • 8 effective index values, one for each mode,
  • a wavelength sweep of the waveguide (plotting n_eff vs wavelength for each mode),
  • whether a mode is qTE or qTM and the percentage overlap with TE and TM, and
  • the group velocity of the mode.

The waveguide parameters are:

  • thin-film thickness: 1.2um,
  • waveguide height: 800nm,
  • waveguide width: 1.2um,
  • refractive index of waveguide: used Sellmeier equations to get n_xx, n_yy, n_zz at 1550nm,
  • refractive index of substrate: used Sellmeier equation to get SiO2 at 1550nm,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.06y_step=0.06wg_height=0.8wg_width=1.8sub_height=1.0sub_width=4.clad_height=1.0film_thickness=1.2angle=60.defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, wg_height, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, angle, n_clad, film_thickness)
n_sub=mat.SiO2().n(wl)
n_wg_xx=mat.Ktp('x').n(wl)
n_wg_yy=mat.Ktp('y').n(wl)
n_wg_zz=mat.Ktp('z').n(wl)
n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
struct_ani.write_to_file()
solver=ms.ModeSolverFullyVectorial(8)
solver.solve(struct_ani)
solver.write_modes_to_file()
solver.solve_ng(struct_ani, 1.55, 0.01)
solver.solve_sweep_wavelength(struct_ani, np.linspace(1.501, 1.60, 21))

Group Velocity

The group velocity at 1550nm for each mode is:

# modes_full_vec/ng.dat
# Mode idx, Group index
0,1.776
1,1.799
2,1.826
3,1.847
4,1.841
5,1.882
6,1.872
7,1.871

Structure

Modes

Only the first 4 (out of 8) modes are shown, and only the E-fields are shown (not H-fields). For the rest of the images, look in the example folder or run the script.

A_{x,y,z} give the percentage power of that particular E-field component with respect to the total of all components.

Mode types:

# modes_full_vec/mode_info
# Mode idx, Mode type, % in major direction, n_eff
0,qTE,97.39,1.643
1,qTM,92.54,1.640
2,qTE,90.60,1.576
3,qTM,91.41,1.571
4,qTE,89.48,1.497
5,qTM,86.70,1.475
6,qTE,89.47,1.447
7,qTM,68.35,1.437

Wavelength Sweep

Example 3: Grating-coupler period

Analytic calculation of the grating coupler period for various duty-cycles in SOI.

Seems to match well with the periods in Taillaert et al., Grating Couplers for Coupling between Optical Fibers and Nanophotonic Waveguides, IOP Science, 2006.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpwls= [1.5, 1.55, 1.6]
x_step=0.05y_step=0.05etch_depth=0.07wg_width=10sub_height=0.5sub_width=14.clad_height=0.5film_thickness=0.22polarisation='TE'dcs=np.linspace(20, 80, 61) /100ed1=etch_depthft1=film_thicknessed2=ft1-ed1ft2=ed2periods= []
periods.append(dcs)
forwlinwls:
ngc= []
fored, ftin [(ed1, ft1), (ed2, ft2)]:
defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, ed, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, ft)
n_sub=mat.SiO2().n(wl)
n_wg_xx=3.46n_wg_yy=3.46n_wg_zz=3.46n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
#struct_ani.write_to_file()solver=ms.ModeSolverFullyVectorial(4)
solver.solve(struct_ani)
#solver.write_modes_to_file()ifpolarisation=='TE':
ngc.append(np.round(np.real(solver.n_effs_te), 4)[0])
elifpolarisation=='TM':
ngc.append(np.round(np.real(solver.n_effs_tm), 4)[0])
period=de.grating_coupler_period(wl, dcs*ngc[0]+(1-dcs)*ngc[1], n_clad, 8, 1)
periods.append(period)
filename='dc-sweep-%s-%inm-etch-%i-film.dat'% (polarisation, etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.array(periods).T, delimiter=',', header=','.join([str(val) forvalinwls]))
print(np.c_[periods])

Example 4: Mode Hybridisation In SOI

Simulation of mode hybridisation in 220nm thick fully-etched SOI ridge waveguides.

Results look the same as those found in Daoxin Dai and Ming Zhang, "Mode hybridization and conversion in silicon-on-insulator nanowires with angled sidewalls," Opt. Express 23, 32452-32464 (2015).

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.02y_step=0.02etch_depth=0.22wg_widths=np.arange(0.3, 2., 0.05)
sub_height=1.sub_width=4.clad_height=1.film_thickness=0.22n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476r= []
forwinwg_widths:
r.append(st.RidgeWaveguide(wl, x_step, y_step, etch_depth, w,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, film_thickness))
solver=ms.ModeSolverFullyVectorial(6)
solver.solve_sweep_structure(r, wg_widths)
solver.write_modes_to_file()

Example 5: Directional Coupler 3dB Length In SOI

Analytic calculation of 3dB coupling length into two parallel SOI waveguides with a varying gap at 3 different TE wavelengths.

An example refractive index profile for the two waveguides spaced 200nm is shown.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpimporttqdmwls= [1.5, 1.55, 1.6]
x_step=0.02y_step=0.02etch_depth=0.22wg_width=0.44sub_height=0.5sub_width=2.clad_height=0.5film_thickness=0.22gaps=np.linspace(0.1, 0.5, 11)
forwlinwls:
lengths= []
n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476forgapintqdm.tqdm(gaps):
r=st.WgArray(wl, x_step, y_step, etch_depth, [wg_width, wg_width], gap,
sub_height, sub_width, clad_height, n_sub, n_wg, None)
#r.write_to_file()solver=ms.ModeSolverFullyVectorial(2)
solver.solve(r)
n1=solver.n_effs_te[0]
n2=solver.n_effs_te[1]
lengths.append(de.directional_coupler_lc(wl*1000, n1, n2)/2)
filename='dc-sweep-%inm-%s-%inm-etch-%i-film.dat'% (wl*1000, 'TE', etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.c_[gaps, lengths], delimiter=',', header='Coupling lengths (50\%)')

Contributions

If you add functionality, please send me a pull request.

Acknowledgments

This finite difference mode solver is based on a modified version of EMpy.

Thank you to Inna Krasnokutska for testing.

About

Photonic mode solver with a simple interface.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

modesolverpy

Photonic mode solver with a nice interface and output.

The documentation for this project can be found here.

Installation

It is recommend to install modesolverpy either via:

Ubuntu/Mint/Debian:

pip3 install modesolverpy
apt install gnuplot

Arch Linux:

yaourt -S python-modesolverpy

Dependencies

If installing using the Arch Linux AUR package or pip, dependencies will be automatically downloaded and installed, if not, one should ensure the following dependencies are installed:

Either Gnuplot or Matplotlib can be used for plotting; I am a Gnuplot user to the code was written with it in mind. If both Gnuplot and Matplotlib are installed, the code will default to Gnuplot.

Plotting

EITHER:

OR:

Features

The main reasons to consider this library include:

  • semi-vectorial and fully vectorial options,
  • simple structure drawing,
  • automated data saving and plotting via Gnuplot,
  • some limited (at this stage) data processing (finding MFD of fundamental mode), and
  • easily extensible library.

Example 1: Semi-vectorial mode solving of a ridge waveguide

The following example finds the first two modes of a waveguide with the following, arbitrary, parameters:

  • thin-film thickness: 500nm
  • waveguide height: 400nm,
  • waveguide width: 500nm,
  • refractive index of waveguide: 3,
  • refractive index of substrate: 1.4,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportnumpyasnp# All units are relative. [um] were chosen in this case.x_step=0.02y_step=0.02wg_height=0.4wg_width=0.5sub_height=0.5sub_width=2.clad_height=0.5n_sub=1.4n_wg=3.n_clad=1.film_thickness=0.5wavelength=1.55angle=75.structure=st.RidgeWaveguide(wavelength,
x_step,
y_step,
wg_height,
wg_width,
sub_height,
sub_width,
clad_height,
n_sub,
n_wg,
angle,
n_clad,
film_thickness)
structure.write_to_file('example_structure_1.dat')
mode_solver=ms.ModeSolverSemiVectorial(2, semi_vectorial_method='Ey')
mode_solver.solve(structure)
mode_solver.write_modes_to_file('example_modes_1.dat')

Structure

Modes

Example 2: Fully vectorial mode solving of anisotropic material

The following looks at a contrived ridge waveguide in Z-cut KTP.

The simulation outputs:

  • 5 plots for each refractive index axis (n_xx, n_xy, n_yx, n_yy and n_zz),
  • 48 plots for Ex, Ey, Ez, Hx, Hy and Hz,
  • 8 effective index values, one for each mode,
  • a wavelength sweep of the waveguide (plotting n_eff vs wavelength for each mode),
  • whether a mode is qTE or qTM and the percentage overlap with TE and TM, and
  • the group velocity of the mode.

The waveguide parameters are:

  • thin-film thickness: 1.2um,
  • waveguide height: 800nm,
  • waveguide width: 1.2um,
  • refractive index of waveguide: used Sellmeier equations to get n_xx, n_yy, n_zz at 1550nm,
  • refractive index of substrate: used Sellmeier equation to get SiO2 at 1550nm,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.06y_step=0.06wg_height=0.8wg_width=1.8sub_height=1.0sub_width=4.clad_height=1.0film_thickness=1.2angle=60.defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, wg_height, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, angle, n_clad, film_thickness)
n_sub=mat.SiO2().n(wl)
n_wg_xx=mat.Ktp('x').n(wl)
n_wg_yy=mat.Ktp('y').n(wl)
n_wg_zz=mat.Ktp('z').n(wl)
n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
struct_ani.write_to_file()
solver=ms.ModeSolverFullyVectorial(8)
solver.solve(struct_ani)
solver.write_modes_to_file()
solver.solve_ng(struct_ani, 1.55, 0.01)
solver.solve_sweep_wavelength(struct_ani, np.linspace(1.501, 1.60, 21))

Group Velocity

The group velocity at 1550nm for each mode is:

# modes_full_vec/ng.dat
# Mode idx, Group index
0,1.776
1,1.799
2,1.826
3,1.847
4,1.841
5,1.882
6,1.872
7,1.871

Structure

Modes

Only the first 4 (out of 8) modes are shown, and only the E-fields are shown (not H-fields). For the rest of the images, look in the example folder or run the script.

A_{x,y,z} give the percentage power of that particular E-field component with respect to the total of all components.

Mode types:

# modes_full_vec/mode_info
# Mode idx, Mode type, % in major direction, n_eff
0,qTE,97.39,1.643
1,qTM,92.54,1.640
2,qTE,90.60,1.576
3,qTM,91.41,1.571
4,qTE,89.48,1.497
5,qTM,86.70,1.475
6,qTE,89.47,1.447
7,qTM,68.35,1.437

Wavelength Sweep

Example 3: Grating-coupler period

Analytic calculation of the grating coupler period for various duty-cycles in SOI.

Seems to match well with the periods in Taillaert et al., Grating Couplers for Coupling between Optical Fibers and Nanophotonic Waveguides, IOP Science, 2006.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpwls= [1.5, 1.55, 1.6]
x_step=0.05y_step=0.05etch_depth=0.07wg_width=10sub_height=0.5sub_width=14.clad_height=0.5film_thickness=0.22polarisation='TE'dcs=np.linspace(20, 80, 61) /100ed1=etch_depthft1=film_thicknessed2=ft1-ed1ft2=ed2periods= []
periods.append(dcs)
forwlinwls:
ngc= []
fored, ftin [(ed1, ft1), (ed2, ft2)]:
defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, ed, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, ft)
n_sub=mat.SiO2().n(wl)
n_wg_xx=3.46n_wg_yy=3.46n_wg_zz=3.46n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
#struct_ani.write_to_file()solver=ms.ModeSolverFullyVectorial(4)
solver.solve(struct_ani)
#solver.write_modes_to_file()ifpolarisation=='TE':
ngc.append(np.round(np.real(solver.n_effs_te), 4)[0])
elifpolarisation=='TM':
ngc.append(np.round(np.real(solver.n_effs_tm), 4)[0])
period=de.grating_coupler_period(wl, dcs*ngc[0]+(1-dcs)*ngc[1], n_clad, 8, 1)
periods.append(period)
filename='dc-sweep-%s-%inm-etch-%i-film.dat'% (polarisation, etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.array(periods).T, delimiter=',', header=','.join([str(val) forvalinwls]))
print(np.c_[periods])

Example 4: Mode Hybridisation In SOI

Simulation of mode hybridisation in 220nm thick fully-etched SOI ridge waveguides.

Results look the same as those found in Daoxin Dai and Ming Zhang, "Mode hybridization and conversion in silicon-on-insulator nanowires with angled sidewalls," Opt. Express 23, 32452-32464 (2015).

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.02y_step=0.02etch_depth=0.22wg_widths=np.arange(0.3, 2., 0.05)
sub_height=1.sub_width=4.clad_height=1.film_thickness=0.22n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476r= []
forwinwg_widths:
r.append(st.RidgeWaveguide(wl, x_step, y_step, etch_depth, w,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, film_thickness))
solver=ms.ModeSolverFullyVectorial(6)
solver.solve_sweep_structure(r, wg_widths)
solver.write_modes_to_file()

Example 5: Directional Coupler 3dB Length In SOI

Analytic calculation of 3dB coupling length into two parallel SOI waveguides with a varying gap at 3 different TE wavelengths.

An example refractive index profile for the two waveguides spaced 200nm is shown.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpimporttqdmwls= [1.5, 1.55, 1.6]
x_step=0.02y_step=0.02etch_depth=0.22wg_width=0.44sub_height=0.5sub_width=2.clad_height=0.5film_thickness=0.22gaps=np.linspace(0.1, 0.5, 11)
forwlinwls:
lengths= []
n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476forgapintqdm.tqdm(gaps):
r=st.WgArray(wl, x_step, y_step, etch_depth, [wg_width, wg_width], gap,
sub_height, sub_width, clad_height, n_sub, n_wg, None)
#r.write_to_file()solver=ms.ModeSolverFullyVectorial(2)
solver.solve(r)
n1=solver.n_effs_te[0]
n2=solver.n_effs_te[1]
lengths.append(de.directional_coupler_lc(wl*1000, n1, n2)/2)
filename='dc-sweep-%inm-%s-%inm-etch-%i-film.dat'% (wl*1000, 'TE', etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.c_[gaps, lengths], delimiter=',', header='Coupling lengths (50\%)')

Contributions

If you add functionality, please send me a pull request.

Acknowledgments

This finite difference mode solver is based on a modified version of EMpy.

Thank you to Inna Krasnokutska for testing.

About

Photonic mode solver with a simple interface.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

modesolverpy

Photonic mode solver with a nice interface and output.

The documentation for this project can be found here.

Installation

It is recommend to install modesolverpy either via:

Ubuntu/Mint/Debian:

pip3 install modesolverpy
apt install gnuplot

Arch Linux:

yaourt -S python-modesolverpy

Dependencies

If installing using the Arch Linux AUR package or pip, dependencies will be automatically downloaded and installed, if not, one should ensure the following dependencies are installed:

Either Gnuplot or Matplotlib can be used for plotting; I am a Gnuplot user to the code was written with it in mind. If both Gnuplot and Matplotlib are installed, the code will default to Gnuplot.

Plotting

EITHER:

OR:

Features

The main reasons to consider this library include:

  • semi-vectorial and fully vectorial options,
  • simple structure drawing,
  • automated data saving and plotting via Gnuplot,
  • some limited (at this stage) data processing (finding MFD of fundamental mode), and
  • easily extensible library.

Example 1: Semi-vectorial mode solving of a ridge waveguide

The following example finds the first two modes of a waveguide with the following, arbitrary, parameters:

  • thin-film thickness: 500nm
  • waveguide height: 400nm,
  • waveguide width: 500nm,
  • refractive index of waveguide: 3,
  • refractive index of substrate: 1.4,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportnumpyasnp# All units are relative. [um] were chosen in this case.x_step=0.02y_step=0.02wg_height=0.4wg_width=0.5sub_height=0.5sub_width=2.clad_height=0.5n_sub=1.4n_wg=3.n_clad=1.film_thickness=0.5wavelength=1.55angle=75.structure=st.RidgeWaveguide(wavelength,
x_step,
y_step,
wg_height,
wg_width,
sub_height,
sub_width,
clad_height,
n_sub,
n_wg,
angle,
n_clad,
film_thickness)
structure.write_to_file('example_structure_1.dat')
mode_solver=ms.ModeSolverSemiVectorial(2, semi_vectorial_method='Ey')
mode_solver.solve(structure)
mode_solver.write_modes_to_file('example_modes_1.dat')

Structure

Modes

Example 2: Fully vectorial mode solving of anisotropic material

The following looks at a contrived ridge waveguide in Z-cut KTP.

The simulation outputs:

  • 5 plots for each refractive index axis (n_xx, n_xy, n_yx, n_yy and n_zz),
  • 48 plots for Ex, Ey, Ez, Hx, Hy and Hz,
  • 8 effective index values, one for each mode,
  • a wavelength sweep of the waveguide (plotting n_eff vs wavelength for each mode),
  • whether a mode is qTE or qTM and the percentage overlap with TE and TM, and
  • the group velocity of the mode.

The waveguide parameters are:

  • thin-film thickness: 1.2um,
  • waveguide height: 800nm,
  • waveguide width: 1.2um,
  • refractive index of waveguide: used Sellmeier equations to get n_xx, n_yy, n_zz at 1550nm,
  • refractive index of substrate: used Sellmeier equation to get SiO2 at 1550nm,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.06y_step=0.06wg_height=0.8wg_width=1.8sub_height=1.0sub_width=4.clad_height=1.0film_thickness=1.2angle=60.defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, wg_height, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, angle, n_clad, film_thickness)
n_sub=mat.SiO2().n(wl)
n_wg_xx=mat.Ktp('x').n(wl)
n_wg_yy=mat.Ktp('y').n(wl)
n_wg_zz=mat.Ktp('z').n(wl)
n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
struct_ani.write_to_file()
solver=ms.ModeSolverFullyVectorial(8)
solver.solve(struct_ani)
solver.write_modes_to_file()
solver.solve_ng(struct_ani, 1.55, 0.01)
solver.solve_sweep_wavelength(struct_ani, np.linspace(1.501, 1.60, 21))

Group Velocity

The group velocity at 1550nm for each mode is:

# modes_full_vec/ng.dat
# Mode idx, Group index
0,1.776
1,1.799
2,1.826
3,1.847
4,1.841
5,1.882
6,1.872
7,1.871

Structure

Modes

Only the first 4 (out of 8) modes are shown, and only the E-fields are shown (not H-fields). For the rest of the images, look in the example folder or run the script.

A_{x,y,z} give the percentage power of that particular E-field component with respect to the total of all components.

Mode types:

# modes_full_vec/mode_info
# Mode idx, Mode type, % in major direction, n_eff
0,qTE,97.39,1.643
1,qTM,92.54,1.640
2,qTE,90.60,1.576
3,qTM,91.41,1.571
4,qTE,89.48,1.497
5,qTM,86.70,1.475
6,qTE,89.47,1.447
7,qTM,68.35,1.437

Wavelength Sweep

Example 3: Grating-coupler period

Analytic calculation of the grating coupler period for various duty-cycles in SOI.

Seems to match well with the periods in Taillaert et al., Grating Couplers for Coupling between Optical Fibers and Nanophotonic Waveguides, IOP Science, 2006.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpwls= [1.5, 1.55, 1.6]
x_step=0.05y_step=0.05etch_depth=0.07wg_width=10sub_height=0.5sub_width=14.clad_height=0.5film_thickness=0.22polarisation='TE'dcs=np.linspace(20, 80, 61) /100ed1=etch_depthft1=film_thicknessed2=ft1-ed1ft2=ed2periods= []
periods.append(dcs)
forwlinwls:
ngc= []
fored, ftin [(ed1, ft1), (ed2, ft2)]:
defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, ed, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, ft)
n_sub=mat.SiO2().n(wl)
n_wg_xx=3.46n_wg_yy=3.46n_wg_zz=3.46n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
#struct_ani.write_to_file()solver=ms.ModeSolverFullyVectorial(4)
solver.solve(struct_ani)
#solver.write_modes_to_file()ifpolarisation=='TE':
ngc.append(np.round(np.real(solver.n_effs_te), 4)[0])
elifpolarisation=='TM':
ngc.append(np.round(np.real(solver.n_effs_tm), 4)[0])
period=de.grating_coupler_period(wl, dcs*ngc[0]+(1-dcs)*ngc[1], n_clad, 8, 1)
periods.append(period)
filename='dc-sweep-%s-%inm-etch-%i-film.dat'% (polarisation, etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.array(periods).T, delimiter=',', header=','.join([str(val) forvalinwls]))
print(np.c_[periods])

Example 4: Mode Hybridisation In SOI

Simulation of mode hybridisation in 220nm thick fully-etched SOI ridge waveguides.

Results look the same as those found in Daoxin Dai and Ming Zhang, "Mode hybridization and conversion in silicon-on-insulator nanowires with angled sidewalls," Opt. Express 23, 32452-32464 (2015).

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.02y_step=0.02etch_depth=0.22wg_widths=np.arange(0.3, 2., 0.05)
sub_height=1.sub_width=4.clad_height=1.film_thickness=0.22n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476r= []
forwinwg_widths:
r.append(st.RidgeWaveguide(wl, x_step, y_step, etch_depth, w,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, film_thickness))
solver=ms.ModeSolverFullyVectorial(6)
solver.solve_sweep_structure(r, wg_widths)
solver.write_modes_to_file()

Example 5: Directional Coupler 3dB Length In SOI

Analytic calculation of 3dB coupling length into two parallel SOI waveguides with a varying gap at 3 different TE wavelengths.

An example refractive index profile for the two waveguides spaced 200nm is shown.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpimporttqdmwls= [1.5, 1.55, 1.6]
x_step=0.02y_step=0.02etch_depth=0.22wg_width=0.44sub_height=0.5sub_width=2.clad_height=0.5film_thickness=0.22gaps=np.linspace(0.1, 0.5, 11)
forwlinwls:
lengths= []
n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476forgapintqdm.tqdm(gaps):
r=st.WgArray(wl, x_step, y_step, etch_depth, [wg_width, wg_width], gap,
sub_height, sub_width, clad_height, n_sub, n_wg, None)
#r.write_to_file()solver=ms.ModeSolverFullyVectorial(2)
solver.solve(r)
n1=solver.n_effs_te[0]
n2=solver.n_effs_te[1]
lengths.append(de.directional_coupler_lc(wl*1000, n1, n2)/2)
filename='dc-sweep-%inm-%s-%inm-etch-%i-film.dat'% (wl*1000, 'TE', etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.c_[gaps, lengths], delimiter=',', header='Coupling lengths (50\%)')

Contributions

If you add functionality, please send me a pull request.

Acknowledgments

This finite difference mode solver is based on a modified version of EMpy.

Thank you to Inna Krasnokutska for testing.

About

Photonic mode solver with a simple interface.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

modesolverpy

Photonic mode solver with a nice interface and output.

The documentation for this project can be found here.

Installation

It is recommend to install modesolverpy either via:

Ubuntu/Mint/Debian:

pip3 install modesolverpy
apt install gnuplot

Arch Linux:

yaourt -S python-modesolverpy

Dependencies

If installing using the Arch Linux AUR package or pip, dependencies will be automatically downloaded and installed, if not, one should ensure the following dependencies are installed:

Either Gnuplot or Matplotlib can be used for plotting; I am a Gnuplot user to the code was written with it in mind. If both Gnuplot and Matplotlib are installed, the code will default to Gnuplot.

Plotting

EITHER:

OR:

Features

The main reasons to consider this library include:

  • semi-vectorial and fully vectorial options,
  • simple structure drawing,
  • automated data saving and plotting via Gnuplot,
  • some limited (at this stage) data processing (finding MFD of fundamental mode), and
  • easily extensible library.

Example 1: Semi-vectorial mode solving of a ridge waveguide

The following example finds the first two modes of a waveguide with the following, arbitrary, parameters:

  • thin-film thickness: 500nm
  • waveguide height: 400nm,
  • waveguide width: 500nm,
  • refractive index of waveguide: 3,
  • refractive index of substrate: 1.4,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportnumpyasnp# All units are relative. [um] were chosen in this case.x_step=0.02y_step=0.02wg_height=0.4wg_width=0.5sub_height=0.5sub_width=2.clad_height=0.5n_sub=1.4n_wg=3.n_clad=1.film_thickness=0.5wavelength=1.55angle=75.structure=st.RidgeWaveguide(wavelength,
x_step,
y_step,
wg_height,
wg_width,
sub_height,
sub_width,
clad_height,
n_sub,
n_wg,
angle,
n_clad,
film_thickness)
structure.write_to_file('example_structure_1.dat')
mode_solver=ms.ModeSolverSemiVectorial(2, semi_vectorial_method='Ey')
mode_solver.solve(structure)
mode_solver.write_modes_to_file('example_modes_1.dat')

Structure

Modes

Example 2: Fully vectorial mode solving of anisotropic material

The following looks at a contrived ridge waveguide in Z-cut KTP.

The simulation outputs:

  • 5 plots for each refractive index axis (n_xx, n_xy, n_yx, n_yy and n_zz),
  • 48 plots for Ex, Ey, Ez, Hx, Hy and Hz,
  • 8 effective index values, one for each mode,
  • a wavelength sweep of the waveguide (plotting n_eff vs wavelength for each mode),
  • whether a mode is qTE or qTM and the percentage overlap with TE and TM, and
  • the group velocity of the mode.

The waveguide parameters are:

  • thin-film thickness: 1.2um,
  • waveguide height: 800nm,
  • waveguide width: 1.2um,
  • refractive index of waveguide: used Sellmeier equations to get n_xx, n_yy, n_zz at 1550nm,
  • refractive index of substrate: used Sellmeier equation to get SiO2 at 1550nm,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.06y_step=0.06wg_height=0.8wg_width=1.8sub_height=1.0sub_width=4.clad_height=1.0film_thickness=1.2angle=60.defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, wg_height, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, angle, n_clad, film_thickness)
n_sub=mat.SiO2().n(wl)
n_wg_xx=mat.Ktp('x').n(wl)
n_wg_yy=mat.Ktp('y').n(wl)
n_wg_zz=mat.Ktp('z').n(wl)
n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
struct_ani.write_to_file()
solver=ms.ModeSolverFullyVectorial(8)
solver.solve(struct_ani)
solver.write_modes_to_file()
solver.solve_ng(struct_ani, 1.55, 0.01)
solver.solve_sweep_wavelength(struct_ani, np.linspace(1.501, 1.60, 21))

Group Velocity

The group velocity at 1550nm for each mode is:

# modes_full_vec/ng.dat
# Mode idx, Group index
0,1.776
1,1.799
2,1.826
3,1.847
4,1.841
5,1.882
6,1.872
7,1.871

Structure

Modes

Only the first 4 (out of 8) modes are shown, and only the E-fields are shown (not H-fields). For the rest of the images, look in the example folder or run the script.

A_{x,y,z} give the percentage power of that particular E-field component with respect to the total of all components.

Mode types:

# modes_full_vec/mode_info
# Mode idx, Mode type, % in major direction, n_eff
0,qTE,97.39,1.643
1,qTM,92.54,1.640
2,qTE,90.60,1.576
3,qTM,91.41,1.571
4,qTE,89.48,1.497
5,qTM,86.70,1.475
6,qTE,89.47,1.447
7,qTM,68.35,1.437

Wavelength Sweep

Example 3: Grating-coupler period

Analytic calculation of the grating coupler period for various duty-cycles in SOI.

Seems to match well with the periods in Taillaert et al., Grating Couplers for Coupling between Optical Fibers and Nanophotonic Waveguides, IOP Science, 2006.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpwls= [1.5, 1.55, 1.6]
x_step=0.05y_step=0.05etch_depth=0.07wg_width=10sub_height=0.5sub_width=14.clad_height=0.5film_thickness=0.22polarisation='TE'dcs=np.linspace(20, 80, 61) /100ed1=etch_depthft1=film_thicknessed2=ft1-ed1ft2=ed2periods= []
periods.append(dcs)
forwlinwls:
ngc= []
fored, ftin [(ed1, ft1), (ed2, ft2)]:
defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, ed, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, ft)
n_sub=mat.SiO2().n(wl)
n_wg_xx=3.46n_wg_yy=3.46n_wg_zz=3.46n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
#struct_ani.write_to_file()solver=ms.ModeSolverFullyVectorial(4)
solver.solve(struct_ani)
#solver.write_modes_to_file()ifpolarisation=='TE':
ngc.append(np.round(np.real(solver.n_effs_te), 4)[0])
elifpolarisation=='TM':
ngc.append(np.round(np.real(solver.n_effs_tm), 4)[0])
period=de.grating_coupler_period(wl, dcs*ngc[0]+(1-dcs)*ngc[1], n_clad, 8, 1)
periods.append(period)
filename='dc-sweep-%s-%inm-etch-%i-film.dat'% (polarisation, etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.array(periods).T, delimiter=',', header=','.join([str(val) forvalinwls]))
print(np.c_[periods])

Example 4: Mode Hybridisation In SOI

Simulation of mode hybridisation in 220nm thick fully-etched SOI ridge waveguides.

Results look the same as those found in Daoxin Dai and Ming Zhang, "Mode hybridization and conversion in silicon-on-insulator nanowires with angled sidewalls," Opt. Express 23, 32452-32464 (2015).

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.02y_step=0.02etch_depth=0.22wg_widths=np.arange(0.3, 2., 0.05)
sub_height=1.sub_width=4.clad_height=1.film_thickness=0.22n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476r= []
forwinwg_widths:
r.append(st.RidgeWaveguide(wl, x_step, y_step, etch_depth, w,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, film_thickness))
solver=ms.ModeSolverFullyVectorial(6)
solver.solve_sweep_structure(r, wg_widths)
solver.write_modes_to_file()

Example 5: Directional Coupler 3dB Length In SOI

Analytic calculation of 3dB coupling length into two parallel SOI waveguides with a varying gap at 3 different TE wavelengths.

An example refractive index profile for the two waveguides spaced 200nm is shown.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpimporttqdmwls= [1.5, 1.55, 1.6]
x_step=0.02y_step=0.02etch_depth=0.22wg_width=0.44sub_height=0.5sub_width=2.clad_height=0.5film_thickness=0.22gaps=np.linspace(0.1, 0.5, 11)
forwlinwls:
lengths= []
n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476forgapintqdm.tqdm(gaps):
r=st.WgArray(wl, x_step, y_step, etch_depth, [wg_width, wg_width], gap,
sub_height, sub_width, clad_height, n_sub, n_wg, None)
#r.write_to_file()solver=ms.ModeSolverFullyVectorial(2)
solver.solve(r)
n1=solver.n_effs_te[0]
n2=solver.n_effs_te[1]
lengths.append(de.directional_coupler_lc(wl*1000, n1, n2)/2)
filename='dc-sweep-%inm-%s-%inm-etch-%i-film.dat'% (wl*1000, 'TE', etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.c_[gaps, lengths], delimiter=',', header='Coupling lengths (50\%)')

Contributions

If you add functionality, please send me a pull request.

Acknowledgments

This finite difference mode solver is based on a modified version of EMpy.

Thank you to Inna Krasnokutska for testing.

About

Photonic mode solver with a simple interface.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

modesolverpy

Photonic mode solver with a nice interface and output.

The documentation for this project can be found here.

Installation

It is recommend to install modesolverpy either via:

Ubuntu/Mint/Debian:

pip3 install modesolverpy
apt install gnuplot

Arch Linux:

yaourt -S python-modesolverpy

Dependencies

If installing using the Arch Linux AUR package or pip, dependencies will be automatically downloaded and installed, if not, one should ensure the following dependencies are installed:

Either Gnuplot or Matplotlib can be used for plotting; I am a Gnuplot user to the code was written with it in mind. If both Gnuplot and Matplotlib are installed, the code will default to Gnuplot.

Plotting

EITHER:

OR:

Features

The main reasons to consider this library include:

  • semi-vectorial and fully vectorial options,
  • simple structure drawing,
  • automated data saving and plotting via Gnuplot,
  • some limited (at this stage) data processing (finding MFD of fundamental mode), and
  • easily extensible library.

Example 1: Semi-vectorial mode solving of a ridge waveguide

The following example finds the first two modes of a waveguide with the following, arbitrary, parameters:

  • thin-film thickness: 500nm
  • waveguide height: 400nm,
  • waveguide width: 500nm,
  • refractive index of waveguide: 3,
  • refractive index of substrate: 1.4,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportnumpyasnp# All units are relative. [um] were chosen in this case.x_step=0.02y_step=0.02wg_height=0.4wg_width=0.5sub_height=0.5sub_width=2.clad_height=0.5n_sub=1.4n_wg=3.n_clad=1.film_thickness=0.5wavelength=1.55angle=75.structure=st.RidgeWaveguide(wavelength,
x_step,
y_step,
wg_height,
wg_width,
sub_height,
sub_width,
clad_height,
n_sub,
n_wg,
angle,
n_clad,
film_thickness)
structure.write_to_file('example_structure_1.dat')
mode_solver=ms.ModeSolverSemiVectorial(2, semi_vectorial_method='Ey')
mode_solver.solve(structure)
mode_solver.write_modes_to_file('example_modes_1.dat')

Structure

Modes

Example 2: Fully vectorial mode solving of anisotropic material

The following looks at a contrived ridge waveguide in Z-cut KTP.

The simulation outputs:

  • 5 plots for each refractive index axis (n_xx, n_xy, n_yx, n_yy and n_zz),
  • 48 plots for Ex, Ey, Ez, Hx, Hy and Hz,
  • 8 effective index values, one for each mode,
  • a wavelength sweep of the waveguide (plotting n_eff vs wavelength for each mode),
  • whether a mode is qTE or qTM and the percentage overlap with TE and TM, and
  • the group velocity of the mode.

The waveguide parameters are:

  • thin-film thickness: 1.2um,
  • waveguide height: 800nm,
  • waveguide width: 1.2um,
  • refractive index of waveguide: used Sellmeier equations to get n_xx, n_yy, n_zz at 1550nm,
  • refractive index of substrate: used Sellmeier equation to get SiO2 at 1550nm,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.06y_step=0.06wg_height=0.8wg_width=1.8sub_height=1.0sub_width=4.clad_height=1.0film_thickness=1.2angle=60.defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, wg_height, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, angle, n_clad, film_thickness)
n_sub=mat.SiO2().n(wl)
n_wg_xx=mat.Ktp('x').n(wl)
n_wg_yy=mat.Ktp('y').n(wl)
n_wg_zz=mat.Ktp('z').n(wl)
n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
struct_ani.write_to_file()
solver=ms.ModeSolverFullyVectorial(8)
solver.solve(struct_ani)
solver.write_modes_to_file()
solver.solve_ng(struct_ani, 1.55, 0.01)
solver.solve_sweep_wavelength(struct_ani, np.linspace(1.501, 1.60, 21))

Group Velocity

The group velocity at 1550nm for each mode is:

# modes_full_vec/ng.dat
# Mode idx, Group index
0,1.776
1,1.799
2,1.826
3,1.847
4,1.841
5,1.882
6,1.872
7,1.871

Structure

Modes

Only the first 4 (out of 8) modes are shown, and only the E-fields are shown (not H-fields). For the rest of the images, look in the example folder or run the script.

A_{x,y,z} give the percentage power of that particular E-field component with respect to the total of all components.

Mode types:

# modes_full_vec/mode_info
# Mode idx, Mode type, % in major direction, n_eff
0,qTE,97.39,1.643
1,qTM,92.54,1.640
2,qTE,90.60,1.576
3,qTM,91.41,1.571
4,qTE,89.48,1.497
5,qTM,86.70,1.475
6,qTE,89.47,1.447
7,qTM,68.35,1.437

Wavelength Sweep

Example 3: Grating-coupler period

Analytic calculation of the grating coupler period for various duty-cycles in SOI.

Seems to match well with the periods in Taillaert et al., Grating Couplers for Coupling between Optical Fibers and Nanophotonic Waveguides, IOP Science, 2006.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpwls= [1.5, 1.55, 1.6]
x_step=0.05y_step=0.05etch_depth=0.07wg_width=10sub_height=0.5sub_width=14.clad_height=0.5film_thickness=0.22polarisation='TE'dcs=np.linspace(20, 80, 61) /100ed1=etch_depthft1=film_thicknessed2=ft1-ed1ft2=ed2periods= []
periods.append(dcs)
forwlinwls:
ngc= []
fored, ftin [(ed1, ft1), (ed2, ft2)]:
defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, ed, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, ft)
n_sub=mat.SiO2().n(wl)
n_wg_xx=3.46n_wg_yy=3.46n_wg_zz=3.46n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
#struct_ani.write_to_file()solver=ms.ModeSolverFullyVectorial(4)
solver.solve(struct_ani)
#solver.write_modes_to_file()ifpolarisation=='TE':
ngc.append(np.round(np.real(solver.n_effs_te), 4)[0])
elifpolarisation=='TM':
ngc.append(np.round(np.real(solver.n_effs_tm), 4)[0])
period=de.grating_coupler_period(wl, dcs*ngc[0]+(1-dcs)*ngc[1], n_clad, 8, 1)
periods.append(period)
filename='dc-sweep-%s-%inm-etch-%i-film.dat'% (polarisation, etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.array(periods).T, delimiter=',', header=','.join([str(val) forvalinwls]))
print(np.c_[periods])

Example 4: Mode Hybridisation In SOI

Simulation of mode hybridisation in 220nm thick fully-etched SOI ridge waveguides.

Results look the same as those found in Daoxin Dai and Ming Zhang, "Mode hybridization and conversion in silicon-on-insulator nanowires with angled sidewalls," Opt. Express 23, 32452-32464 (2015).

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.02y_step=0.02etch_depth=0.22wg_widths=np.arange(0.3, 2., 0.05)
sub_height=1.sub_width=4.clad_height=1.film_thickness=0.22n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476r= []
forwinwg_widths:
r.append(st.RidgeWaveguide(wl, x_step, y_step, etch_depth, w,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, film_thickness))
solver=ms.ModeSolverFullyVectorial(6)
solver.solve_sweep_structure(r, wg_widths)
solver.write_modes_to_file()

Example 5: Directional Coupler 3dB Length In SOI

Analytic calculation of 3dB coupling length into two parallel SOI waveguides with a varying gap at 3 different TE wavelengths.

An example refractive index profile for the two waveguides spaced 200nm is shown.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpimporttqdmwls= [1.5, 1.55, 1.6]
x_step=0.02y_step=0.02etch_depth=0.22wg_width=0.44sub_height=0.5sub_width=2.clad_height=0.5film_thickness=0.22gaps=np.linspace(0.1, 0.5, 11)
forwlinwls:
lengths= []
n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476forgapintqdm.tqdm(gaps):
r=st.WgArray(wl, x_step, y_step, etch_depth, [wg_width, wg_width], gap,
sub_height, sub_width, clad_height, n_sub, n_wg, None)
#r.write_to_file()solver=ms.ModeSolverFullyVectorial(2)
solver.solve(r)
n1=solver.n_effs_te[0]
n2=solver.n_effs_te[1]
lengths.append(de.directional_coupler_lc(wl*1000, n1, n2)/2)
filename='dc-sweep-%inm-%s-%inm-etch-%i-film.dat'% (wl*1000, 'TE', etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.c_[gaps, lengths], delimiter=',', header='Coupling lengths (50\%)')

Contributions

If you add functionality, please send me a pull request.

Acknowledgments

This finite difference mode solver is based on a modified version of EMpy.

Thank you to Inna Krasnokutska for testing.

About

Photonic mode solver with a simple interface.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

modesolverpy

Photonic mode solver with a nice interface and output.

The documentation for this project can be found here.

Installation

It is recommend to install modesolverpy either via:

Ubuntu/Mint/Debian:

pip3 install modesolverpy
apt install gnuplot

Arch Linux:

yaourt -S python-modesolverpy

Dependencies

If installing using the Arch Linux AUR package or pip, dependencies will be automatically downloaded and installed, if not, one should ensure the following dependencies are installed:

Either Gnuplot or Matplotlib can be used for plotting; I am a Gnuplot user to the code was written with it in mind. If both Gnuplot and Matplotlib are installed, the code will default to Gnuplot.

Plotting

EITHER:

OR:

Features

The main reasons to consider this library include:

  • semi-vectorial and fully vectorial options,
  • simple structure drawing,
  • automated data saving and plotting via Gnuplot,
  • some limited (at this stage) data processing (finding MFD of fundamental mode), and
  • easily extensible library.

Example 1: Semi-vectorial mode solving of a ridge waveguide

The following example finds the first two modes of a waveguide with the following, arbitrary, parameters:

  • thin-film thickness: 500nm
  • waveguide height: 400nm,
  • waveguide width: 500nm,
  • refractive index of waveguide: 3,
  • refractive index of substrate: 1.4,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportnumpyasnp# All units are relative. [um] were chosen in this case.x_step=0.02y_step=0.02wg_height=0.4wg_width=0.5sub_height=0.5sub_width=2.clad_height=0.5n_sub=1.4n_wg=3.n_clad=1.film_thickness=0.5wavelength=1.55angle=75.structure=st.RidgeWaveguide(wavelength,
x_step,
y_step,
wg_height,
wg_width,
sub_height,
sub_width,
clad_height,
n_sub,
n_wg,
angle,
n_clad,
film_thickness)
structure.write_to_file('example_structure_1.dat')
mode_solver=ms.ModeSolverSemiVectorial(2, semi_vectorial_method='Ey')
mode_solver.solve(structure)
mode_solver.write_modes_to_file('example_modes_1.dat')

Structure

Modes

Example 2: Fully vectorial mode solving of anisotropic material

The following looks at a contrived ridge waveguide in Z-cut KTP.

The simulation outputs:

  • 5 plots for each refractive index axis (n_xx, n_xy, n_yx, n_yy and n_zz),
  • 48 plots for Ex, Ey, Ez, Hx, Hy and Hz,
  • 8 effective index values, one for each mode,
  • a wavelength sweep of the waveguide (plotting n_eff vs wavelength for each mode),
  • whether a mode is qTE or qTM and the percentage overlap with TE and TM, and
  • the group velocity of the mode.

The waveguide parameters are:

  • thin-film thickness: 1.2um,
  • waveguide height: 800nm,
  • waveguide width: 1.2um,
  • refractive index of waveguide: used Sellmeier equations to get n_xx, n_yy, n_zz at 1550nm,
  • refractive index of substrate: used Sellmeier equation to get SiO2 at 1550nm,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.06y_step=0.06wg_height=0.8wg_width=1.8sub_height=1.0sub_width=4.clad_height=1.0film_thickness=1.2angle=60.defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, wg_height, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, angle, n_clad, film_thickness)
n_sub=mat.SiO2().n(wl)
n_wg_xx=mat.Ktp('x').n(wl)
n_wg_yy=mat.Ktp('y').n(wl)
n_wg_zz=mat.Ktp('z').n(wl)
n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
struct_ani.write_to_file()
solver=ms.ModeSolverFullyVectorial(8)
solver.solve(struct_ani)
solver.write_modes_to_file()
solver.solve_ng(struct_ani, 1.55, 0.01)
solver.solve_sweep_wavelength(struct_ani, np.linspace(1.501, 1.60, 21))

Group Velocity

The group velocity at 1550nm for each mode is:

# modes_full_vec/ng.dat
# Mode idx, Group index
0,1.776
1,1.799
2,1.826
3,1.847
4,1.841
5,1.882
6,1.872
7,1.871

Structure

Modes

Only the first 4 (out of 8) modes are shown, and only the E-fields are shown (not H-fields). For the rest of the images, look in the example folder or run the script.

A_{x,y,z} give the percentage power of that particular E-field component with respect to the total of all components.

Mode types:

# modes_full_vec/mode_info
# Mode idx, Mode type, % in major direction, n_eff
0,qTE,97.39,1.643
1,qTM,92.54,1.640
2,qTE,90.60,1.576
3,qTM,91.41,1.571
4,qTE,89.48,1.497
5,qTM,86.70,1.475
6,qTE,89.47,1.447
7,qTM,68.35,1.437

Wavelength Sweep

Example 3: Grating-coupler period

Analytic calculation of the grating coupler period for various duty-cycles in SOI.

Seems to match well with the periods in Taillaert et al., Grating Couplers for Coupling between Optical Fibers and Nanophotonic Waveguides, IOP Science, 2006.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpwls= [1.5, 1.55, 1.6]
x_step=0.05y_step=0.05etch_depth=0.07wg_width=10sub_height=0.5sub_width=14.clad_height=0.5film_thickness=0.22polarisation='TE'dcs=np.linspace(20, 80, 61) /100ed1=etch_depthft1=film_thicknessed2=ft1-ed1ft2=ed2periods= []
periods.append(dcs)
forwlinwls:
ngc= []
fored, ftin [(ed1, ft1), (ed2, ft2)]:
defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, ed, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, ft)
n_sub=mat.SiO2().n(wl)
n_wg_xx=3.46n_wg_yy=3.46n_wg_zz=3.46n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
#struct_ani.write_to_file()solver=ms.ModeSolverFullyVectorial(4)
solver.solve(struct_ani)
#solver.write_modes_to_file()ifpolarisation=='TE':
ngc.append(np.round(np.real(solver.n_effs_te), 4)[0])
elifpolarisation=='TM':
ngc.append(np.round(np.real(solver.n_effs_tm), 4)[0])
period=de.grating_coupler_period(wl, dcs*ngc[0]+(1-dcs)*ngc[1], n_clad, 8, 1)
periods.append(period)
filename='dc-sweep-%s-%inm-etch-%i-film.dat'% (polarisation, etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.array(periods).T, delimiter=',', header=','.join([str(val) forvalinwls]))
print(np.c_[periods])

Example 4: Mode Hybridisation In SOI

Simulation of mode hybridisation in 220nm thick fully-etched SOI ridge waveguides.

Results look the same as those found in Daoxin Dai and Ming Zhang, "Mode hybridization and conversion in silicon-on-insulator nanowires with angled sidewalls," Opt. Express 23, 32452-32464 (2015).

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.02y_step=0.02etch_depth=0.22wg_widths=np.arange(0.3, 2., 0.05)
sub_height=1.sub_width=4.clad_height=1.film_thickness=0.22n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476r= []
forwinwg_widths:
r.append(st.RidgeWaveguide(wl, x_step, y_step, etch_depth, w,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, film_thickness))
solver=ms.ModeSolverFullyVectorial(6)
solver.solve_sweep_structure(r, wg_widths)
solver.write_modes_to_file()

Example 5: Directional Coupler 3dB Length In SOI

Analytic calculation of 3dB coupling length into two parallel SOI waveguides with a varying gap at 3 different TE wavelengths.

An example refractive index profile for the two waveguides spaced 200nm is shown.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpimporttqdmwls= [1.5, 1.55, 1.6]
x_step=0.02y_step=0.02etch_depth=0.22wg_width=0.44sub_height=0.5sub_width=2.clad_height=0.5film_thickness=0.22gaps=np.linspace(0.1, 0.5, 11)
forwlinwls:
lengths= []
n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476forgapintqdm.tqdm(gaps):
r=st.WgArray(wl, x_step, y_step, etch_depth, [wg_width, wg_width], gap,
sub_height, sub_width, clad_height, n_sub, n_wg, None)
#r.write_to_file()solver=ms.ModeSolverFullyVectorial(2)
solver.solve(r)
n1=solver.n_effs_te[0]
n2=solver.n_effs_te[1]
lengths.append(de.directional_coupler_lc(wl*1000, n1, n2)/2)
filename='dc-sweep-%inm-%s-%inm-etch-%i-film.dat'% (wl*1000, 'TE', etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.c_[gaps, lengths], delimiter=',', header='Coupling lengths (50\%)')

Contributions

If you add functionality, please send me a pull request.

Acknowledgments

This finite difference mode solver is based on a modified version of EMpy.

Thank you to Inna Krasnokutska for testing.

About

Photonic mode solver with a simple interface.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

modesolverpy

Photonic mode solver with a nice interface and output.

The documentation for this project can be found here.

Installation

It is recommend to install modesolverpy either via:

Ubuntu/Mint/Debian:

pip3 install modesolverpy
apt install gnuplot

Arch Linux:

yaourt -S python-modesolverpy

Dependencies

If installing using the Arch Linux AUR package or pip, dependencies will be automatically downloaded and installed, if not, one should ensure the following dependencies are installed:

Either Gnuplot or Matplotlib can be used for plotting; I am a Gnuplot user to the code was written with it in mind. If both Gnuplot and Matplotlib are installed, the code will default to Gnuplot.

Plotting

EITHER:

OR:

Features

The main reasons to consider this library include:

  • semi-vectorial and fully vectorial options,
  • simple structure drawing,
  • automated data saving and plotting via Gnuplot,
  • some limited (at this stage) data processing (finding MFD of fundamental mode), and
  • easily extensible library.

Example 1: Semi-vectorial mode solving of a ridge waveguide

The following example finds the first two modes of a waveguide with the following, arbitrary, parameters:

  • thin-film thickness: 500nm
  • waveguide height: 400nm,
  • waveguide width: 500nm,
  • refractive index of waveguide: 3,
  • refractive index of substrate: 1.4,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportnumpyasnp# All units are relative. [um] were chosen in this case.x_step=0.02y_step=0.02wg_height=0.4wg_width=0.5sub_height=0.5sub_width=2.clad_height=0.5n_sub=1.4n_wg=3.n_clad=1.film_thickness=0.5wavelength=1.55angle=75.structure=st.RidgeWaveguide(wavelength,
x_step,
y_step,
wg_height,
wg_width,
sub_height,
sub_width,
clad_height,
n_sub,
n_wg,
angle,
n_clad,
film_thickness)
structure.write_to_file('example_structure_1.dat')
mode_solver=ms.ModeSolverSemiVectorial(2, semi_vectorial_method='Ey')
mode_solver.solve(structure)
mode_solver.write_modes_to_file('example_modes_1.dat')

Structure

Modes

Example 2: Fully vectorial mode solving of anisotropic material

The following looks at a contrived ridge waveguide in Z-cut KTP.

The simulation outputs:

  • 5 plots for each refractive index axis (n_xx, n_xy, n_yx, n_yy and n_zz),
  • 48 plots for Ex, Ey, Ez, Hx, Hy and Hz,
  • 8 effective index values, one for each mode,
  • a wavelength sweep of the waveguide (plotting n_eff vs wavelength for each mode),
  • whether a mode is qTE or qTM and the percentage overlap with TE and TM, and
  • the group velocity of the mode.

The waveguide parameters are:

  • thin-film thickness: 1.2um,
  • waveguide height: 800nm,
  • waveguide width: 1.2um,
  • refractive index of waveguide: used Sellmeier equations to get n_xx, n_yy, n_zz at 1550nm,
  • refractive index of substrate: used Sellmeier equation to get SiO2 at 1550nm,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.06y_step=0.06wg_height=0.8wg_width=1.8sub_height=1.0sub_width=4.clad_height=1.0film_thickness=1.2angle=60.defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, wg_height, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, angle, n_clad, film_thickness)
n_sub=mat.SiO2().n(wl)
n_wg_xx=mat.Ktp('x').n(wl)
n_wg_yy=mat.Ktp('y').n(wl)
n_wg_zz=mat.Ktp('z').n(wl)
n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
struct_ani.write_to_file()
solver=ms.ModeSolverFullyVectorial(8)
solver.solve(struct_ani)
solver.write_modes_to_file()
solver.solve_ng(struct_ani, 1.55, 0.01)
solver.solve_sweep_wavelength(struct_ani, np.linspace(1.501, 1.60, 21))

Group Velocity

The group velocity at 1550nm for each mode is:

# modes_full_vec/ng.dat
# Mode idx, Group index
0,1.776
1,1.799
2,1.826
3,1.847
4,1.841
5,1.882
6,1.872
7,1.871

Structure

Modes

Only the first 4 (out of 8) modes are shown, and only the E-fields are shown (not H-fields). For the rest of the images, look in the example folder or run the script.

A_{x,y,z} give the percentage power of that particular E-field component with respect to the total of all components.

Mode types:

# modes_full_vec/mode_info
# Mode idx, Mode type, % in major direction, n_eff
0,qTE,97.39,1.643
1,qTM,92.54,1.640
2,qTE,90.60,1.576
3,qTM,91.41,1.571
4,qTE,89.48,1.497
5,qTM,86.70,1.475
6,qTE,89.47,1.447
7,qTM,68.35,1.437

Wavelength Sweep

Example 3: Grating-coupler period

Analytic calculation of the grating coupler period for various duty-cycles in SOI.

Seems to match well with the periods in Taillaert et al., Grating Couplers for Coupling between Optical Fibers and Nanophotonic Waveguides, IOP Science, 2006.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpwls= [1.5, 1.55, 1.6]
x_step=0.05y_step=0.05etch_depth=0.07wg_width=10sub_height=0.5sub_width=14.clad_height=0.5film_thickness=0.22polarisation='TE'dcs=np.linspace(20, 80, 61) /100ed1=etch_depthft1=film_thicknessed2=ft1-ed1ft2=ed2periods= []
periods.append(dcs)
forwlinwls:
ngc= []
fored, ftin [(ed1, ft1), (ed2, ft2)]:
defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, ed, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, ft)
n_sub=mat.SiO2().n(wl)
n_wg_xx=3.46n_wg_yy=3.46n_wg_zz=3.46n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
#struct_ani.write_to_file()solver=ms.ModeSolverFullyVectorial(4)
solver.solve(struct_ani)
#solver.write_modes_to_file()ifpolarisation=='TE':
ngc.append(np.round(np.real(solver.n_effs_te), 4)[0])
elifpolarisation=='TM':
ngc.append(np.round(np.real(solver.n_effs_tm), 4)[0])
period=de.grating_coupler_period(wl, dcs*ngc[0]+(1-dcs)*ngc[1], n_clad, 8, 1)
periods.append(period)
filename='dc-sweep-%s-%inm-etch-%i-film.dat'% (polarisation, etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.array(periods).T, delimiter=',', header=','.join([str(val) forvalinwls]))
print(np.c_[periods])

Example 4: Mode Hybridisation In SOI

Simulation of mode hybridisation in 220nm thick fully-etched SOI ridge waveguides.

Results look the same as those found in Daoxin Dai and Ming Zhang, "Mode hybridization and conversion in silicon-on-insulator nanowires with angled sidewalls," Opt. Express 23, 32452-32464 (2015).

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.02y_step=0.02etch_depth=0.22wg_widths=np.arange(0.3, 2., 0.05)
sub_height=1.sub_width=4.clad_height=1.film_thickness=0.22n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476r= []
forwinwg_widths:
r.append(st.RidgeWaveguide(wl, x_step, y_step, etch_depth, w,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, film_thickness))
solver=ms.ModeSolverFullyVectorial(6)
solver.solve_sweep_structure(r, wg_widths)
solver.write_modes_to_file()

Example 5: Directional Coupler 3dB Length In SOI

Analytic calculation of 3dB coupling length into two parallel SOI waveguides with a varying gap at 3 different TE wavelengths.

An example refractive index profile for the two waveguides spaced 200nm is shown.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpimporttqdmwls= [1.5, 1.55, 1.6]
x_step=0.02y_step=0.02etch_depth=0.22wg_width=0.44sub_height=0.5sub_width=2.clad_height=0.5film_thickness=0.22gaps=np.linspace(0.1, 0.5, 11)
forwlinwls:
lengths= []
n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476forgapintqdm.tqdm(gaps):
r=st.WgArray(wl, x_step, y_step, etch_depth, [wg_width, wg_width], gap,
sub_height, sub_width, clad_height, n_sub, n_wg, None)
#r.write_to_file()solver=ms.ModeSolverFullyVectorial(2)
solver.solve(r)
n1=solver.n_effs_te[0]
n2=solver.n_effs_te[1]
lengths.append(de.directional_coupler_lc(wl*1000, n1, n2)/2)
filename='dc-sweep-%inm-%s-%inm-etch-%i-film.dat'% (wl*1000, 'TE', etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.c_[gaps, lengths], delimiter=',', header='Coupling lengths (50\%)')

Contributions

If you add functionality, please send me a pull request.

Acknowledgments

This finite difference mode solver is based on a modified version of EMpy.

Thank you to Inna Krasnokutska for testing.

About

Photonic mode solver with a simple interface.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

modesolverpy

Photonic mode solver with a nice interface and output.

The documentation for this project can be found here.

Installation

It is recommend to install modesolverpy either via:

Ubuntu/Mint/Debian:

pip3 install modesolverpy
apt install gnuplot

Arch Linux:

yaourt -S python-modesolverpy

Dependencies

If installing using the Arch Linux AUR package or pip, dependencies will be automatically downloaded and installed, if not, one should ensure the following dependencies are installed:

Either Gnuplot or Matplotlib can be used for plotting; I am a Gnuplot user to the code was written with it in mind. If both Gnuplot and Matplotlib are installed, the code will default to Gnuplot.

Plotting

EITHER:

OR:

Features

The main reasons to consider this library include:

  • semi-vectorial and fully vectorial options,
  • simple structure drawing,
  • automated data saving and plotting via Gnuplot,
  • some limited (at this stage) data processing (finding MFD of fundamental mode), and
  • easily extensible library.

Example 1: Semi-vectorial mode solving of a ridge waveguide

The following example finds the first two modes of a waveguide with the following, arbitrary, parameters:

  • thin-film thickness: 500nm
  • waveguide height: 400nm,
  • waveguide width: 500nm,
  • refractive index of waveguide: 3,
  • refractive index of substrate: 1.4,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportnumpyasnp# All units are relative. [um] were chosen in this case.x_step=0.02y_step=0.02wg_height=0.4wg_width=0.5sub_height=0.5sub_width=2.clad_height=0.5n_sub=1.4n_wg=3.n_clad=1.film_thickness=0.5wavelength=1.55angle=75.structure=st.RidgeWaveguide(wavelength,
x_step,
y_step,
wg_height,
wg_width,
sub_height,
sub_width,
clad_height,
n_sub,
n_wg,
angle,
n_clad,
film_thickness)
structure.write_to_file('example_structure_1.dat')
mode_solver=ms.ModeSolverSemiVectorial(2, semi_vectorial_method='Ey')
mode_solver.solve(structure)
mode_solver.write_modes_to_file('example_modes_1.dat')

Structure

Modes

Example 2: Fully vectorial mode solving of anisotropic material

The following looks at a contrived ridge waveguide in Z-cut KTP.

The simulation outputs:

  • 5 plots for each refractive index axis (n_xx, n_xy, n_yx, n_yy and n_zz),
  • 48 plots for Ex, Ey, Ez, Hx, Hy and Hz,
  • 8 effective index values, one for each mode,
  • a wavelength sweep of the waveguide (plotting n_eff vs wavelength for each mode),
  • whether a mode is qTE or qTM and the percentage overlap with TE and TM, and
  • the group velocity of the mode.

The waveguide parameters are:

  • thin-film thickness: 1.2um,
  • waveguide height: 800nm,
  • waveguide width: 1.2um,
  • refractive index of waveguide: used Sellmeier equations to get n_xx, n_yy, n_zz at 1550nm,
  • refractive index of substrate: used Sellmeier equation to get SiO2 at 1550nm,
  • refractive index of cladding: 1, and
  • wavelength: 1550nm.

Python script

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.06y_step=0.06wg_height=0.8wg_width=1.8sub_height=1.0sub_width=4.clad_height=1.0film_thickness=1.2angle=60.defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, wg_height, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, angle, n_clad, film_thickness)
n_sub=mat.SiO2().n(wl)
n_wg_xx=mat.Ktp('x').n(wl)
n_wg_yy=mat.Ktp('y').n(wl)
n_wg_zz=mat.Ktp('z').n(wl)
n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
struct_ani.write_to_file()
solver=ms.ModeSolverFullyVectorial(8)
solver.solve(struct_ani)
solver.write_modes_to_file()
solver.solve_ng(struct_ani, 1.55, 0.01)
solver.solve_sweep_wavelength(struct_ani, np.linspace(1.501, 1.60, 21))

Group Velocity

The group velocity at 1550nm for each mode is:

# modes_full_vec/ng.dat
# Mode idx, Group index
0,1.776
1,1.799
2,1.826
3,1.847
4,1.841
5,1.882
6,1.872
7,1.871

Structure

Modes

Only the first 4 (out of 8) modes are shown, and only the E-fields are shown (not H-fields). For the rest of the images, look in the example folder or run the script.

A_{x,y,z} give the percentage power of that particular E-field component with respect to the total of all components.

Mode types:

# modes_full_vec/mode_info
# Mode idx, Mode type, % in major direction, n_eff
0,qTE,97.39,1.643
1,qTM,92.54,1.640
2,qTE,90.60,1.576
3,qTM,91.41,1.571
4,qTE,89.48,1.497
5,qTM,86.70,1.475
6,qTE,89.47,1.447
7,qTM,68.35,1.437

Wavelength Sweep

Example 3: Grating-coupler period

Analytic calculation of the grating coupler period for various duty-cycles in SOI.

Seems to match well with the periods in Taillaert et al., Grating Couplers for Coupling between Optical Fibers and Nanophotonic Waveguides, IOP Science, 2006.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpwls= [1.5, 1.55, 1.6]
x_step=0.05y_step=0.05etch_depth=0.07wg_width=10sub_height=0.5sub_width=14.clad_height=0.5film_thickness=0.22polarisation='TE'dcs=np.linspace(20, 80, 61) /100ed1=etch_depthft1=film_thicknessed2=ft1-ed1ft2=ed2periods= []
periods.append(dcs)
forwlinwls:
ngc= []
fored, ftin [(ed1, ft1), (ed2, ft2)]:
defstruct_func(n_sub, n_wg, n_clad):
returnst.RidgeWaveguide(wl, x_step, y_step, ed, wg_width,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, ft)
n_sub=mat.SiO2().n(wl)
n_wg_xx=3.46n_wg_yy=3.46n_wg_zz=3.46n_clad=mat.Air().n()
struct_xx=struct_func(n_sub, n_wg_xx, n_clad)
struct_yy=struct_func(n_sub, n_wg_yy, n_clad)
struct_zz=struct_func(n_sub, n_wg_zz, n_clad)
struct_ani=st.StructureAni(struct_xx, struct_yy, struct_zz)
#struct_ani.write_to_file()solver=ms.ModeSolverFullyVectorial(4)
solver.solve(struct_ani)
#solver.write_modes_to_file()ifpolarisation=='TE':
ngc.append(np.round(np.real(solver.n_effs_te), 4)[0])
elifpolarisation=='TM':
ngc.append(np.round(np.real(solver.n_effs_tm), 4)[0])
period=de.grating_coupler_period(wl, dcs*ngc[0]+(1-dcs)*ngc[1], n_clad, 8, 1)
periods.append(period)
filename='dc-sweep-%s-%inm-etch-%i-film.dat'% (polarisation, etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.array(periods).T, delimiter=',', header=','.join([str(val) forvalinwls]))
print(np.c_[periods])

Example 4: Mode Hybridisation In SOI

Simulation of mode hybridisation in 220nm thick fully-etched SOI ridge waveguides.

Results look the same as those found in Daoxin Dai and Ming Zhang, "Mode hybridization and conversion in silicon-on-insulator nanowires with angled sidewalls," Opt. Express 23, 32452-32464 (2015).

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportopticalmaterialspyasmatimportnumpyasnpwl=1.55x_step=0.02y_step=0.02etch_depth=0.22wg_widths=np.arange(0.3, 2., 0.05)
sub_height=1.sub_width=4.clad_height=1.film_thickness=0.22n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476r= []
forwinwg_widths:
r.append(st.RidgeWaveguide(wl, x_step, y_step, etch_depth, w,
sub_height, sub_width, clad_height,
n_sub, n_wg, None, n_clad, film_thickness))
solver=ms.ModeSolverFullyVectorial(6)
solver.solve_sweep_structure(r, wg_widths)
solver.write_modes_to_file()

Example 5: Directional Coupler 3dB Length In SOI

Analytic calculation of 3dB coupling length into two parallel SOI waveguides with a varying gap at 3 different TE wavelengths.

An example refractive index profile for the two waveguides spaced 200nm is shown.

importmodesolverpy.mode_solverasmsimportmodesolverpy.structureasstimportmodesolverpy.designasdeimportopticalmaterialspyasmatimportnumpyasnpimporttqdmwls= [1.5, 1.55, 1.6]
x_step=0.02y_step=0.02etch_depth=0.22wg_width=0.44sub_height=0.5sub_width=2.clad_height=0.5film_thickness=0.22gaps=np.linspace(0.1, 0.5, 11)
forwlinwls:
lengths= []
n_sub=mat.SiO2().n(wl)
n_clad=mat.Air().n(wl)
n_wg=3.476forgapintqdm.tqdm(gaps):
r=st.WgArray(wl, x_step, y_step, etch_depth, [wg_width, wg_width], gap,
sub_height, sub_width, clad_height, n_sub, n_wg, None)
#r.write_to_file()solver=ms.ModeSolverFullyVectorial(2)
solver.solve(r)
n1=solver.n_effs_te[0]
n2=solver.n_effs_te[1]
lengths.append(de.directional_coupler_lc(wl*1000, n1, n2)/2)
filename='dc-sweep-%inm-%s-%inm-etch-%i-film.dat'% (wl*1000, 'TE', etch_depth*1000, film_thickness*1000)
np.savetxt(filename, np.c_[gaps, lengths], delimiter=',', header='Coupling lengths (50\%)')

Contributions

If you add functionality, please send me a pull request.

Acknowledgments

This finite difference mode solver is based on a modified version of EMpy.

Thank you to Inna Krasnokutska for testing.

About

Photonic mode solver with a simple interface.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages