@@ -115,11 +115,13 @@ def add_cell(self, cell, origin=(0, 0), angle: Optional[float] = None, columns=1
115115 :param rows: Number of rows
116116 :param spacing: Spacing between the cells, should be an array in the form [x_spacing, y_spacing]
117117 """
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 (
121120 '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+ )
123125 self .cells .append (
124126 dict (cell = cell , origin = origin , angle = angle , magnification = None , x_reflection = False , columns = columns ,
125127 rows = rows , spacing = spacing ))
@@ -190,10 +192,13 @@ def get_dlw_data(self):
190192 dlw_data = self .dlw_data .copy ()
191193 for sub_cell in self .cells :
192194 cell , origin = sub_cell ['cell' ], sub_cell ['origin' ]
193-
194195 for dlw_type , dlw_type_data in cell .get_dlw_data ().items ():
195196 for dlw_id , data in dlw_type_data .items ():
196197 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' ]
197202 data ['origin' ] = (np .array (origin ) + data ['origin' ]).tolist ()
198203 if dlw_type not in dlw_data :
199204 dlw_data [dlw_type ] = {}
@@ -292,7 +297,7 @@ def start_viewer(self):
292297 import gdspy
293298 gdspy .LayoutViewer (library = self .get_gdspy_lib (), depth = 10 )
294299
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 ):
296301 """
297302 Exports the layout and creates an DLW-file, if DLW-features are used.
298303
@@ -305,6 +310,8 @@ def save(self, name=None, library=None, grid_steps_per_micron=1000, parallel=Fal
305310 :param parallel: Defines if parallelization is used (only supported in Python 3).
306311 Standard value will be changed to True in a future version.
307312 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.
308315 """
309316
310317 if library is not None :
@@ -317,8 +324,8 @@ def save(self, name=None, library=None, grid_steps_per_micron=1000, parallel=Fal
317324 elif name .endswith ('.gds' ):
318325 name = name [:- 4 ]
319326 library = library or 'gdshelpers'
320- elif name .endswith ('.oasis ' ):
321- name = name [:- 6 ]
327+ elif name .endswith ('.oas ' ):
328+ name = name [:- 4 ]
322329 library = library or 'fatamorgana'
323330 elif name .endswith ('.dxf' ):
324331 name = name [:- 4 ]
@@ -331,15 +338,16 @@ def save(self, name=None, library=None, grid_steps_per_micron=1000, parallel=Fal
331338 import shutil
332339
333340 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 )
335343 shutil .move (tmp .name , name + '.gds' )
336344
337345 elif library == 'gdspy' :
338346 import gdspy
339347
340348 if parallel :
341349 from concurrent .futures import ProcessPoolExecutor
342- with ProcessPoolExecutor () as pool :
350+ with ProcessPoolExecutor (max_workers = max_workers ) as pool :
343351 self .get_gdspy_cell (pool )
344352 else :
345353 self .get_gdspy_cell ()
@@ -348,7 +356,7 @@ def save(self, name=None, library=None, grid_steps_per_micron=1000, parallel=Fal
348356 gdspy_cells = self .get_gdspy_lib ().cell_dict .values ()
349357 if parallel :
350358 from concurrent .futures import ProcessPoolExecutor
351- with ProcessPoolExecutor () as pool :
359+ with ProcessPoolExecutor (max_workers = max_workers ) as pool :
352360 binary_cells = pool .map (gdspy .Cell .to_gds , gdspy_cells , [grid_steps_per_micron ] * len (gdspy_cells ))
353361 else :
354362 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
360368
361369 if parallel :
362370 from concurrent .futures import ProcessPoolExecutor
363- with ProcessPoolExecutor () as pool :
371+ with ProcessPoolExecutor (max_workers = max_workers ) as pool :
364372 cells = self .get_oasis_cells (grid_steps_per_micron , pool )
365373 else :
366374 cells = self .get_oasis_cells (grid_steps_per_micron )
367375
368376 layout .cells = [cells [0 ]] + list (set (cells [1 :]))
369377
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-
388378 with open (name + '.oas' , 'wb' ) as f :
389379 layout .write (f )
390380 elif library == 'ezdxf' :
@@ -407,7 +397,7 @@ def save_desc(self, filename: str):
407397 """
408398 if not filename .endswith ('.desc' ):
409399 filename += '.desc'
410- with open (filename + '.desc' , 'w' ) as f :
400+ with open (filename , 'w' ) as f :
411401 json .dump (self .get_desc (), f , indent = True )
412402
413403 def get_reduced_layer (self , layer : int ):
@@ -547,7 +537,7 @@ def add_dlw_marker(self, label: str, layer: int, origin):
547537 self .add_to_layer (layer , DLWMarker (origin ))
548538 self .add_to_layer (std_layers .parnamelayer1 , Text (origin , 2 , label , alignment = 'center-center' ))
549539
550- self .add_dlw_data ('marker' , label , {'origin' : list (origin )})
540+ self .add_dlw_data ('marker' , label , {'origin' : list (origin ), 'angle' : 0 })
551541
552542 def add_dlw_taper_at_port (self , label : str , layer : int , port : Port , taper_length : float , tip_width = .01 ,
553543 with_markers = True ):
0 commit comments