@@ -115,11 +115,13 @@ def add_cell(self, cell, origin=(0, 0), angle: Optional[float] = None, columns=1
115
115
:param rows: Number of rows
116
116
:param spacing: Spacing between the cells, should be an array in the form [x_spacing, y_spacing]
117
117
"""
118
- if cell .name in [cell_dict ['cell' ].name for cell_dict in self .cells ]:
119
- import warnings
120
- warnings .warn (
118
+ if cell .get_dlw_data () and cell .name in [cell_dict ['cell' ].name for cell_dict in self .cells ]:
119
+ raise ValueError (
121
120
'Cell name "{cell_name:s}" added multiple times to {self_name:s}.'
122
- ' Can be problematic for desc/dlw-files' .format (cell_name = cell .name , self_name = self .name ))
121
+ ' This is not allowed for cells containing DLW data.' .format (
122
+ cell_name = cell .name , self_name = self .name
123
+ )
124
+ )
123
125
self .cells .append (
124
126
dict (cell = cell , origin = origin , angle = angle , magnification = None , x_reflection = False , columns = columns ,
125
127
rows = rows , spacing = spacing ))
@@ -190,10 +192,13 @@ def get_dlw_data(self):
190
192
dlw_data = self .dlw_data .copy ()
191
193
for sub_cell in self .cells :
192
194
cell , origin = sub_cell ['cell' ], sub_cell ['origin' ]
193
-
194
195
for dlw_type , dlw_type_data in cell .get_dlw_data ().items ():
195
196
for dlw_id , data in dlw_type_data .items ():
196
197
data = data .copy ()
198
+ if sub_cell ['angle' ] is not None :
199
+ c , s = np .cos (sub_cell ['angle' ]), np .sin (sub_cell ['angle' ])
200
+ data ['origin' ] = np .array ([[c , - s ], [s , c ]]).dot (data ['origin' ])
201
+ data ['angle' ] += sub_cell ['angle' ]
197
202
data ['origin' ] = (np .array (origin ) + data ['origin' ]).tolist ()
198
203
if dlw_type not in dlw_data :
199
204
dlw_data [dlw_type ] = {}
@@ -292,7 +297,7 @@ def start_viewer(self):
292
297
import gdspy
293
298
gdspy .LayoutViewer (library = self .get_gdspy_lib (), depth = 10 )
294
299
295
- def save (self , name = None , library = None , grid_steps_per_micron = 1000 , parallel = False ):
300
+ def save (self , name = None , library = None , grid_steps_per_micron = 1000 , parallel = False , max_workers = None ):
296
301
"""
297
302
Exports the layout and creates an DLW-file, if DLW-features are used.
298
303
@@ -305,6 +310,8 @@ def save(self, name=None, library=None, grid_steps_per_micron=1000, parallel=Fal
305
310
:param parallel: Defines if parallelization is used (only supported in Python 3).
306
311
Standard value will be changed to True in a future version.
307
312
Deactivating can be useful for debugging reasons.
313
+ :param max_workers: If parallel is True, this can be used to limit the number of parallel processes.
314
+ This can be useful if you run into out-of-memory errors otherwise.
308
315
"""
309
316
310
317
if library is not None :
@@ -317,8 +324,8 @@ def save(self, name=None, library=None, grid_steps_per_micron=1000, parallel=Fal
317
324
elif name .endswith ('.gds' ):
318
325
name = name [:- 4 ]
319
326
library = library or 'gdshelpers'
320
- elif name .endswith ('.oasis ' ):
321
- name = name [:- 6 ]
327
+ elif name .endswith ('.oas ' ):
328
+ name = name [:- 4 ]
322
329
library = library or 'fatamorgana'
323
330
elif name .endswith ('.dxf' ):
324
331
name = name [:- 4 ]
@@ -331,15 +338,16 @@ def save(self, name=None, library=None, grid_steps_per_micron=1000, parallel=Fal
331
338
import shutil
332
339
333
340
with NamedTemporaryFile ('wb' , delete = False ) as tmp :
334
- write_cell_to_gdsii_file (tmp , self , grid_steps_per_unit = grid_steps_per_micron , parallel = parallel )
341
+ write_cell_to_gdsii_file (tmp , self , grid_steps_per_unit = grid_steps_per_micron , parallel = parallel ,
342
+ max_workers = max_workers )
335
343
shutil .move (tmp .name , name + '.gds' )
336
344
337
345
elif library == 'gdspy' :
338
346
import gdspy
339
347
340
348
if parallel :
341
349
from concurrent .futures import ProcessPoolExecutor
342
- with ProcessPoolExecutor () as pool :
350
+ with ProcessPoolExecutor (max_workers = max_workers ) as pool :
343
351
self .get_gdspy_cell (pool )
344
352
else :
345
353
self .get_gdspy_cell ()
@@ -348,7 +356,7 @@ def save(self, name=None, library=None, grid_steps_per_micron=1000, parallel=Fal
348
356
gdspy_cells = self .get_gdspy_lib ().cell_dict .values ()
349
357
if parallel :
350
358
from concurrent .futures import ProcessPoolExecutor
351
- with ProcessPoolExecutor () as pool :
359
+ with ProcessPoolExecutor (max_workers = max_workers ) as pool :
352
360
binary_cells = pool .map (gdspy .Cell .to_gds , gdspy_cells , [grid_steps_per_micron ] * len (gdspy_cells ))
353
361
else :
354
362
binary_cells = map (gdspy .Cell .to_gds , gdspy_cells , [grid_steps_per_micron ] * len (gdspy_cells ))
@@ -360,31 +368,13 @@ def save(self, name=None, library=None, grid_steps_per_micron=1000, parallel=Fal
360
368
361
369
if parallel :
362
370
from concurrent .futures import ProcessPoolExecutor
363
- with ProcessPoolExecutor () as pool :
371
+ with ProcessPoolExecutor (max_workers = max_workers ) as pool :
364
372
cells = self .get_oasis_cells (grid_steps_per_micron , pool )
365
373
else :
366
374
cells = self .get_oasis_cells (grid_steps_per_micron )
367
375
368
376
layout .cells = [cells [0 ]] + list (set (cells [1 :]))
369
377
370
- # noinspection PyUnresolvedReferences
371
- def replace_names_by_ids (oasis_layout ):
372
- name_id = {}
373
- for cell_id , cell in enumerate (oasis_layout .cells ):
374
- if cell .name .string in name_id :
375
- raise RuntimeError (
376
- 'Each cell name should be unique, name "' + cell .name .string + '" is used multiple times' )
377
- name_id [cell .name .string ] = cell_id
378
- cell .name = cell_id
379
- for cell in oasis_layout .cells :
380
- for placement in cell .placements :
381
- placement .name = name_id [placement .name .string ]
382
-
383
- oasis_layout .cellnames = {v : k for k , v in name_id .items ()}
384
-
385
- # improves performance for reading oasis file and workaround for fatamorgana-bug
386
- replace_names_by_ids (layout )
387
-
388
378
with open (name + '.oas' , 'wb' ) as f :
389
379
layout .write (f )
390
380
elif library == 'ezdxf' :
@@ -407,7 +397,7 @@ def save_desc(self, filename: str):
407
397
"""
408
398
if not filename .endswith ('.desc' ):
409
399
filename += '.desc'
410
- with open (filename + '.desc' , 'w' ) as f :
400
+ with open (filename , 'w' ) as f :
411
401
json .dump (self .get_desc (), f , indent = True )
412
402
413
403
def get_reduced_layer (self , layer : int ):
@@ -547,7 +537,7 @@ def add_dlw_marker(self, label: str, layer: int, origin):
547
537
self .add_to_layer (layer , DLWMarker (origin ))
548
538
self .add_to_layer (std_layers .parnamelayer1 , Text (origin , 2 , label , alignment = 'center-center' ))
549
539
550
- self .add_dlw_data ('marker' , label , {'origin' : list (origin )})
540
+ self .add_dlw_data ('marker' , label , {'origin' : list (origin ), 'angle' : 0 })
551
541
552
542
def add_dlw_taper_at_port (self , label : str , layer : int , port : Port , taper_length : float , tip_width = .01 ,
553
543
with_markers = True ):
0 commit comments