Skip to content

Commit 395f617

Browse files
more comments
1 parent 4e50c75 commit 395f617

File tree

1 file changed

+118
-27
lines changed

1 file changed

+118
-27
lines changed

tidy3d/components/grid/grid_spec.py

+118-27
Original file line numberDiff line numberDiff line change
@@ -1539,36 +1539,66 @@ def _find_vertical_intersections(self, x, y, vertices):
15391539

15401540
cells_ij = []
15411541
cells_dy = []
1542-
h_inds = np.argmax(x[:, None] > vertices[None, :, 0], axis=0)
1543-
h_inds[vertices[:, 0] > x[-1]] = len(x)
1542+
1543+
# for each polygon vertex find the index of the first grid line on the right
1544+
grid_lines_on_right = np.argmax(x[:, None] > vertices[None, :, 0], axis=0)
1545+
grid_lines_on_right[vertices[:, 0] > x[-1]] = len(x)
1546+
# once we know these indices then we can find grid lines intersected by the i-th
1547+
# segment of the polygon as
1548+
# [grid_lines_on_right[i], grid_lines_on_right[i+1]) for grid_lines_on_right[i] > grid_lines_on_right[i+1]
1549+
# or
1550+
# [grid_lines_on_right[i+1], grid_lines_on_right[i]) for grid_lines_on_right[i] < grid_lines_on_right[i+1]
1551+
1552+
# loop over segments of the polygon and determine in which cells and where exactly they cross grid lines
1553+
# v_beg and v_end are the starting and ending points of the segment
1554+
# ind_beg and ind_end are starting and ending indices of vertical grid lines that the segment intersects
1555+
# as described above
15441556
for ind_beg, ind_end, v_beg, v_end in zip(
1545-
h_inds, np.roll(h_inds, -1), vertices, np.roll(vertices, axis=0, shift=-1)
1557+
grid_lines_on_right,
1558+
np.roll(grid_lines_on_right, -1),
1559+
vertices,
1560+
np.roll(vertices, axis=0, shift=-1),
15461561
):
1547-
# sort vertices in ascending order
1562+
# no intersections
1563+
if ind_end == ind_beg:
1564+
continue
1565+
1566+
# sort vertices in ascending order to make treatmeant unifrom
15481567
if ind_beg > ind_end:
15491568
ind_beg, ind_end, v_beg, v_end = ind_end, ind_beg, v_end, v_beg
15501569

1551-
if ind_end > ind_beg:
1552-
# x coordinates are simply grid x points that are covered by each segment
1553-
h_x = x[ind_beg:ind_end]
1570+
# x coordinates are simply x coordinates of intersected vertical grid lines
1571+
intersections_x = x[ind_beg:ind_end]
1572+
1573+
# y coordinates can be found from line equation
1574+
intersections_y = v_beg[1] + (v_end[1] - v_beg[1]) / (v_end[0] - v_beg[0]) * (
1575+
intersections_x - v_beg[0]
1576+
)
15541577

1555-
# y coordinates can be found from line equation
1556-
h_y = v_beg[1] + (v_end[1] - v_beg[1]) / (v_end[0] - v_beg[0]) * (h_x - v_beg[0])
1578+
# however, some of the vertical lines might be crossed
1579+
# outside of computational domain
1580+
# so we need to see which ones are actually inside along y axis
1581+
inds_inside_grid = np.logical_and(intersections_y >= y[0], intersections_y <= y[-1])
15571582

1558-
# however, we need to see which ones are actually inside along y axis
1559-
inds_inside_grid = np.logical_and(h_y >= y[0], h_y <= y[-1])
1583+
intersections_y = intersections_y[inds_inside_grid]
15601584

1561-
h_y = h_y[inds_inside_grid]
1585+
# find i and j indices of cells which contain these intersections
15621586

1563-
# find cell j coordinates which contain these intersections
1564-
cell_is = np.arange(ind_beg, ind_end)[inds_inside_grid]
1565-
cell_js = np.searchsorted(y, h_y) - 1
1587+
# i indices are simply indices of crossed vertical grid lines
1588+
cell_is = np.arange(ind_beg, ind_end)[inds_inside_grid]
15661589

