Coder Social home page Coder Social logo

kfactory's Introduction

gdsfactory 8.5.3

docs PyPI PyPI Python Downloads MIT codecov Binder Colab

🚀 Notice: Major Release

We are excited to announce that gdsfactory has upgraded its backend from gdstk to KLayout. This change brings enhanced routing functions and additional features from KLayout, including DRC, dummy fill, and connectivity checks.

Notice that the routing and some advanced functions have changed. For a complete list of changes, please refer to our migration guide or review the updated layout tutorial.

Gdsfactory is a Python library for designing chips (Photonics, Analog, Quantum, MEMs, and more), 3D printed objects, and PCBs. Here, you can code your designs in Python or YAML, perform verification (DRC, simulation, and extraction), and enable automated testing in the lab to ensure your fabricated devices meet your specifications.

As input you write python code, as an output GDSFactory creates CAD files (GDS, OASIS, STL, GERBER).

cad

Highlights:

  • +2M downloads
  • +65 Contributors
  • +15 PDKs available

workflow

We facilitate an end-to-end design flow for you to:

  • Design (Layout, Simulation, Optimization): Define parametric cell functions in Python to generate components. Test component settings, ports, and geometry to avoid unwanted regressions, and capture design intent in a schematic.
  • Verify (DRC, DFM, LVS): Run simulations directly from the layout using our simulation interfaces, removing the need to redraw your components in simulation tools. Conduct component and circuit simulations, study design for manufacturing. Ensure complex layouts match their design intent through Layout Versus Schematic verification (LVS) and are DRC clean.
  • Validate: Define layout and test protocols simultaneously for automated chip analysis post-fabrication. This allows you to extract essential component parameters, and build data pipelines from raw data to structured data to monitor chip performance.

Your input: Python or YAML text. Your output: A GDSII or OASIS file for fabrication, alongside component settings (for measurement and data analysis) and netlists (for circuit simulations) in YAML.

We provide a common syntax for design (KLayout, Ansys Lumerical, tidy3d, MEEP, MPB, DEVSIM, SAX, MEOW ...), verification, and validation.

tool interfaces

Many foundries have gdsfactory PDKs available. Please to contact your foundry to access their gdsfactory PDK, as you will require an NDA:

  • AIM photonics PDK
  • AMF photonics PDK
  • Compoundtek photonics PDK
  • GlobalFoundries 45SPCLO Photonics PDK
  • HHI Photonics PDK
  • IMEC photonics PDK
  • Smart Photonics Photonics PDK
  • TowerSemi PH18 photonics PDK
  • III-V Labs PDK
  • Lionix PDK
  • Luxtelligence PDK

Coming soon:

  • Ligentec PDK

There are some open source PDKs available without an NDA:

You can also access:

pdks

Getting started

Who is using gdsfactory?

Hundreds of organisations are using gdsfactory. Some companies and organizations around the world using gdsfactory include:

logos

"I've used gdsfactory since 2017 for all my chip tapeouts. I love that it is fast, easy to use, and easy to extend. It's the only tool that allows us to have an end-to-end chip design flow (design, verification and validation)."

Joaquin Matres - Google

"I've relied on gdsfactory for several tapeouts over the years. It's the only tool I've found that gives me the flexibility and scalability I need for a variety of projects."

Alec Hammond - Meta Reality Labs Research

"The best photonics layout tool I've used so far and it is leaps and bounds ahead of any commercial alternatives out there. Feels like gdsfactory is freeing photonics."

Hasitha Jayatilleka - LightIC Technologies

"As an academic working on large scale silicon photonics at CMOS foundries I've used gdsfactory to go from nothing to full-reticle layouts rapidly (in a few days). I particularly appreciate the full-system approach to photonics, with my layout being connected to circuit simulators which are then connected to device simulators. Moving from legacy tools such as gdspy and phidl to gdsfactory has sped up my workflow at least an order of magnitude."

Alex Sludds - MIT

"I use gdsfactory for all of my photonic tape-outs. The Python interface makes it easy to version control individual photonic components as well as entire layouts, while integrating seamlessly with KLayout and most standard photonic simulation tools, both open-source and commercial.

Thomas Dorch - Freedom Photonics

