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

update gdsfactory and fix import cells #120

Merged
merged 3 commits into from
Nov 21, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .github/workflows/test_code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: Install dependencies
run: |
pip install -e .
pip install flake8 pytest
pip install -r requirements_dev.txt
- name: Lint with flake8
run: |
flake8 .
Expand Down
36 changes: 0 additions & 36 deletions .github/workflows/test_code_updated_requirements.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/test_codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- name: Test with pytest
run: |
pip install pytest
pip install pytest-cov
pip install pytest-cov pytest-regressions
pytest --cov=ubcpdk --cov-report=xml
pytest --cov=ubcpdk --cov-report=xml --cov-config=.coveragerc ubcpdk
- name: Upload coverage to Codecov
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 1.10.0

- update to gdsfactory 6.2.1

## [1.9.0](https://github.com/gdsfactory/ubc/pull/116)

- update to gdsfactory 6.0.3
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
lygadgets
flayout
gdsfactory[full,tidy3d]==6.1.0
gdsfactory[full,tidy3d]==6.2.1
modes==1.0.6
24 changes: 24 additions & 0 deletions requirements_dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
autodoc_pydantic
autotyping
doc8
docutils==0.17.1
flake8
flake8-bugbear
ipykernel
mypy
myst-parser
nbsphinx
pre-commit
pur
pydocstyle
pytest
pytest-cov
pytest-regressions
sphinx-autodoc-typehints
sphinx-book-theme==0.3.3
sphinx-click
sphinx-copybutton
sphinx-markdown-tables==0.0.16
types-PyYAML
types-waitress
xdoctest
183 changes: 160 additions & 23 deletions ubcpdk/klayout/tech/pymacros/klayout_Library.lym
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,172 @@
<interpreter>python</interpreter>
<dsl-interpreter-name/>
<text>
from typing import Callable
import pya
import sys
import pathlib
import os
from inspect import Parameter, signature, Signature
import json
import numpy as np

try:
import flayout as fl
from ubcpdk import cells
except ImportError:
import pya
pya.MessageBox.info('ubcpdk message',
('ubcpdk has not been installed. So ubcpdk pcells will not be available.\n' +
'To use these, go into terminal/command line anywhere and type\n\n' +
'pip install ubcpdk'),
pya.MessageBox.Ok)


pcells = []
for name, cell in cells.items():
# Would be nice to add SiEPIC pins to all of these
config_file = os.path.expanduser(pathlib.Path('~/.gdsfactory/gf-config.json'))

cfg = {}
with open(config_file, 'a+') as j:
j.seek(0)
try:
pcells.append(fl.pcell(cell, on_error="ignore"))
cfg = json.loads(j.read())
except:
# Currently, pcells defined with partial don't work due to a missing __name__ attribute
pass
cfg = {}

if "conda-env" not in cfg.keys():
env_dir_str = pya.FileDialog.ask_existing_dir("Select directory of Python environment to link:", "")

if env_dir_str is None:
quit()

cfg["conda-env"] = env_dir_str

json.dump(cfg, j, sort_keys=True, indent=4)
j.close()

env_dir = pathlib.Path(cfg["conda-env"])

if env_dir is None:
quit()

sys.path.append(str(pathlib.Path(f'{env_dir}/site-packages/')))

try:
import flayout as fl
from flayout.pcell import _klayout_type, _validate_parameter, _validate_on_error, copy_tree
import ubcpdk
import ubcpdk.components as gfc
import gdsfactory as gf
except Exception as e:
pya.MessageBox.info('import error', str(e), pya.MessageBox.Ok)

# Create layout for the library
layout = pya.Layout()
for layer in gf.LAYER:
layout.layer(*layer[1])

# PCell class that creates the PCell
class PCellFactory(pya.PCellDeclarationHelper):
def __init__(self, component) -> None:
"""Create a PCell from a gdsfactory component."""
super().__init__()
self.component = component
self.sig = self._extract_sig(self.component) or {}
self.func_name = self.gdsfactory_to_klayout().name
params = self._pcell_parameters(self.sig, on_error="raise")
self._param_keys = list(params.keys())
self._param_values = []
for name, param in params.items():
# Add the parameter to the PCell
self._param_values.append(
self.param(
name=name,
value_type=_klayout_type(param),
description=name.replace("_", " "),
default=param.default,
)
)

def produce_impl(self):
"""Produce the PCell."""
params = dict(zip(self._param_keys, self._param_values))
cell = self.gdsfactory_to_klayout(**params)

# Add the cell to the layout
copy_tree(cell, self.cell, on_same_name="replace")
self.cell.name = self.func_name

# Cell
generic_lib = fl.library(
"ubcpdk",
pcells=pcells,
def _pcell_parameters(self, sig: Signature, on_error="ignore"):
"""Get the parameters of a function."""
# NOTE: There could be a better way to do this, than use __signature__.
new_params = {}

if len(sig.parameters) == 0:
return new_params

new_params = {'name': Parameter('name', kind=Parameter.KEYWORD_ONLY, default=self.func_name, annotation=str)}
params = sig.parameters
on_error = _validate_on_error(on_error)
for name, param in params.items():
try:
new_params[name] = _validate_parameter(name, param)
except ValueError:
if on_error == "raise":
raise
return new_params

def _extract_sig(self, component):
"""Extract the signature of a function."""
sig = signature(component[1])
ignore_params = []
params = sig.parameters

for name, param in params.items():
try:
_validate_parameter(name, param)
except:
# Ignore parameters that are not accepted by KLayout
ignore_params.append(name)

ignore_params.append('cross_section')

sig_new = Signature(
[param for name, param in params.items() if name not in ignore_params]
) or {}
return sig_new

def gdsfactory_to_klayout(self, **kwargs):
gf.clear_cache() # Clear cache to be able to reload components without changing the name

# Get the component
c = self.component[1](**kwargs)
c.name = self.component[0]

# Get the cell
top = layout.create_cell(c.name)
polygons = c.get_polygons(True)
for layer, polygons in polygons.items():
layer_idx = layout.layer(*layer)

# Add pya.Polygon for every gdsfactory Polygon
for polygon in polygons:
polygon = np.array(polygon)
polygon = polygon * 1000
points_pya = [pya.Point(*p) for p in polygon]
top.shapes(layer_idx).insert(pya.Polygon(points_pya))

top.name = c.name
top.__doc__ = self.component[1].__doc__.split('\n\n')[0] # Cell description is the first line of the docstring
return top

ubcpdk_lib = fl.library(
"ubcpdk PDK",
pcells=[],
cells=[],
description="UBCPDK PCell Library",
description="GDSFactory ubcpdk PCell Library",
)
# Would be nice to add SiEPIC pins to all of these
pb = pya.AbsoluteProgress("Importing ubcpdk components", len(ubcpdk.cells.keys()))
for i, cell in enumerate(ubcpdk.cells.items()):

pb.set(i / len(ubcpdk.cells.items()) * 100, True)

try:
# Cell function signature, used by flayout

func = PCellFactory(cell) # Cell function
ubcpdk_lib.layout().register_pcell(cell[0], func) # Register the PCell

except Exception as e:
pass # Ignore components that cannot be converted to PCells
pb.set(100, True)

</text>
</klayout-macro>