1567-
# find local dy
1568-
dy = h_y - y[cell_js]
1590+
# j indices can be computed by finding insertion indices
1591+
# of y coordinates of intersection points into array of y coordinates
1592+
# of the grid lines that preserve sorting
1593+
cell_js = np.searchsorted(y, intersections_y) - 1
15691594

1570-
cells_ij.append(np.transpose([cell_is, cell_js]))
1571-
cells_dy.append(dy)
1595+
# find local dy, that is, the distance between the intersection point
1596+
# and the bottom edge of the cell
1597+
dy = intersections_y - y[cell_js]
1598+
1599+
# record info
1600+
cells_ij.append(np.transpose([cell_is, cell_js]))
1601+
cells_dy.append(dy)
15721602

15731603
if len(cells_ij) > 0:
15741604
cells_ij = np.concatenate(cells_ij)
@@ -1580,26 +1610,47 @@ def _find_vertical_intersections(self, x, y, vertices):
15801610

15811611
def _process_poly(self, x, y, vertices):
15821612
"""Detect intersection points of single polygon and grid lines."""
1613+
1614+
# find cells that contain intersections of vertical grid lines
1615+
# and locations of those intersections (along y axis)
15831616
v_cells_ij, v_cells_dy = self._find_vertical_intersections(x, y, vertices)
1617+
1618+
# find cells that contain intersections of horizontal grid lines
1619+
# and locations of those intersections (along x axis)
15841620
# reuse the same command but flip dimensions
1585-
h_cells_ij, h_cells_dx = self._find_vertical_intersections(y, x, vertices[:, [1, 0]])
1621+
h_cells_ij, h_cells_dx = self._find_vertical_intersections(y, x, np.flip(vertices, axis=1))
15861622
if len(h_cells_ij) > 0:
15871623
h_cells_ij = np.roll(h_cells_ij, axis=1, shift=1)
1624+
15881625
return v_cells_ij, v_cells_dy, h_cells_ij, h_cells_dx
15891626

15901627
def _process_slice(self, x, y, merged_geos):
15911628
"""Detect intersection points of geometries boundaries and grid lines."""
1629+
1630+
# cells that contain intersections of vertical grid lines
15921631
v_cells_ij = []
1632+
# locations of those intersections (along y axis)
15931633
v_cells_dy = []
1634+
1635+
# cells that contain intersections of horizontal grid lines
15941636
h_cells_ij = []
1637+
# locations of those intersections (along x axis)
15951638
h_cells_dx = []
15961639

1640+
# loop over all shapes
15971641
for mat, shapes in merged_geos:
15981642
if not mat.is_pec:
15991643
continue
16001644
polygon_list = ClipOperation.to_polygon_list(shapes)
16011645
for poly in polygon_list:
16021646
poly = poly.normalize().buffer(0)
1647+
1648+
# find intersections of a polygon with grid lines
1649+
# specifically:
1650+
# 0. cells that contain intersections of vertical grid lines
1651+
# 1. locations of those intersections along y axis
1652+
# 2. cells that contain intersections of horizontal grid lines
1653+
# 3. locations of those intersections along x axis
16031654
data = self._process_poly(x, y, np.array(poly.exterior.coords)[:-1])
16041655

16051656
if len(data[0]) > 0:
@@ -1643,48 +1694,88 @@ def _resolve_gaps(self, structures: List, grid: Grid):
16431694
coord=self.center_axis, normal_axis=self.axis, structure_list=structures
16441695
)
16451696

1697+
# get x and y coordinates of grid lines
16461698
_, tan_dims = Box.pop_axis([0, 1, 2], self.axis)
16471699
x = grid.boundaries.to_list[tan_dims[0]]
16481700
y = grid.boundaries.to_list[tan_dims[1]]
16491701

1650-
# find in which cells pec boundaries cross grid lines and locations of intersections
1702+
# find intersections of pec polygons with grid lines
1703+
# specifically:
1704+
# 0. cells that contain intersections of vertical grid lines
1705+
# 1. locations of those intersections along y axis
1706+
# 2. cells that contain intersections of horizontal grid lines
1707+
# 3. locations of those intersections along x axis
16511708
v_cells_ij, v_cells_dy, h_cells_ij, h_cells_dx = self._process_slice(x, y, plane_slice)
16521709

16531710
detected_gap_width = inf
16541711

