General overhaul of gdsii read/write functions
- read() and write() now take streams instead of filenames - readfile() and writefile() were added to handle filenames and can detect and handle '.gz' suffixed/compressed files. - write_dose2dtype() and and read_dtype2dose() were removed in favor of read(use_dtype_as_dose=True) and dose2dtype()
This commit is contained in:
parent
d6d26b4e46
commit
485a7bc29d
@ -8,11 +8,14 @@ import gdsii.elements
|
||||
|
||||
from typing import List, Any, Dict, Tuple
|
||||
import re
|
||||
import io
|
||||
import copy
|
||||
import numpy
|
||||
import base64
|
||||
import struct
|
||||
import logging
|
||||
import pathlib
|
||||
import gzip
|
||||
|
||||
from .utils import mangle_name, make_dose_table
|
||||
from .. import Pattern, SubPattern, GridRepetition, PatternError, Label, Shape
|
||||
@ -35,7 +38,7 @@ path_cap_map = {0: Path.Cap.Flush,
|
||||
|
||||
|
||||
def write(patterns: Pattern or List[Pattern],
|
||||
filename: str,
|
||||
stream: io.BufferedIOBase,
|
||||
meters_per_unit: float,
|
||||
logical_units_per_unit: float = 1,
|
||||
library_name: str = 'masque-gdsii-write',
|
||||
@ -58,8 +61,8 @@ def write(patterns: Pattern or List[Pattern],
|
||||
If you want pattern polygonized with non-default arguments, just call pattern.polygonize()
|
||||
prior to calling this function.
|
||||
|
||||
:param patterns: A Pattern or list of patterns to write to file. Modified by this function.
|
||||
:param filename: Filename to write to.
|
||||
:param patterns: A Pattern or list of patterns to write to file.
|
||||
:param file: Filename or stream object to write to.
|
||||
:param meters_per_unit: Written into the GDSII file, meters per (database) length unit.
|
||||
All distances are assumed to be an integer multiple of this unit, and are stored as such.
|
||||
:param logical_units_per_unit: Written into the GDSII file. Allows the GDSII to specify a
|
||||
@ -99,50 +102,29 @@ def write(patterns: Pattern or List[Pattern],
|
||||
structure += _labels_to_texts(pat.labels)
|
||||
structure += _subpatterns_to_refs(pat.subpatterns)
|
||||
|
||||
with open(filename, mode='wb') as stream:
|
||||
lib.save(stream)
|
||||
return
|
||||
|
||||
|
||||
def write_dose2dtype(patterns: Pattern or List[Pattern],
|
||||
filename: str,
|
||||
meters_per_unit: float,
|
||||
def writefile(patterns: List[Pattern] or Pattern,
|
||||
filename: str or pathlib.Path,
|
||||
*args,
|
||||
**kwargs,
|
||||
) -> List[float]:
|
||||
):
|
||||
"""
|
||||
Write a Pattern or list of patterns to a GDSII file, by first calling
|
||||
.polygonize() to change the shapes into polygons, and then writing patterns
|
||||
as GDSII structures, polygons as boundary elements, and subpatterns as structure
|
||||
references (sref).
|
||||
Wrapper for gdsii.write() that takes a filename or path instead of a stream.
|
||||
|
||||
For each shape,
|
||||
layer is chosen to be equal to shape.layer if it is an int,
|
||||
or shape.layer[0] if it is a tuple
|
||||
datatype is chosen arbitrarily, based on calcualted dose for each shape.
|
||||
Shapes with equal calcualted dose will have the same datatype.
|
||||
A list of doses is retured, providing a mapping between datatype
|
||||
(list index) and dose (list entry).
|
||||
|
||||
Note that this function modifies the Pattern(s).
|
||||
|
||||
It is often a good idea to run pattern.subpatternize() prior to calling this function,
|
||||
especially if calling .polygonize() will result in very many vertices.
|
||||
|
||||
If you want pattern polygonized with non-default arguments, just call pattern.polygonize()
|
||||
prior to calling this function.
|
||||
|
||||
:param patterns: A Pattern or list of patterns to write to file. Modified by this function.
|
||||
:param filename: Filename to write to.
|
||||
:param meters_per_unit: Written into the GDSII file, meters per (database) length unit.
|
||||
All distances are assumed to be an integer multiple of this unit, and are stored as such.
|
||||
:param args: passed to masque.file.gdsii.write().
|
||||
:param kwargs: passed to masque.file.gdsii.write().
|
||||
:returns: A list of doses, providing a mapping between datatype (int, list index)
|
||||
and dose (float, list entry).
|
||||
Will automatically compress the file if it has a .gz suffix.
|
||||
"""
|
||||
patterns, dose_vals = dose2dtype(patterns)
|
||||
write(patterns, filename, meters_per_unit, *args, **kwargs)
|
||||
return dose_vals
|
||||
path = pathlib.Path(filename)
|
||||
if path.suffix == 'gz':
|
||||
open_func = gzip.open
|
||||
else:
|
||||
open_func = open
|
||||
|
||||
with open_func(path, mode='wb') as stream:
|
||||
results = write(patterns, stream, *args, **kwargs)
|
||||
return results
|
||||
|
||||
|
||||
def dose2dtype(patterns: Pattern or List[Pattern],
|
||||
@ -219,14 +201,27 @@ def dose2dtype(patterns: Pattern or List[Pattern],
|
||||
return patterns, list(dose_vals)
|
||||
|
||||
|
||||
def read_dtype2dose(filename: str) -> (List[Pattern], Dict[str, Any]):
|
||||
def readfile(filename: str or pathlib.Path,
|
||||
*args,
|
||||
**kwargs,
|
||||
) -> (Dict[str, Pattern], Dict[str, Any]):
|
||||
"""
|
||||
Alias for read(filename, use_dtype_as_dose=True)
|
||||
Wrapper for gdsii.read() that takes a filename or path instead of a stream.
|
||||
|
||||
Tries to autodetermine file type based on suffixes
|
||||
"""
|
||||
return read(filename, use_dtype_as_dose=True)
|
||||
path = pathlib.Path(filename)
|
||||
if path.suffix == 'gz':
|
||||
open_func = gzip.open
|
||||
else:
|
||||
open_func = open
|
||||
|
||||
with open_func(path, mode='rb') as stream:
|
||||
results = read(stream, *args, **kwargs)
|
||||
return results
|
||||
|
||||
|
||||
def read(filename: str,
|
||||
def read(stream: io.BufferedIOBase,
|
||||
use_dtype_as_dose: bool = False,
|
||||
clean_vertices: bool = True,
|
||||
) -> (Dict[str, Pattern], Dict[str, Any]):
|
||||
@ -251,7 +246,6 @@ def read(filename: str,
|
||||
:return: Tuple: (Dict of pattern_name:Patterns generated from GDSII structures, Dict of GDSII library info)
|
||||
"""
|
||||
|
||||
with open(filename, mode='rb') as stream:
|
||||
lib = gdsii.library.Library.load(stream)
|
||||
|
||||
library_info = {'name': lib.name.decode('ASCII'),
|
||||
@ -532,3 +526,4 @@ def _disambiguate_pattern_names(patterns):
|
||||
|
||||
pat.name = encoded_name
|
||||
used_names.append(suffixed_name)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user