prefab 1.1.0__py3-none-any.whl → 1.1.2__py3-none-any.whl
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.
- prefab/__init__.py +1 -1
- prefab/compare.py +17 -0
- prefab/device.py +12 -13
- prefab/geometry.py +43 -1
- prefab/read.py +5 -1
- prefab/shapes.py +208 -201
- {prefab-1.1.0.dist-info → prefab-1.1.2.dist-info}/METADATA +12 -12
- prefab-1.1.2.dist-info/RECORD +12 -0
- prefab-1.1.0.dist-info/RECORD +0 -12
- {prefab-1.1.0.dist-info → prefab-1.1.2.dist-info}/WHEEL +0 -0
- {prefab-1.1.0.dist-info → prefab-1.1.2.dist-info}/licenses/LICENSE +0 -0
prefab/__init__.py
CHANGED
prefab/compare.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Provides functions to measure the similarity between devices."""
|
|
2
2
|
|
|
3
|
+
import warnings
|
|
4
|
+
|
|
3
5
|
import numpy as np
|
|
4
6
|
|
|
5
7
|
from .device import Device
|
|
@@ -42,6 +44,11 @@ def intersection_over_union(device_a: Device, device_b: Device) -> float:
|
|
|
42
44
|
float
|
|
43
45
|
The Intersection over Union between two devices.
|
|
44
46
|
"""
|
|
47
|
+
if not device_a.is_binary or not device_b.is_binary:
|
|
48
|
+
warnings.warn(
|
|
49
|
+
"One or both devices are not binarized.", UserWarning, stacklevel=2
|
|
50
|
+
)
|
|
51
|
+
|
|
45
52
|
return np.sum(
|
|
46
53
|
np.logical_and(device_a.device_array, device_b.device_array)
|
|
47
54
|
) / np.sum(np.logical_or(device_a.device_array, device_b.device_array))
|
|
@@ -65,6 +72,11 @@ def hamming_distance(device_a: Device, device_b: Device) -> int:
|
|
|
65
72
|
int
|
|
66
73
|
The Hamming distance between two devices.
|
|
67
74
|
"""
|
|
75
|
+
if not device_a.is_binary or not device_b.is_binary:
|
|
76
|
+
warnings.warn(
|
|
77
|
+
"One or both devices are not binarized.", UserWarning, stacklevel=2
|
|
78
|
+
)
|
|
79
|
+
|
|
68
80
|
return np.sum(device_a.device_array != device_b.device_array)
|
|
69
81
|
|
|
70
82
|
|
|
@@ -86,6 +98,11 @@ def dice_coefficient(device_a: Device, device_b: Device) -> float:
|
|
|
86
98
|
float
|
|
87
99
|
The Dice coefficient between two devices.
|
|
88
100
|
"""
|
|
101
|
+
if not device_a.is_binary or not device_b.is_binary:
|
|
102
|
+
warnings.warn(
|
|
103
|
+
"One or both devices are not binarized.", UserWarning, stacklevel=2
|
|
104
|
+
)
|
|
105
|
+
|
|
89
106
|
intersection = 2.0 * np.sum(
|
|
90
107
|
np.logical_and(device_a.device_array, device_b.device_array)
|
|
91
108
|
)
|
prefab/device.py
CHANGED
|
@@ -18,7 +18,6 @@ from PIL import Image
|
|
|
18
18
|
from pydantic import BaseModel, Field, conint, root_validator, validator
|
|
19
19
|
from scipy.ndimage import distance_transform_edt
|
|
20
20
|
from skimage import measure
|
|
21
|
-
from skimage.morphology import closing, disk, opening, square
|
|
22
21
|
from tqdm import tqdm
|
|
23
22
|
|
|
24
23
|
from . import compare, geometry
|
|
@@ -193,6 +192,7 @@ class Device(BaseModel):
|
|
|
193
192
|
raise ValueError("device_array must be a 2D array.")
|
|
194
193
|
return values
|
|
195
194
|
|
|
195
|
+
@property
|
|
196
196
|
def is_binary(self) -> bool:
|
|
197
197
|
"""
|
|
198
198
|
Check if the device geometry is binary.
|
|
@@ -493,6 +493,7 @@ class Device(BaseModel):
|
|
|
493
493
|
binarize=False,
|
|
494
494
|
gpu=gpu,
|
|
495
495
|
)
|
|
496
|
+
semulated_array += np.random.normal(0, 0.03, semulated_array.shape)
|
|
496
497
|
return self.model_copy(update={"device_array": semulated_array})
|
|
497
498
|
|
|
498
499
|
def to_ndarray(self) -> np.ndarray:
|
|
@@ -695,8 +696,8 @@ class Device(BaseModel):
|
|
|
695
696
|
"try `pip install gdsfactory`."
|
|
696
697
|
) from None
|
|
697
698
|
|
|
698
|
-
device_array = np.rot90(self.
|
|
699
|
-
return gf.read.from_np(device_array
|
|
699
|
+
device_array = np.rot90(self.to_ndarray(), k=-1)
|
|
700
|
+
return gf.read.from_np(device_array, nm_per_pixel=1)
|
|
700
701
|
|
|
701
702
|
def to_tidy3d(
|
|
702
703
|
self,
|
|
@@ -808,6 +809,9 @@ class Device(BaseModel):
|
|
|
808
809
|
raise ValueError("Thickness must be a positive integer.")
|
|
809
810
|
|
|
810
811
|
layered_array = self.to_3d(thickness_nm)
|
|
812
|
+
layered_array = np.pad(
|
|
813
|
+
layered_array, ((0, 0), (0, 0), (10, 10)), mode="constant"
|
|
814
|
+
)
|
|
811
815
|
verts, faces, _, _ = measure.marching_cubes(layered_array, level=0.5)
|
|
812
816
|
cube = mesh.Mesh(np.zeros(faces.shape[0], dtype=mesh.Mesh.dtype))
|
|
813
817
|
for i, f in enumerate(faces):
|
|
@@ -1468,16 +1472,11 @@ class Device(BaseModel):
|
|
|
1468
1472
|
ValueError
|
|
1469
1473
|
If an invalid structuring element type is specified.
|
|
1470
1474
|
"""
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
raise ValueError(f"Invalid structuring element: {strel}")
|
|
1477
|
-
|
|
1478
|
-
modified_geometry = closing(self.device_array[:, :, 0], structuring_element)
|
|
1479
|
-
modified_geometry = opening(modified_geometry, structuring_element)
|
|
1480
|
-
modified_geometry = np.expand_dims(modified_geometry, axis=-1)
|
|
1475
|
+
modified_geometry = geometry.enforce_feature_size(
|
|
1476
|
+
device_array=self.device_array,
|
|
1477
|
+
min_feature_size=min_feature_size,
|
|
1478
|
+
strel=strel,
|
|
1479
|
+
)
|
|
1481
1480
|
return self.model_copy(update={"device_array": modified_geometry})
|
|
1482
1481
|
|
|
1483
1482
|
def check_feature_size(self, min_feature_size: int, strel: str = "disk"):
|
prefab/geometry.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import cv2
|
|
4
4
|
import numpy as np
|
|
5
|
+
from skimage.morphology import closing, disk, opening, square
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
def normalize(device_array: np.ndarray) -> np.ndarray:
|
|
@@ -248,7 +249,6 @@ def rotate(device_array: np.ndarray, angle: float) -> np.ndarray:
|
|
|
248
249
|
),
|
|
249
250
|
axis=-1,
|
|
250
251
|
)
|
|
251
|
-
return np.expand_dims(rotated_device_array, axis=-1)
|
|
252
252
|
|
|
253
253
|
|
|
254
254
|
def erode(device_array: np.ndarray, kernel_size: int) -> np.ndarray:
|
|
@@ -306,3 +306,45 @@ def flatten(device_array: np.ndarray) -> np.ndarray:
|
|
|
306
306
|
The flattened array with values scaled between 0 and 1.
|
|
307
307
|
"""
|
|
308
308
|
return normalize(np.sum(device_array, axis=-1, keepdims=True))
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def enforce_feature_size(
|
|
312
|
+
device_array: np.ndarray, min_feature_size: int, strel: str = "disk"
|
|
313
|
+
) -> np.ndarray:
|
|
314
|
+
"""
|
|
315
|
+
Enforce a minimum feature size on the device geometry.
|
|
316
|
+
|
|
317
|
+
This function applies morphological operations to ensure that all features in the
|
|
318
|
+
device geometry are at least the specified minimum size. It uses either a disk
|
|
319
|
+
or square structuring element for the operations.
|
|
320
|
+
|
|
321
|
+
Parameters
|
|
322
|
+
----------
|
|
323
|
+
device_array : np.ndarray
|
|
324
|
+
The input array representing the device geometry.
|
|
325
|
+
min_feature_size : int
|
|
326
|
+
The minimum feature size to enforce, in nanometers.
|
|
327
|
+
strel : str, optional
|
|
328
|
+
The type of structuring element to use. Can be either "disk" or "square".
|
|
329
|
+
Defaults to "disk".
|
|
330
|
+
|
|
331
|
+
Returns
|
|
332
|
+
-------
|
|
333
|
+
np.ndarray
|
|
334
|
+
The modified device array with enforced feature size.
|
|
335
|
+
|
|
336
|
+
Raises
|
|
337
|
+
------
|
|
338
|
+
ValueError
|
|
339
|
+
If an invalid structuring element type is specified.
|
|
340
|
+
"""
|
|
341
|
+
if strel == "disk":
|
|
342
|
+
structuring_element = disk(radius=min_feature_size / 2)
|
|
343
|
+
elif strel == "square":
|
|
344
|
+
structuring_element = square(width=min_feature_size)
|
|
345
|
+
else:
|
|
346
|
+
raise ValueError(f"Invalid structuring element: {strel}")
|
|
347
|
+
|
|
348
|
+
modified_geometry = closing(device_array[:, :, 0], structuring_element)
|
|
349
|
+
modified_geometry = opening(modified_geometry, structuring_element)
|
|
350
|
+
return np.expand_dims(modified_geometry, axis=-1)
|
prefab/read.py
CHANGED
|
@@ -244,7 +244,7 @@ def from_gdsfactory(
|
|
|
244
244
|
If the gdsfactory package is not installed.
|
|
245
245
|
"""
|
|
246
246
|
try:
|
|
247
|
-
import gdsfactory as gf
|
|
247
|
+
import gdsfactory as gf # noqa: F401
|
|
248
248
|
except ImportError:
|
|
249
249
|
raise ImportError(
|
|
250
250
|
"The gdsfactory package is required to use this function; "
|
|
@@ -352,6 +352,10 @@ def get_sem_resolution(sem_path: str, sem_resolution_key: str) -> float:
|
|
|
352
352
|
Extracts the resolution of a scanning electron microscope (SEM) image from its
|
|
353
353
|
metadata.
|
|
354
354
|
|
|
355
|
+
Note:
|
|
356
|
+
-----
|
|
357
|
+
This function is used internally and may not be useful for most users.
|
|
358
|
+
|
|
355
359
|
Parameters
|
|
356
360
|
----------
|
|
357
361
|
sem_path : str
|
prefab/shapes.py
CHANGED
|
@@ -6,7 +6,7 @@ from skimage.draw import polygon
|
|
|
6
6
|
from .device import Device
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def rectangle(width: int = 200, height: int =
|
|
9
|
+
def rectangle(width: int = 200, height: int = None, **kwargs) -> Device:
|
|
10
10
|
"""
|
|
11
11
|
Create a Device object with a rectangular shape.
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ def rectangle(width: int = 200, height: int = 100, **kwargs) -> Device:
|
|
|
15
15
|
width : int, optional
|
|
16
16
|
The width of the rectangle. Defaults to 200.
|
|
17
17
|
height : int, optional
|
|
18
|
-
The height of the rectangle. Defaults to
|
|
18
|
+
The height of the rectangle. Defaults to the value of width.
|
|
19
19
|
**kwargs : dict
|
|
20
20
|
Additional keyword arguments to be passed to the Device constructor.
|
|
21
21
|
|
|
@@ -24,40 +24,57 @@ def rectangle(width: int = 200, height: int = 100, **kwargs) -> Device:
|
|
|
24
24
|
Device
|
|
25
25
|
A Device object containing the rectangular shape.
|
|
26
26
|
"""
|
|
27
|
+
if height is None:
|
|
28
|
+
height = width
|
|
27
29
|
rectangle = np.zeros((height, width))
|
|
28
30
|
rectangle[:, :] = 1
|
|
29
31
|
return Device(device_array=rectangle, **kwargs)
|
|
30
32
|
|
|
31
33
|
|
|
32
|
-
def
|
|
34
|
+
def window(
|
|
35
|
+
width: int = 200, height: int = None, border_width: int = 60, **kwargs
|
|
36
|
+
) -> Device:
|
|
33
37
|
"""
|
|
34
|
-
Create a Device object with a
|
|
38
|
+
Create a Device object with a window shape (hollow square).
|
|
35
39
|
|
|
36
40
|
Parameters
|
|
37
41
|
----------
|
|
38
42
|
width : int, optional
|
|
39
|
-
The width
|
|
43
|
+
The overall width of the window. Defaults to 200.
|
|
44
|
+
height : int, optional
|
|
45
|
+
The overall height of the window. Defaults to the value of width.
|
|
46
|
+
border_width : int, optional
|
|
47
|
+
The width of the window border. Defaults to 60.
|
|
40
48
|
**kwargs : dict
|
|
41
49
|
Additional keyword arguments to be passed to the Device constructor.
|
|
42
50
|
|
|
43
51
|
Returns
|
|
44
52
|
-------
|
|
45
53
|
Device
|
|
46
|
-
A Device object containing the
|
|
54
|
+
A Device object containing the window shape.
|
|
47
55
|
"""
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
56
|
+
if height is None:
|
|
57
|
+
height = width
|
|
58
|
+
window = np.zeros((height, width))
|
|
59
|
+
window[:border_width, :] = 1
|
|
60
|
+
window[-border_width:, :] = 1
|
|
61
|
+
window[:, :border_width] = 1
|
|
62
|
+
window[:, -border_width:] = 1
|
|
63
|
+
return Device(device_array=window, **kwargs)
|
|
51
64
|
|
|
52
65
|
|
|
53
|
-
def cross(
|
|
66
|
+
def cross(
|
|
67
|
+
width: int = 200, height: int = None, arm_width: int = 60, **kwargs
|
|
68
|
+
) -> Device:
|
|
54
69
|
"""
|
|
55
70
|
Create a Device object with a cross shape.
|
|
56
71
|
|
|
57
72
|
Parameters
|
|
58
73
|
----------
|
|
59
74
|
width : int, optional
|
|
60
|
-
The overall width
|
|
75
|
+
The overall width of the cross. Defaults to 200.
|
|
76
|
+
height : int, optional
|
|
77
|
+
The overall height of the cross. Defaults to the value of width.
|
|
61
78
|
arm_width : int, optional
|
|
62
79
|
The width of the cross arms. Defaults to 60.
|
|
63
80
|
**kwargs : dict
|
|
@@ -68,22 +85,29 @@ def cross(width: int = 200, arm_width: int = 60, **kwargs) -> Device:
|
|
|
68
85
|
Device
|
|
69
86
|
A Device object containing the cross shape.
|
|
70
87
|
"""
|
|
71
|
-
|
|
72
|
-
|
|
88
|
+
if height is None:
|
|
89
|
+
height = width
|
|
90
|
+
cross = np.zeros((height, width))
|
|
91
|
+
center_x = width // 2
|
|
92
|
+
center_y = height // 2
|
|
73
93
|
half_arm_width = arm_width // 2
|
|
74
|
-
cross[
|
|
75
|
-
cross[:,
|
|
94
|
+
cross[center_y - half_arm_width : center_y + half_arm_width + 1, :] = 1
|
|
95
|
+
cross[:, center_x - half_arm_width : center_x + half_arm_width + 1] = 1
|
|
76
96
|
return Device(device_array=cross, **kwargs)
|
|
77
97
|
|
|
78
98
|
|
|
79
|
-
def target(
|
|
99
|
+
def target(
|
|
100
|
+
width: int = 200, height: int = None, arm_width: int = 60, **kwargs
|
|
101
|
+
) -> Device:
|
|
80
102
|
"""
|
|
81
103
|
Create a Device object with a target shape (cross with center removed).
|
|
82
104
|
|
|
83
105
|
Parameters
|
|
84
106
|
----------
|
|
85
107
|
width : int, optional
|
|
86
|
-
The overall width
|
|
108
|
+
The overall width of the target. Defaults to 200.
|
|
109
|
+
height : int, optional
|
|
110
|
+
The overall height of the target. Defaults to the value of width.
|
|
87
111
|
arm_width : int, optional
|
|
88
112
|
The width of the target arms. Defaults to 60.
|
|
89
113
|
**kwargs : dict
|
|
@@ -94,45 +118,22 @@ def target(width: int = 200, arm_width: int = 60, **kwargs) -> Device:
|
|
|
94
118
|
Device
|
|
95
119
|
A Device object containing the target shape.
|
|
96
120
|
"""
|
|
97
|
-
|
|
98
|
-
|
|
121
|
+
if height is None:
|
|
122
|
+
height = width
|
|
123
|
+
target = np.zeros((height, width))
|
|
124
|
+
center_x = width // 2
|
|
125
|
+
center_y = height // 2
|
|
99
126
|
half_arm_width = arm_width // 2
|
|
100
|
-
target[
|
|
101
|
-
target[:,
|
|
127
|
+
target[center_y - half_arm_width : center_y + half_arm_width + 1, :] = 1
|
|
128
|
+
target[:, center_x - half_arm_width : center_x + half_arm_width + 1] = 1
|
|
102
129
|
target[
|
|
103
|
-
|
|
104
|
-
|
|
130
|
+
center_y - half_arm_width : center_y + half_arm_width + 1,
|
|
131
|
+
center_x - half_arm_width : center_x + half_arm_width + 1,
|
|
105
132
|
] = 0
|
|
106
133
|
return Device(device_array=target, **kwargs)
|
|
107
134
|
|
|
108
135
|
|
|
109
|
-
def
|
|
110
|
-
"""
|
|
111
|
-
Create a Device object with a window shape (hollow square).
|
|
112
|
-
|
|
113
|
-
Parameters
|
|
114
|
-
----------
|
|
115
|
-
width : int, optional
|
|
116
|
-
The overall width and height of the window. Defaults to 200.
|
|
117
|
-
border_width : int, optional
|
|
118
|
-
The width of the window border. Defaults to 60.
|
|
119
|
-
**kwargs : dict
|
|
120
|
-
Additional keyword arguments to be passed to the Device constructor.
|
|
121
|
-
|
|
122
|
-
Returns
|
|
123
|
-
-------
|
|
124
|
-
Device
|
|
125
|
-
A Device object containing the window shape.
|
|
126
|
-
"""
|
|
127
|
-
window = np.zeros((width, width))
|
|
128
|
-
window[:border_width, :] = 1
|
|
129
|
-
window[-border_width:, :] = 1
|
|
130
|
-
window[:, :border_width] = 1
|
|
131
|
-
window[:, -border_width:] = 1
|
|
132
|
-
return Device(device_array=window, **kwargs)
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def ellipse(width: int = 200, height: int = 100, **kwargs) -> Device:
|
|
136
|
+
def disk(width: int = 200, height: int = None, **kwargs) -> Device:
|
|
136
137
|
"""
|
|
137
138
|
Create a Device object with an elliptical shape.
|
|
138
139
|
|
|
@@ -141,7 +142,7 @@ def ellipse(width: int = 200, height: int = 100, **kwargs) -> Device:
|
|
|
141
142
|
width : int, optional
|
|
142
143
|
The width of the ellipse. Defaults to 200.
|
|
143
144
|
height : int, optional
|
|
144
|
-
The height of the ellipse. Defaults to
|
|
145
|
+
The height of the ellipse. Defaults to the value of width.
|
|
145
146
|
**kwargs : dict
|
|
146
147
|
Additional keyword arguments to be passed to the Device constructor.
|
|
147
148
|
|
|
@@ -150,38 +151,54 @@ def ellipse(width: int = 200, height: int = 100, **kwargs) -> Device:
|
|
|
150
151
|
Device
|
|
151
152
|
A Device object containing the elliptical shape.
|
|
152
153
|
"""
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
if height is None:
|
|
155
|
+
height = width
|
|
156
|
+
radius_x = width // 2
|
|
157
|
+
radius_y = height // 2
|
|
158
|
+
y, x = np.ogrid[-radius_y:radius_y, -radius_x:radius_x]
|
|
159
|
+
mask = (x**2 / radius_x**2) + (y**2 / radius_y**2) <= 1
|
|
155
160
|
ellipse = np.zeros((height, width))
|
|
156
161
|
ellipse[mask] = 1
|
|
157
162
|
return Device(device_array=ellipse, **kwargs)
|
|
158
163
|
|
|
159
164
|
|
|
160
|
-
def
|
|
165
|
+
def ring(
|
|
166
|
+
width: int = 200, height: int = None, border_width: int = 60, **kwargs
|
|
167
|
+
) -> Device:
|
|
161
168
|
"""
|
|
162
|
-
Create a Device object with a
|
|
169
|
+
Create a Device object with a ring shape.
|
|
163
170
|
|
|
164
171
|
Parameters
|
|
165
172
|
----------
|
|
166
173
|
width : int, optional
|
|
167
|
-
The width
|
|
174
|
+
The overall width of the ring. Defaults to 200.
|
|
175
|
+
height : int, optional
|
|
176
|
+
The overall height of the ring. Defaults to the value of width.
|
|
177
|
+
border_width : int, optional
|
|
178
|
+
The width of the ring border. Defaults to 60.
|
|
168
179
|
**kwargs : dict
|
|
169
180
|
Additional keyword arguments to be passed to the Device constructor.
|
|
170
181
|
|
|
171
182
|
Returns
|
|
172
183
|
-------
|
|
173
184
|
Device
|
|
174
|
-
A Device object containing the
|
|
185
|
+
A Device object containing the ring shape.
|
|
175
186
|
"""
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
187
|
+
if height is None:
|
|
188
|
+
height = width
|
|
189
|
+
radius_x = width // 2
|
|
190
|
+
radius_y = height // 2
|
|
191
|
+
inner_radius_x = radius_x - border_width
|
|
192
|
+
inner_radius_y = radius_y - border_width
|
|
193
|
+
y, x = np.ogrid[-radius_y:radius_y, -radius_x:radius_x]
|
|
194
|
+
outer_mask = x**2 / radius_x**2 + y**2 / radius_y**2 <= 1
|
|
195
|
+
inner_mask = x**2 / inner_radius_x**2 + y**2 / inner_radius_y**2 <= 1
|
|
196
|
+
ring = np.zeros((height, width))
|
|
197
|
+
ring[outer_mask & ~inner_mask] = 1
|
|
198
|
+
return Device(device_array=ring, **kwargs)
|
|
182
199
|
|
|
183
200
|
|
|
184
|
-
def
|
|
201
|
+
def disk_wavy(
|
|
185
202
|
width: int = 200, wave_amplitude: float = 10, wave_frequency: float = 10, **kwargs
|
|
186
203
|
) -> Device:
|
|
187
204
|
"""
|
|
@@ -215,14 +232,18 @@ def circle_wavy(
|
|
|
215
232
|
return Device(device_array=circle_wavy, **kwargs)
|
|
216
233
|
|
|
217
234
|
|
|
218
|
-
def pie(
|
|
235
|
+
def pie(
|
|
236
|
+
width: int = 200, height: int = None, arc_angle: float = 270, **kwargs
|
|
237
|
+
) -> Device:
|
|
219
238
|
"""
|
|
220
239
|
Create a Device object with a pie shape.
|
|
221
240
|
|
|
222
241
|
Parameters
|
|
223
242
|
----------
|
|
224
243
|
width : int, optional
|
|
225
|
-
The width
|
|
244
|
+
The width of the pie. Defaults to 200.
|
|
245
|
+
height : int, optional
|
|
246
|
+
The height of the pie. Defaults to the value of width.
|
|
226
247
|
arc_angle : float, optional
|
|
227
248
|
The angle of the pie slice in degrees. Defaults to 270.
|
|
228
249
|
**kwargs : dict
|
|
@@ -233,12 +254,15 @@ def pie(width: int = 200, arc_angle: float = 270, **kwargs) -> Device:
|
|
|
233
254
|
Device
|
|
234
255
|
A Device object containing the pie shape.
|
|
235
256
|
"""
|
|
236
|
-
|
|
237
|
-
|
|
257
|
+
if height is None:
|
|
258
|
+
height = width
|
|
259
|
+
radius_x = width // 2
|
|
260
|
+
radius_y = height // 2
|
|
261
|
+
y, x = np.ogrid[-radius_y:radius_y, -radius_x:radius_x]
|
|
238
262
|
angle = np.arctan2(y, x) * 180 / np.pi
|
|
239
263
|
angle = (angle + 360) % 360
|
|
240
|
-
mask = (x**2 + y**2
|
|
241
|
-
pie = np.zeros((
|
|
264
|
+
mask = (x**2 / radius_x**2 + y**2 / radius_y**2 <= 1) & (angle <= arc_angle)
|
|
265
|
+
pie = np.zeros((height, width))
|
|
242
266
|
pie[mask] = 1
|
|
243
267
|
return Device(device_array=pie, **kwargs)
|
|
244
268
|
|
|
@@ -350,36 +374,6 @@ def poly(width: int = 200, num_points: int = 5, **kwargs) -> Device:
|
|
|
350
374
|
return Device(device_array=poly, **kwargs)
|
|
351
375
|
|
|
352
376
|
|
|
353
|
-
def ring(width: int = 200, border_width: int = 60, **kwargs) -> Device:
|
|
354
|
-
"""
|
|
355
|
-
Create a Device object with a ring shape.
|
|
356
|
-
|
|
357
|
-
Parameters
|
|
358
|
-
----------
|
|
359
|
-
width : int, optional
|
|
360
|
-
The overall width and height of the ring. Defaults to 200.
|
|
361
|
-
border_width : int, optional
|
|
362
|
-
The width of the ring border. Defaults to 60.
|
|
363
|
-
**kwargs : dict
|
|
364
|
-
Additional keyword arguments to be passed to the Device constructor.
|
|
365
|
-
|
|
366
|
-
Returns
|
|
367
|
-
-------
|
|
368
|
-
Device
|
|
369
|
-
A Device object containing the ring shape.
|
|
370
|
-
"""
|
|
371
|
-
radius_outer = width // 2
|
|
372
|
-
radius_inner = radius_outer - border_width
|
|
373
|
-
y, x = np.ogrid[-radius_outer:radius_outer, -radius_outer:radius_outer]
|
|
374
|
-
distance_from_center = np.sqrt(x**2 + y**2)
|
|
375
|
-
mask = (distance_from_center <= radius_outer) & (
|
|
376
|
-
distance_from_center >= radius_inner
|
|
377
|
-
)
|
|
378
|
-
ring = np.zeros((width, width))
|
|
379
|
-
ring[mask] = 1
|
|
380
|
-
return Device(device_array=ring, **kwargs)
|
|
381
|
-
|
|
382
|
-
|
|
383
377
|
def radial_grating(
|
|
384
378
|
width: int = 200, grating_skew: int = 0, num_gratings: int = 6, **kwargs
|
|
385
379
|
) -> Device:
|
|
@@ -465,7 +459,8 @@ def offset_grating(
|
|
|
465
459
|
|
|
466
460
|
|
|
467
461
|
def L_grating(
|
|
468
|
-
|
|
462
|
+
width: int = 200,
|
|
463
|
+
height: int = None,
|
|
469
464
|
pitch: int = 100,
|
|
470
465
|
duty_cycle: float = 0.5,
|
|
471
466
|
**kwargs,
|
|
@@ -475,8 +470,10 @@ def L_grating(
|
|
|
475
470
|
|
|
476
471
|
Parameters
|
|
477
472
|
----------
|
|
473
|
+
width : int, optional
|
|
474
|
+
The width of the L-grating. Defaults to 200.
|
|
478
475
|
height : int, optional
|
|
479
|
-
The height
|
|
476
|
+
The height of the L-grating. Defaults to the value of width.
|
|
480
477
|
pitch : int, optional
|
|
481
478
|
The pitch (period) of the L-shapes. Defaults to 100.
|
|
482
479
|
duty_cycle : float, optional
|
|
@@ -489,8 +486,10 @@ def L_grating(
|
|
|
489
486
|
Device
|
|
490
487
|
A Device object containing the L-shaped grating pattern.
|
|
491
488
|
"""
|
|
492
|
-
|
|
493
|
-
|
|
489
|
+
if height is None:
|
|
490
|
+
height = width
|
|
491
|
+
L_grating = np.zeros((height, width))
|
|
492
|
+
num_L_shapes = min(height, width) // pitch
|
|
494
493
|
L_width = int(pitch * duty_cycle)
|
|
495
494
|
for i in range(num_L_shapes):
|
|
496
495
|
start = i * pitch
|
|
@@ -499,11 +498,11 @@ def L_grating(
|
|
|
499
498
|
return Device(device_array=L_grating, **kwargs)
|
|
500
499
|
|
|
501
500
|
|
|
502
|
-
def
|
|
503
|
-
rows: int = 5, cols: int = 5,
|
|
501
|
+
def disks(
|
|
502
|
+
rows: int = 5, cols: int = 5, disk_radius: int = 30, spacing: int = 60, **kwargs
|
|
504
503
|
) -> Device:
|
|
505
504
|
"""
|
|
506
|
-
Create a Device object with a grid of uniform
|
|
505
|
+
Create a Device object with a grid of uniform disks.
|
|
507
506
|
|
|
508
507
|
Parameters
|
|
509
508
|
----------
|
|
@@ -511,39 +510,39 @@ def circles(
|
|
|
511
510
|
The number of rows in the grid. Defaults to 5.
|
|
512
511
|
cols : int, optional
|
|
513
512
|
The number of columns in the grid. Defaults to 5.
|
|
514
|
-
|
|
515
|
-
The radius of each
|
|
513
|
+
disk_radius : int, optional
|
|
514
|
+
The radius of each disk. Defaults to 30.
|
|
516
515
|
spacing : int, optional
|
|
517
|
-
The spacing between
|
|
516
|
+
The spacing between disk centers. Defaults to 60.
|
|
518
517
|
**kwargs : dict
|
|
519
518
|
Additional keyword arguments to be passed to the Device constructor.
|
|
520
519
|
|
|
521
520
|
Returns
|
|
522
521
|
-------
|
|
523
522
|
Device
|
|
524
|
-
A Device object containing a grid of
|
|
523
|
+
A Device object containing a grid of disks.
|
|
525
524
|
"""
|
|
526
|
-
grid_height = rows * (2 *
|
|
527
|
-
grid_width = cols * (2 *
|
|
528
|
-
|
|
529
|
-
y, x = np.ogrid[-
|
|
530
|
-
mask = x**2 + y**2 <=
|
|
525
|
+
grid_height = rows * (2 * disk_radius + spacing) - spacing
|
|
526
|
+
grid_width = cols * (2 * disk_radius + spacing) - spacing
|
|
527
|
+
disks = np.zeros((grid_height, grid_width))
|
|
528
|
+
y, x = np.ogrid[-disk_radius:disk_radius, -disk_radius:disk_radius]
|
|
529
|
+
mask = x**2 + y**2 <= disk_radius**2
|
|
531
530
|
for row in range(rows):
|
|
532
531
|
for col in range(cols):
|
|
533
|
-
center_y = row * (2 *
|
|
534
|
-
center_x = col * (2 *
|
|
535
|
-
|
|
536
|
-
center_y -
|
|
537
|
-
center_x -
|
|
532
|
+
center_y = row * (2 * disk_radius + spacing) + disk_radius
|
|
533
|
+
center_x = col * (2 * disk_radius + spacing) + disk_radius
|
|
534
|
+
disks[
|
|
535
|
+
center_y - disk_radius : center_y + disk_radius,
|
|
536
|
+
center_x - disk_radius : center_x + disk_radius,
|
|
538
537
|
][mask] = 1
|
|
539
|
-
return Device(device_array=
|
|
538
|
+
return Device(device_array=disks, **kwargs)
|
|
540
539
|
|
|
541
540
|
|
|
542
|
-
def
|
|
543
|
-
rows: int = 5, cols: int = 5,
|
|
541
|
+
def disks_offset(
|
|
542
|
+
rows: int = 5, cols: int = 5, disk_radius: int = 30, spacing: int = 30, **kwargs
|
|
544
543
|
) -> Device:
|
|
545
544
|
"""
|
|
546
|
-
Create a Device object with an offset grid of
|
|
545
|
+
Create a Device object with an offset grid of disks.
|
|
547
546
|
|
|
548
547
|
Parameters
|
|
549
548
|
----------
|
|
@@ -551,48 +550,50 @@ def circles_offset(
|
|
|
551
550
|
The number of rows in the grid. Defaults to 5.
|
|
552
551
|
cols : int, optional
|
|
553
552
|
The number of columns in the grid. Defaults to 5.
|
|
554
|
-
|
|
555
|
-
The radius of each
|
|
553
|
+
disk_radius : int, optional
|
|
554
|
+
The radius of each disk. Defaults to 30.
|
|
556
555
|
spacing : int, optional
|
|
557
|
-
The spacing between
|
|
556
|
+
The spacing between disk centers. Defaults to 30.
|
|
558
557
|
**kwargs : dict
|
|
559
558
|
Additional keyword arguments to be passed to the Device constructor.
|
|
560
559
|
|
|
561
560
|
Returns
|
|
562
561
|
-------
|
|
563
562
|
Device
|
|
564
|
-
A Device object containing an offset grid of
|
|
563
|
+
A Device object containing an offset grid of disks.
|
|
565
564
|
"""
|
|
566
|
-
grid_height = rows * (2 *
|
|
567
|
-
grid_width =
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
565
|
+
grid_height = rows * (2 * disk_radius + spacing) - spacing
|
|
566
|
+
grid_width = (
|
|
567
|
+
cols * (2 * disk_radius + spacing) - spacing + (disk_radius + spacing // 2)
|
|
568
|
+
)
|
|
569
|
+
disks_offset = np.zeros((grid_height, grid_width))
|
|
570
|
+
y, x = np.ogrid[-disk_radius:disk_radius, -disk_radius:disk_radius]
|
|
571
|
+
mask = x**2 + y**2 <= disk_radius**2
|
|
571
572
|
for row in range(rows):
|
|
572
573
|
for col in range(cols):
|
|
573
|
-
center_y = row * (2 *
|
|
574
|
+
center_y = row * (2 * disk_radius + spacing) + disk_radius
|
|
574
575
|
center_x = (
|
|
575
|
-
col * (2 *
|
|
576
|
-
+
|
|
577
|
-
+ (
|
|
576
|
+
col * (2 * disk_radius + spacing)
|
|
577
|
+
+ disk_radius
|
|
578
|
+
+ (disk_radius + spacing // 2 if row % 2 == 1 else 0)
|
|
578
579
|
)
|
|
579
|
-
|
|
580
|
-
center_y -
|
|
581
|
-
center_x -
|
|
580
|
+
disks_offset[
|
|
581
|
+
center_y - disk_radius : center_y + disk_radius,
|
|
582
|
+
center_x - disk_radius : center_x + disk_radius,
|
|
582
583
|
][mask] = 1
|
|
583
|
-
return Device(device_array=
|
|
584
|
+
return Device(device_array=disks_offset, **kwargs)
|
|
584
585
|
|
|
585
586
|
|
|
586
|
-
def
|
|
587
|
+
def disks_varying(
|
|
587
588
|
rows: int = 5,
|
|
588
589
|
cols: int = 5,
|
|
589
|
-
|
|
590
|
-
|
|
590
|
+
min_disk_radius: int = 10,
|
|
591
|
+
max_disk_radius: int = 30,
|
|
591
592
|
spacing: int = 30,
|
|
592
593
|
**kwargs,
|
|
593
594
|
) -> Device:
|
|
594
595
|
"""
|
|
595
|
-
Create a Device object with a grid of
|
|
596
|
+
Create a Device object with a grid of disks with varying radii.
|
|
596
597
|
|
|
597
598
|
Parameters
|
|
598
599
|
----------
|
|
@@ -600,40 +601,42 @@ def circles_varying(
|
|
|
600
601
|
The number of rows in the grid. Defaults to 5.
|
|
601
602
|
cols : int, optional
|
|
602
603
|
The number of columns in the grid. Defaults to 5.
|
|
603
|
-
|
|
604
|
-
The minimum radius of the
|
|
605
|
-
|
|
606
|
-
The maximum radius of the
|
|
604
|
+
min_disk_radius : int, optional
|
|
605
|
+
The minimum radius of the disks. Defaults to 10.
|
|
606
|
+
max_disk_radius : int, optional
|
|
607
|
+
The maximum radius of the disks. Defaults to 30.
|
|
607
608
|
spacing : int, optional
|
|
608
|
-
The spacing between
|
|
609
|
+
The spacing between disk centers. Defaults to 30.
|
|
609
610
|
**kwargs : dict
|
|
610
611
|
Additional keyword arguments to be passed to the Device constructor.
|
|
611
612
|
|
|
612
613
|
Returns
|
|
613
614
|
-------
|
|
614
615
|
Device
|
|
615
|
-
A Device object containing a grid of
|
|
616
|
+
A Device object containing a grid of disks with varying radii.
|
|
616
617
|
"""
|
|
617
|
-
grid_height = rows * (2 *
|
|
618
|
-
grid_width = cols * (2 *
|
|
619
|
-
|
|
620
|
-
radius_range = np.linspace(
|
|
618
|
+
grid_height = rows * (2 * max_disk_radius + spacing) - spacing
|
|
619
|
+
grid_width = cols * (2 * max_disk_radius + spacing) - spacing
|
|
620
|
+
disks_varying = np.zeros((grid_height, grid_width))
|
|
621
|
+
radius_range = np.linspace(min_disk_radius, max_disk_radius, rows * cols).reshape(
|
|
622
|
+
rows, cols
|
|
623
|
+
)
|
|
621
624
|
for row in range(rows):
|
|
622
625
|
for col in range(cols):
|
|
623
|
-
|
|
624
|
-
y, x = np.ogrid[-
|
|
625
|
-
mask = x**2 + y**2 <=
|
|
626
|
-
center_y = row * (2 *
|
|
627
|
-
center_x = col * (2 *
|
|
628
|
-
|
|
629
|
-
center_y -
|
|
630
|
-
center_x -
|
|
626
|
+
disk_radius = int(radius_range[row, col])
|
|
627
|
+
y, x = np.ogrid[-disk_radius:disk_radius, -disk_radius:disk_radius]
|
|
628
|
+
mask = x**2 + y**2 <= disk_radius**2
|
|
629
|
+
center_y = row * (2 * max_disk_radius + spacing) + max_disk_radius
|
|
630
|
+
center_x = col * (2 * max_disk_radius + spacing) + max_disk_radius
|
|
631
|
+
disks_varying[
|
|
632
|
+
center_y - disk_radius : center_y + disk_radius,
|
|
633
|
+
center_x - disk_radius : center_x + disk_radius,
|
|
631
634
|
][mask] = 1
|
|
632
|
-
return Device(device_array=
|
|
635
|
+
return Device(device_array=disks_varying, **kwargs)
|
|
633
636
|
|
|
634
637
|
|
|
635
638
|
def holes(
|
|
636
|
-
rows: int = 5, cols: int = 5,
|
|
639
|
+
rows: int = 5, cols: int = 5, hole_radius: int = 30, spacing: int = 30, **kwargs
|
|
637
640
|
) -> Device:
|
|
638
641
|
"""
|
|
639
642
|
Create a Device object with a grid of uniform circular holes.
|
|
@@ -644,7 +647,7 @@ def holes(
|
|
|
644
647
|
The number of rows in the grid. Defaults to 5.
|
|
645
648
|
cols : int, optional
|
|
646
649
|
The number of columns in the grid. Defaults to 5.
|
|
647
|
-
|
|
650
|
+
hole_radius : int, optional
|
|
648
651
|
The radius of each hole. Defaults to 30.
|
|
649
652
|
spacing : int, optional
|
|
650
653
|
The spacing between hole centers. Defaults to 30.
|
|
@@ -656,24 +659,24 @@ def holes(
|
|
|
656
659
|
Device
|
|
657
660
|
A Device object containing a grid of circular holes.
|
|
658
661
|
"""
|
|
659
|
-
grid_height = rows * (2 *
|
|
660
|
-
grid_width = cols * (2 *
|
|
662
|
+
grid_height = rows * (2 * hole_radius + spacing) - spacing
|
|
663
|
+
grid_width = cols * (2 * hole_radius + spacing) - spacing
|
|
661
664
|
holes = np.ones((grid_height, grid_width))
|
|
662
|
-
y, x = np.ogrid[-
|
|
663
|
-
mask = x**2 + y**2 <=
|
|
665
|
+
y, x = np.ogrid[-hole_radius:hole_radius, -hole_radius:hole_radius]
|
|
666
|
+
mask = x**2 + y**2 <= hole_radius**2
|
|
664
667
|
for row in range(rows):
|
|
665
668
|
for col in range(cols):
|
|
666
|
-
center_y = row * (2 *
|
|
667
|
-
center_x = col * (2 *
|
|
669
|
+
center_y = row * (2 * hole_radius + spacing) + hole_radius
|
|
670
|
+
center_x = col * (2 * hole_radius + spacing) + hole_radius
|
|
668
671
|
holes[
|
|
669
|
-
center_y -
|
|
670
|
-
center_x -
|
|
672
|
+
center_y - hole_radius : center_y + hole_radius,
|
|
673
|
+
center_x - hole_radius : center_x + hole_radius,
|
|
671
674
|
][mask] = 0
|
|
672
675
|
return Device(device_array=holes, **kwargs)
|
|
673
676
|
|
|
674
677
|
|
|
675
678
|
def holes_offset(
|
|
676
|
-
rows: int = 5, cols: int = 5,
|
|
679
|
+
rows: int = 5, cols: int = 5, hole_radius: int = 30, spacing: int = 30, **kwargs
|
|
677
680
|
) -> Device:
|
|
678
681
|
"""
|
|
679
682
|
Create a Device object with an offset grid of circular holes.
|
|
@@ -684,7 +687,7 @@ def holes_offset(
|
|
|
684
687
|
The number of rows in the grid. Defaults to 5.
|
|
685
688
|
cols : int, optional
|
|
686
689
|
The number of columns in the grid. Defaults to 5.
|
|
687
|
-
|
|
690
|
+
hole_radius : int, optional
|
|
688
691
|
The radius of each hole. Defaults to 30.
|
|
689
692
|
spacing : int, optional
|
|
690
693
|
The spacing between hole centers. Defaults to 30.
|
|
@@ -696,22 +699,24 @@ def holes_offset(
|
|
|
696
699
|
Device
|
|
697
700
|
A Device object containing an offset grid of circular holes.
|
|
698
701
|
"""
|
|
699
|
-
grid_height = rows * (2 *
|
|
700
|
-
grid_width =
|
|
702
|
+
grid_height = rows * (2 * hole_radius + spacing) - spacing
|
|
703
|
+
grid_width = (
|
|
704
|
+
cols * (2 * hole_radius + spacing) - spacing + (hole_radius + spacing // 2)
|
|
705
|
+
)
|
|
701
706
|
holes_offset = np.ones((grid_height, grid_width))
|
|
702
|
-
y, x = np.ogrid[-
|
|
703
|
-
mask = x**2 + y**2 <=
|
|
707
|
+
y, x = np.ogrid[-hole_radius:hole_radius, -hole_radius:hole_radius]
|
|
708
|
+
mask = x**2 + y**2 <= hole_radius**2
|
|
704
709
|
for row in range(rows):
|
|
705
710
|
for col in range(cols):
|
|
706
|
-
center_y = row * (2 *
|
|
711
|
+
center_y = row * (2 * hole_radius + spacing) + hole_radius
|
|
707
712
|
center_x = (
|
|
708
|
-
col * (2 *
|
|
709
|
-
+
|
|
710
|
-
+ (
|
|
713
|
+
col * (2 * hole_radius + spacing)
|
|
714
|
+
+ hole_radius
|
|
715
|
+
+ (hole_radius + spacing // 2 if row % 2 == 1 else 0)
|
|
711
716
|
)
|
|
712
717
|
holes_offset[
|
|
713
|
-
center_y -
|
|
714
|
-
center_x -
|
|
718
|
+
center_y - hole_radius : center_y + hole_radius,
|
|
719
|
+
center_x - hole_radius : center_x + hole_radius,
|
|
715
720
|
][mask] = 0
|
|
716
721
|
return Device(device_array=holes_offset, **kwargs)
|
|
717
722
|
|
|
@@ -719,8 +724,8 @@ def holes_offset(
|
|
|
719
724
|
def holes_varying(
|
|
720
725
|
rows: int = 5,
|
|
721
726
|
cols: int = 5,
|
|
722
|
-
|
|
723
|
-
|
|
727
|
+
min_hole_radius: int = 10,
|
|
728
|
+
max_hole_radius: int = 30,
|
|
724
729
|
spacing: int = 30,
|
|
725
730
|
**kwargs,
|
|
726
731
|
) -> Device:
|
|
@@ -733,9 +738,9 @@ def holes_varying(
|
|
|
733
738
|
The number of rows in the grid. Defaults to 5.
|
|
734
739
|
cols : int, optional
|
|
735
740
|
The number of columns in the grid. Defaults to 5.
|
|
736
|
-
|
|
741
|
+
min_hole_radius : int, optional
|
|
737
742
|
The minimum radius of the holes. Defaults to 10.
|
|
738
|
-
|
|
743
|
+
max_hole_radius : int, optional
|
|
739
744
|
The maximum radius of the holes. Defaults to 30.
|
|
740
745
|
spacing : int, optional
|
|
741
746
|
The spacing between hole centers. Defaults to 30.
|
|
@@ -747,19 +752,21 @@ def holes_varying(
|
|
|
747
752
|
Device
|
|
748
753
|
A Device object containing a grid of circular holes with varying radii.
|
|
749
754
|
"""
|
|
750
|
-
grid_height = rows * (2 *
|
|
751
|
-
grid_width = cols * (2 *
|
|
755
|
+
grid_height = rows * (2 * max_hole_radius + spacing) - spacing
|
|
756
|
+
grid_width = cols * (2 * max_hole_radius + spacing) - spacing
|
|
752
757
|
holes_varying = np.ones((grid_height, grid_width))
|
|
753
|
-
radius_range = np.linspace(
|
|
758
|
+
radius_range = np.linspace(min_hole_radius, max_hole_radius, rows * cols).reshape(
|
|
759
|
+
rows, cols
|
|
760
|
+
)
|
|
754
761
|
for row in range(rows):
|
|
755
762
|
for col in range(cols):
|
|
756
|
-
|
|
757
|
-
y, x = np.ogrid[-
|
|
758
|
-
mask = x**2 + y**2 <=
|
|
759
|
-
center_y = row * (2 *
|
|
760
|
-
center_x = col * (2 *
|
|
763
|
+
hole_radius = int(radius_range[row, col])
|
|
764
|
+
y, x = np.ogrid[-hole_radius:hole_radius, -hole_radius:hole_radius]
|
|
765
|
+
mask = x**2 + y**2 <= hole_radius**2
|
|
766
|
+
center_y = row * (2 * max_hole_radius + spacing) + max_hole_radius
|
|
767
|
+
center_x = col * (2 * max_hole_radius + spacing) + max_hole_radius
|
|
761
768
|
holes_varying[
|
|
762
|
-
center_y -
|
|
763
|
-
center_x -
|
|
769
|
+
center_y - hole_radius : center_y + hole_radius,
|
|
770
|
+
center_x - hole_radius : center_x + hole_radius,
|
|
764
771
|
][mask] = 0
|
|
765
772
|
return Device(device_array=holes_varying, **kwargs)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: prefab
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.2
|
|
4
4
|
Summary: Artificial nanofabrication of integrated photonic circuits using deep learning
|
|
5
5
|
Project-URL: Homepage, https://prefabphotonics.com
|
|
6
6
|
Project-URL: Repository, https://github.com/PreFab-Photonics/PreFab
|
|
@@ -516,7 +516,7 @@ Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 (LGP
|
|
|
516
516
|
Classifier: Operating System :: OS Independent
|
|
517
517
|
Classifier: Programming Language :: Python :: 3
|
|
518
518
|
Requires-Python: >=3.9
|
|
519
|
-
Requires-Dist: gdstk
|
|
519
|
+
Requires-Dist: gdstk>=0.9.55
|
|
520
520
|
Requires-Dist: matplotlib
|
|
521
521
|
Requires-Dist: numpy
|
|
522
522
|
Requires-Dist: opencv-python-headless
|
|
@@ -533,23 +533,23 @@ Description-Content-Type: text/markdown
|
|
|
533
533
|
|
|
534
534
|

|
|
535
535
|
|
|
536
|
-
PreFab leverages **deep learning** to
|
|
536
|
+
PreFab is a _virtual nanofabrication environment_ that leverages **deep learning** and **computer vision** to predict and correct for structural variations in integrated photonic devices during nanofabrication.
|
|
537
537
|
|
|
538
538
|
## Prediction
|
|
539
539
|
|
|
540
|
-
PreFab
|
|
540
|
+
PreFab predicts process-induced structural variations, including corner rounding, loss of small lines and islands, filling of narrow holes and channels, sidewall angle deviations, and stochastic effects. This allows designers to rapidly prototype and evaluate expected performance pre-fabrication.
|
|
541
541
|
|
|
542
542
|

|
|
543
543
|
|
|
544
544
|
## Correction
|
|
545
545
|
|
|
546
|
-
PreFab
|
|
546
|
+
PreFab corrects device designs to ensure that the fabricated outcome closely matches the intended specifications. This minimizes structural variations and reduces performance discrepancies between simulations and actual experiments.
|
|
547
547
|
|
|
548
548
|

|
|
549
549
|
|
|
550
550
|
## Models
|
|
551
551
|
|
|
552
|
-
|
|
552
|
+
Each photonic nanofabrication process requires unique models, which are regularly updated with the latest data. The current models include (see the full list in [`docs/models.md`](https://github.com/PreFab-Photonics/PreFab/blob/main/docs/models.md)):
|
|
553
553
|
|
|
554
554
|
| Foundry | Process | Latest Version | Latest Dataset | Model Name |
|
|
555
555
|
| ------- | ------- | ----------------- | ---------------- | ----------- |
|
|
@@ -557,7 +557,7 @@ PreFab accommodates unique _predictor_ and _corrector_ models for each photonic
|
|
|
557
557
|
| ANT | SiN | ANF1 (May 6 2024) | d1 (Jan 31 2024) | ANT_SiN_ANF1_d1 |
|
|
558
558
|
| Generic | DUV-SOI | ANF1 (May 6 2024) | d0 (Jul 30 2024) | generic_DUV_SOI_ANF1_d0 |
|
|
559
559
|
|
|
560
|
-
> _New models
|
|
560
|
+
> _New models are to be regularly added. Usage may change. For additional foundry and process models, feel free to [contact us](mailto:hi@prefabphotonics.com) or raise an issue._
|
|
561
561
|
|
|
562
562
|
## Installation
|
|
563
563
|
|
|
@@ -581,7 +581,7 @@ pip install -e .
|
|
|
581
581
|
|
|
582
582
|
Before you can make PreFab requests, you will need to [create an account](https://www.prefabphotonics.com/login).
|
|
583
583
|
|
|
584
|
-
To link your account, you will need
|
|
584
|
+
To link your account, you will need an token. You can do this by running the following command in your terminal. This will open a browser window where you can log in and authenticate your token.
|
|
585
585
|
|
|
586
586
|
```sh
|
|
587
587
|
python3 -m prefab setup
|
|
@@ -593,11 +593,11 @@ Visit [`/docs/examples`](https://github.com/PreFab-Photonics/PreFab/tree/main/do
|
|
|
593
593
|
|
|
594
594
|
## Performance and Usage
|
|
595
595
|
|
|
596
|
-
PreFab models are
|
|
596
|
+
PreFab models are hosted on a [serverless cloud platform](https://modal.com/). Please keep in mind:
|
|
597
597
|
|
|
598
|
-
- 🐢 CPU inference may
|
|
599
|
-
- 🥶 The first prediction may take longer due to cold start server loading. Subsequent predictions will be faster.
|
|
600
|
-
- 😊
|
|
598
|
+
- 🐢 Default CPU inference may be slower.
|
|
599
|
+
- 🥶 The first prediction using optional GPU inference may take longer due to cold start server loading. Subsequent predictions will be faster.
|
|
600
|
+
- 😊 Please be considerate of usage. Start with small tasks and limit usage during the initial stages. Thank you!
|
|
601
601
|
|
|
602
602
|
## License
|
|
603
603
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
prefab/__init__.py,sha256=fbGTDuVA76ol5cM6fXbPAZMB0BCT2zmHD7Pgr9I-zV0,401
|
|
2
|
+
prefab/__main__.py,sha256=aAgt1WXa44k1nJqsiSD3uAfNeGpwtjWqMUYCHN5_Qrw,2759
|
|
3
|
+
prefab/compare.py,sha256=2MKUT7N2A639tUGCnJHpfF9MmS-v3oARDkTqHbWJ9OM,3239
|
|
4
|
+
prefab/device.py,sha256=dpx4dDspruImy__bp3X11y_s-CBJZr6dKpxn8wGtmSA,58314
|
|
5
|
+
prefab/geometry.py,sha256=0sa6ietUWZGkxOnUPUzD3q2QpFuOpWkSANoopGpPd6s,11035
|
|
6
|
+
prefab/models.py,sha256=UMzYZzKouroxlwkXCMKIYozmQCMhNhvt8kQrZmwmZB4,3671
|
|
7
|
+
prefab/read.py,sha256=MuF-cugFQ7MWBJ8DOvQuwktIk0fJ8PXBeLye0ydrB8o,14734
|
|
8
|
+
prefab/shapes.py,sha256=2qaqyNzu5WG3wVdk4oQzeNXmhwXRHcPnRZlgRrM4MoA,25576
|
|
9
|
+
prefab-1.1.2.dist-info/METADATA,sha256=wZOFUncUh7ZmZRoJ8AxH_SfpKwd2KdxDnVvmTyiLSR0,34824
|
|
10
|
+
prefab-1.1.2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
11
|
+
prefab-1.1.2.dist-info/licenses/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
|
|
12
|
+
prefab-1.1.2.dist-info/RECORD,,
|
prefab-1.1.0.dist-info/RECORD
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
prefab/__init__.py,sha256=Tx4t6ODZeL-V-ZPuQXjEHHtwb7rjqCb2ApLFDniQ5fA,401
|
|
2
|
-
prefab/__main__.py,sha256=aAgt1WXa44k1nJqsiSD3uAfNeGpwtjWqMUYCHN5_Qrw,2759
|
|
3
|
-
prefab/compare.py,sha256=AfLJ69DTqvt0mkMqNCTdn2KWKoclt_0htGVXvarEhkY,2709
|
|
4
|
-
prefab/device.py,sha256=lklENpvqROifkEgNCT4BwU9xnsLt1nwdLksh5VDgpKU,58507
|
|
5
|
-
prefab/geometry.py,sha256=pXsVeu4Ycnq60bG6WqFNoUWnyiNStIaYQgbMIrEyndM,9614
|
|
6
|
-
prefab/models.py,sha256=UMzYZzKouroxlwkXCMKIYozmQCMhNhvt8kQrZmwmZB4,3671
|
|
7
|
-
prefab/read.py,sha256=Rzj9GGrszsKWdY8GxtmpfYcA4nsiuxgwSdEDVvfHN80,14624
|
|
8
|
-
prefab/shapes.py,sha256=Hc6dc2Y5Wmb2mZAxhdjBNEJF7C7tF2o460HNvcqcQdo,24856
|
|
9
|
-
prefab-1.1.0.dist-info/METADATA,sha256=tHahGccx-TKDbeo2ZMKTjC_JYPWesvovFyUuTONF_YA,34817
|
|
10
|
-
prefab-1.1.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
11
|
-
prefab-1.1.0.dist-info/licenses/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
|
|
12
|
-
prefab-1.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|