1655-
# count crossings of vertical grid lines
1712+
# generate horizontal snapping lines
16561713
snapping_lines_y = []
16571714
if len(v_cells_ij) > 0:
1658-
# add number of intersections
1715+
# count intersections of vertical grid lines in each cell
16591716
ind_unique, counts = np.unique(
16601717
v_cells_ij[:, 0] * len(y) + v_cells_ij[:, 1], return_counts=True
16611718
)
1719+
# when we count intersections we use linearized 2d index because we really
1720+
# need to count intersections in each cell separately
1721+
1722+
# but when we need to decide about refinement, due to cartesian nature of grid
1723+
# we will need to consider all cells with a given j index at a time
1724+
1725+
# so, let's compute j index for each cell in the inique list
16621726
ind_unique_j = ind_unique % len(y)
1727+
1728+
# loop through all j rows that contain intersections
16631729
for ind_j in np.unique(ind_unique_j):
1730+
# we need to refine between two grid lines corresponding to index j
1731+
# if at least one cell with given j contains > 1 intersections
16641732
max_count = np.max(counts[ind_unique_j == ind_j])
1665-
# for those where we have more than one crossing, place a snapping line in the middle
16661733
if max_count > 1:
1734+
# This could use some improvement in future:
1735+
# currently we just calculate the position of the lowest intersection
1736+
# and the highest intersection in row j
1737+
# and just place a snapping line in between.
16671738
min_dy = np.min(v_cells_dy[v_cells_ij[:, 1] == ind_j])
16681739
max_dy = np.max(v_cells_dy[v_cells_ij[:, 1] == ind_j])
16691740
snapping_lines_y.append(y[ind_j] + 0.5 * (min_dy + max_dy))
16701741
detected_gap_width = min(detected_gap_width, max_dy - min_dy)
1742+
# This is expected to work fine when we have a simple gap/strip passing
1743+
# through a number of cells. But not optimal if we have slanted/curved
1744+
# boundaries and/or more than 2 intersections.
16711745

1672-
# count crossings of horizontal grid lines
1746+
# generate vertical snapping lines
16731747
snapping_lines_x = []
16741748
if len(h_cells_ij) > 0:
1675-
# add number of intersections
1749+
# count intersections of horizontal grid lines in each cell
16761750
ind_unique, counts = np.unique(
16771751
h_cells_ij[:, 0] * len(y) + h_cells_ij[:, 1], return_counts=True
16781752
)
1753+
# when we count intersections we use linearized 2d index because we really
1754+
# need to count intersections in each cell separately
1755+
1756+
# but when we need to decide about refinement, due to cartesian nature of grid
1757+
# we will need to consider all cells with a given i index at a time
1758+
1759+
# so, let's compute i index for each cell in the inique list
16791760
ind_unique_i = ind_unique // len(y)
1761+
1762+
# loop through all i columns that contain intersections
16801763
for ind_i in np.unique(ind_unique_i):
1764+
# we need to refine between two grid lines corresponding to index i
1765+
# if at least one cell with given i contains > 1 intersections
16811766
max_count = np.max(counts[ind_unique_i == ind_i])
1682-
# for those where we have more than one crossing, place a snapping line in the middle
16831767
if max_count > 1:
1768+
# This could use some improvement in future:
1769+
# currently we just calculate the position of the leftmost intersection
1770+
# and the rightmost intersection in column i
1771+
# and just place a snapping line in between.
16841772
min_dx = np.min(h_cells_dx[h_cells_ij[:, 0] == ind_i])
16851773
max_dx = np.max(h_cells_dx[h_cells_ij[:, 0] == ind_i])
16861774
snapping_lines_x.append(x[ind_i] + 0.5 * (min_dx + max_dx))
16871775
detected_gap_width = min(detected_gap_width, max_dx - min_dx)
1776+
# This is expected to work fine when we have a simple gap/strip passing
1777+
# through a number of cells. But not optimal if we have slanted/curved
1778+
# boundaries and/or more than 2 intersections.
16881779

16891780
return [Box.unpop_axis(X, (None, None), axis=tan_dims[0]) for X in snapping_lines_x] + [
16901781
Box.unpop_axis(Y, (None, None), axis=tan_dims[1]) for Y in snapping_lines_y

0 commit comments

Comments
 (0)