lnoi400 2.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lnoi400-2.1.1/LICENSE +21 -0
- lnoi400-2.1.1/PKG-INFO +218 -0
- lnoi400-2.1.1/README.md +166 -0
- lnoi400-2.1.1/_utils/__init__.py +0 -0
- lnoi400-2.1.1/_utils/bends.py +109 -0
- lnoi400-2.1.1/_utils/cell_info.py +17 -0
- lnoi400-2.1.1/_utils/chip_floorplan.py +66 -0
- lnoi400-2.1.1/_utils/cross_section.py +316 -0
- lnoi400-2.1.1/_utils/edge_couplers.py +169 -0
- lnoi400-2.1.1/_utils/grating_couplers.py +126 -0
- lnoi400-2.1.1/_utils/gsg_rf.py +1429 -0
- lnoi400-2.1.1/_utils/models.py +214 -0
- lnoi400-2.1.1/_utils/mzm.py +495 -0
- lnoi400-2.1.1/_utils/optical_resonators.py +182 -0
- lnoi400-2.1.1/_utils/spline.py +151 -0
- lnoi400-2.1.1/_utils/thermal_phase_shifters.py +292 -0
- lnoi400-2.1.1/lnoi400/__init__.py +56 -0
- lnoi400-2.1.1/lnoi400/_builders/grating_couplers.py +49 -0
- lnoi400-2.1.1/lnoi400/cells.py +1788 -0
- lnoi400-2.1.1/lnoi400/config.py +23 -0
- lnoi400-2.1.1/lnoi400/layers.yaml +27 -0
- lnoi400-2.1.1/lnoi400/models.py +325 -0
- lnoi400-2.1.1/lnoi400/mzm_with_pads.py +159 -0
- lnoi400-2.1.1/lnoi400/tech.py +320 -0
- lnoi400-2.1.1/lnoi400.egg-info/PKG-INFO +218 -0
- lnoi400-2.1.1/lnoi400.egg-info/SOURCES.txt +44 -0
- lnoi400-2.1.1/lnoi400.egg-info/dependency_links.txt +1 -0
- lnoi400-2.1.1/lnoi400.egg-info/requires.txt +18 -0
- lnoi400-2.1.1/lnoi400.egg-info/top_level.txt +6 -0
- lnoi400-2.1.1/ltoi300/__init__.py +57 -0
- lnoi400-2.1.1/ltoi300/_builders/edge_couplers.py +49 -0
- lnoi400-2.1.1/ltoi300/_builders/mmis.py +116 -0
- lnoi400-2.1.1/ltoi300/_builders/mzms.py +463 -0
- lnoi400-2.1.1/ltoi300/_builders/phase_modulators.py +474 -0
- lnoi400-2.1.1/ltoi300/_builders/straights.py +42 -0
- lnoi400-2.1.1/ltoi300/cells.py +835 -0
- lnoi400-2.1.1/ltoi300/config.py +23 -0
- lnoi400-2.1.1/ltoi300/layers.yaml +35 -0
- lnoi400-2.1.1/ltoi300/models.py +701 -0
- lnoi400-2.1.1/ltoi300/tech.py +276 -0
- lnoi400-2.1.1/pyproject.toml +145 -0
- lnoi400-2.1.1/setup.cfg +4 -0
- lnoi400-2.1.1/tests/test_chip_edge.py +68 -0
- lnoi400-2.1.1/tests/test_components.py +251 -0
- lnoi400-2.1.1/tests/test_mzm_with_pads.py +53 -0
- lnoi400-2.1.1/tests/test_ring_resonator_slab.py +56 -0
lnoi400-2.1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2026 Luxtelligence
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
lnoi400-2.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lnoi400
|
|
3
|
+
Version: 2.1.1
|
|
4
|
+
Summary: Luxtelligence gdsfactory PDK
|
|
5
|
+
Author-email: Luxtelligence <foundry@luxtelligence.ai>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2023-2026 Luxtelligence
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Keywords: python
|
|
29
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
30
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
31
|
+
Classifier: Operating System :: OS Independent
|
|
32
|
+
Requires-Python: ~=3.12.0
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
License-File: LICENSE
|
|
35
|
+
Requires-Dist: gdsfactory~=9.51.0
|
|
36
|
+
Requires-Dist: gdsfactoryplus
|
|
37
|
+
Requires-Dist: gplugins[sax]~=2.1.0
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
40
|
+
Requires-Dist: pytest; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
42
|
+
Requires-Dist: pytest_regressions; extra == "dev"
|
|
43
|
+
Requires-Dist: towncrier; extra == "dev"
|
|
44
|
+
Provides-Extra: docs
|
|
45
|
+
Requires-Dist: jupyter; extra == "docs"
|
|
46
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
47
|
+
Requires-Dist: mkdocs-with-pdf; extra == "docs"
|
|
48
|
+
Requires-Dist: nbconvert; extra == "docs"
|
|
49
|
+
Requires-Dist: mkdocstrings[python]>=0.27.0; extra == "docs"
|
|
50
|
+
Requires-Dist: zensical<0.1.0,>=0.0.40; extra == "docs"
|
|
51
|
+
Dynamic: license-file
|
|
52
|
+
|
|
53
|
+
# Luxtelligence Process Design Kit (PDK) for gdsfactory
|
|
54
|
+
|
|
55
|
+
Luxtelligence's PDK is built on a lithium tantalate/lithium niobate electro-optic platform, leveraging their large Pockels coefficients for high-speed modulation.
|
|
56
|
+
|
|
57
|
+
<!-- BADGES:START -->
|
|
58
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/actions/workflows/pages.yml)
|
|
59
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/actions/workflows/test_code.yml)
|
|
60
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/actions/workflows/drc.yml)
|
|
61
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/actions/workflows/model_regression.yml)
|
|
62
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/actions/workflows/test_coverage.yml)
|
|
63
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/actions/workflows/model_coverage.yml)
|
|
64
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/issues)
|
|
65
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/pulls)
|
|
66
|
+
<!-- BADGES:END -->
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+

