Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SiEPIC functional verification #240

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ gdsfactory plugins:
- `ray` for distributed computing and optimization.
- `sax` S-parameter circuit solver.
- `schematic`: for bokeh schematic editor and `path_length_analysis`.
- `SiEPIC`: for Functional Verification: connectivity, components, and Design for Test (DFT)
- `meep` for FDTD.
- `mpb` for MPB mode solver.
- `elmer` for electrostatic (capacitive) simulations.
Expand All @@ -30,7 +31,7 @@ gdsfactory plugins:
You can install most plugins with:

```
pip install "gplugins[devsim,femwell,gmsh,schematic,meow,meshwell,ray,sax,tidy3d]" --upgrade
pip install "gplugins[devsim,femwell,gmsh,schematic,meow,meshwell,ray,sax,tidy3d,SiEPIC]" --upgrade
```

Or install only the plugins you need with for example `pip install gplugins[schematic,femwell,meow,sax,tidy3d]` from the available plugins.
Expand Down
Empty file added gplugins/SiEPIC/__init__.py
Empty file.
33 changes: 33 additions & 0 deletions gplugins/SiEPIC/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Test functional verification of a simple layout """
import os

import gdsfactory as gf
from verification import layout_check

"""
path_GitHub = '/Users/lukasc/Documents/GitHub/'
if os.path.exists(path_GitHub):
path_ubcpdk = os.path.join(path_GitHub, 'gdsfactory_ubcpdk')
if not path_ubcpdk in sys.path:
sys.path.insert(0,path_ubcpdk) # put SiEPIC at the beginning so that it is overrides the system-installed module
import ubcpdk
"""

if __name__ == "__main__":
# c = gf.components.mmi2x2()

file_path = os.path.join(
os.path.dirname(os.path.realpath(__file__)), "tests/mmi2x2.oas"
)
c = gf.import_gds(file_path, read_metadata=True)

# Uses the SiEPIC-EBeam-PDK, and assumes it is located in
# ~/Documents/GitHub/SiEPIC_EBeam_PDK/klayout
techname = "EBeam"
path_module = "~/Documents/GitHub/SiEPIC_EBeam_PDK/klayout"
path_module = os.path.expanduser(path_module)

# klive.show(gdspath)

# Run verification
layout_check(c, techname, path_module, show_klive=True)
Binary file added gplugins/SiEPIC/tests/mmi2x2.oas
Binary file not shown.
62 changes: 62 additions & 0 deletions gplugins/SiEPIC/verification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# SiEPIC - can be loaded from PyPI or in KLayout Application, or loaded from a local folder such as GitHub
import os
import sys

path_GitHub = "/Users/lukasc/Documents/GitHub/"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded path?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Joaquin,
The hardcoded path section is temporary to use the module from GitHub, rather than the pip-installed one. It can be removed.

if os.path.exists(path_GitHub):
path_siepic = os.path.join(path_GitHub, "SiEPIC-Tools/klayout_dot_config/python")
if path_siepic not in sys.path:
sys.path.insert(
0, path_siepic
) # put SiEPIC at the beginning so that it is overrides the system-installed module
import os
from pathlib import Path

import gdsfactory
import pya
import SiEPIC
import SiEPIC.verification
from SiEPIC.utils import get_technology_by_name, klive


def layout_check(
component: gdsfactory.Component,
techname: str,
path_module: str | Path,
show_klive: bool = True,
) -> int:
"""Run a layout check using SiEPIC-Tool's functional verification.

Args:
techname: KLayout technology name,
path_module: location of the KLayout technology, as a Python module
"""
if not os.path.isdir(path_module):
raise ValueError(f"{path_module} does not exist")

# save layout
gdspath = component.write_gds()

# Load KLayout technology
from SiEPIC.utils import load_klayout_technology

load_klayout_technology(techname, path_module)

# load in KLayout database
ly = pya.Layout()
# load SiEPIC technology
ly.TECHNOLOGY = get_technology_by_name(techname)
ly.read(str(gdspath))
if len(ly.top_cells()) != 1:
raise ValueError("Layout can only have one top cell")
topcell = ly.top_cell()

# perform verification
file_lyrdb = str(gdspath) + ".lyrdb"
num_errors = SiEPIC.verification.layout_check(cell=topcell, file_rdb=file_lyrdb)

# show results in KLayout
if show_klive:
klive.show(gdspath, lyrdb_filename=file_lyrdb, technology=techname)

return num_errors
Empty file.
75 changes: 75 additions & 0 deletions gplugins/klayout/pcell/pcell_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""
This is an example PCell written in KLayout's Python API

requires KLayout installed via pip:
pip install klayout


"""


import math

import pya

"""
This sample PCell implements a library called "MyLib" with a single PCell that
draws a circle. It demonstrates the basic implementation techniques for a PCell
and how to use the "guiding shape" feature to implement a handle for the circle
radius.
"""


class Circle(pya.PCellDeclarationHelper):
"""
The PCell declaration for the circle
"""

def __init__(self):
# Important: initialize the super class
super(Circle, self).__init__()

# declare the parameters
self.param("l", self.TypeLayer, "Layer", default=pya.LayerInfo("1/0"))
self.param("s", self.TypeShape, "", default=pya.DPoint(0, 0))
self.param("r", self.TypeDouble, "Radius", default=0.1)
self.param("n", self.TypeInt, "Number of points", default=64)

