Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: simpler LayerStack and DerivedLayers #2805

Merged
merged 36 commits into from
Jun 9, 2024
Merged

Conversation

simbilod
Copy link
Collaborator

@simbilod simbilod commented May 30, 2024

The current way to deal with "derived layers" (i.e. physical levels on the chip that do not map 1:1 to GDS design layers) is very convoluted. It requires defining etch and grow levels, with flags for what is etched into what, which borders on process emulation. This also does not generalize well to other common mapping between GDS layers and physical elements on the chip, for instance marker layers modifying shared process steps.

I propose instead, at the gdsfactory level, to only consider the final fabricated levels of the chip. These layers should be easily defined from arbitrary combinations of GDS layers. An example could look something like this:

    layer1 = GDSLayer(layer=(1, 0))
    layer2 = GDSLayer(layer=(2, 0))

    ls = LayerStack(
        layers={
            "layerlevel_layer1": LayerLevel(layer=layer1, thickness=10, zmin=0),
            "layerlevel_layer2": LayerLevel(layer=layer2, thickness=10, zmin=10),
            "layerlevel_and_layer": LayerLevel(
                layer=layer1 & layer2,
                thickness=10,
                zmin=0,
                derived_layer=GDSLayer(layer=(3, 0)),
            ),
            "layerlevel_xor_layer": LayerLevel(
                layer=layer1 ^ layer2,
                thickness=10,
                zmin=0,
                derived_layer=GDSLayer(layer=(4, 0)),
            ),
            "layerlevel_not_layer": LayerLevel(
                layer=layer1 - layer2,
                thickness=10,
                zmin=0,
                derived_layer=GDSLayer(layer=(5, 0)),
            ),
            "layerlevel_or_layer": LayerLevel(
                layer=layer1 | layer2,
                thickness=10,
                zmin=0,
                derived_layer=GDSLayer(layer=(6, 0)),
            ),
            "layerlevel_composed_layer": LayerLevel(
                layer=layer1 - (layer1 ^ layer2),
                thickness=10,
                zmin=0,
                derived_layer=GDSLayer(layer=(7, 0)),
            ),
        }
    )

    # Test with simple component
    import gdsfactory as gf

    c = gf.Component()

    rect1 = c << gf.components.rectangle(size=(10, 10), layer=(1, 0))
    rect2 = c << gf.components.rectangle(size=(10, 10), layer=(2, 0))
    rect2.dmove((5, 5))
    c.show()

image

Now get the component with derived layers according to the stack above:

    c = get_component_with_derived_layers(c, ls)
    c.show()

(3,0) is the intersection:

image

(4,0) is the exclusive or:

image

(5,0) is a substraction:

image

(6,0) is union:

image

We can also compose the operations; (7,0) substracts the X0R from layer 1:

image

We can revisit process emulation and/or simulation in gplugins.

If you think this is a good idea I can make tests and fix visualization scripts

@simbilod simbilod linked an issue May 30, 2024 that may be closed by this pull request
@simbilod simbilod requested a review from joamatab May 30, 2024 19:25
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've reviewed this pull request using the Sourcery rules engine. If you would also like our AI-powered code review then let us know.

if isinstance(layer, GDSLayer):
layer_index = get_layer(layer.layer)
polygons = polygons_per_layer[layer_index]
r = kf.kdb.Region(polygons)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Inline variable that is immediately returned [×2] (inline-immediately-returned-variable)

@simbilod simbilod marked this pull request as draft May 30, 2024 19:27
@simbilod
Copy link
Collaborator Author

I'm also removing all the clutter from as discussed in #2556

@joamatab
Copy link
Contributor

looks great, notice there are some conflicts

Copy link
Contributor

@joamatab joamatab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great!

gdsfactory/technology/layer_stack.py Outdated Show resolved Hide resolved
@simbilod
Copy link
Collaborator Author

get_klayout_3d_script needs fixing, but it should be easy to convert the boolean operations in the layerstack to klayout script booleans

@simbilod
Copy link
Collaborator Author

there's issues with Pydantic to_json, will check again later

@sebastian-goeldi sebastian-goeldi added the enhancement New feature or request label May 31, 2024
@simbilod
Copy link
Collaborator Author

simbilod commented Jun 2, 2024

there's issues with Pydantic to_json, will check again later

the pydantic serialization error is fixable by allowing layers to be int, is this acceptable behavior @joamatab @sebastian-goeldi ?

class LogicalLayer(BaseModel):
"""GDS design layer."""

layer: tuple[int, int] | kf.LayerEnum | int
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here

