diff --git a/docs/source/notebooks/00_geometry.py b/docs/source/notebooks/00_geometry.py index 19aa0538..83faf9ac 100644 --- a/docs/source/notebooks/00_geometry.py +++ b/docs/source/notebooks/00_geometry.py @@ -50,7 +50,6 @@ # %% c.shapes(c.kcl.layer(1, 0)).insert(poly1) -# show it in matplotlib and KLayout (you need to have KLayout open and install gdsfactory from the git repo with make install) # %% c.show() # show in klayout @@ -59,26 +58,25 @@ # %% [markdown] # **Exercise** : # -# Make a cell similar to the one above that has a second polygon in layer (1, 1) +# Make a cell similar to the one above that has a second polygon in layer (2, 0) +# +# **Solution** : # %% c = kf.KCell() points = np.array([(-8, -6), (6, 8), (7, 17), (9, 5)]) poly = kf.polygon_from_array(points) c.shapes(c.kcl.layer(1, 0)).insert(poly1) -c.shapes(c.kcl.layer(1, 1)).insert(poly1) +c.shapes(c.kcl.layer(2, 0)).insert(poly1) c -# %% -import kfactory as kf - # %% c = kf.KCell() - -# %% -# Create some new geometry from the functions available in the geometry library textgenerator = kf.kdb.TextGenerator.default_generator() t = textgenerator.text("Hello!", c.kcl.dbu) +c.shapes(kf.kcl.layer(1, 0)).insert(t) +c.show() # show in klayout +c.plot() # %% r = kf.kdb.DBox(-2.5, -5, 2.5, 5) @@ -88,18 +86,21 @@ # Add instances to the new geometry to c, our blank cell # %% -c.shapes(kf.kcl.layer(1, 0)).insert(t) -c.show() # show in klayout -c.plot() - -# %% [markdown] -# Using the << operator (identical to add_ref()), add the same geometry a second time +c = kf.KCell() +c.shapes(c.kcl.layer(1, 0)).insert(r) +c.shapes(c.kcl.layer(2, 0)).insert(r) +c # %% -# Now that the geometry has been added to "c", we can move everything around: +c = kf.KCell() +textgenerator = kf.kdb.TextGenerator.default_generator() text1 = t.transformed( kf.kdb.DTrans(0.0, 10.0).to_itype(c.kcl.dbu) ) # DTrans is a transformation in microns with arguments (, , , ) +# Now that the geometry has been added to "c", we can move everything around: + + +# %% ### complex transformation example:ce # magnification(float): magnification, DO NOT USE on cells or instances, only shapes, most foundries will not allow magnifications on actual cell instances or cells # rotation(float): rotation in degrees @@ -118,7 +119,6 @@ ) # boxes can be moved like this, other shapes and cellss/refs need to be moved with .transform r.move(-5, 0) - # %% c.shapes(c.kcl.layer(1, 0)).insert(text1) c.shapes(c.kcl.layer(2, 0)).insert(text2) @@ -163,27 +163,16 @@ def straight(length=10, width=1, layer=(1, 0)): # %% c = kf.KCell() - -# %% -wg1 = c << straight(length=6, width=2.5, layer=(1, 0)) -wg2 = c << straight(length=11, width=2.5, layer=(1, 0)) -wg3 = c << straight(length=15, width=2.5, layer=(1, 0)) - -# %% -# wg2.transform(kf.kdb.DCplxTrans(1, 10, False, 10, 0)) -# wg3.transform(kf.kdb.DCplxTrans(1, 15, False, 20, 0)) -# wg2.movey(10).rotate(10) -# wg3.movey(20).rotate(15) -print(c.name) -c.show() # show in klayout -# c.plot() +wg1 = c << straight(length=1, width=2.5, layer=(1, 0)) +wg2 = c << straight(length=2, width=2.5, layer=(1, 0)) +wg3 = c << straight(length=3, width=2.5, layer=(1, 0)) +c # %% [markdown] # Now we can align everything together using the ports: # %% [markdown] -# Each straight has two ports: 'W0' and 'E0'. These are arbitrary -# names defined in our straight() function above +# Each straight has two ports: 'o1' and 'o2'. These are arbitrary names defined in our straight() function above # %% # Let's keep wg1 in place on the bottom, and connect the other straights to it. @@ -191,17 +180,13 @@ def straight(length=10, width=1, layer=(1, 0)): wg2.connect("o1", wg1.ports["o2"]) # Next, on wg3 let's grab the "W0" port and connect it to the "E0" on wg2: wg3.connect("o1", wg2.ports["o2"]) - -# %% -c.show() # show in klayout -# c.plot() - +c # %% 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 @@ -236,7 +221,7 @@ def straight(length=10, width=1, layer=(1, 0)): # %% c.show() # show in klayout -# c.plot() +c.plot() # %% [markdown] # ## Ports @@ -311,9 +296,7 @@ def straight(length=10, width=1, layer=(1, 0)): # %% c2.shapes(c2.kcl.layer(1, 0)).insert(kf.kdb.Text("First label", mwg1_ref.trans)) -# c2.shapes(c2.kcl.layer(1,0).insert(kf.kdb.Text("First label", position=mwg1_ref.center) c2.shapes(c2.kcl.layer(1, 0)).insert(kf.kdb.Text("Second label", mwg2_ref.trans)) -# c2.add_label(text="Second label", position=mwg2_ref.center) # %% # It's very useful for recording information about the devices or layout @@ -323,9 +306,8 @@ def straight(length=10, width=1, layer=(1, 0)): kf.kdb.Trans(c2.bbox().right, c2.bbox().top), ) ) - -# %% -c2 +c2.show() +c2.plot() # %% [markdown] # ## Boolean shapes @@ -428,15 +410,10 @@ def straight(length=10, width=1, layer=(1, 0)): # %% [markdown] # ## Write GDS # -# [GDSII](https://en.wikipedia.org/wiki/GDSII) is the Standard format for exchanging CMOS and Photonic circuits. +# [GDSII](https://en.wikipedia.org/wiki/GDSII) is the Standard format for exchanging CMOS circuits with foundries # # You can write your Cell to GDS file. # %% c.write("demo.gds") - -# %% [markdown] -# You can see the GDS file in Klayout viewer. -# -# Sometimes you also want to save the GDS together with metadata (settings, port names, widths, locations ...) in YAML diff --git a/docs/source/notebooks/01_references.py b/docs/source/notebooks/01_references.py index 729b9105..d24cc634 100644 --- a/docs/source/notebooks/01_references.py +++ b/docs/source/notebooks/01_references.py @@ -189,10 +189,6 @@ # In GDS, there's a type of structure called a "Instance" which takes a cell and repeats it NxM times on a fixed grid spacing. For convenience, `Cell` includes this functionality with the add_array() function. # Note that CellArrays are not compatible with ports (since there is no way to access/modify individual elements in a GDS cellarray) # -# gdsfactory also provides with more flexible arrangement options if desired, see for example `grid()` and `packer()`. -# -# As well as `gf.cells.array` -# # Let's make a new Cell and put a big array of our Cell `c` in it: # %% @@ -204,59 +200,6 @@ ) # instance the Cell "c" 3 instances in it with a 3 rows, 6 columns array c3 -# %% [markdown] -# CellArrays don't have ports and there is no way to access/modify individual elements in a GDS cellarray. -# -# gdsfactory provides you with similar functions in `gf.cells.array` and `gf.cells.array_2d` - -# %% -# c4 = gf.Cell("demo_array") # Create a new blank Cell -# aref = c4 << gf.cells.array(cell=c, columns=3, rows=2) -# c4.add_ports(aref.get_ports_list()) -# c4 - - -# %% -# # gf.cells.array? - -# %% [markdown] -# You can also create an array of instances for periodic structures. Lets create a [Distributed Bragg Reflector](https://picwriter.readthedocs.io/en/latest/cells/dbr.html) - - -# %% -# @gf.cell -# def dbr_period(w1=0.5, w2=0.6, l1=0.2, l2=0.4, straight=gf.cells.straight): -# """Return one DBR period.""" -# c = gf.Cell() -# r1 = c << straight(length=l1, width=w1) -# r2 = c << straight(length=l2, width=w2) -# r2.connect(port="o1", destination=r1.ports["o2"]) -# c.add_port("o1", port=r1.ports["o1"]) -# c.add_port("o2", port=r2.ports["o2"]) -# return c - - -# l1 = 0.2 -# l2 = 0.4 -# n = 3 -# period = dbr_period(l1=l1, l2=l2) -# period - -# %% -# dbr = gf.Cell("DBR") -# dbr.add_array(period, columns=n, rows=1, spacing=(l1 + l2, 100)) -# dbr - -# %% [markdown] -# Finally we need to add ports to the new cell - -# %% -# p0 = dbr.add_port("o1", port=period.ports["o1"]) -# p1 = dbr.add_port("o2", port=period.ports["o2"]) - -# p1.center = [(l1 + l2) * n, 0] -# dbr - # %% [markdown] # ## connect instances # @@ -339,3 +282,5 @@ c = kf.cells.euler.bend_euler(radius=5, width=1, layer=0, angle=90) c.draw_ports() c + +# %% diff --git a/docs/source/notebooks/04_KCL.py b/docs/source/notebooks/04_KCL.py index 6bf2087c..e0486408 100644 --- a/docs/source/notebooks/04_KCL.py +++ b/docs/source/notebooks/04_KCL.py @@ -1,68 +1,83 @@ # --- # jupyter: # jupytext: +# custom_cell_magics: kql # text_representation: # extension: .py -# format_name: light -# format_version: '1.5' -# jupytext_version: 1.15.0 +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.11.2 # kernelspec: # display_name: Python 3 (ipykernel) # language: python # name: python3 # --- +# %% [markdown] # # Multi - KCLayout / PDK -# Using multiple KCLayout objects as PDKs or Libraries of KCells and parametric KCell-Functions +# %% [markdown] +# You can also use multiple KCLayout objects as PDKs or Libraries of KCells and parametric KCell-Functions +# %% [markdown] # ## 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 -# - +# %% [markdown] # 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()=}") @@ -74,6 +89,7 @@ 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=}") @@ -81,23 +97,27 @@ 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