Skip to content

Commit

Permalink
Equalize vertex processing in Geometry and PolySlab
Browse files Browse the repository at this point in the history
Use the same grid size for both when loading vertices from GDSII, and
apply dilations in the same manner to avoid unexpected differences due
to operation order.

Signed-off-by: Lucas Heitzmann Gabrielli <lucas@flexcompute.com>
  • Loading branch information
lucas-flexcompute authored and momchil-flex committed Aug 17, 2023
1 parent bde37c2 commit c285f36
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 15 deletions.
2 changes: 1 addition & 1 deletion tests/test_components/test_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ def test_from_gds():
cell, 2, (0, 1), gds_layer=0, dilation=-0.5, sidewall_angle=0.5, reference_plane="bottom"
)
assert len(geo.intersections_plane(z=0)) == 2
assert len(geo.intersections_plane(z=1)) == 5
assert len(geo.intersections_plane(z=1)) == 1


def test_custom_surface_geometry(tmp_path):
Expand Down
17 changes: 13 additions & 4 deletions tidy3d/components/geometry/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from ...exceptions import SetupError, ValidationError, Tidy3dKeyError, Tidy3dError
from ...constants import MICROMETER, LARGE_NUMBER, RADIAN, inf, fp_eps

POLY_GRID_SIZE = 1e-12

class Geometry(Tidy3dBaseModel, ABC):
"""Abstract base class, defines where something exists in space."""
Expand Down Expand Up @@ -921,12 +922,16 @@ def from_gds(
geometries = []
with log as consolidated_logger:
for vertices in gds_loader_fn(gds_cell, gds_layer, gds_dtype, gds_scale):
# buffer(0) is necessary to merge self-intersections before dilation/erosion
shape = shapely.Polygon(vertices).buffer(0).buffer(dilation)
# buffer(0) is necessary to merge self-intersections
shape = shapely.set_precision(shapely.Polygon(vertices).buffer(0), POLY_GRID_SIZE)
try:
geometries.append(
from_shapely(shape, axis, slab_bounds, sidewall_angle, reference_plane)
from_shapely(
shape, axis, slab_bounds, dilation, sidewall_angle, reference_plane
)
)
except pydantic.ValidationError as error:
consolidated_logger.warning(str(error))
except Tidy3dError as error:
consolidated_logger.warning(str(error))
return GeometryGroup(geometries=geometries)
Expand All @@ -936,6 +941,7 @@ def from_shapely(
shape: Shapely,
axis: Axis,
slab_bounds: Tuple[float, float],
dilation: float = 0.0,
sidewall_angle: float = 0,
reference_plane: PlanePosition = "middle",
) -> Geometry:
Expand All @@ -950,6 +956,9 @@ def from_shapely(
Integer index defining the extrusion axis: 0 (x), 1 (y), or 2 (z).
slab_bounds: Tuple[float, float]
Minimal and maximal positions of the extruded slab along ``axis``.
dilation : float
Dilation of the polygon in the base by shifting each edge along its normal outwards
direction by a distance; a negative value corresponds to erosion.
sidewall_angle : float = 0
Angle of the extrusion sidewalls, away from the vertical direction, in radians. Positive
(negative) values result in slabs larger (smaller) at the base than at the top.
Expand All @@ -964,7 +973,7 @@ def from_shapely(
:class:`Geometry`
Geometry extruded from the 2D data.
"""
return from_shapely(shape, axis, slab_bounds, sidewall_angle, reference_plane)
return from_shapely(shape, axis, slab_bounds, dilation, sidewall_angle, reference_plane)

def _as_union(self) -> List[Geometry]:
"""Return a list of geometries that, united, make up the given geometry."""
Expand Down
7 changes: 2 additions & 5 deletions tidy3d/components/geometry/polyslab.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@

_IS_CLOSE_RTOL = np.finfo(float).eps

# polygon merge
_POLY_GRID_SIZE = 1e-12

# Warn for too many divided polyslabs
_COMPLEX_POLYSLAB_DIVISIONS_WARN = 100

Expand Down Expand Up @@ -335,7 +332,7 @@ def _load_gds_vertices(

# convert vertices into polyslabs
polygons = [shapely.Polygon(vertices).buffer(0) for vertices in all_vertices]
polys_union = shapely.unary_union(polygons, grid_size=_POLY_GRID_SIZE)
polys_union = shapely.unary_union(polygons, grid_size=base.POLY_GRID_SIZE)

if polys_union.geom_type == "Polygon":
all_vertices = [np.array(polys_union.exterior.coords)]
Expand Down Expand Up @@ -643,7 +640,7 @@ def _intersections_side(self, position, axis) -> list:
h_base = h_top

# merge touching polygons
polys_union = shapely.unary_union(polys, grid_size=_POLY_GRID_SIZE)
polys_union = shapely.unary_union(polys, grid_size=base.POLY_GRID_SIZE)
if polys_union.geom_type == "Polygon":
return [polys_union]
if polys_union.geom_type == "MultiPolygon":
Expand Down
19 changes: 14 additions & 5 deletions tidy3d/components/geometry/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
]


# pylint:disable=too-many-arguments
def from_shapely(
shape: Shapely,
axis: Axis,
slab_bounds: Tuple[float, float],
dilation: float = 0.0,
sidewall_angle: float = 0,
reference_plane: PlanePosition = "middle",
) -> base.Geometry:
Expand All @@ -40,6 +42,9 @@ def from_shapely(
Integer index defining the extrusion axis: 0 (x), 1 (y), or 2 (z).
slab_bounds: Tuple[float, float]
Minimal and maximal positions of the extruded slab along ``axis``.
dilation : float
Dilation of the polygon in the base by shifting each edge along its normal outwards
direction by a distance; a negative value corresponds to erosion.
sidewall_angle : float = 0
Angle of the extrusion sidewalls, away from the vertical direction, in radians. Positive
(negative) values result in slabs larger (smaller) at the base than at the top.
Expand All @@ -58,23 +63,27 @@ def from_shapely(
if sidewall_angle == 0:
return polyslab.PolySlab(
vertices=shape.coords[:-1],
slab_bounds=slab_bounds,
axis=axis,
slab_bounds=slab_bounds,
dilation=dilation,
reference_plane=reference_plane,
)
group = polyslab.ComplexPolySlabBase(
vertices=shape.coords[:-1],
slab_bounds=slab_bounds,
axis=axis,
slab_bounds=slab_bounds,
dilation=dilation,
sidewall_angle=sidewall_angle,
reference_plane=reference_plane,
).geometry_group
return group.geometries[0] if len(group.geometries) == 1 else group

if shape.geom_type == "Polygon":
exterior = from_shapely(shape.exterior, axis, slab_bounds, sidewall_angle, reference_plane)
exterior = from_shapely(
shape.exterior, axis, slab_bounds, dilation, sidewall_angle, reference_plane
)
interior = [
from_shapely(hole, axis, slab_bounds, -sidewall_angle, reference_plane)
from_shapely(hole, axis, slab_bounds, -dilation, -sidewall_angle, reference_plane)
for hole in shape.interiors
]
if len(interior) == 0:
Expand All @@ -85,7 +94,7 @@ def from_shapely(
if shape.geom_type in {"MultiPolygon", "GeometryCollection"}:
return base.GeometryGroup(
geometries=[
from_shapely(geo, axis, slab_bounds, sidewall_angle, reference_plane)
from_shapely(geo, axis, slab_bounds, dilation, sidewall_angle, reference_plane)
for geo in shape.geoms
]
)
Expand Down

0 comments on commit c285f36

Please sign in to comment.