Device Geometry
Overview
The DeviceGeometry
class is the instance that will handle the device
physical charachteristics. Currently it handles .gds
files, only. It is capable of extending the 2D GDSII description of the
device into a 3D structure that includes handling slanted walls defined in the LayerStack
.
It is also the piece of code that handles material meshing given a cloud of points.
It is the last step in the simulation setup prior to configuring the solver settings. It relies mainly on a
LayerStack
object, a .gds
file and port detection settings.
Considerations
Following are a few considerations to take into account when configuring the device geometry.
The
SetSettings
is the main method for setting up the device geometry;The
SetAutoPortSettings
is the method for setting up the auto port detection settings;It currently support
.gds
files, only. But future support to.stl
files is in order for a future release;It relies on a single
LayerStack
and its internalMaterialLibrary
to define the properties of the nodes in the simulation region.
Device and Port Buffers
When setting up a DeviceGeometry
instance, the user should care
with the device and port buffer definitions. Consider the following figures:
The Top View displays the Mask Layout defined in the raw .gds
file. The edges touching the GDSII Border
can be detected as ports, for example, the one on the left. A port will consist of two elementes: a monitor and a source.
The Port Monitor is place precisely at the GDSII Border, while the source for Mode Injection is place half way through the
buffers
dimension.
The buffers
property specify how much empty space will be added/padded
around the Mask Layout to avoid direct touching of the layout with the solver boundary conditions.
The Cross Section view, display a cross section of the port, it includes the other two buffers
as Simulation Domain Buffers. To be flexible in terms of mode calculation, each port detection direction, can contain its own buffer
(x
, y
) values.
The Port Buffers are used to extend the port size the regular waveguide dimension, allowing that the calculated modes are zero at the perimeter defined by the
Port Border. If the Port Border will never exceed the Simulation Domain Border.
You can check the complete device geometry example for more details on the Simulation Domain Buffer and the Port Buffer.
Auto Port Detection and Port Numbering
The DeviceGeometry
uses an auxiliary GDS tool to detect ports automatically.
This tool relies on finding two consecutive points that are touching the boundaries of the GDSII file. This detection relies on spifying
the minimum and maximum width of the ports, as well as wich edges to detect (e.g., 'X'
, 'Y'
). Once the ports are detected, they follow
the numbering order provided in the follwoing diagram, plus, there is the addition of the the 'o'
letter to it.
Examples
The following examples will cover some specific settings of the DeviceGeometry
and at the end it aggregates some of the example snipets into a more elaborate setup. That can be used prior instancing a specific EM solver.
For more deatails please check the API documentation.
Initial Setup Without Port detection
By default there is no need to detect ports, for example, when using the VFD Mode Solver.
So in this example we present how to instantiate a DeviceGeometry
and then add a wg.gds
GDSII file to specify the geometry type.
In this example we are padding the simulation in all directions by 1.5 microns, to add some empty space between the
waveguide and the edges of the simulation region. The geometry_type="Fixed"
indicates that the geometry speficiations
is done via a static GDSII file (non-parametric structure). The layer_stack
argument can be define as presented in the
LayerStack examples.
from pyOptiShared.DeviceGeometry import DeviceGeometry
device_geometry = DeviceGeometry()
device_geometry.SetSettings(
layer_stack=layer_stack,
geometry_type="Fixed",
gds_file=r"wg.gds",
buffers={'x':1.5,'y':1.5,'z':1.5}
)
Uniform Grid from the Geometry Bounding Box
Considering the previous waveguide example, we can then extract the bounding box of the device geometry and construct an array of linearly spaced points that we can later identify to which materials they are defined from.
import numpy as np
from pyOptiShared.DeviceGeometry import DeviceGeometry
device_geometry = DeviceGeometry()
device_geometry.SetSettings(
layer_stack=layer_stack,
geometry_type="Fixed",
gds_file=r"wg.gds",
buffers={'x':1.5,'y':1.5,'z':1.5}
)
bbox = dev_geom.GetBoundingBox(zbWithBuffer=True)
(xmin, xmax), (ymin, ymax), (zmin, zmax) = bbox
xx = np.linspace(xmin, xmax, int(nx*kk))
yy = np.linspace(ymin, ymax, int(ny*kk))
zz = np.linspace(zmin, zmax, int(nz*kk))
XX, YY, ZZ = np.meshgrid(xx, yy, zz, indexing='ij')
points = np.asarray([XX.ravel(), YY.ravel(), ZZ.ravel()])
Obtaining a Material Mesh/Permittivity from a Cloud of points
Once the points are determined from device geometry bounding box, we can then retrieve the
material mesh by calling the GetMaterialMesh
method.
This mesh contains an array of material numbers, that can be converted to their rescpective permittivity values at a particular
wavelength using the GetPermittivityMesh
method.
import numpy as np
from pyOptiShared.DeviceGeometry import DeviceGeometry
lamb = 1.55 # um
device_geometry = DeviceGeometry()
device_geometry.SetSettings(
layer_stack=layer_stack,
geometry_type="Fixed",
gds_file=r"wg.gds",
buffers={'x':1.5,'y':1.5,'z':1.5}
)
bbox = dev_geom.GetBoundingBox(zbWithBuffer=True)
(xmin, xmax), (ymin, ymax), (zmin, zmax) = bbox
xx = np.linspace(xmin, xmax, int(nx*kk))
yy = np.linspace(ymin, ymax, int(ny*kk))
zz = np.linspace(zmin, zmax, int(nz*kk))
# Crete the mesh arrays and linearize the points
XX, YY, ZZ = np.meshgrid(xx, yy, zz, indexing='ij')
points = np.asarray([XX.ravel(), YY.ravel(), ZZ.ravel()])
# Get the material and permittivity meshes
material_mesh = dev_geom.GetMaterialMesh(points)
eps = dev_geom.GetPermittivityMesh(material_mesh, lamb)
# Get back a 3D array of the linear points
shape = (xx.shape[0] // kk, kk,
yy.shape[0] // kk, kk,
zz.shape[0] // kk, kk)
eps = eps.reshape(shape)
Defining Auto Port Settings:
Auto port settings are used in auto port detection of ports in GDSII files.
For that we use the SetAutoPortSettings
method.
Since it relies on a particular GDSII file, we have to call it after the SetSettings
method.
There are for arguments:
direction
that can bex
,y
orboth
. It indicates in which of the Top View bounds the ports should be detected.min
andmax
, the determine the minimun/maximun port widths to be detected. This can be either a singlefloat
(used for both x and y), alist[float, float]
(x and y independently).buffer
, that determines how much empty space will be added around the port cross section to properly accomodate mode profiles.It can be a single
float
, that will be used for bothx
andy
ports extending by the same quantity both width and height;It can be a
list[float, float]
that will be used for bothx
andy
ports extending by the width and height independently; orA more complex
list[float, float]
that controls independently width and height for each bounds.
Please, refer to SetAutoPortSettings
for more details on the auto port detection settings.
Following is a more complete example, that will be used to detect ports on all sides, with idendependent width and height buffers.
The GDSII file corresponds to a waveguide crossing (wgcrossing.gds
).
import numpy as np
from pyOptiShared.LayerInfo import LayerStack
from pyOptiShared.Material import ConstMaterial
from pyOptiShared.DeviceGeometry import DeviceGeometry
##########################################
### Material Settings ###
##########################################
myindex1p45 = ConstMaterial(mat_name="myindex1p45", epsReal=1.45**2)
myindex3p5 = ConstMaterial(mat_name="myindex3p5", epsReal=3.5**2)
##########################################
### Layer Stack Settings ###
##########################################
layer_stack = LayerStack()
layer_stack.addLayer(name="L1", number=1, thickness=0.25, zmin=0.0,
material=myindex3p5)
layer_stack.addLayer(name="L2", number=2, thickness=0.25, zmin=0.25,
material=myindex3p5)
layer_stack.setBGandSub(background=myindex1p45, substrate=myindex1p45)
##########################################
### Device Geometry/Port Settings ###
##########################################
device_geometry = DeviceGeometry()
device_geometry.SetSettings(
layer_stack=layer_stack,
geometry_type="Fixed",
gds_file=r"wgcrossing.gds",
buffers={'x':1.5,'y':1.5,'z':1.5}
)
device_geometry.SetAutoPortSettings(
direction="both",
buffer=[[2, 1.5],[1.5, 1.25]], # [[x_width, x_height],[y_width, y_height]]
min=[0.2, 0.21], # [x_min, y_min]
max=[0.5, 0.49], # [x_max, y_max]
)
Visualizing the Geometry Setup
The following example shows a complete setup with visualization of thed evice
geometry using the Show
method.
The GDSII file corresponds to a waveguide crossing (wgcrossing.gds
)
from pyOptiShared.DeviceGeometry import DeviceGeometry
from pyOptiShared.LayerInfo import LayerStack
from pyOptiShared.Material import ConstMaterial
si02_mat = ConstMaterial(mat_name="SiO2", epsReal=1.45**2,color='lightgreen')
si_mat = ConstMaterial(mat_name="Si", epsReal=3.5**2,color='lightblue')
air_mat = ConstMaterial(mat_name="Air", epsReal=1**2,color='lightyellow')
layer_stack = LayerStack()
layer_stack.addLayer(name="L1", number=1, thickness=0.22, zmin=0.0,
material=si_mat, cladding=si02_mat,
sideWallAng=20)
layer_stack.addLayer(name="L2", number=2, thickness=0.22, zmin=0.0,
material=si02_mat, cladding=si02_mat,
sideWallAng=0)
layer_stack.setBGandSub(background=air_mat, substrate=si02_mat)
device_geometry = DeviceGeometry()
device_geometry.SetSettings(
layer_stack=layer_stack,
geometry_type="Fixed",
gds_file='wgcrossing.gds',
buffers={'x':1.5,'y':1.5,'z':1.5}
)
device_geometry.SetAutoPortSettings(
direction="both",
buffer=1.5,
)
device_geometry.Show()
A Complete Device Geometry Setup
This example uses the information provided in the previous examples to construct a
full instantiation and setup of a LayerStack
.
This is example is usefull for simulations using the pyFDTD Solver or
the VFD Mode Solver. It starts by configuring some materials, creating the layer stack
and finaly setting up the DeviceGeometry
. The device
under charachterization is a dielectric waveguide (wg.gds
).
import numpy as np
from pyOptiShared.LayerInfo import LayerStack
from pyOptiShared.Material import ConstMaterial
from pyOptiShared.DeviceGeometry import DeviceGeometry
##########################################
### Material Settings ###
##########################################
myindex1p45 = ConstMaterial(mat_name="myindex1p45", epsReal=1.45**2)
myindex3p5 = ConstMaterial(mat_name="myindex3p5", epsReal=3.5**2)
##########################################
### Layer Stack Settings ###
##########################################
layer_stack = LayerStack()
layer_stack.addLayer(name="L1", number=1, thickness=0.25, zmin=0.0,
material=myindex3p5)
layer_stack.addLayer(name="L2", number=2, thickness=0.25, zmin=0.25,
material=myindex3p5)
layer_stack.setBGandSub(background=myindex1p45, substrate=myindex1p45)
##########################################
### Device Geometry/Port Settings ###
##########################################
device_geometry = DeviceGeometry()
device_geometry.SetSettings(
layer_stack=layer_stack,
geometry_type="Fixed",
gds_file=r"wg.gds",
buffers={'x':1.5,'y':1.5,'z':1.5}
)
device_geometry.SetAutoPortSettings(
direction="x",
buffer=1.0,
min=0.2,
max=0.5,
)
API Documentation
This class handles the geometry of the device under simulation. |