prefab 1.1.2__py3-none-any.whl → 1.1.4__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
@@ -5,9 +5,9 @@ Usage:
5
5
  import prefab as pf
6
6
  """
7
7
 
8
- __version__ = "1.1.2"
8
+ __version__ = "1.1.4"
9
9
 
10
- from . import compare, geometry, read, shapes
10
+ from . import compare, geometry, predict, read, shapes
11
11
  from .device import BufferSpec, Device
12
12
  from .models import models
13
13
 
@@ -15,6 +15,7 @@ __all__ = [
15
15
  "Device",
16
16
  "BufferSpec",
17
17
  "geometry",
18
+ "predict",
18
19
  "read",
19
20
  "shapes",
20
21
  "compare",
prefab/device.py CHANGED
@@ -1,27 +1,21 @@
1
1
  """Provides the Device class for representing photonic devices."""
2
2
 
3
- import base64
4
- import io
5
- import json
6
- import os
7
3
  from typing import Optional
8
4
 
9
5
  import cv2
10
6
  import gdstk
11
7
  import matplotlib.pyplot as plt
12
8
  import numpy as np
13
- import requests
14
- import toml
15
9
  from matplotlib.axes import Axes
16
10
  from matplotlib.patches import Rectangle
17
11
  from PIL import Image
18
12
  from pydantic import BaseModel, Field, conint, root_validator, validator
19
13
  from scipy.ndimage import distance_transform_edt
20
14
  from skimage import measure
21
- from tqdm import tqdm
22
15
 
23
16
  from . import compare, geometry
24
17
  from .models import Model
18
+ from .predict import predict_array
25
19
 
26
20
  Image.MAX_IMAGE_PIXELS = None
27
21
 
@@ -210,147 +204,6 @@ class Device(BaseModel):
210
204
  or np.array_equal(unique_values, [1])
211
205
  )
212
206
 
213
- def _encode_array(self, array):
214
- image = Image.fromarray(np.uint8(array * 255))
215
- buffered = io.BytesIO()
216
- image.save(buffered, format="PNG")
217
- encoded_png = base64.b64encode(buffered.getvalue()).decode("utf-8")
218
- return encoded_png
219
-
220
- def _decode_array(self, encoded_png):
221
- binary_data = base64.b64decode(encoded_png)
222
- image = Image.open(io.BytesIO(binary_data))
223
- return np.array(image) / 255
224
-
225
- def _predict_array(
226
- self,
227
- model: Model,
228
- model_type: str,
229
- binarize: bool,
230
- gpu: bool = False,
231
- ) -> "Device":
232
- try:
233
- with open(os.path.expanduser("~/.prefab.toml")) as file:
234
- content = file.readlines()
235
- access_token = None
236
- refresh_token = None
237
- for line in content:
238
- if "access_token" in line:
239
- access_token = line.split("=")[1].strip().strip('"')
240
- if "refresh_token" in line:
241
- refresh_token = line.split("=")[1].strip().strip('"')
242
- break
243
- if not access_token or not refresh_token:
244
- raise ValueError("Token not found in the configuration file.")
245
- except FileNotFoundError:
246
- raise FileNotFoundError(
247
- "Could not validate user.\n"
248
- "Please update prefab using: pip install --upgrade prefab.\n"
249
- "Signup/login and generate a new token.\n"
250
- "See https://www.prefabphotonics.com/docs/guides/quickstart."
251
- ) from None
252
-
253
- headers = {
254
- "Authorization": f"Bearer {access_token}",
255
- "X-Refresh-Token": refresh_token,
256
- }
257
-
258
- predict_data = {
259
- "device_array": self._encode_array(self.device_array[:, :, 0]),
260
- "model": model.to_json(),
261
- "model_type": model_type,
262
- "binary": binarize,
263
- }
264
- json_data = json.dumps(predict_data)
265
-
266
- endpoint_url = (
267
- "https://prefab-photonics--predict-gpu-v1.modal.run"
268
- if gpu
269
- else "https://prefab-photonics--predict-v1.modal.run"
270
- )
271
-
272
- try:
273
- with requests.post(
274
- endpoint_url, data=json_data, headers=headers, stream=True
275
- ) as response:
276
- response.raise_for_status()
277
- event_type = None
278
- model_descriptions = {
279
- "p": "Prediction",
280
- "c": "Correction",
281
- "s": "SEMulate",
282
- }
283
- progress_bar = tqdm(
284
- total=100,
285
- desc=f"{model_descriptions[model_type]}",
286
- unit="%",
287
- colour="green",
288
- bar_format="{l_bar}{bar:30}{r_bar}{bar:-10b}",
289
- )
290
-
291
- for line in response.iter_lines():
292
- if line:
293
- decoded_line = line.decode("utf-8").strip()
294
- if decoded_line.startswith("event:"):
295
- event_type = decoded_line.split(":")[1].strip()
296
- elif decoded_line.startswith("data:"):
297
- try:
298
- data_content = json.loads(
299
- decoded_line.split("data: ")[1]
300
- )
301
- if event_type == "progress":
302
- progress = round(100 * data_content["progress"])
303
- progress_bar.update(progress - progress_bar.n)
304
- elif event_type == "result":
305
- results = []
306
- for key in sorted(data_content.keys()):
307
- if key.startswith("result"):
308
- decoded_image = self._decode_array(
309
- data_content[key]
310
- )
311
- results.append(decoded_image)
312
-
313
- if results:
314
- prediction = np.stack(results, axis=-1)
315
- if binarize:
316
- prediction = geometry.binarize_hard(
317
- prediction
318
- )
319
- progress_bar.close()
320
- return prediction
321
- elif event_type == "end":
322
- print("Stream ended.")
323
- progress_bar.close()
324
- break
325
- elif event_type == "auth":
326
- if "new_refresh_token" in data_content["auth"]:
327
- prefab_file_path = os.path.expanduser(
328
- "~/.prefab.toml"
329
- )
330
- with open(
331
- prefab_file_path, "w", encoding="utf-8"
332
- ) as toml_file:
333
- toml.dump(
334
- {
335
- "access_token": data_content[
336
- "auth"
337
- ]["new_access_token"],
338
- "refresh_token": data_content[
339
- "auth"
340
- ]["new_refresh_token"],
341
- },
342
- toml_file,
343
- )
344
- elif event_type == "error":
345
- raise ValueError(f"{data_content['error']}")
346
- except json.JSONDecodeError:
347
- raise ValueError(
348
- "Failed to decode JSON:",
349
- decoded_line.split("data: ")[1],
350
- ) from None
351
- except requests.RequestException as e:
352
- raise RuntimeError(f"Request failed: {e}") from e
353
-
354
207
  def predict(
355
208
  self,
356
209
  model: Model,
@@ -393,7 +246,8 @@ class Device(BaseModel):
393
246
  If the prediction service returns an error or if the response from the
394
247
  service cannot be processed correctly.
395
248
  """
