diff --git a/gplugins/common/config.py b/gplugins/common/config.py index 8393351a..a529eb29 100644 --- a/gplugins/common/config.py +++ b/gplugins/common/config.py @@ -22,6 +22,8 @@ class Path: results_tidy3d = home / ".tidy3d" test_data = repo / "test-data" sparameters_repo = test_data / "sp" + klayout = module_path / "klayout" + klayout_tech = klayout / "tech.lyt" extra = repo / "extra" cwd = pathlib.Path.cwd() diff --git a/gplugins/klayout/get_netlist.py b/gplugins/klayout/get_netlist.py index 63a5fa0b..b18031b5 100644 --- a/gplugins/klayout/get_netlist.py +++ b/gplugins/klayout/get_netlist.py @@ -1,7 +1,10 @@ +import gdsfactory as gf import kfactory as kf import klayout.db as kdb from gdsfactory.typings import PathType +from gplugins.common.config import PATH + def get_l2n( gdspath: PathType, klayout_tech_path: PathType | None = None @@ -17,17 +20,57 @@ def get_l2n( """ lib = kf.kcell.KCLayout(str(gdspath)) + Tech = kdb.Technology() + + tech_dir = PATH.klayout + tech_dir.mkdir(exist_ok=True, parents=True) + if not klayout_tech_path: + gf.get_active_pdk().klayout_technology.write_tech(tech_dir) + klayout_tech_path = tech_dir + + # klayout tech path is now assumed to contain a `tech.lyt`` file to use + technology = Tech.load(str(klayout_tech_path / "tech.lyt")) + lib.read(filename=str(gdspath)) c = lib[0] - if klayout_tech_path: - technology = kdb.Technology() - technology.load(str(klayout_tech_path)) - l2n = kf.kdb.LayoutToNetlist(c.begin_shapes_rec(0)) l2n.threads = kf.config.n_threads + + reversed_layer_map = dict() + for k, v in gf.get_active_pdk().layers.items(): + reversed_layer_map[v] = reversed_layer_map.get(v, set()) | {k} + + # define stack connections through vias + layer_connection_iter = [ + [ + (connection.layer_a(), connection.via_layer(), connection.layer_b()) + for connection in connectivity.each_connection() + ] + for connectivity in technology.component("connectivity").each() + ][0] + correct_layer_names = set(sum(layer_connection_iter, ())) + + # define the layers to be extracted for l_idx in c.kcl.layer_indexes(): - l2n.connect(l2n.make_layer(l_idx, f"layer{l_idx}")) + layer_info = c.kcl.get_info(l_idx) + names = reversed_layer_map[(layer_info.layer, layer_info.datatype)] + try: + same_name_as_in_connections = next(iter(correct_layer_names & names)) + except StopIteration: + same_name_as_in_connections = next(iter(names)) + l2n.connect(l2n.make_layer(l_idx, same_name_as_in_connections)) + + for layer_a, layer_via, layer_b in ( + (l2n.layer_by_name(layer) for layer in layers) + for layers in layer_connection_iter + ): + # Don't try to connect Nones + if all((layer_a, layer_via)): + l2n.connect(layer_a, layer_via) + if all((layer_b, layer_via)): + l2n.connect(layer_via, layer_b) + l2n.extract_netlist() return l2n @@ -52,8 +95,6 @@ def get_netlist(gdspath: PathType, **kwargs) -> kdb.Netlist: if __name__ == "__main__": from gdsfactory.samples.demo.lvs import pads_correct, pads_shorted - from gplugins.common.config import PATH - c = pads_correct() c = pads_shorted() gdspath = c.write_gds()