FAQ & Troubleshooting
Paths
I want to apply a taper or attach bridges along an entire path. Can I do this without having to worry about each individual segment in the path?
You can use the simplify! function to combine some range of segments into a single compound segment with a single style.
A caveat: Decorated styles should not become part of compound styles, for now. Avoid this by decorating / attaching references at the end.
I want to apply MeshSized or OptionalStyle to a path. How do I do that?
Short answer: my_style(simplify(my_path)).
Longer answer: A GeometryEntityStyle can only be applied to a GeometryEntity, but a Path is a GeometryStructure. However, simplify(my_path) returns a single GeometryEntity describing the entire path. (simplify is not to be confused with simplify!, which modifies the path to contain only that entity, as in the previous question.) That entity can then be styled and placed in a coordinate system as usual: place!(cs, my_style(simplify(my_path)), metadata).
Caveat: Any attachments to the path are discarded when that entity is used outside a path. (See the following question.)
Note that this will still not work for Rounded, which can be applied only to AbstractPolygon. To round the ends of a path, you can use terminate!.
Why is Path a GeometryStructure rather than a GeometryEntity?
Path is a GeometryStructure because it can contain references to other structures (added using attach! or overlay!).
Meanwhile, a GeometryEntity can only be associated with a single piece of metadata. The metadata applied to a Path is not shared by those references, so Path can't be a GeometryEntity.
Note that it is possible for a GeometryEntity to define disjoint shapes. They just have to share metadata when placed in a coordinate system. For example, a straight CPW segment can be represented as a single entity, even though it defines two disjoint rectangles, since they must have the same metadata. Specifically, a CPW-styled segment is represented as a Paths.Node <: GeometryEntity, which combines a Paths.Straight segment and a Paths.CPW style. (Path styles are unrelated to GeometryEntityStyle.)
A Path then contains a vector of Paths.Node. While these nodes do all share metadata, they can also have styles that attach references along the segment. If a node is used as its own entity outside the context of a Path, however, those references are ignored.
GDS output
I can't save my GDS file.
Try deleting any file that happens to be at the target path. A corrupted file at the target path may prevent saving.
When I refresh KLayout after saving changes to a file, everything disappears. Where did it go?
The most likely answer is that the name of the top-level cell changed. To show the new geometry, right click on the cell name in the upper left panel and choose "Show As New Top". To avoid this in the future, make sure your top-level cell has a fixed name, rather than something generated by uniquename. For example, if you are saving the result of a flatten operation, you can use the name keyword argument in flatten.
When I look at my final GDS file, there are ~1nm gaps between edges that should coincide. Why is this happening, and can it be avoided?
This can happen for at least two reasons, both of which are related to the use of integer coordinates in a database unit (typically 1nm) by the GDSII format.
Gaps between elements in the same
Cellcan occur if you have two line segments that are meant to be collinear but have different endpoints. The four endpoints will be rounded to four points on the integer grid, and these four points will not necessarily be collinear. One solution here is to insert a point in either line segment where any endpoint of the other falls. This is how an open CPW termination created byPaths.terminate!is drawn (when not using rounding), instead of just placing a four-point rectangle at the end of the CPW.Gaps between elements in different
Cells can occur if you're usingCellReferences (corresponding to SREF in the GDSII format described here), since coordinates within each cell as well as the origins of cell references are rounded to integers on saving. This occurs particularly often when rotating references by angles other than multiples of 90 degrees. One solution is toflattencells before saving, since DeviceLayout's internal representation ofCells uses 64-bit floating point precision.
Schematic-Driven Design
Is there a way to not render a node in the SchematicGraph?
Rendering with a LayoutTarget will skip all entities with the special metadata DeviceLayout.NORENDER_META = SemanticMeta(:norender), so there's a workaround: Try running map_metadata!(component(mynode), (_) -> DeviceLayout.NORENDER_META) before calling build! or render!.
How do I attach components along a path in the schematic?
Given a schematic node containing the Path, you can attach your component to that with attach!(::SchematicGraph, ...). For example:
pa = Path(
Point(0μm, 0μm),
α0=0°,
metadata=SemanticMeta(:metal_negative),
name=uniquename("coupseg")
)
straight!(pa, 250μm, cpw_style)
coupling_seg_node = add_node!(g, pa)
rres_node = add_node!(g, readout_resonator)
attach!.(
g,
coupling_seg_node,
rres_node => :readout_line,
pathlength(SchematicDrivenLayout.component(coupling_seg_node).path) / 2,
i=1,
location=1
)
# ... then fuse/route these to other nodes as usualHow do I attach components along a route in the schematic?
If you have an existing component created by route!(::SchematicGraph, ...), you can attach CoordinateSystemReferences with the function attach!(r::RouteComponent, c::CoordSysRef, t::Coordinate; location::Int=0), and it works like attaching things to a single-segment Path. Right now there's no way to attach a Component along a RouteComponent so that it becomes part of the schematic. For that, use a Path with attach!(::SchematicGraph, ...).
What's with all the semicolons?
Semicolons are used in Julia in a few places related to key-value pairs:
In function definitions, separating positional arguments from keyword arguments.
- If there are no positional arguments, it's still necessary to start with a semicolon:
function f(; a=1, b=2)...
- If there are no positional arguments, it's still necessary to start with a semicolon:
In function calls, separating positional arguments from keyword arguments.
- This is optional, but may be used for clarity, especially when splatting keyword arguments when there are no positional arguments
To construct literal
NamedTuples:(; a=1, b=2).- The semicolon is optional, but if there is only one key/value pair, either a leading semicolon
(; a=1)or trailing comma(a=1,)must be used to distinguish it from the expressiona=1wrapped in parentheses. (The leading semicolon is preferred for a couple reasons. A single-elementTuplealso uses a trailing comma; also, it's easy to accidentally remove the required trailing comma when removing all but one elements from the expression.) - An empty
NamedTuplecan also be constructed with(;). - You can also construct
NamedTuples programmatically by splatting an iterator yielding key-value pairs after the semicolon:(; a=1, my_namedtuple..., b=2).
- The semicolon is optional, but if there is only one key/value pair, either a leading semicolon
On the left-hand side of an assignment, to unpack/"destructure" a
NamedTupleorstruct(starting in Julia 1.7).(; a, b) = xis equivalent to the assignmentsa = x.aandb = x.b
For completeness, there are a couple unrelated uses of semicolons:
To separate statements without a line break, as in
a = x.a; b = x.bTo separate array literals for vertical concatenation, as in
A_2x3 = [1 2 3; 4 5 6]- N semicolons concatenate along the Nth dimension, as in
A_3x2 = [1:3 ;; 4:6]
- N semicolons concatenate along the Nth dimension, as in
In SchematicDrivenLayout specifically, we often work with the parameters of a Component as a NamedTuple.
How do I add a schematic node so that it's at a fixed position on the chip?
One way to do that is to make a top-level parent component with a hook at the position you want. For example, you can use the built-in SchematicDrivenLayout.Spacer component:
g = SchematicGraph("fixed_demo")
spacernode = add_node!(g, Spacer(p1=Point(6mm, 1mm)))
fuse!(g, spacernode => :p1_north, mycomp => :myhook)Any "root" node (one that's not attached to any previously added non-route node by any chain of connections; this always includes the first node added to a graph) will have its origin at the global origin.
In many cases, it's useful to start with a "template" component containing multiple required fixed-position hooks. This is how ExampleChip in the DemoQPU17 example fixes the positions of ports on the edge of the chip.
How do I attach one component to another if there's no hook where I need it?
If you need some offset relative to existing hooks, you can use the Spacer (see above) with a p0 compass hook fused to one component and a p1 compass hook fused to the other.
For truly ad-hoc positioning, you can use fuse! with an actual Hook object rather than a Symbol identifying the Hook for one or both components. For example, this might be appropriate for labeling and annotation:
fuse!(
g,
mynode => PointHook(0.5mm, 0.5mm, 90°),
ArrowAnnotation{typeof(1.0nm)}(text="(0.5mm, 0.5mm) in mynode's coordinate system") =>
:tip
)However, if you find yourself needing a consistent hook that doesn't already exist for MyComponent, then it's generally better to update the component definition so that the hook is available by name through hooks(::MyComponent).
I edited a component's _geometry! method but I'm still getting the old geometry. Can I get the new geometry without restarting Julia?
First, make sure the new code is being loaded. You can use Revise to automatically use updated code within any package loaded after Revise with import or using as well as any scripts loaded with includet.
Most component types, including those defined using @compdef, contain a _geometry field that allows them to store their geometry so that it is only generated once. It is not marked as dirty or automatically regenerated when geometry methods change. Currently, to regenerate the geometry, you have to empty the geometry or instantiate a new component. (For composite components, there are also similar fields for their graph, schematic, and hooks.)