Simulations with PICwriter

The 3-dimensional geometry of all PICwriter components (a scalar dielectric function) can be exported to an HDF5 file format for simulation using various open-source and commercial electromagnetic simulation software. Convenient functions are also provided for automatically computing the transmission/reflection spectra of PICwriter components with arbitrary numbers of ports (specified by their portlist) using freely available finite-difference time-domain (FDTD) software (MEEP).

In order to specify the vertical profile in the vertical (out-of-plane) direction, the user must first specify a `MaterialStack` object that is responsible for mapping each mask layer/datatype to a vertical stack of materials.

Defining 3D geometries using PICwriter

The mapping of GDSII layers/datatypes to vertical dielectric profiles is done by creating a MaterialStack object and adding VStacks for each layer/datatype to be considered. An example of creating a MaterialStack is given below:

import picwriter.picsim as ps

epsSiO2 = 1.444**2
epsSi = 3.55**2
etch_stack = [(epsSiO2, 1.89), (epsSi, 0.07), (epsSiO2, 2.04)]
mstack = ps.MaterialStack(vsize=4.0, default_stack=etch_stack, name="Si waveguide")
waveguide_stack = [(epsSiO2, 1.89), (epsSi, 0.22), (epsSiO2, 1.89)]
clad_stack = [(epsSiO2, 1.89), (epsSi, 0.05), (epsSiO2, 2.06)]
mstack.addVStack(layer=1, datatype=0, stack=waveguide_stack)
mstack.addVStack(layer=2, datatype=0, stack=clad_stack)

First, we import the picsim library Next, we specified the dielectric constant for the two materials considered (silicon and silicon dioxide at a wavelength of 1550 nm). Then, we create a VStack list (etch_stack), that is in the format [(dielectric1, thickness1), (dielectric2, thickness2), …]. Withthis we can create the MaterialStack object, with etch_stack the default vertical stack in the domain. Next, we create a waveguide_stack VStack list and associate it with the (1,0) GDSII layer using the addVStack call.

Quickly computing mode profiles

With a properly defined material stack, PICsim makes it easy to quickly view the mode profile corresponding to your layout’s WaveguideTemplate with the compute_mode() function:

import picwriter.components as pc

wgt = pc.WaveguideTemplate(bend_radius=15, wg_width=0.5, clad_width=3.0,
                           wg_layer=1, wg_datatype=0, clad_layer=2, clad_datatype=0)

ps.compute_mode(wgt, mstack, res=128, wavelength=1.55, sx=3.0, sy=3.0,
                plot_mode_number=1, polarization="TE")

Which produces plots of the corresponding electric fields:

_images/mode_Efields.png

and magnetic fields:

_images/mode_Hfields.png

Computing the transmission/reflection spectra

Likewise, we can build a PICwriter component in the normal way and directly launch a MEEP simulation. Below we build a DirectionalCoupler object and give it 2 um of waveguide at all the inputs/outputs (this will be useful when we simulate with MEEP later):

import picwriter.toolkit as tk
from picwriter.components import *
import numpy as np
import gdspy

top = gdspy.Cell("top")
wgt = WaveguideTemplate(bend_radius=15, wg_width=0.5, clad_width=3.0,
                        wg_layer=1, wg_datatype=0, clad_layer=2, clad_datatype=0)

simulated_component = gdspy.Cell('sc')

dc = DirectionalCoupler(wgt, 3.5, 0.2, angle=np.pi/16.0,
                                            parity=1, direction='EAST', port=(0,0))
tk.add(simulated_component, dc)

x0,y0 = dc.portlist['input_top']['port']
x1,y1 = dc.portlist['input_bot']['port']
x2,y2 = dc.portlist['output_top']['port']
x3,y3 = dc.portlist['output_bot']['port']