def display_text_impl(self):
# Provide a descriptive text for the cell
return "Circle(L=" + str(self.l) + ",R=" + ("%.3f" % self.r) + ")"

def produce_impl(self):
# This is the main part of the implementation: create the layout

# compute the circle
da = math.pi * 2 / self.n
pts = [
pya.DPoint(self.r * math.cos(i * da), self.r * math.sin(i * da))
for i in range(0, self.n)
]

# create the shape
self.cell.shapes(self.l_layer).insert(pya.DPolygon(pts))


class MyLib(pya.Library):
"""
The library where we will put the PCell into
"""

def __init__(self):
# Set the description
self.description = "My First Library"

# Create the PCell declarations
self.layout().register_pcell("Circle", Circle())
# That would be the place to put in more PCells ...

# Register us with the name "MyLib".
# If a library with that name already existed, it will be replaced then.
self.register("MyLib")


# Instantiate and register the library
MyLib()
44 changes: 44 additions & 0 deletions gplugins/klayout/pcell/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Load PCell library
import pcell_example

pcell_example.MyLib()

# Using KLayout
import pya

# Create new layout and top cell
ly = pya.Layout()
topcell = ly.create_cell("top")

# Instantiate PCell
cell = ly.create_cell("Circle", "MyLib", {})
if cell:
t = pya.Trans.from_s("r0 0,0")
inst = topcell.insert(pya.CellInstArray(cell.cell_index(), t))
ly.delete_cell(topcell.cell_index())
else:
Exception("Cannot import PCell from KLayout library")

# Export layout
save_options = pya.SaveLayoutOptions()
save_options.write_context_info = False # remove $$$CONTEXT_INFO$$$
ly.write("/tmp/tmp.gds", save_options)

# Using gdsfactory
import gdsfactory as gf

# Load the cell
c = gf.read.import_gds("/tmp/tmp.gds")

# display
# c.plot()

# create example layout
top = gf.Component()
top.name = "Top"
top.add_ref(c).movex(1)
top.add_ref(c).movey(1)
top.plot()

# save
top.write_gds("/tmp/tmp2.gds")
Empty file added pcell/klayout_pcell.py
Empty file.
75 changes: 75 additions & 0 deletions pcell/pcell_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""
This is an example PCell written in KLayout's Python API

requires KLayout installed via pip:
pip install klayout


"""


import math

import pya

"""
This sample PCell implements a library called "MyLib" with a single PCell that
draws a circle. It demonstrates the basic implementation techniques for a PCell
and how to use the "guiding shape" feature to implement a handle for the circle
radius.
"""


class Circle(pya.PCellDeclarationHelper):
"""
The PCell declaration for the circle
"""

def __init__(self):
# Important: initialize the super class
super(Circle, self).__init__()

# declare the parameters
self.param("l", self.TypeLayer, "Layer", default=pya.LayerInfo("1/0"))
self.param("s", self.TypeShape, "", default=pya.DPoint(0, 0))
self.param("r", self.TypeDouble, "Radius", default=0.1)
self.param("n", self.TypeInt, "Number of points", default=64)

def display_text_impl(self):
# Provide a descriptive text for the cell
return "Circle(L=" + str(self.l) + ",R=" + ("%.3f" % self.r) + ")"

def produce_impl(self):
# This is the main part of the implementation: create the layout

# compute the circle
da = math.pi * 2 / self.n
pts = [
pya.DPoint(self.r * math.cos(i * da), self.r * math.sin(i * da))
for i in range(0, self.n)
]

# create the shape
self.cell.shapes(self.l_layer).insert(pya.DPolygon(pts))


class MyLib(pya.Library):
"""
The library where we will put the PCell into
"""

def __init__(self):
# Set the description
self.description = "My First Library"

# Create the PCell declarations
self.layout().register_pcell("Circle", Circle())
# That would be the place to put in more PCells ...

# Register us with the name "MyLib".
# If a library with that name already existed, it will be replaced then.
self.register("MyLib")


# Instantiate and register the library
MyLib()
44 changes: 44 additions & 0 deletions pcell/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Load PCell library
import pcell_example

pcell_example.MyLib()

# Using KLayout
import pya

# Create new layout and top cell
ly = pya.Layout()
topcell = ly.create_cell("top")

# Instantiate PCell
cell = ly.create_cell("Circle", "MyLib", {})
if cell:
t = pya.Trans.from_s("r0 0,0")
inst = topcell.insert(pya.CellInstArray(cell.cell_index(), t))
ly.delete_cell(topcell.cell_index())
else:
Exception("Cannot import PCell from KLayout library")

# Export layout
save_options = pya.SaveLayoutOptions()
save_options.write_context_info = False # remove $$$CONTEXT_INFO$$$
ly.write("/tmp/tmp.gds", save_options)

# Using gdsfactory
import gdsfactory as gf

# Load the cell
c = gf.read.import_gds("/tmp/tmp.gds")

# display
# c.plot()

# create example layout
top = gf.Component()
top.name = "Top"
top.add_ref(c).movex(1)
top.add_ref(c).movey(1)
top.plot()

# save
top.write_gds("/tmp/tmp2.gds")
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ requires-python = ">=3.10"
version = "0.8.5"

[project.optional-dependencies]
SiEPIC = [
"SiEPIC"
]
dagster = ["dagster", "dagit"]
dev = [
"pre-commit",
Expand Down
Loading