396
- prediction_array = self._predict_array(
249
+ prediction_array = predict_array(
250
+ device_array=self.device_array,
397
251
  model=model,
398
252
  model_type="p",
399
253
  binarize=binarize,
@@ -445,7 +299,8 @@ class Device(BaseModel):
445
299
  If the correction service returns an error or if the response from the
446
300
  service cannot be processed correctly.
447
301
  """
448
- correction_array = self._predict_array(
302
+ correction_array = predict_array(
303
+ device_array=self.device_array,
449
304
  model=model,
450
305
  model_type="c",
451
306
  binarize=binarize,
@@ -487,7 +342,8 @@ class Device(BaseModel):
487
342
  A new instance of the Device class with its geometry transformed to simulate
488
343
  an SEM image style.
489
344
  """
490
- semulated_array = self._predict_array(
345
+ semulated_array = predict_array(
346
+ device_array=self.device_array,
491
347
  model=model,
492
348
  model_type="s",
493
349
  binarize=False,
@@ -550,6 +406,7 @@ class Device(BaseModel):
550
406
  cell_name: str = "prefab_device",
551
407
  gds_layer: tuple[int, int] = (1, 0),
552
408
  contour_approx_mode: int = 2,
409
+ origin: tuple[float, float] = (0.0, 0.0),
553
410
  ):
554
411
  """
555
412
  Exports the device geometry as a GDSII file.
@@ -572,11 +429,15 @@ class Device(BaseModel):
572
429
  The mode of contour approximation used during the conversion. Defaults to 2,
573
430
  which corresponds to `cv2.CHAIN_APPROX_SIMPLE`, a method that compresses
574
431
  horizontal, vertical, and diagonal segments and leaves only their endpoints.
432
+ origin : tuple[float, float], optional
433
+ The x and y coordinates of the origin for the GDSII export. Defaults to
434
+ (0.0, 0.0).
575
435
  """
576
436
  gdstk_cell = self.flatten()._device_to_gdstk(
577
437
  cell_name=cell_name,
578
438
  gds_layer=gds_layer,
579
439
  contour_approx_mode=contour_approx_mode,
440
+ origin=origin,
580
441
  )
581
442
  print(f"Saving GDS to '{gds_path}'...")
582
443
  gdstk_library = gdstk.Library()
@@ -588,6 +449,7 @@ class Device(BaseModel):
588
449
  cell_name: str = "prefab_device",
589
450
  gds_layer: tuple[int, int] = (1, 0),
590
451
  contour_approx_mode: int = 2,
452
+ origin: tuple[float, float] = (0.0, 0.0),
591
453
  ):
592
454
  """
593
455
  Converts the device geometry to a GDSTK cell object.
@@ -607,6 +469,9 @@ class Device(BaseModel):
607
469
  The mode of contour approximation used during the conversion. Defaults to 2,
608
470
  which corresponds to `cv2.CHAIN_APPROX_SIMPLE`, a method that compresses
609
471
  horizontal, vertical, and diagonal segments and leaves only their endpoints.
472
+ origin : tuple[float, float], optional
473
+ The x and y coordinates of the origin for the GDSTK cell. Defaults to
474
+ (0.0, 0.0).
610
475
 
611
476
  Returns
612
477
  -------
@@ -618,6 +483,7 @@ class Device(BaseModel):
618
483
  cell_name=cell_name,
619
484
  gds_layer=gds_layer,
620
485
  contour_approx_mode=contour_approx_mode,
486
+ origin=origin,
621
487
  )
622
488
  return gdstk_cell
623
489
 
@@ -626,6 +492,7 @@ class Device(BaseModel):
626
492
  cell_name: str,
627
493
  gds_layer: tuple[int, int],
628
494
  contour_approx_mode: int,
495
+ origin: tuple[float, float],
629
496
  ) -> gdstk.Cell:
630
497
  approx_mode_mapping = {
631
498
  1: cv2.CHAIN_APPROX_NONE,
@@ -662,8 +529,21 @@ class Device(BaseModel):
662
529
  polygons_to_process = hierarchy_polygons[level]
663
530
 
664
531
  if polygons_to_process:
532
+ center_x_nm = self.device_array.shape[1] / 2
533
+ center_y_nm = self.device_array.shape[0] / 2
534
+
535
+ center_x_um = center_x_nm / 1000
536
+ center_y_um = center_y_nm / 1000
537
+
538
+ adjusted_polygons = [
539
+ [
540
+ (x - center_x_um + origin[0], y - center_y_um + origin[1])
541
+ for x, y in polygon
542
+ ]
543
+ for polygon in polygons_to_process
544
+ ]
665
545
  processed_polygons = gdstk.boolean(
666
- polygons_to_process,
546
+ adjusted_polygons,
667
547
  processed_polygons,
668
548
  operation,
669
549
  layer=gds_layer[0],
@@ -1313,13 +1193,6 @@ class Device(BaseModel):
1313
1193
  """
1314
1194
  Trim the device geometry by removing empty space around it.
1315
1195
 
1316
- Parameters
1317
- ----------
1318
- buffer_thickness : dict, optional
1319
- A dictionary specifying the thickness of the buffer to leave around the
1320
- non-zero elements of the array. Should contain keys 'top', 'bottom', 'left',
1321
- 'right'. Defaults to None, which means no buffer is added.
1322
-
1323
1196
  Returns
1324
1197
  -------
1325
1198
  Device
@@ -1414,15 +1287,10 @@ class Device(BaseModel):
1414
1287
  Flatten the device geometry by summing the vertical layers and normalizing the
1415
1288
  result.
1416
1289
 
1417
- Parameters
1418
- ----------
1419
- device_array : np.ndarray
1420
- The input array to be flattened.
1421
-
1422
1290
  Returns
1423
1291
  -------
1424
- np.ndarray
1425
- The flattened array with values scaled between 0 and 1.
1292
+ Device
1293
+ A new instance of the Device with the flattened geometry.
1426
1294
  """
1427
1295
  flattened_device_array = geometry.flatten(device_array=self.device_array)
1428
1296
  return self.model_copy(update={"device_array": flattened_device_array})
prefab/models.py CHANGED
@@ -10,7 +10,7 @@ class Fab(BaseModel):
10
10
  """
11
11
  Represents a fabrication process in the PreFab model library.
12
12
 
13
- Parameters
13
+ Attributes
14
14
  ----------
15
15
  foundry : str
16
16
  The name of the foundry where the fabrication process takes place.
prefab/predict.py ADDED
@@ -0,0 +1,307 @@
1
+ """Provides prediction functions for ndarrays of device geometries."""
2
+
3
+ import base64
4
+ import io
5
+ import json
6
+ import os
7
+
8
+ import numpy as np
9
+ import requests
10
+ import toml
11
+ from autograd import primitive
12
+ from autograd.extend import defvjp
13
+ from PIL import Image
14
+ from tqdm import tqdm
15
+
16
+ from .geometry import binarize_hard
17
+ from .models import Model
18
+
19
+ BASE_URL = "https://prefab-photonics--predict"
20
+
21
+
22
+ def predict_array(
23
+ device_array: np.ndarray,
24
+ model: Model,
25
+ model_type: str,
26
+ binarize: bool,
27
+ gpu: bool = False,
28
+ ) -> np.ndarray:
29
+ """
30
+ Predict the nanofabrication outcome of a device array using a specified model.
31
+
32
+ This function sends the device array to a serverless prediction service, which uses
33
+ a specified machine learning model to predict the outcome of the nanofabrication
34
+ process. The prediction can be performed on a GPU if specified.
35
+
36
+ Parameters
37
+ ----------
38
+ device_array : np.ndarray
39
+ A 2D array representing the planar geometry of the device. This array undergoes
40
+ various transformations to predict the nanofabrication process.
41
+ model : Model
42
+ The model to use for prediction, representing a specific fabrication process and
43
+ dataset. This model encapsulates details about the fabrication foundry, process,
44
+ material, technology, thickness, and sidewall presence, as defined in
45
+ `models.py`. Each model is associated with a version and dataset that detail its
46
+ creation and the data it was trained on, ensuring the prediction is tailored to
47
+ specific fabrication parameters.
48
+ model_type : str
49
+ The type of model to use (e.g., 'p', 'c', 's').
50
+ binarize : bool
51
+ If True, the predicted device geometry will be binarized using a threshold
52
+ method. This is useful for converting probabilistic predictions into binary
53
+ geometries.
54
+ gpu : bool, optional
55
+ If True, the prediction will be performed on a GPU. Defaults to False. Note: The
56
+ GPU option has more overhead and will take longer for small devices, but will be
57
+ faster for larger devices.
58
+
59
+ Returns
60
+ -------
61
+ np.ndarray
62
+ The predicted output array.
63
+
64
+ Raises
65
+ ------
66
+ RuntimeError
67
+ If the request to the prediction service fails.
68
+ """
69
+ headers = _prepare_headers()
70
+ predict_data = _prepare_predict_data(device_array, model, model_type, binarize)
71
+ endpoint_url = f"{BASE_URL}-gpu-v1.modal.run" if gpu else f"{BASE_URL}-v1.modal.run"
72
+
73
+ try:
74
+ with requests.post(
75
+ endpoint_url,
76
+ data=json.dumps(predict_data),
77
+ headers=headers,
78
+ stream=True,
79
+ ) as response:
80
+ response.raise_for_status()
81
+ return _process_response(response, model_type, binarize)
82
+ except requests.RequestException as e:
83
+ raise RuntimeError(f"Request failed: {e}") from e
84
+
85
+
86
+ def _predict_array_with_grad(
87
+ device_array: np.ndarray, model: Model
88
+ ) -> tuple[np.ndarray, np.ndarray]:
89
+ headers = _prepare_headers()
90
+ predict_data = _prepare_predict_data(device_array, model, "p", False)
91
+ endpoint_url = f"{BASE_URL}-with-grad-v1.modal.run"
92
+
93
+ response = requests.post(
94
+ endpoint_url, data=json.dumps(predict_data), headers=headers
95
+ )
96
+ prediction_array = _decode_array(response.json()["prediction_array"])
97
+ gradient_array = _decode_array(response.json()["gradient_array"])
98
+ gradient_min = response.json()["gradient_min"]
99
+ gradient_max = response.json()["gradient_max"]
100
+ gradient_range = gradient_max - gradient_min
101
+ gradient_array = gradient_array * gradient_range + gradient_min
102
+
103
+ return (prediction_array, gradient_array)
104
+
105
+
106
+ @primitive
107
+ def predict_array_with_grad(device_array: np.ndarray, model: Model) -> np.ndarray:
108
+ """
109
+ Predict the nanofabrication outcome of a device array and compute its gradient.
110
+
111
+ This function predicts the outcome of the nanofabrication process for a given
112
+ device array using a specified model. It also computes the gradient of the
113
+ prediction with respect to the input device array.
114
+
115
+ Parameters
116
+ ----------
117
+ device_array : np.ndarray
118
+ A 2D array representing the planar geometry of the device.
119
+ model : Model
120
+ The model to use for prediction, representing a specific fabrication process.
121
+
122
+ Returns
123
+ -------
124
+ np.ndarray
125
+ The predicted output array.
126
+ """
127
+ prediction_array, gradient_array = _predict_array_with_grad(
128
+ device_array=device_array, model=model
129
+ )
130
+ predict_array_with_grad.gradient_array = gradient_array
131
+ return prediction_array
132
+
133
+
134
+ def predict_array_with_grad_vjp(ans: np.ndarray, x: np.ndarray, model: Model):
135
+ """
136
+ Define the vector-Jacobian product (VJP) for the prediction function.
137
+
138
+ This function provides the VJP for the `predict_array_with_grad` function,
139
+ which is used in reverse-mode automatic differentiation to compute gradients.
140
+
141
+ Parameters
142
+ ----------
143
+ ans : np.ndarray
144
+ The output of the `predict_array_with_grad` function.
145
+ x : np.ndarray
146
+ The input device array for which the gradient is computed.
147
+ model : Model
148
+ The model used for prediction.
149
+
150
+ Returns
151
+ -------
152
+ function
153
+ A function that computes the VJP given an upstream gradient `g`.
154
+ """
155
+ grad_x = predict_array_with_grad.gradient_array
156
+
157
+ def vjp(g: np.ndarray) -> np.ndarray:
158
+ return g * grad_x
159
+
160
+ return vjp
161
+
162
+
163
+ defvjp(predict_array_with_grad, predict_array_with_grad_vjp)
164
+
165
+
166
+ def _encode_array(array):
167
+ """Encode an ndarray as a base64 encoded image for transmission."""
168
+ image = Image.fromarray(np.uint8(array * 255))
169
+ buffered = io.BytesIO()
170
+ image.save(buffered, format="PNG")
171
+ encoded_png = base64.b64encode(buffered.getvalue()).decode("utf-8")
172
+ return encoded_png
173
+
174
+
175
+ def _decode_array(encoded_png):
176
+ """Decode a base64 encoded image and return an ndarray."""
177
+ binary_data = base64.b64decode(encoded_png)
178
+ image = Image.open(io.BytesIO(binary_data))
179
+ return np.array(image) / 255
180
+
181
+
182
+ def _read_tokens():
183
+ """Read access and refresh tokens from the configuration file."""
184
+ token_file_path = os.path.expanduser("~/.prefab.toml")
185
+ try:
186
+ with open(token_file_path) as file:
187
+ tokens = toml.load(file)
188
+ access_token = tokens.get("access_token")
189
+ refresh_token = tokens.get("refresh_token")
190
+ if not access_token or not refresh_token:
191
+ raise ValueError("Tokens not found in the configuration file.")
192
+ return access_token, refresh_token
193
+ except FileNotFoundError:
194
+ raise FileNotFoundError(
195
+ "Could not validate user.\n"
196
+ "Please update prefab using: pip install --upgrade prefab.\n"
197
+ "Signup/login and generate a new token.\n"
198
+ "See https://www.prefabphotonics.com/docs/guides/quickstart."
199
+ ) from None
200
+
201
+
202
+ def _prepare_headers():
203
+ """Prepare HTTP headers for the request."""
204
+ access_token, refresh_token = _read_tokens()
205
+ return {
206
+ "Authorization": f"Bearer {access_token}",
207
+ "X-Refresh-Token": refresh_token,
208
+ }
209
+
210
+
211
+ def _prepare_predict_data(device_array, model, model_type, binarize):
212
+ """Prepare the data payload for the prediction request."""
213
+ return {
214
+ "device_array": _encode_array(np.squeeze(device_array)),
215
+ "model": model.to_json(),
216
+ "model_type": model_type,
217
+ "binary": binarize,
218
+ }
219
+
220
+
221
+ def _process_response(response, model_type, binarize):
222
+ """Process the streaming response from the prediction request."""
223
+ event_type = None
224
+ model_descriptions = {
225
+ "p": "Prediction",
226
+ "c": "Correction",
227
+ "s": "SEMulate",
228
+ }
229
+ progress_bar = tqdm(
230
+ total=100,
231
+ desc=model_descriptions.get(model_type, "Processing"),
232
+ unit="%",
233
+ colour="green",
234
+ bar_format="{l_bar}{bar:30}{r_bar}{bar:-10b}",
235
+ )
236
+
237
+ for line in response.iter_lines():
238
+ if line:
239
+ decoded_line = line.decode("utf-8").strip()
240
+ if decoded_line.startswith("event:"):
241
+ event_type = decoded_line.split(":", 1)[1].strip()
242
+ elif decoded_line.startswith("data:"):
243
+ data_content = _parse_data_line(decoded_line)
244
+ result = _handle_event(event_type, data_content, progress_bar, binarize)
245
+ if result is not None:
246
+ progress_bar.close()
247
+ return result
248
+ progress_bar.close()
249
+
250
+
251
+ def _parse_data_line(decoded_line):
252
+ """Parse a data line from the response stream."""
253
+ data_line = decoded_line.split(":", 1)[1].strip()
254
+ try:
255
+ return json.loads(data_line)
256
+ except json.JSONDecodeError:
257
+ raise ValueError(f"Failed to decode JSON: {data_line}") from None
258
+
259
+
260
+ def _handle_event(event_type, data_content, progress_bar, binarize):
261
+ """Handle different types of events received from the server."""
262
+ if event_type == "progress":
263
+ _update_progress(progress_bar, data_content)
264
+ elif event_type == "result":
265
+ return _process_result(data_content, binarize)
266
+ elif event_type == "end":
267
+ print("Stream ended.")
268
+ elif event_type == "auth":
269
+ _update_tokens(data_content.get("auth", {}))
270
+ elif event_type == "error":
271
+ raise ValueError(f"{data_content['error']}")
272
+
273
+
274
+ def _update_progress(progress_bar, data_content):
275
+ """Update the progress bar based on the progress event."""
276
+ progress = round(100 * data_content.get("progress", 0))
277
+ progress_bar.update(progress - progress_bar.n)
278
+
279
+
280
+ def _process_result(data_content, binarize):
281
+ """Process the result event and return the prediction."""
282
+ results = [
283
+ _decode_array(data_content[key])
284
+ for key in sorted(data_content.keys())
285
+ if key.startswith("result")
286
+ ]
287
+ if results:
288
+ prediction = np.stack(results, axis=-1)
289
+ if binarize:
290
+ prediction = binarize_hard(prediction)
291
+ return prediction
292
+
293
+
294
+ def _update_tokens(auth_data):
295
+ """Update tokens if new tokens are provided in the auth event."""
296
+ new_access_token = auth_data.get("new_access_token")
297
+ new_refresh_token = auth_data.get("new_refresh_token")
298
+ if new_access_token and new_refresh_token:
299
+ prefab_file_path = os.path.expanduser("~/.prefab.toml")
300
+ with open(prefab_file_path, "w", encoding="utf-8") as toml_file:
301
+ toml.dump(
302
+ {
303
+ "access_token": new_access_token,
304
+ "refresh_token": new_refresh_token,
305
+ },
306
+ toml_file,
307
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: prefab
3
- Version: 1.1.2
3
+ Version: 1.1.4
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
@@ -0,0 +1,13 @@
1
+ prefab/__init__.py,sha256=7MmkG6X6FZ7c4lS8eAF5cNu_NYnwIeDVgwCiX9ysYPw,425
2
+ prefab/__main__.py,sha256=aAgt1WXa44k1nJqsiSD3uAfNeGpwtjWqMUYCHN5_Qrw,2759
3
+ prefab/compare.py,sha256=2MKUT7N2A639tUGCnJHpfF9MmS-v3oARDkTqHbWJ9OM,3239
4
+ prefab/device.py,sha256=l0etqB0559xa9Frb0IKl5N3kU56vWHlwHc-qehINTlw,52292
5
+ prefab/geometry.py,sha256=0sa6ietUWZGkxOnUPUzD3q2QpFuOpWkSANoopGpPd6s,11035
6
+ prefab/models.py,sha256=JpBqNFIqbo1ymKEl0NWWF4ZkhvK23rEVVBEFl05TXCI,3671
7
+ prefab/predict.py,sha256=upGTeNC6vY9Tdko6JEM0gKQH1PGUVYXACpep1OT8EVs,10593
8
+ prefab/read.py,sha256=MuF-cugFQ7MWBJ8DOvQuwktIk0fJ8PXBeLye0ydrB8o,14734
9
+ prefab/shapes.py,sha256=2qaqyNzu5WG3wVdk4oQzeNXmhwXRHcPnRZlgRrM4MoA,25576
10
+ prefab-1.1.4.dist-info/METADATA,sha256=FDqQukBN09Eg4BDhn7Q7p46nWOoLwxjWk9CP2VeRoxo,34824
11
+ prefab-1.1.4.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
12
+ prefab-1.1.4.dist-info/licenses/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
13
+ prefab-1.1.4.dist-info/RECORD,,
@@ -1,12 +0,0 @@
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,,
File without changes