Skip to content

Commit

Permalink
moved 2x2mmi gds to files, updates to notebook
Browse files Browse the repository at this point in the history
  • Loading branch information
Andeloth committed Feb 13, 2024
1 parent 664a747 commit d25d515
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 53 deletions.
File renamed without changes.
92 changes: 39 additions & 53 deletions book/pages/scattering_parameters.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"\n",
"In this section we'll demonstrate how to find the s-params for any device using a meep simulation. We'll show both 2D and 3D simulations, but keep in mind that 2D s-params are not very accurate, but the simulations run much faster. It is often recommended to set up the simulation in 2D to ensure everything works, then extend the simulation into 3D to run the final simulations. This can save us a lot of debugging time since the 2D simulations run faster.\n",
"\n",
"We'll run through the steps using gdsfactory's default 2x2 mmi, and explain on the way how the principles can be applied to any component. There are other ways to find s-parameters, and another method is shown on the [Gds To Meep](/pages/gds_to_meep) page"
"We'll run through the steps using gdsfactory's default 2x2 mmi, and explain on the way how the principles can be applied to any component. There are other ways to find s-parameters, one such method is shown on the [Gds To Meep](/pages/gds_to_meep) page."
]
},
{
Expand All @@ -61,28 +61,30 @@
"source": [
"### Step 1 - Import Geometry\n",
"\n",
"If we have a gds of the device t can make life easy if we add all of our sources and detectors into our gds before we import it into meep. For this tutorial I have already done this. For your simulations, you can modify your gds file directly in Klayout if you like a GUI, or you can use gdsfactory itself. If you like, you can also use meep to do the same thing, but I won't be showing how to do that here. This tutorial is adapted from the [GDSII Import](https://meep.readthedocs.io/en/latest/Python_Tutorials/GDSII_Import/) tutorial on the meep documentation\n",
"This tutorial is adapted from the [GDSII Import](https://meep.readthedocs.io/en/latest/Python_Tutorials/GDSII_Import/) tutorial.\n",
"\n",
"If we have a gds of the device whose parameters we want to simulate, we can add all of our sources and detectors into our gds before we import it into meep. This will create the sources and monitors in meep that we need for the simulation.\n",
"\n",
"Here is a picture of the gds we will be using. \n",
"\n",
"![Image of splitter file](https://raw.githubusercontent.com/BYUCamachoLab/Photonics-Bootcamp/main/book/images/Notebook_Images/mmi2x2_gds_with_ports.png)\n",
"\n",
"I've added a box around the entire component (in purple) which will become the simulation region, and 8 lines, 2 on each end that will become the sources and detectors. I also added straight waveguides on the ports of the gdsfactory mmi so that my ports could be exactly where the light would enter and exit the component in an actual circuit. My sources are then slightly outside the mmi, in the waveguides.\n",
"We add a box around the entire component (purple) which will become the simulation region, and 8 lines, 2 on each end that will become the sources and detectors. We also add straight waveguides on the ports of the gdsfactory mmi so that the ports will be exactly where the light would enter and exit the component in an actual circuit.\n",
"\n",
"So, now that we have a gds, lets import it into meep!"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# Imports\n",
"import meep as mp \n",
"import numpy\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt \n",
"#import math"
"import os"
]
},
{
Expand All @@ -95,27 +97,15 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 2,
"metadata": {},
"outputs": [
{
"ename": "",
"evalue": "",
"output_type": "error",
"traceback": [
"\u001b[1;31mFailed to start the Kernel. \n",
"\u001b[1;31mKernel Python 3.9.6 is not usable. Check the Jupyter output tab for more information. \n",
"\u001b[1;31mView Jupyter <a href='command:jupyter.viewOutput'>log</a> for further details."
]
}
],
"outputs": [],
"source": [
"res = 40 # the resolution of the simulation in pixels/um\n",
"three_d = False # Turn this to false for a 2D simulation\n",
"if three_d: # If three_d, reduce the resolution\n",
" res = res/2\n",
"sim_is_3D = False # Turn this to false for a 2D simulation\n",
"\n",
"gds_file = \"/home/jkart/Work/Photonics-Bootcamp/Photonics-Bootcamp/book/images/mmi2x2.gds\" # The name of our gds file\n",
"pwd = os.path.abspath('')\n",
"gds_file = f\"{pwd}/../images/mmi2x2.gds\" # The name of our gds file\n",
"\n",
"# Here we define the layer numbers for each part of our gds\n",
"geometry_L = 1\n",
Expand Down Expand Up @@ -147,15 +137,14 @@
"silicon = mp.Medium(epsilon=12)\n",
"\n",
"# Sets the min and max values for the cell and the silicon. Our simulation will be centered at y=0\n",
"cell_zmax = 0.5*cell_thickness if three_d else 0\n",
"cell_zmin = -0.5 * cell_thickness if three_d else 0\n",
"si_zmax = 0.5 * t_Si if three_d else 10 # In a 2D simulation, the geometry still has to have a thickness or it won't show up\n",
"si_zmin = -0.5 * t_Si if three_d else -10\n",
"cell_zmax = 0.5*cell_thickness if sim_is_3D else 0\n",
"cell_zmin = -0.5 * cell_thickness if sim_is_3D else 0\n",
"si_zmax = 0.5 * t_Si if sim_is_3D else 10 # In a 2D simulation, the geometry still has to have a thickness or it won't show up\n",
"si_zmin = -0.5 * t_Si if sim_is_3D else -10\n",
"\n",
"# Create a 2D array to hold the S-Parameters for the device\n",
"numPorts = 4 # The number of ports, also the size of our array\n",
"# s_params = [[0 for i in range(numPorts)] for j in range(numPorts)]\n",
"# input_params = [0 for i in range(numPorts)]\n"
"n_ports = 4 # The number of ports, also the size of our array\n",
"s_params = np.zeros((n_ports, n_ports))\n"
]
},
{
Expand All @@ -176,9 +165,7 @@
"evalue": "",
"output_type": "error",
"traceback": [
"\u001b[1;31mFailed to start the Kernel. \n",
"\u001b[1;31mKernel Python 3.9.6 is not usable. Check the Jupyter output tab for more information. \n",
"\u001b[1;31mView Jupyter <a href='command:jupyter.viewOutput'>log</a> for further details."
"\u001b[1;31mThe Kernel crashed while executing code in the the current cell or a previous cell. Please review the code in the cell(s) to identify a possible cause of the failure. Click <a href='https://aka.ms/vscodeJupyterKernelCrash'>here</a> for more info. View Jupyter <a href='command:jupyter.viewOutput'>log</a> for further details."
]
}
],
Expand All @@ -196,8 +183,7 @@
"source3 = mp.GDSII_vol(fname = gds_file, layer = source3_L, zmax=cell_zmax, zmin=cell_zmin)\n",
"source4 = mp.GDSII_vol(fname = gds_file, layer = source4_L, zmax=cell_zmax, zmin=cell_zmin)\n",
"\n",
"\n",
"if three_d: # Sets up the oxide cladding for a three d simulation (Not used in a 2D simulation)\n",
"if sim_is_3D: # Sets up the oxide cladding for a three d simulation (Not used in a 2D simulation)\n",
" oxide_center = mp.Vector3(z=-0.5 * t_oxide)\n",
" oxide_size = mp.Vector3(cell.size.x, cell.size.y, t_oxide)\n",
" oxide_layer = [mp.Block(material=oxide, center=oxide_center, size=oxide_size)]\n",
Expand Down Expand Up @@ -243,7 +229,7 @@
" size=source1.size, # Here we input the geometry for our first source\n",
" center=source1.center,\n",
" eig_band=1,\n",
" eig_parity = mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z,\n",
" eig_parity = mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z,\n",
" eig_match_freq = True,\n",
"\n",
" )\n",
Expand Down Expand Up @@ -362,11 +348,11 @@
"#############################################################\n",
"alphas = [[1,1,0,0,0], [1,1,0,0,0],[1,1,0,0,1],[1,1,0,0,1]] # This array holds the values for forwards and backward propagation for each soure. The 5th number is for the total input\n",
"# Finds the S parameters\n",
"input_coeff = sim.get_eigenmode_coefficients(modeMonitors[0], [1], eig_parity=mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[0][4]] # This is the amount of light from the source that enters the device\n",
"port1_coeff = sim.get_eigenmode_coefficients(modeMonitors[0], [1], eig_parity=mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[0][0]]\n",
"port2_coeff = sim.get_eigenmode_coefficients(modeMonitors[1], [1], eig_parity=mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[0][1]]\n",
"port3_coeff = sim.get_eigenmode_coefficients(modeMonitors[2], [1], eig_parity=mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[0][2]]\n",
"port4_coeff = sim.get_eigenmode_coefficients(modeMonitors[3], [1], eig_parity=mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[0][3]]\n",
"input_coeff = sim.get_eigenmode_coefficients(modeMonitors[0], [1], eig_parity=mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[0][4]] # This is the amount of light from the source that enters the device\n",
"port1_coeff = sim.get_eigenmode_coefficients(modeMonitors[0], [1], eig_parity=mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[0][0]]\n",
"port2_coeff = sim.get_eigenmode_coefficients(modeMonitors[1], [1], eig_parity=mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[0][1]]\n",
"port3_coeff = sim.get_eigenmode_coefficients(modeMonitors[2], [1], eig_parity=mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[0][2]]\n",
"port4_coeff = sim.get_eigenmode_coefficients(modeMonitors[3], [1], eig_parity=mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[0][3]]\n",
"# Store the S parameters in s_params\n",
"s_params[0] = [port1_coeff, port2_coeff, port3_coeff, port4_coeff]\n",
"input_params[0] = input_coeff\n",
Expand Down Expand Up @@ -534,7 +520,7 @@
" size=source2.size, # Here we input the geometry for our first source\n",
" center=source2.center,\n",
" eig_band=1,\n",
" eig_parity = mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z,\n",
" eig_parity = mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z,\n",
" eig_match_freq = True,\n",
"\n",
" ),\n",
Expand All @@ -543,7 +529,7 @@
" size=source3.size, # Here we input the geometry for our first source\n",
" center=source3.center,\n",
" eig_band=1,\n",
" eig_parity = mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z,\n",
" eig_parity = mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z,\n",
" eig_match_freq = True,\n",
" eig_kpoint = mp.Vector3(-1,0,0),\n",
" direction = mp.NO_DIRECTION\n",
Expand All @@ -554,7 +540,7 @@
" size=source4.size, # Here we input the geometry for our first source\n",
" center=source4.center,\n",
" eig_band=1,\n",
" eig_parity = mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z,\n",
" eig_parity = mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z,\n",
" eig_match_freq = True,\n",
" eig_kpoint = mp.Vector3(-1,0,0),\n",
" direction = mp.NO_DIRECTION\n",
Expand Down Expand Up @@ -582,7 +568,7 @@
"source": [
"\n",
"\n",
"for i in range(numPorts-1) :\n",
"for i in range(n_ports-1) :\n",
"\n",
" source = sources[i:i+1]\n",
"\n",
Expand All @@ -609,11 +595,11 @@
"\n",
" #############################################################\n",
" # Finds the S parameters\n",
" port1_coeff = sim.get_eigenmode_coefficients(modeMonitors[0], [1], eig_parity=mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][0]]\n",
" port2_coeff = sim.get_eigenmode_coefficients(modeMonitors[1], [1], eig_parity=mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][1]]\n",
" port3_coeff = sim.get_eigenmode_coefficients(modeMonitors[2], [1], eig_parity=mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][2]]\n",
" port4_coeff = sim.get_eigenmode_coefficients(modeMonitors[3], [1], eig_parity=mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][3]]\n",
" input_coeff = sim.get_eigenmode_coefficients(modeMonitors[i+1], [1], eig_parity=mp.NO_PARITY if three_d else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][4]] # This is the total amount of light that entered the devie\n",
" port1_coeff = sim.get_eigenmode_coefficients(modeMonitors[0], [1], eig_parity=mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][0]]\n",
" port2_coeff = sim.get_eigenmode_coefficients(modeMonitors[1], [1], eig_parity=mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][1]]\n",
" port3_coeff = sim.get_eigenmode_coefficients(modeMonitors[2], [1], eig_parity=mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][2]]\n",
" port4_coeff = sim.get_eigenmode_coefficients(modeMonitors[3], [1], eig_parity=mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][3]]\n",
" input_coeff = sim.get_eigenmode_coefficients(modeMonitors[i+1], [1], eig_parity=mp.NO_PARITY if 3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][4]] # This is the total amount of light that entered the devie\n",
"\n",
" # Store the S parameters in s_params\n",
" index = 1+i \n",
Expand All @@ -639,7 +625,7 @@
],
"source": [
"print(\"S-Params:\")\n",
"for i in range(numPorts):\n",
"for i in range(n_ports):\n",
" print(f\"S{i+1}1: {s_params[i][0]}\\tS{i+1}2: {s_params[i][1]}\\tS{i+1}3: {s_params[i][2]}\\tS{i+1}4: {s_params[i][3]}\")\n",
"\n",
"print(\"Input S-Params\")\n",
Expand All @@ -648,7 +634,7 @@
"\n",
"\n",
"print(\"Transmission:\")\n",
"for i in range(numPorts):\n",
"for i in range(n_ports):\n",
" input_power = abs(input_params[i])**2\n",
" trans1 = abs(s_params[i][0])**2 / input_power * 100\n",
" trans2 = abs(s_params[i][1])**2 / input_power * 100\n",
Expand Down Expand Up @@ -720,7 +706,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
"version": "3.11.7"
},
"orig_nbformat": 4,
"vscode": {
Expand Down

0 comments on commit d25d515

Please sign in to comment.