"""

layer1: LogicalLayer | DerivedLayer | int
layer2: LogicalLayer | DerivedLayer | int
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here

@sebastian-goeldi
Copy link
Collaborator

there's issues with Pydantic to_json, will check again later

the pydantic serialization error is fixable by allowing layers to be int, is this acceptable behavior @joamatab @sebastian-goeldi ?

The problem with int is, it's not a good identifier, even LayerEnum is questionable in this case. Anything that should live with layers outside or directly tied info, should use something more akin to gf.kdb.LayerInfo, so tuple with layer datatype or a string with layer name are better choices.

An int should be stricly used for layout purposes (it's even not so good to pass it through function calls tbh as they will be serialized as ints)

To get tuple from LayerEnum:
tuple(LAYER.WG) for example

To get name:
LAYER.WG.name

To get layerenum from tuple:
LAYER(gf.kcl.layer(*layer_tuple)) (or layer_tuple[0],layer_tuple[1] instead o *... of course.

Get LayerEnum by name:
LAYER[layer_name]

@joamatab joamatab added the minor minor release label Jun 6, 2024
@HelgeGehring
Copy link
Collaborator

Great work @simbilod !

Just some ideas:
Why not do a common class between BaseModel and DerivedLayer/LogicalLayer? (AbstractLayer?)
That one could implement and /... so we would only have that code once (as they would need to do exactly the same)
Then, DerivedLayer/LogicalLayer could both implement an abstract function of AbstractLayer called getShapes(component), which would either return the polygons for a LogicalLayer or do the operation for a DerivedLayer. That way we wouldn't need an extra function to derive the Polygons from the Layers.

@joamatab
Copy link
Contributor

joamatab commented Jun 7, 2024

when will this PR be ready to review? we plan to release gdsfactory8 in the coming days

@simbilod simbilod marked this pull request as ready for review June 8, 2024 07:58
@simbilod
Copy link
Collaborator Author

simbilod commented Jun 8, 2024

I've implemented @HelgeGehring 's suggestions, it still works exactly as I showed above

@joamatab this is ready to review. I've added a NotImplementedError on the klayout 3d script for now. The only sketchy thing is the int type allowed for layer object to fix pydantic issues. Also the commit history is a bit messy, we can rebase against main if you want.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have skipped reviewing this pull request. It looks like we've already reviewed this pull request.

@simbilod
Copy link
Collaborator Author

simbilod commented Jun 8, 2024

Some export tests are still failing, probably just need to call layer.layer in some places. I can look tomorrow

@joamatab
Copy link
Contributor

joamatab commented Jun 8, 2024

Sounds good,

will this work with the plugins? like gmsh?

im having lots of issues with the gdsfactory8 brach in gplugins

i think it would be great to use klayout instead of shapely there if possible

@simbilod
Copy link
Collaborator Author

simbilod commented Jun 8, 2024

Sounds good,

will this work with the plugins? like gmsh?

im having lots of issues with the gdsfactory8 brach in gplugins

i think it would be great to use klayout instead of shapely there if possible

The meshing should mostly be fine, it only relies on get_component or get_component_with_derived_layers, so if those work it will be OK. We might need to add a layer.layer here and there at most.

Copy link

codecov bot commented Jun 8, 2024

Codecov Report

Attention: Patch coverage is 63.31361% with 62 lines in your changes missing coverage. Please review.

Project coverage is 68.63%. Comparing base (bc4dca4) to head (92b7895).

Files Patch % Lines
gdsfactory/technology/layer_stack.py 45.91% 51 Missing and 2 partials ⚠️
gdsfactory/export/to_stl.py 84.84% 2 Missing and 3 partials ⚠️
gdsfactory/export/to_3d.py 88.46% 1 Missing and 2 partials ⚠️
gdsfactory/component.py 66.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2805      +/-   ##
==========================================
- Coverage   69.05%   68.63%   -0.42%     
==========================================
  Files         296      296              
  Lines       15215    15235      +20     
  Branches     2225     2229       +4     
==========================================
- Hits        10506    10457      -49     
- Misses       4113     4183      +70     
+ Partials      596      595       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@sebastian-goeldi
Copy link
Collaborator

I think for layers in general, I think we should just pass them as strings (i.e. layer name).

The longer the more I think it's easier to do it that way. Getting them can be as easy as kcl.get_layer. This also allows for easier and more meaningful (de)serialization of layers as the index itself has next to no meaning (except during construction)

@joamatab joamatab merged commit 7bd4017 into main Jun 9, 2024
11 of 16 checks passed
@joamatab joamatab deleted the 2556-clean-up-layerlevel branch June 9, 2024 08:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request minor minor release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

clean up LayerLevel
4 participants