PML_wg1 = Waveguide([(x0,y0), (x0-2,y0)], wgt)
PML_wg2 = Waveguide([(x1,y1), (x1-2,y1)], wgt)
PML_wg3 = Waveguide([(x2,y2), (x2+2,y2)], wgt)
PML_wg4 = Waveguide([(x3,y3), (x3+2,y3)], wgt)

tk.add(simulated_component, PML_wg1)
tk.add(simulated_component, PML_wg2)
tk.add(simulated_component, PML_wg3)
tk.add(simulated_component, PML_wg4)

The gdspy Cell object simulated_component now contains four short waveguides and a DirectionalCoupler object. In order to launch a MEEP simulation and compute transmission/reflection spectra, we need to tell PICwriter what ports we want to monitor the flux through:

ports = [dc.portlist['input_top'],
         dc.portlist['input_bot'],
         dc.portlist['output_top'],
         dc.portlist['output_bot']]

The first port specified in the list above will be the inport where MEEP will place an EigenmodeSource. The last step is calling compute_transmission_spectra with the simulated component, MaterialStack, ports, and some additional information about the simulation:

ps.compute_transmission_spectra(simulated_component, mstack, wgt, ports, port_vcenter=0,
                            port_height=1.5*0.22, port_width=1.5*wgt.wg_width, dpml=0.5,
                            res=20, wl_center=1.55, wl_span=0.6, fields=True,
                            norm=True, parallel=True, n_p=4)

In the above port_vcenter specifies the center of the port in the vertical direction, port_height and port_width are the cross-sectional size of the power flux planes, res is the resolution (in pixels/um), wl_center and wl_span specify the center wavelength and wavelength span of the input pulse (in um), fields = True tells MEEP to output images of the electric field profile every few timesteps, norm = True tells MEEP to first perform a normalization calculation (straight waveguide) using the wgt WaveguideTemplate parameters. parallel specifies if the simulation should be run using multiple processor cores (requires MEEP/MPB to be built using parallel libaries), and n_p then specifies the number of cores to run on.

NOTE: This function requires MEEP and MPB to be compiled (from source) together, so that MEEP can call MPB to input an EigenmodeSource at the first port location.

The resulting structure that is simulated and several field images are shown below:

_images/topview-mcts.png _images/mcts-ez-topview.t124.png _images/mcts-ez-topview.t147.png _images/mcts-ez-topview.t178.png

The compute_transmission_spectra() function will also compute and plot the appropriately normalized transmission/reflection spectra, saving the .png image in the working directory. The raw power flux data is also saved in .out and .dat files in the working directory.

_images/meep-sim-res20-dc.png

PICsim Documentation

Set of useful functions for converting PICwriter objects from polygons to hdf5 epsilon files that can be easily imported to MEEP or MPB for quick simulations. Functions for launching siulations using MEEP/MPB are also included.

class picwriter.picsim.MaterialStack(vsize, default_stack, name=u'mstack')

Standard template for generating a material stack

Args:
  • vsize (float): Vertical size of the material stack in microns (um)
  • default_layer (list): Default VStack with the following format: [(eps1, t1), (eps2, t2), (eps3, t3), …] where eps1, eps2, .. are the permittivity (float), and t1, t2, .. are the thicknesses (float) from bottom to top. Note: t1+t2+… must add up to vsize.
Members:
  • stacklist (dictionary): Each entry of the stacklist dictionary contains a VStack list.
Keyword Args:
  • name (string): Identifier (optional) for the material stack
addVStack(layer, datatype, stack)

Adds a vertical layer to the material stack LIST

Args:
  • layer (int): Layer of the VStack
  • datatype (int): Datatype of the VStack
  • stack (list): Vstack list with the following format: [(eps1, t1), (eps2, t2), (eps3, t3), …] where eps1, eps2, .. are the permittivity (float), and t1, t2, .. are the thicknesses (float) from bottom to top. Note: if t1+t2+… must add up to vsize.
default_stack = None

self.stack below contains a DICT of all the VStack lists

get_eps(key, height)

