gplugins 2.1.0__tar.gz → 2.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gplugins-2.1.0 → gplugins-2.1.2}/PKG-INFO +20 -12
- {gplugins-2.1.0 → gplugins-2.1.2}/README.md +2 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/__init__.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/tests/test_get_component_with_new_port_layers.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/devsim/doping.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/devsim/get_simulation.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/elmer/get_capacitance.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/elmer/tests/test_elmer.py +1 -1
- gplugins-2.1.2/gplugins/emode/__init__.py +13 -0
- gplugins-2.1.2/gplugins/emode/emode.py +244 -0
- gplugins-2.1.2/gplugins/emode/tests/test_emode.py +218 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/fdtdz/get_epsilon_fdtdz.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/fdtdz/get_ports_fdtdz.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/fdtdz/get_sparameters_fdtdz.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/femwell/mode_solver.py +3 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/femwell/test_mode_solver.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/get_simulation.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/write_sparameters_meep_mpi.py +2 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/dataprep/regions.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/drc/check_width.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/drc/write_drc.py +4 -4
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/tests/test_dataprep_regions.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/lumerical/read.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/lumerical/write_sparameters_lumerical.py +19 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/meshwell/get_meshwell_3D.py +3 -3
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/meshwell/get_meshwell_cross_section.py +3 -3
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/meshwell/tests/test_meshwell.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/palace/get_capacitance.py +3 -3
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/palace/get_scattering.py +3 -3
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/palace/tests/test_palace.py +1 -1
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sentaurus/sde.py +3 -3
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sentaurus/sprocess.py +2 -2
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/component.py +10 -3
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/materials.py +10 -3
- gplugins-2.1.2/gplugins/vlsir/tests/__init__.py +0 -0
- gplugins-2.1.2/gplugins/vlsir/tests/conftest.py +3 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/pyproject.toml +18 -13
- {gplugins-2.1.0 → gplugins-2.1.2}/LICENSE +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/base_models/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/base_models/component.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/base_models/simulation.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/config.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/types.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/add_simulation_markers.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/async_helpers.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/cache.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/convert_sparameters.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/disable_print.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/geometry.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/get_capacitance.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/get_component_with_net_layers.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/get_effective_indices.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/get_scattering.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/get_sparameters_path.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/optical_constants.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/parse_layer_stack.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/plot.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/plot_csv.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/common/utils/port_symmetries.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/devsim/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/devsim/get_simulation_xsection.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/devsim/get_solver.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/devsim/test_devsim.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/elmer/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/elmer/electrostatic.sif.j2 +0 -0
- {gplugins-2.1.0/gplugins/klayout → gplugins-2.1.2/gplugins/emode/tests}/__init__.py +0 -0
- {gplugins-2.1.0/gplugins/klayout → gplugins-2.1.2/gplugins/emode}/tests/conftest.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/fdtdz/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/femwell/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/femwell/solve_thermal.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gfviz/Makefile +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gfviz/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gfviz/b64.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gfviz/gfviz.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gfviz/netlist.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gfviz/serve.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gfviz/static/b64.js +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gfviz/static/schemedit.js +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gfviz/static/schemedit.wasm +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gfviz/templates/example.json +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gfviz/templates/index.html +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/get_material.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/get_meep_geometry.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/get_port_eigenmode.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/get_simulation_grating_farfield.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/get_simulation_grating_fiber.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/meep_adjoint_optimization.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_eigenmode.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_materials.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_sparameterNxN/test_sparameterNxN_crossing.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_sparameterNxN/test_sparameterNxN_straight.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_write_sparameters_meep/test_sparameterNxN_crossing.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_write_sparameters_meep/test_sparameterNxN_straight.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_write_sparameters_meep/test_sparameterNxN_symmetries_straight.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_write_sparameters_meep/test_sparameter_straight_mpi.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_write_sparameters_meep/test_sparameter_straight_mpi_pool.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_write_sparameters_meep/test_sparameters_crossing_symmetric.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_write_sparameters_meep/test_sparameters_straight.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_write_sparameters_meep/test_sparameters_straight_batch.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_write_sparameters_meep/test_sparameters_straight_mpi.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_write_sparameters_meep/test_sparameters_straight_mpi_pool.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_write_sparameters_meep/test_sparameters_straight_symmetric.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/test_write_sparameters_meep.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/write_sparameters_grating.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/write_sparameters_meep.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/gmeep/write_sparameters_meep_batch.py +0 -0
- {gplugins-2.1.0/gplugins/klayout/drc → gplugins-2.1.2/gplugins/klayout}/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/dataprep/__init__.py +0 -0
- {gplugins-2.1.0/gplugins/klayout/tests → gplugins-2.1.2/gplugins/klayout/drc}/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/drc/check_duplicated_cells.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/drc/check_exclusion.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/drc/check_inclusion.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/drc/check_space.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/drc/count_drc.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/drc/samples/drc_errors.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/get_density.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/get_netlist.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/netlist_graph.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/netlist_spice_reader.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/plot_nets.py +0 -0
- {gplugins-2.1.0/gplugins/materials → gplugins-2.1.2/gplugins/klayout/tests}/__init__.py +0 -0
- {gplugins-2.1.0/gplugins/palace → gplugins-2.1.2/gplugins/klayout}/tests/conftest.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/tests/test_density.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/tests/test_drc_exclusion.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/tests/test_drc_inclusion.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/tests/test_drc_space.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/tests/test_drc_width.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/tests/test_global_density.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/tests/test_netlist_spice_reader.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/klayout/tests/test_plot_nets.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/lumerical/README.md +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/lumerical/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/lumerical/interconnect.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/lumerical/mapping_ubcpdk.yml +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/lumerical/settings.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/lumerical/tests/test_lumerical_read_sparameters.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/lumerical/tests/test_netlist.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/lumerical/tests/test_netlist_get_routes.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/lumerical/write_sparameters_lumerical_components.py +0 -0
- {gplugins-2.1.0/gplugins/materials/optical → gplugins-2.1.2/gplugins/materials}/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/materials/inorganic.py +0 -0
- {gplugins-2.1.0/gplugins/materials/semiconductor → gplugins-2.1.2/gplugins/materials/optical}/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/materials/optical/optical_mat.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/materials/optical/refractive_index_info.py +0 -0
- {gplugins-2.1.0/gplugins/palace/tests → gplugins-2.1.2/gplugins/materials/semiconductor}/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/materials/semiconductor/semiconductor_mat.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/meow/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/meow/meow_eme.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/meow/test_meow_simulation.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/meshwell/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/coupler.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/find_coupling_vs_gap.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/find_mode_dispersion.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/find_modes.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/find_modes_cross_section.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/find_neff_ng_dw_dh.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/find_neff_vs_width.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/get_mode_solver_coupler.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/get_mode_solver_cross_section.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/get_mode_solver_rib.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/modes/neff_vs_width_nitride.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/modes/neff_vs_width_rib.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/modes/neff_vs_width_strip.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/neff_convergence_test.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/neff_vs_width.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/overlap.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/tests/test_dw_dh/test_dw_dh.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/tests/test_dw_dh/test_dw_dh.obtained.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/tests/test_dw_dh/test_dw_dh_dispersion.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/tests/test_dw_dh.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/tests/test_find_modes.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/tests/test_find_modes_dispersion.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/tests/test_neff_vs_width/test_neff_vs_width.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/tests/test_neff_vs_width/test_neff_vs_width.obtained.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/tests/test_neff_vs_width.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/types.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/modes/waveguide.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/palace/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/palace/driven.json +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/palace/electrostatic.json +0 -0
- {gplugins-2.1.0/gplugins/process → gplugins-2.1.2/gplugins/palace/tests}/__init__.py +0 -0
- {gplugins-2.1.0/gplugins/sax → gplugins-2.1.2/gplugins/palace}/tests/conftest.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/path_length_analysis/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/path_length_analysis/path_length_analysis.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/path_length_analysis/path_length_analysis_from_gds.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/path_length_analysis/test_pathlength_extraction.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/path_length_analysis/test_pathlength_extraction_from_gds.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/path_length_analysis/test_pathlength_extraction_utils.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/path_length_analysis/utils.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/photonic_circuit_models/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/photonic_circuit_models/coupler.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/photonic_circuit_models/fsr.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/photonic_circuit_models/heater.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/photonic_circuit_models/mzi.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/photonic_circuit_models/ring.py +0 -0
- {gplugins-2.1.0/gplugins/sax/tests → gplugins-2.1.2/gplugins/process}/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/process/diffusion.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/process/implant_tables.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/process/pysrim.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/process/silicon.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/process/skew/antimony_si_skew.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/process/skew/arsenic_si_skew.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/process/skew/boron_si_skew.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/process/skew/phosphorus_si_skew.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sax/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sax/interpolators.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sax/mlp.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sax/models.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sax/parameter.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sax/plot_model.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sax/read.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sax/strategy.py +0 -0
- {gplugins-2.1.0/gplugins/spice → gplugins-2.1.2/gplugins/sax/tests}/__init__.py +0 -0
- {gplugins-2.1.0/gplugins/tidy3d → gplugins-2.1.2/gplugins/sax}/tests/conftest.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sax/tests/test_mzi.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sax/tests/test_mzi_lattice/test_mzi_lattice.obtained.yml +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sax/tests/test_mzi_lattice/test_mzi_lattice.yml +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sax/tests/test_mzi_lattice.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sax/tests/test_parameters.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sentaurus/mask_sde.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sentaurus/mask_sprocess.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sentaurus/sdevice.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/sentaurus/svisual.py +0 -0
- {gplugins-2.1.0/gplugins/spice/tests → gplugins-2.1.2/gplugins/spice}/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/spice/spice_to_yaml.py +0 -0
- {gplugins-2.1.0/gplugins/tidy3d → gplugins-2.1.2/gplugins/spice}/tests/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/spice/tests/test_interconnect.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/get_results.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/get_simulation_grating_coupler.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/modes.py +0 -0
- {gplugins-2.1.0/gplugins/vlsir → gplugins-2.1.2/gplugins/tidy3d}/tests/__init__.py +0 -0
- {gplugins-2.1.0/gplugins/vlsir → gplugins-2.1.2/gplugins/tidy3d}/tests/conftest.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/tests/test_component_modeler.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/tests/test_materials.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/tests/test_modes/test_sweep_width.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/tests/test_modes/test_sweep_width.obtained.csv +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/tests/test_modes_coupler.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/tests/test_modes_waveguide.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/tests/test_plot_simulation_grating_coupler.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/tests/test_write_sparameters.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/tests/tests_sparameters/sim_ref.yaml +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/tests/tests_sparameters/test_write_sparameters.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/tests/tests_sparameters/test_write_sparameters_grating_coupler.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/types.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/util.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/tidy3d/write_sparameters_grating_coupler.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/typings.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/vlsir/__init__.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/vlsir/export_netlist.py +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/vlsir/tests/resources/pads_correct.cir +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/vlsir/tests/resources/pads_correct.scs +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/vlsir/tests/resources/pads_correct.sp +0 -0
- {gplugins-2.1.0 → gplugins-2.1.2}/gplugins/vlsir/tests/test_vlsir.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: gplugins
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.2
|
|
4
4
|
Summary: gdsfactory plugins
|
|
5
5
|
Keywords: python
|
|
6
6
|
Author-email: gdsfactory <contact@gdsfactory.com>
|
|
@@ -17,23 +17,28 @@ Requires-Dist: tqdm
|
|
|
17
17
|
Requires-Dist: numpy>=2.0,<3
|
|
18
18
|
Requires-Dist: xarray==2026.4.0
|
|
19
19
|
Requires-Dist: hypothesis ; extra == "dev"
|
|
20
|
-
Requires-Dist: numba ; extra == "dev"
|
|
20
|
+
Requires-Dist: numba>=0.60 ; extra == "dev"
|
|
21
21
|
Requires-Dist: pre-commit ; extra == "dev"
|
|
22
22
|
Requires-Dist: pyswarms ; extra == "dev"
|
|
23
23
|
Requires-Dist: pytest ; extra == "dev"
|
|
24
24
|
Requires-Dist: pytest-cov ; extra == "dev"
|
|
25
25
|
Requires-Dist: pytest_regressions ; extra == "dev"
|
|
26
26
|
Requires-Dist: devsim ; extra == "devsim"
|
|
27
|
-
Requires-Dist: pyvista<=0.48.
|
|
27
|
+
Requires-Dist: pyvista<=0.48.4 ; extra == "devsim"
|
|
28
28
|
Requires-Dist: tidy3d~=2.11.1 ; extra == "devsim"
|
|
29
|
+
Requires-Dist: jupyter ; extra == "docs"
|
|
29
30
|
Requires-Dist: jupytext ; extra == "docs"
|
|
30
31
|
Requires-Dist: matplotlib ; extra == "docs"
|
|
31
|
-
Requires-Dist:
|
|
32
|
-
Requires-Dist:
|
|
32
|
+
Requires-Dist: nbconvert ; extra == "docs"
|
|
33
|
+
Requires-Dist: mkdocstrings[python] ; extra == "docs"
|
|
34
|
+
Requires-Dist: mkdocs-bibtex ; extra == "docs"
|
|
35
|
+
Requires-Dist: pyvista[all]<=0.48.4 ; extra == "docs"
|
|
33
36
|
Requires-Dist: bokeh ; extra == "docs"
|
|
34
37
|
Requires-Dist: scikit-learn ; extra == "docs"
|
|
38
|
+
Requires-Dist: zensical>=0.0.46,<0.1.0 ; extra == "docs"
|
|
39
|
+
Requires-Dist: emodeconnection>=1.1.11 ; extra == "emode"
|
|
35
40
|
Requires-Dist: femwell~=0.1.11 ; extra == "femwell"
|
|
36
|
-
Requires-Dist: meshwell~=2.1.
|
|
41
|
+
Requires-Dist: meshwell~=2.1.2 ; extra == "femwell"
|
|
37
42
|
Requires-Dist: jinja2 ; extra == "gfviz"
|
|
38
43
|
Requires-Dist: fastapi ; extra == "gfviz"
|
|
39
44
|
Requires-Dist: shapely ; extra == "gfviz"
|
|
@@ -49,14 +54,14 @@ Requires-Dist: mypy ; extra == "maintainer"
|
|
|
49
54
|
Requires-Dist: tbump ; extra == "maintainer"
|
|
50
55
|
Requires-Dist: towncrier ; extra == "maintainer"
|
|
51
56
|
Requires-Dist: meow-sim>=0.15 ; extra == "meow"
|
|
52
|
-
Requires-Dist: sax
|
|
57
|
+
Requires-Dist: sax>=0.17,<0.19 ; extra == "meow"
|
|
53
58
|
Requires-Dist: tidy3d~=2.11.1 ; extra == "meow"
|
|
54
59
|
Requires-Dist: shapely ; extra == "meshwell"
|
|
55
|
-
Requires-Dist: meshwell~=2.1.
|
|
60
|
+
Requires-Dist: meshwell~=2.1.2 ; extra == "meshwell"
|
|
56
61
|
Requires-Dist: bokeh ; extra == "path-length-analysis"
|
|
57
|
-
Requires-Dist: numba ; extra == "path-length-analysis"
|
|
62
|
+
Requires-Dist: numba>=0.60 ; extra == "path-length-analysis"
|
|
58
63
|
Requires-Dist: shapely ; extra == "path-length-analysis"
|
|
59
|
-
Requires-Dist: sax
|
|
64
|
+
Requires-Dist: sax>=0.17,<0.19 ; extra == "sax"
|
|
60
65
|
Requires-Dist: bokeh ; extra == "schematic"
|
|
61
66
|
Requires-Dist: ipywidgets ; extra == "schematic"
|
|
62
67
|
Requires-Dist: natsort ; extra == "schematic"
|
|
@@ -68,6 +73,7 @@ Requires-Dist: vlsirtools ; extra == "vlsir"
|
|
|
68
73
|
Provides-Extra: dev
|
|
69
74
|
Provides-Extra: devsim
|
|
70
75
|
Provides-Extra: docs
|
|
76
|
+
Provides-Extra: emode
|
|
71
77
|
Provides-Extra: femwell
|
|
72
78
|
Provides-Extra: gfviz
|
|
73
79
|
Provides-Extra: klayout
|
|
@@ -80,8 +86,9 @@ Provides-Extra: sax
|
|
|
80
86
|
Provides-Extra: schematic
|
|
81
87
|
Provides-Extra: tidy3d
|
|
82
88
|
Provides-Extra: vlsir
|
|
89
|
+
Import-Name: gplugins
|
|
83
90
|
|
|
84
|
-
# gplugins 2.1.
|
|
91
|
+
# gplugins 2.1.2
|
|
85
92
|
|
|
86
93
|
[](https://gdsfactory.github.io/gplugins/)
|
|
87
94
|
[](https://pypi.org/project/gplugins/)
|
|
@@ -111,6 +118,7 @@ Run simulations with GDSFactory by installing plugins.
|
|
|
111
118
|
- Tidy3d
|
|
112
119
|
- Femwell
|
|
113
120
|
- MPB
|
|
121
|
+
- `EMode` Finite Difference Method (FDM) mode solver with EME propagation (commercial).
|
|
114
122
|
- TCAD
|
|
115
123
|
- `devsim` TCAD device simulator.
|
|
116
124
|
- Circuit simulations
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# gplugins 2.1.
|
|
1
|
+
# gplugins 2.1.2
|
|
2
2
|
|
|
3
3
|
[](https://gdsfactory.github.io/gplugins/)
|
|
4
4
|
[](https://pypi.org/project/gplugins/)
|
|
@@ -28,6 +28,7 @@ Run simulations with GDSFactory by installing plugins.
|
|
|
28
28
|
- Tidy3d
|
|
29
29
|
- Femwell
|
|
30
30
|
- MPB
|
|
31
|
+
- `EMode` Finite Difference Method (FDM) mode solver with EME propagation (commercial).
|
|
31
32
|
- TCAD
|
|
32
33
|
- `devsim` TCAD device simulator.
|
|
33
34
|
- Circuit simulations
|
|
@@ -230,7 +230,7 @@ def create_2Duz_simulation(
|
|
|
230
230
|
|
|
231
231
|
if __name__ == "__main__":
|
|
232
232
|
import gdsfactory as gf
|
|
233
|
-
from gdsfactory.
|
|
233
|
+
from gdsfactory.gpdk import LAYER, LAYER_STACK
|
|
234
234
|
|
|
235
235
|
# We choose a representative subdomain of the component
|
|
236
236
|
waveguide = gf.Component()
|
|
@@ -11,7 +11,7 @@ from typing import Any
|
|
|
11
11
|
|
|
12
12
|
import gdsfactory as gf
|
|
13
13
|
import gmsh
|
|
14
|
-
from gdsfactory.
|
|
14
|
+
from gdsfactory.gpdk import LAYER_STACK
|
|
15
15
|
from gdsfactory.technology import LayerStack
|
|
16
16
|
from jinja2 import Environment, FileSystemLoader
|
|
17
17
|
from numpy import isfinite
|
|
@@ -4,7 +4,7 @@ import gdsfactory as gf
|
|
|
4
4
|
import pytest
|
|
5
5
|
from gdsfactory.component import Component
|
|
6
6
|
from gdsfactory.components import interdigital_capacitor_enclosed
|
|
7
|
-
from gdsfactory.
|
|
7
|
+
from gdsfactory.gpdk import LAYER
|
|
8
8
|
from gdsfactory.technology import LayerStack
|
|
9
9
|
from gdsfactory.technology.layer_stack import LayerLevel
|
|
10
10
|
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"""gdsfactory interface to EMode Photonix.
|
|
2
|
+
|
|
3
|
+
EMode is a commercial photonic simulation package with an electromagnetic
|
|
4
|
+
waveguide mode solver (FDM), eigenmode expansion propagation (EME), nonlinear
|
|
5
|
+
photonics, and thermal/electrical FEM solvers.
|
|
6
|
+
See https://docs.emodephotonix.com for the full API.
|
|
7
|
+
|
|
8
|
+
This module translates gdsfactory objects (:class:`~gdsfactory.CrossSection`,
|
|
9
|
+
:class:`~gdsfactory.technology.LayerStack`) into EMode geometry. The
|
|
10
|
+
translation itself is implemented as pure functions
|
|
11
|
+
(:func:`get_emode_settings`, :func:`get_shapes_from_layer_stack`) that only
|
|
12
|
+
require the pip-installable ``emodeconnection`` client. Creating an
|
|
13
|
+
:class:`EMode` session and running solvers requires a local EMode installation
|
|
14
|
+
and license.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from collections.abc import Sequence
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
import emodeconnection as emc
|
|
23
|
+
import gdsfactory as gf
|
|
24
|
+
from gdsfactory.technology import LayerLevel, LayerStack
|
|
25
|
+
from gdsfactory.typings import CrossSectionSpec, LayerSpec
|
|
26
|
+
|
|
27
|
+
UM_TO_NM = 1e3
|
|
28
|
+
|
|
29
|
+
DIMENSIONAL_SETTINGS = frozenset(
|
|
30
|
+
{
|
|
31
|
+
"wavelength",
|
|
32
|
+
"x_resolution",
|
|
33
|
+
"y_resolution",
|
|
34
|
+
"window_width",
|
|
35
|
+
"window_height",
|
|
36
|
+
"bend_radius",
|
|
37
|
+
"expansion_resolution",
|
|
38
|
+
"expansion_size",
|
|
39
|
+
"propagation_resolution",
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_emode_settings(**settings: Any) -> dict[str, Any]:
|
|
45
|
+
"""Convert gdsfactory-style settings to EMode units.
|
|
46
|
+
|
|
47
|
+
gdsfactory uses microns for all dimensions while EMode defaults to
|
|
48
|
+
nanometers. Settings named in ``DIMENSIONAL_SETTINGS`` are converted from
|
|
49
|
+
um to nm; all other settings pass through unchanged.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
settings: keyword arguments for EMode's ``settings()`` function,
|
|
53
|
+
with dimensional values in um.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
The same settings with dimensional values converted to nm.
|
|
57
|
+
"""
|
|
58
|
+
return {
|
|
59
|
+
key: value * UM_TO_NM
|
|
60
|
+
if key in DIMENSIONAL_SETTINGS and value is not None
|
|
61
|
+
else value
|
|
62
|
+
for key, value in settings.items()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def get_emode_material(material: str, materials: Sequence[str]) -> str:
|
|
67
|
+
"""Match a gdsfactory material name to the EMode material database.
|
|
68
|
+
|
|
69
|
+
Matching is case-insensitive (e.g. gdsfactory's ``si`` matches EMode's
|
|
70
|
+
``Si``). If no match is found the name is returned unchanged so EMode can
|
|
71
|
+
report an informative error for genuinely unknown materials.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
material: gdsfactory material name.
|
|
75
|
+
materials: available EMode material names, from ``EMode.get('materials')``.
|
|
76
|
+
"""
|
|
77
|
+
return next((m for m in materials if m.lower() == material.lower()), material)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _layer_tuple(layer: LayerSpec) -> tuple[int, int] | None:
|
|
81
|
+
"""Resolve a layer spec to a (layer, datatype) tuple via the active PDK.
|
|
82
|
+
|
|
83
|
+
Returns None for layers that cannot be resolved to a single GDS layer
|
|
84
|
+
(e.g. unresolved DerivedLayer expressions).
|
|
85
|
+
"""
|
|
86
|
+
# LogicalLayer and DerivedLayer wrap the underlying spec in .layer.
|
|
87
|
+
layer = getattr(layer, "layer", layer)
|
|
88
|
+
try:
|
|
89
|
+
return gf.get_layer_tuple(layer)
|
|
90
|
+
except (KeyError, TypeError, ValueError):
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _level_layer_tuple(level: LayerLevel) -> tuple[int, int] | None:
|
|
95
|
+
"""Resolve a layer level to a (layer, datatype) tuple.
|
|
96
|
+
|
|
97
|
+
The derived layer takes precedence over the source layer, since it is the
|
|
98
|
+
physically meaningful output of a derived-layer boolean operation.
|
|
99
|
+
"""
|
|
100
|
+
return _layer_tuple(level.derived_layer or level.layer)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def get_shapes_from_layer_stack(
|
|
104
|
+
cross_section: CrossSectionSpec,
|
|
105
|
+
layer_stack: LayerStack,
|
|
106
|
+
materials: Sequence[str] = (),
|
|
107
|
+
) -> list[dict[str, Any]]:
|
|
108
|
+
"""Translate a gdsfactory layer stack and cross-section into EMode shapes.
|
|
109
|
+
|
|
110
|
+
Each :class:`~gdsfactory.technology.LayerLevel` becomes one EMode shape.
|
|
111
|
+
A layer whose ``layer`` (or ``derived_layer``) matches a section of the
|
|
112
|
+
cross-section is patterned: it takes its mask width and offset from that
|
|
113
|
+
section and is etched through its full thickness. Layers without a
|
|
114
|
+
matching section become blanket layers (no mask or etch, following the
|
|
115
|
+
defaults of EMode's ``shape()`` function). Vertical positions are
|
|
116
|
+
referenced to the bottom of the layer stack, and gdsfactory mesh order
|
|
117
|
+
(lower = higher priority) is converted to EMode shape priority (higher =
|
|
118
|
+
higher priority).
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
cross_section: gdsfactory cross-section (or spec) defining mask
|
|
122
|
+
widths and offsets.
|
|
123
|
+
layer_stack: gdsfactory LayerStack defining layer materials,
|
|
124
|
+
thicknesses, and vertical placement.
|
|
125
|
+
materials: available EMode material names used to match gdsfactory
|
|
126
|
+
material names case-insensitively, typically from
|
|
127
|
+
``EMode.get('materials')``.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
One dict of keyword arguments for EMode's ``shape()`` function per
|
|
131
|
+
layer, in layer-stack order, with dimensions in nm.
|
|
132
|
+
"""
|
|
133
|
+
if not layer_stack.layers:
|
|
134
|
+
raise ValueError("layer_stack must contain at least one layer.")
|
|
135
|
+
|
|
136
|
+
xs = gf.get_cross_section(cross_section)
|
|
137
|
+
|
|
138
|
+
max_order = max(level.mesh_order for level in layer_stack.layers.values())
|
|
139
|
+
min_zmin = min(level.zmin for level in layer_stack.layers.values())
|
|
140
|
+
|
|
141
|
+
shapes: list[dict[str, Any]] = []
|
|
142
|
+
for name, level in layer_stack.layers.items():
|
|
143
|
+
if level.material is None:
|
|
144
|
+
raise ValueError(
|
|
145
|
+
f"Layer {name!r} has no material defined in the layer stack."
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
shape: dict[str, Any] = {
|
|
149
|
+
"name": name,
|
|
150
|
+
"material": get_emode_material(level.material, materials),
|
|
151
|
+
"height": level.thickness * UM_TO_NM,
|
|
152
|
+
"sidewall_angle": level.sidewall_angle,
|
|
153
|
+
"position": [0.0, (level.zmin - min_zmin + level.thickness / 2) * UM_TO_NM],
|
|
154
|
+
"priority": max_order - level.mesh_order + 1,
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
level_layer = _level_layer_tuple(level)
|
|
158
|
+
section = next(
|
|
159
|
+
(
|
|
160
|
+
s
|
|
161
|
+
for s in xs.sections
|
|
162
|
+
if level_layer is not None and _layer_tuple(s.layer) == level_layer
|
|
163
|
+
),
|
|
164
|
+
None,
|
|
165
|
+
)
|
|
166
|
+
if section is not None:
|
|
167
|
+
shape["mask"] = section.width * UM_TO_NM
|
|
168
|
+
shape["mask_offset"] = section.offset * UM_TO_NM
|
|
169
|
+
shape["etch_depth"] = level.thickness * UM_TO_NM
|
|
170
|
+
|
|
171
|
+
shapes.append(shape)
|
|
172
|
+
|
|
173
|
+
return shapes
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class EMode(emc.EMode):
|
|
177
|
+
"""EMode session with gdsfactory geometry helpers.
|
|
178
|
+
|
|
179
|
+
Creating an instance launches the EMode application and connects to it,
|
|
180
|
+
so it requires a local EMode installation and license (the
|
|
181
|
+
``emodeconnection`` client alone is not enough). Any EMode function can
|
|
182
|
+
be called as a method, e.g. ``FDM()``, ``EME()``, ``report()``,
|
|
183
|
+
``plot()``; see https://docs.emodephotonix.com for the full API.
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
def build_waveguide(
|
|
187
|
+
self,
|
|
188
|
+
cross_section: CrossSectionSpec,
|
|
189
|
+
layer_stack: LayerStack,
|
|
190
|
+
**settings: Any,
|
|
191
|
+
) -> None:
|
|
192
|
+
"""Build a waveguide in this EMode session from gdsfactory geometry.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
cross_section: gdsfactory cross-section (or spec) defining mask
|
|
196
|
+
widths and offsets.
|
|
197
|
+
layer_stack: gdsfactory LayerStack defining layer materials,
|
|
198
|
+
thicknesses, and vertical placement.
|
|
199
|
+
settings: forwarded to EMode's ``settings()`` function, with
|
|
200
|
+
dimensional values in um (see :func:`get_emode_settings`).
|
|
201
|
+
"""
|
|
202
|
+
self.settings(**get_emode_settings(**settings))
|
|
203
|
+
materials = self.get("materials")
|
|
204
|
+
for shape in get_shapes_from_layer_stack(cross_section, layer_stack, materials):
|
|
205
|
+
self.shape(**shape)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
if __name__ == "__main__":
|
|
209
|
+
# Silicon-on-insulator rib waveguide example.
|
|
210
|
+
# Requires a local EMode installation and license.
|
|
211
|
+
from gdsfactory.gpdk import LAYER_STACK
|
|
212
|
+
|
|
213
|
+
layer_stack = LayerStack(
|
|
214
|
+
layers={
|
|
215
|
+
k: LAYER_STACK.layers[k].model_copy()
|
|
216
|
+
for k in ("core", "clad", "slab90", "box")
|
|
217
|
+
}
|
|
218
|
+
)
|
|
219
|
+
layer_stack.layers["core"].thickness = 0.22
|
|
220
|
+
layer_stack.layers["core"].zmin = 0.0
|
|
221
|
+
layer_stack.layers["slab90"].thickness = 0.09
|
|
222
|
+
layer_stack.layers["slab90"].zmin = 0.0
|
|
223
|
+
layer_stack.layers["box"].thickness = 1.5
|
|
224
|
+
layer_stack.layers["box"].zmin = -1.5
|
|
225
|
+
layer_stack.layers["clad"].thickness = 1.5
|
|
226
|
+
layer_stack.layers["clad"].zmin = 0.0
|
|
227
|
+
|
|
228
|
+
em = EMode()
|
|
229
|
+
em.build_waveguide(
|
|
230
|
+
cross_section=gf.cross_section.rib(width=0.6),
|
|
231
|
+
layer_stack=layer_stack,
|
|
232
|
+
wavelength=1.55,
|
|
233
|
+
num_modes=1,
|
|
234
|
+
x_resolution=0.010,
|
|
235
|
+
y_resolution=0.010,
|
|
236
|
+
window_width=3.0,
|
|
237
|
+
window_height=3.0,
|
|
238
|
+
background_material="Air",
|
|
239
|
+
max_effective_index=2.631,
|
|
240
|
+
)
|
|
241
|
+
em.FDM()
|
|
242
|
+
em.report()
|
|
243
|
+
em.plot()
|
|
244
|
+
em.close()
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"""CI-safe tests for the EMode plugin.
|
|
2
|
+
|
|
3
|
+
These tests only require the pip-installable ``emodeconnection`` client. They
|
|
4
|
+
exercise the pure gdsfactory-to-EMode translation functions and use a stub
|
|
5
|
+
session to test ``EMode.build_waveguide`` without launching the EMode
|
|
6
|
+
application (which requires a separate installation and license).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
import pytest
|
|
14
|
+
|
|
15
|
+
pytest.importorskip("emodeconnection")
|
|
16
|
+
|
|
17
|
+
import gdsfactory as gf
|
|
18
|
+
from gdsfactory.gpdk import LAYER_STACK
|
|
19
|
+
from gdsfactory.technology import LayerStack
|
|
20
|
+
|
|
21
|
+
from gplugins.emode import (
|
|
22
|
+
EMode,
|
|
23
|
+
get_emode_settings,
|
|
24
|
+
get_shapes_from_layer_stack,
|
|
25
|
+
)
|
|
26
|
+
from gplugins.emode.emode import DIMENSIONAL_SETTINGS, get_emode_material
|
|
27
|
+
|
|
28
|
+
EMODE_MATERIALS = ["Air", "Si", "SiO2", "Si3N4"]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.fixture
|
|
32
|
+
def layer_stack() -> LayerStack:
|
|
33
|
+
"""Silicon-on-insulator rib stack with pinned dimensions and mesh orders."""
|
|
34
|
+
updates = {
|
|
35
|
+
"core": {"thickness": 0.22, "zmin": 0.0, "mesh_order": 1},
|
|
36
|
+
"slab90": {"thickness": 0.09, "zmin": 0.0, "mesh_order": 2},
|
|
37
|
+
"clad": {"thickness": 1.5, "zmin": 0.0, "mesh_order": 9},
|
|
38
|
+
"box": {"thickness": 1.5, "zmin": -1.5, "mesh_order": 8},
|
|
39
|
+
}
|
|
40
|
+
return LayerStack(
|
|
41
|
+
layers={
|
|
42
|
+
name: LAYER_STACK.layers[name].model_copy(update=update)
|
|
43
|
+
for name, update in updates.items()
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class FakeEMode(EMode):
|
|
49
|
+
"""EMode session that records calls instead of launching the application."""
|
|
50
|
+
|
|
51
|
+
def __init__(self) -> None:
|
|
52
|
+
"""Initialize without calling super().__init__, which launches the app."""
|
|
53
|
+
self.recorded_settings: list[dict[str, Any]] = []
|
|
54
|
+
self.recorded_shapes: list[dict[str, Any]] = []
|
|
55
|
+
|
|
56
|
+
def settings(self, **kwargs: Any) -> None:
|
|
57
|
+
self.recorded_settings.append(kwargs)
|
|
58
|
+
|
|
59
|
+
def shape(self, **kwargs: Any) -> None:
|
|
60
|
+
self.recorded_shapes.append(kwargs)
|
|
61
|
+
|
|
62
|
+
def get(self, key: str) -> list[str]:
|
|
63
|
+
assert key == "materials"
|
|
64
|
+
return list(EMODE_MATERIALS)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_get_emode_settings_converts_dimensional_values() -> None:
|
|
68
|
+
settings = get_emode_settings(
|
|
69
|
+
wavelength=1.55,
|
|
70
|
+
window_width=3.0,
|
|
71
|
+
num_modes=2,
|
|
72
|
+
background_material="Air",
|
|
73
|
+
)
|
|
74
|
+
assert settings["wavelength"] == pytest.approx(1550.0)
|
|
75
|
+
assert settings["window_width"] == pytest.approx(3000.0)
|
|
76
|
+
assert settings["num_modes"] == 2
|
|
77
|
+
assert settings["background_material"] == "Air"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_get_emode_settings_passes_none_through() -> None:
|
|
81
|
+
settings = get_emode_settings(wavelength=1.55, bend_radius=None)
|
|
82
|
+
assert settings["wavelength"] == pytest.approx(1550.0)
|
|
83
|
+
assert settings["bend_radius"] is None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@pytest.mark.parametrize("key", sorted(DIMENSIONAL_SETTINGS))
|
|
87
|
+
def test_get_emode_settings_converts_every_dimensional_key(key: str) -> None:
|
|
88
|
+
settings = get_emode_settings(**{key: 1.0})
|
|
89
|
+
assert settings[key] == pytest.approx(1000.0)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_get_emode_material_matches_case_insensitively() -> None:
|
|
93
|
+
assert get_emode_material("si", EMODE_MATERIALS) == "Si"
|
|
94
|
+
assert get_emode_material("SIO2", EMODE_MATERIALS) == "SiO2"
|
|
95
|
+
assert get_emode_material("unknown_material", EMODE_MATERIALS) == "unknown_material"
|
|
96
|
+
assert get_emode_material("si", ()) == "si"
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_shapes_one_per_layer_in_order(layer_stack: LayerStack) -> None:
|
|
100
|
+
shapes = get_shapes_from_layer_stack("rib", layer_stack)
|
|
101
|
+
assert [shape["name"] for shape in shapes] == list(layer_stack.layers)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_shapes_mask_from_cross_section(layer_stack: LayerStack) -> None:
|
|
105
|
+
shapes = {
|
|
106
|
+
shape["name"]: shape
|
|
107
|
+
for shape in get_shapes_from_layer_stack(
|
|
108
|
+
gf.cross_section.rib(width=0.6), layer_stack
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
# The core layer matches the WG section of the rib cross-section, so it
|
|
112
|
+
# is patterned: masked and etched through its full thickness.
|
|
113
|
+
assert shapes["core"]["mask"] == pytest.approx(600.0)
|
|
114
|
+
assert shapes["core"]["mask_offset"] == pytest.approx(0.0)
|
|
115
|
+
assert shapes["core"]["etch_depth"] == pytest.approx(220.0)
|
|
116
|
+
# Layers without a matching section are blanket layers with no mask/etch.
|
|
117
|
+
assert "mask" not in shapes["box"]
|
|
118
|
+
assert "mask_offset" not in shapes["box"]
|
|
119
|
+
assert "etch_depth" not in shapes["box"]
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_shapes_mask_offset_from_cross_section(layer_stack: LayerStack) -> None:
|
|
123
|
+
xs = gf.CrossSection(sections=(gf.Section(width=0.5, offset=0.1, layer="WG"),))
|
|
124
|
+
shapes = {
|
|
125
|
+
shape["name"]: shape for shape in get_shapes_from_layer_stack(xs, layer_stack)
|
|
126
|
+
}
|
|
127
|
+
assert shapes["core"]["mask"] == pytest.approx(500.0)
|
|
128
|
+
assert shapes["core"]["mask_offset"] == pytest.approx(100.0)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_shapes_match_section_by_layer_tuple(layer_stack: LayerStack) -> None:
|
|
132
|
+
# Layer specs are normalized through the PDK, so a section defined with a
|
|
133
|
+
# (layer, datatype) tuple matches a layer stack that uses layer names.
|
|
134
|
+
wg_tuple = gf.get_layer_tuple("WG")
|
|
135
|
+
xs = gf.CrossSection(sections=(gf.Section(width=0.5, layer=wg_tuple),))
|
|
136
|
+
shapes = {
|
|
137
|
+
shape["name"]: shape for shape in get_shapes_from_layer_stack(xs, layer_stack)
|
|
138
|
+
}
|
|
139
|
+
assert shapes["core"]["mask"] == pytest.approx(500.0)
|
|
140
|
+
assert "mask" not in shapes["clad"]
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_shapes_positions_relative_to_stack_bottom(layer_stack: LayerStack) -> None:
|
|
144
|
+
shapes = {
|
|
145
|
+
shape["name"]: shape
|
|
146
|
+
for shape in get_shapes_from_layer_stack("rib", layer_stack)
|
|
147
|
+
}
|
|
148
|
+
# min zmin is -1.5 (box), so the box spans 0..1500 nm with center at 750 nm.
|
|
149
|
+
assert shapes["box"]["position"] == pytest.approx([0.0, 750.0])
|
|
150
|
+
assert shapes["core"]["position"] == pytest.approx([0.0, 1610.0])
|
|
151
|
+
assert shapes["slab90"]["position"] == pytest.approx([0.0, 1545.0])
|
|
152
|
+
assert shapes["clad"]["position"] == pytest.approx([0.0, 2250.0])
|
|
153
|
+
assert shapes["core"]["height"] == pytest.approx(220.0)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_shapes_priority_from_mesh_order(layer_stack: LayerStack) -> None:
|
|
157
|
+
shapes = {
|
|
158
|
+
shape["name"]: shape
|
|
159
|
+
for shape in get_shapes_from_layer_stack("rib", layer_stack)
|
|
160
|
+
}
|
|
161
|
+
# gdsfactory mesh order (lower = higher priority) maps to EMode priority
|
|
162
|
+
# (higher = higher priority): priority = max_order - mesh_order + 1.
|
|
163
|
+
assert shapes["core"]["priority"] == 9
|
|
164
|
+
assert shapes["slab90"]["priority"] == 8
|
|
165
|
+
assert shapes["box"]["priority"] == 2
|
|
166
|
+
assert shapes["clad"]["priority"] == 1
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def test_shapes_match_materials(layer_stack: LayerStack) -> None:
|
|
170
|
+
shapes = {
|
|
171
|
+
shape["name"]: shape
|
|
172
|
+
for shape in get_shapes_from_layer_stack("rib", layer_stack, EMODE_MATERIALS)
|
|
173
|
+
}
|
|
174
|
+
assert shapes["core"]["material"] == "Si"
|
|
175
|
+
assert shapes["box"]["material"] == "SiO2"
|
|
176
|
+
|
|
177
|
+
# Without a material list, gdsfactory names pass through unchanged.
|
|
178
|
+
shapes = {
|
|
179
|
+
shape["name"]: shape
|
|
180
|
+
for shape in get_shapes_from_layer_stack("rib", layer_stack)
|
|
181
|
+
}
|
|
182
|
+
assert shapes["core"]["material"] == "si"
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def test_empty_layer_stack_raises() -> None:
|
|
186
|
+
with pytest.raises(ValueError, match="at least one layer"):
|
|
187
|
+
get_shapes_from_layer_stack("rib", LayerStack(layers={}))
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def test_layer_without_material_raises(layer_stack: LayerStack) -> None:
|
|
191
|
+
layer_stack.layers["core"] = layer_stack.layers["core"].model_copy(
|
|
192
|
+
update={"material": None}
|
|
193
|
+
)
|
|
194
|
+
with pytest.raises(ValueError, match="core"):
|
|
195
|
+
get_shapes_from_layer_stack("rib", layer_stack)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def test_build_waveguide_forwards_to_session(layer_stack: LayerStack) -> None:
|
|
199
|
+
em = FakeEMode()
|
|
200
|
+
em.build_waveguide(
|
|
201
|
+
cross_section="rib",
|
|
202
|
+
layer_stack=layer_stack,
|
|
203
|
+
wavelength=1.55,
|
|
204
|
+
num_modes=2,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
assert len(em.recorded_settings) == 1
|
|
208
|
+
assert em.recorded_settings[0]["wavelength"] == pytest.approx(1550.0)
|
|
209
|
+
assert em.recorded_settings[0]["num_modes"] == 2
|
|
210
|
+
|
|
211
|
+
shapes = {shape["name"]: shape for shape in em.recorded_shapes}
|
|
212
|
+
assert set(shapes) == set(layer_stack.layers)
|
|
213
|
+
# Materials from the session are used to match gdsfactory material names.
|
|
214
|
+
assert shapes["core"]["material"] == "Si"
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
if __name__ == "__main__":
|
|
218
|
+
pytest.main([__file__, "-v"])
|
|
@@ -190,7 +190,7 @@ def plot_mode(
|
|
|
190
190
|
|
|
191
191
|
if __name__ == "__main__":
|
|
192
192
|
import gdsfactory as gf
|
|
193
|
-
from gdsfactory.
|
|
193
|
+
from gdsfactory.gpdk import LAYER, LAYER_STACK
|
|
194
194
|
|
|
195
195
|
from gplugins.fdtdz.get_epsilon_fdtdz import component_to_epsilon_pjz
|
|
196
196
|
|