Why use gdsfactory?

  • It's fast, extensible and easy to use.
  • It's free, as in freedom and in cost.
  • It's the most popular EDA tool with a growing community of users, developers, and extensions to other tools.

Gdsfactory is really fast thanks to KLayout C++ library for manipulating GDSII objects. You will notice this when reading/writing big GDS files or doing large boolean operations.

Benchmark gdspy gdsfactory Gain
10k_rectangles 80.2 ms 4.87 ms 16.5
boolean-offset 187 μs 44.7 μs 4.19
bounding_box 36.7 ms 170 μs 216
flatten 465 μs 8.17 μs 56.9
read_gds 2.68 ms 94 μs 28.5

Contributors

Thanks to all the contributors that make this awesome project possible!

contributors

kfactory's People

Contributors

dependabot[bot] avatar drinwater avatar gdspaul avatar github-merge-queue[bot] avatar hsuan-tung avatar joamatab avatar sebastian-goeldi avatar skandanc avatar sourcery-ai[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

kfactory's Issues

save name of python function in KCell / metadata

Can we get the name of the python function that created a cell stored in the KCell metadata?

Example:

@kf.cell
def my_cell(length, width):
  ...

c = my_cell(10000, 1000)
print(c.funcname)

Rationale:

Frequently in extracting information from a layout (whether pulling it from a GDS file or from a saved netlist), it's helpful to be able to find all cells generated from the same original python function and handle them together in some way. For instance,

@kf.cell
def my_cell(length, width):
  ...

defines a pcell, and I'd like to open the resulting GDS file somewhere and identify each cell with its originating python function. So, for instance, a cell named my_cell_L10000_W1000 could be associated with the my_cell function.

It is not always possible to split a cell name on underscores and determine the original function name. For instance, assuming I'm remembering the cell naming scheme correctly, if some developer upstream of me wrote a KCell

@kf.cell
def my_cell_L1(width):
  ...

and I was analyzing the GDS file later on, then I wouldn't necessarily know which python function gave rise to the cell named my_cell_L10000_W1000 just by splitting the name on underscores. Function name suffixes with a single capital letter and a couple digits occur from time to time, and especially if a GDS file gets separated from its original Python repository, it would be lovely to be able to get function names out without a headache.

Example use case:

Traverse the hierarchical graph of a layout and collect the names of all the Python functions which created leaf nodes.

python3.7 compatibility

How can we keep python3.7 compatibility? it's still not end of live and Google colab still uses it

port `>>` operator

Describe the solution you'd like
Add an operator to ports that allows the use of instance.ports[portname_or_index] >> other_port instead of instance.transport(portname_or_index, other_port)

Additional context
This will require extensive additons to ports as a port is currently not aware of any owner/parent and in case of instances they are actual copies and cannot be attached to anything, so this will require either to change how ports behave or add infos about their owner.

As suggested in #97 (comment)

Make a docs segment about differences to gdsfactory

There are certain differences with high impact APIs (add_polygon, add_label) where it doesn't make sense to port the API over or it would completely break with KLayout API (layer_index instead of tuple or layer number only).

Therefore, it is definitely time to make a docs section outlining these differences and providing kfactory/klayout solution for equivalent functionality.

array with floats?

When I run array with floats (um) instead of int (dbu) the result looks strange

c3 = kf.KCell()  # Create a new blank Cell
aref = c3.create_inst(c, na=6, nb=3, a=kf.kdb.DVector(20e3, 0), b=kf.kdb.DVector(0, 15))  # instance the Cell "c" 3 instances in it with a 3 rows, 6 columns array
c3

improve names

coming from gdsfactory I find some kfactory names confusing, How about renaming some of the names to more intuitive?

  • align. Align is used in powerpoint and other software to do something else. I prefer connect, join, or mate. My preference would be connect
  • connect. we are not connecting things. we are routing things. in gdsfactory we call this get_route, but maybe we should follow phidl on this and just use route. I like the idea of
    • connect_elec --> route_electrical
    • connect -> route
    • route_bundle
    • route_path_length_match

Use JupyterBook and Sphinx instead of mkdocs

Is your feature request related to a problem? Please describe.
I don't like mkdocs, it's not as user friendly or organized. While the website theme looks nice, usability suffers in my opinion. I know a lot of famous projects use it (Pydantic, FastAPI, etc.) but I literally dread going to their docs. I have to look through everything, because it's all nested in prose, which is the main selling point of mkdocs. It takes so much longer to read and find what I want. Sphinx is great, API generation in Sphinx is great, and it's a heavily-developed and well-proven library. There are too many tradeoffs with mkdocs. And the API documentation is ugly and hard to read.

Describe the solution you'd like
Switch the docs to JupyterBook. Write them all in markdown.

I strongly believe in The Grand Unifying Theory of Documentation. That means the docs have tutorials, how-to guides, explanations, and an easy to use reference. Mkdocs excels at tutorials; it's great for writing prose. That's only useful as a beginner; once you're coming back to the docs to actually be productive, you want a good API. And mkdocs just really doesn't have a good API experience. Presently, when viewing kfactory's API docs, I have to do a whole bunch of sideways scrolling to view typehints, function signatures, etc.

Describe alternatives you've considered
JupyterBook is the alternative to mkdocs 😉

Additional context
gdsfactory docs were jupyterbook. Super easy to maintain. Built for converting notebooks to webpages. Easy to download/run notebooks elsewhere. This kind of stuff is not available in mkdocs.

Fix Enclosure Names

Names of enclosures use not the type with address instead of name or hash

allow usage in klayout embedded python

Would re-using kfactory component model when implementing klayout pcells for interactive usage (inside klayout gui) be within the scope of the project?

Context is the discussion about a recent refactoring of open source PDKs pcells in efabless/globalfoundries-pdk-libs-gf180mcu_fd_pr#28

A few question toward this:

  • does kfactory aim to feature parity with gdsfactory drawing primitive (rectangle, boolean ops, etc)
  • would KCell just work on top of pya instead of klayout.db/lay
    import klayout.dbcore as kdb
    import klayout.lay as lay
  • would it makes sense to package an lite version of kfactory with less dependencies (no yaml, no scipy)

Let me know what you think!

invalid syntax error when importing kfactory

import kfactory

gives error:

Traceback (most recent call last):

  File "C:\Users\atosato\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py", line 3553, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)

  File "C:\Users\atosato\AppData\Local\Temp\ipykernel_25776\1518496074.py", line 1, in <cell line: 1>
    from kfactory import KCell

  File "C:\Users\atosato\Anaconda3\lib\site-packages\kfactory\__init__.py", line 8, in <module>
    from .kcell import (

  File "C:\Users\atosato\Anaconda3\lib\site-packages\kfactory\kcell.py", line 1558
    match x0_yml:
          ^
SyntaxError: invalid syntax

kfactory version 0.5.7

pydantic < 2

Could we move to pydantic<2 until all the other tools have moved? (tidy3d ...)

access ports by name

in gdsfactory you can access ports from cells and instances using

c.ports['o1'] or c['o1']

However in kfactory Kcells, this can be used to access instances (not as frequently accessed compared to ports)
How about accessing instances with c.instances['wg1']?

Multithreading & distributed operations

KLayout allows a way to split a layout into tiles that are processed in parallel via the TilingProcessor

In parallel, there are now very powerful general-purpose packages such as Ray to seamlessly distribute Python code to multiple local cores, to clusters, to cloud, if one were to "tile" their layout themselves.

Is there an agreed-upon plan to introduce some form of parallelism into kfactory? This could accelerate booleans, fill, DRC, etc...

snapping

Im trying to see if we can solve some of the issues here in kfactory

gdsfactory/gdsfactory#1722

import kfactory as kf
import numpy as np

import kgeneric as kg
import kgeneric.cells as kc


@kf.cell(check_instances=False)
def bent_coupler_half(
    g: float = 0.200,
    Rc: float = 26,
    Ls: float = 1.8,
    Lc: float = 8.6,
    w1: float = 0.400,
    w2: float = 0.400,
    Lx: float = 10,
):
    # Rc = R1-(w1+g)/2 = R2 + (w2 +g)/2
    # Lc = 2 * alpha * Rc

    R1 = Rc + (w1 + g) / 2
    R2 = Rc - (w2 + g) / 2
    alpha = round(np.rad2deg(Lc / (2 * Rc)), 4)
    beta = alpha

    c = kf.KCell("bent_coupler_half")

    angle = np.round(alpha, 3)
    layer = kg.LAYER.WG

    outer_bend = c << kc.bend_circular(
        radius=R1, angle=angle, layer=kg.LAYER.WG, width=w1
    )

    inner_bend = c << kc.bend_circular(
        radius=R2, angle=angle, width=w2, layer=kg.LAYER.WG
    )

    # outer_bend.movey((w1 + g) / 2)
    # inner_bend.movey(-(w2 + g) / 2)

    outer_straight = c << kc.waveguide(length=Lc, width=w1, layer=kg.LAYER.WG)

    inner_straight = c << kc.waveguide(length=Lc, width=w2, layer=kg.LAYER.WG)

    outer_straight.connect("o1", outer_bend.ports["o2"])
    inner_straight.connect("o1", inner_bend.ports["o2"])

    outer_exit_bend = c << kc.bend_circular(
        radius=R2, angle=alpha, width=w1, layer=kg.LAYER.WG
    )

    inner_exit_bend_down = c << kc.bend_circular(
        radius=R2, angle=-beta, width=w2, layer=kg.LAYER.WG
    )

    inner_exit_bend_up = c << kc.bend_circular(
        radius=R2, angle=alpha + beta, width=w2, layer=kg.LAYER.WG
    )

    outer_exit_bend.connect("o1", outer_straight.ports["o2"])
    inner_exit_bend_down.connect("o1", inner_straight.ports["o2"])
    inner_exit_bend_up.connect("o1", inner_exit_bend_down.ports["o2"])

    inner_exit_straight = c << kc.waveguide(length=Lx, width=w2, layer=layer)
    inner_exit_straight.connect("o1", inner_exit_bend_up.ports["o2"])

    outer_exit_straight = c << kc.waveguide(
        length=abs(
            inner_exit_straight.ports["o2"].d.x - outer_exit_bend.ports["o2"].d.x
        ),
        width=w1,
        layer=layer,
    )
    outer_exit_straight.connect("o1", outer_exit_bend.ports["o2"])

    c.add_port(outer_bend.ports["o1"])
    c.add_port(inner_bend.ports["o1"])
    c.add_port(outer_exit_straight.ports["o2"])
    c.add_port(inner_exit_straight.ports["o2"])

    outer_exit_bend.flatten()
    inner_exit_bend_down.flatten()
    inner_exit_bend_up.flatten()
    return c


@kf.cell
def bent_coupler(
    g: float = 0.200,
    Rc: float = 26,
    Ls: float = 1.8,
    Lc: float = 8.6,
    w1: float = 0.400,
    w2: float = 0.400,
    Lx: float = 10,
):
    c = kf.KCell("bent_coupler")

    right_half = c << bent_coupler_half(g=g, Rc=Rc, Ls=Ls, Lc=Lc, w1=w1, w2=w2, Lx=Lx)
    left_half = c << bent_coupler_half(g=g, Rc=Rc, Ls=Ls, Lc=Lc, w1=w1, w2=w2, Lx=Lx)

    left_half.mirror_x()
    left_half.connect("o1", right_half.ports["o1"])

    c.add_port(left_half.ports["o3"])
    c.add_port(left_half.ports["o4"])
    c.add_port(right_half.ports["o3"])
    c.add_port(right_half.ports["o4"])
    c.autorename_ports()
    return c


if __name__ == "__main__":
    # c = gf.KCell("top")
    # coupler = c << bent_coupler(
    #     g=0.200, Rc=26, Lc=8.1, Ls=1.8, w1=0.400, w2=0.400, Lx=5
    # )
    # print(coupler.ports)
    c = bent_coupler_half()

    c.show()

Virtual Cells

Is your feature request related to a problem? Please describe.
Currently, there is no good way in kfactory for doing all-angle routing or ,more generally speaking ways, of handling off-grid operations that will be snapped later on.

Describe the solution you'd like
We can use virtual cells:

  • Acts like a normal KCell wrt transformation and connections, but allows arbitrary angles and positions off-grid
  • Internally a fully virtual KCell (let's call it a VCell) is collection of DPolygons and ports (DCplxTrans ports) or a proxy for a virtual instance of a KCell.
  • Upon insertion of a VCell, all DPolygons and proxies are flattened into the new parent cell. This should ensure all the DPolygons are flattened with enough accuracy to avoid 1nm gaps or mismatches.
  • Ensure when inserted into a KCell, there are either no ports or only 90° ports that are snapped to a polygon edge

@joamatab
@SkandanC
@tvt173

(Port) MetaInfo

Is your feature request related to a problem? Please describe.
In order to have a reliable PDK, it would be great to store most (ideally all) photonic info in a gds, particularly ports.

Describe the solution you'd like
With Klayout implementing LayoutMetaInfo on a cell level, this should be straight forward to implement.

Additional context

KLayout/klayout#1358

Just got merged to Klayout master, so we should be able to get a protoype working for this.

I habe a test branch where it works on a local layout object but not across savings

https://github.com/gdsfactory/kfactory/tree/metainfo

@SkandanC

Enclosure in um

enclosures are defined in dbu while other units are defined in um,

this may be confusing

add gdsfactory convenient functions

TODO:

  • inst.xmin = 0 setter (xmin, xmax, ymin, ymax, x, y)
  • inst.mirror(), inst.mirror_x(), inst_mirror_y()
    • mirror_x mirrors over an x axis, for example x=0
    • mirror_y mirrors over a y axis , for example y=0
  • inst.rotate()
  • cell.add_polygon(points, layer)
  • add_label(text, layer)

Propagate `settings` and `info` through dup by default

Describe the bug
Currently a cell that is duplicated with copy(kcell) / kcell.dup() don't copy any of the settings / infos set in their parent.

Info and settings are also not properly restricted, so they can crash kfactory

Bug in autorenaming by direction

Describe the bug
A clear and concise description of what the bug is.

To Reproduce

import kfactory as kf

c = kf.KCell()
c.create_port(
    trans=kf.kdb.Trans(2, False, 0, 500),
    width=1000,
    layer=kf.kcl.layer(1, 0),
)
c.create_port(
    trans=kf.kdb.Trans(2, False, 0, 0),
    width=1000,
    layer=kf.kcl.layer(2, 0),
)
c.create_port(
    trans=kf.kdb.Trans(2, False, 0, 750),
    width=1000,
    layer=kf.kcl.layer(1, 0),
    port_type="electrical",
)
c.create_port(
    trans=kf.kdb.Trans(2, False, 0, 750), width=1000, layer=kf.kcl.layer(1, 0)
)
c.create_port(
    trans=kf.kdb.Trans(0, False, 0, 500),
    width=1000,
    layer=kf.kcl.layer(1, 0),
)
c.create_port(
    port_type="electrical",
    trans=kf.kdb.Trans(0, False, 0, 0),
    width=1000,
    layer=kf.kcl.layer(1, 0),
)
c.create_port(
    trans=kf.kdb.Trans(0, False, 0, 750),
    width=1000,
    layer=kf.kcl.layer(1, 0),
)
c.kcl.rename_function = lambda ports: kf.port.rename_by_direction(
    ports, layer=kf.kcl.layer(1, 0), port_type="optical"
)


c.autorename_ports()
print(c.ports)

gives

['Port(, width: 1000, trans: r180 0,500, layer: 0, port_type: optical)', 'Port(, width: 1000, trans: r180 0,0, layer: 1, port_type: optical)', 'Port(, width: 1000, trans: r180 0,750, layer: 0, port_type: electrical)', 'Port(, width: 1000, trans: r180 0,750, layer: 0, port_type: optical)', 'Port(name: E0, width: 1000, trans: r0 0,500, layer: 0, port_type: optical)', 'Port(, width: 1000, trans: r0 0,0, layer: 0, port_type: electrical)', 'Port(name: E1, width: 1000, trans: r0 0,750, layer: 0, port_type: optical)']

Expected behavior

['Port(name: W0, width: 1000, trans: r180 0,500, layer: 0, port_type: optical)', 'Port(, width: 1000, trans: r180 0,0, layer: 1, port_type: optical)', 'Port(, width: 1000, trans: r180 0,750, layer: 0, port_type: electrical)', 'Port(name: W1, width: 1000, trans: r180 0,750, layer: 0, port_type: optical)', 'Port(name: E0, width: 1000, trans: r0 0,500, layer: 0, port_type: optical)', 'Port(, width: 1000, trans: r0 0,0, layer: 0, port_type: electrical)', 'Port(name: E1, width: 1000, trans: r0 0,750, layer: 0, port_type: optical)']

Automatic bumping and changelog creation

Is your feature request related to a problem? Please describe.
KFactory doesn't keep track of changes. Additionally bump2version has no active developers anymore

Describe the solution you'd like
Implement towncrier and tbump like klive

Name collisions due to rounding of floats

Describe the bug
We are cutting off floatings after a certain number of digits. This can cause name collisions

To Reproduce

>>> b1 = kf.cells.circular.bend_circular(width=1, radius=10.5, layer=kf.kcl.layer(1,0))
>>> b2 = kf.cells.circular.bend_circular(width=1, radius=10.500005, layer=kf.kcl.layer(1,0))
>>> b1
bend_circular_W1_R10p5_L0_ENone_A90_AS1: ports ['o1', 'o2'], 0 instances
>>> b2
bend_circular_W1_R10p5_L0_ENone_A90_AS1: ports ['o1', 'o2'], 0 instances

Expected behavior
Clear name distinction. I.e. don't cut of floats

klayout-stubs

ERROR: Could not find a version that satisfies the requirement klayout-stubs; extra == "dev" (from kfactory[dev,docs]) (from versions: none)
ERROR: No matching distribution found for klayout-stubs; extra == "dev"

gdsfactory/kfactory compatibility

Here are some issues that would be great to add to kfactory to enable gdsfactory compatibility with kfactory backend

  • gdsfactory allows to define ports with None angle for electrical ports.

fix euler bend for non-90° cases

How can we fix non-manhattan connect?

c = kf.KCell()
b1 = c << kf.cells.euler.bend_euler(radius=5, width=1, layer=0, theta=30)
b2 = c << kf.cells.euler.bend_euler(radius=5, width=1, layer=0, theta=30)
b2.connect('o1', b1.ports['o2'])
c.show()
c

Netlist extraction based on klayout

Netlist extraction using the klayout.db.Netlist.

Example:

    c = kf.KCell("netlist_test")

    b = kf.cells.circular.bend_circular(width=1, radius=10, layer=LAYER.WG)
    s = kf.cells.straight.straight(width=1, length=20, layer=LAYER.WG)

    b1 = c << b
    b2 = c << b
    b2.connect("o1", b1, "o2")
    b3 = c << b
    b3.connect("o1", b2, "o2")
    s1 = c << s
    s1.connect("o1", b3, "o2")
    c.add_port(b1.ports["o1"])
    # c.add_port(s1.ports["o2"])
    p = s1.ports["o2"].copy()
    p.name = None
    c.add_port(p)

    nl = c.netlist()

Gives a netlist like this:

circuit bend_circular_W1_R10_LWG_ENone_A90_AS1 (o1=o1,o2=o2);
end;
circuit straight_W1000_L20000_LWG_ENone (o1=o1,o2=o2);
end;
circuit netlist_test (o1=o1,'1'='1');
  subcircuit bend_circular_W1_R10_LWG_ENone_A90_AS1 '0_bend_circular_W1_R10_LWG_ENone_A90_AS1' (o1=o1,o2='0_o2-1_o1');
  subcircuit bend_circular_W1_R10_LWG_ENone_A90_AS1 '1_bend_circular_W1_R10_LWG_ENone_A90_AS1' (o1='0_o2-1_o1',o2='1_o2-2_o1');
  subcircuit bend_circular_W1_R10_LWG_ENone_A90_AS1 '2_bend_circular_W1_R10_LWG_ENone_A90_AS1' (o1='1_o2-2_o1',o2='2_o2-3_o1');
  subcircuit straight_W1000_L20000_LWG_ENone '3_straight_W1000_L20000_LWG_ENone' (o1='2_o2-3_o1',o2='1');
end;

enable non-manhattan grid snapping issues

import kfactory as kf

c = kf.KCell()
bend = kf.cells.circular.bend_circular(
    width=1, radius=10, layer=kf.kcl.layer(1, 0), theta=30
)
b1 = c << bend
b2 = c << bend
b2.connect("o1", b1.ports["o2"])

c.draw_ports()
c.show()

creates less than 1nm gaps

image

How could we fix this?

@sebastian-goeldi

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.