diff --git a/_images/d7a1ebc0245c1cd021c3b83c8290f8dc3a6930dd6487603fa3bce28f13f50f54.png b/_images/d7a1ebc0245c1cd021c3b83c8290f8dc3a6930dd6487603fa3bce28f13f50f54.png
deleted file mode 100644
index 1afa30d..0000000
Binary files a/_images/d7a1ebc0245c1cd021c3b83c8290f8dc3a6930dd6487603fa3bce28f13f50f54.png and /dev/null differ
diff --git a/_sources/pages/scattering_parameters.ipynb b/_sources/pages/scattering_parameters.ipynb
index 41c17b4..2fd48d2 100644
--- a/_sources/pages/scattering_parameters.ipynb
+++ b/_sources/pages/scattering_parameters.ipynb
@@ -76,20 +76,9 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "3"
- ]
- },
- "execution_count": 6,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# Imports\n",
"import meep as mp \n",
@@ -100,7 +89,7 @@
"from gplugins.gmeep.get_meep_geometry import get_meep_geometry_from_component\n",
"from gdsfactory.read import import_gds\n",
"import gdsfactory as gf\n",
- "mp.verbosity(1)"
+ "mp.verbosity(0)"
]
},
{
@@ -113,11 +102,11 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": null,
"metadata": {},
"outputs": [],
"source": [
- "res = 20 # the resolution of the simulation in pixels/um\n",
+ "res = 40 # the resolution of the simulation in pixels/um\n",
"sim_is_3D = False # Turn this to false for a 2D simulation\n",
"\n",
"pwd = Path(os.path.abspath(''))\n",
@@ -161,7 +150,7 @@
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -181,12 +170,14 @@
"mmi_comp = import_gds(gds_file)\n",
"geometry = get_meep_geometry_from_component(mmi_comp, is_3d=sim_is_3D, wavelength=lcen, layer_stack=layer_stack)\n",
"# Use this to modify the material of the loaded geometry if needed.\n",
- "# geometry = [mp.Prism(geom.vertices, geom.height, geom.axis, geom.center, material=mp.Medium(index=3.45)) for geom in geometry]"
+ "# geometry = [mp.Prism(geom.vertices, geom.height, geom.axis, geom.center, material=mp.Medium(index=3.45)) for geom in geometry]\n",
+ "mmi_comp.plot()\n",
+ "plt.show()"
]
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -208,8 +199,8 @@
"\n",
"port1 = mp.Volume(center=mp.Vector3(-port_xdisp,-port_ydisp,0), size=port_size)\n",
"port2 = mp.Volume(center=mp.Vector3(-port_xdisp,port_ydisp,0), size=port_size)\n",
- "port3 = mp.Volume(center=mp.Vector3(port_xdisp,port_ydisp,0), size=port_size)\n",
- "port4 = mp.Volume(center=mp.Vector3(port_xdisp,-port_ydisp,0), size=port_size)\n",
+ "port3 = mp.Volume(center=mp.Vector3(port_xdisp,-port_ydisp,0), size=port_size)\n",
+ "port4 = mp.Volume(center=mp.Vector3(port_xdisp,port_ydisp,0), size=port_size)\n",
"source1 = mp.Volume(center=port1.center-mp.Vector3(x=0.5),size=port_size)\n",
"source2 = mp.Volume(center=port4.center+mp.Vector3(x=0.5), size=port_size)"
]
@@ -228,7 +219,7 @@
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -251,8 +242,7 @@
" sources = sources, # The sources\n",
" geometry = geometry, # The geometry\n",
" default_material=SiO2\n",
- ")\n",
- "sim.init_sim()"
+ ")"
]
},
{
@@ -267,103 +257,13 @@
},
{
"cell_type": "code",
- "execution_count": 12,
+ "execution_count": null,
"metadata": {
"tags": [
"hide-output"
]
},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- " prism, center = (-7.75,-0.625,5e+19)\n",
- " height 1e+20, axis (0,0,1), sidewall angle: 0 radians, 4 vertices:\n",
- " (-2.75,-1.125,0)\n",
- " (-12.75,-0.875,0)\n",
- " (-12.75,-0.375,0)\n",
- " (-2.75,-0.125,0)\n",
- " dielectric constant epsilon diagonal = (12.0946,12.0946,12.0946)\n",
- " prism, center = (-7.75,0.625,5e+19)\n",
- " height 1e+20, axis (0,0,1), sidewall angle: 0 radians, 4 vertices:\n",
- " (-2.75,0.125,0)\n",
- " (-12.75,0.375,0)\n",
- " (-12.75,0.875,0)\n",
- " (-2.75,1.125,0)\n",
- " dielectric constant epsilon diagonal = (12.0946,12.0946,12.0946)\n",
- " prism, center = (7.75,0.625,5e+19)\n",
- " height 1e+20, axis (0,0,1), sidewall angle: 0 radians, 4 vertices:\n",
- " (2.75,0.125,0)\n",
- " (2.75,1.125,0)\n",
- " (12.75,0.875,0)\n",
- " (12.75,0.375,0)\n",
- " dielectric constant epsilon diagonal = (12.0946,12.0946,12.0946)\n",
- " prism, center = (7.75,-0.625,5e+19)\n",
- " height 1e+20, axis (0,0,1), sidewall angle: 0 radians, 4 vertices:\n",
- " (2.75,-1.125,0)\n",
- " (2.75,-0.125,0)\n",
- " (12.75,-0.375,0)\n",
- " (12.75,-0.875,0)\n",
- " dielectric constant epsilon diagonal = (12.0946,12.0946,12.0946)\n",
- " prism, center = (0,0,5e+19)\n",
- " height 1e+20, axis (0,0,1), sidewall angle: 0 radians, 4 vertices:\n",
- " (-2.75,-1.25,0)\n",
- " (-2.75,1.25,0)\n",
- " (2.75,1.25,0)\n",
- " (2.75,-1.25,0)\n",
- " dielectric constant epsilon diagonal = (12.0946,12.0946,12.0946)\n",
- " prism, center = (15.25,-0.625,5e+19)\n",
- " height 1e+20, axis (0,0,1), sidewall angle: 0 radians, 4 vertices:\n",
- " (12.75,-0.875,0)\n",
- " (12.75,-0.375,0)\n",
- " (17.75,-0.375,0)\n",
- " (17.75,-0.875,0)\n",
- " dielectric constant epsilon diagonal = (12.0946,12.0946,12.0946)\n",
- " prism, center = (15.25,0.625,5e+19)\n",
- " height 1e+20, axis (0,0,1), sidewall angle: 0 radians, 4 vertices:\n",
- " (12.75,0.375,0)\n",
- " (12.75,0.875,0)\n",
- " (17.75,0.875,0)\n",
- " (17.75,0.375,0)\n",
- " dielectric constant epsilon diagonal = (12.0946,12.0946,12.0946)\n",
- " prism, center = (-15.25,0.625,5e+19)\n",
- " height 1e+20, axis (0,0,1), sidewall angle: 0 radians, 4 vertices:\n",
- " (-12.75,0.875,0)\n",
- " (-12.75,0.375,0)\n",
- " (-17.75,0.375,0)\n",
- " (-17.75,0.875,0)\n",
- " dielectric constant epsilon diagonal = (12.0946,12.0946,12.0946)\n",
- " prism, center = (-15.25,-0.625,5e+19)\n",
- " height 1e+20, axis (0,0,1), sidewall angle: 0 radians, 4 vertices:\n",
- " (-12.75,-0.375,0)\n",
- " (-12.75,-0.875,0)\n",
- " (-17.75,-0.875,0)\n",
- " (-17.75,-0.375,0)\n",
- " dielectric constant epsilon diagonal = (12.0946,12.0946,12.0946)\n"
- ]
- },
- {
- "data": {
- "text/plain": [
- "
This cross-over length \(L\), that gives 100% power transfer is found with:
-This is found from determining what length when multiplied by the propagation constants makes the phase difference \(\pi\):
diff --git a/pages/scattering_parameters.html b/pages/scattering_parameters.html index 5b42710..19fcf33 100644 --- a/pages/scattering_parameters.html +++ b/pages/scattering_parameters.html @@ -318,11 +318,11 @@gplugins.gmeep.write_sparameters_meep
3
+mp.verbosity(0)
res = 20 # the resolution of the simulation in pixels/um
+res = 40 # the resolution of the simulation in pixels/um
sim_is_3D = False # Turn this to false for a 2D simulation
pwd = Path(os.path.abspath(''))
@@ -444,6 +439,8 @@ Step 1 - Import Geometrygeometry = get_meep_geometry_from_component(mmi_comp, is_3d=sim_is_3D, wavelength=lcen, layer_stack=layer_stack)
# Use this to modify the material of the loaded geometry if needed.
# geometry = [mp.Prism(geom.vertices, geom.height, geom.axis, geom.center, material=mp.Medium(index=3.45)) for geom in geometry]
+mmi_comp.plot()
+plt.show()
As we see from the output of sim.plot2D, our simulation is set up correctly. The red line is our source, the blue are our 4 monitors. We are ready to run the simulation! Actually running the simulation is the most computationally intense part of this, so it may take some time if you have a high resolution and are running a 3D simulation. The until_after_sources=mp.stop_when_dft_decayed
parameter for sim.run() means meep will start checking how much the cumulative Fourier Transform of all the fields in the simulation changes only after the sources have turned off. Then, it will wait until the DFT’s change over one time step is below a certain threshold (1e-11 relative change by default), at which point it will stop the simulation
# Calculates the transmittance based off of the S parameters
-port1_trans = abs(port1_coeff) ** 2 / abs(input_coeff) ** 2
-port2_trans = abs(port2_coeff) ** 2 / abs(input_coeff) ** 2
-port3_trans = abs(port3_coeff) ** 2 / abs(input_coeff) ** 2
-port4_trans = abs(port4_coeff) ** 2 / abs(input_coeff) ** 2
+port1_trans = abs(port1_coeff) ** 2
+port2_trans = abs(port2_coeff) ** 2
+port3_trans = abs(port3_coeff) ** 2
+port4_trans = abs(port4_coeff) ** 2
# Calculates the Insertion loss as a percent and in dB
insertionLoss = 1-(port2_trans + port3_trans + port4_trans)
@@ -648,14 +567,14 @@ Step 2: Run simulation for a single source# Prints the Transmittance
print("\n-----------------------------------------------------------------\n")
-print("Transmittance/Reflectance: Port1: {:.6f}% Port2: {:.6f}%, Port3: {:.6f}%, Port4: {:.6f}%".format(port1_trans*100, port2_trans*100, port3_trans*100, port4_trans*100))
-print("Insertion Loss: {:.6f}% -> {:.6f}db".format(insertionLoss*100, insertionLoss_dB))
+print(f"Transmittance/Reflectance: Port1: {port1_trans*100:.4f}% Port2: {port2_trans*100:.4f}%, Port3: {port3_trans*100:.4f}%, Port4: {port4_trans*100:.4f}%")
+print(f"Insertion Loss: {insertionLoss*100:.4f}% = {insertionLoss_dB:.4f}db")
print("\n-----------------------------------------------------------------\n")
We find that this component is actually terrible and would never be used in an actual photonic design. Almost a third of the light is lost, and the light that isn’t lost is not split in any specific ratio. Fortunately, it was never meant to be used, and just exists as an example of the basic shape of an mmi.
+We find that this component is actually terrible and would never be used in an actual photonic design. Over a third of the light is lost, and the light that isn’t lost is not split in any specific ratio. Fortunately, it was never meant to be used, and just exists as an example of the basic shape of an mmi.
Finally, before we move on to the next step, we’ll run the simulation again and create a plot of the steady state of the mmi.
Now, all that’s left to do is to run the simulation for each source. Here, I’ll use a for loop to run the other three simulations. We could have done this for all four, but hopefully this makes the code make more sense.
For the sources going into port 3 and 4, we have to specify that the light will be propagating backwards. Below, I’ve done this by setting the direction to mp.NO_DIRECTION and using the eig_kpoint parameter to specify the direction. You can use this same method to launch sources in any direction.
It should be noted, that since the 2x2 mmi we are using is symmetrical across both the x and y axies, the S-parameters should be the same for all of the other ports. But for the sake of demonstration, we’ll simulate all of them. Then at then end we can check to see the the S-parameters are actually the same.
@@ -717,37 +633,42 @@# Set up the rest of the sources for the simulation.
sources = [
- mp.EigenModeSource(
+ mp.EigenModeSource(
+ src = mp.GaussianSource(fcen, fwidth=df),
+ size=port1.size, # Here we input the geometry for our first source
+ center=port1.center + mp.Vector3(-0.5,0,0),
+ eig_band=1,
+ eig_parity = mp.NO_PARITY if sim_is_3D else mp.EVEN_Y + mp.ODD_Z,
+ eig_match_freq = True,
+ ),
+ mp.EigenModeSource(
src = mp.GaussianSource(fcen, fwidth=df),
size=port2.size, # Here we input the geometry for our first source
- center=port2.center,
+ center=port2.center + mp.Vector3(-0.5,0,0),
eig_band=1,
eig_parity = mp.NO_PARITY if sim_is_3D else mp.EVEN_Y + mp.ODD_Z,
eig_match_freq = True,
-
- ),
- mp.EigenModeSource(
+ ),
+ mp.EigenModeSource(
src = mp.GaussianSource(fcen, fwidth=df),
size=port3.size, # Here we input the geometry for our first source
- center=port3.center,
+ center=port3.center + mp.Vector3(0.5,0,0),
eig_band=1,
eig_parity = mp.NO_PARITY if sim_is_3D else mp.EVEN_Y + mp.ODD_Z,
eig_match_freq = True,
eig_kpoint = mp.Vector3(-1,0,0),
direction = mp.NO_DIRECTION
-
- ),
- mp.EigenModeSource(
+ ),
+ mp.EigenModeSource(
src = mp.GaussianSource(fcen, fwidth=df),
size=port4.size, # Here we input the geometry for our first source
- center=port4.center,
+ center=port4.center + mp.Vector3(0.5,0,0),
eig_band=1,
eig_parity = mp.NO_PARITY if sim_is_3D else mp.EVEN_Y + mp.ODD_Z,
eig_match_freq = True,
eig_kpoint = mp.Vector3(-1,0,0),
direction = mp.NO_DIRECTION
-
- )
+ )
]
for i in range(n_ports-1) :
+for i in range(n_ports) :
- source = sources[i:i+1]
+ source = sources[i]
sim.reset_meep() # resets everything
# Create Simulation
sim = mp.Simulation(
resolution=res, # The resolution, defined further up
- cell_size=cell.size, # The cell size, taken from the gds
+ cell_size=cell, # The cell size, taken from the gds
boundary_layers=[mp.PML(dpml)], # the perfectly matched layers, with a diameter as defined above
- sources = source, # The source(s) we just defined
+ sources = [source], # The source(s) we just defined
geometry = geometry # The geometry, from above
)
# Adds mode monitors at each of the ports to track the energy that goes in or out
- mode_monitors = []
- mode_monitors.append(sim.add_mode_monitor(fcen, 0,1, mp.ModeRegion(volume=port1)))
- mode_monitors.append(sim.add_mode_monitor(fcen, 0,1, mp.ModeRegion(volume=port2)))
- mode_monitors.append(sim.add_mode_monitor(fcen, 0,1, mp.ModeRegion(volume=port3)))
- mode_monitors.append(sim.add_mode_monitor(fcen, 0,1, mp.ModeRegion(volume=port4)))
+ mode_monitor_1 = sim.add_mode_monitor(fcen, 0,1, mp.ModeRegion(volume=port1))
+ mode_monitor_2 = sim.add_mode_monitor(fcen, 0,1, mp.ModeRegion(volume=port2))
+ mode_monitor_3 = sim.add_mode_monitor(fcen, 0,1, mp.ModeRegion(volume=port3))
+ mode_monitor_4 = sim.add_mode_monitor(fcen, 0,1, mp.ModeRegion(volume=port4))
# Runs the simulation
- sim.run(until_after_sources=100)
+ sim.run(until_after_sources=mp.stop_when_dft_decayed)
#############################################################
# Finds the S parameters
- port1_coeff = sim.get_eigenmode_coefficients(mode_monitors[0], [1], eig_parity=mp.NO_PARITY if sim_is_3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][0]]
- port2_coeff = sim.get_eigenmode_coefficients(mode_monitors[1], [1], eig_parity=mp.NO_PARITY if sim_is_3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][1]]
- port3_coeff = sim.get_eigenmode_coefficients(mode_monitors[2], [1], eig_parity=mp.NO_PARITY if sim_is_3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][2]]
- port4_coeff = sim.get_eigenmode_coefficients(mode_monitors[3], [1], eig_parity=mp.NO_PARITY if sim_is_3D else mp.EVEN_Y + mp.ODD_Z).alpha[0, 0, alphas[i+1][3]]
- input_coeff = sim.get_eigenmode_coefficients(mode_monitors[i+1], [1], eig_parity=mp.NO_PARITY if sim_is_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
+ mode_monitors = [mode_monitor_1, mode_monitor_2, mode_monitor_3, mode_monitor_4]
+ norm_mode = sim.get_eigenmode_coefficients(mode_monitors[i], [1], eig_parity=mode_parity)
+ norm_mode_coeff = norm_mode.alpha[0,0,0] if i < 2 else norm_mode.alpha[0,0,1]
+ port1_coeff = sim.get_eigenmode_coefficients(mode_monitor_1, [1], eig_parity=mode_parity).alpha[0, 0, 1] / norm_mode_coeff
+ port2_coeff = sim.get_eigenmode_coefficients(mode_monitor_2, [1], eig_parity=mode_parity).alpha[0, 0, 1] / norm_mode_coeff
+ port3_coeff = sim.get_eigenmode_coefficients(mode_monitor_3, [1], eig_parity=mode_parity).alpha[0, 0, 0] / norm_mode_coeff
+ port4_coeff = sim.get_eigenmode_coefficients(mode_monitor_4, [1], eig_parity=mode_parity).alpha[0, 0, 0] / norm_mode_coeff # This is the total amount of light that entered the devie
# Store the S parameters in s_params
- index = 1+i
+ index = i
s_params[index] = [port1_coeff, port2_coeff, port3_coeff, port4_coeff]
- input_params[index] = input_coeff
print("S-Params:")
for i in range(n_ports):
- 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]}")
-
-print("Input S-Params")
-print(f"S1: {input_params[0]}\tS2: {input_params[1]}\tS3: {input_params[2]}\tS4: {input_params[3]}")
-
-
+ print(f"S{i+1}1: {s_params[i][0]:.4f}\tS{i+1}2: {s_params[i][1]:.4f}\tS{i+1}3: {s_params[i][2]:.4f}\tS{i+1}4: {s_params[i][3]:.4f}")
print("Transmission:")
for i in range(n_ports):
- input_power = abs(input_params[i])**2
- trans1 = abs(s_params[i][0])**2 / input_power * 100
- trans2 = abs(s_params[i][1])**2 / input_power * 100
- trans3 = abs(s_params[i][2])**2 / input_power * 100
- trans4 = abs(s_params[i][3])**2 / input_power * 100
- print("{:.6f}\t{:.6f}\t{:.6f}\t{:.6f}".format(trans1, trans2, trans3, trans4))
+ trans1 = abs(s_params[i][0])**2 * 100
+ trans2 = abs(s_params[i][1])**2 * 100
+ trans3 = abs(s_params[i][2])**2 * 100
+ trans4 = abs(s_params[i][3])**2 * 100
+ print(f"{trans1:.6} %\t{trans2:.6} %\t{trans3:.6} %\t{trans4:.6} %")
For most applications, you’ll want to know the S-parameters across a range of frequencies. This can be done using the simulations created here. When we get the S-parameters using the sim.get_eigenmode_coefficients().alpha[] we get a matrix. The first entry in the matrix specifies the wavelength. For brevities sake, we won’t show that here, but a good exercise would be to find and plot the s-paramters across a range of frequencies for the component shown here.
+For most applications, you’ll want to know the S-parameters across a range of frequencies. This can be done using the simulations created here. When we get the S-parameters using the sim.get_eigenmode_coefficients().alpha[] we get a matrix. The first entry in the matrix specifies the wavelength. For brevity’s sake, we won’t show that here, but a good exercise would be to find and plot the s-paramters across a range of frequencies for the component shown here.
+Multiple frequencies can be simulated at once by setting the second and third arguments in the mode monitors to the desired frequency width and number of points, e.g.
+sim.add_mode_monitor(fcen, df, n_freq_points, mp.ModeRegion(volume=port))
+
gplugins.gmeep.write_sparameters_meep
#An alternative method to the one outlined above is using the gplugins package. The write_sparameters_meep
function can automate the entire process that we outlined above, but it is less customizable in exchange for its ease of use. This is how we could use it to find the s-parameters for the 2x2 mmi.
NOTE: Currently bugged, will be fixed soon.
+from gplugins.gmeep import write_sparameters_meep
+
+port_xpos = 17.75
+port_ypos = (0.75 + 0.5) / 2
+
+mmi_comp = import_gds(gds_file)
+mmi_comp.add_port(name="o1", center=[-port_xpos, -port_ypos], width=port_ysize, orientation=0, cross_section=gf.cross_section.cross_section(width=port_ysize, layer='WG'))
+mmi_comp.add_port(name="o2", center=[-port_xpos, port_ypos], width=port_ysize, orientation=0, cross_section=gf.cross_section.cross_section(width=port_ysize, layer='WG'))
+mmi_comp.add_port(name="o3", center=[port_xpos, -port_ypos], width=port_ysize, orientation=180, cross_section=gf.cross_section.cross_section(width=port_ysize, layer='WG'))
+mmi_comp.add_port(name="o4", center=[port_xpos, port_ypos], width=port_ysize, orientation=180, cross_section=gf.cross_section.cross_section(width=port_ysize, layer='WG'))
+
+sparams = write_sparameters_meep(
+ component=mmi_comp,
+ port_margin=2,
+ port_source_offset=0.5,
+ run=False,
+ xmargin=2,
+ ymargin=2,
+ zmargin=2 if sim_is_3D else 0,
+ is_3d=sim_is_3D,
+ tpml=1,
+ clad_material="SiO2",
+ wavelength_start=1.5,
+ wavelength_stop=1.6,
+ wavelength_points=100
+)
+
gplugins.gmeep.write_sparameters_meep