Returns the dielectric constant (epsilon) corresponding to the height and VStack specified by key, where the height range is zero centered (-vsize/2.0, +vsize/2.0).

Args:
  • key (layer,datatype): Key value of the VStack being used
  • height (float): Vertical position of the desired epsilon value (must be between -vsize/2.0, vsize/2.0)
picwriter.picsim.compute_mode(wgt, mstack, res, wavelength, sx, sy, plot_mode_number=1, polarization=u'TE', output_directory=u'mpb-sim', save_mode_data=True, suppress_window=False)

Launches a MPB simulation to quickly compute and visualize a waveguide’s electromagnetic eigenmodes

Args:
  • wgt (WaveguideTemplate): WaveguideTemplate object used to specify the waveguide geometry (mask-level)
  • mstack (MaterialStack): MaterialStack object that maps the gds layers to a physical stack
  • res (int): Resolution of the MPB simulation (number of pixels per micron).
  • wavelength (float): Wavelength in microns.
  • sx (float): Size of the simulation region in the x-direction.
  • sy (float): Size of the simulation region in the y-direction.
  • plot_mode_number (int): Which mode to plot (only plots one mode at a time). Must be a number equal to or less than num_modes. Defaults to 1.
  • polarization (string): Mode polarization. Must be either “TE”, “TM”, or “None” (corresponding to MPB parities of ODD-X, EVEN-X, or NO-PARITY).
  • output_directory (string): Output directory for files generated. Defaults to ‘mpb-sim’.
  • save_mode_data (Boolean): Save the mode image and data to a separate file. Defaults to True.
  • suppress_window (Boolean): Suppress the matplotlib window. Defaults to false.
Returns:
List of values for the modes: [[\(n_{eff,1}, n_{g,1}\)], [\(n_{eff,2}, n_{g,2}\)], …]
picwriter.picsim.compute_transmission_spectra(pic_component, mstack, wgt, ports, port_vcenter, port_height, port_width, res, wl_center, wl_span, boolean_operations=None, norm=False, input_pol=u'TE', nfreq=100, dpml=0.5, fields=False, plot_window=False, source_offset=0.1, symmetry=None, skip_sim=False, output_directory=u'meep-sim', parallel=False, n_p=2)

Launches a MEEP simulation to compute the transmission/reflection spectra from each of the component’s ports when light enters at the input port.

How this function maps the GDSII layers to the material stack is something that will be improved in the future. Currently works well for 1 or 2 layer devices. Currently only supports components with port-directions that are `EAST` (0) or `WEST` (pi)

Args:
  • pic_component (gdspy.Cell): Cell object (component of the PICwriter library)
  • mstack (MaterialStack): MaterialStack object that maps the gds layers to a physical stack
  • wgt (WaveguideTemplate): Waveguide template
  • ports (list of Port dicts): These are the ports to track the Poynting flux through. IMPORTANT The first element of this list is where the Eigenmode source will be input.
  • port_vcenter (float): Vertical center of the waveguide
  • port_height (float): Height of the port cross-section (flux plane)
  • port_width (float): Width of the port cross-section (flux plane)
  • res (int): Resolution of the MEEP simulation
  • wl_center (float): Center wavelength (in microns)
  • wl_span (float): Wavelength span (determines the pulse width)
