add functions for reading/writing tuple-valued layers to gds
This commit is contained in:
parent
1127242aa0
commit
fdd18ca7d8
@ -18,6 +18,83 @@ from ..utils import rotation_matrix_2d, get_bit, vector2
|
|||||||
__author__ = 'Jan Petykiewicz'
|
__author__ = 'Jan Petykiewicz'
|
||||||
|
|
||||||
|
|
||||||
|
def write(pattern: Pattern,
|
||||||
|
filename: str,
|
||||||
|
meters_per_unit: float):
|
||||||
|
"""
|
||||||
|
Write a Pattern to a GDSII file, by first calling .polygonize() on it
|
||||||
|
to change the shapes into polygons, and then writing patterns as GDSII
|
||||||
|
structures, polygons as boundary elements, and subpatterns as structure
|
||||||
|
references (sref).
|
||||||
|
|
||||||
|
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 to be shape.layer[1] if available,
|
||||||
|
otherwise 0
|
||||||
|
|
||||||
|
Note that this function modifies the Pattern.
|
||||||
|
|
||||||
|
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 pattern: A Pattern 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 length unit.
|
||||||
|
"""
|
||||||
|
# Create library
|
||||||
|
lib = gdsii.library.Library(version=600,
|
||||||
|
name='masque-write_dose2dtype'.encode('ASCII'),
|
||||||
|
logical_unit=1,
|
||||||
|
physical_unit=meters_per_unit)
|
||||||
|
|
||||||
|
# Get a dict of id(pattern) -> pattern
|
||||||
|
patterns_by_id = {**(pattern.referenced_patterns_by_id()), id(pattern): pattern}
|
||||||
|
|
||||||
|
# Now create a structure for each row in sd_table (ie, each pattern + dose combination)
|
||||||
|
# and add in any Boundary and SREF elements
|
||||||
|
for pat_id, pat_dose in sd_table:
|
||||||
|
pat = patterns_by_id[pat_id]
|
||||||
|
|
||||||
|
sanitized_name = re.compile('[^A-Za-z0-9_\?\$]').sub('_', pattern.name)
|
||||||
|
structure = gdsii.structure.Structure(name=sanitized_name.encode('ASCII'))
|
||||||
|
lib.append(structure)
|
||||||
|
|
||||||
|
# Add a Boundary element for each shape
|
||||||
|
for shape in pat.shapes:
|
||||||
|
for polygon in shape.to_polygons():
|
||||||
|
xy_open = numpy.round(polygon.vertices + polygon.offset).astype(int)
|
||||||
|
xy_closed = numpy.vstack((xy_open, xy_open[0, :]))
|
||||||
|
if hasattr(polygon.layer, '__len__'):
|
||||||
|
layer = polygon.layer[0]
|
||||||
|
if len(polygon.layer) > 1:
|
||||||
|
data_type = polygon.layer[1]
|
||||||
|
else:
|
||||||
|
data_type = 0
|
||||||
|
else:
|
||||||
|
layer = polygon.layer
|
||||||
|
data_type = 0
|
||||||
|
structure.append(gdsii.elements.Boundary(layer=layer,
|
||||||
|
data_type=data_type,
|
||||||
|
xy=xy_closed))
|
||||||
|
# Add an SREF for each subpattern entry
|
||||||
|
# strans must be set for angle and mag to take effect
|
||||||
|
for subpat in pat.subpatterns:
|
||||||
|
sanitized_name = re.compile('[^A-Za-z0-9_\?\$]').sub('_', subpat.name)
|
||||||
|
sref = gdsii.elements.SRef(struct_name=sanitized_name.encode('ASCII'),
|
||||||
|
xy=numpy.round([subpat.offset]).astype(int))
|
||||||
|
sref.strans = 0
|
||||||
|
sref.angle = subpat.rotation
|
||||||
|
sref.mag = subpat.scale
|
||||||
|
structure.append(sref)
|
||||||
|
|
||||||
|
with open(filename, mode='wb') as stream:
|
||||||
|
lib.save(stream)
|
||||||
|
|
||||||
|
|
||||||
def write_dose2dtype(pattern: Pattern,
|
def write_dose2dtype(pattern: Pattern,
|
||||||
filename: str,
|
filename: str,
|
||||||
meters_per_unit: float) -> List[float]:
|
meters_per_unit: float) -> List[float]:
|
||||||
@ -113,12 +190,21 @@ def write_dose2dtype(pattern: Pattern,
|
|||||||
|
|
||||||
|
|
||||||
def read_dtype2dose(filename: str) -> (List[Pattern], Dict[str, Any]):
|
def read_dtype2dose(filename: str) -> (List[Pattern], Dict[str, Any]):
|
||||||
|
"""
|
||||||
|
Alias for read(filename, use_dtype_as_dose=True)
|
||||||
|
"""
|
||||||
|
return read(filename, use_dtype_as_dose=True)
|
||||||
|
|
||||||
|
|
||||||
|
def read(filename: str, use_dtype_as_dose=False) -> (List[Pattern], Dict[str, Any]):
|
||||||
"""
|
"""
|
||||||
Read a gdsii file and translate it into a list of Pattern objects. GDSII structures are
|
Read a gdsii file and translate it into a list of Pattern objects. GDSII structures are
|
||||||
translated into Pattern objects; boundaries are translated into polygons, and srefs and arefs
|
translated into Pattern objects; boundaries are translated into polygons, and srefs and arefs
|
||||||
are translated into SubPattern objects.
|
are translated into SubPattern objects.
|
||||||
|
|
||||||
:param filename: Filename specifying a GDSII file to read from.
|
:param filename: Filename specifying a GDSII file to read from.
|
||||||
|
:param use_dtype_as_dose: If false, set each polygon's layer to (gds_layer, gds_datatype).
|
||||||
|
If true, set the layer to gds_layer and the dose to gds_datatype.
|
||||||
:return: Tuple: (List of Patterns generated GDSII structures, Dict of GDSII library info)
|
:return: Tuple: (List of Patterns generated GDSII structures, Dict of GDSII library info)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -158,10 +244,14 @@ def read_dtype2dose(filename: str) -> (List[Pattern], Dict[str, Any]):
|
|||||||
for element in structure:
|
for element in structure:
|
||||||
# Switch based on element type:
|
# Switch based on element type:
|
||||||
if isinstance(element, gdsii.elements.Boundary):
|
if isinstance(element, gdsii.elements.Boundary):
|
||||||
pat.shapes.append(
|
if use_dtype_as_dose:
|
||||||
Polygon(vertices=element.xy[:-1],
|
shape = Polygon(vertices=element.xy[:-1],
|
||||||
dose=element.data_type,
|
dose=element.data_type,
|
||||||
layer=element.layer))
|
layer=element.layer)
|
||||||
|
else:
|
||||||
|
shape = Polygon(vertices=element.xy[:-1],
|
||||||
|
layer=(element.layer, element.data_type))
|
||||||
|
pat.shapes.append(shape)
|
||||||
|
|
||||||
elif isinstance(element, gdsii.elements.SRef):
|
elif isinstance(element, gdsii.elements.SRef):
|
||||||
pat.subpatterns.append(ref_element_to_subpat(element, element.xy))
|
pat.subpatterns.append(ref_element_to_subpat(element, element.xy))
|
||||||
|
Loading…
Reference in New Issue
Block a user