├── .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 = "