Tagged: pathfinder, trace, distance, cell_iter, pin snapping
- This topic has 5 replies, 2 voices, and was last updated 4 years, 10 months ago by
Ronald.
-
AuthorPosts
-
11 April 2020 at 11:17 #6061
iv_tern
MemberHello all,
Had a bunch of questions about interconnects and sanity checks, that I have lumped together, apologies if this poses difficulty.
I was wondering if there is any way of checking whether an interconnect clips onto a pre-existing feature? I tried playing around with clipper, but it seemed to always return an empty list (have to confirm this, as I can’t use my nazca machine for a day or two). Similarly, is there an implemented way of checking the minimum distance between two features? Finally, is there a way to check the overall length of an interconnect?
11 April 2020 at 11:53 #6063Ronald
KeymasterDear iv_tern,
When you place elements (cells) Nazca checks on all of the pins of the element if they are closer than a small value epsilon (typically < 1 nm) from an existing pin in the parent cell. In that case Nazca internally creates a connection between all matching pins for a complete circuit netlist. The connections are validated against a number of conditions, like the pin width, xsection and symmetry. Note this is on pins, not an arbitrary feature of the polygons or polylines; It is about circuit connectivity in this context, not geometrical drawings.
The same feature can be used for snapping (useful in a drag & drop environment) by using a larger epsilon and let the placement follow the existing pin if close enough and if all the other required pin properties (apart from spatial proximity) match according to a customizable set of rules. It needs some small adaptations in the code to be able to switch from proximity based in-place connections to snapping connections depending on the situation (script vs mouse).
—
The distance between two pins can be obtained as followsx, y, a = nazca.diff(pin1, pin2)
Some other features in this context may be useful, e.g. getting the position in between two pins:
x, y, a = nazca.midpoint(pin1, pin2) pin = nazca.midpointer(pin1, pin2)
—
The geometrical length of interconnects can be obtained by starting a “trace”:import nazca as nd ic = nd.interconnects.Interconnect(width=1.0, radius=100) nd.trace.trace_start() ic.strt(length=200).put(0) ic.sbend(offset=100).put() ic.bend(angle=45).put() nd.trace.trace_stop() length = nd.trace.trace_length() print(length)
The trace does not check if elements are connected.
Instead of the trace method you can use the pathfinder, which returns all connected paths and their geometrical lengths, starting in the pin provided to the “start” keyword.
import nazca as nd ic = nd.interconnects.Interconnect(width=1.0, radius=100) e1 = ic.strt(length=200).put(0) ic.sbend(offset=100).put() ic.bend(angle=45).put() nd.pathfinder(start=e1.pin['a0'])
Note that some parametric interconnect elements may not have a path length yet.
Ronald
13 April 2020 at 14:32 #6075iv_tern
MemberThank you for your input!
One final question, if that’s ok – is there any way to get the coordinates of all the points in an interconnect (i.e. where in the object properties as those stores?) I.e. doing the reverse of the tutorial example of placing a polygon, where we give a list of points and then use nd.Polygon(points=pts, layer=’layer’).put(coords).
Let me know if this isn’t clear, and I can try to elaborate.
13 April 2020 at 17:23 #6084Ronald
KeymasterDear iv_tern,
The properties are accessible through the Cell objects, which are themselves in a tree structure.
If you want to see the polygons (if I interpret your question well) you can iterate over all cells under a specific cell and in each cell iterate over all polygons. The method cell_iter() is available for that as demonstrated in the example below.
import nazca as nd import nazca.demofab as demo cell_1 = demo.deep.strt(length=10, width=5) print("points in original polygon:") for NT in nd.cell_iter(cell_1): # NT is a named tuple object if NT.cell_start: print(f"\ncell: '{NT.cell.cell_name}'") for i, (pgon, points, bbox) in enumerate(NT.iters['polygon']): print(f"{i}: points: {pgon.points}, layer: '{pgon.layer}'")
In the line (pgon, points, bbox), the “pgon” refers to the original polygon object, the “points” to the polygon translated w.r.t. the top cell provided to cell_iter, and “bbox” the translated bounding box.
Ronald
14 April 2020 at 13:33 #6090iv_tern
MemberDear Ronald, thank you very much for your prompt response – this is almost what I’m looking for.
If I run the following code:
import nazca as nd nd.clear_layers() nd.clear_layout() toy_points1=[(0,0), (0,7), (10, 14), (0,25)] toy_points2=[(0,0), (0,15), (10, 14), (0,20)] with nd.Cell('toy_poly1') as tp1: toy_polygon1=nd.Polygon(points=toy_points1, layer=1).put(0) nd.Pin('a0').put(0, 0, 180) nd.Pin('b0').put(10, 2.5, 0) with nd.Cell('toy_poly2') as tp2: toy_polygon2=nd.Polygon(points=toy_points2, layer=1).put(0) nd.Pin('a0').put(0, 0, 180) nd.Pin('b0').put(10, 2.5, 0) p1 = tp1.put(0,0,0) p2 = tp2.put(40,40,90) print("points in original polygon:") for NT in nd.cell_iter(p1): # NT is a named tuple object if NT.cell_start: print(f"\ncell: '{NT.cell.cell_name}'") for i, (pgon, points, bbox) in enumerate(NT.iters['polygon']): print(f"{i}: points: {pgon.points}, layer: '{pgon.layer}'") print("points in original polygon:") for NT in nd.cell_iter(p2): # NT is a named tuple objec if NT.cell_start: print(f"\ncell: '{NT.cell.cell_name}'") for i, (pgon, points, bbox) in enumerate(NT.iters['polygon']): print(f"{i}: points: {pgon.points}, layer: '{pgon.layer}'")
I get this output:
points in original polygon: cell: 'toy_poly1' 0: points: [(0, 0), (0, 7), (10, 14), (0, 25)], layer: '1/0/None' points in original polygon: cell: 'toy_poly2' 0: points: [(0, 0), (0, 15), (10, 14), (0, 20)], layer: '1/0/None'
Whereas I’m looking for the output, that takes into account the fact that p2 has been .put at 40,40 and rotated 90. I.e. I’m interested in the points with the origin of the entire mask, as opposed to the origin of the top cell, if this makes sense.
Regards,
iv_tern14 April 2020 at 13:39 #6091Ronald
KeymasterDear iv_tern,
print
points
rather thanpgon.points
for the polygon coordinates with respect to the first instantiated parent cell, which maximaly goes up to the cell provided to cell_iter(), the “topcell” in this context.To get the polygon with respect to the topcell, regardless of any cell instantiation, flatten the hierarchy with
flat=True
orhierarchy='flat'
.In your case you are looking for the position with respect to the “nazca” top cell, which is always created as a blank canvas when importing nazca.
– nazca
.. – tp1
…. – polygon1
.. – tp2
…. – polygon2That “nazca” topcell can be accessed as nd.cfg.defaultcell and you get:
for NT in nd.cell_iter(nd.cfg.defaultcell, flat=True): if NT.cell_start: print(f"\ncell: '{NT.cell.cell_name}'") for i, (pgon, points, bbox) in enumerate(NT.iters['polygon']): print(f"{i}: points: {points}, layer: '{pgon.layer}'")
output:
cell: 'nazca' cell: 'toy_poly2' 0: points: [(40.0, 40.0), (25.0, 40.0), (26.0, 50.0), (20.0, 40.0)], layer: '1/0/None' cell: 'toy_poly1' 0: points: [(0, 0), (0, 7), (10, 14), (0, 25)], layer: '1/0/None'
Alternatively put the design in a custom topcell:
nd.with(name='topcell') as top: p1 = tp1.put(0, 0, 0) p2 = tp2.put(40, 40, 90)
and use
nd.cell_iter(cell=top, flat=True)
to get the coordinates as before andnd.export_gds(top)
in case you export cell “top” to gds.Ronald
-
AuthorPosts
- You must be logged in to reply to this topic.