prefab 0.4.3__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 CHANGED
@@ -13,22 +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, # 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 gdspy 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, # 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
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
32
32
  )
33
33
 
34
34
  __all__ = (
@@ -43,5 +43,5 @@ __all__ = (
43
43
  "zero_boundary",
44
44
  "generate_device_contour",
45
45
  "calculate_prediction_uncertainty",
46
- "mse"
46
+ "mse",
47
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 gdspy
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(path: str, cell_name: str,
45
- coords: Optional[List[List[int]]] = None) -> np.ndarray:
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 first layer (silicon) is loaded.
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 = gdspy.GdsLibrary(infile=path)
71
- cell = gds.cells[cell_name]
72
- polygons = cell.get_polygons(by_spec=(1, 0))
73
- bounds = 1000 * cell.get_bounding_box()
74
- device = np.zeros((int(bounds[1][1] - bounds[0][1]),
75
- int(bounds[1][0] - bounds[0][0])))
76
-
77
- contours = [np.array([[[int(1000*vertex[0] - bounds[0][0]),
78
- int(1000*vertex[1] - bounds[0][1])]] for vertex in polygon],
79
- dtype=np.int32)
80
- for polygon in polygons]
81
-
82
- for contour in contours:
83
- cv2.fillPoly(img=device, pts=[contour], color=(1, 1, 1))
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
- device = device[int(coords[0][1] - bounds[0][1]):int(coords[1][1] - bounds[0][1]),
87
- int(coords[0][0] - bounds[0][0]):int(coords[1][0] - bounds[0][0])]
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(device: np.ndarray, cell_name: str, library: gdspy.GdsLibrary,
95
- resolution: float = 1.0, layer: int = 1, approximation_mode: int = 2) -> gdspy.Cell:
96
- """Converts a device layout to a gdspy cell for GDSII export.
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 : gdspy.GdsLibrary
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
- The GDSII layer to be used for the polygons. Default is 1.
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
- gdspy.Cell
160
+ gdstk.Cell
125
161
  The newly created cell containing the device layout.
126
162
  """
127
- approximation_method_mapping = {1: cv2.CHAIN_APPROX_NONE,
128
- 2: cv2.CHAIN_APPROX_SIMPLE,
129
- 3: cv2.CHAIN_APPROX_TC89_L1,
130
- 4: cv2.CHAIN_APPROX_TC89_KCOS}
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(device.astype(np.uint8), cv2.RETR_CCOMP,
134
- approximation_method_mapping[approximation_mode])
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 = gdspy.boolean(outer_polygons, inner_polygons, 'xor', layer=layer)
150
- polygons.scale(resolution, resolution)
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
- cell.add(polygons)
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
- def predict(device: np.ndarray, model_name: str, model_tags: str,
13
- binarize: bool = False) -> np.ndarray:
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,11 +25,11 @@ def predict(device: np.ndarray, model_name: str, model_tags: 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
31
  model_tags : Union[str, List[str]]
30
- The tags of the ML model.
32
+ The tags of the ML model.
31
33
  Consult the module's documentation for available tags.
32
34
 
33
35
  binarize : bool, optional
@@ -36,30 +38,36 @@ def predict(device: np.ndarray, model_name: str, model_tags: 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 = 'https://prefab-photonics--predict.modal.run'
46
+ function_url = "https://prefab-photonics--predict.modal.run"
45
47
 
46
- predict_data = {'device': _encode_image(device),
47
- 'model_name': model_name,
48
- 'model_tags': model_tags}
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(requests.post(function_url, json=predict_data, timeout=200))
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
- def correct(device: np.ndarray, model_name: str, model_tags: str,
58
- binarize: bool = False) -> np.ndarray:
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,11 +76,11 @@ def correct(device: np.ndarray, model_name: str, model_tags: 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
82
  model_tags : Union[str, List[str]]
75
- The tags of the ML model.
83
+ The tags of the ML model.
76
84
  Consult the module's documentation for available tags.
77
85
 
78
86
  binarize : bool, optional
@@ -81,24 +89,29 @@ def correct(device: np.ndarray, model_name: str, model_tags: 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 = 'https://prefab-photonics--correct.modal.run'
97
+ function_url = "https://prefab-photonics--correct.modal.run"
90
98
 
91
- correct_data = {'device': _encode_image(device),
92
- 'model_name': model_name,
93
- 'model_tags': model_tags}
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(requests.post(function_url, json=correct_data, timeout=200))
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('.png', 255 * image)[1].tobytes()
117
- encoded_image_base64 = base64.b64encode(encoded_image).decode('utf-8')
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
@@ -79,8 +79,8 @@ def ternarize(device: np.ndarray, eta1: float = 0.33, eta2: float = 0.66) -> np.
79
79
  This function performs a ternarization process on a given device image, dividing it into three
80
80
  distinct regions based on two threshold values (`eta1` and `eta2`). It assigns three different
81
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
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
84
  assigned 1. This function can be useful for categorizing different regions in a device image.
85
85
 
86
86
  Parameters
@@ -110,8 +110,8 @@ def remove_padding(device: np.ndarray) -> np.ndarray:
110
110
  """
111
111
  Removes the empty padding from the edges of a device.
112
112
 
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
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
115
115
  in the device representation.
116
116
 
117
117
  Parameters
@@ -126,8 +126,10 @@ def remove_padding(device: np.ndarray) -> np.ndarray:
126
126
  of equal or smaller size compared to the input device.
127
127
  """
128
128
  nonzero_rows, nonzero_cols = np.nonzero(device)
129
- trimmed_device = device[nonzero_rows.min():nonzero_rows.max()+1,
130
- nonzero_cols.min():nonzero_cols.max()+1]
129
+ trimmed_device = device[
130
+ nonzero_rows.min() : nonzero_rows.max() + 1,
131
+ nonzero_cols.min() : nonzero_cols.max() + 1,
132
+ ]
131
133
  return trimmed_device
132
134
 
133
135
 
@@ -135,8 +137,8 @@ def zero_boundary(device: np.ndarray, margin: int) -> np.ndarray:
135
137
  """
136
138
  Sets the boundaries of a device matrix to zero up to a specified margin.
137
139
 
138
- This function zeroes the outermost rows and columns of the device matrix
139
- 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
140
142
  "zeroed" frame around the device representation.
141
143
 
142
144
  Parameters
@@ -150,7 +152,7 @@ def zero_boundary(device: np.ndarray, margin: int) -> np.ndarray:
150
152
  Returns
151
153
  -------
152
154
  np.ndarray
153
- 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
154
156
  rows and columns up to 'margin' distance set to zero.
155
157
  """
156
158
  zeroed_device = device.copy()
@@ -161,12 +163,14 @@ def zero_boundary(device: np.ndarray, margin: int) -> np.ndarray:
161
163
  return zeroed_device
162
164
 
163
165
 
164
- def generate_device_contour(device: np.ndarray, linewidth: Optional[int] = None) -> np.ndarray:
166
+ def generate_device_contour(
167
+ device: np.ndarray, linewidth: Optional[int] = None
168
+ ) -> np.ndarray:
165
169
  """
166
170
  Generates a contour of a device for visualization purposes.
167
171
 
168
- This function generates a binary contour of a device's shape which can be overlaid
169
- 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
170
174
  line can be specified, with a default value calculated as 1% of the device's height.
171
175
 
172
176
  Parameters
@@ -175,7 +179,7 @@ def generate_device_contour(device: np.ndarray, linewidth: Optional[int] = None)
175
179
  A 2D numpy array representing the device's shape.
176
180
 
177
181
  linewidth : int, optional
178
- 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
179
183
  to 1% of the device's height.
180
184
 
181
185
  Returns
@@ -187,8 +191,9 @@ def generate_device_contour(device: np.ndarray, linewidth: Optional[int] = None)
187
191
  linewidth = device.shape[0] // 100
188
192
 
189
193
  binary_device = binarize_hard(device).astype(np.uint8)
190
- contours, _ = cv2.findContours(binary_device, mode=cv2.RETR_CCOMP,
191
- method=cv2.CHAIN_APPROX_SIMPLE)
194
+ contours, _ = cv2.findContours(
195
+ binary_device, mode=cv2.RETR_CCOMP, method=cv2.CHAIN_APPROX_SIMPLE
196
+ )
192
197
 
193
198
  contour_overlay = np.zeros_like(device)
194
199
  cv2.drawContours(contour_overlay, contours, -1, (255, 255, 255), linewidth)
@@ -200,11 +205,11 @@ def calculate_prediction_uncertainty(prediction: np.ndarray) -> np.ndarray:
200
205
  """
201
206
  Computes the uncertainty profile of a non-binary prediction matrix.
202
207
 
203
- This function quantifies the level of uncertainty in a given prediction matrix by
204
- identifying the areas between the core (value 1) and cladding (value 0). These regions
205
- often correspond to the boundaries of the predicted structure and are represented by
206
- pixel values ranging between 0 and 1 in the prediction matrix. The function calculates
207
- 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),
208
213
  highlighting regions of maximum uncertainty.
209
214
 
210
215
  Parameters
@@ -215,13 +220,14 @@ def calculate_prediction_uncertainty(prediction: np.ndarray) -> np.ndarray:
215
220
  Returns
216
221
  -------
217
222
  np.ndarray
218
- A 2D numpy array (same shape as the input prediction matrix) representing the
219
- 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
220
225
  uncertainty.
221
226
  """
222
227
  uncertainty = 1 - 2 * np.abs(0.5 - prediction)
223
228
  return uncertainty
224
229
 
230
+
225
231
  def mse(prediction: np.ndarray, device: np.ndarray) -> float:
226
232
  """
227
233
  Computes the mean squared error (MSE) between a prediction and a device matrix.
@@ -239,4 +245,4 @@ def mse(prediction: np.ndarray, device: np.ndarray) -> float:
239
245
  float
240
246
  The mean squared error between the prediction and device matrices.
241
247
  """
242
- 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
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
  ![PreFab logo](https://github.com/PreFab-Photonics/PreFab/blob/main/assets/logo.png?raw=true)
527
527
 
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.
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 *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)):
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 | 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 |
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
- *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.*
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,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.18.0
2
+ Generator: hatchling 1.21.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,8 +0,0 @@
1
- prefab/__init__.py,sha256=W2zDXR-7KOezjTVyxuZDSL5NgIoEv8q2Yp57x9dy4tc,1576
2
- prefab/io.py,sha256=1pkSb8OEz2woqYo81mJ-EgRqsLfh21YtvIi5OuSlZVk,5326
3
- prefab/predictor.py,sha256=Ms7ApFO6to8mAuOuhGqtHUpTiJFyzJqZdCuCdHrsWpE,4572
4
- prefab/processor.py,sha256=zY0OPjjUXR_be2QKmwuFsbYs6yla7c5n0WMz7jhTtvE,9022
5
- prefab-0.4.3.dist-info/METADATA,sha256=nSumNEM-RO7KQTWCLOgJTcjRWGICozL4funoQ4NKrzI,34731
6
- prefab-0.4.3.dist-info/WHEEL,sha256=9QBuHhg6FNW7lppboF2vKVbCGTVzsFykgRQjjlajrhA,87
7
- prefab-0.4.3.dist-info/licenses/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
8
- prefab-0.4.3.dist-info/RECORD,,