{"id":15009889,"url":"https://github.com/jtambasco/modesolverpy","last_synced_at":"2025-08-20T22:32:30.865Z","repository":{"id":57442686,"uuid":"77348694","full_name":"jtambasco/modesolverpy","owner":"jtambasco","description":"Photonic mode solver with a simple interface.","archived":false,"fork":false,"pushed_at":"2022-08-01T11:56:30.000Z","size":49169,"stargazers_count":87,"open_issues_count":5,"forks_count":33,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-07-13T19:45:54.203Z","etag":null,"topics":["mode","mode-solver","photonic-mode-solver","photonics","python","python2","python3","waveguide"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jtambasco.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-12-26T00:52:20.000Z","updated_at":"2025-06-07T22:22:25.000Z","dependencies_parsed_at":"2022-09-26T17:21:18.920Z","dependency_job_id":null,"html_url":"https://github.com/jtambasco/modesolverpy","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/jtambasco/modesolverpy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jtambasco%2Fmodesolverpy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jtambasco%2Fmodesolverpy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jtambasco%2Fmodesolverpy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jtambasco%2Fmodesolverpy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jtambasco","download_url":"https://codeload.github.com/jtambasco/modesolverpy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jtambasco%2Fmodesolverpy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270932588,"owners_count":24670242,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-17T02:00:09.016Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mode","mode-solver","photonic-mode-solver","photonics","python","python2","python3","waveguide"],"created_at":"2024-09-24T19:29:02.379Z","updated_at":"2025-08-20T22:32:30.270Z","avatar_url":"https://github.com/jtambasco.png","language":"Python","readme":"# modesolverpy\nPhotonic mode solver with a nice interface and output.\n* semi-vectorial and fully vectorial options,\n* simple structure drawing,\n* automated data saving and plotting via Gnuplot,\n* some limited (at this stage) data processing (finding MFD of fundamental mode), and\n* easily extensible library\n\nThe documentation for this project can be found [here](http://modesolverpy.rtfd.io).\n\n## Examples\n* [Ex1: Semi-vectorial mode solving of a ridge waveguide](#example-1-semi-vectorial-mode-solving-of-a-ridge-waveguide)\n* [Ex2: Fully vectorial mode solving of an anisotropic material waveguide](#example-2-fully-vectorial-mode-solving-of-anisotropic-material)\n* [Ex3: Grating-coupler period](#example-3-grating-coupler-period)\n* [Ex4: Mode Hybridisation In SOI](#example-4-mode-hybridisation-in-soi)\n* [Ex6: Directional Coupler 3dB Length In SOI](#example-5-directional-coupler-3db-length-in-soi)\n\n## Example 1: Semi-vectorial mode solving of a ridge waveguide\nThe following example finds the first two modes of a waveguide with the following, arbitrary, parameters:\n\n* thin-film thickness: 500nm\n* waveguide height: 400nm,\n* waveguide width: 500nm,\n* refractive index of waveguide: 3,\n* refractive index of substrate: 1.4,\n* refractive index of cladding: 1, and\n* wavelength: 1550nm.\n\n#### Python script\n```python\nimport modesolverpy.mode_solver as ms\nimport modesolverpy.structure as st\nimport numpy as np\n\n# All units are relative.  [um] were chosen in this case.\nx_step = 0.02\ny_step = 0.02\nwg_height = 0.4\nwg_width = 0.5\nsub_height = 0.5\nsub_width = 2.\nclad_height = 0.5\nn_sub = 1.4\nn_wg = 3.\nn_clad = 1.\nfilm_thickness = 0.5\nwavelength = 1.55\nangle = 75.\n\nstructure = st.RidgeWaveguide(wavelength,\n                              x_step,\n                              y_step,\n                              wg_height,\n                              wg_width,\n                              sub_height,\n                              sub_width,\n                              clad_height,\n                              n_sub,\n                              n_wg,\n                              angle,\n                              n_clad,\n                              film_thickness)\n\nstructure.write_to_file('example_structure_1.dat')\n\nmode_solver = ms.ModeSolverSemiVectorial(2, semi_vectorial_method='Ey')\nmode_solver.solve(structure)\nmode_solver.write_modes_to_file('example_modes_1.dat')\n```\n\n#### Structure\n\u003cimg src=\"./examples/modes_semi_vec_ex1/example_structure_1.png \" width=\"400\"\u003e\n\n### Modes\n\u003cimg src=\"./examples/modes_semi_vec_ex1/example_modes_1_Ey_0.png \" width=\"400\"\u003e \u003cimg src=\"./examples/modes_semi_vec_ex1/example_modes_1_Ey_1.png \" width=\"400\"\u003e\n\n## Example 2: Fully vectorial mode solving  of an anisotropic material waveguide\nThe following looks at a contrived ridge waveguide in Z-cut KTP.\n\nThe simulation outputs:\n* 5 plots for each refractive index axis (n_xx, n_xy, n_yx, n_yy and n_zz),\n* 48 plots for Ex, Ey, Ez, Hx, Hy and Hz,\n* 8 effective index values, one for each mode,\n* a wavelength sweep of the waveguide (plotting n_eff vs wavelength for each mode),\n* whether a mode is qTE or qTM and the percentage overlap with TE and TM, and\n* the group velocity of the mode.\n\nThe waveguide parameters are:\n* thin-film thickness: 1.2um,\n* waveguide height: 800nm,\n* waveguide width: 1.2um,\n* refractive index of waveguide: used Sellmeier equations to get n_xx, n_yy, n_zz at 1550nm,\n* refractive index of substrate: used Sellmeier equation to get SiO2 at 1550nm,\n* refractive index of cladding: 1, and\n* wavelength: 1550nm.\n\n### Python script\n```python\nimport modesolverpy.mode_solver as ms\nimport modesolverpy.structure as st\nimport opticalmaterialspy as mat\nimport numpy as np\n\nwl = 1.55\nx_step = 0.06\ny_step = 0.06\nwg_height = 0.8\nwg_width = 1.8\nsub_height = 1.0\nsub_width = 4.\nclad_height = 1.0\nfilm_thickness = 1.2\nangle = 60.\n\ndef struct_func(n_sub, n_wg, n_clad):\n    return st.RidgeWaveguide(wl, x_step, y_step, wg_height, wg_width,\n                             sub_height, sub_width, clad_height,\n                             n_sub, n_wg, angle, n_clad, film_thickness)\n\nn_sub = mat.SiO2().n(wl)\nn_wg_xx = mat.Ktp('x').n(wl)\nn_wg_yy = mat.Ktp('y').n(wl)\nn_wg_zz = mat.Ktp('z').n(wl)\nn_clad = mat.Air().n()\n\nstruct_xx = struct_func(n_sub, n_wg_xx, n_clad)\nstruct_yy = struct_func(n_sub, n_wg_yy, n_clad)\nstruct_zz = struct_func(n_sub, n_wg_zz, n_clad)\n\nstruct_ani = st.StructureAni(struct_xx, struct_yy, struct_zz)\nstruct_ani.write_to_file()\n\nsolver = ms.ModeSolverFullyVectorial(8)\nsolver.solve(struct_ani)\nsolver.write_modes_to_file()\n\nsolver.solve_ng(struct_ani, 1.55, 0.01)\n\nsolver.solve_sweep_wavelength(struct_ani, np.linspace(1.501, 1.60, 21))\n```\n\n### Group Velocity\nThe group velocity at 1550nm for each mode is:\n```\n# modes_full_vec/ng.dat\n# Mode idx, Group index\n0,1.776\n1,1.799\n2,1.826\n3,1.847\n4,1.841\n5,1.882\n6,1.872\n7,1.871\n```\n\n### Structure\n\u003cimg src=\"./examples/modes_full_vec_ex2/material_index/material_index_xx.png \" width=\"250\"\u003e \u003cimg src=\"./examples/modes_full_vec_ex2/material_index/material_index_xy.png \" width=\"250\"\u003e \u003cimg src=\"./examples/modes_full_vec_ex2/material_index/material_index_yx.png \" width=\"250\"\u003e\n\u003cimg src=\"./examples/modes_full_vec_ex2/material_index/material_index_yy.png \" width=\"250\"\u003e \u003cimg src=\"./examples/modes_full_vec_ex2/material_index/material_index_zz.png \" width=\"250\"\u003e\n\n### Modes\nOnly 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.\n\nA_{x,y,z} give the percentage power of that particular E-field component with respect to the total of all components.\n\nMode types:\n```\n# modes_full_vec/mode_info\n# Mode idx, Mode type, % in major direction, n_eff\n0,qTE,97.39,1.643\n1,qTM,92.54,1.640\n2,qTE,90.60,1.576\n3,qTM,91.41,1.571\n4,qTE,89.48,1.497\n5,qTM,86.70,1.475\n6,qTE,89.47,1.447\n7,qTM,68.35,1.437\n```\n\u003cimg src=\"./examples/modes_full_vec_ex2/mode_0/mode_Ex_0.png \" width=\"265\"\u003e \u003cimg src=\"./examples/modes_full_vec_ex2/mode_0/mode_Ey_0.png \" width=\"265\"\u003e \u003cimg src=\"./examples/modes_full_vec_ex2/mode_0/mode_Ez_0.png \" width=\"265\"\u003e\n\u003cimg src=\"./examples/modes_full_vec_ex2/mode_1/mode_Ex_1.png \" width=\"265\"\u003e \u003cimg src=\"./examples/modes_full_vec_ex2/mode_1/mode_Ey_1.png \" width=\"265\"\u003e \u003cimg src=\"./examples/modes_full_vec_ex2/mode_1/mode_Ez_1.png \" width=\"265\"\u003e\n\u003cimg src=\"./examples/modes_full_vec_ex2/mode_2/mode_Ex_2.png \" width=\"265\"\u003e \u003cimg src=\"./examples/modes_full_vec_ex2/mode_2/mode_Ey_2.png \" width=\"265\"\u003e \u003cimg src=\"./examples/modes_full_vec_ex2/mode_2/mode_Ez_2.png \" width=\"265\"\u003e\n\u003cimg src=\"./examples/modes_full_vec_ex2/mode_3/mode_Ex_3.png \" width=\"265\"\u003e \u003cimg src=\"./examples/modes_full_vec_ex2/mode_3/mode_Ey_3.png \" width=\"265\"\u003e \u003cimg src=\"./examples/modes_full_vec_ex2/mode_3/mode_Ez_3.png \" width=\"265\"\u003e\n\n### Wavelength Sweep\n\u003cimg src=\"./examples/modes_full_vec_ex2/wavelength_n_effs.png \" width=\"400\"\u003e\n\n## Example 3: Grating-coupler period\nAnalytic calculation of the grating coupler period for various duty-cycles in SOI.\n\nSeems to match well with the periods in [Taillaert et al., _Grating Couplers for\nCoupling between Optical Fibers and Nanophotonic Waveguides_, IOP Science, 2006](http://iopscience.iop.org/article/10.1143/JJAP.45.6071/meta).\n\n```python\nimport modesolverpy.mode_solver as ms\nimport modesolverpy.structure as st\nimport modesolverpy.design as de\nimport opticalmaterialspy as mat\nimport numpy as np\n\nwls = [1.5, 1.55, 1.6]\nx_step = 0.05\ny_step = 0.05\netch_depth = 0.07\nwg_width = 10\nsub_height = 0.5\nsub_width = 14.\nclad_height = 0.5\nfilm_thickness = 0.22\npolarisation = 'TE'\ndcs = np.linspace(20, 80, 61) / 100\n\ned1 = etch_depth\nft1 = film_thickness\ned2 = ft1 - ed1\nft2 = ed2\n\nperiods = []\nperiods.append(dcs)\n\nfor wl in wls:\n    ngc = []\n    for ed, ft in [(ed1, ft1), (ed2, ft2)]:\n        def struct_func(n_sub, n_wg, n_clad):\n            return st.RidgeWaveguide(wl, x_step, y_step, ed, wg_width,\n                                     sub_height, sub_width, clad_height,\n                                     n_sub, n_wg, None, n_clad, ft)\n\n        n_sub = mat.SiO2().n(wl)\n        n_wg_xx = 3.46\n        n_wg_yy = 3.46\n        n_wg_zz = 3.46\n        n_clad = mat.Air().n()\n\n        struct_xx = struct_func(n_sub, n_wg_xx, n_clad)\n        struct_yy = struct_func(n_sub, n_wg_yy, n_clad)\n        struct_zz = struct_func(n_sub, n_wg_zz, n_clad)\n\n        struct_ani = st.StructureAni(struct_xx, struct_yy, struct_zz)\n        #struct_ani.write_to_file()\n\n        solver = ms.ModeSolverFullyVectorial(4)\n        solver.solve(struct_ani)\n        #solver.write_modes_to_file()\n\n        if polarisation == 'TE':\n            ngc.append(np.round(np.real(solver.n_effs_te), 4)[0])\n        elif polarisation == 'TM':\n            ngc.append(np.round(np.real(solver.n_effs_tm), 4)[0])\n\n    period = de.grating_coupler_period(wl, dcs*ngc[0]+(1-dcs)*ngc[1], n_clad, 8, 1)\n    periods.append(period)\n\nfilename = 'dc-sweep-%s-%inm-etch-%i-film.dat' % (polarisation, etch_depth*1000, film_thickness*1000)\nnp.savetxt(filename, np.array(periods).T, delimiter=',', header=','.join([str(val) for val in wls]))\nprint(np.c_[periods])\n```\n\n\u003cimg src=\"./examples/gc-sweep-soi.png\" width=\"600\"\u003e\n\n## Example 4: Mode Hybridisation In SOI\nSimulation of mode hybridisation in 220nm thick fully-etched SOI ridge\nwaveguides.\n\nResults 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)](https://www.osapublishing.org/oe/abstract.cfm?uri=oe-23-25-32452).\n\n```python\nimport modesolverpy.mode_solver as ms\nimport modesolverpy.structure as st\nimport opticalmaterialspy as mat\nimport numpy as np\n\nwl = 1.55\nx_step = 0.02\ny_step = 0.02\netch_depth = 0.22\nwg_widths = np.arange(0.3, 2., 0.05)\nsub_height = 1.\nsub_width = 4.\nclad_height = 1.\nfilm_thickness = 0.22\n\nn_sub = mat.SiO2().n(wl)\nn_clad = mat.Air().n(wl)\nn_wg = mat.RefractiveIndexWeb(\n    'https://refractiveindex.info/?shelf=main\u0026book=Si\u0026page=Li-293K').n(wl)\n\nr = []\nfor w in wg_widths:\n    r.append(\n        st.RidgeWaveguide(wl, x_step, y_step, etch_depth, w, sub_height,\n                          sub_width, clad_height, n_sub, n_wg, None, n_clad,\n                          film_thickness))\n\nr[0].write_to_file('start_n_profile.dat')\nr[-1].write_to_file('end_n_profile.dat')\n\nsolver = ms.ModeSolverFullyVectorial(6)\nsolver.solve_sweep_structure(r, wg_widths, x_label='Taper width', fraction_mode_list=[1,2])\nsolver.write_modes_to_file()\n```\n\n\u003cimg src=\"./examples/width-sweep/width-sweep-start-n-profile.png\" width=\"300\"\u003e \u003cimg src=\"./examples/width-sweep/width-sweep-end-n-profile.png\" width=\"300\"\u003e\n\u003cimg src=\"./examples/width-sweep/width-sweep-soi.png\" width=\"600\"\u003e\n\n## Example 5: Directional Coupler 3dB Length In SOI\nAnalytic calculation of 3dB coupling length into two parallel SOI waveguides\nwith a varying gap at 3 different TE wavelengths.\n\nAn example refractive index profile for the two waveguides spaced 200nm is\nshown.\n\n```python\nimport modesolverpy.mode_solver as ms\nimport modesolverpy.structure as st\nimport modesolverpy.design as de\nimport opticalmaterialspy as mat\nimport numpy as np\nimport tqdm\n\nwls = [1.5, 1.55, 1.6]\nx_step = 0.02\ny_step = 0.02\netch_depth = 0.22\nwg_width = 0.44\nsub_height = 0.5\nsub_width = 2.\nclad_height = 0.5\nfilm_thickness = 0.22\ngaps = np.linspace(0.1, 0.5, 11)\n\nfor wl in wls:\n    lengths = []\n\n    n_sub = mat.SiO2().n(wl)\n    n_clad = mat.Air().n(wl)\n    n_wg = 3.476\n\n    for gap in tqdm.tqdm(gaps):\n        r = st.WgArray(wl, x_step, y_step, etch_depth, [wg_width, wg_width], gap,\n                       sub_height, sub_width, clad_height, n_sub, n_wg, None)\n        #r.write_to_file()\n\n        solver = ms.ModeSolverFullyVectorial(2)\n        solver.solve(r)\n        n1 = solver.n_effs_te[0]\n        n2 = solver.n_effs_te[1]\n        lengths.append(de.directional_coupler_lc(wl*1000, n1, n2)/2)\n\n    filename = 'dc-sweep-%inm-%s-%inm-etch-%i-film.dat' % (wl*1000, 'TE', etch_depth*1000, film_thickness*1000)\n    np.savetxt(filename, np.c_[gaps, lengths], delimiter=',', header='Coupling lengths (50\\%)')\n```\n\n\u003cimg src=\"./examples/dc-sweep-soi-3db-index-profile-200nm-gap.png\" width=\"600\"\u003e\n\u003cimg src=\"./examples/dc-sweep-soi-3db.png\" width=\"600\"\u003e\n\n## Installation\nIt is recommend to install `modesolverpy` either via:\n\n### Ubuntu/Mint/Debian:\n```bash\npip3 install modesolverpy # or pip2 install modesolverpy\napt install gnuplot\n```\n\n### Arch Linux:\n```bash\nyaourt -S python-modesolverpy\n```\n\n### Dependencies\nIf installing using the [Arch Linux AUR package](https://aur.archlinux.org/packages/python-modesolverpy/) or `pip`, dependencies will be automatically downloaded and installed, if not, one should ensure the following dependencies are installed:\n\nEither 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.\n\n* [setuptools](https://pypi.python.org/pypi/setuptools),\n* [numpy](http://www.numpy.org/),\n* [scipy](https://www.scipy.org/),\n* [tqdm](https://pypi.python.org/pypi/tqdm), and\n* [opticalmaterialspy](https://github.com/jtambasco/opticalmaterialspy).\n\n#### Plotting\nEITHER:\n\n* [Gnuplot](http://www.gnuplot.info/).\n* [gnuplotpy](https://github.com/jtambasco/gnuplotpy),\n\nOR:\n\n* [matplotlib](https://matplotlib.org/),\n\n## Acknowledgments\nThis finite difference mode solver is based on a modified version of [EMpy](https://github.com/lbolla/EMpy).\n\nThank you to [Inna Krasnokutska](https://github.com/ikrasnokutska) for testing.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjtambasco%2Fmodesolverpy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjtambasco%2Fmodesolverpy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjtambasco%2Fmodesolverpy/lists"}