Skip to content

Commit

Permalink
Merge pull request #171 from gdsfactory/pdk-cells
Browse files Browse the repository at this point in the history
Better PDK cells
  • Loading branch information
sebastian-goeldi authored Sep 1, 2023
2 parents 8688ea9 + 345a480 commit 957cbe3
Show file tree
Hide file tree
Showing 59 changed files with 2,792 additions and 2,350 deletions.
1 change: 1 addition & 0 deletions changelog.d/+ab59f6ef.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add PDK capabilities to KCLayout [#171](https://github.com/gdsfactory/kfactory/pull/171)
4 changes: 2 additions & 2 deletions docs/source/gdsfactory.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,5 +169,5 @@ about layer, width and port type matching.
## LayerEnclosure / KCellEnclosure vs CrossSection

kfactory doesn't have the concept of cross sections. since cross sections are limited to have a path as a backbone, kfactory implemented a more generalized form as enclosures.
[LayerEnclosures][kfactory.utils.enclosure.LayerEnclosure] can use regions or even entire layers as a basis to apply excludes and claddings (or anythin that depends on the base form). Additionally, kfactory has the extended
concept of [KCellEnclosure][kfactory.utils.enclosure.KCellEnclosure]. These can apply enclosures to a whole KCell on all layers the KCellEnclosure is aware of. For further info, please head over to the [Tutorial](/kfactory/notebooks/03_Enclosures)
[LayerEnclosures][kfactory.enclosure.LayerEnclosure] can use regions or even entire layers as a basis to apply excludes and claddings (or anythin that depends on the base form). Additionally, kfactory has the extended
concept of [KCellEnclosure][kfactory.enclosure.KCellEnclosure]. These can apply enclosures to a whole KCell on all layers the KCellEnclosure is aware of. For further info, please head over to the [Tutorial](/kfactory/notebooks/03_Enclosures)
2 changes: 1 addition & 1 deletion docs/source/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ As an example we will build a small waveduide and instantiate a circular bend wa
First let's create some layers. We will use the standard library for this.
Create a `layers.py`. The full one can be downloaded here: [`layers.py`](./layers.py).

Additionally we will create a `wkfactory.utils.enclosure.Enclosure`. Enclosures allow to automatically generate claddings with minkosky sums or use a function to apply claddings to a cell or region. This enclosure will add the cladding to the bend we will use later.
Additionally we will create a `kfactory.enclosure.Enclosure`. Enclosures allow to automatically generate claddings with minkosky sums or use a function to apply claddings to a cell or region. This enclosure will add the cladding to the bend we will use later.

```python
import kfactory as kf
Expand Down
2 changes: 1 addition & 1 deletion docs/source/layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ class LAYER(kf.LayerEnum):
SIEXCLUDE = (1, 1)


si_enc = kf.utils.LayerEnclosure([(LAYER.SIEXCLUDE, 2000)])
si_enc = kf.enclosure.LayerEnclosure([(LAYER.SIEXCLUDE, 2000)])
8 changes: 4 additions & 4 deletions docs/source/notebooks/00_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def straight(length=10, width=1, layer=(1, 0)):
# wg3.movey(20).rotate(15)
print(c.name)
c.show() # show in klayout
c.plot()
# c.plot()

# %% [markdown]
# Now we can align everything together using the ports:
Expand All @@ -194,14 +194,14 @@ def straight(length=10, width=1, layer=(1, 0)):

# %%
c.show() # show in klayout
c.plot()
# c.plot()


# %%
c.add_port(name="o1", port=wg1.ports["o1"])
c.add_port(name="o2", port=wg3.ports["o2"])
c.show() # show in klayout
c.plot()
# c.plot()

# %% [markdown]
# As you can see the `red` labels are for the cell ports while
Expand Down Expand Up @@ -236,7 +236,7 @@ def straight(length=10, width=1, layer=(1, 0)):

# %%
c.show() # show in klayout
c.plot()
# c.plot()

# %% [markdown]
# ## Ports
Expand Down
7 changes: 4 additions & 3 deletions docs/source/notebooks/03_Enclosures.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@


class LAYER(kf.LayerEnum):
kcl = kf.constant(kf.kcl)
WG = (1, 0)
SLAB = (2, 0)
NPP = (3, 0)


# %%
enc = kf.utils.LayerEnclosure(
enc = kf.enclosure.LayerEnclosure(
[
(LAYER.SLAB, 2000),
],
Expand All @@ -40,7 +41,7 @@ class LAYER(kf.LayerEnum):
c.plot()

# %%
enc = kf.utils.LayerEnclosure(
enc = kf.enclosure.LayerEnclosure(
[
(LAYER.SLAB, 2000),
(LAYER.NPP, 1000, 2000),
Expand All @@ -59,7 +60,7 @@ def two_bends(
radius: float,
width: float,
layer: kf.LayerEnum,
enclosure: kf.utils.LayerEnclosure | None = None,
enclosure: kf.enclosure.LayerEnclosure | None = None,
) -> kf.KCell:
c = kf.KCell()
b1 = c << kf.cells.euler.bend_euler(radius=radius, width=width, layer=layer)
Expand Down
101 changes: 101 additions & 0 deletions docs/source/notebooks/04_KCL.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# ---
# jupyter:
# jupytext:
# text_representation:
# extension: .py
# format_name: light
# format_version: '1.5'
# jupytext_version: 1.15.0
# kernelspec:
# display_name: Python 3 (ipykernel)
# language: python
# name: python3
# ---

# # KCLayout / PDK: Using multiple KCLayout objects as PDKs or Libraries of KCells and parametric KCell-Functions

# ## Use multiple KCLayout objects as PDKs/Libraries
#
# KCLayouts can act as PDKs. They can be seamlessly instantiated into each other

# +
import kfactory as kf

kcl_default = kf.kcl
# -

# Empty default KCLayout

kcl_default.kcells

# Create a default straight waveguide in the default KCLayout with dbu==0.001 (1nm grid)
s_default = kf.cells.straight.straight(
width=1, length=10, layer=kcl_default.layer(1, 0)
)

# There is now a a KCell in the KCLayout
kcl_default.kcells

# Control the dbu is still 1nm
kcl_default.dbu

# Create a new KCLayout to simulate pdk (could be package with e.g. `from test_pdk import kcl as pdk` or similar)
kcl2 = kf.KCLayout("TEST_PDK")
# Set the dbu to 0.005 (5nm)
kcl2.dbu = 0.005
kcl2.layout.dbu

# Since it's a new KCLayout, it's empty
kcl2

# Create an parametric KCell-Function for straights on the new pdk
sf2 = kf.cells.dbu.Straight(kcl=kcl2)

# The function hasn't been added to the function yes, so it's still empty
sf2.kcl

# Add it to the pdk factories
kcl2.factories.update({"straight": kf.cells.dbu.Straight(kcl2)})

# Make an instance with
s2 = kcl2.factories["straight"](length=10000, width=200, layer=kcl2.layer(1, 0))
s2.settings

# The default kcl's straight uses 1nm grid and is therefore 1000dbu (1um) high and 10000dbu (10um) wide
print(f"{s_default.bbox().height()=}")
print(f"{s_default.dbbox().height()=}")
print(f"{s_default.bbox().width()=}")
print(f"{s_default.dbbox().width()=}")
# The test pdk uses a 5nm grid, so it will be 200dbu (1um) high and 10000dbu (50um) wide
print(f"{s2.bbox().height()=}")
print(f"{s2.dbbox().height()=}")
print(f"{s2.bbox().width()=}")
print(f"{s2.dbbox().width()=}")

# The ports of the default kcl also have different dbu dimensions, but are the same in um
print(f"{s_default.ports=}")
print(f"{s2.ports=}")
# But in um they are the same
print(f"{[port.d for port in s_default.ports]=}")
print(f"{[port.d for port in s2.ports]=}")

# Both can be instantiated into the same KCell
c = kcl_default.kcell()
si_d = c << s_default
si_2 = c << s2

si_2.connect("o1", si_d, "o2")

c


class LAYER2(kf.LayerEnum):
kcl = kf.constant(kcl2)
WG = (1, 0)


kcl2.layers = LAYER2

kcl2.layers

LAYER2
Binary file added docs/source/notebooks/demo.gds
Binary file not shown.
Binary file removed gds/gds_ref/bend_circular.gds
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed gds/gds_ref/bend_euler.gds
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed gds/gds_ref/bend_s.gds
Binary file not shown.
Binary file removed gds/gds_ref/bend_s_euler.gds
Binary file not shown.
Binary file removed gds/gds_ref/straight_W500_L1000_LWG_EWGSTD.gds
Binary file not shown.
Binary file removed gds/gds_ref/taper.gds
Binary file not shown.
Binary file removed gds/gds_ref/waveguide.gds
Binary file not shown.
Binary file removed gds/gds_ref/waveguide_W500_L1000_LWG_EWGSTD.gds
Binary file not shown.
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies = [
"tomli",
"requests",
"typer[all]",
"aenum",
]

[project.optional-dependencies]
Expand All @@ -48,7 +49,10 @@ dev = [
"kfactory[git]",
"towncrier",
"tbump",
"types-reqeusts",
"types-requests",
"types-setuptools",
"types-docutils",
"types-Pygments",
]
docs = [
"kfactory[ipy]",
Expand Down
10 changes: 8 additions & 2 deletions src/kfactory/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@
polygon_from_array,
dpolygon_from_array,
)
from . import cells, placer, routing, utils, port, pdk, technology
from . import cells, placer, routing, port, technology, enclosure, utils
from .conf import config
from .enclosure import LayerEnclosure, KCellEnclosure

from aenum import constant # type: ignore[import]

__version__ = "0.8.4"

Expand All @@ -48,10 +51,13 @@
"utils",
"show",
"config",
"enclosure",
"LayerEnum",
"logger",
"pdk",
"polygon_from_array",
"dpolygon_from_array",
"technology",
"LayerEnclosure",
"KCellEnclosure",
"constant",
]
124 changes: 74 additions & 50 deletions src/kfactory/cells/bezier.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import numpy.typing as nty
from scipy.special import binom # type: ignore[import]

from .. import KCell, LayerEnum, cell, kdb
from ..utils import LayerEnclosure
from .. import KCell, KCLayout, LayerEnum, cell, kcl, kdb
from ..enclosure import LayerEnclosure

__all__ = ["bend_s"]

Expand All @@ -28,17 +28,7 @@ def bezier_curve(
return [kdb.DPoint(float(x), float(y)) for x, y in zip(xs, ys)]


@cell
def bend_s(
width: float,
height: float,
length: float,
layer: int | LayerEnum,
nb_points: int = 99,
t_start: float = 0,
t_stop: float = 1,
enclosure: LayerEnclosure | None = None,
) -> KCell:
class BendS:
"""Creat a bezier bend.
Args:
Expand All @@ -51,40 +41,74 @@ def bend_s(
t_stop: end
enclosure: Slab/Exclude definition. [dbu]
"""
c = KCell()
_length, _height = length, height
pts = bezier_curve(
control_points=[
(0.0, 0.0),
(_length / 2, 0.0),
(_length / 2, _height),
(_length, _height),
],
t=np.linspace(t_start, t_stop, nb_points),
)

if enclosure is None:
enclosure = LayerEnclosure()

enclosure.extrude_path(
c, path=pts, main_layer=layer, width=width, start_angle=0, end_angle=0
)

c.create_port(
width=int(width / c.kcl.dbu),
trans=kdb.Trans(2, False, 0, 0),
layer=layer,
port_type="optical",
)
c.create_port(
width=int(width / c.kcl.dbu),
trans=kdb.Trans(
0, False, c.bbox().right, c.bbox().top - int(width / c.kcl.dbu) // 2
),
layer=layer,
port_type="optical",
)

c.autorename_ports()

return c

kcl: KCLayout

def __init__(self, kcl: KCLayout) -> None:
"""Bezier bend function on custom KCLayout."""
self.kcl = kcl

@cell
def __call__(
self,
width: float,
height: float,
length: float,
layer: int | LayerEnum,
nb_points: int = 99,
t_start: float = 0,
t_stop: float = 1,
enclosure: LayerEnclosure | None = None,
) -> KCell:
"""Creat a bezier bend.
Args:
width: Width of the core. [um]
height: height difference of left/right. [um]
length: Length of the bend. [um]
layer: Layer index of the core.
nb_points: Number of points of the backbone.
t_start: start
t_stop: end
enclosure: Slab/Exclude definition. [dbu]
"""
c = self.kcl.kcell()
_length, _height = length, height
pts = bezier_curve(
control_points=[
(0.0, 0.0),
(_length / 2, 0.0),
(_length / 2, _height),
(_length, _height),
],
t=np.linspace(t_start, t_stop, nb_points),
)

if enclosure is None:
enclosure = LayerEnclosure()

enclosure.extrude_path(
c, path=pts, main_layer=layer, width=width, start_angle=0, end_angle=0
)

c.create_port(
width=int(width / c.kcl.dbu),
trans=kdb.Trans(2, False, 0, 0),
layer=layer,
port_type="optical",
)
c.create_port(
width=int(width / c.kcl.dbu),
trans=kdb.Trans(
0, False, c.bbox().right, c.bbox().top - int(width / c.kcl.dbu) // 2
),
layer=layer,
port_type="optical",
)

c.autorename_ports()

return c


bend_s = BendS(kcl)
Loading

0 comments on commit 957cbe3

Please sign in to comment.