def save(self, name=None, library=None, grid_steps_per_micron=1000, parallel=False, max_workers=None): """ Exports the layout and creates an DLW-file, if DLW-features are used. :param name: The filename of the saved file. The ending of the filename defines the format. Currently .gds, .oasis and .dxf are supported. :param library: Name of the used library. Should stay `None` in order to select the library depending on the file-ending. The use of this parameter is deprecated and this parameter will be removed in a future release. :param grid_steps_per_micron: Defines the resolution :param parallel: Defines if parallelization is used (only supported in Python 3). Standard value will be changed to True in a future version. Deactivating can be useful for debugging reasons. :param max_workers: If parallel is True, this can be used to limit the number of parallel processes. This can be useful if you run into out-of-memory errors otherwise. """ if library is not None: import warnings warnings.warn( 'The use of the `library` parameter is deprecated. ' 'Instead, define the format by the file ending of the filename.', DeprecationWarning) if not name: name = self.name elif name.endswith('.gds'): name = name[:-4] library = library or 'gdshelpers' elif name.endswith('.oas'): name = name[:-4] library = library or 'fatamorgana' elif name.endswith('.dxf'): name = name[:-4] library = library or 'ezdxf' library = library or 'gdshelpers' if library == 'gdshelpers': from tempfile import NamedTemporaryFile import shutil with NamedTemporaryFile('wb', delete=False) as tmp: write_cell_to_gdsii_file( tmp, self, grid_steps_per_unit=grid_steps_per_micron, parallel=parallel, max_workers=max_workers) shutil.move(tmp.name, name + '.gds') elif library == 'gdspy': import gdspy if parallel: from concurrent.futures import ProcessPoolExecutor with ProcessPoolExecutor(max_workers=max_workers) as pool: self.get_gdspy_cell(pool) else: self.get_gdspy_cell() self.get_gdspy_lib( ).precision = self.get_gdspy_lib().unit / grid_steps_per_micron gdspy_cells = self.get_gdspy_lib().cell_dict.values() if parallel: from concurrent.futures import ProcessPoolExecutor with ProcessPoolExecutor(max_workers=max_workers) as pool: binary_cells = pool.map(gdspy.Cell.to_gds, gdspy_cells, [grid_steps_per_micron] * len(gdspy_cells)) else: binary_cells = map(gdspy.Cell.to_gds, gdspy_cells, [grid_steps_per_micron] * len(gdspy_cells)) self.get_gdspy_lib().write_gds(name + '.gds', cells=[], binary_cells=binary_cells) elif library == 'fatamorgana': import fatamorgana layout = fatamorgana.OasisLayout(grid_steps_per_micron) if parallel: from concurrent.futures import ProcessPoolExecutor with ProcessPoolExecutor(max_workers=max_workers) as pool: cells = self.get_oasis_cells(grid_steps_per_micron, pool) else: cells = self.get_oasis_cells(grid_steps_per_micron) layout.cells = [cells[0]] + list(set(cells[1:])) with open(name + '.oas', 'wb') as f: layout.write(f) elif library == 'ezdxf': from gdshelpers.export.dxf_export import write_cell_to_dxf_file with open(name + '.dxf', 'w') as f: write_cell_to_dxf_file(f, self, grid_steps_per_micron, parallel=parallel) else: raise ValueError( 'library must be either "gdshelpers", "gdspy", "fatamorgana" or "ezdxf"' ) dlw_data = self.get_dlw_data() if dlw_data: with open(name + '.dlw', 'w') as f: json.dump(dlw_data, f, indent=True)
def save(self, name=None, library=None, grid_steps_per_micron=1000, parallel=False): """ Exports the layout and creates an DLW-file, if DLW-features are used. :param name: The filename of the saved file. The ending of the filename defines the format. Currently .gds, .oasis and .dxf are supported. :param library: Name of the used library. Should stay `None` in order to select the library depending on the file-ending. The use of this parameter is deprecated and this parameter will be removed in a future release. :param grid_steps_per_micron: Defines the resolution :param parallel: Defines if parallelization is used (only supported in Python 3). Standard value will be changed to True in a future version. Deactivating can be useful for debugging reasons. """ if library is not None: import warnings warnings.warn( 'The use of the `library` parameter is deprecated. ' 'Instead, define the format by the file ending of the filename.', DeprecationWarning) if not name: name = self.name elif name.endswith('.gds'): name = name[:-4] library = library or 'gdshelpers' elif name.endswith('.oasis'): name = name[:-6] library = library or 'fatamorgana' elif name.endswith('.dxf'): name = name[:-4] library = library or 'ezwriter' library = library or 'gdshelpers' if library == 'gdshelpers': from tempfile import NamedTemporaryFile import shutil with NamedTemporaryFile('wb', delete=False) as tmp: write_cell_to_gdsii_file( tmp, self, grid_steps_per_unit=grid_steps_per_micron, parallel=parallel) shutil.move(tmp.name, name + '.gds') elif library == 'gdspy': import gdspy if parallel: from concurrent.futures import ProcessPoolExecutor with ProcessPoolExecutor() as pool: self.get_gdspy_cell(pool) else: self.get_gdspy_cell() self.get_gdspy_lib( ).precision = self.get_gdspy_lib().unit / grid_steps_per_micron gdspy_cells = self.get_gdspy_lib().cell_dict.values() if parallel: from concurrent.futures import ProcessPoolExecutor with ProcessPoolExecutor() as pool: binary_cells = pool.map(gdspy.Cell.to_gds, gdspy_cells, [grid_steps_per_micron] * len(gdspy_cells)) else: binary_cells = map(gdspy.Cell.to_gds, gdspy_cells, [grid_steps_per_micron] * len(gdspy_cells)) self.get_gdspy_lib().write_gds(name + '.gds', cells=[], binary_cells=binary_cells) elif library == 'fatamorgana': import fatamorgana layout = fatamorgana.OasisLayout(grid_steps_per_micron) if parallel: from concurrent.futures import ProcessPoolExecutor with ProcessPoolExecutor() as pool: cells = self.get_oasis_cells(grid_steps_per_micron, pool) else: cells = self.get_oasis_cells(grid_steps_per_micron) layout.cells = [cells[0]] + list(set(cells[1:])) # noinspection PyUnresolvedReferences def replace_names_by_ids(oasis_layout): name_id = {} for cell_id, cell in enumerate(oasis_layout.cells): if cell.name.string in name_id: raise RuntimeError( 'Each cell name should be unique, name "' + cell.name.string + '" is used multiple times') name_id[cell.name.string] = cell_id cell.name = cell_id for cell in oasis_layout.cells: for placement in cell.placements: placement.name = name_id[placement.name.string] oasis_layout.cellnames = {v: k for k, v in name_id.items()} # improves performance for reading oasis file and workaround for fatamorgana-bug replace_names_by_ids(layout) with open(name + '.oas', 'wb') as f: layout.write(f) elif library == 'ezdxf': from gdshelpers.export.dxf_export import write_cell_to_dxf_file with open(name + '.gds', 'wb') as f: write_cell_to_dxf_file(f, self, grid_steps_per_micron, parallel=parallel) else: raise ValueError('library must be either "gdspy" or "fatamorgana"') dlw_data = self.get_dlw_data() if dlw_data: with open(name + '.dlw', 'w') as f: json.dump(dlw_data, f, indent=True)
def save(self, name=None, library=None, grid_steps_per_micron=1000, parallel=False): """ Exports the layout and creates an DLW-file, if DLW-features are used. :param name: Optionally, the filename of the saved file (without ending). :param library: Name of the used library. Currently, for gds-export gdspy and gdscad are supported, for oasis-export fatamorgana is supported. :param grid_steps_per_micron: Defines the resolution :param parallel: Defines if palatalization is used (only supported in Python 3). Standard value will be changed to True in a future version. Deactivating can be useful for debugging reasons. """ if not name: name = self.name elif name.endswith('.gds'): name = name[:-4] library = library or gds_library elif name.endswith('.oasis'): name = name[:-6] library = library or 'fatamorgana' library = library or gds_library if library == 'gdspy': if parallel: from concurrent.futures import ProcessPoolExecutor with ProcessPoolExecutor() as pool: self.get_gdspy_cell(pool) else: self.get_gdspy_cell() self.get_gdspy_lib().precision = self.get_gdspy_lib().unit / grid_steps_per_micron gdspy_cells = self.get_gdspy_lib().cell_dict.values() if parallel: from concurrent.futures import ProcessPoolExecutor with ProcessPoolExecutor() as pool: binary_cells = pool.map(gdspy.Cell.to_gds, gdspy_cells, [grid_steps_per_micron] * len(gdspy_cells)) else: binary_cells = map(gdspy.Cell.to_gds, gdspy_cells, [grid_steps_per_micron] * len(gdspy_cells)) self.get_gdspy_lib().write_gds(name + '.gds', cells=[], binary_cells=binary_cells) elif library == 'gdscad': layout = gdsCAD.core.Layout(precision=1e-6 / grid_steps_per_micron) if parallel: from concurrent.futures import ProcessPoolExecutor with ProcessPoolExecutor() as pool: layout.add(self.get_gdscad_cell(pool)) else: layout.add(self.get_gdscad_cell()) layout.save(name + '.gds') elif library == 'fatamorgana': layout = fatamorgana.OasisLayout(grid_steps_per_micron) if parallel: from concurrent.futures import ProcessPoolExecutor with ProcessPoolExecutor() as pool: cells = self.get_oasis_cells(grid_steps_per_micron, pool) else: cells = self.get_oasis_cells(grid_steps_per_micron) layout.cells = [cells[0]] + list(set(cells[1:])) # noinspection PyUnresolvedReferences def replace_names_by_ids(oasis_layout): name_id = {} for cell_id, cell in enumerate(oasis_layout.cells): if cell.name.string in name_id: raise RuntimeError( 'Each cell name should be unique, name "' + cell.name.string + '" is used multiple times') name_id[cell.name.string] = cell_id cell.name = cell_id for cell in oasis_layout.cells: for placement in cell.placements: placement.name = name_id[placement.name.string] oasis_layout.cellnames = {v: k for k, v in name_id.items()} # improves performance for reading oasis file and workaround for fatamorgana-bug replace_names_by_ids(layout) with open(name + '.oas', 'wb') as f: layout.write(f) else: raise ValueError('library must be either "gdscad", "gdspy" or "fatamorgana"') dlw_data = self.get_dlw_data() if dlw_data: with open(name + '.dlw', 'w') as f: json.dump(dlw_data, f, indent=True) with open(name + '.desc', 'w') as f: json.dump(self.get_desc(), f, indent=True)