Forum Replies Created
-
AuthorPosts
-
Ronald
KeymasterDear Lumico,
You can add growy similar to growx, as described in this tutorial on xsections and layers.
Ronald
Ronald
KeymasterDear Lumico,
This is the same/similar effect as the snapping discussed in this post.
The delta is in the order of the grid resolution or smaller.The simplest way to align the pin with the end line is to add a polygon point to the waveguide at the pin location. This is something that may be added to Nazca, mainly to avoid this visual misalignment (mostly harmless). Note this phenomena is not specific for the Euler bends but something that tends to show up for floating point positioning and subsequent snapping to a grid.
The above is optically and process-technically mostly not an issue, but floating point rotations and/or translations in combination with hierarchical (gds) design can lead to (grid resolution) notches after flattening a design for mask manufacturing. In silicon photonics the DRC tends to be relatively unforgiven and it flags these notches (they can be waived, typically). The reason is that these DRC rules are based on previously existing “multiples of 90 deg” kind of geometries and not on photonic floating point geometry. In Nazca we created methods that force cells to ultimately snap polygons to the same top cell grid. These are not in the public Nazca release branch at present.
Ronald
Ronald
KeymasterDear Jon,
The properties dict works fine as you use it.
Note that from Nazca >0.5.12 there will be a pin.radius attribute to store the radius directly in the pin. This also allows pin2pin DRC on connections, in addition to xs, width, angle and symmmetry checks.
Ronald
29 March 2021 at 10:10 in reply to: Calculating loss for a waveguide section which is not straight #6422Ronald
KeymasterDear Tuhin,
There are basically three loss factors in a bent waveguide:
1- material loss
2- sidewall (roughness) loss
3- radiation lossThe first two are also present in a straight guide. The extra loss in the bend is both an increase in (2), due to a higher field strength at the waveguide edge in a bend and (3). Both increase with smaller radii. To obtain (3) you need a complex (2D) modesolver that applies a conformal transformation to cylindrical coordinates. The complex index of the solution provides the bend loss. Hence, you need 2D bend solver, of which there are many, commercial ones like in VPI photonics, Lumerical or FIMwave, or open source solvers like in wgms3d.
To get the loss in the bent guide a good approximation is to add the radiation loss to the known straight waveguide loss.
Ronald
Ronald
KeymasterDear Tommaso,
Good to hear Nazca works well for you.
In principle, a cell should not be changed after creation and there is no need for that. Note that the
put_stub()does accept a list of pins, so if you only want to see pin ‘a0’, simply usend.put_stub(['a0']), ornd.put_stub('a0'). But I think that’s what you use your boolean for that you mentioned, i.e. change that list of pins.That said, the stub/pin features discussed here are just a visualization of the pin, and the pin (Node object) actually already has a (sleeping) “show” attribute. It would not harm the cells fundamental features (like its connectivity) when changing the “show” after cell closure. It would quite straight forward to implement a
cellA.showpins()method, and subsequently filter on the “show” attribute at time of mask export. It can actually be useful to clean up the layout view this way. Hence, I will add the lines for the next release (after 0.5.13).Ronald
Ronald
KeymasterDear Rose,
If I copy paste the example with nd_export_plt() as provided and run in Spyder it shows the plot in the Spyder plot tab (Spyder4), as expected and shown in the post. If you do not see it, do you see any matplotlib output outside Nazca?
If I copy paste the example and *replace*
nd.export_plt(C)withnd.export_gds(C)it exports the gds as expected.Starting layout export... ...gds generation ...Wrote file './nazca_export.gds'Note-1
nd_export_plt(C) # the C is needed as cell C is never put() in the example. # alternatively: C.put(0) nd_export_plt() # export the nazca main canvas having C on board.If you keep both plt and gds output commands you have to check the notes below.
Note-2:
nd_export_plt() # deletes/resets the canvas after export nd_export_gds() # nothing to drawNote-3:
nd_export_plt(clear=False) # does *not* delete the canvas nd_export_gds() # now generates full gdsRonald
Ronald
KeymasterDear Marios,
Yes that will work, but as mentioned it needs the anglei and angleo keywords to be added to the Tp_Viper internally, which will now be in the new Nazca release (>0.5.12).
For your information, the Viper internally only needs an override when angles are provided, like below. Angle “ab” carries through to a deeper polygon routine.
if angleo is None: ab = degrees(atan2( Y(1)-Y(1-d), X(1)-X(1-d))) # angle of last semgent else: ab = angleoRonald
Ronald
KeymasterDear Rose,
It generates a png as the one shown in the post.
You may need to add a line likeplt.show().
(to poke Matplotlib,import matplotlob.pyplot as plt)For gds you can use
nd.export_gds(C)Ronald
Ronald
KeymasterDear Marios,
The discretization may indeed lead to small polygon issues at the start and end points of a curve, as these angles are not exact when based in the last two points near an edge, if there is a curvature.
This deviation can be avoided by providing the exact “input” and “output” angles of a curve. In the case of the Tp_viper() these should be optionally provided through keywords
angleiandangleo, for the “input” and “output” of the curve, but these are not yet in the Viper keywords. I will add them (now always calculated inside the function before calling a deeper polygon function). Another way to improve the angle is to add a smaller last step in the Viper angle calculation, though this may suffer from numerical noise at some point. Yet another way is to extrapolate the curvature trend near the end an extrapolate that to the end point.Ronald
PS
Because you seem to have an input and output in the x-direction, you would simply haveanglei=180, angleo=0in your case.Ronald
KeymasterDear Rose,
To make a polygon shape follow an “arbitrary” line would require to transform its polygon from the standard straight coordinate system to one that follows the line. For an arc you can do something like below, where the red shape is the original shape and the blue is wrapped on a circular arc:
from math import sin, cos import nazca as nd def create_taper(): """Create a taper shape as you see fit.""" dh = 1 s = 30 N = 20 points1 = [] points2 = [] for i in range(N + 1): scale = -0.5 + i / N points1.append((s*scale, dh * (1 - abs(scale)))) points2.append((-s*scale, -dh *(1 - abs(scale)))) return points1 + points2 def bend_polygon(points=None, radius=10): """Bend a polygon along a circular arc.""" pointsout = [] # Conformal transformation to a circular grid: for x, y in points: x2 = (radius + y) * sin(x / radius) y2 = (radius + y) * cos(x / radius) pointsout.append((x2, y2)) return pointsout with nd.Cell() as C: radius = 15 points = create_taper() pointsbend = bend_polygon(points=points, radius=radius) nd.Polygon(points=points, layer=1).put(0, radius) nd.Polygon(points=pointsbend, layer=2).put(0) nd.export_png(C)Ronald
Ronald
KeymasterDear Rose,
Would you have a picture of what you like to achieve?
Ronald
Ronald
KeymasterDear JHazan,
The warning has been added to indicate that a second @hashme decorator has been activated before using the information generated by the first hashme in a
with Cell()statement. Nazca warns now by raising an Exception. The hashme inspects the function it decorates and uses that to create a hash of call signature to add to the cell. That hash info is used in the first nd.Cell() call.You probably tried something like this
import nazca as nd @nd.bb_util.hashme() # A def A(): with nd.Cell(): ... @nd.bb_util.hashme() def B(): A() # call A() which has a hashme, which deletes the B hash with nd.Cell(): # B hash lost at this point ....The above overwrites the B hash due to the A call.
Better is the following:@nd.bb_util.hashme() def A(): with nd.Cell(): ... @nd.bb_util.hashme() def B(): with nd.Cell(): # use B hash before calling other hashed functions. A() ....Ronald
Ronald
KeymasterDear MirceaB,
The cell instances c1 and c2 need to be connected in the scope of your cell ‘final’, not the pins inside the original cells. Pins inside cell1 and cell2 are indeed not in scope of cell ‘final’.
Change the last line in cell ‘final’ to
demofab.deep.cobra_p2p(pin1=cl1.pin['b0'], pin2=cl2.pin['a0']).put()Ronald
Ronald
KeymasterDear Dagi,
If you makes cells of the holes, as in cell ‘hole’, the work would need to be done on the cell instances in your pxtal. This is possible via the cell_iter(), but here there may be a simpler solution by placing hole polygon objects directly in the pxtal cell. This is not something I have used before a lot, but you can scan and update directly on the polygon attribute in the cell object and filter it based on e.g. x-position of a hole, as demonstrated in the example below.
I also added pins to make it a circuit type waveguide.import nazca as nd import numpy as np # Add layer nd.add_layer(name="ebeam", layer=1, overwrite=(True), fill_color=("red")) # Define PhC parameters hole_radius = 0.125 PhC_ax = 0.425 PhC_ay = 0.5 * PhC_ax * np.sqrt(3) hole_polygon = 20 nx = 20 ny = 10 # Define hole shape and geometry hole_shape = nd.geometries.circle(radius=hole_radius, N=hole_polygon) hole1 = nd.Polygon(points=hole_shape, layer="ebeam") # ================================ # make triangular lattice of holes # ================================ with nd.Cell('pxtal', instantiate=False) as pxtal: hole_reference = [] for ix in np.arange(-np.floor(nx / 2), np.floor(nx / 2)): for iy in np.arange(-np.floor(ny / 2), np.floor(ny / 2) + 1): x = (ix + np.mod(iy, 2) * 0.5) * PhC_ax y = iy * PhC_ay if ix != -np.floor(nx / 2) or np.mod(iy, 2) != 0: hole1.put(x, y) nd.Pin('a0').put(0, 2, 90) nd.Pin('b0').put(0, -2, -90) nd.put_stub() # ============================= # Add line-defect PhC waveguide # ============================= pgons_new = [] for pgon in pxtal.polygons: node, Poly = pgon x, y, a = node.xya() if abs(x) > 0.2: pgons_new.append((node, Poly)) pxtal.polygons = pgons_new pxtal.put(0, 0, 90) # Export gds file nd.export_gds(filename="PhC.gds")Ronald
Ronald
KeymasterRonald
KeymasterDear lumico,
A paralellogram function as you describe can be defined along these lines:
def paralellogram(x=10, y=20, dy=None, y2=None): if y2 is None: y2 = y if dy is None: dy = 0.5 * (y - y2) return [(0, 0), (x, dy), (x, y2+dy), (0, y)] nd.Polygon(points=paralellogram(y2=2), layer=1).put() nd.Polygon(points=paralellogram(dy=1, y2=5), layer=1).put(15) nd.export_png()Ronald
25 September 2020 at 11:22 in reply to: Trouble understanding normalized variable t: [0,1] for nd.strt() #6246Ronald
KeymasterDear lumico,
It seems the edge definition you used for the taper scales with
t*length_1.
Remove length_1 to make it indepent of the length as you need?Ronald
17 September 2020 at 21:34 in reply to: Select/delete objects in a cell with a size smallerthan x #6238Ronald
KeymasterDear Cameron,
The best way to go about is to use the cell_iter(). It can dissect a Cell and rebuild it. This example shows an extended version where you can filter any cell element. In your case you can rebuild your gds but filter specific polygons, as indicated with the upper case remark:
# Nazca-0.5.12 import nazca as nd gds = 'your_file.gds' mask = nd.load_gds(gds) ly = nd.layout(layermap={}, layermapmode='all') for params in nd.cell_iter(mask): if params.cell_close: ly.close() continue if params.cell_create: ly.open(params=params) for pgon, xy, bbox in params.iters['polygon']: # xy and bbox coordinates are w.r.t. first instantiated parent # SELECT HERE WHICH POLYGONS YOU WANT TO ADD: if < size of positions in xy > 5x5 >: ly.add_polygon(points=xy, layer=pgon.layer) else: print(f"polygon {xy} has been filtered out.") for pline, xy, bbox in params.iters['polyline']: # xy and bbox coordinates are w.r.t. first instantiated parent ly.add_polyline(points=xy, layer=pline.layer) for anno, pos in params.iters['annotation']: ly.add_annotation(text=anno.text, layer=anno.layer, pos=pos) for inode, [x, y, a], flip in params.iters['instance']: ly.add_instance(inode=inode, trans=[x, y, a], flip=flip) ly.put() nd.export_gds(filename=gds[:-4]+'_rebuild')If you know that your polygons that you want to filter are in a specific layer, you can use that too (I reversed the logic a bit compared to the example above):
if pgon.layer == nd.get_layer(<layer>) and < size of positions in xy < 5x5 >: print(f"polygon {xy} has been filtered out.") else: ly.add_polygon(points=xy, layer=pgon.layer)The get_layer() is to make sure you get the layer ID regardless if you use the layer numbers or layer names. pgon.layer contains the layer ID as well.
Ronald
Ronald
KeymasterDear iv_tern,
Note that obj1 in
pin2=obj1.pin['a0']is not in scope of this snippet. If obj1 refers to an instance in another cell than you are working in you will get the “outside the scope” message. Note that obj1 should not be a Cell. Try type(obj1) to see what obj1 is.
Can you reproduce this behaviour without the custom import?The nd.clear statements are better put directly after
import nazca as nd
Which Nazca version are you using?Ronald
Ronald
KeymasterDear Alex,
Define a single polygon for the grating element and place that element repeatedly on the spine of the spiral waveguide curve at the right intervals. Would that work for your use case?
Ronald
-
AuthorPosts