Keyword Args:
  • boolean_operations (list): A list of specified boolean operations to be performed on the layers (ORDER MATTERS). In the following format:
    [((layer1/datatype1), (layer2/datatype2), operation), …] where ‘operation’ can be ‘xor’, ‘or’, ‘and’, or ‘not’ and the resulting polygons are placed on (layer1, datatype1). See below for example.
  • norm (boolean): If True, first computes a normalization run (transmission through a straight waveguide defined by wgt above. Defaults to False. If True, a WaveguideTemplate must be specified.
  • input_pol (String): Input polarization of the waveguide mode. Must be either “TE” or “TM”. Defaults to “TE” (z-antisymmetric).
  • nfreq (int): Number of frequencies (wavelengths) to compute the spectrum over. Defaults to 100.
  • dpml (float): Length (in microns) of the perfectly-matched layer (PML) at simulation boundaries. Defaults to 0.5 um.
  • fields (boolean): If true, outputs the epsilon and cross-sectional fields. Defaults to false.
  • plot_window (boolean): If true, outputs the spectrum plot in a matplotlib window (in addition to saving). Defaults to False.
  • source_offset (float): Offset (in x-direction) between reflection monitor and source. Defaults to 0.1 um.
  • skip_sim (boolean): Defaults to False. If True, skips the simulation (and hdf5 export). Useful if you forgot to perform a normalization and don’t want to redo the whole MEEP simulation.
  • output_directory (string): Output directory for files generated. Defaults to ‘meep-sim’.
  • parallel (boolean): If True, will run simulation on np cores (np must be specified below, and MEEP/MPB must be built from source with parallel-libraries). Defaults to False.
  • n_p (int): Number of processors to run meep simulation on. Defaults to 2.
Example of boolean_operations (using the default):
The following default boolean_operation will:
  1. do an ‘xor’ of the default layerset (-1,-1) with a cladding (2,0) and then make this the new default layerset
  2. do an ‘xor’ of the cladding (2,0) and waveguide (1,0) and make this the new cladding

boolean_operations = [((-1,-1), (2,0), ‘and’), ((2,0), (1,0), ‘xor’)]

picwriter.picsim.export_component_to_hdf5(filename, component, mstack, boolean_operations)

Outputs the polygons corresponding to the desired component and MaterialStack. Format is compatible for generating prism geometries in MEEP/MPB.

Note: that the top-down view of the device is the ‘X-Z’ plane. The ‘Y’ direction specifies the vertical height.

Args:
  • filename (string): Filename to save (must end with ‘.h5’)
  • component (gdspy.Cell): Cell object (component of the PICwriter library)
  • mstack (MaterialStack): MaterialStack object that maps the gds layers to a physical stack
  • boolean_operations (list): A list of specified boolean operations to be performed on the layers (order matters, see below).

The boolean_operations argument must be specified in the following format:

boolean_opeartions = [((layer1/datatype1), (layer2/datatype2), operation), ...]

where ‘operation’ can be ‘xor’, ‘or’, ‘and’, or ‘not’ and the resulting polygons are placed on (layer1, datatype1). For example, the boolean_operation below:

boolean_operations = [((-1,-1), (2,0), 'and'), ((2,0), (1,0), 'xor')]

will:

  1. do an ‘xor’ of the default layerset (-1,-1) with the cladding (2,0) and then make this the new default
  2. do an ‘xor’ of the cladding (2,0) and waveguide (1,0) and make this the new cladding
Write format:
  • LL = layer
  • DD = datatype
  • NN = polygon index
  • VV = vertex index
  • XX = x-position
  • ZZ = z-position
  • height = height of the prism
  • eps = epsilon of the prism
  • y-center = center (y-direction) of the prism [note: (x,y) center defaults to (0,0)]
picwriter.picsim.export_wgt_to_hdf5(filename, wgt, mstack, sx)

Outputs the polygons corresponding to the desired waveguide template and MaterialStack. Format is compatible for generating prism geometries in MEEP/MPB.

Note: that the top-down view of the device is the ‘X-Z’ plane. The ‘Y’ direction specifies the vertical height.

Args:
  • filename (string): Filename to save (must end with ‘.h5’)
  • wgt (WaveguideTemplate): WaveguideTemplate object from the PICwriter library
  • mstack (MaterialStack): MaterialStack object that maps the gds layers to a physical stack
  • sx (float): Size of the simulation region in the x-direction
Write-format for all blocks:
  • CX = center-x
  • CY = center-y
  • width = width (x-direction) of block
  • height = height (y-direction) of block
  • eps = dielectric constant