prefab 0.4.2__py3-none-any.whl → 0.4.5__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 +13 -11
- prefab/io.py +86 -41
- prefab/predictor.py +46 -32
- prefab/processor.py +70 -30
- {prefab-0.4.2.dist-info → prefab-0.4.5.dist-info}/METADATA +10 -10
- prefab-0.4.5.dist-info/RECORD +8 -0
- {prefab-0.4.2.dist-info → prefab-0.4.5.dist-info}/WHEEL +1 -1
- prefab-0.4.2.dist-info/RECORD +0 -8
- {prefab-0.4.2.dist-info → prefab-0.4.5.dist-info}/licenses/LICENSE +0 -0
prefab/__init__.py
CHANGED
|
@@ -13,21 +13,22 @@ from prefab.predictor import correct
|
|
|
13
13
|
# I/O Utilities
|
|
14
14
|
# Function to load/save device images and gds files
|
|
15
15
|
from prefab.io import (
|
|
16
|
-
load_device_img,
|
|
17
|
-
load_device_gds,
|
|
18
|
-
device_to_cell
|
|
16
|
+
load_device_img, # Load device from an image file
|
|
17
|
+
load_device_gds, # Load device from a GDSII file
|
|
18
|
+
device_to_cell, # Convert a device layout to a gdstk cell
|
|
19
19
|
)
|
|
20
20
|
|
|
21
21
|
# Import image processing utilities
|
|
22
22
|
# Functions to modify and manipulate device images
|
|
23
23
|
from prefab.processor import (
|
|
24
|
-
binarize,
|
|
25
|
-
binarize_hard,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
binarize, # Soft binarization of grayscale images
|
|
25
|
+
binarize_hard, # Hard binarization of grayscale images
|
|
26
|
+
ternarize, # Ternarization of grayscale images
|
|
27
|
+
remove_padding, # Trims excess padding from device images
|
|
28
|
+
zero_boundary, # Applies zero boundary to device images
|
|
29
|
+
generate_device_contour, # Generates contour of device images
|
|
30
|
+
calculate_prediction_uncertainty, # Computes prediction uncertainty for device images
|
|
31
|
+
mse, # Computes mean squared error between two images
|
|
31
32
|
)
|
|
32
33
|
|
|
33
34
|
__all__ = (
|
|
@@ -37,9 +38,10 @@ __all__ = (
|
|
|
37
38
|
"device_to_cell",
|
|
38
39
|
"binarize",
|
|
39
40
|
"binarize_hard",
|
|
41
|
+
"ternarize",
|
|
40
42
|
"remove_padding",
|
|
41
43
|
"zero_boundary",
|
|
42
44
|
"generate_device_contour",
|
|
43
45
|
"calculate_prediction_uncertainty",
|
|
44
|
-
"mse"
|
|
46
|
+
"mse",
|
|
45
47
|
)
|
prefab/io.py
CHANGED
|
@@ -3,10 +3,10 @@ This module offers tools to import, export, and preprocess device layouts in mul
|
|
|
3
3
|
nanofabrication prediction tasks.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from typing import Optional, List
|
|
6
|
+
from typing import Optional, List, Tuple
|
|
7
7
|
import matplotlib.image as img
|
|
8
8
|
import numpy as np
|
|
9
|
-
import
|
|
9
|
+
import gdstk
|
|
10
10
|
import cv2
|
|
11
11
|
from prefab.processor import binarize_hard
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ def load_device_img(path: str, img_length_nm: int = None) -> np.ndarray:
|
|
|
15
15
|
"""
|
|
16
16
|
Load, process and scale device image from file for prediction.
|
|
17
17
|
|
|
18
|
-
This function reads an image file, scales it according to the provided image length in
|
|
18
|
+
This function reads an image file, scales it according to the provided image length in
|
|
19
19
|
nanometers, and performs preprocessing tasks such as binarization, preparing it for prediction.
|
|
20
20
|
|
|
21
21
|
Parameters
|
|
@@ -24,7 +24,7 @@ def load_device_img(path: str, img_length_nm: int = None) -> np.ndarray:
|
|
|
24
24
|
Path to the device image file.
|
|
25
25
|
|
|
26
26
|
img_length_nm : int, optional
|
|
27
|
-
Desired length of the device image in nanometers for scaling. If not provided,
|
|
27
|
+
Desired length of the device image in nanometers for scaling. If not provided,
|
|
28
28
|
the length of the original image is used.
|
|
29
29
|
|
|
30
30
|
Returns
|
|
@@ -41,14 +41,18 @@ def load_device_img(path: str, img_length_nm: int = None) -> np.ndarray:
|
|
|
41
41
|
return device
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
def load_device_gds(
|
|
45
|
-
|
|
44
|
+
def load_device_gds(
|
|
45
|
+
path: str,
|
|
46
|
+
cell_name: str,
|
|
47
|
+
coords: Optional[List[List[int]]] = None,
|
|
48
|
+
layer: Tuple[int, int] = (1, 0),
|
|
49
|
+
) -> np.ndarray:
|
|
46
50
|
"""
|
|
47
51
|
Load and process a device layout from a GDSII file.
|
|
48
52
|
|
|
49
|
-
This function reads a device layout from a GDSII file, performs necessary
|
|
53
|
+
This function reads a device layout from a GDSII file, performs necessary
|
|
50
54
|
preprocessing tasks such as scaling and padding, and prepares it for prediction.
|
|
51
|
-
Only the
|
|
55
|
+
Only the specified layer is loaded.
|
|
52
56
|
|
|
53
57
|
Parameters
|
|
54
58
|
----------
|
|
@@ -59,41 +63,73 @@ def load_device_gds(path: str, cell_name: str,
|
|
|
59
63
|
Name of the GDSII cell to be loaded.
|
|
60
64
|
|
|
61
65
|
coords : List[List[int]], optional
|
|
62
|
-
A list of coordinates [[xmin, ymin], [xmax, ymax]] in nm, defining the
|
|
66
|
+
A list of coordinates [[xmin, ymin], [xmax, ymax]] in nm, defining the
|
|
63
67
|
region of the cell to be loaded. If None, the entire cell is loaded.
|
|
64
68
|
|
|
69
|
+
layer : Tuple[int, int], optional
|
|
70
|
+
A tuple specifying the layer to be loaded. Default is (1, 0).
|
|
71
|
+
|
|
65
72
|
Returns
|
|
66
73
|
-------
|
|
67
74
|
np.ndarray
|
|
68
75
|
A 2D numpy array representing the preprocessed device layout, ready for prediction.
|
|
69
76
|
"""
|
|
70
|
-
gds =
|
|
71
|
-
cell = gds
|
|
72
|
-
polygons = cell.get_polygons(
|
|
73
|
-
bounds =
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
gds = gdstk.read_gds(path)
|
|
78
|
+
cell = gds[cell_name]
|
|
79
|
+
polygons = cell.get_polygons(layer=layer[0], datatype=layer[1])
|
|
80
|
+
bounds = tuple(
|
|
81
|
+
tuple(1000 * x for x in sub_tuple) for sub_tuple in cell.bounding_box()
|
|
82
|
+
)
|
|
83
|
+
device = np.zeros(
|
|
84
|
+
(int(bounds[1][1] - bounds[0][1]), int(bounds[1][0] - bounds[0][0]))
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
contours = [
|
|
88
|
+
np.array(
|
|
89
|
+
[
|
|
90
|
+
[
|
|
91
|
+
[
|
|
92
|
+
int(1000 * vertex[0] - bounds[0][0]),
|
|
93
|
+
int(1000 * vertex[1] - bounds[0][1]),
|
|
94
|
+
]
|
|
95
|
+
]
|
|
96
|
+
for vertex in polygon.points
|
|
97
|
+
],
|
|
98
|
+
dtype=np.int32,
|
|
99
|
+
)
|
|
100
|
+
for polygon in polygons
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
cv2.fillPoly(img=device, pts=contours, color=(1, 1, 1))
|
|
84
104
|
|
|
85
105
|
if coords is not None:
|
|
86
|
-
|
|
87
|
-
|
|
106
|
+
new_device = np.zeros(
|
|
107
|
+
(int(bounds[1][1] - bounds[0][1]), int(bounds[1][0] - bounds[0][0]))
|
|
108
|
+
)
|
|
109
|
+
new_device[
|
|
110
|
+
int(coords[0][1] - bounds[0][1]) : int(coords[1][1] - bounds[0][1]),
|
|
111
|
+
int(coords[0][0] - bounds[0][0]) : int(coords[1][0] - bounds[0][0]),
|
|
112
|
+
] = device[
|
|
113
|
+
int(coords[0][1] - bounds[0][1]) : int(coords[1][1] - bounds[0][1]),
|
|
114
|
+
int(coords[0][0] - bounds[0][0]) : int(coords[1][0] - bounds[0][0]),
|
|
115
|
+
]
|
|
116
|
+
device = new_device
|
|
88
117
|
|
|
89
118
|
device = np.flipud(device)
|
|
90
119
|
device = np.pad(device, 100)
|
|
120
|
+
|
|
91
121
|
return device
|
|
92
122
|
|
|
93
123
|
|
|
94
|
-
def device_to_cell(
|
|
95
|
-
|
|
96
|
-
|
|
124
|
+
def device_to_cell(
|
|
125
|
+
device: np.ndarray,
|
|
126
|
+
cell_name: str,
|
|
127
|
+
library: gdstk.Library,
|
|
128
|
+
resolution: float = 1.0,
|
|
129
|
+
layer: int = 1,
|
|
130
|
+
approximation_mode: int = 2,
|
|
131
|
+
) -> gdstk.Cell:
|
|
132
|
+
"""Converts a device layout to a gdstk cell for GDSII export.
|
|
97
133
|
|
|
98
134
|
This function creates a cell that represents a device layout. The created cell
|
|
99
135
|
is ready to be exported as a GDSII file.
|
|
@@ -106,14 +142,14 @@ def device_to_cell(device: np.ndarray, cell_name: str, library: gdspy.GdsLibrary
|
|
|
106
142
|
cell_name : str
|
|
107
143
|
Name for the new cell.
|
|
108
144
|
|
|
109
|
-
library :
|
|
145
|
+
library : gdstk.Library
|
|
110
146
|
Library to which the cell will be added.
|
|
111
147
|
|
|
112
148
|
resolution : float, optional
|
|
113
149
|
The resolution of the device in pixels per nm. Default is 1.0.
|
|
114
150
|
|
|
115
|
-
layer : int, optional
|
|
116
|
-
|
|
151
|
+
layer : Tuple[int, int], optional
|
|
152
|
+
A tuple specifying the layer to be exported. Default is (1, 0).
|
|
117
153
|
|
|
118
154
|
approximation_mode : int, optional
|
|
119
155
|
The approximation method to be used for finding contours. Possible values are 1, 2, 3, and
|
|
@@ -121,17 +157,22 @@ def device_to_cell(device: np.ndarray, cell_name: str, library: gdspy.GdsLibrary
|
|
|
121
157
|
|
|
122
158
|
Returns
|
|
123
159
|
-------
|
|
124
|
-
|
|
160
|
+
gdstk.Cell
|
|
125
161
|
The newly created cell containing the device layout.
|
|
126
162
|
"""
|
|
127
|
-
approximation_method_mapping = {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
163
|
+
approximation_method_mapping = {
|
|
164
|
+
1: cv2.CHAIN_APPROX_NONE,
|
|
165
|
+
2: cv2.CHAIN_APPROX_SIMPLE,
|
|
166
|
+
3: cv2.CHAIN_APPROX_TC89_L1,
|
|
167
|
+
4: cv2.CHAIN_APPROX_TC89_KCOS,
|
|
168
|
+
}
|
|
131
169
|
|
|
132
170
|
device = np.flipud(device)
|
|
133
|
-
contours, hierarchy = cv2.findContours(
|
|
134
|
-
|
|
171
|
+
contours, hierarchy = cv2.findContours(
|
|
172
|
+
device.astype(np.uint8),
|
|
173
|
+
cv2.RETR_CCOMP,
|
|
174
|
+
approximation_method_mapping[approximation_mode],
|
|
175
|
+
)
|
|
135
176
|
|
|
136
177
|
outer_polygons = []
|
|
137
178
|
inner_polygons = []
|
|
@@ -146,10 +187,14 @@ def device_to_cell(device: np.ndarray, cell_name: str, library: gdspy.GdsLibrary
|
|
|
146
187
|
else:
|
|
147
188
|
inner_polygons.append(points)
|
|
148
189
|
|
|
149
|
-
polygons =
|
|
150
|
-
|
|
190
|
+
polygons = gdstk.boolean(
|
|
191
|
+
outer_polygons, inner_polygons, "xor", layer=layer[0], datatype=layer[1]
|
|
192
|
+
)
|
|
193
|
+
for polygon in polygons:
|
|
194
|
+
polygon.scale(resolution, resolution)
|
|
151
195
|
|
|
152
196
|
cell = library.new_cell(cell_name)
|
|
153
|
-
|
|
197
|
+
for polygon in polygons:
|
|
198
|
+
cell.add(polygon)
|
|
154
199
|
|
|
155
200
|
return cell
|
prefab/predictor.py
CHANGED
|
@@ -9,12 +9,14 @@ import requests
|
|
|
9
9
|
from cv2 import imencode, imdecode, IMREAD_GRAYSCALE
|
|
10
10
|
from prefab.processor import binarize_hard
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
|
|
13
|
+
def predict(
|
|
14
|
+
device: np.ndarray, model_name: str, model_tags: str, binarize: bool = False
|
|
15
|
+
) -> np.ndarray:
|
|
14
16
|
"""
|
|
15
17
|
Generates a prediction for a photonic device using a specified cloud-based ML model.
|
|
16
18
|
|
|
17
|
-
The function sends an image of the device to a cloud function, which uses the specified
|
|
19
|
+
The function sends an image of the device to a cloud function, which uses the specified
|
|
18
20
|
machine learning model to generate a prediction.
|
|
19
21
|
|
|
20
22
|
Parameters
|
|
@@ -23,12 +25,12 @@ def predict(device: np.ndarray, model_name: str, model_tag: str,
|
|
|
23
25
|
A binary numpy matrix representing the shape of a device.
|
|
24
26
|
|
|
25
27
|
model_name : str
|
|
26
|
-
The name of the ML model to use for the prediction.
|
|
28
|
+
The name of the ML model to use for the prediction.
|
|
27
29
|
Consult the module's documentation for available models.
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
The
|
|
31
|
-
Consult the module's documentation for available
|
|
31
|
+
model_tags : Union[str, List[str]]
|
|
32
|
+
The tags of the ML model.
|
|
33
|
+
Consult the module's documentation for available tags.
|
|
32
34
|
|
|
33
35
|
binarize : bool, optional
|
|
34
36
|
If set to True, the prediction will be binarized (default is False).
|
|
@@ -36,30 +38,36 @@ def predict(device: np.ndarray, model_name: str, model_tag: str,
|
|
|
36
38
|
Returns
|
|
37
39
|
-------
|
|
38
40
|
np.ndarray
|
|
39
|
-
A numpy matrix representing the predicted shape of the device. Pixel values closer
|
|
40
|
-
to 1 indicate a higher likelihood of core material, while pixel values closer to 0
|
|
41
|
-
suggest a higher likelihood of cladding material. Pixel values in between represent
|
|
41
|
+
A numpy matrix representing the predicted shape of the device. Pixel values closer
|
|
42
|
+
to 1 indicate a higher likelihood of core material, while pixel values closer to 0
|
|
43
|
+
suggest a higher likelihood of cladding material. Pixel values in between represent
|
|
42
44
|
prediction uncertainty.
|
|
43
45
|
"""
|
|
44
|
-
function_url =
|
|
46
|
+
function_url = "https://prefab-photonics--predict.modal.run"
|
|
45
47
|
|
|
46
|
-
predict_data = {
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
predict_data = {
|
|
49
|
+
"device": _encode_image(device),
|
|
50
|
+
"model_name": model_name,
|
|
51
|
+
"model_tags": model_tags,
|
|
52
|
+
}
|
|
49
53
|
|
|
50
|
-
prediction = _decode_image(
|
|
54
|
+
prediction = _decode_image(
|
|
55
|
+
requests.post(function_url, json=predict_data, timeout=200)
|
|
56
|
+
)
|
|
51
57
|
|
|
52
58
|
if binarize:
|
|
53
59
|
prediction = binarize_hard(prediction)
|
|
54
60
|
|
|
55
61
|
return prediction
|
|
56
62
|
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
|
|
64
|
+
def correct(
|
|
65
|
+
device: np.ndarray, model_name: str, model_tags: str, binarize: bool = False
|
|
66
|
+
) -> np.ndarray:
|
|
59
67
|
"""
|
|
60
68
|
Generates a correction for a photonic device using a specified cloud-based ML model.
|
|
61
69
|
|
|
62
|
-
The function sends an image of the device to a cloud function, which uses the specified
|
|
70
|
+
The function sends an image of the device to a cloud function, which uses the specified
|
|
63
71
|
machine learning model to generate a correction.
|
|
64
72
|
|
|
65
73
|
Parameters
|
|
@@ -68,12 +76,12 @@ def correct(device: np.ndarray, model_name: str, model_tag: str,
|
|
|
68
76
|
A binary numpy matrix representing the shape of a device.
|
|
69
77
|
|
|
70
78
|
model_name : str
|
|
71
|
-
The name of the ML model to use for the correction.
|
|
79
|
+
The name of the ML model to use for the correction.
|
|
72
80
|
Consult the module's documentation for available models.
|
|
73
81
|
|
|
74
|
-
|
|
75
|
-
The
|
|
76
|
-
Consult the module's documentation for available
|
|
82
|
+
model_tags : Union[str, List[str]]
|
|
83
|
+
The tags of the ML model.
|
|
84
|
+
Consult the module's documentation for available tags.
|
|
77
85
|
|
|
78
86
|
binarize : bool, optional
|
|
79
87
|
If set to True, the correction will be binarized (default is False).
|
|
@@ -81,24 +89,29 @@ def correct(device: np.ndarray, model_name: str, model_tag: str,
|
|
|
81
89
|
Returns
|
|
82
90
|
-------
|
|
83
91
|
np.ndarray
|
|
84
|
-
A numpy matrix representing the corrected shape of the device. Pixel values closer
|
|
85
|
-
to 1 indicate a higher likelihood of core material, while pixel values closer to 0
|
|
86
|
-
suggest a higher likelihood of cladding material. Pixel values in between represent
|
|
92
|
+
A numpy matrix representing the corrected shape of the device. Pixel values closer
|
|
93
|
+
to 1 indicate a higher likelihood of core material, while pixel values closer to 0
|
|
94
|
+
suggest a higher likelihood of cladding material. Pixel values in between represent
|
|
87
95
|
correction uncertainty.
|
|
88
96
|
"""
|
|
89
|
-
function_url =
|
|
97
|
+
function_url = "https://prefab-photonics--correct.modal.run"
|
|
90
98
|
|
|
91
|
-
correct_data = {
|
|
92
|
-
|
|
93
|
-
|
|
99
|
+
correct_data = {
|
|
100
|
+
"device": _encode_image(device),
|
|
101
|
+
"model_name": model_name,
|
|
102
|
+
"model_tags": model_tags,
|
|
103
|
+
}
|
|
94
104
|
|
|
95
|
-
correction = _decode_image(
|
|
105
|
+
correction = _decode_image(
|
|
106
|
+
requests.post(function_url, json=correct_data, timeout=200)
|
|
107
|
+
)
|
|
96
108
|
|
|
97
109
|
if binarize:
|
|
98
110
|
correction = binarize_hard(correction)
|
|
99
111
|
|
|
100
112
|
return correction
|
|
101
113
|
|
|
114
|
+
|
|
102
115
|
def _encode_image(image: np.ndarray) -> str:
|
|
103
116
|
"""
|
|
104
117
|
Encodes a numpy image array to its base64 representation.
|
|
@@ -113,10 +126,11 @@ def _encode_image(image: np.ndarray) -> str:
|
|
|
113
126
|
str
|
|
114
127
|
The base64 encoded string of the image.
|
|
115
128
|
"""
|
|
116
|
-
encoded_image = imencode(
|
|
117
|
-
encoded_image_base64 = base64.b64encode(encoded_image).decode(
|
|
129
|
+
encoded_image = imencode(".png", 255 * image)[1].tobytes()
|
|
130
|
+
encoded_image_base64 = base64.b64encode(encoded_image).decode("utf-8")
|
|
118
131
|
return encoded_image_base64
|
|
119
132
|
|
|
133
|
+
|
|
120
134
|
def _decode_image(encoded_image_base64: str) -> np.ndarray:
|
|
121
135
|
"""
|
|
122
136
|
Decodes a base64 encoded image to its numpy array representation.
|
prefab/processor.py
CHANGED
|
@@ -13,10 +13,10 @@ def binarize(device: np.ndarray, eta: float = 0.5, beta: float = np.inf) -> np.n
|
|
|
13
13
|
"""
|
|
14
14
|
Applies soft binarization to a device image using a sigmoid function.
|
|
15
15
|
|
|
16
|
-
The binarization process can be controlled by adjusting the thresholding level (`eta`)
|
|
17
|
-
and the steepness of the sigmoid function (`beta`). `eta` influences the threshold level
|
|
18
|
-
for binarization, simulating under-etching for smaller values and over-etching for larger
|
|
19
|
-
values. `beta` controls the steepness of the sigmoid function, thereby determining the
|
|
16
|
+
The binarization process can be controlled by adjusting the thresholding level (`eta`)
|
|
17
|
+
and the steepness of the sigmoid function (`beta`). `eta` influences the threshold level
|
|
18
|
+
for binarization, simulating under-etching for smaller values and over-etching for larger
|
|
19
|
+
values. `beta` controls the steepness of the sigmoid function, thereby determining the
|
|
20
20
|
degree of binarization.
|
|
21
21
|
|
|
22
22
|
Parameters
|
|
@@ -28,7 +28,7 @@ def binarize(device: np.ndarray, eta: float = 0.5, beta: float = np.inf) -> np.n
|
|
|
28
28
|
Threshold level for binarization, with values between 0 and 1. Default is 0.5.
|
|
29
29
|
|
|
30
30
|
beta : float, optional
|
|
31
|
-
Controls the steepness of the sigmoid function and thereby the degree of
|
|
31
|
+
Controls the steepness of the sigmoid function and thereby the degree of
|
|
32
32
|
binarization. Default is infinity, resulting in maximum binarization.
|
|
33
33
|
|
|
34
34
|
Returns
|
|
@@ -36,8 +36,8 @@ def binarize(device: np.ndarray, eta: float = 0.5, beta: float = np.inf) -> np.n
|
|
|
36
36
|
np.ndarray
|
|
37
37
|
A 2D numpy array representing the binarized device image.
|
|
38
38
|
"""
|
|
39
|
-
numerator = np.tanh(beta*eta) + np.tanh(beta*(device - eta))
|
|
40
|
-
denominator = np.tanh(beta*eta) + np.tanh(beta*(1 - eta))
|
|
39
|
+
numerator = np.tanh(beta * eta) + np.tanh(beta * (device - eta))
|
|
40
|
+
denominator = np.tanh(beta * eta) + np.tanh(beta * (1 - eta))
|
|
41
41
|
device_bin = numerator / denominator
|
|
42
42
|
return device_bin
|
|
43
43
|
|
|
@@ -48,9 +48,9 @@ def binarize_hard(device: np.ndarray, eta: float = 0.5) -> np.ndarray:
|
|
|
48
48
|
|
|
49
49
|
The binarization process depends solely on the threshold level (`eta`), which
|
|
50
50
|
controls the demarcation point for determining the binary values in the output image.
|
|
51
|
-
Smaller `eta` values simulate under-etching (more pixels are turned off), while
|
|
51
|
+
Smaller `eta` values simulate under-etching (more pixels are turned off), while
|
|
52
52
|
larger `eta` values simulate over-etching (more pixels are turned on). Compared to the
|
|
53
|
-
sigmoid binarization function, this hard binarization method is less likely to produce
|
|
53
|
+
sigmoid binarization function, this hard binarization method is less likely to produce
|
|
54
54
|
NaN values and may sometimes yield better results.
|
|
55
55
|
|
|
56
56
|
Parameters
|
|
@@ -72,12 +72,46 @@ def binarize_hard(device: np.ndarray, eta: float = 0.5) -> np.ndarray:
|
|
|
72
72
|
return device_bin
|
|
73
73
|
|
|
74
74
|
|
|
75
|
+
def ternarize(device: np.ndarray, eta1: float = 0.33, eta2: float = 0.66) -> np.ndarray:
|
|
76
|
+
"""
|
|
77
|
+
Applies ternarization to a device image using two thresholds.
|
|
78
|
+
|
|
79
|
+
This function performs a ternarization process on a given device image, dividing it into three
|
|
80
|
+
distinct regions based on two threshold values (`eta1` and `eta2`). It assigns three different
|
|
81
|
+
values (0, 1, or 2) to each pixel based on its intensity in relation to the thresholds.
|
|
82
|
+
Pixels with intensity less than `eta1` are assigned 0, pixels with intensity greater than or
|
|
83
|
+
equal to `eta2` are assigned 2, and pixels with intensity between `eta1` and `eta2` are
|
|
84
|
+
assigned 1. This function can be useful for categorizing different regions in a device image.
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
device : np.ndarray
|
|
89
|
+
A 2D numpy array representing the grayscale device image to be ternarized.
|
|
90
|
+
|
|
91
|
+
eta1 : float, optional
|
|
92
|
+
First threshold level for ternarization, with values between 0 and 1. Default is 0.33.
|
|
93
|
+
|
|
94
|
+
eta2 : float, optional
|
|
95
|
+
Second threshold level for ternarization, with values between 0 and 1. Default is 0.66.
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
np.ndarray
|
|
100
|
+
A 2D numpy array representing the ternarized device image.
|
|
101
|
+
"""
|
|
102
|
+
device_ter = np.copy(device)
|
|
103
|
+
device_ter[device_ter < eta1] = 0
|
|
104
|
+
device_ter[device_ter >= eta2] = 1
|
|
105
|
+
device_ter[(device_ter >= eta1) & (device_ter < eta2)] = 0.5
|
|
106
|
+
return device_ter
|
|
107
|
+
|
|
108
|
+
|
|
75
109
|
def remove_padding(device: np.ndarray) -> np.ndarray:
|
|
76
110
|
"""
|
|
77
111
|
Removes the empty padding from the edges of a device.
|
|
78
112
|
|
|
79
|
-
This function eliminates rows and columns from the edges of the device matrix
|
|
80
|
-
that are entirely zeros, effectively removing any unnecessary padding present
|
|
113
|
+
This function eliminates rows and columns from the edges of the device matrix
|
|
114
|
+
that are entirely zeros, effectively removing any unnecessary padding present
|
|
81
115
|
in the device representation.
|
|
82
116
|
|
|
83
117
|
Parameters
|
|
@@ -92,8 +126,10 @@ def remove_padding(device: np.ndarray) -> np.ndarray:
|
|
|
92
126
|
of equal or smaller size compared to the input device.
|
|
93
127
|
"""
|
|
94
128
|
nonzero_rows, nonzero_cols = np.nonzero(device)
|
|
95
|
-
trimmed_device = device[
|
|
96
|
-
|
|
129
|
+
trimmed_device = device[
|
|
130
|
+
nonzero_rows.min() : nonzero_rows.max() + 1,
|
|
131
|
+
nonzero_cols.min() : nonzero_cols.max() + 1,
|
|
132
|
+
]
|
|
97
133
|
return trimmed_device
|
|
98
134
|
|
|
99
135
|
|
|
@@ -101,8 +137,8 @@ def zero_boundary(device: np.ndarray, margin: int) -> np.ndarray:
|
|
|
101
137
|
"""
|
|
102
138
|
Sets the boundaries of a device matrix to zero up to a specified margin.
|
|
103
139
|
|
|
104
|
-
This function zeroes the outermost rows and columns of the device matrix
|
|
105
|
-
up to a distance (margin) from the boundaries, effectively creating a
|
|
140
|
+
This function zeroes the outermost rows and columns of the device matrix
|
|
141
|
+
up to a distance (margin) from the boundaries, effectively creating a
|
|
106
142
|
"zeroed" frame around the device representation.
|
|
107
143
|
|
|
108
144
|
Parameters
|
|
@@ -116,7 +152,7 @@ def zero_boundary(device: np.ndarray, margin: int) -> np.ndarray:
|
|
|
116
152
|
Returns
|
|
117
153
|
-------
|
|
118
154
|
np.ndarray
|
|
119
|
-
A 2D numpy array representing the shape of the device with its outermost
|
|
155
|
+
A 2D numpy array representing the shape of the device with its outermost
|
|
120
156
|
rows and columns up to 'margin' distance set to zero.
|
|
121
157
|
"""
|
|
122
158
|
zeroed_device = device.copy()
|
|
@@ -127,12 +163,14 @@ def zero_boundary(device: np.ndarray, margin: int) -> np.ndarray:
|
|
|
127
163
|
return zeroed_device
|
|
128
164
|
|
|
129
165
|
|
|
130
|
-
def generate_device_contour(
|
|
166
|
+
def generate_device_contour(
|
|
167
|
+
device: np.ndarray, linewidth: Optional[int] = None
|
|
168
|
+
) -> np.ndarray:
|
|
131
169
|
"""
|
|
132
170
|
Generates a contour of a device for visualization purposes.
|
|
133
171
|
|
|
134
|
-
This function generates a binary contour of a device's shape which can be overlaid
|
|
135
|
-
on top of the device's image for better visualization. The thickness of the contour
|
|
172
|
+
This function generates a binary contour of a device's shape which can be overlaid
|
|
173
|
+
on top of the device's image for better visualization. The thickness of the contour
|
|
136
174
|
line can be specified, with a default value calculated as 1% of the device's height.
|
|
137
175
|
|
|
138
176
|
Parameters
|
|
@@ -141,7 +179,7 @@ def generate_device_contour(device: np.ndarray, linewidth: Optional[int] = None)
|
|
|
141
179
|
A 2D numpy array representing the device's shape.
|
|
142
180
|
|
|
143
181
|
linewidth : int, optional
|
|
144
|
-
The width of the contour line. If not provided, the linewidth is set
|
|
182
|
+
The width of the contour line. If not provided, the linewidth is set
|
|
145
183
|
to 1% of the device's height.
|
|
146
184
|
|
|
147
185
|
Returns
|
|
@@ -153,8 +191,9 @@ def generate_device_contour(device: np.ndarray, linewidth: Optional[int] = None)
|
|
|
153
191
|
linewidth = device.shape[0] // 100
|
|
154
192
|
|
|
155
193
|
binary_device = binarize_hard(device).astype(np.uint8)
|
|
156
|
-
contours, _ = cv2.findContours(
|
|
157
|
-
|
|
194
|
+
contours, _ = cv2.findContours(
|
|
195
|
+
binary_device, mode=cv2.RETR_CCOMP, method=cv2.CHAIN_APPROX_SIMPLE
|
|
196
|
+
)
|
|
158
197
|
|
|
159
198
|
contour_overlay = np.zeros_like(device)
|
|
160
199
|
cv2.drawContours(contour_overlay, contours, -1, (255, 255, 255), linewidth)
|
|
@@ -166,11 +205,11 @@ def calculate_prediction_uncertainty(prediction: np.ndarray) -> np.ndarray:
|
|
|
166
205
|
"""
|
|
167
206
|
Computes the uncertainty profile of a non-binary prediction matrix.
|
|
168
207
|
|
|
169
|
-
This function quantifies the level of uncertainty in a given prediction matrix by
|
|
170
|
-
identifying the areas between the core (value 1) and cladding (value 0). These regions
|
|
171
|
-
often correspond to the boundaries of the predicted structure and are represented by
|
|
172
|
-
pixel values ranging between 0 and 1 in the prediction matrix. The function calculates
|
|
173
|
-
the uncertainty as the distance from the pixel value to the nearest extreme (0 or 1),
|
|
208
|
+
This function quantifies the level of uncertainty in a given prediction matrix by
|
|
209
|
+
identifying the areas between the core (value 1) and cladding (value 0). These regions
|
|
210
|
+
often correspond to the boundaries of the predicted structure and are represented by
|
|
211
|
+
pixel values ranging between 0 and 1 in the prediction matrix. The function calculates
|
|
212
|
+
the uncertainty as the distance from the pixel value to the nearest extreme (0 or 1),
|
|
174
213
|
highlighting regions of maximum uncertainty.
|
|
175
214
|
|
|
176
215
|
Parameters
|
|
@@ -181,13 +220,14 @@ def calculate_prediction_uncertainty(prediction: np.ndarray) -> np.ndarray:
|
|
|
181
220
|
Returns
|
|
182
221
|
-------
|
|
183
222
|
np.ndarray
|
|
184
|
-
A 2D numpy array (same shape as the input prediction matrix) representing the
|
|
185
|
-
uncertainty profile of the prediction. Higher values correspond to areas of higher
|
|
223
|
+
A 2D numpy array (same shape as the input prediction matrix) representing the
|
|
224
|
+
uncertainty profile of the prediction. Higher values correspond to areas of higher
|
|
186
225
|
uncertainty.
|
|
187
226
|
"""
|
|
188
227
|
uncertainty = 1 - 2 * np.abs(0.5 - prediction)
|
|
189
228
|
return uncertainty
|
|
190
229
|
|
|
230
|
+
|
|
191
231
|
def mse(prediction: np.ndarray, device: np.ndarray) -> float:
|
|
192
232
|
"""
|
|
193
233
|
Computes the mean squared error (MSE) between a prediction and a device matrix.
|
|
@@ -205,4 +245,4 @@ def mse(prediction: np.ndarray, device: np.ndarray) -> float:
|
|
|
205
245
|
float
|
|
206
246
|
The mean squared error between the prediction and device matrices.
|
|
207
247
|
"""
|
|
208
|
-
return np.mean((prediction - device)**2)
|
|
248
|
+
return np.mean((prediction - device) ** 2)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: prefab
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.5
|
|
4
4
|
Summary: Machine learning based prediction of photonic device fabrication
|
|
5
5
|
Project-URL: Homepage, https://github.com/PreFab-Photonics/PreFab
|
|
6
6
|
Author-email: Dusan Gostimirovic <dusan@prefabphotonics.com>
|
|
@@ -525,7 +525,7 @@ Description-Content-Type: text/markdown
|
|
|
525
525
|
|
|
526
526
|

|
|
527
527
|
|
|
528
|
-
`PreFab` leverages **deep learning** to model fabrication-induced structural variations in integrated photonic devices. Through this
|
|
528
|
+
`PreFab` leverages **deep learning** to model fabrication-induced structural variations in integrated photonic devices. Through this _virtual nanofabrication environment_, we uncover valuable insights into nanofabrication processes and enhance device design accuracy.
|
|
529
529
|
|
|
530
530
|
## Prediction
|
|
531
531
|
|
|
@@ -541,16 +541,16 @@ Description-Content-Type: text/markdown
|
|
|
541
541
|
|
|
542
542
|
## Models
|
|
543
543
|
|
|
544
|
-
`PreFab` accommodates unique
|
|
544
|
+
`PreFab` accommodates unique _predictor_ and _corrector_ models for each photonic foundry, regularly updated based on recent fabrication data. Current models include (see full list on [`docs/models.md`](docs/models.md)):
|
|
545
545
|
|
|
546
|
-
| Foundry
|
|
547
|
-
|
|
|
548
|
-
| ANT
|
|
549
|
-
| ANT
|
|
550
|
-
| ANT
|
|
551
|
-
| SiEPICfab | [SOI](https://siepic.ca/fabrication/)
|
|
546
|
+
| Foundry | Process | Latest Version | Latest Dataset | Model Name | Model Tag | Status |
|
|
547
|
+
| --------- | ---------------------------------------------------------------------------------- | --------------- | ---------------- | ------------- | ----------- | ------ |
|
|
548
|
+
| ANT | [NanoSOI](https://www.appliednt.com/nanosoi-fabrication-service/) | v5 (Jun 3 2023) | d4 (Apr 12 2023) | ANT_NanoSOI | v5-d4 | Beta |
|
|
549
|
+
| ANT | [SiN (Upper Edge)](https://www.appliednt.com/nanosoi/sys/resources/specs_nitride/) | v5 (Jun 3 2023) | d0 (Jun 1 2023) | ANT_SiN | v5-d0-upper | Alpha |
|
|
550
|
+
| ANT | [SiN (Lower Edge)](https://www.appliednt.com/nanosoi/sys/resources/specs_nitride/) | v5 (Jun 3 2023) | d0 (Jun 1 2023) | ANT_SiN | v5-d0-lower | Alpha |
|
|
551
|
+
| SiEPICfab | [SOI](https://siepic.ca/fabrication/) | v5 (Jun 3 2023) | d0 (Jun 14 2023) | SiEPICfab_SOI | v5-d0 | Alpha |
|
|
552
552
|
|
|
553
|
-
|
|
553
|
+
_New models and foundries are regularly added. Usage may change. For additional foundry and process models, feel free to contact us or raise an issue._
|
|
554
554
|
|
|
555
555
|
## Installation
|
|
556
556
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
prefab/__init__.py,sha256=0r0FhWL0XnAE_rq9OuqrNsXNOWjU8eI3-wMvHVDBHWc,1461
|
|
2
|
+
prefab/io.py,sha256=lSjtxbk3YmWhG816Ok-LgjMceZIU1lRZy7pWaPlCpF4,6007
|
|
3
|
+
prefab/predictor.py,sha256=BvcmoUuN3g_MNb9IichHMmueqQILnQK7U8LureMXJec,4562
|
|
4
|
+
prefab/processor.py,sha256=lmSOTouyFOb8UZo7JLXi78VjdUz6eJoOyPZMn6IKraw,8996
|
|
5
|
+
prefab-0.4.5.dist-info/METADATA,sha256=GNbIUFC4ZQZZO0KEHxnVxnn6SxXMbczdrdhnjUZpXHw,35014
|
|
6
|
+
prefab-0.4.5.dist-info/WHEEL,sha256=mRYSEL3Ih6g5a_CVMIcwiF__0Ae4_gLYh01YFNwiq1k,87
|
|
7
|
+
prefab-0.4.5.dist-info/licenses/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
|
|
8
|
+
prefab-0.4.5.dist-info/RECORD,,
|
prefab-0.4.2.dist-info/RECORD
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
prefab/__init__.py,sha256=6PDbpXSExwKQHTl9AxJeSrB8EOPYcHCgq_7zsFcmGBY,1488
|
|
2
|
-
prefab/io.py,sha256=1pkSb8OEz2woqYo81mJ-EgRqsLfh21YtvIi5OuSlZVk,5326
|
|
3
|
-
prefab/predictor.py,sha256=fc7LRJgTc8SIm-bpNEoDspgth2Fd0k6UTdkAdgbmwBQ,4556
|
|
4
|
-
prefab/processor.py,sha256=DH8IX7fx_TMbnvfjfR-acy-JAnYz1efxdQHgLFgF9_k,7580
|
|
5
|
-
prefab-0.4.2.dist-info/METADATA,sha256=y3P_3VSWthzRd3vmD0bu-Wslz3_1JKQIVm6jvJhuaiU,34731
|
|
6
|
-
prefab-0.4.2.dist-info/WHEEL,sha256=9QBuHhg6FNW7lppboF2vKVbCGTVzsFykgRQjjlajrhA,87
|
|
7
|
-
prefab-0.4.2.dist-info/licenses/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
|
|
8
|
-
prefab-0.4.2.dist-info/RECORD,,
|
|
File without changes
|