├── .gitignore ├── DEVICE ├── electro_optic │ ├── charge_region.py │ ├── electrostatics │ │ ├── get_Efield_static_2D.py │ │ └── get_index_change_2D.py │ ├── feem_region.py │ ├── mode_profile │ │ └── mode_index.py │ ├── user_inputs │ │ ├── user_materials.py │ │ └── user_simulation_parameters.py │ └── waveguide_render.py └── pin_modulator │ ├── analytical_calculations │ └── capacitance_analytical.py │ ├── charge_distribution │ ├── get_band_potential.py │ ├── get_charge_1D.py │ └── get_junction_width.py │ ├── charge_region.py │ ├── dc_sweep │ ├── getDC_RC.py │ └── voltage_sweep.py │ ├── user_inputs │ ├── user_materials.py │ ├── user_simulation_parameters.py │ └── user_sweep_parameters.py │ └── waveguide_render.py ├── FDTD ├── README.md ├── adiabatic_directional_coupler │ ├── fields │ │ └── getFields.py │ ├── gap_sweep │ │ └── getGapSweep.py │ ├── transmission │ │ └── getFrequencyResponse.py │ └── user_inputs │ │ ├── lumerical_files │ │ └── sbend_adiabatic_directional_coupler.fsp │ │ └── user_simulation_parameters.py ├── adiabatic_y_branch │ ├── fields │ │ └── getFields.py │ ├── gap_sweep │ │ └── getGapSweep.py │ ├── length_sweep │ │ └── getLengthSweep.py │ ├── transmission │ │ └── getFrequencyResponse.py │ └── user_inputs │ │ ├── lumerical_files │ │ └── adiabatic_y_branch.fsp │ │ └── user_simulation_parameters.py ├── directional-coupler │ └── user_inputs │ │ └── lumerical_files │ │ └── sbend_directional_coupler.fsp ├── disk_resonator_coupler │ ├── fields │ │ └── getFields.py │ ├── gap_sweep │ │ └── getGapSweep.py │ ├── index_profile │ │ └── index_profile_2D.py │ ├── override_disk_coupler_region.py │ ├── override_fdtd_region.py │ ├── transmission │ │ └── getFrequencyResponse.py │ └── user_inputs │ │ ├── lumerical_files │ │ └── straight_disk_coupling_section.fsp │ │ └── user_simulation_parameters.py ├── edge_coupler │ ├── fields │ │ └── getFields.py │ ├── index_profile │ │ └── index_profile_2D.py │ ├── override_edge_coupler_region.py │ ├── override_fdtd_region.py │ ├── tip_sweep │ │ └── getTipSweep.py │ ├── transmission │ │ └── getFrequencyResponse.py │ └── user_inputs │ │ ├── lumerical_files │ │ └── edge_taper.fsp │ │ └── user_simulation_parameters.py ├── grating_coupler_2D │ ├── README.md │ ├── analytical │ │ └── 1D_grating_coupler_design.ipynb │ ├── index_profile │ │ └── index_profile_2D.py │ ├── override_fdtd_region.py │ ├── override_grating_coupler_region.py │ ├── sweep_functions │ │ ├── getFiberAngle.py │ │ ├── getFiberPosition.py │ │ └── getFillFactorSweep.py │ ├── transmission │ │ └── getFrequencyResponse.py │ └── user_inputs │ │ ├── lumerical_files │ │ └── grating_coupler_2D.fsp │ │ └── user_simulation_parameters.py ├── grating_coupler_rectangular_3D │ ├── README.md │ ├── analytical │ │ └── 1D_grating_coupler_design.ipynb │ ├── index_profile │ │ └── index_profile_2D.py │ ├── override_fdtd_region.py │ ├── override_grating_coupler_region.py │ ├── sweep_functions │ │ ├── getFiberAngle.py │ │ ├── getFiberPosition.py │ │ └── getFillFactorSweep.py │ ├── transmission │ │ └── getFrequencyResponse.py │ └── user_inputs │ │ ├── lumerical_files │ │ └── grating_coupler_rectangular_3D.fsp │ │ └── user_simulation_parameters.py ├── laser_tapered_waveguide │ ├── fields │ │ └── getFields.py │ └── user_inputs │ │ └── lumerical_files │ │ └── laser_mesa_waveguide_tapered.fsp ├── mmi_couplers │ ├── 1x2 │ │ ├── fields │ │ │ └── getFields.py │ │ ├── transmission │ │ │ └── getFrequencyResponse.py │ │ └── user_inputs │ │ │ └── lumerical_files │ │ │ └── MMI_1x2.fsp │ └── 2x2 │ │ └── user_inputs │ │ └── lumerical_files │ │ └── MMI_2x2.fsp ├── ring_resonator_coupler │ ├── fields │ │ └── getFields.py │ ├── gap_sweep │ │ └── getGapSweep.py │ ├── index_profile │ │ └── index_profile_2D.py │ ├── override_fdtd_region.py │ ├── override_ring_coupler_region.py │ ├── transmission │ │ └── getFrequencyResponse.py │ └── user_inputs │ │ ├── lumerical_files │ │ ├── coocentric_ring_coupling_section.fsp │ │ ├── rectangular_ring_coupling_section.fsp │ │ └── straight_ring_coupling_section.fsp │ │ └── user_simulation_parameters.py ├── swg_grating │ ├── Fields │ │ └── getFields.py │ ├── index_profile │ │ └── index_profile_2D.py │ ├── override_fdtd_region.py │ ├── override_swg_region.py │ ├── transmission │ │ └── getFrequencyResponse.py │ └── user_inputs │ │ ├── lumerical_files │ │ ├── sub_wavelength_grating_layer_1.fsp │ │ └── sub_wavelength_grating_layer_2.fsp │ │ └── user_simulation_parameters.py ├── vertical_taper │ ├── fields │ │ └── getFields.py │ ├── index_profile │ │ └── index_profile_2D.py │ ├── override_fdtd_region.py │ ├── override_vertical_taper_region.py │ ├── transmission │ │ └── getFrequencyResponse.py │ └── user_inputs │ │ ├── lumerical_files │ │ └── vertical_taper.fsp │ │ └── user_simulation_parameters.py ├── waveguide-bend │ ├── README.md │ ├── propagation_mode │ │ └── mode_profile.py │ ├── sweep_transmission │ │ └── sweep_radius_transmission.py │ ├── tree_chart.txt │ └── user_inputs │ │ ├── lumerical_files │ │ └── waveguide_bend.fsp │ │ └── user_sweep_parameters.py ├── waveguide-straight │ ├── README.md │ ├── fdtd_region.py │ ├── propagation_mode │ │ └── mode_profile.py │ ├── sweep_transmission │ │ └── sweep_width_transmission.py │ ├── user_inputs │ │ ├── user_materials.py │ │ ├── user_simulation_parameters.py │ │ └── user_sweep_parameters.py │ └── waveguide_render.py ├── waveguide_crossing │ ├── fields │ │ └── getFields.py │ ├── index_profile │ │ └── index_profile_2D.py │ ├── transmission │ │ └── getFrequencyResponse.py │ └── user_inputs │ │ └── lumerical_files │ │ └── waveguide_crossing_multi_wg_taper.fsp └── waveguide_mode_taper │ ├── README.md │ ├── fdtd_region.py │ ├── propagation_mode │ └── getFields.py │ ├── sweep_transmission │ ├── sweep_length_transmission.py │ └── sweep_width_transmission.py │ ├── user_inputs │ ├── user_materials.py │ ├── user_simulation_parameters.py │ └── user_sweep_parameters.py │ └── waveguide_taper_render.py ├── LICENSE ├── MODE ├── README.md ├── awg_star_coupler │ ├── mode_field_profile │ │ ├── apperture_profile_2D.py │ │ └── get_index_mesh_2D.py │ └── user_inputs │ │ └── lumerical_files │ │ ├── awg_input_taper.lms │ │ └── awg_input_taper_p0.log ├── butt_coupling │ ├── README.md │ ├── fde_region.py │ ├── mode_profile │ │ └── mode_profile_2D.py │ ├── overlap_mode │ │ └── overlap_mode_integral_2D.py │ ├── overlap_profile_sweep │ │ ├── overlap_misalignment_integral_2D.py │ │ └── overlap_width_sweep_2D.py │ └── user_inputs │ │ ├── lumerical_files │ │ ├── waveguide_1.lms │ │ └── waveguide_2.lms │ │ ├── user_simulation_parameters.py │ │ └── user_sweep_parameters.py ├── directional_coupler │ ├── README.md │ ├── coupling_sweep │ │ ├── coupling_gap.py │ │ └── coupling_length.py │ ├── dissimilar_waveguides │ │ └── coupling_length.py │ ├── even_odd_mode_profile.py │ ├── mode_profile │ │ └── mode_profile_2D.py │ └── user_inputs │ │ ├── lumerical_files │ │ └── waveguide_coupler.lms │ │ ├── user_simulation_parameters.py │ │ └── user_sweep_parameters.py ├── edge_coupler │ ├── README.md │ ├── fde_region.py │ ├── gaussian_beam_render.py │ ├── overlap_profile_sweep │ │ ├── overlap_height_sweep_2D.py │ │ └── overlap_mfd_sweep_2D.py │ ├── user_inputs │ │ ├── gaussian_beam_parameters.py │ │ ├── user_materials.py │ │ ├── user_simulation_parameters.py │ │ └── user_sweep_parameters.py │ └── waveguide_render.py ├── swg_grating │ ├── fields │ │ └── getFields.py │ ├── index_profile │ │ └── index_profile_2D.py │ ├── override_swg_region.py │ ├── override_varfdtd_region.py │ ├── transmission │ │ └── getFrequencyResponse.py │ └── user_inputs │ │ ├── lumerical_files │ │ └── sub_wavelength_grating_layer_1.lms │ │ └── user_simulation_parameters.py ├── vertical_taper │ ├── README.md │ ├── neff_sweep │ │ └── neff_width_sweep_2D.py │ └── user_inputs │ │ ├── lumerical_files │ │ ├── taper_waveguide_layer1.lms │ │ └── taper_waveguide_layer2.lms │ │ └── user_sweep_parameters.py └── waveguide │ ├── README.md │ ├── fde_region.py │ ├── index_profile │ └── get_index_mesh_2D.py │ ├── mode_profile │ ├── mode_profile_1D.py │ └── mode_profile_2D.py │ ├── neff_sweep │ ├── neff_height_sweep_2D.py │ ├── neff_height_sweep_variations_2D.py │ ├── neff_width_sweep_2D.py │ └── neff_width_sweep_variations_2D.py │ ├── np_density_sweep │ └── voltage_sweep_2D.py │ ├── pcm │ └── confinement_factor.py │ ├── pin_offset_sweep │ └── loss_offset_sweep_2D.py │ ├── radius_sweep │ ├── Q_factor_radius_sweep_2D.py │ └── overlap_radius_sweep_2D.py │ ├── user_inputs │ ├── user_materials.py │ ├── user_simulation_parameters.py │ └── user_sweep_parameters.py │ └── waveguide_render.py ├── README.md ├── TODO.md ├── config.py └── requirements.txt /DEVICE/electro_optic/feem_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The purpose of this script is to take the parameters from the 11 | 12 | 13 | """ 14 | import lumapi 15 | from config import * 16 | 17 | 18 | #---------------------------------------------------------------------------- 19 | # Imports from user files 20 | # --------------------------------------------------------------------------- 21 | 22 | from DEVICE.electro_optic.user_inputs.user_simulation_parameters import * 23 | from DEVICE.electro_optic.user_inputs.user_materials import * 24 | from DEVICE.electro_optic.waveguide_render import waveguide_draw 25 | 26 | def add_feem_region(device): 27 | 28 | # Add the mesh and the FDE regions 29 | device.addfeemsolver() 30 | device.addfeemmesh() 31 | device.addpec() 32 | 33 | 34 | 35 | configuration = ( 36 | 37 | ("FEEM", 38 | (("edges per wavelength", 4), 39 | ("wavelength", wavelength), 40 | ("number of trial modes", num_modes), 41 | ("polynomial order", 2))), 42 | 43 | 44 | 45 | ("simulation region", 46 | (("dimension", "2D Y-Normal"), 47 | ("x", 0.), 48 | ("z", 0.), 49 | ("y", 0.), 50 | ("x span", simulation_span_x), 51 | ("z min", simulation_min_z), 52 | ("z max", simulation_max_z), 53 | ("background material", background_material_e))), 54 | 55 | 56 | 57 | ("FEEM::boundary conditions::PEC", 58 | (("surface type", "simulation region"), 59 | ("x min", 1), 60 | ("x max", 1), 61 | ("y min", 1), 62 | ("y max", 1), 63 | ("z min", 1), 64 | ("z max", 1))), 65 | 66 | 67 | ("FEEM::mesh", 68 | (("x", 0.), 69 | ("geometry type", "volume"), 70 | ("volume solid", "waveguide"), 71 | ("max edge length", max_edge_length_mesh_override), 72 | ("enabled", mesh_enable))), 73 | 74 | ) 75 | 76 | 77 | 78 | # Populate the waveguide simulation region 79 | 80 | for obj, parameters in configuration: 81 | for k, v in parameters: 82 | device.setnamed(obj, k, v) 83 | 84 | 85 | 86 | 87 | if(__name__=="__main__"): 88 | with lumapi.DEVICE(hide=True) as device: 89 | 90 | # Draw the waveguide structure using a custom function 91 | device.redrawoff() 92 | waveguide_draw(device) 93 | 94 | # Draw the Simulation Region 95 | add_feem_region(device) 96 | 97 | 98 | device.save(EO_MODULATOR_DIRECTORY_WRITE_FILE + "\\eo_waveguide_render.ldev") 99 | 100 | 101 | -------------------------------------------------------------------------------- /DEVICE/electro_optic/user_inputs/user_simulation_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # Author: Georgios Gcharalampous (gcharalampous) 5 | # Version: 1.0 6 | # Description: User inputs required to set up the simulation file. 7 | #---------------------------------------------------------------------------- 8 | 9 | """ 10 | User inputs are required. 11 | 12 | This script prompts the user to enter parameters needed to set up the simulation file. 13 | """ 14 | 15 | # Length units are in meters! 16 | 17 | # 1. Simulation Region Parameters 18 | simulation_span_x = 10.5e-6 # X-axis span of simulation 19 | simulation_min_z = -3.0e-6 # Minimum Z-coordinate of simulation region 20 | simulation_max_z = 3.5e-6 # Maximum Z-coordinate of simulation region 21 | 22 | 23 | # 2. Cladding Dimensions. Note: waveguide y min = 0. 24 | clad_min_y = 0e-6 # Minimum Y-coordinate of cladding 25 | clad_max_y = 1.0e-6 # Maximum Y-coordinate of cladding 26 | 27 | 28 | # 3. Waveguide Dimensions 29 | wg_width = 0.5e-6 # Width of waveguide 30 | wg_thickness = 0.4e-6 # Thickness of waveguide 31 | wg_angle = 80 # Angle of waveguide (degrees) - Not yet implemented 32 | 33 | 34 | # 3.1 Set slab thickness > 0 to enable a slab waveguide 35 | slab_thickness = 0.05e-6 # Thickness of slab waveguide (set > 0 to enable) 36 | 37 | 38 | # 3.2 Metal Layer 39 | metal_left_width = 2.0e-6 # Width of left metal layer 40 | metal_center_width = metal_left_width # Width of center metal layer 41 | metal_right_width = metal_left_width # Width of right metal layer 42 | metal_thickness = 1.0e-6 # Thickness of metal layer 43 | metal_pitch = 4e-6 # Pitch of metal layer 44 | 45 | 46 | # 3.2.1 GSG Pads 47 | GSG_pads_enable = True # True for GSG Pads, False for GS Pads 48 | 49 | 50 | # 3.4 Voltage of Signal and Ground 51 | v_signal = 1 # Voltage of signal 52 | 53 | 54 | # 4. Box Layer Thickness 55 | box_thickness = abs(simulation_min_z) # Thickness of box layer 56 | 57 | 58 | # 5. Substrate Layer Thickness 59 | sub_thickness = 10e-6 # Thickness of substrate layer 60 | 61 | 62 | # 6. Charge Parameters. 63 | # 6.1 Mesh Parameters 64 | min_edge_length = 4e-9 # Minimum edge length for mesh 65 | max_edge_length = 600e-9 # Maximum edge length for mesh 66 | 67 | 68 | # 6.2 3D Expansion 69 | norm_length = 1e-6 # Normalization length for 3D expansion 70 | 71 | 72 | # 6.3 Doping 73 | # 6.3.1 Background Doping 74 | pepi_p_doping_enable = True # Enable background doping 75 | 76 | 77 | # 6.3.2 Waveguide Doping (thickness starts from top) 78 | waveguide_pp_doping_enable = False # Enable waveguide doping 79 | waveguide_pp_thickness = 100e-9 # Thickness of waveguide doping 80 | 81 | 82 | # 7 FEEM Parameters 83 | wavelength = 1.55e-6 # Wavelength 84 | num_modes = 6 # Number of modes 85 | 86 | 87 | # 7.1 Mesh (waveguide) 88 | mesh_enable = True # Enable mesh 89 | max_edge_length_mesh_override = 500e-9 # Maximum edge length for mesh override 90 | 91 | 92 | 93 | # 8. Figures 94 | my_dpi = 96 # DPI for figures 95 | -------------------------------------------------------------------------------- /DEVICE/pin_modulator/analytical_calculations/capacitance_analytical.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Dec 22 09:53:18 2023 4 | 5 | @author: Lab 6 | """ 7 | 8 | #---------------------------------------------------------------------------- 9 | # Imports from user files 10 | # --------------------------------------------------------------------------- 11 | 12 | 13 | import numpy as np 14 | from DEVICE.pin_modulator.user_inputs.user_materials import Nnn, Ppp 15 | from DEVICE.pin_modulator.user_inputs.user_sweep_parameters import * 16 | from DEVICE.pin_modulator.user_inputs.user_simulation_parameters import wg_thickness 17 | from DEVICE.pin_modulator.user_inputs.user_simulation_parameters import * 18 | 19 | 20 | 21 | 22 | 23 | def capDCanalytical(): 24 | 25 | # CONSTANTS 26 | epsilon0 = 8.854187817620e-12 # [F/m] 27 | epsilon_s = 11.8 # Si Relative Dielectric constant 28 | q = 1.60217646e-19 # Electronic charge [Coulumbs] 29 | kB = 1.3806503e-23 # Boltzmann Constant in J/K 30 | h = 4.135e-15 # Plank’s constant [eV-s] 31 | m_0 = 9.11e-31 # Electron Mass [kg] 32 | m_n = 1.08*m_0 # Density-of-states effective 33 | # mass for electrons 34 | m_p = 1.15*m_0 # Density-of-states effective 35 | # mass for holes 36 | Eg=1.1242 # Si Band-gap [eV] 37 | pi = np.pi 38 | # -------------------------------------------------------------------------- 39 | 40 | ND = Nnn; 41 | NA = Ppp 42 | 43 | 44 | # T = T+273.15 # Temperature [K] 45 | # VT = kB*T/q # Thermal Voltage 46 | 47 | # Nc = ( 2*(2*pi*m_n*(kB/q)*T/h**2)** # Effective Density of states Conduction Band 48 | # (3/2)/(q)**(3/2) ) 49 | 50 | # Nv = ( 2*(2*pi*m_p*(kB/q)*T/h**2)** # Effective Density of states Valence Band 51 | # (3/2)/(q)**(3/2) ) 52 | 53 | 54 | # ni = ( np.sqrt(Nc*Nv)* 55 | # np.exp(-Eg/(2*(kB/q)*T)) ) # intrinsict charge carriers in m^-3 56 | 57 | # Vbi = VT*np.log(NA*ND/ni**2) # Built-in or Diffusion Potential 58 | 59 | 60 | # Cj = np.sqrt(q*epsilon0*epsilon_s/2/(1/ND+1/NA)/(Vbi-V))*h_rib 61 | 62 | 63 | d = offset_Ppp + offset_Nnn 64 | 65 | Cj = ((epsilon0*epsilon_s)*metal_anode_width)/d 66 | 67 | return Cj 68 | 69 | 70 | if(__name__=="__main__"): 71 | 72 | 73 | T = 25 74 | V = np.linspace(v_anode_start, v_anode_stop, v_num_pts) 75 | V = V[V<=0] 76 | h_rib = wg_thickness 77 | 78 | 79 | Cj = capDCanalytical() 80 | 81 | 82 | print('Capacitance (pF)',Cj*1e12 ) 83 | 84 | -------------------------------------------------------------------------------- /DEVICE/pin_modulator/charge_distribution/get_band_potential.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | 8 | import lumapi 9 | import matplotlib.pyplot as plt 10 | import heapq 11 | 12 | #---------------------------------------------------------------------------- 13 | # Imports from user files 14 | # --------------------------------------------------------------------------- 15 | 16 | from DEVICE.pin_modulator.user_inputs.user_simulation_parameters import * 17 | from DEVICE.pin_modulator.user_inputs.user_materials import * 18 | from DEVICE.pin_modulator.waveguide_render import waveguide_draw 19 | from DEVICE.pin_modulator.charge_region import add_charge_region 20 | from config import * 21 | 22 | 23 | 24 | def find_closest_value(array, target): 25 | 26 | closest_value = min(array, key=lambda x: abs(x - target)) 27 | return closest_value 28 | 29 | 30 | def getDCVbi(device): 31 | 32 | Ei = device.getdata("CHARGE", "bandstructure","Ei") 33 | Vbi= np.max(Ei) - np.min(Ei) 34 | return Vbi 35 | 36 | 37 | 38 | def getJunctionWidth(device): 39 | 40 | band = device.getresult("CHARGE::band_monitor", "bandstructure") 41 | 42 | Ec = np.squeeze((band["Ec"])) 43 | Ec_gradient = np.gradient(Ec) # Find max and minimum of Ec 44 | x = np.squeeze((band["x"])) 45 | 46 | mid = int(len(x)/2) 47 | 48 | min_values = min(Ec_gradient[:(mid)]) 49 | index = np.where(Ec_gradient == min_values) 50 | W_max99 = x[index] 51 | 52 | min_values = min(Ec_gradient[(mid):]) 53 | index = np.where(Ec_gradient == min_values) 54 | W_min99 = x[index] 55 | 56 | 57 | 58 | 59 | 60 | junction_width = abs(W_max99 - W_min99) 61 | 62 | return junction_width, W_max99, W_min99, Ec, x 63 | 64 | 65 | 66 | if(__name__=="__main__"): 67 | with lumapi.DEVICE(hide=True) as device: 68 | 69 | 70 | # Draw the waveguide structure using a custom function 71 | device.redrawoff() 72 | waveguide_draw(device) 73 | 74 | # Draw the Simulation Region 75 | add_charge_region(device) 76 | 77 | # Save and Run 78 | device.save(PIN_MODULATOR_DIRECTORY_WRITE_FILE + "\\pin_waveguide_simulation.ldev") 79 | 80 | device.run() 81 | 82 | Vbi = getDCVbi(device) 83 | print("Built in Voltage is " + str(Vbi)+ " eV") 84 | 85 | junction_width, W_max99, W_min99, Ec, x = getJunctionWidth(device) 86 | print("Junction Width is " + str(junction_width)+ " V") 87 | 88 | plt.figure(1, figsize=(512/my_dpi, 256/my_dpi), dpi=my_dpi) 89 | plt.plot(x*1e6,Ec) 90 | plt.axvline(x = W_max99*1e6, color = 'r', linestyle = '--') 91 | plt.axvline(x = W_min99*1e6, color = 'r', linestyle = '--') 92 | 93 | plt.xlabel("x (\u00B5m)") 94 | plt.ylabel("$E_c$ (eV)") 95 | plt.grid() -------------------------------------------------------------------------------- /DEVICE/pin_modulator/charge_distribution/get_charge_1D.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | 8 | """ 9 | No user-inputs are required. 10 | 11 | """ 12 | 13 | 14 | import lumapi 15 | import matplotlib.pyplot as plt 16 | 17 | 18 | 19 | #---------------------------------------------------------------------------- 20 | # Imports from user files 21 | # --------------------------------------------------------------------------- 22 | 23 | from DEVICE.pin_modulator.user_inputs.user_simulation_parameters import * 24 | from DEVICE.pin_modulator.user_inputs.user_materials import * 25 | from DEVICE.pin_modulator.waveguide_render import waveguide_draw 26 | from DEVICE.pin_modulator.charge_region import add_charge_region 27 | from config import * 28 | 29 | 30 | 31 | def get_charge_1D (device): 32 | 33 | 34 | 35 | 36 | charge_result = device.getresult("CHARGE::charge_monitor","charge") 37 | x = np.squeeze(charge_result['x']) 38 | n = np.squeeze(charge_result['n']) 39 | p = np.squeeze(charge_result['p']) 40 | # n = device.getdata("CHARGE::charge_monitor","charge","n") 41 | # p = device.getdata("CHARGE::charge_monitor","charge","p") 42 | 43 | return x, n, p 44 | 45 | 46 | 47 | if(__name__=="__main__"): 48 | with lumapi.DEVICE(hide=True) as device: 49 | 50 | # Draw the waveguide structure using a custom function 51 | device.redrawoff() 52 | waveguide_draw(device) 53 | 54 | # Draw the Simulation Region 55 | add_charge_region(device) 56 | 57 | 58 | # Save and Run 59 | device.setnamed("CHARGE::charge_monitor","monitor type", 2) 60 | device.save(PIN_MODULATOR_DIRECTORY_WRITE_FILE + "\\pin_waveguide_simulation.ldev") 61 | device.run() 62 | 63 | # Get the charge 64 | x, n, p = get_charge_1D(device) 65 | 66 | 67 | 68 | plt.figure(1, figsize=(512/my_dpi, 256/my_dpi), dpi=my_dpi) 69 | plt.semilogy(x*1e6, n, label = 'ND') 70 | plt.semilogy(x*1e6, p, label = 'NA') 71 | plt.minorticks_on 72 | plt.legend() 73 | 74 | plt.xlabel("x (\u00B5m)") 75 | plt.ylabel("Charge (cm$^{-3}$)") 76 | plt.grid(True, 'both') 77 | 78 | plt.savefig(PIN_MODULATOR_DIRECTORY_WRITE[0] + "\\charge_distrigution.png") 79 | 80 | 81 | -------------------------------------------------------------------------------- /DEVICE/pin_modulator/charge_distribution/get_junction_width.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Dec 22 10:40:10 2023 4 | 5 | @author: Lab 6 | """ 7 | 8 | -------------------------------------------------------------------------------- /DEVICE/pin_modulator/dc_sweep/voltage_sweep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | 8 | import lumapi 9 | import matplotlib.pyplot as plt 10 | 11 | 12 | 13 | #---------------------------------------------------------------------------- 14 | # Imports from user files 15 | # --------------------------------------------------------------------------- 16 | 17 | from DEVICE.pin_modulator.analytical_calculations.capacitance_analytical import capDCanalytical 18 | from DEVICE.pin_modulator.user_inputs.user_simulation_parameters import * 19 | from DEVICE.pin_modulator.user_inputs.user_materials import * 20 | from DEVICE.pin_modulator.user_inputs.user_sweep_parameters import * 21 | from DEVICE.pin_modulator.waveguide_render import waveguide_draw 22 | from DEVICE.pin_modulator.charge_region import add_charge_region 23 | from config import * 24 | 25 | 26 | def voltage_sweep(device, v_anode_start,v_anode_stop,v_num_pts): 27 | 28 | configuration = ( 29 | 30 | ("CHARGE::boundary conditions::anode", 31 | (("bc mode", "steady state"), 32 | ('sweep type', 'range'), 33 | ('range start', v_anode_start), 34 | ('range stop', v_anode_stop), 35 | ('range num points', v_num_pts), 36 | ("surface type", "solid"), 37 | ("solid", "metal_anode"))), 38 | 39 | 40 | ("CHARGE::boundary conditions::cathode", 41 | (("bc mode", "steady state"), 42 | ('sweep type', 'single'), 43 | ('voltage', 0), 44 | ("surface type", "solid"), 45 | ("solid", "metal_cathode"))), 46 | 47 | 48 | ("CHARGE", 49 | (("norm length", norm_length), 50 | ("max refine steps", max_refine_steps), 51 | ('solver type', solver_type))), 52 | 53 | 54 | ("CHARGE::charge_monitor", 55 | (("monitor type", 7), 56 | ("integrate total charge", 1), 57 | ("save data", True), 58 | ("filename","charge_sweep.mat"))), 59 | 60 | 61 | ) 62 | 63 | 64 | 65 | # Populate the waveguide simulation region 66 | 67 | for obj, parameters in configuration: 68 | for k, v in parameters: 69 | device.setnamed(obj, k, v) 70 | 71 | 72 | if(__name__=="__main__"): 73 | with lumapi.DEVICE(hide=False) as device: 74 | 75 | 76 | # Draw the waveguide structure using a custom function 77 | device.redrawoff() 78 | waveguide_draw(device) 79 | 80 | # Draw the Simulation Region 81 | add_charge_region(device) 82 | 83 | 84 | 85 | # Load voltage sweep range from user_sweep_parameters 86 | voltage_sweep(device, v_anode_start, v_anode_stop, v_num_pts) 87 | 88 | # Save and Run 89 | device.save(PIN_MODULATOR_DIRECTORY_WRITE_FILE + "\\pin_waveguide_simulation.ldev") 90 | 91 | device.run() -------------------------------------------------------------------------------- /DEVICE/pin_modulator/user_inputs/user_materials.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | 8 | import numpy as np 9 | 10 | """ 11 | User-inputs are required. 12 | 13 | Input the appropriate material for each structure as appears below 14 | 15 | 16 | +--------------------------------+ 17 | | Claddding | 18 | | | 19 | | +-----------+ | 20 | | | | | 21 | | | waveguide | | 22 | | | | | 23 | +--------------------------------+ 24 | | Box | 25 | +--------------------------------+ 26 | | | 27 | | Substrate | 28 | | | 29 | +--------------------------------+ 30 | 31 | 32 | Select between material model or material index. By selecting the variable 33 | 'is_clad_index = True' the material model will be ingonred and instead the 34 | cladding_index = 1 cladding index 1 will be set. 35 | 36 | 37 | Please make sure that you type the material model exactly as it is in the material 38 | database. 39 | 40 | """ 41 | 42 | # Oxide 43 | oxide_material = "SiO2 (Glass) - Sze" 44 | 45 | 46 | # Waveguide Core 47 | wg_material = "Si (Silicon)" 48 | wg_mole_fract = 0.2 # If applicable, otherwise will be neglected 49 | 50 | # Contacts 51 | contact_material = "Al (Aluminium) - CRC" 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | ## ------ Doping 61 | 62 | # PEPI [doping in cm^-3] 63 | pepi_p_doping = 1e15 64 | 65 | Nnn=2.2e20 # N++ 66 | Ppp=9e19 # P++ 67 | 68 | # -------------------------- End of Input Section ----------------------------- 69 | 70 | material_list = [oxide_material, wg_material, contact_material] 71 | 72 | # Remove Duplicate strings 73 | unique_material_list = [] 74 | for item in material_list: 75 | if item not in unique_material_list: 76 | unique_material_list.append(item) 77 | -------------------------------------------------------------------------------- /DEVICE/pin_modulator/user_inputs/user_sweep_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user is rmust enter the parameters required to sweep. 11 | 12 | The waveguide parameters to sweep are 'wg_thickness' and 'wg_width' . 13 | 14 | 15 | 16 | ^ 17 | | 18 | | 19 | | - 20 | wg_width 21 | <---------------> 22 | +-------|--------+ ^ 23 | | | | | 24 | | waveguide | | wg_thickness 25 | | | | | 26 | ------------|----------v---------------------> 27 | (0,0)| 28 | | 29 | | 30 | | 31 | 32 | """ 33 | 34 | 35 | 36 | # Voltage Sweep 37 | v_anode_start = -0.15 38 | v_anode_stop = 3.0 39 | v_anode_step = 25e-3 40 | v_num_pts = int((v_anode_stop - v_anode_start)/v_anode_step)+1 41 | 42 | 43 | offset_P_start = 0.0e-6 # Choose the start clear width (offset) 'offset_P_start' 44 | offset_P_stop = 1.1e-6 # Choose the stop clear width (offset) 'offset_P_stop' 45 | offset_P_step = 0.1e-6 # Choose the step clear width (offset) 'offset_P_step' 46 | 47 | offset_N_start = offset_P_start # Choose the start clear width (offset) 'offset_N_start' 48 | offset_N_stop = offset_P_stop # Choose the stop clear width (offset) 'offset_N_stop' 49 | offset_N_step = offset_P_step # Choose the step clear width (offset) 'offset_N_step' -------------------------------------------------------------------------------- /FDTD/README.md: -------------------------------------------------------------------------------- 1 | ## FDTD Simulations 2 | 3 | Feel free to explore the following: 4 | 5 | ### [directional-coupler](directional-coupler) 6 | 7 | - Simulates the coupling between two parallel waveguides. 8 | - Calculates the power transfer between waveguides as a function of the coupling length. 9 | - Plots the E-field profiles for different coupling lengths. 10 | 11 | ### [disk-resonator-coupler](disk_resonator_coupler) 12 | 13 | - Simulates the coupling between a waveguide and a disk resonator. 14 | - Models the resonance and coupling efficiency as a function of the waveguide-resonator distance. 15 | - Plots the E-field profiles of the resonator. 16 | 17 | ### [edge-coupler](edge_coupler) 18 | 19 | - Models light coupling from a waveguide to a 2D edge structure. 20 | - Simulates the coupling efficiency and the E-field profile of the coupling region. 21 | 22 | ### [grating-coupler-2D](grating_coupler_2D) 23 | 24 | - Simulates the performance of a 2D grating coupler. 25 | - Calculates the coupling efficiency and the angle of incidence required for maximum coupling. 26 | 27 | ### [mmi-couplers](mmi-couplers) 28 | 29 | - Models the multi-mode interference (MMI) coupler performance. 30 | - Calculates the output power distribution for different input waveguide configurations. 31 | - Plots the E-field profiles at the output of the MMI. 32 | 33 | ### [ring-resonator-coupler](ring_resonator_coupler) 34 | 35 | - Models the coupling between a waveguide and a ring resonator. 36 | - Calculates the resonance wavelength and the coupling efficiency. 37 | - Plots the E-field profiles inside the resonator. 38 | 39 | ### [swg-grating](swg_grating) 40 | 41 | - Simulates the performance of a slab waveguide (SWG) grating coupler. 42 | - Calculates the diffraction efficiency and the far-field diffraction patterns. 43 | - Plots the E-field profiles of the grating coupler. 44 | 45 | ### [vertical-taper](vertical_taper) 46 | 47 | - Simulates the performance of a vertical taper between waveguide sections with different heights. 48 | - Calculates the transmission and power transfer efficiency between waveguide segments. 49 | - Plots the E-field profiles across the taper region. 50 | 51 | ### [waveguide-bend](waveguide-bend) 52 | - Calculates the transmission as a function of the bending radius. 53 | - Plots the E-field profiles at the bending section. 54 | 55 | ### [waveguide-crossing](waveguide-crossing) 56 | - Simulates the field profile at waveguide crossings. 57 | - Calculates the coupling between intersecting waveguides as a function of the crossing angle. 58 | - Plots the E-field profile across the intersection. 59 | 60 | ### [waveguide-mode-taper](waveguide-mode-taper) 61 | - Plots the E-field profile of the propagated mode across the tapered waveguide section and calculates transmission. 62 | - Sweeps the taper-tip width: 63 | - Calculates the transmission of the fundamental TE or TM mode. 64 | - Sweeps the taper length (Adiabaticity): 65 | - Calculates the transmission of the fundamental TE, TM modes, and any higher-order modes. 66 | 67 | ### [waveguide-straight](waveguide-straight) 68 | - Plots the E-field profile of the propagated mode. 69 | - Sweeps the waveguide width: 70 | - Calculates the transmission of the fundamental TE or TM mode. 71 | -------------------------------------------------------------------------------- /FDTD/adiabatic_directional_coupler/fields/getFields.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the E-fields profile for the device structure 11 | defined in the sbend_adiabatic_directional_coupler.fsp file 12 | 13 | """ 14 | 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | from matplotlib.colors import LogNorm 24 | from config import * 25 | 26 | # from FDTD.waveguide_cross.override_cross_region import * 27 | 28 | 29 | def getFields(fdtd): 30 | 31 | 32 | field_xy = fdtd.getelectric("xy_topview") 33 | 34 | x = fdtd.getdata("xy_topview","x").squeeze() 35 | y = fdtd.getdata("xy_topview","y").squeeze() 36 | 37 | return x,y,field_xy 38 | 39 | 40 | 41 | 42 | 43 | 44 | if(__name__=="__main__"): 45 | with lumapi.FDTD(FDTD_ADIAB_DC_DIRECTORY_READ) as fdtd: 46 | 47 | # ------------ Comment for Avoiding Overriding the Simulation Region 48 | # override_cross(fdtd=fdtd) 49 | # fdtd.run() 50 | 51 | x,y,E_xy = getFields(fdtd=fdtd) 52 | c_wavelength = np.rint(len(E_xy[0,0,0,:])/2) 53 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 54 | 55 | # --------------------------------Top-View--------------------------------- 56 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 57 | cmap = ax.pcolormesh(x*1e6, y*1e6, (np.transpose(E_xy[:, :, 0, int(c_wavelength)])), 58 | shading='gouraud', cmap='jet', norm=LogNorm(vmin=1e-4, vmax=1)) 59 | fig.colorbar(cmap) 60 | plt.xlabel("x (um)") 61 | plt.ylabel("y (um)") 62 | plt.title('Top-view(xy)') 63 | plt.tight_layout() 64 | file_name_plot = os.path.join(FDTD_ADIAB_DC_DIRECTORY_WRITE[2], "E_profile_xy.png") 65 | plt.savefig(file_name_plot) 66 | 67 | 68 | 69 | plt.show() 70 | 71 | -------------------------------------------------------------------------------- /FDTD/adiabatic_directional_coupler/gap_sweep/getGapSweep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the transmission and crosstalk for the waveguide crossing 11 | structure defined in the waveguide_crossing_multi_wg_taper.fsp file 12 | from the 'through' and crosstalk monitor. 13 | 14 | """ 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | from config import * 24 | 25 | 26 | def getCouplingResponse(fdtd): 27 | T = (fdtd.getsweepresult("sweep_taper_length","T1")) 28 | C = (fdtd.getsweepresult("sweep_taper_length","T2")) 29 | 30 | 31 | return T, C 32 | 33 | 34 | 35 | if(__name__=="__main__"): 36 | with lumapi.FDTD(FDTD_ADIAB_Y_BR_DIRECTORY_READ) as fdtd: 37 | 38 | # ------------ Comment for Avoiding Overriding the Simulation Region defined in the file 39 | # override_fdtd(fdtd=fdtd) 40 | 41 | # ------------ Comment for Avoiding Running Sweep 42 | # fdtd.runsweep() 43 | 44 | 45 | # Get Coupling and Through 46 | T, C = getCouplingResponse(fdtd=fdtd) 47 | length = np.squeeze(T['length']) 48 | through = np.squeeze(T['T']) 49 | bar = np.squeeze(C['T']) 50 | 51 | 52 | # --------------------------------Plot-T/C--------------------------------- 53 | 54 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 55 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 56 | ax.semilogy(length*1e6, through, label = 'Through') 57 | ax.grid(which='both') 58 | ax.legend() 59 | ax.set_xlabel("length (um)") 60 | ax.set_ylabel("Magnitude") 61 | ax.set_title(fdtd.getnamed("source","mode selection")) 62 | plt.tight_layout() 63 | file_name_plot = os.path.join(FDTD_ADIAB_Y_BR_DIRECTORY_WRITE[1], "frequency_response_T.png") 64 | plt.savefig(file_name_plot) 65 | 66 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 67 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 68 | ax.semilogy(length*1e6, bar,label = 'Coupling') 69 | ax.grid(which='both') 70 | ax.legend() 71 | ax.set_title(fdtd.getnamed("source","mode selection")) 72 | ax.set_xlabel("length (um)") 73 | ax.set_ylabel("Magnitude") 74 | plt.tight_layout() 75 | file_name_plot = os.path.join(FDTD_ADIAB_Y_BR_DIRECTORY_WRITE[1], "frequency_response_C.png") 76 | plt.savefig(file_name_plot) 77 | 78 | 79 | 80 | 81 | 82 | plt.show() -------------------------------------------------------------------------------- /FDTD/adiabatic_directional_coupler/user_inputs/lumerical_files/sbend_adiabatic_directional_coupler.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/adiabatic_directional_coupler/user_inputs/lumerical_files/sbend_adiabatic_directional_coupler.fsp -------------------------------------------------------------------------------- /FDTD/adiabatic_directional_coupler/user_inputs/user_simulation_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user is must enter the parameters required to setup the 11 | simulation file. The simulation parameters along with their dimensions are 12 | presented below. 13 | 14 | 15 | """ 16 | 17 | 18 | # Length units are in meters! 19 | 20 | 21 | # 1. Taper Parameters 22 | 23 | taper_gap = 0.5e-6 24 | taper_length = 100e-6 25 | 26 | 27 | 28 | 29 | # # 1.1. Taper-bottom Parameters - Soyrce is attached on this taper 30 | # wg_bottom_width_left = 1.20e-6 31 | # wg_bottom_width_right = 0.25e-6 32 | # wg_bottom_thickness = 0.2e-6 33 | 34 | # wg_bottom_rib_thickness = 0.0e-6 35 | 36 | # # 1.2. Taper-Top Parameters 37 | # wg_top_width_left = 0.25e-6 38 | # wg_top_width_right = 1.20e-6 39 | # wg_top_thickness = 0.2e-6 40 | 41 | # wg_top_rib_thickness = 0.0e-6 42 | 43 | 44 | # # 2. FDTD Simulation Parameters 45 | 46 | # # 2.1 FDTD Span Region 47 | # simulation_span_y = 20e-6 48 | # simulation_span_z = 20e-6 49 | # simulation_time = 5e-12 50 | 51 | # # 2.2.1. Mesh Settings 52 | # mesh_accuracy = 1 53 | 54 | # # 2.2.2. Override Mesh Settings 55 | # mesh_dx = 50e-9 56 | # mesh_dy = wg_top_width_left/2 57 | # mesh_dz = taper_gap/5 58 | # enable_dx = 0 59 | # enable_dy = 1 60 | # enable_dz = 1 61 | 62 | 63 | # # 2.3 Source/Monitor Properties 64 | # wavelength_start = 1.2e-6 65 | # wavelength_stop = 1.4e-6 66 | # mode_fundamental = "TE" # Select TE for fundamental TE or TM for fundamental TM 67 | # frequency_points = 32 68 | 69 | # # 2.4. Port extension 70 | # port_extension = 5e-6 71 | 72 | 73 | # # 3. Figures 74 | # my_dpi = 96 75 | 76 | 77 | # # -------------------------- End of Input Section ----------------------------- 78 | 79 | 80 | # if(mode_fundamental == "TE"): 81 | # mode_monitor = "fundamental TE mode" 82 | # else: 83 | # mode_monitor = "fundamental TM mode" 84 | 85 | 86 | 87 | # if(mode_fundamental == "TE"): 88 | # mode_source = "fundamental TE mode" 89 | # else: 90 | # mode_source = "fundamental TM mode" 91 | -------------------------------------------------------------------------------- /FDTD/adiabatic_y_branch/fields/getFields.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the E-fields profile for the device structure 11 | defined in the adiabatic_y_branch.fsp file 12 | 13 | """ 14 | 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | from matplotlib.colors import LogNorm 24 | from config import * 25 | 26 | # from FDTD.waveguide_cross.override_cross_region import * 27 | 28 | 29 | def getFields(fdtd): 30 | 31 | 32 | field_xy = fdtd.getelectric("field_xy") 33 | 34 | x = fdtd.getdata("field_xy","x").squeeze() 35 | y = fdtd.getdata("field_xy","y").squeeze() 36 | 37 | return x,y,field_xy 38 | 39 | 40 | 41 | 42 | 43 | 44 | if(__name__=="__main__"): 45 | with lumapi.FDTD(FDTD_ADIAB_Y_BR_DIRECTORY_READ) as fdtd: 46 | 47 | # ------------ Comment for Avoiding Overriding the Simulation Region 48 | # override_cross(fdtd=fdtd) 49 | # fdtd.run() 50 | 51 | x,y,E_xy = getFields(fdtd=fdtd) 52 | c_wavelength = np.rint(len(E_xy[0,0,0,:])/2) 53 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 54 | 55 | # --------------------------------Top-View--------------------------------- 56 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 57 | cmap = ax.pcolormesh(x*1e6, y*1e6, (np.transpose(E_xy[:, :, 0, int(c_wavelength)])), 58 | shading='gouraud', cmap='jet', norm=LogNorm(vmin=1e-4, vmax=1)) 59 | fig.colorbar(cmap) 60 | plt.xlabel("x (um)") 61 | plt.ylabel("y (um)") 62 | plt.title('Top-view(xy)') 63 | plt.tight_layout() 64 | file_name_plot = os.path.join(FDTD_ADIAB_Y_BR_DIRECTORY_WRITE[2], "E_profile_xy.png") 65 | plt.savefig(file_name_plot) 66 | 67 | 68 | 69 | plt.show() 70 | 71 | -------------------------------------------------------------------------------- /FDTD/adiabatic_y_branch/user_inputs/lumerical_files/adiabatic_y_branch.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/adiabatic_y_branch/user_inputs/lumerical_files/adiabatic_y_branch.fsp -------------------------------------------------------------------------------- /FDTD/adiabatic_y_branch/user_inputs/user_simulation_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user is must enter the parameters required to setup the 11 | simulation file. The simulation parameters along with their dimensions are 12 | presented below. 13 | 14 | 15 | """ 16 | 17 | 18 | # Length units are in meters! 19 | 20 | 21 | # 1. Taper Parameters 22 | 23 | taper_gap = 0.5e-6 24 | taper_length = 100e-6 25 | 26 | 27 | 28 | 29 | # # 1.1. Taper-bottom Parameters - Soyrce is attached on this taper 30 | # wg_bottom_width_left = 1.20e-6 31 | # wg_bottom_width_right = 0.25e-6 32 | # wg_bottom_thickness = 0.2e-6 33 | 34 | # wg_bottom_rib_thickness = 0.0e-6 35 | 36 | # # 1.2. Taper-Top Parameters 37 | # wg_top_width_left = 0.25e-6 38 | # wg_top_width_right = 1.20e-6 39 | # wg_top_thickness = 0.2e-6 40 | 41 | # wg_top_rib_thickness = 0.0e-6 42 | 43 | 44 | # # 2. FDTD Simulation Parameters 45 | 46 | # # 2.1 FDTD Span Region 47 | # simulation_span_y = 20e-6 48 | # simulation_span_z = 20e-6 49 | # simulation_time = 5e-12 50 | 51 | # # 2.2.1. Mesh Settings 52 | # mesh_accuracy = 1 53 | 54 | # # 2.2.2. Override Mesh Settings 55 | # mesh_dx = 50e-9 56 | # mesh_dy = wg_top_width_left/2 57 | # mesh_dz = taper_gap/5 58 | # enable_dx = 0 59 | # enable_dy = 1 60 | # enable_dz = 1 61 | 62 | 63 | # # 2.3 Source/Monitor Properties 64 | # wavelength_start = 1.2e-6 65 | # wavelength_stop = 1.4e-6 66 | # mode_fundamental = "TE" # Select TE for fundamental TE or TM for fundamental TM 67 | # frequency_points = 32 68 | 69 | # # 2.4. Port extension 70 | # port_extension = 5e-6 71 | 72 | 73 | # # 3. Figures 74 | # my_dpi = 96 75 | 76 | 77 | # # -------------------------- End of Input Section ----------------------------- 78 | 79 | 80 | # if(mode_fundamental == "TE"): 81 | # mode_monitor = "fundamental TE mode" 82 | # else: 83 | # mode_monitor = "fundamental TM mode" 84 | 85 | 86 | 87 | # if(mode_fundamental == "TE"): 88 | # mode_source = "fundamental TE mode" 89 | # else: 90 | # mode_source = "fundamental TM mode" 91 | -------------------------------------------------------------------------------- /FDTD/directional-coupler/user_inputs/lumerical_files/sbend_directional_coupler.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/directional-coupler/user_inputs/lumerical_files/sbend_directional_coupler.fsp -------------------------------------------------------------------------------- /FDTD/disk_resonator_coupler/fields/getFields.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the E-fields profile for the device structure 11 | defined in the *.fsp files 12 | 13 | """ 14 | 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | from matplotlib.colors import LogNorm 24 | from config import * 25 | 26 | from FDTD.disk_resonator_coupler.user_inputs.user_simulation_parameters import * 27 | 28 | from FDTD.disk_resonator_coupler.override_fdtd_region import * 29 | from FDTD.disk_resonator_coupler.override_disk_coupler_region import * 30 | 31 | def getFields(fdtd): 32 | 33 | fdtd.run() 34 | 35 | field_xy = fdtd.getelectric("xy_topview") 36 | 37 | x = fdtd.getdata("xy_topview","x").squeeze() 38 | y = fdtd.getdata("xy_topview","y").squeeze() 39 | 40 | return x,y,field_xy 41 | 42 | 43 | 44 | 45 | 46 | 47 | if(__name__=="__main__"): 48 | with lumapi.FDTD(FDTD_DISK_DIRECTORY_READ[file_index]) as fdtd: 49 | 50 | # ------------ Comment for Avoiding Overriding the Simulation Region defined in the file 51 | override_fdtd(fdtd=fdtd) 52 | override_disk_coupler(fdtd=fdtd) 53 | 54 | 55 | x,y,E_xy = getFields(fdtd=fdtd) 56 | c_wavelength = np.rint(len(E_xy[0,0,0,:])/2) 57 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 58 | 59 | # --------------------------------Top-View--------------------------------- 60 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 61 | cmap = ax.pcolormesh(x*1e6,y*1e6,(np.transpose(E_xy[:,:,0,int(c_wavelength)])), 62 | shading = 'gouraud',cmap = 'jet', norm = LogNorm(vmin=1e-4, vmax=1)) 63 | fig.colorbar(cmap) 64 | plt.xlabel("x (um)") 65 | plt.ylabel("y (um)") 66 | plt.title('Top-view(xy)') 67 | plt.tight_layout() 68 | file_name_plot = os.path.join(FDTD_DISK_DIRECTORY_WRITE[2], "E_profile_xy.png") 69 | plt.savefig(file_name_plot) 70 | 71 | 72 | 73 | plt.show() 74 | 75 | -------------------------------------------------------------------------------- /FDTD/disk_resonator_coupler/gap_sweep/getGapSweep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the transmission and crosstalk for the waveguide crossing 11 | structure defined in the waveguide_crossing_multi_wg_taper.fsp file 12 | from the 'through' and crosstalk monitor. 13 | 14 | """ 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | import scipy.constants as scpy 24 | from config import * 25 | 26 | from FDTD.disk_resonator_coupler.user_inputs.user_simulation_parameters import * 27 | 28 | from FDTD.disk_resonator_coupler.override_fdtd_region import * 29 | from FDTD.disk_resonator_coupler.override_disk_coupler_region import * 30 | 31 | def getCouplingResponse(fdtd): 32 | T = (fdtd.getsweepresult("sweep_gap","T")) 33 | C = (fdtd.getsweepresult("sweep_gap","C")) 34 | 35 | 36 | return T, C 37 | 38 | 39 | 40 | if(__name__=="__main__"): 41 | with lumapi.FDTD(FDTD_DISK_DIRECTORY_READ[file_index]) as fdtd: 42 | 43 | # ------------ Comment for Avoiding Overriding the Simulation Region defined in the file 44 | # override_fdtd(fdtd=fdtd) 45 | # override_disk_coupler(fdtd=fdtd) 46 | 47 | # ------------ Comment for Avoiding Running Sweep 48 | fdtd.runsweep() 49 | 50 | 51 | # Get Coupling and Through 52 | T, C = getCouplingResponse(fdtd=fdtd) 53 | gap = np.squeeze(T['gap']) 54 | through = np.squeeze(T['T']) 55 | bar = np.squeeze(C['T']) 56 | 57 | 58 | # --------------------------------Plot-T/C--------------------------------- 59 | 60 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 61 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 62 | ax.semilogy(gap*1e9, through, label = 'Through') 63 | ax.grid(which='both') 64 | ax.legend() 65 | ax.set_xlabel("gap (nm)") 66 | ax.set_ylabel("Magnitude") 67 | ax.set_title(fdtd.getnamed("source","mode selection")) 68 | plt.tight_layout() 69 | file_name_plot = os.path.join(FDTD_DISK_DIRECTORY_WRITE[3], "Coupling_gap_linear.png") 70 | plt.savefig(file_name_plot) 71 | 72 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 73 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 74 | ax.semilogy(gap*1e9, bar,label = 'Coupling') 75 | ax.grid(which='both') 76 | ax.legend() 77 | ax.set_title(fdtd.getnamed("source","mode selection")) 78 | ax.set_xlabel("gap (nm)") 79 | ax.set_ylabel("Magnitude") 80 | plt.tight_layout() 81 | file_name_plot = os.path.join(FDTD_DISK_DIRECTORY_WRITE[3], "Coupling_gap_log.png") 82 | plt.savefig(file_name_plot) 83 | 84 | 85 | 86 | 87 | 88 | plt.show() -------------------------------------------------------------------------------- /FDTD/disk_resonator_coupler/override_disk_coupler_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script overrides the FDTD region for the ring coupler simulation. 11 | 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user files 17 | # --------------------------------------------------------------------------- 18 | 19 | import lumapi 20 | from FDTD.disk_resonator_coupler.user_inputs.user_simulation_parameters import * 21 | from config import FDTD_DISK_DIRECTORY_READ 22 | from FDTD.disk_resonator_coupler.user_inputs.user_simulation_parameters import * 23 | 24 | 25 | 26 | 27 | def override_disk_coupler(fdtd): 28 | 29 | fdtd.switchtolayout() 30 | 31 | 32 | configuration = ( 33 | ("ring", (("ring_radius", ring_radius), 34 | ("wg_bus_width", wg_bus_width), 35 | ("wg_thickness", wg_thickness), 36 | ("slab_thickness", slab_thickness), 37 | ("bus_angle", bus_angle), 38 | ("gap", gap))), 39 | 40 | ) 41 | 42 | 43 | # Populate the waveguide simulation region 44 | 45 | for obj, parameters in configuration: 46 | for k, v in parameters: 47 | fdtd.setnamed(obj, k, v) 48 | 49 | fdtd.save() 50 | 51 | # --------------------------------------------------------------------------- 52 | 53 | 54 | if(__name__=="__main__"): 55 | 56 | with lumapi.FDTD(FDTD_DISK_DIRECTORY_READ[file_index]) as fdtd: 57 | override_disk_coupler(fdtd=fdtd) 58 | 59 | 60 | -------------------------------------------------------------------------------- /FDTD/disk_resonator_coupler/override_fdtd_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script overrides the FDTD simulation region from the *.fsp files. 11 | 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user files 17 | # --------------------------------------------------------------------------- 18 | 19 | import lumapi 20 | from FDTD.disk_resonator_coupler.user_inputs.user_simulation_parameters import * 21 | from config import FDTD_DISK_DIRECTORY_READ 22 | 23 | def override_fdtd(fdtd): 24 | 25 | fdtd.switchtolayout() 26 | 27 | configuration = ( 28 | 29 | ("source", (("mode selection", mode_polarization), 30 | ("wavelength start", wavelength_start), 31 | ("wavelength stop", wavelength_stop))), 32 | 33 | ("C", (("mode selection", mode_polarization),)), 34 | 35 | ("T", (("mode selection", mode_polarization),)), 36 | 37 | ("mesh", (("dx", mesh_dx), 38 | ("dy", mesh_dy), 39 | ("override x mesh", enable_dx), 40 | ("override y mesh", enable_dy), 41 | ("override z mesh", False))), 42 | 43 | ("::model", (("monitor_theta", monitor_theta), 44 | ("FDTD_z_span", simulation_span_z), 45 | ("port_extension", port_extension))), 46 | 47 | ("FDTD", (("simulation time", simulation_time), 48 | ("mesh accuracy", mesh_accuracy))), 49 | ) 50 | 51 | 52 | # Populate the waveguide simulation region 53 | 54 | for obj, parameters in configuration: 55 | for k, v in parameters: 56 | fdtd.setnamed(obj, k, v) 57 | 58 | fdtd.setglobalmonitor("frequency points",frequency_points) 59 | 60 | fdtd.save() 61 | 62 | 63 | # --------------------------------------------------------------------------- 64 | 65 | 66 | if(__name__=="__main__"): 67 | with lumapi.FDTD(FDTD_DISK_DIRECTORY_READ[file_index]) as fdtd: 68 | override_fdtd(fdtd=fdtd) 69 | 70 | 71 | -------------------------------------------------------------------------------- /FDTD/disk_resonator_coupler/transmission/getFrequencyResponse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the transmission and coupling for the ring coupler 11 | structure defined in the *.fsp files from the 'T' and 'C' monitors. 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user input files 17 | # --------------------------------------------------------------------------- 18 | 19 | import numpy as np 20 | import lumapi, os 21 | import matplotlib.pyplot as plt 22 | import scipy.constants as scpy 23 | from config import * 24 | 25 | from FDTD.disk_resonator_coupler.user_inputs.user_simulation_parameters import * 26 | 27 | from FDTD.disk_resonator_coupler.override_fdtd_region import * 28 | from FDTD.disk_resonator_coupler.override_disk_coupler_region import * 29 | 30 | 31 | def getCouplingResponse(fdtd): 32 | fdtd.run() 33 | T = np.squeeze(fdtd.getresult("T","expansion for ").get("T_forward")) 34 | C = np.squeeze(fdtd.getresult("C","expansion for ").get("T_forward")) 35 | f = np.squeeze(fdtd.getdata("through","f")) 36 | 37 | return T, C, f 38 | 39 | 40 | 41 | if(__name__=="__main__"): 42 | with lumapi.FDTD(FDTD_RING_DIRECTORY_READ[file_index]) as fdtd: 43 | 44 | # ------------ Comment for Avoiding Overriding the Simulation Region defined in the file 45 | # override_fdtd(fdtd=fdtd) 46 | # override_disk_coupler(fdtd=fdtd) 47 | 48 | # --------------------------------Plot-T/R--------------------------------- 49 | 50 | T, C, f = getCouplingResponse(fdtd=fdtd) 51 | 52 | # --------------------------------Plot-T/R--------------------------------- 53 | 54 | if(T.size==1): 55 | print("T: " + str(round(T*100,2)) + ' %') 56 | print("C: " + str(round(C*100,2)) + ' %') 57 | else: 58 | 59 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 60 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 61 | ax.semilogy((scpy.c/f)*1e6,T,label = 'Through') 62 | ax.grid(which='both') 63 | ax.legend() 64 | ax.set_xlabel("wavelength (um)") 65 | ax.set_ylabel("Magnitude") 66 | plt.tight_layout() 67 | file_name_plot = os.path.join(FDTD_DISK_DIRECTORY_WRITE[1], "frequency_response_T.png") 68 | plt.savefig(file_name_plot) 69 | 70 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 71 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 72 | ax.semilogy((scpy.c/f)*1e6,C,label = 'Coupling') 73 | ax.grid(which='both') 74 | ax.legend() 75 | ax.set_xlabel("wavelength (um)") 76 | ax.set_ylabel("Magnitude") 77 | plt.tight_layout() 78 | file_name_plot = os.path.join(FDTD_DISK_DIRECTORY_WRITE[1], "frequency_response_C.png") 79 | plt.savefig(file_name_plot) 80 | plt.show() 81 | 82 | -------------------------------------------------------------------------------- /FDTD/disk_resonator_coupler/user_inputs/lumerical_files/straight_disk_coupling_section.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/disk_resonator_coupler/user_inputs/lumerical_files/straight_disk_coupling_section.fsp -------------------------------------------------------------------------------- /FDTD/disk_resonator_coupler/user_inputs/user_simulation_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user is must enter the parameters required to setup the 11 | simulation file. 12 | 13 | """ 14 | 15 | # 1. Set the index file name to load one of the lumerical files 16 | # ["straight_disk_coupling_section.fsp","coocentric_disk_coupling_section.fsp","rectangular_disk_coupling_section"] - under development 17 | 18 | file_index = 0 19 | 20 | 21 | # 2. FDTD Simulation Parameters 22 | 23 | # 2.1 FDTD Simulation Region 24 | simulation_span_z = 3e-6 25 | port_extension = 5e-6 26 | monitor_theta = 0 27 | 28 | # 2.2 Simulation Accuracy 29 | simulation_time = 5000e-15 30 | mesh_accuracy = 3 31 | 32 | # 2.3 Simulation Mesh 33 | enable_dx = True 34 | enable_dy = True 35 | mesh_dx = 100e-9 36 | mesh_dy = 100e-9 37 | 38 | # 3. Mode Source 39 | mode_polarization = 'fundamental TE mode' # or fundamental TM mode 40 | wavelength_start = 1.55e-6 41 | wavelength_stop = 1.55e-6 42 | 43 | # 4. Monitor Properties 44 | frequency_points = 64 45 | 46 | 47 | # 5. Ring Coupler Parameters 48 | ring_radius = 4e-6 49 | wg_bus_width = 0.5e-6 50 | wg_thickness = 0.22e-6 51 | slab_thickness = 0.05e-6 52 | gap = 0.25e-6 53 | bus_angle = 60 -------------------------------------------------------------------------------- /FDTD/edge_coupler/fields/getFields.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the E-fields profile for the device structure 11 | defined in the edge_taper.fsp file 12 | 13 | """ 14 | 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | import scipy.constants as scpy 24 | from config import * 25 | 26 | from FDTD.edge_coupler.override_fdtd_region import override_fdtd 27 | from FDTD.edge_coupler.override_edge_coupler_region import * 28 | 29 | 30 | def getFields(fdtd): 31 | 32 | fdtd.run() 33 | 34 | field_xy = fdtd.getelectric("field_xy") 35 | field_xy = fdtd.getelectric("field_xy") 36 | 37 | field_xz = fdtd.getelectric("field_xz") 38 | 39 | x = fdtd.getdata("field_xy","x").squeeze() 40 | y = fdtd.getdata("field_xy","y").squeeze() 41 | z = fdtd.getdata("field_xz","z").squeeze() 42 | 43 | return x, y, z, field_xy, field_xz 44 | 45 | 46 | 47 | 48 | 49 | 50 | if(__name__=="__main__"): 51 | with lumapi.FDTD(FDTD_EDGE_DIRECTORY_READ) as fdtd: 52 | 53 | # ------------ Comment for Avoiding Overriding the Simulation Region 54 | # override_taper(fdtd=fdtd) 55 | # override_fdtd(fdtd=fdtd) 56 | 57 | x,y,z,E_xy, E_xz = getFields(fdtd=fdtd) 58 | c_wavelength = np.rint(len(E_xy[0,0,0,:])/2) 59 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 60 | 61 | # --------------------------------Top-View--------------------------------- 62 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 63 | cmap = ax.pcolormesh(x*1e6,y*1e6,np.transpose(E_xy[:,:,0,int(c_wavelength)]), 64 | shading = 'gouraud',cmap = 'jet') 65 | fig.colorbar(cmap) 66 | plt.xlabel("x (um)") 67 | plt.ylabel("y (um)") 68 | plt.title('Top-view(xy)') 69 | plt.tight_layout() 70 | file_name_plot = os.path.join(FDTD_EDGE_DIRECTORY_WRITE[2], "E_profile_xy.png") 71 | plt.savefig(file_name_plot) 72 | 73 | # --------------------------------Side-View--------------------------------- 74 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 75 | cmap = ax.pcolormesh(x*1e6,z*1e6,np.transpose(E_xz[:,0,:,int(c_wavelength)]), 76 | shading = 'gouraud',cmap = 'jet') 77 | fig.colorbar(cmap) 78 | plt.xlabel("x (um)") 79 | plt.ylabel("z (um)") 80 | plt.title('Side-view(xz)') 81 | plt.tight_layout() 82 | file_name_plot = os.path.join(FDTD_EDGE_DIRECTORY_WRITE[2], "E_profile_xz.png") 83 | plt.savefig(file_name_plot) 84 | 85 | plt.show() 86 | 87 | -------------------------------------------------------------------------------- /FDTD/edge_coupler/override_edge_coupler_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script overrides the FDTD region for the edge coupler taper simulation. 11 | 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user files 17 | # --------------------------------------------------------------------------- 18 | 19 | import lumapi 20 | from FDTD.edge_coupler.user_inputs.user_simulation_parameters import * 21 | from config import FDTD_EDGE_DIRECTORY_READ 22 | 23 | 24 | 25 | def override_taper(fdtd): 26 | 27 | fdtd.switchtolayout() 28 | 29 | 30 | configuration = ( 31 | ("taper", (("width_wg_left", wg_width_left), 32 | ("width_wg_right", wg_width_right), 33 | ("taper_thickness", wg_thickness), 34 | ("slab_thickness", slab_thickness))), 35 | 36 | ("::model", (("taper_length", taper_length), 37 | ("port_extension", port_extension), 38 | ("FDTD_y_span", simulation_span_y), 39 | ("FDTD_z_span", simulation_span_z))), 40 | 41 | 42 | ) 43 | 44 | 45 | # Populate the waveguide simulation region 46 | 47 | for obj, parameters in configuration: 48 | for k, v in parameters: 49 | fdtd.setnamed(obj, k, v) 50 | 51 | fdtd.save() 52 | 53 | # --------------------------------------------------------------------------- 54 | 55 | 56 | if(__name__=="__main__"): 57 | 58 | with lumapi.FDTD(FDTD_EDGE_DIRECTORY_READ) as fdtd: 59 | override_taper(fdtd=fdtd) 60 | 61 | 62 | -------------------------------------------------------------------------------- /FDTD/edge_coupler/override_fdtd_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script overrides the FDTD simulation region from the edge_taper.fsp 11 | file. 12 | 13 | 14 | """ 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user files 18 | # --------------------------------------------------------------------------- 19 | 20 | import lumapi 21 | from FDTD.edge_coupler.user_inputs.user_simulation_parameters import * 22 | from config import FDTD_EDGE_DIRECTORY_READ 23 | 24 | def override_fdtd(fdtd): 25 | 26 | fdtd.switchtolayout() 27 | 28 | configuration = ( 29 | 30 | 31 | ("source", (("polarization angle", mode_source), 32 | ("waist radius w0", waist_radius), 33 | ("wavelength start", wavelength_start), 34 | ("wavelength stop", wavelength_stop))), 35 | 36 | ("T_exp", (("mode selection", mode_monitor), 37 | )), 38 | 39 | ("mesh", (("dx", mesh_dx), 40 | ("dy", mesh_dy), 41 | ("dz", mesh_dz), 42 | ("override x mesh", enable_dx), 43 | ("override y mesh", enable_dy), 44 | ("override z mesh", enable_dz))), 45 | 46 | ("::model", (("taper_length",taper_length), 47 | ("FDTD_z_span", simulation_span_z), 48 | ("FDTD_y_span", simulation_span_y), 49 | ("port_extension", port_extension))), 50 | 51 | ("FDTD", (("simulation time", simulation_time), 52 | ("mesh accuracy",mesh_accuracy))), 53 | 54 | ) 55 | 56 | # Populate the waveguide simulation region 57 | 58 | for obj, parameters in configuration: 59 | for k, v in parameters: 60 | fdtd.setnamed(obj, k, v) 61 | 62 | fdtd.setglobalmonitor("frequency points",frequency_points) 63 | 64 | fdtd.save() 65 | 66 | 67 | # --------------------------------------------------------------------------- 68 | 69 | 70 | if(__name__=="__main__"): 71 | with lumapi.FDTD(FDTD_EDGE_DIRECTORY_READ) as fdtd: 72 | override_fdtd(fdtd=fdtd) 73 | 74 | 75 | -------------------------------------------------------------------------------- /FDTD/edge_coupler/tip_sweep/getTipSweep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the transmission for the edge coupler structure defined in 11 | the edge_taper.fsp file from the mode expansion monitor 'T_exp'. 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user input files 17 | # --------------------------------------------------------------------------- 18 | 19 | import numpy as np 20 | import lumapi, os 21 | import matplotlib.pyplot as plt 22 | import scipy.constants as scpy 23 | from config import * 24 | 25 | from FDTD.edge_coupler.user_inputs.user_simulation_parameters import * 26 | 27 | from FDTD.edge_coupler.override_fdtd_region import * 28 | from FDTD.edge_coupler.override_edge_coupler_region import * 29 | 30 | def getCouplingResponse(fdtd): 31 | T = (fdtd.getsweepresult("sweep_tip","mode0")) 32 | 33 | 34 | 35 | return T 36 | 37 | 38 | if(__name__=="__main__"): 39 | with lumapi.FDTD(FDTD_EDGE_DIRECTORY_READ) as fdtd: 40 | 41 | # ------------ Comment for Avoiding Overriding the Simulation Region defined in the file 42 | # override_fdtd(fdtd=fdtd) 43 | # override_taper(fdtd=fdtd) 44 | 45 | # ------------ Comment for Avoiding Running Sweep 46 | fdtd.runsweep() 47 | 48 | # Get Coupling and Through 49 | T = getCouplingResponse(fdtd=fdtd) 50 | width_wg_left = np.squeeze(T['width_wg_left']) 51 | through = np.squeeze(T['T_forward']) 52 | gaussian_radius = fdtd.getnamed("source","waist radius w0") 53 | 54 | # --------------------------------Plot-T/C--------------------------------- 55 | 56 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 57 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 58 | ax.plot(width_wg_left*1e9, through, label = 'Fundamental Mode') 59 | ax.grid(which='major') 60 | ax.legend() 61 | ax.set_xlabel("waveguide tip (nm)") 62 | ax.set_ylabel("Magnitude") 63 | ax.set_title("Waist Radius: {:.2f} um".format(gaussian_radius*1e6)) 64 | plt.tight_layout() 65 | file_name_plot = os.path.join(FDTD_EDGE_DIRECTORY_WRITE[3], "Coupling_tip_sweep.png") 66 | plt.savefig(file_name_plot) 67 | -------------------------------------------------------------------------------- /FDTD/edge_coupler/transmission/getFrequencyResponse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the transmission for the fundamental TE or TM mode 11 | of the vertical taper structure defined in the edge_taper.fsp file 12 | from the T_exp monitor. The back reflection from the source is also printed 13 | 14 | """ 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | import scipy.constants as scpy 24 | from config import * 25 | 26 | from FDTD.edge_coupler.override_fdtd_region import override_fdtd 27 | from FDTD.edge_coupler.override_edge_coupler_region import * 28 | 29 | def getTaperResponse(fdtd): 30 | fdtd.run() 31 | T_total = np.squeeze(fdtd.getresult("T_exp","expansion for fundamental").get("T_total")) 32 | T_forward = np.squeeze(fdtd.getresult("T_exp","expansion for fundamental").get("T_forward")) 33 | R = np.squeeze(fdtd.transmission("R")) 34 | f = np.squeeze(fdtd.getdata("T","f")) 35 | 36 | return T_total, T_forward, R, f 37 | 38 | 39 | 40 | if(__name__=="__main__"): 41 | with lumapi.FDTD(FDTD_EDGE_DIRECTORY_READ) as fdtd: 42 | 43 | # ------------ Comment for Avoiding Overriding the Simulation Region 44 | # override_taper(fdtd=fdtd) 45 | # override_fdtd(fdtd=fdtd) 46 | 47 | # -----------------------------Plot-T_forward/T_total------------------------------ 48 | 49 | T_total, T_forward, R, f = getTaperResponse(fdtd=fdtd) 50 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 51 | 52 | # -----------------------------Plot-T_forward/T_total------------------------------ 53 | 54 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 55 | ax.plot((scpy.c/f)*1e6, T_total,'-o',label = 'Total') 56 | ax.plot((scpy.c/f)*1e6, T_forward,'-o',label = 'Fundamental') 57 | ax.legend() 58 | ax.set_xlabel("wavelength (um)") 59 | ax.set_ylabel("Magnitude") 60 | ax.set_title('Mode: ' + mode_fundamental) 61 | plt.ylim([0,1]) 62 | plt.tight_layout() 63 | file_name_plot = os.path.join(FDTD_EDGE_DIRECTORY_WRITE[1], "frequency_response.png") 64 | plt.savefig(file_name_plot) 65 | 66 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 67 | ax.plot((scpy.c/f)*1e6,10*np.log10(T_total),'-o',label = 'Total') 68 | ax.plot((scpy.c/f)*1e6,10*np.log10(abs(T_forward)),'-o',label = 'Fundamental') 69 | ax.legend() 70 | ax.set_xlabel("wavelength (um)") 71 | ax.set_ylabel("Magnitude (dB)") 72 | ax.set_title('Mode: ' + mode_fundamental) 73 | plt.tight_layout() 74 | file_name_plot = os.path.join(FDTD_EDGE_DIRECTORY_WRITE[1], "frequency_response_dB.png") 75 | plt.savefig(file_name_plot) 76 | 77 | plt.show() 78 | 79 | print('Back Reflection: ' + str(round(10*np.log10(abs(R.mean())),2)) + ' dB') -------------------------------------------------------------------------------- /FDTD/edge_coupler/user_inputs/lumerical_files/edge_taper.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/edge_coupler/user_inputs/lumerical_files/edge_taper.fsp -------------------------------------------------------------------------------- /FDTD/edge_coupler/user_inputs/user_simulation_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user is must enter the parameters required to setup the 11 | simulation file. The simulation parameters along with their dimensions are 12 | presented below. 13 | 14 | 15 | """ 16 | 17 | 18 | # Length units are in meters! 19 | 20 | 21 | # 1. Taper Parameters 22 | 23 | taper_length = 100e-6 24 | 25 | 26 | 27 | 28 | # 1.1. Taper-bottom Parameters - Soyrce is attached on this taper 29 | wg_width_left = 0.25e-6 30 | wg_width_right = 0.50e-6 31 | wg_thickness = 0.30e-6 32 | 33 | slab_thickness = 0.0e-6 34 | 35 | 36 | 37 | # 2. FDTD Simulation Parameters 38 | 39 | # 2.1 FDTD Span Region 40 | simulation_span_y = 20e-6 41 | simulation_span_z = 20e-6 42 | simulation_time = 5e-12 43 | 44 | # 2.2.1. Mesh Settings 45 | mesh_accuracy = 1 46 | 47 | # 2.2.2. Override Mesh Settings 48 | mesh_dx = 50e-9 49 | mesh_dy = wg_width_left/2 50 | mesh_dz = 50e-9 51 | enable_dx = 0 52 | enable_dy = 1 53 | enable_dz = 0 54 | 55 | 56 | # 2.3 Source/Monitor Properties 57 | waist_radius = 1.25e-6 58 | wavelength_start = 1.55e-6 - (25.6/2)*1e-9 59 | wavelength_stop = 1.55e-6 + (25.6/2)*1e-9 60 | mode_fundamental = "TE" # Select TE for fundamental TE or TM for fundamental TM 61 | frequency_points = 32 62 | 63 | # 2.4. Port extension 64 | port_extension = 5e-6 65 | 66 | 67 | # 3. Figures 68 | my_dpi = 96 69 | 70 | 71 | # -------------------------- End of Input Section ----------------------------- 72 | 73 | 74 | if(mode_fundamental == "TE"): 75 | mode_monitor = "fundamental TE mode" 76 | else: 77 | mode_monitor = "fundamental TM mode" 78 | 79 | 80 | 81 | if(mode_fundamental == "TE"): 82 | mode_source = 0 83 | else: 84 | mode_source = 90 85 | -------------------------------------------------------------------------------- /FDTD/grating_coupler_2D/README.md: -------------------------------------------------------------------------------- 1 | ## 2D Grating Coupler Simulation (2D FDTD) 2 | 3 | ``` 4 | . 5 | ├── analytical 6 | │ └── 1D_grating_coupler_design.ipynb 7 | ├── index_profile 8 | │ └── index_profile_2D.py 9 | ├── override_fdtd_region.py 10 | ├── override_grating_coupler_region.py 11 | ├── sweep_functions 12 | │ ├── getFiberAngle.py 13 | │ ├── getFiberPosition.py 14 | │ └── getFillFactorSweep.py 15 | ├── transmission 16 | │ └── getFrequencyResponse.py 17 | └── user_inputs 18 | ├── lumerical_files 19 | │ └── grating_coupler_2D.fsp 20 | └── user_simulation_parameters.py 21 | 22 | ``` 23 | 24 | ### Quick Simulation Setup 25 | 26 | 1. After cloning the repository, navigate to `analytical/1D_grating_coupler_design.ipynb` to estimate roughly the grating period based on the slab effective indices from the waveguides, fiber angle of incidences, and refractive indices. 27 | 2. Navigate through the `user_inputs/lumerical_files` directory and edit the Lumerical file `grating_coupler_2D.fsp` to define the simulation materials for the cladding, core, and box layers along with their dimensions. 28 | 3. Edit the `user_inputs/user_simulation_parameters.py` to define the simulation properties, region, and structure dimensions. Follow the instructions written in the file. 29 | 4. Run the files in the `sweep_functions` directory to perform the desired parameter sweeps and obtain the results. -------------------------------------------------------------------------------- /FDTD/grating_coupler_2D/index_profile/index_profile_2D.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the refractive index profile for the device structure 11 | defined in the edge_taper.fsp file 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user input files 17 | # --------------------------------------------------------------------------- 18 | 19 | import numpy as np 20 | import lumapi 21 | import os 22 | import matplotlib.pyplot as plt 23 | from config import * 24 | 25 | from FDTD.grating_coupler_2D.override_fdtd_region import * 26 | from FDTD.grating_coupler_2D.override_grating_coupler_region import * 27 | 28 | # -------------------_----- No inputs are required --------------------------- 29 | 30 | def get_index(fdtd): 31 | """Get the data from the Index monitors.""" 32 | try: 33 | index_data = fdtd.getresult("index_xy", "index") 34 | return index_data 35 | except Exception as e: 36 | print(f"Error getting index data: {e}") 37 | return None 38 | 39 | def plot_index_profile(x, y, index_x, output_path): 40 | """Plot the refractive index profile.""" 41 | px = 1 / plt.rcParams['figure.dpi'] # pixel in inches 42 | fig, ax = plt.subplots(figsize=(512 * px, 256 * px)) 43 | cmap = ax.pcolormesh(x * 1e6, y * 1e6, np.transpose(index_x)) 44 | fig.colorbar(cmap) 45 | plt.xlabel("x (um)") 46 | plt.ylabel("y (um)") 47 | plt.title('Side-view(xz)') 48 | plt.tight_layout() 49 | plt.savefig(output_path) 50 | plt.show() 51 | 52 | if __name__ == "__main__": 53 | with lumapi.FDTD(FDTD_GRATING_COUPLER_2D_DIRECTORY_READ) as fdtd: 54 | # Comment for Avoiding Overriding the Simulation Region 55 | override_grating_coupler(fdtd=fdtd) 56 | override_fdtd(fdtd=fdtd) 57 | 58 | index_data = get_index(fdtd=fdtd) 59 | if index_data is not None: 60 | x = index_data["x"].squeeze() 61 | y = index_data["y"].squeeze() 62 | index_x = np.real(index_data["index_x"].squeeze()) 63 | index_y = np.real(index_data["index_y"].squeeze()) 64 | 65 | output_file_path = os.path.join(FDTD_GRATING_COUPLER_2D_DIRECTORY_WRITE[0], "taper_index_profile_xy.png") 66 | plot_index_profile(x, y, index_x, output_file_path) 67 | else: 68 | print("Failed to retrieve index data.") -------------------------------------------------------------------------------- /FDTD/grating_coupler_2D/override_fdtd_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script overrides the FDTD simulation region from the edge_taper.fsp 11 | file. 12 | 13 | 14 | """ 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user files 18 | # --------------------------------------------------------------------------- 19 | 20 | import lumapi 21 | from FDTD.grating_coupler_2D.user_inputs.user_simulation_parameters import * 22 | from config import FDTD_GRATING_COUPLER_2D_DIRECTORY_READ 23 | 24 | def override_fdtd(fdtd): 25 | 26 | fdtd.switchtolayout() 27 | 28 | configuration = ( 29 | ("::model", ( 30 | ("FDTD_y_min", simulation_min_y), 31 | ("fiber_position_x", fiber_position_x), 32 | ("fiber_angle", fiber_angle) 33 | )), 34 | ("FDTD", ( 35 | ("simulation time", simulation_time), 36 | ("mesh accuracy", mesh_accuracy) 37 | )), 38 | 39 | ("fiber", ( 40 | ("polarization angle", mode_source), 41 | ("angle theta", fiber_angle), 42 | ("x", fiber_position_x), 43 | ("waist radius w0", waist_radius), 44 | ("distance from waist", distance_from_waist), 45 | ("override global source settings", 1), 46 | ("wavelength start", wavelength_start), 47 | ("wavelength stop", wavelength_stop) 48 | )), 49 | 50 | 51 | # ("mesh", ( 52 | # ("dx", mesh_dx), 53 | # ("dy", mesh_dy), 54 | # ("dz", mesh_dz), 55 | # ("override x mesh", enable_dx), 56 | # ("override y mesh", enable_dy), 57 | # ("override z mesh", enable_dz) 58 | # )), 59 | 60 | ) 61 | 62 | # Populate the waveguide simulation region 63 | 64 | for obj, parameters in configuration: 65 | for k, v in parameters: 66 | fdtd.setnamed(obj, k, v) 67 | 68 | fdtd.setglobalmonitor("frequency points",frequency_points) 69 | 70 | fdtd.save() 71 | 72 | 73 | # --------------------------------------------------------------------------- 74 | 75 | 76 | if(__name__=="__main__"): 77 | with lumapi.FDTD(FDTD_GRATING_COUPLER_2D_DIRECTORY_READ) as fdtd: 78 | override_fdtd(fdtd=fdtd) 79 | 80 | 81 | -------------------------------------------------------------------------------- /FDTD/grating_coupler_2D/override_grating_coupler_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script overrides the FDTD region for the edge coupler taper simulation. 11 | 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user files 17 | # --------------------------------------------------------------------------- 18 | 19 | import lumapi 20 | from FDTD.grating_coupler_2D.user_inputs.user_simulation_parameters import * 21 | from config import FDTD_GRATING_COUPLER_2D_DIRECTORY_READ 22 | 23 | 24 | 25 | def override_grating_coupler(fdtd): 26 | 27 | fdtd.switchtolayout() 28 | 29 | 30 | configuration = ( 31 | ("::model", ( 32 | ("cladding_thickness", cladding_thickness), 33 | ("box_thickness", box_thickness), 34 | )), 35 | 36 | ("grating_coupler", ( 37 | ("wg_thickness", wg_thickness), 38 | ("slab_thickness", slab_thickness), 39 | ("grating_period", period), 40 | ("fill_factor", fill_factor), 41 | ("gc_sections", gc_sections), 42 | ("port_extension", port_extension) 43 | )), 44 | 45 | ) 46 | 47 | 48 | # Populate the waveguide simulation region 49 | 50 | for obj, parameters in configuration: 51 | for k, v in parameters: 52 | fdtd.setnamed(obj, k, v) 53 | 54 | fdtd.save() 55 | 56 | # --------------------------------------------------------------------------- 57 | 58 | 59 | if(__name__=="__main__"): 60 | 61 | with lumapi.FDTD(FDTD_GRATING_COUPLER_2D_DIRECTORY_READ) as fdtd: 62 | override_grating_coupler(fdtd=fdtd) 63 | 64 | 65 | -------------------------------------------------------------------------------- /FDTD/grating_coupler_2D/user_inputs/lumerical_files/grating_coupler_2D.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/grating_coupler_2D/user_inputs/lumerical_files/grating_coupler_2D.fsp -------------------------------------------------------------------------------- /FDTD/grating_coupler_2D/user_inputs/user_simulation_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User Inputs Required 9 | 10 | This file contains the parameters necessary to set up the simulation. 11 | Users must input the required values to configure the simulation environment. 12 | The parameters and their respective units are listed below. 13 | """ 14 | 15 | # Length units are in meters! 16 | 17 | # 1. Simulation Parameters 18 | simulation_min_y = -5.0e-6 19 | 20 | # 2. Cladding Dimensions. Note, waveguide y min = 0. 21 | cladding_thickness = 1.5e-6 22 | 23 | # 3. Waveguide Dimensions - Slab Waveguide 24 | wg_thickness = 0.22e-6 25 | 26 | # 3.1 Set slab thickness > 0 to enable a slab waveguide 27 | slab_thickness = 0.110e-6 28 | 29 | # 4. Box Layer Thickness 30 | box_thickness = 3.0e-6 31 | 32 | # 5. Substrate Layer Thickness 33 | sub_thickness = 10e-6 34 | 35 | # 6. Grating Coupler Parameters 36 | period = 0.657e-6 # Grating Period 37 | fill_factor = 0.5 # Fill Factor 38 | gc_sections = 50 # Number of Gratings Sections 39 | port_extension = 15.0e-6 # Port Extension 40 | 41 | # 7. Input Optical Source Parameters 42 | wavelength_center = 1.55e-6 # Central Wavelength 43 | wavelength_span = 0.1e-6 # Wavelength Span 44 | polarization = 'TE' # 'TE' or 'TM' 45 | 46 | # 7.1 Optical Fibre Parameters (Gaussian Source) 47 | fiber_position_x = 4.5e-6 # Position of the optical source on GC 48 | fiber_angle = -12 # Angle of the optical source - Incident Angle 49 | waist_radius = 4.5e-6 50 | distance_from_waist = 0.0e-6 51 | 52 | 53 | # 10. 2D FDTD Simulation Parameters 54 | 55 | # 10.1 2D FDTD Span Region 56 | simulation_time = 5e-12 57 | 58 | # 10.2 Mesh Settings 59 | mesh_accuracy = 3 60 | 61 | # 10.2 Mesh Settings 62 | # mesh_dy = wg_width / 2 63 | # mesh_dz = 50e-9 64 | # enable_dx = 0 65 | # enable_dy = 1 66 | # enable_dz = 0 67 | 68 | # 10.3 Source/Monitor Properties 69 | mode_fundamental = "TE" # Select TE for fundamental TE or TM for fundamental TM 70 | frequency_points = 64 71 | 72 | # 11. Figures 73 | my_dpi = 96 74 | 75 | # -------------------------- End of Input Section ----------------------------- 76 | 77 | wavelength_start = wavelength_center - wavelength_span / 2 78 | wavelength_stop = wavelength_center + wavelength_span / 2 79 | 80 | 81 | if mode_fundamental == "TE": 82 | mode_source = 90 83 | else: 84 | mode_source = 0 85 | -------------------------------------------------------------------------------- /FDTD/grating_coupler_rectangular_3D/README.md: -------------------------------------------------------------------------------- 1 | ## 2D Grating Coupler Simulation (2D FDTD) 2 | 3 | ``` 4 | . 5 | ├── analytical 6 | │ └── 1D_grating_coupler_design.ipynb 7 | ├── index_profile 8 | │ └── index_profile_2D.py 9 | ├── override_fdtd_region.py 10 | ├── override_grating_coupler_region.py 11 | ├── sweep_functions 12 | │ ├── getFiberAngle.py 13 | │ ├── getFiberPosition.py 14 | │ └── getFillFactorSweep.py 15 | ├── transmission 16 | │ └── getFrequencyResponse.py 17 | └── user_inputs 18 | ├── lumerical_files 19 | │ └── grating_coupler_2D.fsp 20 | └── user_simulation_parameters.py 21 | 22 | ``` 23 | 24 | ### Quick Simulation Setup 25 | 26 | 1. After cloning the repository, navigate to `analytical/1D_grating_coupler_design.ipynb` to estimate roughly the grating period based on the slab effective indices from the waveguides, fiber angle of incidences, and refractive indices. 27 | 2. Navigate through the `user_inputs/lumerical_files` directory and edit the Lumerical file `grating_coupler_2D.fsp` to define the simulation materials for the cladding, core, and box layers along with their dimensions. 28 | 3. Edit the `user_inputs/user_simulation_parameters.py` to define the simulation properties, region, and structure dimensions. Follow the instructions written in the file. 29 | 4. Run the files in the `sweep_functions` directory to perform the desired parameter sweeps and obtain the results. -------------------------------------------------------------------------------- /FDTD/grating_coupler_rectangular_3D/index_profile/index_profile_2D.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the refractive index profile for the device structure 11 | defined in the edge_taper.fsp file 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user input files 17 | # --------------------------------------------------------------------------- 18 | 19 | import numpy as np 20 | import lumapi 21 | import os 22 | import matplotlib.pyplot as plt 23 | from config import * 24 | 25 | from FDTD.grating_coupler_2D.override_fdtd_region import * 26 | from FDTD.grating_coupler_2D.override_grating_coupler_region import * 27 | 28 | # -------------------_----- No inputs are required --------------------------- 29 | 30 | def get_index(fdtd): 31 | """Get the data from the Index monitors.""" 32 | try: 33 | index_data = fdtd.getresult("index_xy", "index") 34 | return index_data 35 | except Exception as e: 36 | print(f"Error getting index data: {e}") 37 | return None 38 | 39 | def plot_index_profile(x, y, index_x, output_path): 40 | """Plot the refractive index profile.""" 41 | px = 1 / plt.rcParams['figure.dpi'] # pixel in inches 42 | fig, ax = plt.subplots(figsize=(512 * px, 256 * px)) 43 | cmap = ax.pcolormesh(x * 1e6, y * 1e6, np.transpose(index_x)) 44 | fig.colorbar(cmap) 45 | plt.xlabel("x (um)") 46 | plt.ylabel("y (um)") 47 | plt.title('Side-view(xz)') 48 | plt.tight_layout() 49 | plt.savefig(output_path) 50 | plt.show() 51 | 52 | if __name__ == "__main__": 53 | with lumapi.FDTD(FDTD_GRATING_COUPLER_2D_DIRECTORY_READ) as fdtd: 54 | # Comment for Avoiding Overriding the Simulation Region 55 | override_grating_coupler(fdtd=fdtd) 56 | override_fdtd(fdtd=fdtd) 57 | 58 | index_data = get_index(fdtd=fdtd) 59 | if index_data is not None: 60 | x = index_data["x"].squeeze() 61 | y = index_data["y"].squeeze() 62 | index_x = np.real(index_data["index_x"].squeeze()) 63 | index_y = np.real(index_data["index_y"].squeeze()) 64 | 65 | output_file_path = os.path.join(FDTD_GRATING_COUPLER_2D_DIRECTORY_WRITE[0], "taper_index_profile_xy.png") 66 | plot_index_profile(x, y, index_x, output_file_path) 67 | else: 68 | print("Failed to retrieve index data.") -------------------------------------------------------------------------------- /FDTD/grating_coupler_rectangular_3D/override_fdtd_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script overrides the FDTD simulation region from the edge_taper.fsp 11 | file. 12 | 13 | 14 | """ 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user files 18 | # --------------------------------------------------------------------------- 19 | 20 | import lumapi 21 | from FDTD.grating_coupler_2D.user_inputs.user_simulation_parameters import * 22 | from config import FDTD_GRATING_COUPLER_2D_DIRECTORY_READ 23 | 24 | def override_fdtd(fdtd): 25 | 26 | fdtd.switchtolayout() 27 | 28 | configuration = ( 29 | ("::model", ( 30 | ("FDTD_y_min", simulation_min_y), 31 | ("fiber_position_x", fiber_position_x), 32 | ("fiber_angle", fiber_angle) 33 | )), 34 | ("FDTD", ( 35 | ("simulation time", simulation_time), 36 | ("mesh accuracy", mesh_accuracy) 37 | )), 38 | 39 | ("fiber", ( 40 | ("polarization angle", mode_source), 41 | ("angle theta", fiber_angle), 42 | ("x", fiber_position_x), 43 | ("waist radius w0", waist_radius), 44 | ("distance from waist", distance_from_waist), 45 | ("override global source settings", 1), 46 | ("wavelength start", wavelength_start), 47 | ("wavelength stop", wavelength_stop) 48 | )), 49 | 50 | 51 | # ("mesh", ( 52 | # ("dx", mesh_dx), 53 | # ("dy", mesh_dy), 54 | # ("dz", mesh_dz), 55 | # ("override x mesh", enable_dx), 56 | # ("override y mesh", enable_dy), 57 | # ("override z mesh", enable_dz) 58 | # )), 59 | 60 | ) 61 | 62 | # Populate the waveguide simulation region 63 | 64 | for obj, parameters in configuration: 65 | for k, v in parameters: 66 | fdtd.setnamed(obj, k, v) 67 | 68 | fdtd.setglobalmonitor("frequency points",frequency_points) 69 | 70 | fdtd.save() 71 | 72 | 73 | # --------------------------------------------------------------------------- 74 | 75 | 76 | if(__name__=="__main__"): 77 | with lumapi.FDTD(FDTD_GRATING_COUPLER_2D_DIRECTORY_READ) as fdtd: 78 | override_fdtd(fdtd=fdtd) 79 | 80 | 81 | -------------------------------------------------------------------------------- /FDTD/grating_coupler_rectangular_3D/override_grating_coupler_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script overrides the FDTD region for the edge coupler taper simulation. 11 | 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user files 17 | # --------------------------------------------------------------------------- 18 | 19 | import lumapi 20 | from FDTD.grating_coupler_2D.user_inputs.user_simulation_parameters import * 21 | from config import FDTD_GRATING_COUPLER_2D_DIRECTORY_READ 22 | 23 | 24 | 25 | def override_grating_coupler(fdtd): 26 | 27 | fdtd.switchtolayout() 28 | 29 | 30 | configuration = ( 31 | ("::model", ( 32 | ("cladding_thickness", cladding_thickness), 33 | ("box_thickness", box_thickness), 34 | )), 35 | 36 | ("grating_coupler", ( 37 | ("wg_thickness", wg_thickness), 38 | ("slab_thickness", slab_thickness), 39 | ("grating_period", period), 40 | ("fill_factor", fill_factor), 41 | ("gc_sections", gc_sections), 42 | ("port_extension", port_extension) 43 | )), 44 | 45 | ) 46 | 47 | 48 | # Populate the waveguide simulation region 49 | 50 | for obj, parameters in configuration: 51 | for k, v in parameters: 52 | fdtd.setnamed(obj, k, v) 53 | 54 | fdtd.save() 55 | 56 | # --------------------------------------------------------------------------- 57 | 58 | 59 | if(__name__=="__main__"): 60 | 61 | with lumapi.FDTD(FDTD_GRATING_COUPLER_2D_DIRECTORY_READ) as fdtd: 62 | override_grating_coupler(fdtd=fdtd) 63 | 64 | 65 | -------------------------------------------------------------------------------- /FDTD/grating_coupler_rectangular_3D/user_inputs/lumerical_files/grating_coupler_rectangular_3D.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/grating_coupler_rectangular_3D/user_inputs/lumerical_files/grating_coupler_rectangular_3D.fsp -------------------------------------------------------------------------------- /FDTD/grating_coupler_rectangular_3D/user_inputs/user_simulation_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User Inputs Required 9 | 10 | This file contains the parameters necessary to set up the simulation. 11 | Users must input the required values to configure the simulation environment. 12 | The parameters and their respective units are listed below. 13 | """ 14 | 15 | # Length units are in meters! 16 | 17 | # 1. Simulation Parameters 18 | simulation_min_y = -7.0e-6 19 | 20 | # 2. Cladding Dimensions. Note, waveguide y min = 0. 21 | cladding_thickness = 1.5e-6 22 | 23 | # 3. Waveguide Dimensions - Slab Waveguide 24 | wg_thickness = 0.30e-6 25 | 26 | # 3.1 Set slab thickness > 0 to enable a slab waveguide 27 | slab_thickness = 0.05e-6 28 | 29 | # 4. Box Layer Thickness 30 | box_thickness = 6.0e-6 31 | 32 | # 5. Substrate Layer Thickness 33 | sub_thickness = 10e-6 34 | 35 | # 6. Grating Coupler Parameters 36 | period = 0.80e-6 # Grating Period 37 | fill_factor = 0.4 # Fill Factor 38 | gc_sections = 50 # Number of Gratings Sections 39 | port_extension = 15.0e-6 # Port Extension 40 | 41 | # 7. Input Optical Source Parameters 42 | wavelength_center = 1.55e-6 # Central Wavelength 43 | wavelength_span = 0.30e-6 # Wavelength Span 44 | polarization = 'TE' # 'TE' or 'TM' 45 | 46 | # 7.1 Optical Fibre Parameters (Gaussian Source) 47 | fiber_position_x = 4.5e-6 # Position of the optical source on GC 48 | fiber_angle = -12 # Angle of the optical source - Incident Angle 49 | waist_radius = 4.5e-6 50 | distance_from_waist = 0.0e-6 51 | 52 | 53 | # 10. 2D FDTD Simulation Parameters 54 | 55 | # 10.1 2D FDTD Span Region 56 | simulation_time = 5e-12 57 | 58 | # 10.2 Mesh Settings 59 | mesh_accuracy = 3 60 | 61 | # 10.2 Mesh Settings 62 | # mesh_dy = wg_width / 2 63 | # mesh_dz = 50e-9 64 | # enable_dx = 0 65 | # enable_dy = 1 66 | # enable_dz = 0 67 | 68 | # 10.3 Source/Monitor Properties 69 | mode_fundamental = "TE" # Select TE for fundamental TE or TM for fundamental TM 70 | frequency_points = 64 71 | 72 | # 11. Figures 73 | my_dpi = 96 74 | 75 | # -------------------------- End of Input Section ----------------------------- 76 | 77 | wavelength_start = wavelength_center - wavelength_span / 2 78 | wavelength_stop = wavelength_center + wavelength_span / 2 79 | 80 | 81 | if mode_fundamental == "TE": 82 | mode_source = 90 83 | else: 84 | mode_source = 0 85 | -------------------------------------------------------------------------------- /FDTD/laser_tapered_waveguide/user_inputs/lumerical_files/laser_mesa_waveguide_tapered.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/laser_tapered_waveguide/user_inputs/lumerical_files/laser_mesa_waveguide_tapered.fsp -------------------------------------------------------------------------------- /FDTD/mmi_couplers/1x2/fields/getFields.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the E-fields profile for the device structure 11 | defined in the MMI_1x2.fsp file 12 | 13 | """ 14 | 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | from matplotlib.colors import LogNorm 24 | from config import * 25 | 26 | 27 | 28 | def getFields(fdtd): 29 | 30 | 31 | field_xy = fdtd.getelectric("xy_topview") 32 | 33 | x = fdtd.getdata("xy_topview","x").squeeze() 34 | y = fdtd.getdata("xy_topview","y").squeeze() 35 | 36 | return x,y,field_xy 37 | 38 | 39 | 40 | 41 | 42 | 43 | if(__name__=="__main__"): 44 | with lumapi.FDTD(FDTD_MMI_DIRECTORY_READ[0]) as fdtd: 45 | 46 | # ------------ Comment for Avoiding Overriding the Simulation Region 47 | # override_cross(fdtd=fdtd) 48 | # fdtd.run() 49 | 50 | x,y,E_xy = getFields(fdtd=fdtd) 51 | c_wavelength = np.rint(len(E_xy[0,0,0,:])/2) 52 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 53 | 54 | # --------------------------------Top-View--------------------------------- 55 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 56 | cmap = ax.pcolormesh(x*1e6, y*1e6, (np.transpose(E_xy[:, :, 0, int(c_wavelength)])), 57 | shading='gouraud', cmap='jet', norm=LogNorm(vmin=1e-3, vmax=1)) 58 | fig.colorbar(cmap) 59 | plt.xlabel("x (um)") 60 | plt.ylabel("y (um)") 61 | plt.title('Top-view(xy)') 62 | plt.tight_layout() 63 | file_name_plot = os.path.join(FDTD_MMI_DIRECTORY_WRITE[2], "E_profile_xy_MMI1x2.png") 64 | plt.savefig(file_name_plot) 65 | 66 | 67 | 68 | plt.show() 69 | 70 | -------------------------------------------------------------------------------- /FDTD/mmi_couplers/1x2/user_inputs/lumerical_files/MMI_1x2.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/mmi_couplers/1x2/user_inputs/lumerical_files/MMI_1x2.fsp -------------------------------------------------------------------------------- /FDTD/mmi_couplers/2x2/user_inputs/lumerical_files/MMI_2x2.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/mmi_couplers/2x2/user_inputs/lumerical_files/MMI_2x2.fsp -------------------------------------------------------------------------------- /FDTD/ring_resonator_coupler/fields/getFields.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the E-fields profile for the device structure 11 | defined in the *.fsp files 12 | 13 | """ 14 | 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | from matplotlib.colors import LogNorm 24 | from config import * 25 | 26 | from FDTD.ring_resonator_coupler.user_inputs.user_simulation_parameters import * 27 | 28 | from FDTD.ring_resonator_coupler.override_fdtd_region import * 29 | from FDTD.ring_resonator_coupler.override_ring_coupler_region import * 30 | 31 | def getFields(fdtd): 32 | 33 | fdtd.run() 34 | 35 | field_xy = fdtd.getelectric("xy_topview") 36 | 37 | x = fdtd.getdata("xy_topview","x").squeeze() 38 | y = fdtd.getdata("xy_topview","y").squeeze() 39 | 40 | return x,y,field_xy 41 | 42 | 43 | 44 | 45 | 46 | 47 | if(__name__=="__main__"): 48 | with lumapi.FDTD(FDTD_RING_DIRECTORY_READ[file_index]) as fdtd: 49 | 50 | # ------------ Comment for Avoiding Overriding the Simulation Region defined in the file 51 | # override_fdtd(fdtd=fdtd) 52 | # override_ring_coupler(fdtd=fdtd) 53 | 54 | 55 | x,y,E_xy = getFields(fdtd=fdtd) 56 | c_wavelength = np.rint(len(E_xy[0,0,0,:])/2) 57 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 58 | 59 | # --------------------------------Top-View--------------------------------- 60 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 61 | cmap = ax.pcolormesh(x*1e6,y*1e6,(np.transpose(E_xy[:,:,0,int(c_wavelength)])), 62 | shading = 'gouraud',cmap = 'jet', norm = LogNorm(vmin=1e-4, vmax=1)) 63 | fig.colorbar(cmap) 64 | plt.xlabel("x (um)") 65 | plt.ylabel("y (um)") 66 | plt.title('Top-view(xy)') 67 | plt.tight_layout() 68 | file_name_plot = os.path.join(FDTD_RING_DIRECTORY_WRITE[2], "E_profile_xy.png") 69 | plt.savefig(file_name_plot) 70 | 71 | 72 | 73 | plt.show() 74 | 75 | -------------------------------------------------------------------------------- /FDTD/ring_resonator_coupler/gap_sweep/getGapSweep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the transmission and crosstalk for the waveguide crossing 11 | structure defined in the waveguide_crossing_multi_wg_taper.fsp file 12 | from the 'through' and crosstalk monitor. 13 | 14 | """ 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | import scipy.constants as scpy 24 | from config import * 25 | 26 | from FDTD.ring_resonator_coupler.user_inputs.user_simulation_parameters import * 27 | 28 | from FDTD.ring_resonator_coupler.override_fdtd_region import * 29 | from FDTD.ring_resonator_coupler.override_ring_coupler_region import * 30 | 31 | def getCouplingResponse(fdtd): 32 | T = (fdtd.getsweepresult("sweep_gap","T")) 33 | C = (fdtd.getsweepresult("sweep_gap","C")) 34 | 35 | 36 | return T, C 37 | 38 | 39 | 40 | if(__name__=="__main__"): 41 | with lumapi.FDTD(FDTD_RING_DIRECTORY_READ[file_index]) as fdtd: 42 | 43 | # ------------ Comment for Avoiding Overriding the Simulation Region defined in the file 44 | override_fdtd(fdtd=fdtd) 45 | override_ring_coupler(fdtd=fdtd) 46 | 47 | # ------------ Comment for Avoiding Running Sweep 48 | fdtd.runsweep() 49 | 50 | 51 | # Get Coupling and Through 52 | T, C = getCouplingResponse(fdtd=fdtd) 53 | gap = np.squeeze(T['gap']) 54 | through = np.squeeze(T['T']) 55 | bar = np.squeeze(C['T']) 56 | 57 | 58 | # --------------------------------Plot-T/C--------------------------------- 59 | 60 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 61 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 62 | ax.semilogy(gap*1e9, through, label = 'Through') 63 | ax.grid(which='both') 64 | ax.legend() 65 | ax.set_xlabel("gap (nm)") 66 | ax.set_ylabel("Magnitude") 67 | ax.set_title(fdtd.getnamed("source","mode selection")) 68 | plt.tight_layout() 69 | file_name_plot = os.path.join(FDTD_RING_DIRECTORY_WRITE[1], "frequency_response_T.png") 70 | plt.savefig(file_name_plot) 71 | 72 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 73 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 74 | ax.semilogy(gap*1e9, bar,label = 'Coupling') 75 | ax.grid(which='both') 76 | ax.legend() 77 | ax.set_title(fdtd.getnamed("source","mode selection")) 78 | ax.set_xlabel("gap (nm)") 79 | ax.set_ylabel("Magnitude") 80 | plt.tight_layout() 81 | file_name_plot = os.path.join(FDTD_RING_DIRECTORY_WRITE[1], "frequency_response_C.png") 82 | plt.savefig(file_name_plot) 83 | 84 | 85 | 86 | 87 | 88 | plt.show() -------------------------------------------------------------------------------- /FDTD/ring_resonator_coupler/override_fdtd_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script overrides the FDTD simulation region from the *.fsp files. 11 | 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user files 17 | # --------------------------------------------------------------------------- 18 | 19 | import lumapi 20 | from FDTD.ring_resonator_coupler.user_inputs.user_simulation_parameters import * 21 | from config import FDTD_RING_DIRECTORY_READ 22 | 23 | def override_fdtd(fdtd): 24 | 25 | fdtd.switchtolayout() 26 | 27 | configuration = ( 28 | 29 | ("source", (("mode selection", mode_polarization), 30 | ("wavelength start", wavelength_start), 31 | ("wavelength stop", wavelength_stop))), 32 | 33 | ("C", (("mode selection", mode_polarization),)), 34 | 35 | ("T", (("mode selection", mode_polarization),)), 36 | 37 | ("mesh", (("dx", mesh_dx), 38 | ("dy", mesh_dy), 39 | ("override x mesh", enable_dx), 40 | ("override y mesh", enable_dy), 41 | ("override z mesh", False))), 42 | 43 | ("::model", (("monitor_theta", monitor_theta), 44 | ("FDTD_z_span", simulation_span_z), 45 | ("port_extension", port_extension))), 46 | 47 | ("FDTD", (("simulation time", simulation_time), 48 | ("mesh accuracy", mesh_accuracy))), 49 | ) 50 | 51 | 52 | # Populate the waveguide simulation region 53 | 54 | for obj, parameters in configuration: 55 | for k, v in parameters: 56 | fdtd.setnamed(obj, k, v) 57 | 58 | fdtd.setglobalmonitor("frequency points",frequency_points) 59 | 60 | fdtd.save() 61 | 62 | 63 | # --------------------------------------------------------------------------- 64 | 65 | 66 | if(__name__=="__main__"): 67 | with lumapi.FDTD(FDTD_RING_DIRECTORY_READ[file_index]) as fdtd: 68 | override_fdtd(fdtd=fdtd) 69 | 70 | 71 | -------------------------------------------------------------------------------- /FDTD/ring_resonator_coupler/override_ring_coupler_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script overrides the FDTD region for the ring coupler simulation. 11 | 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user files 17 | # --------------------------------------------------------------------------- 18 | 19 | import lumapi 20 | from FDTD.vertical_taper.user_inputs.user_simulation_parameters import * 21 | from config import FDTD_RING_DIRECTORY_READ 22 | from FDTD.ring_resonator_coupler.user_inputs.user_simulation_parameters import * 23 | 24 | 25 | 26 | 27 | def override_ring_coupler(fdtd): 28 | 29 | fdtd.switchtolayout() 30 | 31 | 32 | configuration = ( 33 | ("ring", (("ring_radius", ring_radius), 34 | ("wg_ring_width", wg_ring_width), 35 | ("wg_bus_width", wg_bus_width), 36 | ("wg_thickness", wg_thickness), 37 | ("slab_thickness", slab_thickness), 38 | ("bus_angle", bus_angle), 39 | ("gap", gap))), 40 | 41 | ) 42 | 43 | 44 | # Populate the waveguide simulation region 45 | 46 | for obj, parameters in configuration: 47 | for k, v in parameters: 48 | fdtd.setnamed(obj, k, v) 49 | 50 | fdtd.save() 51 | 52 | # --------------------------------------------------------------------------- 53 | 54 | 55 | if(__name__=="__main__"): 56 | 57 | with lumapi.FDTD(FDTD_RING_DIRECTORY_READ[file_index]) as fdtd: 58 | override_ring_coupler(fdtd=fdtd) 59 | 60 | 61 | -------------------------------------------------------------------------------- /FDTD/ring_resonator_coupler/transmission/getFrequencyResponse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the transmission and coupling for the ring coupler 11 | structure defined in the *.fsp files from the 'T' and 'C' monitors. 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user input files 17 | # --------------------------------------------------------------------------- 18 | 19 | import numpy as np 20 | import lumapi, os 21 | import matplotlib.pyplot as plt 22 | import scipy.constants as scpy 23 | from config import * 24 | 25 | from FDTD.ring_resonator_coupler.user_inputs.user_simulation_parameters import * 26 | 27 | from FDTD.ring_resonator_coupler.override_fdtd_region import * 28 | from FDTD.ring_resonator_coupler.override_ring_coupler_region import * 29 | 30 | 31 | def getCouplingResponse(fdtd): 32 | fdtd.run() 33 | T = np.squeeze(fdtd.getresult("T","expansion for ").get("T_forward")) 34 | C = np.squeeze(fdtd.getresult("C","expansion for ").get("T_forward")) 35 | f = np.squeeze(fdtd.getdata("through","f")) 36 | 37 | return T, C, f 38 | 39 | 40 | 41 | if(__name__=="__main__"): 42 | with lumapi.FDTD(FDTD_RING_DIRECTORY_READ[file_index]) as fdtd: 43 | 44 | # ------------ Comment for Avoiding Overriding the Simulation Region defined in the file 45 | override_fdtd(fdtd=fdtd) 46 | override_ring_coupler(fdtd=fdtd) 47 | 48 | # --------------------------------Plot-T/R--------------------------------- 49 | 50 | T, C, f = getCouplingResponse(fdtd=fdtd) 51 | 52 | # --------------------------------Plot-T/R--------------------------------- 53 | 54 | if(T.size==1): 55 | print("T: " + str(round(T*100,2)) + ' %') 56 | print("C: " + str(round(C*100,2)) + ' %') 57 | else: 58 | 59 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 60 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 61 | ax.semilogy((scpy.c/f)*1e6,T,label = 'Through') 62 | ax.grid(which='both') 63 | ax.legend() 64 | ax.set_xlabel("wavelength (um)") 65 | ax.set_ylabel("Magnitude") 66 | plt.tight_layout() 67 | file_name_plot = os.path.join(FDTD_RING_DIRECTORY_WRITE[1], "frequency_response_T.png") 68 | plt.savefig(file_name_plot) 69 | 70 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 71 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 72 | ax.semilogy((scpy.c/f)*1e6,C,label = 'Coupling') 73 | ax.grid(which='both') 74 | ax.legend() 75 | ax.set_xlabel("wavelength (um)") 76 | ax.set_ylabel("Magnitude") 77 | plt.tight_layout() 78 | file_name_plot = os.path.join(FDTD_RING_DIRECTORY_WRITE[1], "frequency_response_C.png") 79 | plt.savefig(file_name_plot) 80 | plt.show() 81 | 82 | -------------------------------------------------------------------------------- /FDTD/ring_resonator_coupler/user_inputs/lumerical_files/coocentric_ring_coupling_section.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/ring_resonator_coupler/user_inputs/lumerical_files/coocentric_ring_coupling_section.fsp -------------------------------------------------------------------------------- /FDTD/ring_resonator_coupler/user_inputs/lumerical_files/rectangular_ring_coupling_section.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/ring_resonator_coupler/user_inputs/lumerical_files/rectangular_ring_coupling_section.fsp -------------------------------------------------------------------------------- /FDTD/ring_resonator_coupler/user_inputs/lumerical_files/straight_ring_coupling_section.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/ring_resonator_coupler/user_inputs/lumerical_files/straight_ring_coupling_section.fsp -------------------------------------------------------------------------------- /FDTD/ring_resonator_coupler/user_inputs/user_simulation_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user is must enter the parameters required to setup the 11 | simulation file. 12 | 13 | """ 14 | 15 | # 1. Set the index file name to load one of the lumerical files 16 | # ["straight_ring_coupling_section.fsp","coocentric_ring_coupling_section.fsp","rectangular_ring_coupling_section"] 17 | 18 | file_index = 0 19 | 20 | 21 | # 2. FDTD Simulation Parameters 22 | 23 | # 2.1 FDTD Simulation Region 24 | simulation_span_z = 3e-6 25 | port_extension = 5e-6 26 | monitor_theta = 0 27 | 28 | # 2.2 Simulation Accuracy 29 | simulation_time = 5000e-15 30 | mesh_accuracy = 3 31 | 32 | # 2.3 Simulation Mesh 33 | enable_dx = True 34 | enable_dy = True 35 | mesh_dx = 100e-9 36 | mesh_dy = 100e-9 37 | 38 | # 3. Mode Source 39 | mode_polarization = 'fundamental TE mode' # or fundamental TM mode 40 | wavelength_start = 1.55e-6 41 | wavelength_stop = 1.55e-6 42 | 43 | # 4. Monitor Properties 44 | frequency_points = 64 45 | 46 | 47 | # 5. Ring Coupler Parameters 48 | ring_radius = 10e-6 49 | wg_ring_width = 0.48e-6 50 | wg_bus_width = wg_ring_width 51 | wg_thickness = 0.22e-6 52 | slab_thickness = 0.11e-6 53 | gap = 0.30e-6 54 | bus_angle = 60 -------------------------------------------------------------------------------- /FDTD/swg_grating/Fields/getFields.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the E-fields profile for the device structure 11 | defined in the sub_wavelength_grating.fsp file 12 | 13 | """ 14 | 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | import scipy.constants as scpy 24 | from config import * 25 | 26 | from FDTD.swg_grating.override_fdtd_region import override_fdtd 27 | from FDTD.swg_grating.override_swg_region import * 28 | 29 | 30 | def getFields(fdtd): 31 | 32 | fdtd.run() 33 | 34 | field_xy = fdtd.getelectric("field_xy") 35 | field_xz = fdtd.getelectric("field_xz") 36 | 37 | x = fdtd.getdata("field_xy","x").squeeze() 38 | y = fdtd.getdata("field_xy","y").squeeze() 39 | z = fdtd.getdata("field_xz","z").squeeze() 40 | 41 | return x,y,z,field_xy, field_xz 42 | 43 | 44 | 45 | 46 | 47 | 48 | if(__name__=="__main__"): 49 | with lumapi.FDTD(FDTD_SWG_DIRECTORY_READ) as fdtd: 50 | 51 | # ------------ Comment for Avoiding Overriding the Simulation Region 52 | # override_swg(fdtd=fdtd) 53 | # override_fdtd(fdtd=fdtd) 54 | 55 | x,y,z,E_xy,E_xz = getFields(fdtd=fdtd) 56 | c_wavelength = np.rint(len(E_xy[0,0,0,:])/2) 57 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 58 | 59 | # --------------------------------Top-View--------------------------------- 60 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 61 | cmap = ax.pcolormesh(x*1e6,y*1e6,np.transpose(E_xy[:,:,0,int(c_wavelength)]), 62 | shading = 'gouraud',cmap = 'jet') 63 | fig.colorbar(cmap) 64 | plt.xlabel("x (um)") 65 | plt.ylabel("y (um)") 66 | plt.title('Top-view(xy)') 67 | plt.tight_layout() 68 | file_name_plot = os.path.join(FDTD_SWG_DIRECTORY_WRITE[2], "E_profile_xy.png") 69 | plt.savefig(file_name_plot) 70 | 71 | # --------------------------------Side-View--------------------------------- 72 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 73 | cmap = ax.pcolormesh(x*1e6,z*1e6,np.transpose(E_xz[:,0,:,int(c_wavelength)]), 74 | shading = 'gouraud',cmap = 'jet') 75 | fig.colorbar(cmap) 76 | plt.xlabel("x (um)") 77 | plt.ylabel("z (um)") 78 | plt.title('Side-view(xz)') 79 | plt.tight_layout() 80 | file_name_plot = os.path.join(FDTD_SWG_DIRECTORY_WRITE[2], "E_profile_xz.png") 81 | plt.savefig(file_name_plot) 82 | 83 | plt.show() 84 | 85 | -------------------------------------------------------------------------------- /FDTD/swg_grating/index_profile/index_profile_2D.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the refractive index profile for the device structure 11 | defined in the sub_wavelength_grating.fsp file 12 | 13 | """ 14 | 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | from config import * 24 | 25 | from FDTD.swg_grating.override_fdtd_region import * 26 | from FDTD.swg_grating.override_swg_region import * 27 | 28 | # -------------------_----- No inputs are required --------------------------- 29 | 30 | 31 | def getIndex(fdtd): 32 | 33 | # Get the data from the Index monitors 34 | index_xy = fdtd.getresult("index_xy","index") 35 | index_xz = fdtd.getresult("index_xz","index") 36 | return index_xy, index_xz 37 | 38 | 39 | if(__name__=="__main__"): 40 | with lumapi.FDTD(FDTD_SWG_DIRECTORY_READ) as fdtd: 41 | 42 | # ------------Comment for Avoiding Overriding the Simulation Region 43 | # override_swg(fdtd=fdtd) 44 | # override_fdtd(fdtd=fdtd) 45 | 46 | index_xy, index_xz = getIndex(fdtd=fdtd) 47 | 48 | 49 | 50 | 51 | # --------------------------------Top-View--------------------------------- 52 | x = index_xy["x"].squeeze() 53 | y = index_xy["y"].squeeze() 54 | index_x = np.real(index_xy["index_x"].squeeze()) 55 | 56 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 57 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 58 | cmap = ax.pcolormesh(x*1e6, y*1e6,np.transpose(index_x)) 59 | fig.colorbar(cmap) 60 | plt.xlabel("x (um)") 61 | plt.ylabel("y (um)") 62 | plt.title('Top-view(xy)') 63 | plt.tight_layout() 64 | file_name_plot = os.path.join(FDTD_SWG_DIRECTORY_WRITE[0], "index_profile_xy.png") 65 | plt.savefig(file_name_plot) 66 | plt.show() 67 | 68 | 69 | 70 | # --------------------------------Side-View--------------------------------- 71 | xx = index_xz["x"].squeeze() 72 | z = index_xz["z"].squeeze() 73 | index_z = np.real(index_xz["index_z"].squeeze()) 74 | 75 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 76 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 77 | cmap = ax.pcolormesh(x*1e6, z*1e6,np.transpose(index_z)) 78 | fig.colorbar(cmap) 79 | plt.xlabel("x (um)") 80 | plt.ylabel("z (um)") 81 | plt.title('Side-view(xz)') 82 | plt.tight_layout() 83 | file_name_plot = os.path.join(FDTD_SWG_DIRECTORY_WRITE[0], "index_profile_xz.png") 84 | plt.savefig(file_name_plot) 85 | plt.show() 86 | -------------------------------------------------------------------------------- /FDTD/swg_grating/override_fdtd_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script sets the FDTD region for the sub-wavelength grating simulation. 11 | 12 | There are in total 13 | 14 | 1. ... 15 | """ 16 | 17 | #---------------------------------------------------------------------------- 18 | # Imports from user files 19 | # --------------------------------------------------------------------------- 20 | 21 | import lumapi 22 | from FDTD.swg_grating.user_inputs.user_simulation_parameters import * 23 | from config import FDTD_SWG_DIRECTORY_READ 24 | 25 | def override_fdtd(fdtd): 26 | 27 | fdtd.switchtolayout() 28 | 29 | configuration = ( 30 | 31 | 32 | ("source", (("mode selection", mode_source), 33 | ("wavelength start", wavelength_start), 34 | ("wavelength stop", wavelength_stop))), 35 | 36 | ("R_exp", (("mode selection", mode_monitor), 37 | )), 38 | 39 | ("T_exp", (("mode selection", mode_monitor), 40 | )), 41 | 42 | ("mesh", (("dx", mesh_dx), 43 | ("dy", mesh_dy), 44 | ("dz", mesh_dz), 45 | ("override x mesh", enable_dx), 46 | ("override y mesh", enable_dy), 47 | ("override z mesh", enable_dz))), 48 | 49 | ("::model", (("FTDT_z_span", simulation_span_z), 50 | ("FTDT_y_span", simulation_span_y), 51 | ("port_extension", port_extension))), 52 | 53 | ("FDTD", (("simulation time", simulation_time), 54 | ("mesh accuracy",mesh_accuracy))), 55 | 56 | ) 57 | 58 | # Populate the waveguide simulation region 59 | 60 | for obj, parameters in configuration: 61 | for k, v in parameters: 62 | fdtd.setnamed(obj, k, v) 63 | 64 | fdtd.setglobalmonitor("frequency points",frequency_points) 65 | 66 | fdtd.save() 67 | 68 | 69 | # --------------------------------------------------------------------------- 70 | 71 | 72 | if(__name__=="__main__"): 73 | with lumapi.FDTD(FDTD_SWG_DIRECTORY_READ) as fdtd: 74 | override_fdtd(fdtd=fdtd) 75 | 76 | 77 | -------------------------------------------------------------------------------- /FDTD/swg_grating/override_swg_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script sets the FDTD region for the sub-wavelength grating simulation. 11 | 12 | There are in total 13 | 14 | 1. ... 15 | """ 16 | 17 | #---------------------------------------------------------------------------- 18 | # Imports from user files 19 | # --------------------------------------------------------------------------- 20 | 21 | import lumapi 22 | from FDTD.swg_grating.user_inputs.user_simulation_parameters import * 23 | from config import FDTD_SWG_DIRECTORY_READ 24 | 25 | 26 | 27 | def override_swg(fdtd): 28 | 29 | fdtd.switchtolayout() 30 | 31 | 32 | configuration = ( 33 | ("grating-constructor", (("wg_width", wg_width), 34 | ("wg_thickness", wg_thickness), 35 | ("mirror_periods", mirror_periods), 36 | ("pitch", pitch), 37 | ("duty_cycle", duty_cycle), 38 | ("etch_depth", etch_depth))), 39 | 40 | 41 | ) 42 | 43 | # Populate the waveguide simulation region 44 | 45 | for obj, parameters in configuration: 46 | for k, v in parameters: 47 | fdtd.setnamed(obj, k, v) 48 | 49 | fdtd.save() 50 | 51 | # --------------------------------------------------------------------------- 52 | 53 | 54 | if(__name__=="__main__"): 55 | 56 | with lumapi.FDTD(FDTD_SWG_DIRECTORY_READ) as fdtd: 57 | override_swg(fdtd=fdtd) 58 | 59 | 60 | -------------------------------------------------------------------------------- /FDTD/swg_grating/transmission/getFrequencyResponse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the transmission and reflection for the sub-wavelength 11 | bragg grating structure defined in the sub_wavelength_grating.fsp file 12 | from the T and R monitors 13 | 14 | """ 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | import scipy.constants as scpy 24 | from config import * 25 | 26 | from FDTD.swg_grating.override_fdtd_region import override_fdtd 27 | from FDTD.swg_grating.override_swg_region import * 28 | 29 | def getBraggResponse(fdtd): 30 | fdtd.run() 31 | T = np.squeeze(fdtd.transmission("T")) 32 | R = np.squeeze(fdtd.transmission("R")) 33 | f = np.squeeze(fdtd.getdata("T","f")) 34 | 35 | return T, R, f 36 | 37 | 38 | 39 | if(__name__=="__main__"): 40 | with lumapi.FDTD(FDTD_SWG_DIRECTORY_READ) as fdtd: 41 | 42 | # ------------ Comment for Avoiding Overriding the Simulation Region 43 | # override_swg(fdtd=fdtd) 44 | # override_fdtd(fdtd=fdtd) 45 | 46 | # --------------------------------Plot-T/R--------------------------------- 47 | 48 | T, R, f = getBraggResponse(fdtd=fdtd) 49 | 50 | # --------------------------------Plot-T/R--------------------------------- 51 | 52 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 53 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 54 | ax.plot((scpy.c/f)*1e6,T,label = 'Transmission') 55 | ax.plot((scpy.c/f)*1e6,abs(R),label = 'Reflection') 56 | ax.legend() 57 | ax.set_xlabel("wavelength (um)") 58 | ax.set_ylabel("Magnitude") 59 | plt.ylim([0,1]) 60 | plt.tight_layout() 61 | file_name_plot = os.path.join(FDTD_SWG_DIRECTORY_WRITE[1], "frequency_response.png") 62 | plt.savefig(file_name_plot) 63 | 64 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 65 | ax.plot((scpy.c/f)*1e6,10*np.log10(T),label = 'Transmission') 66 | ax.plot((scpy.c/f)*1e6,10*np.log10(abs(R)),label = 'Reflection') 67 | ax.legend() 68 | ax.set_xlabel("wavelength (um)") 69 | ax.set_ylabel("Magnitude (dB)") 70 | ax.set_ylim([-20,0]) 71 | plt.tight_layout() 72 | file_name_plot = os.path.join(FDTD_SWG_DIRECTORY_WRITE[1], "frequency_response_dB.png") 73 | plt.savefig(file_name_plot) 74 | 75 | plt.show() -------------------------------------------------------------------------------- /FDTD/swg_grating/user_inputs/lumerical_files/sub_wavelength_grating_layer_1.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/swg_grating/user_inputs/lumerical_files/sub_wavelength_grating_layer_1.fsp -------------------------------------------------------------------------------- /FDTD/swg_grating/user_inputs/lumerical_files/sub_wavelength_grating_layer_2.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/swg_grating/user_inputs/lumerical_files/sub_wavelength_grating_layer_2.fsp -------------------------------------------------------------------------------- /FDTD/vertical_taper/override_fdtd_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script overrides the FDTD simulation region from the vertical_taper.fsp 11 | file. 12 | 13 | 14 | """ 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user files 18 | # --------------------------------------------------------------------------- 19 | 20 | import lumapi 21 | from FDTD.vertical_taper.user_inputs.user_simulation_parameters import * 22 | from config import FDTD_VERTICAL_DIRECTORY_READ 23 | 24 | def override_fdtd(fdtd): 25 | 26 | fdtd.switchtolayout() 27 | 28 | configuration = ( 29 | 30 | 31 | ("source", (("mode selection", mode_source), 32 | ("wavelength start", wavelength_start), 33 | ("wavelength stop", wavelength_stop))), 34 | 35 | ("T_exp", (("mode selection", mode_monitor), 36 | )), 37 | 38 | ("mesh", (("dx", mesh_dx), 39 | ("dy", mesh_dy), 40 | ("dz", mesh_dz), 41 | ("override x mesh", enable_dx), 42 | ("override y mesh", enable_dy), 43 | ("override z mesh", enable_dz))), 44 | 45 | ("::model", (("taper_gap",taper_gap), 46 | ("taper_length",taper_length), 47 | ("FDTD_z_span", simulation_span_z), 48 | ("FDTD_y_span", simulation_span_y), 49 | ("port_extension", port_extension))), 50 | 51 | ("FDTD", (("simulation time", simulation_time), 52 | ("mesh accuracy",mesh_accuracy))), 53 | 54 | ) 55 | 56 | # Populate the waveguide simulation region 57 | 58 | for obj, parameters in configuration: 59 | for k, v in parameters: 60 | fdtd.setnamed(obj, k, v) 61 | 62 | fdtd.setglobalmonitor("frequency points",frequency_points) 63 | 64 | fdtd.save() 65 | 66 | 67 | # --------------------------------------------------------------------------- 68 | 69 | 70 | if(__name__=="__main__"): 71 | with lumapi.FDTD(FDTD_VERTICAL_DIRECTORY_READ) as fdtd: 72 | override_fdtd(fdtd=fdtd) 73 | 74 | 75 | -------------------------------------------------------------------------------- /FDTD/vertical_taper/override_vertical_taper_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script overrides the FDTD region for the vertical taper simulation. 11 | 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user files 17 | # --------------------------------------------------------------------------- 18 | 19 | import lumapi 20 | from FDTD.vertical_taper.user_inputs.user_simulation_parameters import * 21 | from config import FDTD_VERTICAL_DIRECTORY_READ 22 | 23 | 24 | 25 | def override_vertical_taper(fdtd): 26 | 27 | fdtd.switchtolayout() 28 | 29 | 30 | configuration = ( 31 | ("taper-bottom", (("width_wg_left", wg_bottom_width_left), 32 | ("width_wg_right", wg_bottom_width_right), 33 | ("taper_thickness", wg_bottom_thickness), 34 | ("rib_thickness", wg_bottom_rib_thickness))), 35 | 36 | 37 | ("taper-top", (("width_wg_left", wg_top_width_left), 38 | ("width_wg_right", wg_top_width_right), 39 | ("taper_thickness", wg_top_thickness), 40 | ("rib_thickness", wg_top_rib_thickness))), 41 | 42 | ("::model", (("taper_gap", taper_gap), 43 | ("taper_length", taper_length), 44 | ("port_extension", port_extension), 45 | ("FDTD_y_span", simulation_span_y), 46 | ("FDTD_z_span", simulation_span_z))), 47 | 48 | 49 | ) 50 | 51 | 52 | # Populate the waveguide simulation region 53 | 54 | for obj, parameters in configuration: 55 | for k, v in parameters: 56 | fdtd.setnamed(obj, k, v) 57 | 58 | fdtd.save() 59 | 60 | # --------------------------------------------------------------------------- 61 | 62 | 63 | if(__name__=="__main__"): 64 | 65 | with lumapi.FDTD(FDTD_VERTICAL_DIRECTORY_READ) as fdtd: 66 | override_vertical_taper(fdtd=fdtd) 67 | 68 | 69 | -------------------------------------------------------------------------------- /FDTD/vertical_taper/transmission/getFrequencyResponse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the transmission for the fundamental TE or TM mode 11 | of the vertical taper structure defined in the vertical_taper.fsp file 12 | from the T_exp monitor. The back reflection from the source is also printed 13 | 14 | """ 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | import scipy.constants as scpy 24 | from config import * 25 | 26 | from FDTD.vertical_taper.override_fdtd_region import override_fdtd 27 | from FDTD.vertical_taper.override_vertical_taper_region import * 28 | 29 | def getBraggResponse(fdtd): 30 | fdtd.run() 31 | T_total = np.squeeze(fdtd.getresult("T_exp","expansion for fundamental").get("T_total")) 32 | T_forward = np.squeeze(fdtd.getresult("T_exp","expansion for fundamental").get("T_forward")) 33 | R = np.squeeze(fdtd.transmission("R")) 34 | f = np.squeeze(fdtd.getdata("T","f")) 35 | 36 | return T_total, T_forward, R, f 37 | 38 | 39 | 40 | if(__name__=="__main__"): 41 | with lumapi.FDTD(FDTD_VERTICAL_DIRECTORY_READ) as fdtd: 42 | 43 | # ------------ Comment for Avoiding Overriding the Simulation Region 44 | # override_vertical_taper(fdtd=fdtd) 45 | # override_fdtd(fdtd=fdtd) 46 | 47 | # -----------------------------Plot-T_forward/T_total------------------------------ 48 | 49 | T_total, T_forward, R, f = getBraggResponse(fdtd=fdtd) 50 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 51 | 52 | # -----------------------------Plot-T_forward/T_total------------------------------ 53 | 54 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 55 | ax.plot((scpy.c/f)*1e6, T_total,'-o',label = 'Total') 56 | ax.plot((scpy.c/f)*1e6, T_forward,'-o',label = 'Fundamental') 57 | ax.legend() 58 | ax.set_xlabel("wavelength (um)") 59 | ax.set_ylabel("Magnitude") 60 | plt.ylim([0,1]) 61 | plt.tight_layout() 62 | file_name_plot = os.path.join(FDTD_VERTICAL_DIRECTORY_WRITE[1], "frequency_response.png") 63 | plt.savefig(file_name_plot) 64 | 65 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 66 | ax.plot((scpy.c/f)*1e6,10*np.log10(T_total),'-o',label = 'Total') 67 | ax.plot((scpy.c/f)*1e6,10*np.log10(abs(T_forward)),'-o',label = 'Fundamental') 68 | ax.legend() 69 | ax.set_xlabel("wavelength (um)") 70 | ax.set_ylabel("Magnitude (dB)") 71 | plt.tight_layout() 72 | file_name_plot = os.path.join(FDTD_VERTICAL_DIRECTORY_WRITE[1], "frequency_response_dB.png") 73 | plt.savefig(file_name_plot) 74 | 75 | plt.show() 76 | 77 | print('Back Reflection: ' + str(round(10*np.log10(abs(R.mean())),2)) + ' dB') -------------------------------------------------------------------------------- /FDTD/vertical_taper/user_inputs/lumerical_files/vertical_taper.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/vertical_taper/user_inputs/lumerical_files/vertical_taper.fsp -------------------------------------------------------------------------------- /FDTD/vertical_taper/user_inputs/user_simulation_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user is must enter the parameters required to setup the 11 | simulation file. The simulation parameters along with their dimensions are 12 | presented below. 13 | 14 | 15 | """ 16 | 17 | 18 | # Length units are in meters! 19 | 20 | 21 | # 1. Taper Parameters 22 | 23 | taper_gap = 0.5e-6 24 | taper_length = 100e-6 25 | 26 | 27 | 28 | 29 | # 1.1. Taper-bottom Parameters - Soyrce is attached on this taper 30 | wg_bottom_width_left = 1.20e-6 31 | wg_bottom_width_right = 0.25e-6 32 | wg_bottom_thickness = 0.2e-6 33 | 34 | wg_bottom_rib_thickness = 0.0e-6 35 | 36 | # 1.2. Taper-Top Parameters 37 | wg_top_width_left = 0.25e-6 38 | wg_top_width_right = 1.20e-6 39 | wg_top_thickness = 0.2e-6 40 | 41 | wg_top_rib_thickness = 0.0e-6 42 | 43 | 44 | # 2. FDTD Simulation Parameters 45 | 46 | # 2.1 FDTD Span Region 47 | simulation_span_y = 20e-6 48 | simulation_span_z = 20e-6 49 | simulation_time = 5e-12 50 | 51 | # 2.2.1. Mesh Settings 52 | mesh_accuracy = 1 53 | 54 | # 2.2.2. Override Mesh Settings 55 | mesh_dx = 50e-9 56 | mesh_dy = wg_top_width_left/2 57 | mesh_dz = taper_gap/5 58 | enable_dx = 0 59 | enable_dy = 1 60 | enable_dz = 1 61 | 62 | 63 | # 2.3 Source/Monitor Properties 64 | wavelength_start = 1.2e-6 65 | wavelength_stop = 1.4e-6 66 | mode_fundamental = "TE" # Select TE for fundamental TE or TM for fundamental TM 67 | frequency_points = 32 68 | 69 | # 2.4. Port extension 70 | port_extension = 5e-6 71 | 72 | 73 | # 3. Figures 74 | my_dpi = 96 75 | 76 | 77 | # -------------------------- End of Input Section ----------------------------- 78 | 79 | 80 | if(mode_fundamental == "TE"): 81 | mode_monitor = "fundamental TE mode" 82 | else: 83 | mode_monitor = "fundamental TM mode" 84 | 85 | 86 | 87 | if(mode_fundamental == "TE"): 88 | mode_source = "fundamental TE mode" 89 | else: 90 | mode_source = "fundamental TM mode" 91 | -------------------------------------------------------------------------------- /FDTD/waveguide-bend/README.md: -------------------------------------------------------------------------------- 1 | ## 3D Waveguide Bend Simulations (3D FDTD) 2 | 3 | ┌───────────────────────────────────────────────┐ 4 | │waveguide-bend │ 5 | └┬───────────────────┬─────────────────────────┬┘ 6 | ┌▽─────────────────┐┌▽───────────────────────┐┌▽───────────────────────────┐ 7 | │user_inputs ││sweep_transmission ││propagation_mode │ 8 | └┬────────────────┬┘└───────────────────────┬┘└───────────────────────────┬┘ 9 | ┌▽──────────────┐┌▽───────────────────────┐┌▽───────────────────────────┐┌▽──────────────┐ 10 | │lumerical_files││user_sweep_parameters.py││sweep_radius_transmission.py││mode_profile.py│ 11 | └┬──────────────┘└────────────────────────┘└────────────────────────────┘└───────────────┘ 12 | ┌▽─────────────────┐ 13 | │waveguide_bend.lms│ 14 | └──────────────────┘ 15 | 16 | 17 | 18 | ### Quick Simulation Setup 19 | 20 | 1. After downloading the repository, navigate through the `waveguide-bend/user_inputs/lumerical_files` directory. 21 | 2. Edit the lumerical file template`waveguide_bend.lms` and define the simulation materials for the cladding, core, and box layers along with their dimensions. 22 | 3. Edit the `user_sweep_parameters.py` to define the simulation sweep parameters. Follow the comment-sections written in the file. 23 | 4. Run the `sweep_transmission/swee_radius_transmission.py` Python file to get the results. 24 | 1. You can also run the `propagation_mode/mode_profile.py` to see the E-fields at the bending section 25 | 26 | Tip: Low-index contrast material platforms such as silica have larger bending radius than high-index contrast material platforms 27 | -------------------------------------------------------------------------------- /FDTD/waveguide-bend/tree_chart.txt: -------------------------------------------------------------------------------- 1 | waveguide-bend -> user_inputs 2 | waveguide-bend -> sweep_transmission 3 | waveguide-bend -> propagation_mode 4 | 5 | user_inputs -> lumerical_files 6 | user_inputs -> user_sweep_parameters.py 7 | 8 | lumerical_files -> waveguide_bend.lms 9 | 10 | propagation_mode -> mode_profile.py 11 | sweep_transmission -> sweep_radius_transmission.py 12 | -------------------------------------------------------------------------------- /FDTD/waveguide-bend/user_inputs/lumerical_files/waveguide_bend.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/waveguide-bend/user_inputs/lumerical_files/waveguide_bend.fsp -------------------------------------------------------------------------------- /FDTD/waveguide-bend/user_inputs/user_sweep_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user must enter the sweep parameters. 11 | 12 | The waveguide parameter to sweep bend_radius. 13 | 14 | 15 | 16 | """ 17 | 18 | 19 | 20 | 21 | 22 | bend_radius_start = 10.0e-6 # Choose the start waveguide width 'wg_width_start' you want to start sweeping 23 | bend_radius_stop = 150.0e-6 # Choose the stop waveguide width 'wg_width_stop' you want to finish sweeping 24 | bend_radius_step = 10e-6 # Choose the step of each sweep 'wg_step' 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /FDTD/waveguide-straight/README.md: -------------------------------------------------------------------------------- 1 | ## 3D Waveguide Simulations (FDTD) 2 | 3 | +---------------------+ 4 | +----------- waveguide-straight ----+-------------------+---------------------+ 5 | | +----------|----------+ | | | 6 | | | | | | 7 | | | | | | 8 | v v +-----v-----+ +---------v--------+ +--------v--------+ 9 | waveguide_render.py fdtd_region.py |user-inputs| |sweep-transmission| |propagation-mode | 10 | +-----|-----+ +---------|--------+ +--------|--------+ 11 | | | | 12 | +-----------+--------------| v | 13 | | | | sweep_width_transmission.py | 14 | | | | | 15 | | | v v 16 | | | user_simulation_parameters.py mode_profile.py 17 | | v 18 | | user_materials.py 19 | v 20 | user_sweep_parameters.py 21 | 22 | ### Quick Simulation Setup 23 | 24 | 1. After downloading the repository, navigate through the `waveguide-straight/user-inputs` directory. 25 | 2. Edit the `user_materials.py` to define the simulation materials for the cladding, core, box, and substrate layers. Follow the instructions written in the file. 26 | 3. Edit the `user_simulation_parameters.py` to define the simulation properties, region and structure dimensions. Follow the instructions written in the file. 27 | 4. Edit the `user_sweep_parameters.py` to define the parameters to sweep, like the waveguide width. 28 | 5. Navigate under the `waveguide-straight/propagation-mode` and run ` mode_profile.py`file to calculate the transmission for fundamental TE or TM modes and watch the propagated E-field profiles. 29 | -------------------------------------------------------------------------------- /FDTD/waveguide-straight/sweep_transmission/sweep_width_transmission.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The scripts sweeps the width of the waveguide and calculates the transmission 11 | of the fundamental mode. 12 | """ 13 | 14 | #---------------------------------------------------------------------------- 15 | # Imports from user files 16 | # --------------------------------------------------------------------------- 17 | 18 | 19 | import numpy as np 20 | import lumapi 21 | import matplotlib.pyplot as plt 22 | from matplotlib.patches import Rectangle 23 | import sys 24 | sys.path.append("..") 25 | 26 | from waveguide_render import waveguide_draw 27 | from user_inputs.user_simulation_parameters import * 28 | from user_inputs.user_materials import * 29 | from user_inputs.user_sweep_parameters import * 30 | from fdtd_region import add_fdtd_region 31 | 32 | 33 | fdtd = lumapi.FDTD() 34 | 35 | 36 | wav = ((wavelength_start + wavelength_stop)/2)*1e6 37 | fdtd.save(str(round(wav,2)) + "nm_straight_waveguide_width_sweep" + "_thick_" + str(round(wg_thickness*1e6,2))) 38 | 39 | 40 | waveguide_draw(fdtd) 41 | add_fdtd_region(fdtd) 42 | 43 | fdtd.redrawoff() 44 | 45 | wg_width_array = [] 46 | wg_width_array = np.arange(wg_width_start, wg_width_stop, wg_width_step) 47 | 48 | 49 | trans_f=[] 50 | trans_t=[] 51 | 52 | # Sweeps through the waveguide widths, and calculates the transmission 53 | 54 | for wd in range(0,len(wg_width_array)): 55 | fdtd.switchtolayout() 56 | fdtd.redrawoff() 57 | fdtd.setnamed("waveguide","y span",wg_width_array[wd]) 58 | 59 | fdtd.run() 60 | trans_f.append(fdtd.getresult("monitor_exp","expansion for input").get("T_forward")) 61 | trans_t.append(fdtd.getresult("monitor_exp","expansion for input").get("T_total")) 62 | 63 | 64 | 65 | trans_f_array = np.squeeze(trans_f) 66 | trans_t_array = np.squeeze(trans_t) 67 | 68 | plt.figure(1, figsize=(512/my_dpi, 256/my_dpi), dpi=my_dpi) 69 | plt.plot(wg_width_array*1e6,trans_f_array,'-o',wg_width_array*1e6,trans_t_array,'-o') 70 | 71 | plt.xlabel("width (um)") 72 | plt.ylabel("T") 73 | plt.title("thickness "+ str(wg_thickness*1e6) + " um") 74 | plt.show() 75 | 76 | fdtd.redrawon() 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /FDTD/waveguide-straight/user_inputs/user_sweep_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user is rmust enter the parameters required to sweep. 11 | 12 | The waveguide parameters to sweep are 'wg_thickness' and 'wg_width' . 13 | 14 | 15 | 16 | ^ 17 | | 18 | | 19 | | - 20 | wg_width 21 | <---------------> 22 | +-------|--------+ ^ 23 | | | | | 24 | | waveguide | | wg_thickness 25 | | | | | 26 | ------------|----------v---------------------> 27 | (0,0)| 28 | | 29 | | 30 | | 31 | 32 | """ 33 | 34 | # Choose the start waveguide width 'wg_width_start' you want to start sweeping 35 | # Choose the stop waveguide width 'wg_width_stop' you want to finish sweeping 36 | # Choose the step of each sweep 'wg_step' 37 | wg_width_start = 0.5e-6 38 | wg_width_stop = 3.0e-6 39 | wg_width_step = 0.1e-6 40 | -------------------------------------------------------------------------------- /FDTD/waveguide_crossing/fields/getFields.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the E-fields profile for the device structure 11 | defined in the waveguide_crossing_multi_wg_taper.fsp file 12 | 13 | """ 14 | 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | from matplotlib.colors import LogNorm 24 | from config import * 25 | 26 | # from FDTD.waveguide_cross.override_cross_region import * 27 | 28 | 29 | def getFields(fdtd): 30 | 31 | fdtd.run() 32 | 33 | field_xy = fdtd.getelectric("xy_topview") 34 | 35 | x = fdtd.getdata("xy_topview","x").squeeze() 36 | y = fdtd.getdata("xy_topview","y").squeeze() 37 | 38 | return x,y,field_xy 39 | 40 | 41 | 42 | 43 | 44 | 45 | if(__name__=="__main__"): 46 | with lumapi.FDTD(FDTD_CROSS_DIRECTORY_READ) as fdtd: 47 | 48 | # ------------ Comment for Avoiding Overriding the Simulation Region 49 | # override_cross(fdtd=fdtd) 50 | 51 | x,y,E_xy = getFields(fdtd=fdtd) 52 | c_wavelength = np.rint(len(E_xy[0,0,0,:])/2) 53 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 54 | 55 | # --------------------------------Top-View--------------------------------- 56 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 57 | cmap = ax.pcolormesh(x*1e6,y*1e6,(np.transpose(E_xy[:,:,0,int(c_wavelength)])), 58 | shading = 'gouraud',cmap = 'jet', norm = LogNorm()) 59 | fig.colorbar(cmap) 60 | plt.xlabel("x (um)") 61 | plt.ylabel("y (um)") 62 | plt.title('Top-view(xy)') 63 | plt.tight_layout() 64 | file_name_plot = os.path.join(FDTD_CROSS_DIRECTORY_WRITE[2], "E_profile_xy.png") 65 | plt.savefig(file_name_plot) 66 | 67 | 68 | 69 | plt.show() 70 | 71 | -------------------------------------------------------------------------------- /FDTD/waveguide_crossing/index_profile/index_profile_2D.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the refractive index profile for the device structure 11 | defined in the waveguide_crossing_multi_wg_taper.fsp file 12 | 13 | """ 14 | 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | from config import * 24 | 25 | # from FDTD.waveguide_cross.override_cross_region import * 26 | 27 | # -------------------_----- No inputs are required --------------------------- 28 | 29 | 30 | def getIndex(fdtd): 31 | 32 | # Get the data from the Index monitors 33 | index_xy = fdtd.getresult("index_xy","index") 34 | index_xz = fdtd.getresult("index_yz","index") 35 | return index_xy, index_xz 36 | 37 | 38 | if(__name__=="__main__"): 39 | with lumapi.FDTD(FDTD_CROSS_DIRECTORY_READ) as fdtd: 40 | 41 | # ------------Comment for Avoiding Overriding the Simulation Region 42 | # override_cross(fdtd=fdtd) 43 | 44 | index_xy, index_yz = getIndex(fdtd=fdtd) 45 | 46 | 47 | 48 | 49 | # --------------------------------Top-View--------------------------------- 50 | x = index_xy["x"].squeeze() 51 | y = index_xy["y"].squeeze() 52 | index_x = np.real(index_xy["index_x"].squeeze()) 53 | 54 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 55 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 56 | ax.axis('equal') 57 | cmap = ax.pcolormesh(x*1e6, y*1e6,np.transpose(index_x)) 58 | fig.colorbar(cmap) 59 | ax.set_xlabel("x (um)") 60 | ax.set_ylabel("y (um)") 61 | ax.set_title('Top-view(xy)') 62 | fig.tight_layout() 63 | file_name_plot = os.path.join(FDTD_CROSS_DIRECTORY_WRITE[0], "index_profile_xy.png") 64 | plt.savefig(file_name_plot) 65 | plt.show() 66 | 67 | 68 | 69 | # --------------------------------Cross-View--------------------------------- 70 | y = index_yz["y"].squeeze() 71 | zz = index_yz["z"].squeeze() 72 | index_z = np.real(index_yz["index_z"].squeeze()) 73 | 74 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 75 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 76 | cmap = ax.pcolormesh(y*1e6, zz*1e6,np.transpose(index_z)) 77 | fig.colorbar(cmap) 78 | plt.xlabel("y (um)") 79 | plt.ylabel("z (um)") 80 | plt.title('Cross-view(yz)') 81 | plt.tight_layout() 82 | file_name_plot = os.path.join(FDTD_CROSS_DIRECTORY_WRITE[0], "index_profile_xz.png") 83 | plt.savefig(file_name_plot) 84 | plt.show() 85 | -------------------------------------------------------------------------------- /FDTD/waveguide_crossing/transmission/getFrequencyResponse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the transmission and crosstalk for the waveguide crossing 11 | structure defined in the waveguide_crossing_multi_wg_taper.fsp file 12 | from the 'through' and crosstalk monitor. 13 | 14 | """ 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | import scipy.constants as scpy 24 | from config import * 25 | 26 | # from FDTD.waveguide_cross.override_cross_region import * 27 | 28 | def getCrossResponse(fdtd): 29 | fdtd.run() 30 | T = np.squeeze(fdtd.getresult("through_mode","expansion for ").get("T_forward")) 31 | C = np.squeeze(fdtd.getresult("crosstalk_mode","expansion for ").get("T_forward")) 32 | f = np.squeeze(fdtd.getdata("through","f")) 33 | 34 | return T, C, f 35 | 36 | 37 | 38 | if(__name__=="__main__"): 39 | with lumapi.FDTD(FDTD_CROSS_DIRECTORY_READ) as fdtd: 40 | 41 | # ------------ Comment for Avoiding Overriding the Simulation Region 42 | # override_cross(fdtd=fdtd) 43 | 44 | # --------------------------------Plot-T/R--------------------------------- 45 | 46 | T, C, f = getCrossResponse(fdtd=fdtd) 47 | 48 | # --------------------------------Plot-T/R--------------------------------- 49 | 50 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 51 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 52 | ax.semilogy((scpy.c/f)*1e6,T,label = 'Transmission') 53 | ax.semilogy((scpy.c/f)*1e6,C,label = 'Crosstalk') 54 | ax.grid(which='both') 55 | ax.legend() 56 | ax.set_xlabel("wavelength (um)") 57 | ax.set_ylabel("Magnitude") 58 | plt.tight_layout() 59 | file_name_plot = os.path.join(FDTD_CROSS_DIRECTORY_WRITE[1], "frequency_response.png") 60 | plt.savefig(file_name_plot) 61 | 62 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 63 | ax.plot((scpy.c/f)*1e6,10*np.log10(T),label = 'Transmission') 64 | ax.plot((scpy.c/f)*1e6,10*np.log10(C),label = 'Crosstalk') 65 | ax.grid(which='major') 66 | ax.legend() 67 | ax.set_xlabel("wavelength (um)") 68 | ax.set_ylabel("Magnitude (dB)") 69 | plt.tight_layout() 70 | file_name_plot = os.path.join(FDTD_CROSS_DIRECTORY_WRITE[1], "frequency_response_dB.png") 71 | plt.savefig(file_name_plot) 72 | 73 | plt.show() -------------------------------------------------------------------------------- /FDTD/waveguide_crossing/user_inputs/lumerical_files/waveguide_crossing_multi_wg_taper.fsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/waveguide_crossing/user_inputs/lumerical_files/waveguide_crossing_multi_wg_taper.fsp -------------------------------------------------------------------------------- /FDTD/waveguide_mode_taper/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/FDTD/waveguide_mode_taper/README.md -------------------------------------------------------------------------------- /FDTD/waveguide_mode_taper/user_inputs/user_sweep_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user must enter the sweep parameters. 11 | 12 | The waveguide parameters to sweep are 'wg_thickness' and 'wg_width' . 13 | 14 | 15 | 16 | ^ 17 | | 18 | | 19 | | - 20 | wg_width 21 | <---------------> 22 | +-------|--------+ ^ 23 | | | | | 24 | | waveguide | | wg_thickness 25 | | | | | 26 | ------------|----------v---------------------> 27 | (0,0)| 28 | | 29 | | 30 | | 31 | 32 | """ 33 | 34 | 35 | 36 | 37 | 38 | wg_width_start = 2.0e-6 # Choose the start waveguide width 'wg_width_start' you want to start sweeping 39 | wg_width_stop = 5.25e-6 # Choose the stop waveguide width 'wg_width_stop' you want to finish sweeping 40 | wg_width_step = 0.25e-6 # Choose the step of each sweep 'wg_step' 41 | 42 | 43 | wg_taper_start = 10.0e-6 # Choose the start waveguide length 'wg_taper_start' you want to start sweeping 44 | wg_taper_stop = 110.0e-6 # Choose the stop waveguide length 'wg_taper_stop' you want to finish sweeping 45 | wg_taper_step = 10.0e-6 # Choose the step of each sweep 'wg_taper_step' 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Georgios Charalampous 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MODE/README.md: -------------------------------------------------------------------------------- 1 | # Mode Solution Library for Photonic Simulations 2 | 3 | This repository contains a collection of Python-based simulations and calculations for integrated photonics, focusing on mode analysis, coupling efficiencies, and waveguide characteristics. 4 | 5 | ## Features 6 | 7 | ### [awg-star-coupler](awg_star_coupler) 8 | - Simulates the aperture profile of a 2D star coupler. 9 | 10 | ### [butt-coupling](butt_coupling) 11 | - Visualizes mode profiles for two coupled waveguides. 12 | - Computes overlap integrals to quantify coupling efficiency. 13 | - Analyzes misalignment effects on coupling. 14 | - Studies coupling efficiency as a function of the second waveguide width for fundamental TE/TM modes. 15 | 16 | ### [directional-coupler](directional_coupler) 17 | - Visualizes symmetric and antisymmetric mode profiles. 18 | - Calculates the coupling length, \(L_{\pi}\), as a function of gap and distance between waveguides. 19 | 20 | ### [edge-coupler](edge_coupler) 21 | - Evaluates overlap between Gaussian beam and waveguide mode profiles. 22 | - Examines coupling efficiency as a function of Gaussian beam Mode-Field Diameter (MFD). 23 | - Analyzes the impact of waveguide thickness on overlap efficiency. 24 | 25 | ### [swg-grating](swg_grating) 26 | - Calculates the transmission and reflection properties of a sub-wavelength grating. 27 | 28 | ### [vertical-taper](vertical_taper) 29 | - Computes effective index variation as a function of taper length for vertically tapered structures. 30 | 31 | ### [waveguide](waveguide) 32 | - Visualizes mode profiles for various waveguide configurations. 33 | - Calculates effective index variations with respect to waveguide width and height. 34 | - Models absorption loss due to metal layer deposition on waveguides. 35 | - Estimates the Q-factor and Free Spectral Range (FSR) for racetrack resonators. 36 | - Calculates straight-to-bend waveguide loss. 37 | - Determines confinement factors in Phase Change Materials (PCM). -------------------------------------------------------------------------------- /MODE/awg_star_coupler/mode_field_profile/apperture_profile_2D.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script calculates the apperture profile of the star coupler specified in 11 | 'user_inputs/awg_input_taper.lms' and 'user_simulation_parameters.py'. 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user files 17 | # --------------------------------------------------------------------------- 18 | 19 | import numpy as np 20 | import lumapi 21 | import matplotlib.pyplot as plt 22 | from config import * 23 | 24 | # Import user-defined parameters from another file 25 | from MODE.directional_coupler.user_inputs.user_simulation_parameters import * 26 | 27 | 28 | 29 | 30 | 31 | with lumapi.MODE(MODE_AWG_DIRECTORY_READ) as mode: 32 | 33 | mode.switchtolayout() 34 | mode.run() 35 | mode.save() 36 | 37 | 38 | # Get the far field 39 | Ep=mode.farfield2d("monitor_field") 40 | theta=mode.farfieldangle("monitor_field") 41 | 42 | 43 | # Normalize in dB scale 44 | Ep_dB = 10*np.log10(abs(Ep)) 45 | Ep_dB_unity = 10*np.log10(abs(Ep))-np.max(Ep_dB) 46 | 47 | 48 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 49 | 50 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 51 | ax.plot(theta,Ep_dB_unity,label = 'Ep') 52 | ax.set_xlabel("\u03B8 (deg)") 53 | ax.set_ylabel("Transmission (dB)") 54 | ax.grid() 55 | 56 | ax.axhline(y = -30,linestyle = '--', color = 'g') 57 | 58 | ax.axvline(x = -30,linestyle = '--', color = 'r') 59 | ax.axvline(x = 30,linestyle = '--', color = 'r') 60 | 61 | file_name_plot_writing = os.path.join(MODE_AWG_DIRECTORY_WRITE[1], 62 | "far_field_profile.png") 63 | fig.tight_layout() 64 | 65 | fig.savefig(file_name_plot_writing, dpi=my_dpi, format="png") -------------------------------------------------------------------------------- /MODE/awg_star_coupler/mode_field_profile/get_index_mesh_2D.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script calculates the apperture profile of the star coupler specified in 11 | 'user_inputs/awg_input_taper.lms' and 'user_simulation_parameters.py'. 12 | 13 | """ 14 | 15 | #---------------------------------------------------------------------------- 16 | # Imports from user files 17 | # --------------------------------------------------------------------------- 18 | 19 | import numpy as np 20 | import lumapi 21 | import matplotlib.pyplot as plt 22 | import os 23 | from config import * 24 | 25 | # Import user-defined parameters from another file 26 | from MODE.directional_coupler.user_inputs.user_simulation_parameters import * 27 | 28 | 29 | # ------------------------- No inputs are required --------------------------- 30 | if(__name__=="__main__"): 31 | 32 | with lumapi.MODE(MODE_AWG_DIRECTORY_READ) as mode: 33 | 34 | mode.switchtolayout() 35 | mode.run() 36 | 37 | 38 | # Get the index profile 39 | index = np.squeeze(mode.getdata("effective_index","index_x")) 40 | x = np.squeeze(mode.getdata("effective_index","x")) 41 | y = np.squeeze(mode.getdata("effective_index","y")) 42 | 43 | 44 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 45 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 46 | 47 | c = ax.pcolormesh(x*1e6,y*1e6,np.real(np.transpose(index)),shading = 'gouraud',cmap = 'jet') 48 | fig.colorbar(c, ax = ax) 49 | 50 | ax.set_xlabel("x (\u00B5m)") 51 | ax.set_ylabel("y (\u00B5m)") 52 | ax.set_title("Star Coupler Index Mesh") 53 | 54 | file_name_plot = os.path.join(MODE_AWG_DIRECTORY_WRITE[0], "index_profile_xz.png") 55 | plt.savefig(file_name_plot) 56 | 57 | -------------------------------------------------------------------------------- /MODE/awg_star_coupler/user_inputs/lumerical_files/awg_input_taper.lms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/MODE/awg_star_coupler/user_inputs/lumerical_files/awg_input_taper.lms -------------------------------------------------------------------------------- /MODE/butt_coupling/overlap_mode/overlap_mode_integral_2D.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The scripts calculates the overlap integral for the mode order you defined in 11 | the user_simulation_parameters.py. 12 | 13 | # 4.1 Waveguide_1.lms 14 | m_waveguide1=2 15 | 16 | # 4.2 Waveguide_2.lms 17 | m_waveguide2=1 18 | 19 | 20 | """ 21 | 22 | #---------------------------------------------------------------------------- 23 | # Imports from user files 24 | # --------------------------------------------------------------------------- 25 | # Import necessary modules 26 | import lumapi 27 | from MODE.butt_coupling.user_inputs.user_simulation_parameters import * 28 | import os 29 | 30 | 31 | # Define path to read files from 32 | path_to_read = "MODE\\Results\\butt_coupling\\lumerical_files\\d_cards" 33 | 34 | # Define the list of waveguide files to be loaded into Lumerical MODE 35 | file_waveguide = ['waveguide_1.ldf', 'waveguide_2.ldf'] 36 | 37 | # Get the current path and directory of this Python script 38 | current_path = os.path.abspath(__file__) 39 | current_dir = os.path.dirname(current_path) 40 | 41 | # Move up the directory hierarchy until we find the .gitignore file, 42 | # which is assumed to be in the root directory of the project 43 | while not os.path.isfile(os.path.join(current_dir, ".gitignore")): 44 | current_dir = os.path.dirname(current_dir) 45 | 46 | # Define the directory to read the files from, based on the project root directory 47 | dir_to_read = os.path.join(current_dir, path_to_read) 48 | 49 | # Initialize a list to store the names of the waveguide modes in Lumerical MODE 50 | file_name_mode = [str]*len(file_waveguide) 51 | 52 | # Initialize LumAPI and turn off redraw for faster simulations 53 | with lumapi.MODE() as mode: 54 | 55 | # Switch to layout mode 56 | mode.switchtolayout() 57 | 58 | # Load each waveguide file into Lumerical MODE 59 | for i in range(0,len(file_waveguide)): 60 | file_name_mode[i] = os.path.join(dir_to_read, file_waveguide[i]) 61 | mode.loaddata(file_name_mode[i]) 62 | 63 | # Compute the overlap integral between the two waveguides 64 | print("Overlap Integral [Mode,Power]\n") 65 | print(mode.overlap("waveguide_1_mode" + str(m_waveguide1), 66 | "waveguide_2_mode" + str(m_waveguide2))) 67 | -------------------------------------------------------------------------------- /MODE/butt_coupling/user_inputs/lumerical_files/waveguide_1.lms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/MODE/butt_coupling/user_inputs/lumerical_files/waveguide_1.lms -------------------------------------------------------------------------------- /MODE/butt_coupling/user_inputs/lumerical_files/waveguide_2.lms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/MODE/butt_coupling/user_inputs/lumerical_files/waveguide_2.lms -------------------------------------------------------------------------------- /MODE/butt_coupling/user_inputs/user_sweep_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user is must enter the parameters required to sweep. 11 | 12 | The waveguide parameters to sweep are 'wg_2_width', which is the width 13 | of the waveguide_2.lms file only. 14 | 15 | The width from waveguide_1.lms is held constant. It can be changed from the 16 | user_simulation_paramaters.py 17 | 18 | 19 | ^ 20 | | 21 | | 22 | | - 23 | wg_width 24 | <---------------> 25 | +-------|--------+ ^ 26 | | | | | 27 | | waveguide | | wg_thickness 28 | | | | | 29 | ------------|----------v---------------------> 30 | (0,0)| 31 | | 32 | | 33 | | 34 | 35 | """ 36 | 37 | 38 | 39 | wg_2_width_start = 0.250e-6 # Choose the start width for waveguide-2 'wg_2_width_start' 40 | wg_2_width_stop = 10.0e-6 # Choose the stop width for waveguide-2 'wg_2_width_stop' 41 | wg_2_width_step = 0.50e-6 # Choose the step width for waveguide-2 'wg_2_width_step' 42 | 43 | 44 | 45 | # Misalign the two beams in y (horizontal) or z (vertical) directions 46 | misalign_y_start = -5e-6 47 | misalign_y_stop = 5e-6 48 | misalign_y_step = 0.5e-6 49 | 50 | 51 | misalign_z_start = -5e-6 52 | misalign_z_stop = 5e-6 53 | misalign_z_step = 0.25e-6 54 | 55 | -------------------------------------------------------------------------------- /MODE/directional_coupler/README.md: -------------------------------------------------------------------------------- 1 | ## 2D Directional Coupler (MODE Solutions) 2 | 3 | ``` 4 | directional_coupler/ 5 | ├── coupling_sweep 6 | │   ├── coupling_gap.py 7 | │   └── coupling_length.py 8 | ├── dissimilar_waveguides 9 | │   └── coupling_length.py 10 | ├── even_odd_mode_profile.py 11 | ├── mode_profile 12 | │   └── mode_profile_2D.py 13 | ├── README.md 14 | └── user_inputs 15 | ├── lumerical_files 16 | │   └── waveguide_coupler.lms 17 | ├── user_simulation_parameters.py 18 | └── user_sweep_parameters.py 19 | ``` 20 | 21 | ### Quick Simulation Setup 22 | 23 | 1. After downloading the repository, navigate through the `directional-coupler/user_inputs/lumerical_files` directory. 24 | 2. Edit the lumerical file `waveguide_coupler.lms` to define the simulation parameters such as materials, cladding, core, and box layers along with their dimensions. 25 | 3. Edit the `user_sweep_parameters.py` and `user_simulation_parameters.py`to define the sweep and simulation parameters, respectively. Follow the comment-sections written in the file. 26 | 4. Run the `mode_profile/mode_profile_2D.py`, `coupling_sweep/coupling_length.py` and `coupling_sweep/coupling_gap.py` Python files to get the results. 27 | 28 | **Tip**: The analysis found in `coupling_sweep` is valid only when the two waveguides are phase-matched. This means both waveguides should have the same dimensions and materials. If the two waveguides have different widths, run `dissimilar_waveguides/coupling_length.py`. 29 | -------------------------------------------------------------------------------- /MODE/directional_coupler/user_inputs/lumerical_files/waveguide_coupler.lms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/MODE/directional_coupler/user_inputs/lumerical_files/waveguide_coupler.lms -------------------------------------------------------------------------------- /MODE/directional_coupler/user_inputs/user_simulation_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | 11 | 12 | wg1_width gap wg2_width 13 | <---------------><--><---------------> 14 | +-------^--------+ ^ +-------^--------+ ^ 15 | | | | | | | | | 16 | | waveguide-1 | | | waveguide-2 | | wg_thickness 17 | | | | | | | | | 18 | ------------v----------v---------V----------v---> 19 | (0,0)| 20 | 21 | 22 | 23 | In addition, there is a mesh layer which overlaps both waveguide-1 and waveguide-2. 24 | You can disable it from the .lms file in order to speed up the simulation results 25 | 26 | 27 | """ 28 | 29 | # 1. Simulation Parameters 30 | num_modes = 4 # Typically (2x modes per polarization - symm/anti-symm) 31 | 32 | # 2. Figure pixels density 33 | my_dpi = 96 -------------------------------------------------------------------------------- /MODE/directional_coupler/user_inputs/user_sweep_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | 11 | 12 | wg1_width gap wg2_width 13 | <---------------><--><---------------> 14 | +-------^--------+ ^ +-------^--------+ ^ 15 | | | | | | | | | 16 | | waveguide-1 | | | waveguide-2 | | wg_thickness 17 | | | | | | | | | 18 | ------------v----------v---------V----------v---> 19 | (0,0)| 20 | 21 | 22 | 23 | In addition, there is a mesh layer which overlaps both waveguide-1 and waveguide-2. 24 | You can disable it from the .lms file in order to speed up the simulation results 25 | 26 | 27 | """ 28 | 29 | # 1. Define the coupling length array 30 | coupling_length_start = 1e-6 31 | coupling_length_stop = 80e-6 32 | coupling_length_step = 0.5e-6 33 | 34 | # 2. Define the coupling gap array 35 | coupling_gap_start = 0.1e-6 36 | coupling_gap_stop = 0.5e-6 37 | coupling_gap_step = 0.05e-6 -------------------------------------------------------------------------------- /MODE/edge_coupler/README.md: -------------------------------------------------------------------------------- 1 | ## 2D Edge-Coupler Simulations (MODE Solutions) 2 | 3 | edge_coupler 4 | ├── fde_region.py 5 | ├── gaussian_beam_render.py 6 | ├── overlap_profile_sweep 7 | │   └── overlap_width_sweep_2D.py 8 | ├── README.md 9 | ├── user_inputs 10 | │   ├── gaussian_beam_parameters.py 11 | │   ├── user_materials.py 12 | │   ├── user_simulation_parameters.py 13 | │   └── user_sweep_parameters.py 14 | └── waveguide_render.py 15 | 16 | ### Quick Simulation Setup 17 | 18 | 1. After downloading the repository, navigate through the `edge_coupler/user_inputs/` directory. 19 | 2. Edit the parameter file `gausian_beam_parameters.py` to define the Gaussian beam parameter properties (i.e. waist-radius, index, sample span, etc). 20 | 3. Edit the `user_inputs/user_materials.py` and `user_inputs/user_simulation_parameters.py` to define the simulation materials for the cladding, core, box, and substrate layers. Follow the instructions written in the file. 21 | 4. Then define the in `user_inputs/user_sweep_parameters.py` the sweep parameters. 22 | 5. Run the `overlap_profile_sweep/overlap_profile_sweep_2D.py` Python file and get the overlap integral results. 23 | 24 | Tip: The script works only with the two fundamental polarizations namely TE and TM. If the Gaussian beam angle is set to 0o the script will calculate the overlap integral for TE mode. Setting the angle to 90o, the script will calculate the overlap integral for TM. 25 | -------------------------------------------------------------------------------- /MODE/edge_coupler/gaussian_beam_render.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Thu Apr 13 19:26:57 2023 4 | 5 | @author: Georgios 6 | """ 7 | 8 | 9 | #---------------------------------------------------------------------------- 10 | # Imports from user files 11 | # --------------------------------------------------------------------------- 12 | 13 | from MODE.edge_coupler.user_inputs.gaussian_beam_parameters import * 14 | 15 | 16 | def add_gaussian_beam(mode): 17 | 18 | 19 | 20 | configuration = ( 21 | 22 | 23 | ("FDE", (("use fully vectorial thin lens beam profile", False), 24 | ("define gaussian beam by","waist size and position"), 25 | ("beam direction","2D Z normal"), 26 | ("waist radius", waist_radius), 27 | ("distance from waist", distance_from_waist), 28 | ("refractive index", refractive_index), 29 | ("theta", theta), 30 | ("phi", phi), 31 | ("polarization angle", polarization_angle), 32 | ("sample span", sample_span), 33 | ("sample resolution",sample_resolution))), 34 | ) 35 | 36 | # Populate the waveguide simulation region 37 | 38 | for obj, parameters in configuration: 39 | for k, v in parameters: 40 | mode.setnamed(obj, k, v) 41 | 42 | mode.createbeam() 43 | -------------------------------------------------------------------------------- /MODE/edge_coupler/user_inputs/gaussian_beam_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user rmust enter the parameters to define the Gaussian 11 | properties of the beam 12 | 13 | 14 | *** 15 | * * 16 | * * * ^ 17 | * * * * - beam radius 18 | * * * v 19 | * * 20 | *** 21 | 22 | 23 | You can also use the thin lense approach by adding your own variables and filling 24 | the appropriate values in the gaussian_beam_render.py 25 | 26 | """ 27 | 28 | 29 | waist_radius = 1.25e-6 30 | distance_from_waist = 0.0e-6 31 | refractive_index = 1.0 32 | theta = 0.0 33 | phi = 0.0 34 | polarization_angle = 0 # 0 for TE Mode, 90 for TM Mode 35 | sample_span = 10e-6 36 | sample_resolution = 200 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /MODE/edge_coupler/user_inputs/user_materials.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | Input the appropriate material for each structure as appears below 11 | 12 | 13 | +--------------------------------+ 14 | | Claddding | 15 | | | 16 | | +-----------+ | 17 | | | | | 18 | | | waveguide | | 19 | | | | | 20 | +--------------------------------+ 21 | | Box | 22 | +--------------------------------+ 23 | | | 24 | | Substrate | 25 | | | 26 | +--------------------------------+ 27 | 28 | 29 | Select between material model or material index. By selecting the variable 30 | 'is_clad_index = True' the material model will be ingonred and instead the 31 | cladding_index = 1 cladding index 1 will be set. 32 | 33 | 34 | Please make sure that you type the material model exactly as it is in the material 35 | database. 36 | 37 | """ 38 | 39 | # Cladding 40 | is_clad_index = False # If true ignore clad_material 41 | clad_material = "SiO2 (Glass) - Palik" 42 | clad_index = 1 43 | 44 | 45 | # Waveguide Core 46 | is_wg_index = False # If true ignore wg_material 47 | wg_material = "Si3N4 (Silicon Nitride) - Phillip" 48 | wg_index = 3.9846 49 | 50 | 51 | # Box 52 | is_box_index = False # If true ignore box_material 53 | box_material = "SiO2 (Glass) - Palik" 54 | box_index = 3.4304 55 | 56 | 57 | 58 | # Substrate 59 | is_sub_index = False # If true ignore sub_material 60 | sub_material = "Si (Silicon) - Palik" 61 | sub_index = 3.4304 62 | 63 | 64 | # -------------------------- End of Input Section ----------------------------- 65 | 66 | 67 | if(is_wg_index): 68 | wg_material = "" 69 | else: 70 | wg_material = wg_material 71 | 72 | if(is_clad_index): 73 | clad_material = "" 74 | else: 75 | clad_material = clad_material 76 | 77 | if(is_box_index): 78 | box_material = "" 79 | else: 80 | box_material = box_material 81 | 82 | if(is_sub_index): 83 | sub_material = "" 84 | else: 85 | sub_material = sub_material 86 | -------------------------------------------------------------------------------- /MODE/edge_coupler/user_inputs/user_sweep_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user is rmust enter the parameters required to sweep. 11 | 12 | The waveguide parameters to sweep are 'wg_thickness' and 'wg_width' . 13 | 14 | 15 | 16 | ^ 17 | | 18 | | 19 | | - 20 | wg_width 21 | <---------------> 22 | +-------|--------+ ^ 23 | | | | | 24 | | waveguide | | wg_thickness 25 | | | | | 26 | ------------|----------v---------------------> 27 | (0,0)| 28 | | 29 | | 30 | | 31 | 32 | """ 33 | 34 | 35 | 36 | 37 | wg_width_start = 0.050e-6 # Choose the start waveguide width 'wg_width_start' 38 | #you want to start sweeping 39 | wg_width_stop = 3.0e-6 # Choose the stop waveguide width 'wg_width_stop' you 40 | #want to finish sweeping 41 | wg_width_step = 0.10e-6 # Choose the step of each sweep 'wg_width_step' 42 | 43 | 44 | 45 | 46 | wg_height_start = 0.05e-6 # Choose the start waveguide height 'wg_height_start' 47 | #you want to start sweeping 48 | wg_height_stop = 0.50e-6 # Choose the stop waveguide height 'wg_height_stop' you 49 | #want to finish sweeping 50 | wg_height_step = 0.025e-6 # Choose the step of each sweep 'wg_height_step' 51 | 52 | 53 | 54 | waist_start = 1.0e-6 # Choose the start waist radius 'waist_start' 55 | #you want to start sweeping 56 | waist_stop = 6.0e-6 # Choose the stop waist radius 'waist_stop' you 57 | #want to finish sweeping 58 | waist_step = 0.5e-6 # Choose the step of waist step 'waist_step' 59 | -------------------------------------------------------------------------------- /MODE/swg_grating/fields/getFields.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the E-fields profile for the device structure 11 | defined in the sub_wavelength_grating.fsp file 12 | 13 | """ 14 | 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | import scipy.constants as scpy 24 | from config import * 25 | 26 | from MODE.swg_grating.override_varfdtd_region import override_varfdtd 27 | from MODE.swg_grating.override_swg_region import * 28 | 29 | 30 | def getFields(mode): 31 | 32 | mode.run() 33 | 34 | field_xy = mode.getelectric("field_xy") 35 | field_xz = mode.getelectric("field_xz") 36 | 37 | x = mode.getdata("field_xy","x").squeeze() 38 | y = mode.getdata("field_xy","y").squeeze() 39 | z = mode.getdata("field_xz","z") 40 | 41 | return x,y,z,field_xy, field_xz 42 | 43 | 44 | 45 | 46 | 47 | 48 | if(__name__=="__main__"): 49 | with lumapi.MODE(MODE_SWG_DIRECTORY_READ) as mode: 50 | 51 | # ------------ Comment for Avoiding Overriding the Simulation Region 52 | # override_swg(mode=mode) 53 | # override_varfdtd(mode=mode) 54 | 55 | x,y,z,E_xy,E_xz = getFields(mode=mode) 56 | c_wavelength = np.rint(len(E_xy[0,0,0,:])/2) 57 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 58 | 59 | # --------------------------------Side-View--------------------------------- 60 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 61 | cmap = ax.pcolormesh(x*1e6,y*1e6,np.transpose(E_xy[:,:,0,int(c_wavelength)]), 62 | shading = 'gouraud',cmap = 'jet') 63 | fig.colorbar(cmap) 64 | plt.xlabel("x (um)") 65 | plt.ylabel("y (um)") 66 | plt.title('Side-view(xy)') 67 | plt.tight_layout() 68 | file_name_plot = os.path.join(MODE_SWG_DIRECTORY_WRITE[2], "E_profile_xy.png") 69 | plt.savefig(file_name_plot) 70 | 71 | # --------------------------------Top-View--------------------------------- 72 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 73 | cmap = ax.plot(x*1e6,np.transpose(E_xz[:,0,0,int(c_wavelength)])) 74 | 75 | plt.xlabel("x (um)") 76 | plt.ylabel("Normalized E-field") 77 | plt.title('Top-view (2D)') 78 | plt.tight_layout() 79 | file_name_plot = os.path.join(MODE_SWG_DIRECTORY_WRITE[2], "E_profile_xz.png") 80 | plt.savefig(file_name_plot) 81 | 82 | plt.show() 83 | 84 | -------------------------------------------------------------------------------- /MODE/swg_grating/index_profile/index_profile_2D.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the refractive index profile for the device structure 11 | defined in the sub_wavelength_grating.fsp file 12 | 13 | """ 14 | 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | from config import * 24 | 25 | from MODE.swg_grating.override_varfdtd_region import * 26 | from MODE.swg_grating.override_swg_region import * 27 | 28 | # -------------------_----- No inputs are required --------------------------- 29 | 30 | 31 | def getIndex(mode): 32 | 33 | # Get the data from the Index monitors 34 | index_xy = mode.getresult("index_xy","index") 35 | index_xz = mode.getresult("index_xz","index") 36 | return index_xy, index_xz 37 | 38 | 39 | if(__name__=="__main__"): 40 | with lumapi.MODE(MODE_SWG_DIRECTORY_READ) as mode: 41 | 42 | # ------------Comment for Avoiding Overriding the Simulation Region 43 | # override_varfdtd(mode=mode) 44 | # override_swg(mode=mode) 45 | 46 | index_xy, index_xz = getIndex(mode=mode) 47 | 48 | 49 | 50 | 51 | # --------------------------------Side-View--------------------------------- 52 | x = index_xy["x"].squeeze() 53 | y = index_xy["y"].squeeze() 54 | index_x = np.real(index_xy["index_x"].squeeze()) 55 | 56 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 57 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 58 | cmap = ax.pcolormesh(x*1e6, y*1e6,np.transpose(index_x)) 59 | fig.colorbar(cmap) 60 | plt.xlabel("x (um)") 61 | plt.ylabel("y (um)") 62 | plt.title('Side-view(xy)') 63 | plt.tight_layout() 64 | file_name_plot = os.path.join(MODE_SWG_DIRECTORY_WRITE[0], "index_profile_xy.png") 65 | plt.savefig(file_name_plot) 66 | plt.show() 67 | 68 | 69 | 70 | # --------------------------------Top-View--------------------------------- 71 | xx = index_xz["x"].squeeze() 72 | z = index_xz["z"].squeeze() 73 | index_z = np.real(index_xz["index_z"].squeeze()) 74 | 75 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 76 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 77 | cmap = ax.pcolormesh(x*1e6, z*1e6,np.transpose(index_z)) 78 | fig.colorbar(cmap) 79 | plt.xlabel("x (um)") 80 | plt.ylabel("z (um)") 81 | plt.title('Top-view(xz)') 82 | plt.tight_layout() 83 | file_name_plot = os.path.join(MODE_SWG_DIRECTORY_WRITE[0], "index_profile_xz.png") 84 | plt.savefig(file_name_plot) 85 | plt.show() 86 | -------------------------------------------------------------------------------- /MODE/swg_grating/override_swg_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script sets the MODE region for the sub-wavelength grating simulation. 11 | 12 | There are in total 13 | 14 | 1. ... 15 | """ 16 | 17 | #---------------------------------------------------------------------------- 18 | # Imports from user files 19 | # --------------------------------------------------------------------------- 20 | 21 | import lumapi 22 | from MODE.swg_grating.user_inputs.user_simulation_parameters import * 23 | from config import MODE_SWG_DIRECTORY_READ 24 | 25 | 26 | 27 | def override_swg(mode): 28 | 29 | mode.switchtolayout() 30 | 31 | 32 | configuration = ( 33 | ("grating-constructor", (("wg_width", wg_width), 34 | ("wg_thickness", wg_thickness), 35 | ("mirror_periods", mirror_periods), 36 | ("pitch", pitch), 37 | ("duty_cycle", duty_cycle), 38 | ("etch_depth", etch_depth))), 39 | 40 | 41 | ) 42 | 43 | # Populate the waveguide simulation region 44 | 45 | for obj, parameters in configuration: 46 | for k, v in parameters: 47 | mode.setnamed(obj, k, v) 48 | 49 | mode.save() 50 | 51 | # --------------------------------------------------------------------------- 52 | 53 | 54 | if(__name__=="__main__"): 55 | 56 | with lumapi.MODE(MODE_SWG_DIRECTORY_READ) as mode: 57 | override_swg(mode=mode) 58 | 59 | 60 | -------------------------------------------------------------------------------- /MODE/swg_grating/override_varfdtd_region.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The script sets the varFDTD region for the sub-wavelength grating simulation. 11 | 12 | There are in total 13 | 14 | 1. ... 15 | """ 16 | 17 | #---------------------------------------------------------------------------- 18 | # Imports from user files 19 | # --------------------------------------------------------------------------- 20 | 21 | import lumapi 22 | from MODE.swg_grating.user_inputs.user_simulation_parameters import * 23 | from config import MODE_SWG_DIRECTORY_READ 24 | 25 | def override_varfdtd(mode): 26 | 27 | mode.switchtolayout() 28 | 29 | configuration = ( 30 | 31 | 32 | ("source", (("mode selection", mode_source), 33 | ("wavelength start", wavelength_start), 34 | ("wavelength stop", wavelength_stop))), 35 | 36 | ("R_exp", (("monitor type", mode_monitor), 37 | )), 38 | 39 | ("T_exp", (("monitor type", mode_monitor), 40 | )), 41 | 42 | ("mesh", (("dx", mesh_dx), 43 | ("dy", mesh_dy), 44 | ("dz", mesh_dz), 45 | ("override x mesh", enable_dx), 46 | ("override y mesh", enable_dy), 47 | ("override z mesh", enable_dz))), 48 | 49 | ("::model", (("FDTD_z_span", simulation_span_z), 50 | ("FDTD_y_span", simulation_span_y), 51 | ("port_extension", port_extension))), 52 | 53 | ("varFDTD", (("simulation time", simulation_time), 54 | ("mesh accuracy",mesh_accuracy))), 55 | 56 | ) 57 | 58 | # Populate the waveguide simulation region 59 | 60 | for obj, parameters in configuration: 61 | for k, v in parameters: 62 | mode.setnamed(obj, k, v) 63 | 64 | mode.setglobalmonitor("frequency points",frequency_points) 65 | 66 | mode.save() 67 | 68 | 69 | # --------------------------------------------------------------------------- 70 | 71 | 72 | if(__name__=="__main__"): 73 | with lumapi.MODE(MODE_SWG_DIRECTORY_READ) as mode: 74 | override_varfdtd(mode=mode) 75 | 76 | 77 | -------------------------------------------------------------------------------- /MODE/swg_grating/transmission/getFrequencyResponse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script plots the transmission and reflection for the sub-wavelength 11 | bragg grating structure defined in the sub_wavelength_grating.fsp file 12 | from the T and R monitors 13 | 14 | """ 15 | 16 | #---------------------------------------------------------------------------- 17 | # Imports from user input files 18 | # --------------------------------------------------------------------------- 19 | 20 | import numpy as np 21 | import lumapi, os 22 | import matplotlib.pyplot as plt 23 | import scipy.constants as scpy 24 | from config import * 25 | 26 | from MODE.swg_grating.override_varfdtd_region import override_varfdtd 27 | from MODE.swg_grating.override_swg_region import * 28 | 29 | def getBraggResponse(mode): 30 | mode.run() 31 | T = np.squeeze(mode.transmission("T")) 32 | R = np.squeeze(mode.transmission("R")) 33 | f = np.squeeze(mode.getdata("T","f")) 34 | 35 | return T, R, f 36 | 37 | 38 | 39 | if(__name__=="__main__"): 40 | with lumapi.MODE(MODE_SWG_DIRECTORY_READ) as mode: 41 | 42 | # ------------ Comment for Avoiding Overriding the Simulation Region 43 | # override_varfdtd(mode=mode) 44 | # override_swg(mode=mode) 45 | 46 | # --------------------------------Plot-T/R--------------------------------- 47 | 48 | T, R, f = getBraggResponse(mode=mode) 49 | 50 | # --------------------------------Plot-T/R--------------------------------- 51 | 52 | px = 1/plt.rcParams['figure.dpi'] # pixel in inches 53 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 54 | ax.plot((scpy.c/f)*1e6,T,label = 'Transmission') 55 | ax.plot((scpy.c/f)*1e6,abs(R),label = 'Reflection') 56 | ax.legend() 57 | ax.set_xlabel("wavelength (um)") 58 | ax.set_ylabel("Magnitude") 59 | plt.ylim([0,1]) 60 | plt.tight_layout() 61 | file_name_plot = os.path.join(MODE_SWG_DIRECTORY_WRITE[1], "frequency_response.png") 62 | plt.savefig(file_name_plot) 63 | 64 | fig, ax = plt.subplots(figsize=(512*px, 256*px)) 65 | ax.plot((scpy.c/f)*1e6,10*np.log10(T),label = 'Transmission') 66 | ax.plot((scpy.c/f)*1e6,10*np.log10(abs(R)),label = 'Reflection') 67 | ax.legend() 68 | ax.set_xlabel("wavelength (um)") 69 | ax.set_ylabel("Magnitude (dB)") 70 | plt.tight_layout() 71 | file_name_plot = os.path.join(MODE_SWG_DIRECTORY_WRITE[1], "frequency_response_dB.png") 72 | plt.savefig(file_name_plot) 73 | 74 | plt.show() -------------------------------------------------------------------------------- /MODE/swg_grating/user_inputs/lumerical_files/sub_wavelength_grating_layer_1.lms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/MODE/swg_grating/user_inputs/lumerical_files/sub_wavelength_grating_layer_1.lms -------------------------------------------------------------------------------- /MODE/vertical_taper/README.md: -------------------------------------------------------------------------------- 1 | ## 2D Verttical Taper Simulations (MODE Solutions) 2 | 3 | ``` 4 | vertical_taper/ 5 | ├── neff_sweep 6 | │   └── neff_width_sweep_2D.py 7 | └── user_inputs 8 | ├── lumerical_files 9 | │   ├── taper_waveguide_layer1.lms 10 | │   └── taper_waveguide_layer2.lms 11 | └── user_sweep_parameters.py 12 | ``` 13 | 14 | ### Quick Simulation Setup 15 | 16 | 1. After downloading the repository, navigate through the `vertical_taper/user_inputs/lumerical_files` directory. 17 | 2. Edit the two lumerical files `taper_waveguide_layer1.lms` and `taper_waveguide_layer2.lms` to define the simulation materials for the cladding, core, and box layers along with their dimensions. 18 | 3. Edit the `user_sweep_parameters.py` to define the simulation sweep parameters. Follow the comment-sections written in the file. 19 | 4. Run the files in the `vertical_taper/neff_sweep` directory and get the results. 20 | 21 | 22 | 23 | Tip: At the taper-length where the two effective indices of the bottom and upper taper are equal, that's the point where the light couples from the bottom to the upper layer. 24 | -------------------------------------------------------------------------------- /MODE/vertical_taper/user_inputs/lumerical_files/taper_waveguide_layer1.lms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/MODE/vertical_taper/user_inputs/lumerical_files/taper_waveguide_layer1.lms -------------------------------------------------------------------------------- /MODE/vertical_taper/user_inputs/lumerical_files/taper_waveguide_layer2.lms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcharalampous/lumerical-py-scripts/4f1f00877f8dff7da7085385bd9fd0c30c1a71a6/MODE/vertical_taper/user_inputs/lumerical_files/taper_waveguide_layer2.lms -------------------------------------------------------------------------------- /MODE/vertical_taper/user_inputs/user_sweep_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are required. 9 | 10 | In this file, the user is rmust enter the parameters required to sweep. 11 | 12 | The waveguide parameters to sweep are 'wg_width' for each Taper. 13 | 14 | 15 | ^ 16 | | 17 | | 18 | | - 19 | wg_width 20 | <---------------> 21 | +-------|--------+ ^ 22 | | | | | 23 | | waveguide | | Thickness defined in Lumerical File 24 | | | | | 25 | ------------|----------v---------------------> 26 | (0,0)| 27 | | 28 | | 29 | | 30 | 31 | """ 32 | 33 | # 1. Simulation Parameters 34 | num_modes = 4 35 | 36 | # 2. Taper length parameters 37 | res = 30 # Ressolution of polygon, thus, loop itterations 38 | m=1 # Order of the taper 39 | taper_length = 200e-6; # Total length of the taper 40 | 41 | # 3. Taper width parameters 42 | # 3.1 Choose the waveguide width on left side 'width_wg_left' 43 | width_wg_left_1 = 1.2e-6; 44 | width_wg_right_1 = 0.25e-6; 45 | # 3.2 Choose the waveguide width on right side 'width_wg_right' 46 | width_wg_left_2 = 0.25e-6; 47 | width_wg_right_2 = 1.2e-6; 48 | 49 | # 4 Figure plot DPI 50 | my_dpi = 96 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /MODE/waveguide/README.md: -------------------------------------------------------------------------------- 1 | ## 2D Waveguide Simulations (MODE Solutions) 2 | 3 | ```` 4 | MODE/waveguide/ 5 | ├── fde_region.py 6 | ├── index_profile 7 | │   └── get_index_mesh_2D.py 8 | ├── mode_profile 9 | │   ├── mode_profile_1D.py 10 | │   └── mode_profile_2D.py 11 | ├── neff_sweep 12 | │   ├── neff_height_sweep_2D.py 13 | │   ├── neff_height_sweep_variations_2D.py 14 | │   ├── neff_width_sweep_2D.py 15 | │   └── neff_width_sweep_variations_2D.py 16 | ├── np_density_sweep 17 | │   └── voltage_sweep_2D.py 18 | ├── pcm 19 | │   └── confinement_factor.py 20 | ├── pin_offset_sweep 21 | │   └── loss_offset_sweep_2D.py 22 | ├── radius_sweep 23 | │   ├── overlap_radius_sweep_2D.py 24 | │   └── Q_factor_radius_sweep_2D.py 25 | ├── README.md 26 | ├── user_inputs 27 | │   ├── user_materials.py 28 | │   ├── user_simulation_parameters.py 29 | │   └── user_sweep_parameters.py 30 | └── waveguide_render.py 31 | 32 | ```` 33 | 34 | 35 | ### Quick Simulation Setup 36 | 37 | 1. After downloading the repository, navigate through the `waveguide/user-inputs` directory. 38 | 2. Edit the `user_materials.py` to define the simulation materials for the cladding, core, box, and substrate layers. Follow the instructions written in the file. 39 | 3. Edit the `user_simulation_parameters.py` to define the simulation properties, region and structure dimensions. Follow the instructions written in the file. If you would like to do a sweep, modify the `user_sweep_parameters/py`. 40 | 4. Navigate under the `waveguide/mode_profile` or `waveguide/neff_sweep` directories to run the desired python file. 41 | -------------------------------------------------------------------------------- /MODE/waveguide/neff_sweep/neff_height_sweep_variations_2D.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The scripts calculates the effective index variations of the width based on 11 | the number of modes you defined. 12 | 13 | You need to run the neef_width_sweep_2D.pyto calculate the effective index 14 | vs width. 15 | """ 16 | 17 | 18 | #---------------------------------------------------------------------------- 19 | # Imports from user files 20 | # --------------------------------------------------------------------------- 21 | 22 | import numpy as np 23 | import matplotlib.pyplot as plt 24 | 25 | # Import user-defined input parameters 26 | from MODE.waveguide.user_inputs.user_sweep_parameters import * 27 | from MODE.waveguide.waveguide_render import * 28 | 29 | # Runs the module to calculate the neff vs height 30 | from MODE.waveguide.neff_sweep.neff_height_sweep_2D import * 31 | 32 | 33 | 34 | # Plots the effective index width variations as a function of width 35 | if(__name__=="__main__"): 36 | with lumapi.MODE() as mode: 37 | 38 | # Disable Rendering 39 | mode.redrawoff() 40 | 41 | # Draw the waveguide structure using a custom function 42 | waveguide_draw(mode) 43 | 44 | # Add a finite-difference eigenmode (FDE) region to the simulation environment 45 | add_fde_region(mode) 46 | 47 | 48 | neff_array, wg_height_array, polariz_frac, polariz_mode = heightSweep(mode=mode) 49 | 50 | # Plots the effective index width variations as a function of heigt 51 | plt.figure(2,figsize=(512/my_dpi, 256/my_dpi), dpi=my_dpi) 52 | 53 | for m in range(1,num_modes+1): 54 | 55 | # Calculates the derivative 56 | dneffdwidth = np.gradient(neff_array[:,m-1], wg_height_array) 57 | plt.semilogy(wg_height_array*1e6,np.real(dneffdwidth)*1e-9,'-o', label = 'M-'+str(m)) 58 | 59 | plt.legend() 60 | plt.ylim([1e-5,1e-2]) 61 | plt.xlabel("height (um)") 62 | plt.ylabel('$\partial(n_{eff})/\partial(h)\quad (nm^{-1})$') 63 | plt.title("width "+ str(wg_width*1e6) + " um") 64 | plt.grid(True, which='both') 65 | plt.tight_layout() 66 | 67 | # Save the figure files as .png 68 | file_name_plot = os.path.join(MODE_WAVEGUIDE_DIRECTORY_WRITE[2], "neff_height_sweep_variations.png") 69 | plt.savefig(file_name_plot, dpi=my_dpi, format="png") -------------------------------------------------------------------------------- /MODE/waveguide/neff_sweep/neff_width_sweep_variations_2D.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | No user-inputs are required. 9 | 10 | The scripts calculates the effective index variations of the width based on 11 | the number of modes you defined. 12 | 13 | You need to run the neef_width_sweep_2D.pyto calculate the effective index 14 | vs width. 15 | """ 16 | 17 | 18 | #---------------------------------------------------------------------------- 19 | # Imports from user files 20 | # --------------------------------------------------------------------------- 21 | 22 | import numpy as np 23 | import lumapi 24 | import matplotlib.pyplot as plt 25 | from matplotlib.patches import Rectangle 26 | 27 | 28 | # Import user-defined input parameters 29 | from MODE.waveguide.user_inputs.user_sweep_parameters import * 30 | from MODE.waveguide.waveguide_render import * 31 | 32 | # Runs the module to calculate the neff vs height 33 | from MODE.waveguide.neff_sweep.neff_width_sweep_2D import * 34 | 35 | 36 | 37 | 38 | # Plots the effective index width variations as a function of width 39 | if(__name__=="__main__"): 40 | with lumapi.MODE() as mode: 41 | 42 | # Disable Rendering 43 | mode.redrawoff() 44 | 45 | # Draw the waveguide structure using a custom function 46 | waveguide_draw(mode) 47 | 48 | # Add a finite-difference eigenmode (FDE) region to the simulation environment 49 | add_fde_region(mode) 50 | 51 | 52 | neff_array, wg_width_array, polariz_frac, polariz_mode = widthSweep(mode=mode) 53 | 54 | 55 | # Plots effective index with widths 56 | plt.figure(2, figsize=(512/my_dpi, 256/my_dpi), dpi=my_dpi) 57 | 58 | for m in range(1,num_modes+1): 59 | 60 | # Calculates the derivative 61 | dneffdwidth = np.gradient(neff_array[:,m-1], wg_width_array) 62 | plt.semilogy(wg_width_array*1e6,np.real(dneffdwidth)*1e-9,'-o', label = 'M-'+str(m)) 63 | 64 | plt.legend() 65 | plt.ylim([1e-6,1e-2]) 66 | plt.xlabel("waveguide width (um)") 67 | plt.ylabel('$d(n_{eff})/d(w)\quad (nm^{-1})$') 68 | plt.title("thickness "+ str(wg_thickness*1e6) + " um") 69 | 70 | # Save the figure files as .png 71 | 72 | file_name_plot = os.path.join(MODE_WAVEGUIDE_DIRECTORY_WRITE[2], "neff_width_sweep_variations.png") 73 | plt.grid(True, which='both') 74 | plt.tight_layout() 75 | plt.savefig(file_name_plot, dpi=my_dpi, format="png") -------------------------------------------------------------------------------- /MODE/waveguide/pcm/confinement_factor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #---------------------------------------------------------------------------- 4 | # @author: Georgios Gcharalampous (gcharalampous) 5 | # version ='1.0' 6 | # --------------------------------------------------------------------------- 7 | """ 8 | User-inputs are Not required. 9 | 10 | The script calculates confinement factor in PCM region 11 | 12 | """ 13 | 14 | #---------------------------------------------------------------------------- 15 | # Imports from user input files 16 | # --------------------------------------------------------------------------- 17 | 18 | import numpy as np 19 | from config import * 20 | from scipy import integrate 21 | 22 | from MODE.waveguide.waveguide_render import * 23 | from MODE.waveguide.fde_region import add_fde_region 24 | 25 | 26 | # ------------------------- No inputs are required --------------------------- 27 | 28 | def integrate_power(): 29 | if(pcm_layer_enable): 30 | pcm_x_min = mode.getnamed("pcm","x min") 31 | pcm_x_max = mode.getnamed("pcm","x max") 32 | pcm_y_min = mode.getnamed("pcm","y min") 33 | pcm_y_max = mode.getnamed("pcm","y max") 34 | 35 | for m in range(1,num_modes+1): 36 | Em = np.squeeze(mode.getelectric("FDE::data::mode"+str(m))) 37 | Im = np.abs(Em)**2 38 | 39 | # Integrate power over the specified region 40 | 41 | x=np.squeeze(mode.getdata("FDE::data::mode"+str(m),"x")) 42 | y=np.squeeze(mode.getdata("FDE::data::mode"+str(m),"y")) 43 | X, Y = np.meshgrid(x, y) 44 | 45 | filter = (Xpcm_x_min) 46 | filter = filter & (Ypcm_y_min) 47 | 48 | E1 = integrate.simpson(integrate.simpson(np.transpose(Im)*filter,x),y) 49 | 50 | E2 = integrate.simpson(integrate.simpson(np.transpose(Im),x),y) 51 | 52 | # Accumulate the power integration result 53 | print(str(np.round((E1/E2)*100,2)) + " %") 54 | else: 55 | print("Enable PCM material in user_inputs/user_simulation_parameters.py") 56 | 57 | 58 | if(__name__=="__main__"): 59 | with lumapi.MODE() as mode: 60 | 61 | # Disable Rendering 62 | mode.redrawoff() 63 | 64 | # Draw the waveguide structure using a custom function 65 | waveguide_draw(mode) 66 | 67 | # Add a finite-difference eigenmode (FDE) region to the simulation environment 68 | add_fde_region(mode) 69 | 70 | # Run the simulation, create a mesh, and compute the modes, then save 71 | mode.run() 72 | mode.findmodes() 73 | mode.save(MODE_WAVEGUIDE_DIRECTORY_WRITE_FILE + "\\waveguide_modes.lms") 74 | 75 | # Turn redraw back on and close LumAPI connection 76 | mode.redrawon() 77 | 78 | # Get confinement factor 79 | integrate_power() 80 | 81 | 82 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | ## To-Do List 2 | 3 | ### Features (New Scripts) 4 | - [ ] Adding Confinment Factor Future MODE/waveguide 5 | - [ ] PN Loss Calculation MODE/waveguide 6 | 7 | ### Updating Code 8 | - [ ] Add the scripts for FDTD/mmi_coupler 9 | - [ ] Add the scripts for FDTD/directional_coupler 10 | - [ ] Update the code for saving the files in several scripts using the config file 11 | - [ ] Add a new sub-repo for FDTD/grating_coupler_rectangular_3D 12 | 13 | ### Optimization (New Scripts) 14 | - [ ] Optimize grating period calculation 15 | 16 | ### Documentation 17 | - Quick Simulation Setup and Project Tree for 18 | - [ ] MODE/awg_star_coupler 19 | - [ ] MDOE/swg_star_coupler 20 | - [ ] FDTD/waveguide_mode_taper 21 | - [ ] FDTD/waveguide_crossing 22 | - [ ] FDTD/vertical_taper 23 | - [ ] FDTD/swg_grating 24 | - [ ] FDTD/ring_resonator_coupler 25 | - [ ] FDTD/edge_coupler 26 | - [ ] FDTD/disk_resonator_coupler 27 | - [ ] FDTD/directional_coupler 28 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | matplotlib==3.8.1 2 | numpy==1.24.4 3 | pandas==2.2.0 4 | scipy==1.12.0 5 | Shapely==2.0.2 6 | --------------------------------------------------------------------------------