|
|
70
|
+
|
|
71
|
+
[Luxtelligence](https://luxtelligence.ai/) Process Design Kit (PDK) for gdsfactory. The Luxtelligence PDK contains a library of components that facilitate the design of photonic integrated circuits for Luxtelligence's foundry service. The PDK includes both electrical and optical building blocks that leverage Lithium Tantalate and Lithium Niobate's electro-optic effect and attractive optical properties. Each building block consists of a geometrical layout, defining the starting point for microfabrication of the integrated circuit, and a compact circuit model that approximates the real frequency-domain behaviour of the component.
|
|
72
|
+
|
|
73
|
+
The `lxt_pdk_gf` PDK is released open-source to allow users to easily evaluate a sample of what Luxtelligence has to offer. Please [contact us](mailto:foundry@luxtelligence.ai) for information on advanced building blocks and variations on the standard PDK geometry.
|
|
74
|
+
|
|
75
|
+
## Installation
|
|
76
|
+
|
|
77
|
+
We recommend [KLayout](https://www.klayout.de/) as a layout viewer and editor for GDS and OASIS files. gdsfactory itself is based on and closely integrated with KLayout.
|
|
78
|
+
|
|
79
|
+
Python 3.12 is required. We recommend [VSCode](https://code.visualstudio.com/) or [Google Antigravity](https://antigravity.google/) as IDEs.
|
|
80
|
+
|
|
81
|
+
If you do not have Python installed, you can [download Anaconda](https://www.anaconda.com/download/). Once Python is available, clone the repository and install the package in editable mode:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
git clone https://github.com/Luxtelligence/lxt_pdk_gf.git
|
|
85
|
+
cd lxt_pdk_gf
|
|
86
|
+
pip install -e .
|
|
87
|
+
python install_tech.py
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Restart KLayout afterwards to ensure the newly installed technology appears.
|
|
91
|
+
|
|
92
|
+
## KLayout Layer Properties
|
|
93
|
+
|
|
94
|
+
Each PDK has a `klayout/` folder containing `.lyp` layer property files (e.g. `ltoi300/klayout/` and `lnoi400/klayout/`). These files define the colours, fill patterns, and display names for every process layer.
|
|
95
|
+
|
|
96
|
+
To activate them in KLayout:
|
|
97
|
+
|
|
98
|
+
1. Open KLayout and go to **File → Setup**.
|
|
99
|
+
2. Navigate to the **Application** section and select **Layer Properties**.
|
|
100
|
+
3. Under **Default layer properties file**, click **Browse** and point it to the `.lyp` file for your PDK (e.g. `lxt_pdk_gf/ltoi300/klayout/ltoi300.lyp`).
|
|
101
|
+
4. Click **Apply** and **OK**. Restart KLayout to apply the changes.
|
|
102
|
+
|
|
103
|
+
## KLayout DRC
|
|
104
|
+
|
|
105
|
+
Design Rule Check (DRC) runsets for KLayout can be downloaded from [resources.luxtelligence.ai](https://resources.luxtelligence.ai/request-access?resource=drc). The files have a `.lydrc` extension and are specific to the technology stack you are using.
|
|
106
|
+
|
|
107
|
+
**Installation:**
|
|
108
|
+
|
|
109
|
+
Place the downloaded `.lydrc` file(s) in your local KLayout DRC folder:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
<user home folder>/Klayout/drc/
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
> **Note:** KLayout has a known issue where only the first DRC file in the `drc/` folder is actually used. It is recommended to keep **only one `.lydrc` file** in that folder at a time. If you need to switch between DRC scripts for different stacks, simply replace the file.
|
|
116
|
+
|
|
117
|
+
**Running the DRC in KLayout:**
|
|
118
|
+
|
|
119
|
+
1. Open your GDS layout in KLayout.
|
|
120
|
+
2. Go to **Tools → DRC**.
|
|
121
|
+
3. Click **Edit DRC Script** and select the `.lydrc` file corresponding to your process stack.
|
|
122
|
+
4. Run the script. The results will appear in a dedicated DRC results window, where violations are listed and can be highlighted in the layout.
|
|
123
|
+
|
|
124
|
+
> **Important:** Not every flagged violation necessarily needs to be corrected — some rules may be advisory or context-dependent. Conversely, the DRC script does not guarantee that all possible design errors are caught. Always review results in the context of your specific design intent and consult Luxtelligence if in doubt.
|
|
125
|
+
|
|
126
|
+
## Examples
|
|
127
|
+
|
|
128
|
+
### Chip edge, singulation, and polishing
|
|
129
|
+
|
|
130
|
+
For LNOI400 edge couplers, **the outside edge of layer 6/1
|
|
131
|
+
(`CHIP_EXCLUSION_ZONE`) is the physical chip edge**. Layer 6/0
|
|
132
|
+
(`CHIP_CONTOUR`) serves other layout purposes and does not define the
|
|
133
|
+
straight tip extension.
|
|
134
|
+
|
|
135
|
+
The coupler tip extends **5 µm outside layer 6/1**, regardless of the total
|
|
136
|
+
straight tip length. At least **5 µm of constant-width straight** remains
|
|
137
|
+
inside that edge for successful singulation:
|
|
138
|
+
|
|
139
|
+
| Process | Total straight tip (`input_ext`) | Outside 6/1 | Inside 6/1 |
|
|
140
|
+
| --- | --- | --- | --- |
|
|
141
|
+
| Singulation without polishing | 10 µm | 5 µm | 5 µm |
|
|
142
|
+
| Singulation with polishing allowance | Approximately 30 µm | 5 µm | Approximately 25 µm |
|
|
143
|
+
|
|
144
|
+
The longer polishing option keeps the width at the polished facet constant.
|
|
145
|
+
Do not use the longer straight by default when polishing is not planned:
|
|
146
|
+
the large tip mode interacts with silicon over a longer distance, which can
|
|
147
|
+
increase edge-coupler insertion loss. The required polishing allowance depends
|
|
148
|
+
on the planned process; approximately 30 µm is a guide, not a predicted loss
|
|
149
|
+
or a fixed polishing removal depth.
|
|
150
|
+
|
|
151
|
+
`lnoi400.cells.die_phix_rf()` uses the standard LXT chip frame and the 10 µm
|
|
152
|
+
straight tip by default. For polishing, keep the same 5 µm facet offset and
|
|
153
|
+
change only the straight length:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
import lnoi400
|
|
157
|
+
from lnoi400 import cells
|
|
158
|
+
|
|
159
|
+
lnoi400.PDK.activate()
|
|
160
|
+
die = cells.die_phix_rf(
|
|
161
|
+
edge_coupler={
|
|
162
|
+
"component": "double_linear_inverse_taper_mirror",
|
|
163
|
+
"settings": {"input_ext": 30.0},
|
|
164
|
+
},
|
|
165
|
+
fiber_coupler_xoffset=5.0,
|
|
166
|
+
)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Both right and optional left coupler arrays use this outward offset from 6/1.
|
|
170
|
+
Custom couplers must supply at least 10 µm of constant-width straight tip.
|
|
171
|
+
The low-level unmirrored `double_linear_inverse_taper` retains its zero-extension
|
|
172
|
+
default; set `input_ext` explicitly when using it at a singulated chip edge.
|
|
173
|
+
|
|
174
|
+
The die wrapper follows `chip_frame` dimension restrictions: nominal dimensions
|
|
175
|
+
of 5000, 10000, and 20000 µm map to layer-6/0 extents of 4950, 10000, and
|
|
176
|
+
20100 µm respectively, within the frame's existing tolerances. A nominal
|
|
177
|
+
5000-by-5000 µm die is unsupported. Layer 6/1 adds `exclusion_zone_width` on
|
|
178
|
+
each side. Pad offsets remain referenced to layer 6/0.
|
|
179
|
+
|
|
180
|
+
After installing the PDK, you can verify that it is working correctly by running the Jupyter notebooks in the [docs/notebooks](https://github.com/Luxtelligence/lxt_pdk_gf/tree/main/docs/notebooks) folder.
|
|
181
|
+
|
|
182
|
+
## Documentation
|
|
183
|
+
|
|
184
|
+
- [PDK documentation](https://luxtelligence.github.io/lxt_pdk_gf/)
|
|
185
|
+
- [gdsfactory documentation](https://gdsfactory.github.io/gdsfactory/)
|
|
186
|
+
|
|
187
|
+
## Pre-commit
|
|
188
|
+
|
|
189
|
+
Pre-commit hooks are centrally maintained in [pdk-ci-workflow-public](https://github.com/doplaydo/pdk-ci-workflow-public). `make dev` fetches the canonical config and installs the git hook.
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
make dev
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Tests
|
|
196
|
+
|
|
197
|
+
Run the test suite:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
make test
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Release
|
|
204
|
+
|
|
205
|
+
1. Bump the version:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
tbump 0.0.1
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
2. Push the tag:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
git push --tags
|
|
215
|
+
```
|
|
216
|
+
This triggers the release workflow that builds wheels and uploads them.
|
|
217
|
+
|
|
218
|
+
3. Create a pull request with the updated changelog since last release.
|
lnoi400-2.1.1/README.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Luxtelligence Process Design Kit (PDK) for gdsfactory
|
|
2
|
+
|
|
3
|
+
Luxtelligence's PDK is built on a lithium tantalate/lithium niobate electro-optic platform, leveraging their large Pockels coefficients for high-speed modulation.
|
|
4
|
+
|
|
5
|
+
<!-- BADGES:START -->
|
|
6
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/actions/workflows/pages.yml)
|
|
7
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/actions/workflows/test_code.yml)
|
|
8
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/actions/workflows/drc.yml)
|
|
9
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/actions/workflows/model_regression.yml)
|
|
10
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/actions/workflows/test_coverage.yml)
|
|
11
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/actions/workflows/model_coverage.yml)
|
|
12
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/issues)
|
|
13
|
+
[](https://github.com/gdsfactory/lxt_pdk_gf/pulls)
|
|
14
|
+
<!-- BADGES:END -->
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
[Luxtelligence](https://luxtelligence.ai/) Process Design Kit (PDK) for gdsfactory. The Luxtelligence PDK contains a library of components that facilitate the design of photonic integrated circuits for Luxtelligence's foundry service. The PDK includes both electrical and optical building blocks that leverage Lithium Tantalate and Lithium Niobate's electro-optic effect and attractive optical properties. Each building block consists of a geometrical layout, defining the starting point for microfabrication of the integrated circuit, and a compact circuit model that approximates the real frequency-domain behaviour of the component.
|
|
20
|
+
|
|
21
|
+
The `lxt_pdk_gf` PDK is released open-source to allow users to easily evaluate a sample of what Luxtelligence has to offer. Please [contact us](mailto:foundry@luxtelligence.ai) for information on advanced building blocks and variations on the standard PDK geometry.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
We recommend [KLayout](https://www.klayout.de/) as a layout viewer and editor for GDS and OASIS files. gdsfactory itself is based on and closely integrated with KLayout.
|
|
26
|
+
|
|
27
|
+
Python 3.12 is required. We recommend [VSCode](https://code.visualstudio.com/) or [Google Antigravity](https://antigravity.google/) as IDEs.
|
|
28
|
+
|
|
29
|
+
If you do not have Python installed, you can [download Anaconda](https://www.anaconda.com/download/). Once Python is available, clone the repository and install the package in editable mode:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
git clone https://github.com/Luxtelligence/lxt_pdk_gf.git
|
|
33
|
+
cd lxt_pdk_gf
|
|
34
|
+
pip install -e .
|
|
35
|
+
python install_tech.py
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Restart KLayout afterwards to ensure the newly installed technology appears.
|
|
39
|
+
|
|
40
|
+
## KLayout Layer Properties
|
|
41
|
+
|
|
42
|
+
Each PDK has a `klayout/` folder containing `.lyp` layer property files (e.g. `ltoi300/klayout/` and `lnoi400/klayout/`). These files define the colours, fill patterns, and display names for every process layer.
|
|
43
|
+
|
|
44
|
+
To activate them in KLayout:
|
|
45
|
+
|
|
46
|
+
1. Open KLayout and go to **File → Setup**.
|
|
47
|
+
2. Navigate to the **Application** section and select **Layer Properties**.
|
|
48
|
+
3. Under **Default layer properties file**, click **Browse** and point it to the `.lyp` file for your PDK (e.g. `lxt_pdk_gf/ltoi300/klayout/ltoi300.lyp`).
|
|
49
|
+
4. Click **Apply** and **OK**. Restart KLayout to apply the changes.
|
|
50
|
+
|
|
51
|
+
## KLayout DRC
|
|
52
|
+
|
|
53
|
+
Design Rule Check (DRC) runsets for KLayout can be downloaded from [resources.luxtelligence.ai](https://resources.luxtelligence.ai/request-access?resource=drc). The files have a `.lydrc` extension and are specific to the technology stack you are using.
|
|
54
|
+
|
|
55
|
+
**Installation:**
|
|
56
|
+
|
|
57
|
+
Place the downloaded `.lydrc` file(s) in your local KLayout DRC folder:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
<user home folder>/Klayout/drc/
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
> **Note:** KLayout has a known issue where only the first DRC file in the `drc/` folder is actually used. It is recommended to keep **only one `.lydrc` file** in that folder at a time. If you need to switch between DRC scripts for different stacks, simply replace the file.
|
|
64
|
+
|
|
65
|
+
**Running the DRC in KLayout:**
|
|
66
|
+
|
|
67
|
+
1. Open your GDS layout in KLayout.
|
|
68
|
+
2. Go to **Tools → DRC**.
|
|
69
|
+
3. Click **Edit DRC Script** and select the `.lydrc` file corresponding to your process stack.
|
|
70
|
+
4. Run the script. The results will appear in a dedicated DRC results window, where violations are listed and can be highlighted in the layout.
|
|
71
|
+
|
|
72
|
+
> **Important:** Not every flagged violation necessarily needs to be corrected — some rules may be advisory or context-dependent. Conversely, the DRC script does not guarantee that all possible design errors are caught. Always review results in the context of your specific design intent and consult Luxtelligence if in doubt.
|
|
73
|
+
|
|
74
|
+
## Examples
|
|
75
|
+
|
|
76
|
+
### Chip edge, singulation, and polishing
|
|
77
|
+
|
|
78
|
+
For LNOI400 edge couplers, **the outside edge of layer 6/1
|
|
79
|
+
(`CHIP_EXCLUSION_ZONE`) is the physical chip edge**. Layer 6/0
|
|
80
|
+
(`CHIP_CONTOUR`) serves other layout purposes and does not define the
|
|
81
|
+
straight tip extension.
|
|
82
|
+
|
|
83
|
+
The coupler tip extends **5 µm outside layer 6/1**, regardless of the total
|
|
84
|
+
straight tip length. At least **5 µm of constant-width straight** remains
|
|
85
|
+
inside that edge for successful singulation:
|
|
86
|
+
|
|
87
|
+
| Process | Total straight tip (`input_ext`) | Outside 6/1 | Inside 6/1 |
|
|
88
|
+
| --- | --- | --- | --- |
|
|
89
|
+
| Singulation without polishing | 10 µm | 5 µm | 5 µm |
|
|
90
|
+
| Singulation with polishing allowance | Approximately 30 µm | 5 µm | Approximately 25 µm |
|
|
91
|
+
|
|
92
|
+
The longer polishing option keeps the width at the polished facet constant.
|
|
93
|
+
Do not use the longer straight by default when polishing is not planned:
|
|
94
|
+
the large tip mode interacts with silicon over a longer distance, which can
|
|
95
|
+
increase edge-coupler insertion loss. The required polishing allowance depends
|
|
96
|
+
on the planned process; approximately 30 µm is a guide, not a predicted loss
|
|
97
|
+
or a fixed polishing removal depth.
|
|
98
|
+
|
|
99
|
+
`lnoi400.cells.die_phix_rf()` uses the standard LXT chip frame and the 10 µm
|
|
100
|
+
straight tip by default. For polishing, keep the same 5 µm facet offset and
|
|
101
|
+
change only the straight length:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
import lnoi400
|
|
105
|
+
from lnoi400 import cells
|
|
106
|
+
|
|
107
|
+
lnoi400.PDK.activate()
|
|
108
|
+
die = cells.die_phix_rf(
|
|
109
|
+
edge_coupler={
|
|
110
|
+
"component": "double_linear_inverse_taper_mirror",
|
|
111
|
+
"settings": {"input_ext": 30.0},
|
|
112
|
+
},
|
|
113
|
+
fiber_coupler_xoffset=5.0,
|
|
114
|
+
)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Both right and optional left coupler arrays use this outward offset from 6/1.
|
|
118
|
+
Custom couplers must supply at least 10 µm of constant-width straight tip.
|
|
119
|
+
The low-level unmirrored `double_linear_inverse_taper` retains its zero-extension
|
|
120
|
+
default; set `input_ext` explicitly when using it at a singulated chip edge.
|
|
121
|
+
|
|
122
|
+
The die wrapper follows `chip_frame` dimension restrictions: nominal dimensions
|
|
123
|
+
of 5000, 10000, and 20000 µm map to layer-6/0 extents of 4950, 10000, and
|
|
124
|
+
20100 µm respectively, within the frame's existing tolerances. A nominal
|
|
125
|
+
5000-by-5000 µm die is unsupported. Layer 6/1 adds `exclusion_zone_width` on
|
|
126
|
+
each side. Pad offsets remain referenced to layer 6/0.
|
|
127
|
+
|
|
128
|
+
After installing the PDK, you can verify that it is working correctly by running the Jupyter notebooks in the [docs/notebooks](https://github.com/Luxtelligence/lxt_pdk_gf/tree/main/docs/notebooks) folder.
|
|
129
|
+
|
|
130
|
+
## Documentation
|
|
131
|
+
|
|
132
|
+
- [PDK documentation](https://luxtelligence.github.io/lxt_pdk_gf/)
|
|
133
|
+
- [gdsfactory documentation](https://gdsfactory.github.io/gdsfactory/)
|
|
134
|
+
|
|
135
|
+
## Pre-commit
|
|
136
|
+
|
|
137
|
+
Pre-commit hooks are centrally maintained in [pdk-ci-workflow-public](https://github.com/doplaydo/pdk-ci-workflow-public). `make dev` fetches the canonical config and installs the git hook.
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
make dev
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Tests
|
|
144
|
+
|
|
145
|
+
Run the test suite:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
make test
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Release
|
|
152
|
+
|
|
153
|
+
1. Bump the version:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
tbump 0.0.1
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
2. Push the tag:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
git push --tags
|
|
163
|
+
```
|
|
164
|
+
This triggers the release workflow that builds wheels and uploads them.
|
|
165
|
+
|
|
166
|
+
3. Create a pull request with the updated changelog since last release.
|
|
File without changes
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import gdsfactory as gf
|
|
2
|
+
import numpy as np
|
|
3
|
+
from gdsfactory.cross_section import (
|
|
4
|
+
CrossSection,
|
|
5
|
+
)
|
|
6
|
+
from gdsfactory.typings import CrossSectionSpec
|
|
7
|
+
|
|
8
|
+
from _utils.spline import (
|
|
9
|
+
bend_S_spline,
|
|
10
|
+
spline_clamped_path,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def L_turn_bend(
|
|
15
|
+
radius: float = 80.0,
|
|
16
|
+
p: float = 1.0,
|
|
17
|
+
with_arc_floorplan: bool = True,
|
|
18
|
+
cross_section: CrossSectionSpec = "xs_rwg700",
|
|
19
|
+
**kwargs,
|
|
20
|
+
) -> gf.Component:
|
|
21
|
+
"""
|
|
22
|
+
A 90-degrees bend following an Euler path, with linearly-varying curvature
|
|
23
|
+
(increasing and decreasing).
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
npoints = int(np.round(200 * radius / 80.0))
|
|
27
|
+
angle = 90.0
|
|
28
|
+
|
|
29
|
+
return gf.components.bend_euler(
|
|
30
|
+
radius=radius,
|
|
31
|
+
angle=angle,
|
|
32
|
+
p=p,
|
|
33
|
+
with_arc_floorplan=with_arc_floorplan,
|
|
34
|
+
npoints=npoints,
|
|
35
|
+
cross_section=cross_section,
|
|
36
|
+
**kwargs,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def S_bend_vert(
|
|
41
|
+
v_offset: float = 25.0,
|
|
42
|
+
h_extent: float = 100.0,
|
|
43
|
+
dx_straight: float = 5.0,
|
|
44
|
+
cross_section: CrossSectionSpec = "xs_rwg700",
|
|
45
|
+
) -> gf.Component:
|
|
46
|
+
"""A spline bend that bridges a vertical displacement."""
|
|
47
|
+
|
|
48
|
+
if np.abs(v_offset) < 10.0:
|
|
49
|
+
raise ValueError(
|
|
50
|
+
f"The vertical distance bridged by the S-bend ({v_offset}) is too small."
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if np.abs(h_extent / v_offset) < 3.5 or h_extent < 90.0:
|
|
54
|
+
raise ValueError(
|
|
55
|
+
f"The bend would be too tight. Increase h_extent from its current value of {h_extent}."
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
S_bend = gf.components.extend_ports(
|
|
59
|
+
bend_S_spline(
|
|
60
|
+
size=(h_extent, v_offset),
|
|
61
|
+
cross_section=cross_section,
|
|
62
|
+
npoints=int(np.round(2.5 * h_extent)),
|
|
63
|
+
path_method=spline_clamped_path,
|
|
64
|
+
),
|
|
65
|
+
length=dx_straight,
|
|
66
|
+
cross_section=cross_section,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
bend_cell = gf.Component()
|
|
70
|
+
bend_ref = bend_cell << S_bend
|
|
71
|
+
bend_ref.dmove(bend_ref.ports["o1"].dcenter, (0.0, 0.0))
|
|
72
|
+
bend_cell.add_port(name="o1", port=bend_ref.ports["o1"])
|
|
73
|
+
bend_cell.add_port(name="o2", port=bend_ref.ports["o2"])
|
|
74
|
+
bend_cell.flatten()
|
|
75
|
+
|
|
76
|
+
return bend_cell
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def bend_euler_tapered(
|
|
80
|
+
radius: float = 45.0,
|
|
81
|
+
w0: float = 3.0,
|
|
82
|
+
wc: float = 1.0,
|
|
83
|
+
cross_section: CrossSection = None,
|
|
84
|
+
) -> gf.Component:
|
|
85
|
+
"""A tapered bend following an Euler path."""
|
|
86
|
+
|
|
87
|
+
euler_path = gf.path.euler(
|
|
88
|
+
radius=radius,
|
|
89
|
+
angle=180.0,
|
|
90
|
+
p=1,
|
|
91
|
+
use_eff=True,
|
|
92
|
+
)
|
|
93
|
+
euler_path.start_angle = 0.0
|
|
94
|
+
euler_path.end_angle = 180.0
|
|
95
|
+
|
|
96
|
+
def width_fun(t):
|
|
97
|
+
if any(t > 1) or any(t < 0):
|
|
98
|
+
raise ValueError()
|
|
99
|
+
y = np.zeros_like(t)
|
|
100
|
+
y[t <= 0.5] = w0 + (wc - w0) * 2 * t[t <= 0.5]
|
|
101
|
+
y[t > 0.5] = -(wc - w0) * 2 * t[t > 0.5] + 2 * wc - w0
|
|
102
|
+
return y
|
|
103
|
+
|
|
104
|
+
if not cross_section:
|
|
105
|
+
raise ValueError("cross_section is required")
|
|
106
|
+
|
|
107
|
+
xs_tapered = cross_section(width_function=width_fun)
|
|
108
|
+
|
|
109
|
+
return euler_path.extrude(cross_section=xs_tapered)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from gdsfactory import Component
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def copy_info(dst: Component, src: Component, prefix: str | None = None) -> None:
|
|
5
|
+
"""Copy `src.info` entries into `dst.info` with a prefix.
|
|
6
|
+
|
|
7
|
+
By default, the prefix is derived from `src.function_name` when available.
|
|
8
|
+
"""
|
|
9
|
+
if not hasattr(dst, "info") or not hasattr(src, "info"):
|
|
10
|
+
raise ValueError("Both dst and src must expose an 'info' attribute.")
|
|
11
|
+
|
|
12
|
+
src_prefix = prefix or getattr(src, "function_name", None) or "cell"
|
|
13
|
+
src_data = (
|
|
14
|
+
src.info.model_dump() if hasattr(src.info, "model_dump") else dict(src.info)
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
dst.info.update({f"{src_prefix}_{key}": value for key, value in src_data.items()})
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import gdsfactory as gf
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@gf.cell(tags=["chip_floorplan"])
|
|
5
|
+
def chip_frame(
|
|
6
|
+
size: tuple[float, float] = (10_000, 5000),
|
|
7
|
+
exclusion_zone_width: float = 50,
|
|
8
|
+
center: tuple[float, float] = None,
|
|
9
|
+
chip_contour_layer: tuple[int, int] = (6, 0),
|
|
10
|
+
chip_exclusion_zone_layer: tuple[int, int] = (6, 1),
|
|
11
|
+
) -> gf.Component:
|
|
12
|
+
"""Provide the chip extent and the exclusion zone around the chip frame.
|
|
13
|
+
|
|
14
|
+
@tags lnoi400-chip-edge
|
|
15
|
+
|
|
16
|
+
The outside edge of chip_exclusion_zone_layer (6/1) is the physical chip
|
|
17
|
+
edge. chip_contour_layer (6/0) is a separate design contour, not the facet.
|
|
18
|
+
In the exclusion zone, only the edge couplers routing to the chip facet should be placed.
|
|
19
|
+
Allowed chip dimensions (in either direction): 5000 um, 10000 um, 20000 um."""
|
|
20
|
+
|
|
21
|
+
# Check that the chip dimensions have the admissible values.
|
|
22
|
+
|
|
23
|
+
snapped_size = []
|
|
24
|
+
|
|
25
|
+
if size[0] <= 5050 and size[1] <= 5050:
|
|
26
|
+
raise (ValueError(f"The chip frame size {size} is not supported."))
|
|
27
|
+
|
|
28
|
+
if size[0] > 20200 or size[1] > 20200:
|
|
29
|
+
raise (ValueError(f"The chip frame size {size} is not supported."))
|
|
30
|
+
|
|
31
|
+
else:
|
|
32
|
+
for s in size:
|
|
33
|
+
if abs(s - 5000.0) <= 50.0:
|
|
34
|
+
snapped_size.append(4950.0)
|
|
35
|
+
elif abs(s - 10000.0) <= 100.0:
|
|
36
|
+
snapped_size.append(10000)
|
|
37
|
+
elif abs(s - 20000.0) <= 200:
|
|
38
|
+
snapped_size.append(20100)
|
|
39
|
+
else:
|
|
40
|
+
raise (ValueError(f"The chip frame size {size} is not supported."))
|
|
41
|
+
|
|
42
|
+
# Chip frame elements
|
|
43
|
+
|
|
44
|
+
inner_box = gf.components.rectangle(
|
|
45
|
+
size=tuple(snapped_size),
|
|
46
|
+
layer=chip_contour_layer,
|
|
47
|
+
centered=True,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
outer_box = gf.components.rectangle(
|
|
51
|
+
size=tuple(s + 2 * exclusion_zone_width for s in snapped_size),
|
|
52
|
+
layer=chip_exclusion_zone_layer,
|
|
53
|
+
centered=True,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
c = gf.Component()
|
|
57
|
+
ib = c << inner_box
|
|
58
|
+
ob = c << outer_box
|
|
59
|
+
|
|
60
|
+
if center:
|
|
61
|
+
ib.dmove(origin=(0.0, 0.0), destination=center)
|
|
62
|
+
ob.dmove(origin=(0.0, 0.0), destination=center)
|
|
63
|
+
|
|
64
|
+
c.flatten()
|
|
65
|
+
|
|
66
|
+
return c
|