PathLength
- class ipkiss3.all.PathLength
Calculates the path length between two ports.
PathLength extracts a netlist from the layout and builds a connection graph of the circuit, allowing you to trace the paths between source and target ports. You can then calculate the total length of each of these paths.
By default, the trace_length method will be invoked to calculate the length of a component. If no trace_length method is available the component will be ignored.
The calculation of the path length can be customized by registering custom implementations.
- Parameters:
- layout: LayoutView or Layout
LayoutView or Layout of the circuit to analyze.
- source: str
Identifier of the start port.
- target: str
Identifier of the end port.
Examples
import si_fab.all as pdk import ipkiss3.all as i3 class Circuit(i3.PCell): class Layout(i3.LayoutView): def generate(self, layout): mmi = pdk.MMI1x2() wg = i3.Waveguide().Layout( shape=[ (0, 0), (20, 0), ] ) layout += i3.place_and_route( insts={ "wg": wg, "mmi1": mmi, "mmi2": mmi, }, specs=[ i3.Join("wg:out", "mmi1:in1"), i3.ConnectManhattan("mmi1:out1", "mmi2:out1"), i3.ConnectManhattan("mmi1:out2", "mmi2:out2", control_points=[i3.H(15.0)]), i3.FlipH("mmi2"), i3.Place("mmi2:in1", (100, -10)), ], ) layout += i3.expose_ports(layout, {"wg:in": "opt1", "mmi2:in1": "opt2"}) return layout layout = Circuit().Layout() layout.visualize(annotate=True) length = i3.PathLength(layout).trace("opt1", "opt2").total_length() # outputs: 81.4155365094152 print(length) @i3.PathLength.register def mmi_length(layout: pdk.MMI1x2.Layout, source, target): return 20.0 length2 = i3.PathLength(layout).trace("opt1", "opt2").total_length() # outputs: 121.4155365094152 print(length2) assert length2 == length + 2 * 20.0 # Print a report of all components, paths, and length calculations (results) between "opt1" and "opt2". report = i3.PathLength(layout).trace("opt1", "opt2").report() print(report) print(report["trace0"]["results"]) # outputs: [20.0, 20.0, 61.415536509415205, 20.0] print(report["trace1"]["results"]) # outputs: [20.0, 20.0, 65.41553650941526, 20.0]
import math import si_fab.all as pdk import ipkiss3.all as i3 @i3.PathLength.register def dc_length(layout: pdk.SiDirectionalCouplerS.Layout, source, target): # Extract the length from the directional coupler's waveguides top, bottom = layout._get_wg_shapes() return top.length() class Circuit(i3.PCell): desired_length = i3.PositiveNumberProperty(default=140.0) class Layout(i3.LayoutView): def generate(self, layout): dc = pdk.SiDirectionalCouplerS() y_control = 20 temp_layout = i3.place_and_route( insts={ "dc1": dc, "dc2": dc, }, specs=[ i3.Place("dc2", (40, 0)), i3.ConnectManhattan("dc1:out1", "dc2:in1", control_points=[i3.H(-y_control)]), ], ) length = i3.PathLength(temp_layout).trace("dc1:in1", "dc2:out1").total_length() y_control = y_control + (self.desired_length - length) / 2 layout += i3.place_and_route( insts={ "dc1": dc, "dc2": dc, }, specs=[ i3.Place("dc2", (40, 0)), i3.ConnectManhattan("dc1:out1", "dc2:in1", control_points=[i3.H(-y_control)]), i3.ConnectManhattan("dc1:out2", "dc2:in2"), ], ) length = i3.PathLength(layout).trace("dc1:in1", "dc2:out1").total_length() assert math.isclose(length, self.desired_length) # Check if the final arm length is correct return layout layout = Circuit(desired_length=140.0).Layout() layout.visualize()
- classmethod register(func)
Decorator to register a custom implementation to extract the length.
- Parameters:
- func: Callable
Function to extract the length.
Examples
import si_fab.all as pdk @i3.PathLength.register def mmi_length(layout: pdk.MMI1x2.Layout, source, target): return 20.0
import si_fab.all as pdk @i3.PathLength.register def dc_length(layout: pdk.SiDirectionalCouplerS.Layout, source, target): # Extract the length from the directional coupler's waveguides # This way the returned length varies depending on the actual DC length top, bottom = layout._get_wg_shapes() return top.length()
import si_fab.all as pdk @i3.PathLength.register def mmi_length(layout: pdk.MMI1x2.Layout, source, target): # use python's match/case statements # to declare the lengths between the port pairs match (source, target): case ("in1", "out1") | ("out1" | "in1"): return 20.0 case ("in1", "out2") | ("out2" | "in1"): return 20.0 case _: raise LookupError(f"unknown port pair ({source}, {target})
- trace(source, target)
Derives the traces between source and target.
- Parameters:
- source: str
Source Port identifier e.g. “porta” or “instA:port1”.
- target: str
Target Port identifier e.g. “porta” or “instA:port1”.
- Returns:
- ipkiss3.pcell.layout.path_length_tracer.PathLengthTraces