prefab 1.0.2__py3-none-any.whl → 1.0.3__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 +5 -1
- prefab/compare.py +22 -20
- prefab/device.py +62 -36
- prefab/geometry.py +21 -15
- prefab/models.py +31 -1
- prefab/read.py +45 -22
- prefab/shapes.py +765 -0
- {prefab-1.0.2.dist-info → prefab-1.0.3.dist-info}/METADATA +7 -5
- prefab-1.0.3.dist-info/RECORD +12 -0
- prefab-1.0.2.dist-info/RECORD +0 -11
- {prefab-1.0.2.dist-info → prefab-1.0.3.dist-info}/WHEEL +0 -0
- {prefab-1.0.2.dist-info → prefab-1.0.3.dist-info}/licenses/LICENSE +0 -0
prefab/shapes.py
ADDED
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
"""Contains functions for creating various shapes as Device objects."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from skimage.draw import polygon
|
|
5
|
+
|
|
6
|
+
from .device import Device
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def rectangle(width: int = 200, height: int = 100, **kwargs) -> Device:
|
|
10
|
+
"""
|
|
11
|
+
Create a Device object with a rectangular shape.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
width : int, optional
|
|
16
|
+
The width of the rectangle. Defaults to 200.
|
|
17
|
+
height : int, optional
|
|
18
|
+
The height of the rectangle. Defaults to 100.
|
|
19
|
+
**kwargs : dict
|
|
20
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
Device
|
|
25
|
+
A Device object containing the rectangular shape.
|
|
26
|
+
"""
|
|
27
|
+
rectangle = np.zeros((height, width))
|
|
28
|
+
rectangle[:, :] = 1
|
|
29
|
+
return Device(device_array=rectangle, **kwargs)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def box(width: int = 200, **kwargs) -> Device:
|
|
33
|
+
"""
|
|
34
|
+
Create a Device object with a square box shape.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
width : int, optional
|
|
39
|
+
The width and height of the square box. Defaults to 200.
|
|
40
|
+
**kwargs : dict
|
|
41
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
Device
|
|
46
|
+
A Device object containing the square box shape.
|
|
47
|
+
"""
|
|
48
|
+
box = np.zeros((width, width))
|
|
49
|
+
box[:, :] = 1
|
|
50
|
+
return Device(device_array=box, **kwargs)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def cross(width: int = 200, arm_width: int = 60, **kwargs) -> Device:
|
|
54
|
+
"""
|
|
55
|
+
Create a Device object with a cross shape.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
width : int, optional
|
|
60
|
+
The overall width and height of the cross. Defaults to 200.
|
|
61
|
+
arm_width : int, optional
|
|
62
|
+
The width of the cross arms. Defaults to 60.
|
|
63
|
+
**kwargs : dict
|
|
64
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
65
|
+
|
|
66
|
+
Returns
|
|
67
|
+
-------
|
|
68
|
+
Device
|
|
69
|
+
A Device object containing the cross shape.
|
|
70
|
+
"""
|
|
71
|
+
cross = np.zeros((width, width))
|
|
72
|
+
center = width // 2
|
|
73
|
+
half_arm_width = arm_width // 2
|
|
74
|
+
cross[center - half_arm_width : center + half_arm_width + 1, :] = 1
|
|
75
|
+
cross[:, center - half_arm_width : center + half_arm_width + 1] = 1
|
|
76
|
+
return Device(device_array=cross, **kwargs)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def target(width: int = 200, arm_width: int = 60, **kwargs) -> Device:
|
|
80
|
+
"""
|
|
81
|
+
Create a Device object with a target shape (cross with center removed).
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
width : int, optional
|
|
86
|
+
The overall width and height of the target. Defaults to 200.
|
|
87
|
+
arm_width : int, optional
|
|
88
|
+
The width of the target arms. Defaults to 60.
|
|
89
|
+
**kwargs : dict
|
|
90
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
Device
|
|
95
|
+
A Device object containing the target shape.
|
|
96
|
+
"""
|
|
97
|
+
target = np.zeros((width, width))
|
|
98
|
+
center = width // 2
|
|
99
|
+
half_arm_width = arm_width // 2
|
|
100
|
+
target[center - half_arm_width : center + half_arm_width + 1, :] = 1
|
|
101
|
+
target[:, center - half_arm_width : center + half_arm_width + 1] = 1
|
|
102
|
+
target[
|
|
103
|
+
center - half_arm_width : center + half_arm_width + 1,
|
|
104
|
+
center - half_arm_width : center + half_arm_width + 1,
|
|
105
|
+
] = 0
|
|
106
|
+
return Device(device_array=target, **kwargs)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def window(width: int = 200, border_width: int = 60, **kwargs) -> Device:
|
|
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
|
+
"""
|
|
137
|
+
Create a Device object with an elliptical shape.
|
|
138
|
+
|
|
139
|
+
Parameters
|
|
140
|
+
----------
|
|
141
|
+
width : int, optional
|
|
142
|
+
The width of the ellipse. Defaults to 200.
|
|
143
|
+
height : int, optional
|
|
144
|
+
The height of the ellipse. Defaults to 100.
|
|
145
|
+
**kwargs : dict
|
|
146
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
Device
|
|
151
|
+
A Device object containing the elliptical shape.
|
|
152
|
+
"""
|
|
153
|
+
y, x = np.ogrid[-height // 2 : height // 2, -width // 2 : width // 2]
|
|
154
|
+
mask = (x**2 / (width // 2) ** 2) + (y**2 / (height // 2) ** 2) <= 1
|
|
155
|
+
ellipse = np.zeros((height, width))
|
|
156
|
+
ellipse[mask] = 1
|
|
157
|
+
return Device(device_array=ellipse, **kwargs)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def circle(width: int = 200, **kwargs) -> Device:
|
|
161
|
+
"""
|
|
162
|
+
Create a Device object with a circular shape.
|
|
163
|
+
|
|
164
|
+
Parameters
|
|
165
|
+
----------
|
|
166
|
+
width : int, optional
|
|
167
|
+
The width and height of the circle. Defaults to 200.
|
|
168
|
+
**kwargs : dict
|
|
169
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
170
|
+
|
|
171
|
+
Returns
|
|
172
|
+
-------
|
|
173
|
+
Device
|
|
174
|
+
A Device object containing the circular shape.
|
|
175
|
+
"""
|
|
176
|
+
radius = width // 2
|
|
177
|
+
y, x = np.ogrid[-radius:radius, -radius:radius]
|
|
178
|
+
mask = x**2 + y**2 <= radius**2
|
|
179
|
+
circle = np.zeros((width, width))
|
|
180
|
+
circle[mask] = 1
|
|
181
|
+
return Device(device_array=circle, **kwargs)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def circle_wavy(
|
|
185
|
+
width: int = 200, wave_amplitude: float = 10, wave_frequency: float = 10, **kwargs
|
|
186
|
+
) -> Device:
|
|
187
|
+
"""
|
|
188
|
+
Create a Device object with a circular shape with wavy edges.
|
|
189
|
+
|
|
190
|
+
Parameters
|
|
191
|
+
----------
|
|
192
|
+
width : int, optional
|
|
193
|
+
The overall width and height of the wavy circle. Defaults to 200.
|
|
194
|
+
wave_amplitude : float, optional
|
|
195
|
+
The amplitude of the waves. Defaults to 10.
|
|
196
|
+
wave_frequency : float, optional
|
|
197
|
+
The frequency of the waves. Defaults to 10.
|
|
198
|
+
**kwargs : dict
|
|
199
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
200
|
+
|
|
201
|
+
Returns
|
|
202
|
+
-------
|
|
203
|
+
Device
|
|
204
|
+
A Device object containing the wavy circular shape.
|
|
205
|
+
"""
|
|
206
|
+
effective_radius = (width // 2) - wave_amplitude
|
|
207
|
+
y, x = np.ogrid[-width // 2 : width // 2, -width // 2 : width // 2]
|
|
208
|
+
distance_from_center = np.sqrt(x**2 + y**2)
|
|
209
|
+
sinusoidal_boundary = effective_radius + wave_amplitude * np.sin(
|
|
210
|
+
wave_frequency * np.arctan2(y, x)
|
|
211
|
+
)
|
|
212
|
+
mask = distance_from_center <= sinusoidal_boundary
|
|
213
|
+
circle_wavy = np.zeros((width, width))
|
|
214
|
+
circle_wavy[mask] = 1
|
|
215
|
+
return Device(device_array=circle_wavy, **kwargs)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def pie(width: int = 200, arc_angle: float = 270, **kwargs) -> Device:
|
|
219
|
+
"""
|
|
220
|
+
Create a Device object with a pie shape.
|
|
221
|
+
|
|
222
|
+
Parameters
|
|
223
|
+
----------
|
|
224
|
+
width : int, optional
|
|
225
|
+
The width and height of the pie. Defaults to 200.
|
|
226
|
+
arc_angle : float, optional
|
|
227
|
+
The angle of the pie slice in degrees. Defaults to 270.
|
|
228
|
+
**kwargs : dict
|
|
229
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
230
|
+
|
|
231
|
+
Returns
|
|
232
|
+
-------
|
|
233
|
+
Device
|
|
234
|
+
A Device object containing the pie shape.
|
|
235
|
+
"""
|
|
236
|
+
radius = width // 2
|
|
237
|
+
y, x = np.ogrid[-radius:radius, -radius:radius]
|
|
238
|
+
angle = np.arctan2(y, x) * 180 / np.pi
|
|
239
|
+
angle = (angle + 360) % 360
|
|
240
|
+
mask = (x**2 + y**2 <= radius**2) & (angle <= arc_angle)
|
|
241
|
+
pie = np.zeros((width, width))
|
|
242
|
+
pie[mask] = 1
|
|
243
|
+
return Device(device_array=pie, **kwargs)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def grating(
|
|
247
|
+
height: int = 200,
|
|
248
|
+
pitch: int = 120,
|
|
249
|
+
duty_cycle: float = 0.5,
|
|
250
|
+
num_gratings: int = 3,
|
|
251
|
+
**kwargs,
|
|
252
|
+
) -> Device:
|
|
253
|
+
"""
|
|
254
|
+
Create a Device object with a grating pattern.
|
|
255
|
+
|
|
256
|
+
Parameters
|
|
257
|
+
----------
|
|
258
|
+
height : int, optional
|
|
259
|
+
The height of the grating. Defaults to 200.
|
|
260
|
+
pitch : int, optional
|
|
261
|
+
The pitch (period) of the grating. Defaults to 120.
|
|
262
|
+
duty_cycle : float, optional
|
|
263
|
+
The duty cycle of the grating. Defaults to 0.5.
|
|
264
|
+
num_gratings : int, optional
|
|
265
|
+
The number of grating periods. Defaults to 3.
|
|
266
|
+
**kwargs : dict
|
|
267
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
268
|
+
|
|
269
|
+
Returns
|
|
270
|
+
-------
|
|
271
|
+
Device
|
|
272
|
+
A Device object containing the grating pattern.
|
|
273
|
+
"""
|
|
274
|
+
width = pitch * num_gratings - pitch // 2
|
|
275
|
+
grating = np.zeros((height, width))
|
|
276
|
+
grating_width = int(pitch * duty_cycle)
|
|
277
|
+
for i in range(num_gratings):
|
|
278
|
+
start = i * pitch
|
|
279
|
+
grating[:, start : start + grating_width] = 1
|
|
280
|
+
return Device(device_array=grating, **kwargs)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def star(width: int = 200, num_points: int = 5, **kwargs) -> Device:
|
|
284
|
+
"""
|
|
285
|
+
Create a Device object with a star shape.
|
|
286
|
+
|
|
287
|
+
Parameters
|
|
288
|
+
----------
|
|
289
|
+
width : int, optional
|
|
290
|
+
The overall width and height of the star. Defaults to 200.
|
|
291
|
+
num_points : int, optional
|
|
292
|
+
The number of points on the star. Defaults to 5.
|
|
293
|
+
**kwargs : dict
|
|
294
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
295
|
+
|
|
296
|
+
Returns
|
|
297
|
+
-------
|
|
298
|
+
Device
|
|
299
|
+
A Device object containing the star shape.
|
|
300
|
+
"""
|
|
301
|
+
radius_outer = width // 2
|
|
302
|
+
radius_inner = radius_outer // 2
|
|
303
|
+
angles_outer = np.linspace(0, 2 * np.pi, num_points, endpoint=False) - np.pi / 2
|
|
304
|
+
angles_inner = angles_outer + np.pi / num_points
|
|
305
|
+
x_outer = (radius_outer * np.cos(angles_outer) + radius_outer).astype(int)
|
|
306
|
+
y_outer = (radius_outer * np.sin(angles_outer) + radius_outer).astype(int)
|
|
307
|
+
x_inner = (radius_inner * np.cos(angles_inner) + radius_outer).astype(int)
|
|
308
|
+
y_inner = (radius_inner * np.sin(angles_inner) + radius_outer).astype(int)
|
|
309
|
+
x = np.empty(2 * num_points, dtype=int)
|
|
310
|
+
y = np.empty(2 * num_points, dtype=int)
|
|
311
|
+
x[0::2] = x_outer
|
|
312
|
+
x[1::2] = x_inner
|
|
313
|
+
y[0::2] = y_outer
|
|
314
|
+
y[1::2] = y_inner
|
|
315
|
+
star = np.zeros((width, width))
|
|
316
|
+
rr, cc = polygon(y, x)
|
|
317
|
+
rr = np.clip(rr, 0, width - 1)
|
|
318
|
+
cc = np.clip(cc, 0, width - 1)
|
|
319
|
+
star[rr, cc] = 1
|
|
320
|
+
return Device(device_array=star, **kwargs)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def poly(width: int = 200, num_points: int = 5, **kwargs) -> Device:
|
|
324
|
+
"""
|
|
325
|
+
Create a Device object with a regular polygon shape.
|
|
326
|
+
|
|
327
|
+
Parameters
|
|
328
|
+
----------
|
|
329
|
+
width : int, optional
|
|
330
|
+
The overall width and height of the polygon. Defaults to 200.
|
|
331
|
+
num_points : int, optional
|
|
332
|
+
The number of sides of the polygon. Defaults to 5.
|
|
333
|
+
**kwargs : dict
|
|
334
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
335
|
+
|
|
336
|
+
Returns
|
|
337
|
+
-------
|
|
338
|
+
Device
|
|
339
|
+
A Device object containing the regular polygon shape.
|
|
340
|
+
"""
|
|
341
|
+
radius = width // 2
|
|
342
|
+
angles = np.linspace(0, 2 * np.pi, num_points, endpoint=False) - np.pi / 2
|
|
343
|
+
x = (radius * np.cos(angles) + radius).astype(int)
|
|
344
|
+
y = (radius * np.sin(angles) + radius).astype(int)
|
|
345
|
+
poly = np.zeros((width, width))
|
|
346
|
+
rr, cc = polygon(y, x)
|
|
347
|
+
rr = np.clip(rr, 0, width - 1)
|
|
348
|
+
cc = np.clip(cc, 0, width - 1)
|
|
349
|
+
poly[rr, cc] = 1
|
|
350
|
+
return Device(device_array=poly, **kwargs)
|
|
351
|
+
|
|
352
|
+
|
|
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
|
+
def radial_grating(
|
|
384
|
+
width: int = 200, grating_skew: int = 0, num_gratings: int = 6, **kwargs
|
|
385
|
+
) -> Device:
|
|
386
|
+
"""
|
|
387
|
+
Create a Device object with a radial grating pattern.
|
|
388
|
+
|
|
389
|
+
Parameters
|
|
390
|
+
----------
|
|
391
|
+
width : int, optional
|
|
392
|
+
The overall width and height of the radial grating. Defaults to 200.
|
|
393
|
+
grating_skew : int, optional
|
|
394
|
+
The skew angle of the grating arms. Defaults to 0.
|
|
395
|
+
num_gratings : int, optional
|
|
396
|
+
The number of grating arms. Defaults to 6.
|
|
397
|
+
**kwargs : dict
|
|
398
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
399
|
+
|
|
400
|
+
Returns
|
|
401
|
+
-------
|
|
402
|
+
Device
|
|
403
|
+
A Device object containing the radial grating pattern.
|
|
404
|
+
"""
|
|
405
|
+
radial_grating = np.zeros((width, width))
|
|
406
|
+
center = width // 2
|
|
407
|
+
radius = center
|
|
408
|
+
theta = np.linspace(0, 2 * np.pi, num_gratings, endpoint=False)
|
|
409
|
+
for angle in theta:
|
|
410
|
+
x0, y0 = center, center
|
|
411
|
+
x1 = int(center + radius * np.cos(angle))
|
|
412
|
+
y1 = int(center + radius * np.sin(angle))
|
|
413
|
+
x2 = int(
|
|
414
|
+
center + (radius - grating_skew) * np.cos(angle + np.pi / num_gratings)
|
|
415
|
+
)
|
|
416
|
+
y2 = int(
|
|
417
|
+
center + (radius - grating_skew) * np.sin(angle + np.pi / num_gratings)
|
|
418
|
+
)
|
|
419
|
+
rr, cc = polygon([y0, y1, y2], [x0, x1, x2])
|
|
420
|
+
rr = np.clip(rr, 0, width - 1)
|
|
421
|
+
cc = np.clip(cc, 0, width - 1)
|
|
422
|
+
radial_grating[rr, cc] = 1
|
|
423
|
+
return Device(device_array=radial_grating, **kwargs)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def offset_grating(
|
|
427
|
+
height: int = 200,
|
|
428
|
+
pitch: int = 120,
|
|
429
|
+
duty_cycle: float = 0.5,
|
|
430
|
+
num_gratings: int = 3,
|
|
431
|
+
**kwargs,
|
|
432
|
+
) -> Device:
|
|
433
|
+
"""
|
|
434
|
+
Create a Device object with an offset grating pattern (alternating rows).
|
|
435
|
+
|
|
436
|
+
Parameters
|
|
437
|
+
----------
|
|
438
|
+
height : int, optional
|
|
439
|
+
The height of the grating. Defaults to 200.
|
|
440
|
+
pitch : int, optional
|
|
441
|
+
The pitch (period) of the grating. Defaults to 120.
|
|
442
|
+
duty_cycle : float, optional
|
|
443
|
+
The duty cycle of the grating. Defaults to 0.5.
|
|
444
|
+
num_gratings : int, optional
|
|
445
|
+
The number of grating periods. Defaults to 3.
|
|
446
|
+
**kwargs : dict
|
|
447
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
448
|
+
|
|
449
|
+
Returns
|
|
450
|
+
-------
|
|
451
|
+
Device
|
|
452
|
+
A Device object containing the offset grating pattern.
|
|
453
|
+
"""
|
|
454
|
+
width = pitch * num_gratings
|
|
455
|
+
grating = np.zeros((height, width))
|
|
456
|
+
grating_width = int(pitch * duty_cycle)
|
|
457
|
+
half_height = height // 2
|
|
458
|
+
for i in range(num_gratings):
|
|
459
|
+
start = i * pitch
|
|
460
|
+
grating[half_height:, start : start + grating_width] = 1
|
|
461
|
+
for i in range(num_gratings):
|
|
462
|
+
start = i * pitch + pitch // 2
|
|
463
|
+
grating[:half_height, start : start + grating_width] = 1
|
|
464
|
+
return Device(device_array=grating, **kwargs)
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
def L_grating(
|
|
468
|
+
height: int = 200,
|
|
469
|
+
pitch: int = 100,
|
|
470
|
+
duty_cycle: float = 0.5,
|
|
471
|
+
**kwargs,
|
|
472
|
+
) -> Device:
|
|
473
|
+
"""
|
|
474
|
+
Create a Device object with an L-shaped grating pattern.
|
|
475
|
+
|
|
476
|
+
Parameters
|
|
477
|
+
----------
|
|
478
|
+
height : int, optional
|
|
479
|
+
The height and width of the L-grating. Defaults to 200.
|
|
480
|
+
pitch : int, optional
|
|
481
|
+
The pitch (period) of the L-shapes. Defaults to 100.
|
|
482
|
+
duty_cycle : float, optional
|
|
483
|
+
The duty cycle of the L-shapes. Defaults to 0.5.
|
|
484
|
+
**kwargs : dict
|
|
485
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
486
|
+
|
|
487
|
+
Returns
|
|
488
|
+
-------
|
|
489
|
+
Device
|
|
490
|
+
A Device object containing the L-shaped grating pattern.
|
|
491
|
+
"""
|
|
492
|
+
L_grating = np.zeros((height, height))
|
|
493
|
+
num_L_shapes = height // pitch
|
|
494
|
+
L_width = int(pitch * duty_cycle)
|
|
495
|
+
for i in range(num_L_shapes):
|
|
496
|
+
start = i * pitch
|
|
497
|
+
L_grating[start : start + L_width, start:] = 1
|
|
498
|
+
L_grating[start:, start : start + L_width] = 1
|
|
499
|
+
return Device(device_array=L_grating, **kwargs)
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def circles(
|
|
503
|
+
rows: int = 5, cols: int = 5, radius: int = 30, spacing: int = 60, **kwargs
|
|
504
|
+
) -> Device:
|
|
505
|
+
"""
|
|
506
|
+
Create a Device object with a grid of uniform circles.
|
|
507
|
+
|
|
508
|
+
Parameters
|
|
509
|
+
----------
|
|
510
|
+
rows : int, optional
|
|
511
|
+
The number of rows in the grid. Defaults to 5.
|
|
512
|
+
cols : int, optional
|
|
513
|
+
The number of columns in the grid. Defaults to 5.
|
|
514
|
+
radius : int, optional
|
|
515
|
+
The radius of each circle. Defaults to 30.
|
|
516
|
+
spacing : int, optional
|
|
517
|
+
The spacing between circle centers. Defaults to 60.
|
|
518
|
+
**kwargs : dict
|
|
519
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
520
|
+
|
|
521
|
+
Returns
|
|
522
|
+
-------
|
|
523
|
+
Device
|
|
524
|
+
A Device object containing a grid of circles.
|
|
525
|
+
"""
|
|
526
|
+
grid_height = rows * (2 * radius + spacing) - spacing
|
|
527
|
+
grid_width = cols * (2 * radius + spacing) - spacing
|
|
528
|
+
circles = np.zeros((grid_height, grid_width))
|
|
529
|
+
y, x = np.ogrid[-radius:radius, -radius:radius]
|
|
530
|
+
mask = x**2 + y**2 <= radius**2
|
|
531
|
+
for row in range(rows):
|
|
532
|
+
for col in range(cols):
|
|
533
|
+
center_y = row * (2 * radius + spacing) + radius
|
|
534
|
+
center_x = col * (2 * radius + spacing) + radius
|
|
535
|
+
circles[
|
|
536
|
+
center_y - radius : center_y + radius,
|
|
537
|
+
center_x - radius : center_x + radius,
|
|
538
|
+
][mask] = 1
|
|
539
|
+
return Device(device_array=circles, **kwargs)
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
def circles_offset(
|
|
543
|
+
rows: int = 5, cols: int = 5, radius: int = 30, spacing: int = 30, **kwargs
|
|
544
|
+
) -> Device:
|
|
545
|
+
"""
|
|
546
|
+
Create a Device object with an offset grid of circles.
|
|
547
|
+
|
|
548
|
+
Parameters
|
|
549
|
+
----------
|
|
550
|
+
rows : int, optional
|
|
551
|
+
The number of rows in the grid. Defaults to 5.
|
|
552
|
+
cols : int, optional
|
|
553
|
+
The number of columns in the grid. Defaults to 5.
|
|
554
|
+
radius : int, optional
|
|
555
|
+
The radius of each circle. Defaults to 30.
|
|
556
|
+
spacing : int, optional
|
|
557
|
+
The spacing between circle centers. Defaults to 30.
|
|
558
|
+
**kwargs : dict
|
|
559
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
560
|
+
|
|
561
|
+
Returns
|
|
562
|
+
-------
|
|
563
|
+
Device
|
|
564
|
+
A Device object containing an offset grid of circles.
|
|
565
|
+
"""
|
|
566
|
+
grid_height = rows * (2 * radius + spacing) - spacing
|
|
567
|
+
grid_width = cols * (2 * radius + spacing) - spacing + (radius + spacing // 2)
|
|
568
|
+
circles_offset = np.zeros((grid_height, grid_width))
|
|
569
|
+
y, x = np.ogrid[-radius:radius, -radius:radius]
|
|
570
|
+
mask = x**2 + y**2 <= radius**2
|
|
571
|
+
for row in range(rows):
|
|
572
|
+
for col in range(cols):
|
|
573
|
+
center_y = row * (2 * radius + spacing) + radius
|
|
574
|
+
center_x = (
|
|
575
|
+
col * (2 * radius + spacing)
|
|
576
|
+
+ radius
|
|
577
|
+
+ (radius + spacing // 2 if row % 2 == 1 else 0)
|
|
578
|
+
)
|
|
579
|
+
circles_offset[
|
|
580
|
+
center_y - radius : center_y + radius,
|
|
581
|
+
center_x - radius : center_x + radius,
|
|
582
|
+
][mask] = 1
|
|
583
|
+
return Device(device_array=circles_offset, **kwargs)
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
def circles_varying(
|
|
587
|
+
rows: int = 5,
|
|
588
|
+
cols: int = 5,
|
|
589
|
+
min_radius: int = 10,
|
|
590
|
+
max_radius: int = 30,
|
|
591
|
+
spacing: int = 30,
|
|
592
|
+
**kwargs,
|
|
593
|
+
) -> Device:
|
|
594
|
+
"""
|
|
595
|
+
Create a Device object with a grid of circles with varying radii.
|
|
596
|
+
|
|
597
|
+
Parameters
|
|
598
|
+
----------
|
|
599
|
+
rows : int, optional
|
|
600
|
+
The number of rows in the grid. Defaults to 5.
|
|
601
|
+
cols : int, optional
|
|
602
|
+
The number of columns in the grid. Defaults to 5.
|
|
603
|
+
min_radius : int, optional
|
|
604
|
+
The minimum radius of the circles. Defaults to 10.
|
|
605
|
+
max_radius : int, optional
|
|
606
|
+
The maximum radius of the circles. Defaults to 30.
|
|
607
|
+
spacing : int, optional
|
|
608
|
+
The spacing between circle centers. Defaults to 30.
|
|
609
|
+
**kwargs : dict
|
|
610
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
611
|
+
|
|
612
|
+
Returns
|
|
613
|
+
-------
|
|
614
|
+
Device
|
|
615
|
+
A Device object containing a grid of circles with varying radii.
|
|
616
|
+
"""
|
|
617
|
+
grid_height = rows * (2 * max_radius + spacing) - spacing
|
|
618
|
+
grid_width = cols * (2 * max_radius + spacing) - spacing
|
|
619
|
+
circles_varying = np.zeros((grid_height, grid_width))
|
|
620
|
+
radius_range = np.linspace(min_radius, max_radius, rows * cols).reshape(rows, cols)
|
|
621
|
+
for row in range(rows):
|
|
622
|
+
for col in range(cols):
|
|
623
|
+
radius = int(radius_range[row, col])
|
|
624
|
+
y, x = np.ogrid[-radius:radius, -radius:radius]
|
|
625
|
+
mask = x**2 + y**2 <= radius**2
|
|
626
|
+
center_y = row * (2 * max_radius + spacing) + max_radius
|
|
627
|
+
center_x = col * (2 * max_radius + spacing) + max_radius
|
|
628
|
+
circles_varying[
|
|
629
|
+
center_y - radius : center_y + radius,
|
|
630
|
+
center_x - radius : center_x + radius,
|
|
631
|
+
][mask] = 1
|
|
632
|
+
return Device(device_array=circles_varying, **kwargs)
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
def holes(
|
|
636
|
+
rows: int = 5, cols: int = 5, radius: int = 30, spacing: int = 30, **kwargs
|
|
637
|
+
) -> Device:
|
|
638
|
+
"""
|
|
639
|
+
Create a Device object with a grid of uniform circular holes.
|
|
640
|
+
|
|
641
|
+
Parameters
|
|
642
|
+
----------
|
|
643
|
+
rows : int, optional
|
|
644
|
+
The number of rows in the grid. Defaults to 5.
|
|
645
|
+
cols : int, optional
|
|
646
|
+
The number of columns in the grid. Defaults to 5.
|
|
647
|
+
radius : int, optional
|
|
648
|
+
The radius of each hole. Defaults to 30.
|
|
649
|
+
spacing : int, optional
|
|
650
|
+
The spacing between hole centers. Defaults to 30.
|
|
651
|
+
**kwargs : dict
|
|
652
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
653
|
+
|
|
654
|
+
Returns
|
|
655
|
+
-------
|
|
656
|
+
Device
|
|
657
|
+
A Device object containing a grid of circular holes.
|
|
658
|
+
"""
|
|
659
|
+
grid_height = rows * (2 * radius + spacing) - spacing
|
|
660
|
+
grid_width = cols * (2 * radius + spacing) - spacing
|
|
661
|
+
holes = np.ones((grid_height, grid_width))
|
|
662
|
+
y, x = np.ogrid[-radius:radius, -radius:radius]
|
|
663
|
+
mask = x**2 + y**2 <= radius**2
|
|
664
|
+
for row in range(rows):
|
|
665
|
+
for col in range(cols):
|
|
666
|
+
center_y = row * (2 * radius + spacing) + radius
|
|
667
|
+
center_x = col * (2 * radius + spacing) + radius
|
|
668
|
+
holes[
|
|
669
|
+
center_y - radius : center_y + radius,
|
|
670
|
+
center_x - radius : center_x + radius,
|
|
671
|
+
][mask] = 0
|
|
672
|
+
return Device(device_array=holes, **kwargs)
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
def holes_offset(
|
|
676
|
+
rows: int = 5, cols: int = 5, radius: int = 30, spacing: int = 30, **kwargs
|
|
677
|
+
) -> Device:
|
|
678
|
+
"""
|
|
679
|
+
Create a Device object with an offset grid of circular holes.
|
|
680
|
+
|
|
681
|
+
Parameters
|
|
682
|
+
----------
|
|
683
|
+
rows : int, optional
|
|
684
|
+
The number of rows in the grid. Defaults to 5.
|
|
685
|
+
cols : int, optional
|
|
686
|
+
The number of columns in the grid. Defaults to 5.
|
|
687
|
+
radius : int, optional
|
|
688
|
+
The radius of each hole. Defaults to 30.
|
|
689
|
+
spacing : int, optional
|
|
690
|
+
The spacing between hole centers. Defaults to 30.
|
|
691
|
+
**kwargs : dict
|
|
692
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
693
|
+
|
|
694
|
+
Returns
|
|
695
|
+
-------
|
|
696
|
+
Device
|
|
697
|
+
A Device object containing an offset grid of circular holes.
|
|
698
|
+
"""
|
|
699
|
+
grid_height = rows * (2 * radius + spacing) - spacing
|
|
700
|
+
grid_width = cols * (2 * radius + spacing) - spacing + (radius + spacing // 2)
|
|
701
|
+
holes_offset = np.ones((grid_height, grid_width))
|
|
702
|
+
y, x = np.ogrid[-radius:radius, -radius:radius]
|
|
703
|
+
mask = x**2 + y**2 <= radius**2
|
|
704
|
+
for row in range(rows):
|
|
705
|
+
for col in range(cols):
|
|
706
|
+
center_y = row * (2 * radius + spacing) + radius
|
|
707
|
+
center_x = (
|
|
708
|
+
col * (2 * radius + spacing)
|
|
709
|
+
+ radius
|
|
710
|
+
+ (radius + spacing // 2 if row % 2 == 1 else 0)
|
|
711
|
+
)
|
|
712
|
+
holes_offset[
|
|
713
|
+
center_y - radius : center_y + radius,
|
|
714
|
+
center_x - radius : center_x + radius,
|
|
715
|
+
][mask] = 0
|
|
716
|
+
return Device(device_array=holes_offset, **kwargs)
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
def holes_varying(
|
|
720
|
+
rows: int = 5,
|
|
721
|
+
cols: int = 5,
|
|
722
|
+
min_radius: int = 10,
|
|
723
|
+
max_radius: int = 30,
|
|
724
|
+
spacing: int = 30,
|
|
725
|
+
**kwargs,
|
|
726
|
+
) -> Device:
|
|
727
|
+
"""
|
|
728
|
+
Create a Device object with a grid of circular holes with varying radii.
|
|
729
|
+
|
|
730
|
+
Parameters
|
|
731
|
+
----------
|
|
732
|
+
rows : int, optional
|
|
733
|
+
The number of rows in the grid. Defaults to 5.
|
|
734
|
+
cols : int, optional
|
|
735
|
+
The number of columns in the grid. Defaults to 5.
|
|
736
|
+
min_radius : int, optional
|
|
737
|
+
The minimum radius of the holes. Defaults to 10.
|
|
738
|
+
max_radius : int, optional
|
|
739
|
+
The maximum radius of the holes. Defaults to 30.
|
|
740
|
+
spacing : int, optional
|
|
741
|
+
The spacing between hole centers. Defaults to 30.
|
|
742
|
+
**kwargs : dict
|
|
743
|
+
Additional keyword arguments to be passed to the Device constructor.
|
|
744
|
+
|
|
745
|
+
Returns
|
|
746
|
+
-------
|
|
747
|
+
Device
|
|
748
|
+
A Device object containing a grid of circular holes with varying radii.
|
|
749
|
+
"""
|
|
750
|
+
grid_height = rows * (2 * max_radius + spacing) - spacing
|
|
751
|
+
grid_width = cols * (2 * max_radius + spacing) - spacing
|
|
752
|
+
holes_varying = np.ones((grid_height, grid_width))
|
|
753
|
+
radius_range = np.linspace(min_radius, max_radius, rows * cols).reshape(rows, cols)
|
|
754
|
+
for row in range(rows):
|
|
755
|
+
for col in range(cols):
|
|
756
|
+
radius = int(radius_range[row, col])
|
|
757
|
+
y, x = np.ogrid[-radius:radius, -radius:radius]
|
|
758
|
+
mask = x**2 + y**2 <= radius**2
|
|
759
|
+
center_y = row * (2 * max_radius + spacing) + max_radius
|
|
760
|
+
center_x = col * (2 * max_radius + spacing) + max_radius
|
|
761
|
+
holes_varying[
|
|
762
|
+
center_y - radius : center_y + radius,
|
|
763
|
+
center_x - radius : center_x + radius,
|
|
764
|
+
][mask] = 0
|
|
765
|
+
return Device(device_array=holes_varying, **kwargs)
|