gdsfactory / gplugins

gdsfactory plugins
https://gdsfactory.github.io/gplugins/
MIT License
35 stars 30 forks source link

Tidy3DComponent crashes when using layer tuples #448

Open thanojo opened 3 months ago

thanojo commented 3 months ago

Describe the bug

Even when the resulting components are pretty much identical, the Tidy3DComponent does not plot the simulation geometry and instead crashes when using a Layer tuple as the layer argument in a cross section function. The bug is not present when using a str to access the layer from the activated generic PDK, though I am also struggling with this when defining own PDKs (actually, this is where this becomes really weird and messy but it would be too much to include here).

To Reproduce

from functools import partial

import gdsfactory as gf
from gdsfactory.technology import LayerLevel, LayerStack
import gplugins.tidy3d as gt

# Define a layer map
Layer = tuple[int, int]
class LAYER(gf.LayerEnum):
    kcl = gf.constant(gf.kcl)
    WAFER: Layer = (0, 0)
    WG_new:    Layer = (1, 0)
gf.kcl.layers = LAYER    # this doesn't seem to make a difference

# Create a layer stack
LAYER_STACK = LayerStack(
        layers=dict(
            substrate=LayerLevel(
                layer=(0,0),
                thickness=1,
                zmin=-1,
                material="sio2",
                info={"mesh_order": 99},
            ),
            core=LayerLevel(
                layer=(1,0),
                thickness=0.5,
                zmin=0,
                material="si",
                info={"mesh_order": 99},
            )
        )
    )

# Create a waveguide cross section
strip_PASSES      = partial(gf.cross_section.strip, layer = 'WG')
strip_FAILS       = partial(gf.cross_section.strip, layer = LAYER.WG_new)
strip_ALSO_FAILS  = partial(gf.cross_section.strip, layer = (1,0))

# Create a component
MMIPASS = gf.components.mmi2x2(width = 0.5, cross_section= strip_PASSES)
MMI1    = gf.components.mmi2x2(width = 0.5, cross_section= strip_FAILS)
MMI2    = gf.components.mmi2x2(width = 0.5, cross_section= strip_ALSO_FAILS)
MMI1.show()

# Define PDK
pdk1 = gf.Pdk(name="fab1", layers=LAYER, cross_sections={'WG_new': strip_PASSES})
pdk1.activate()

# Define further cross sections depending on the PDK
strip_PDK_FAILS  = partial(gf.cross_section.strip, layer = pdk1.get_layer("WG_new"))
strip_PDK_PASSES = partial(gf.cross_section.strip, layer = 'WG_new')

# Compare the layers
MMI3        = gf.components.mmi2x2(width = 0.5, cross_section= strip_PDK_FAILS) # PDK
MMIPASS_PDK = gf.components.mmi2x2(width = 0.5, cross_section= strip_PDK_PASSES) # PDK
print(MMIPASS.layers, MMI1.layers, MMI2.layers, MMI3.layers, MMIPASS_PDK.layers)
print(MMIPASS.layers == MMI1.layers == MMI2.layers == MMI3.layers == MMIPASS_PDK.layers )

# Setup the tidy3d component
c = gt.Tidy3DComponent(
    component=MMI1,
    layer_stack=LAYER_STACK,
    material_mapping= gt.material_name_to_medium,
    pad_xy_inner=2.0,
    pad_xy_outer=2.0,
    pad_z_inner=0,
    pad_z_outer=0,
    extend_ports=2.0,
)

# Check the simulation geometry
c.plot_slice(z="core")

Depending on which MMI or cross section is used, the simulation geometry is successfully plotted (MMIPASS or MMIPASS_PDK) or python crashes. The error message is the following:

--- Logging error in Loguru Handler #1 ---
Record was: {'elapsed': datetime.timedelta(seconds=5, microseconds=790321), 'exception': (type=<class 'pydantic_core._pydantic_core.ValidationError'>, value=2 validation errors for Section
layer.tuple[int, int]
  Input should be a valid tuple [type=tuple_type, input_value=1, input_type=int]
    For further information visit https://errors.pydantic.dev/2.8/v/tuple_type
layer.str
  Input should be a valid string [type=string_type, input_value=1, input_type=int]
    For further information visit https://errors.pydantic.dev/2.8/v/string_type, traceback=<traceback object at 0x00000189D21BAC40>), 'extra': {'stack': '<frozen runpy>:_run_module_as_main:198 > <frozen runpy>:_run_code:88 > ...\test_envs\\test_gplugins_bugs\\.venv\\Lib\\site-packages\\ipykernel_launcher.py:<module>:18 > ....\test_envs\\test_gplugins_bugs\\.

    ... (full report attached)

error_message.txt

Expected behavior

The simulation geometry should be plotted (and any ensuing simulation steps should work).

image

Suggested fix

I am not sure what is causing the error, but will post a workaround if I find one. This could just be the tidy3d plugin, but it could also go deep into the gdsfactory.technology. The weirdest part is that when defining own PDKs and importing them from elsewhere (as opposed to the above), this behaviour becomes seemingly non-deterministic, sometimes passing and sometimes not in subsequent executions.

Versions

joamatab commented 3 months ago

Hi Yannick, Tyler or Momchil,

Can you guys help with this?

@yaugenst @momchil-flex @tylerflex

tylerflex commented 3 months ago

From the error message it looks like a Section is getting passed an int somewhere instead of a LayerSpec (tuple[int, int] | str).

Seems like a gdsfactory internal issue to me / not a tidy3d bug.

thanojo commented 3 months ago

Okay, thanks for the update. If you want to, I can try to get to the bottom of this in terms of gdsfactory, and if I find something, then close this issue and create the corresponding issue in https://github.com/gdsfactory/gdsfactory/issues . But I feel like this may be fixed 'automatically' through the continuing improvements on gdsfactory8