import%20marimo%0A%0A__generated_with%20%3D%20%220.18.4%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20from%20_notebook_template%20import%20inject_css%0A%0A%20%20%20%20inject_css(mo)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20from%20_notebook_template%20import%20make_doc_helpers%0A%0A%20%20%20%20doc_badges%2C%20doc_callout_html%2C%20doc_callout_list%20%3D%20make_doc_helpers(mo)%0A%20%20%20%20return%20doc_badges%2C%20doc_callout_html%2C%20doc_callout_list%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20from%20_notebook_template%20import%20make_section_tabs%0A%0A%20%20%20%20section_tabs%2C%20view_state%2C%20set_view%20%3D%20make_section_tabs(%0A%20%20%20%20%20%20%20%20mo%2C%0A%20%20%20%20%20%20%20%20options%3D(%22All%22%2C%20%22Overview%22%2C%20%22Build%20MZI%20%2B%20Targets%22%2C%20%22Layout%20skeleton%22%2C%20%22Submission%22)%2C%0A%20%20%20%20%20%20%20%20value%3D%22All%22%2C%0A%20%20%20%20)%0A%20%20%20%20section_tabs%0A%20%20%20%20return%20set_view%2C%20view_state%0A%0A%0A%40app.cell%0Adef%20_(view_state)%3A%0A%20%20%20%20view%20%3D%20view_state()%0A%20%20%20%20show_overview%20%3D%20view%20in%20%5B%22All%22%2C%20%22Overview%22%5D%0A%20%20%20%20show_targets%20%3D%20view%20in%20%5B%22All%22%2C%20%22Build%20MZI%20%2B%20Targets%22%5D%0A%20%20%20%20show_skeleton%20%3D%20view%20in%20%5B%22All%22%2C%20%22Layout%20skeleton%22%5D%0A%20%20%20%20show_submission%20%3D%20view%20in%20%5B%22All%22%2C%20%22Submission%22%5D%0A%20%20%20%20return%20show_overview%2C%20show_skeleton%2C%20show_submission%2C%20show_targets%2C%20view%0A%0A%0A%40app.cell%0Adef%20_(doc_badges%2C%20view)%3A%0A%20%20%20%20doc_badges(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22Notebook%20view%3A%20%3Cstrong%3E%7Bview%7D%3C%2Fstrong%3E%22%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_overview)%3A%0A%20%20%20%20mo.stop(not%20show_overview)%0A%20%20%20%20from%20_style%20import%20header%0A%0A%20%20%20%20header(%0A%20%20%20%20%20%20%20%20mo%2C%0A%20%20%20%20%20%20%20%20title%3D%22PDK%20MZI%20layout%20(SiEPIC%20PDK)%22%2C%0A%20%20%20%20%20%20%20%20subtitle%3D(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Build%20a%20first%20MZI%20layout%20using%20the%20SiEPIC-EBeam%20PDK%20workflow%20in%20Python.%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Use%20modelling%20targets%20(%CE%94L%20%E2%86%94%20FSR)%20to%20guide%20geometry%20choices%2C%20then%20save%20your%20work%20in%20the%20openEBL%20repo.%22%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20badges%3D%5B%22Week%202%22%2C%20%22Lab%20companion%22%2C%20%22PDK%22%2C%20%22openEBL%20workflow%22%5D%2C%0A%20%20%20%20%20%20%20%20toc%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22Overview%22%2C%20%22overview%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22Build%20MZI%20%2B%20Targets%22%2C%20%22targets%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22Layout%20skeleton%22%2C%20%22skeleton%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22Submission%22%2C%20%22submission%22)%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20build%3D%222025-12-16%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(doc_callout_list%2C%20mo%2C%20show_overview)%3A%0A%20%20%20%20mo.stop(not%20show_overview)%0A%20%20%20%20overview_md%20%3D%20mo.md(r%22%22%22%0A%20%20%20%20%3Ca%20id%3D%22overview%22%3E%3C%2Fa%3E%0A%20%20%20%20%23%23%20Overview%0A%0A%20%20%20%20This%20is%20the%20**PDK%20%2B%20compact-model%20%2B%20layout**%20companion%20for%20Week%202.%20The%20modelling%20companion%20is%3A%0A%20%20%20%20%60marimo_course%2Flessons%2Fw02_mzi_modelling.py%60%2C%20where%20you%20derived%20and%20explored%20the%20ideal%20MZI%20transfer%20function.%0A%0A%20%20%20%20In%20this%20notebook%2C%20you'll%20connect%20three%20ideas%20that%20show%20up%20in%20every%20photonics%20workflow%3A%0A%0A%20%20%20%20-%20**Compact%20models%3A**%20fast%2C%20circuit-level%20models%20of%20components%20(couplers%2C%20waveguides%2C%20phase%20shifters)%20that%20let%20you%0A%20%20%20%20%20%20simulate%20a%20whole%20photonic%20circuit%20without%20solving%20Maxwell's%20equations%20everywhere.%0A%20%20%20%20-%20**PDK%20(process%20design%20kit)%3A**%20a%20foundry%2Ftechnology%20%22package%22%20that%20defines%20the%20**design%20rules**%2C%20**layers**%2C%20and%0A%20%20%20%20%20%20**parameterized%20building%20blocks**%20(plus%20their%20compact%20models)%20so%20your%20design%20is%20manufacturable%20and%20checkable.%0A%20%20%20%20-%20**Reproducibility%20across%20views%3A**%20build%20the%20*same*%20MZI%20you%20modelled%20last%20lesson%2C%20first%20as%20a%20**circuit**%20from%20compact%0A%20%20%20%20%20%20models%20and%20then%20as%20a%20**layout**%20using%20PDK%20cells.%0A%0A%20%20%20%20In%20lab%2C%20you%20will%3A%0A%0A%20%20%20%201.%20Build%20an%20MZI%20from%20**compact%20models**%20(component%20%E2%86%92%20circuit)%20and%20sanity-check%20it%20against%20the%20Week%202%20model.%0A%20%20%20%202.%20Decide%20on%20a%20**target**%20(FSR%20%E2%86%92%20%CE%94L)%20near%20**1550%20nm**.%0A%20%20%20%203.%20Assemble%20the%20same%20MZI%20from%20**PDK%20building%20blocks**%20(splitter%2C%20waveguides%2C%20combiner%2C%20I%2FO).%0A%20%20%20%204.%20Add%20the%20**conventions**%20required%20for%20downstream%20checks%20(ports%2Fpins%2C%20DevRec%2C%20labels%2Ffloorplan%20as%20required).%0A%20%20%20%205.%20Save%20your%20design%20in%20the%20**openEBL**%20submission%20repo%20and%20keep%20CI%20green.%0A%20%20%20%20%22%22%22)%0A%0A%20%20%20%20goals%20%3D%20doc_callout_list(%0A%20%20%20%20%20%20%20%20%22info%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Learning%20goals%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22What%20you%20should%20be%20able%20to%20do%20after%20this%20notebook%22%2C%0A%20%20%20%20%20%20%20%20items%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Explain%20what%20a%20compact%20model%20is%20and%20why%20we%20use%20them%20for%20circuit-level%20photonics%20design.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Describe%20what%20a%20PDK%20provides%20(layers%2C%20rules%2C%20cells%2C%20models)%20and%20why%20it%20matters%20for%20manufacturable%20layouts.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Create%20an%20MZI%20from%20compact-model%20building%20blocks%20and%20connect%20%CE%94L%20%E2%86%94%20FSR%20back%20to%20the%20modelling%20notebook.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Implement%20the%20same%20MZI%20using%20PDK-accurate%20cells%20so%20it%20passes%20downstream%20checks.%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20grading_note%20%3D%20doc_callout_list(%0A%20%20%20%20%20%20%20%20%22warning%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Where%20is%20the%20graded%20work%3F%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Lab%20companion%20vs%20homework%22%2C%0A%20%20%20%20%20%20%20%20items%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22This%20notebook%20is%20a%20lab%20companion%20(workflow%20%2B%20checklists%20%2B%20reference).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Graded%20work%20should%20live%20in%20a%20homework%20notebook%20under%20%60marimo_course%2Fassignments%2F%60.%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%20%20%20%20mo.vstack(%5Boverview_md%2C%20goals%2C%20grading_note%5D)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_overview)%3A%0A%20%20%20%20mo.stop(not%20show_overview)%0A%20%20%20%20placed_blocks%20%3D%20mo.ui.checkbox(label%3D%22Placed%20I%2FO%20%2B%20splitter%2Fcombiner%20cells%22%2C%20value%3DFalse)%0A%20%20%20%20routed%20%3D%20mo.ui.checkbox(label%3D%22Routed%20an%20MZI%20skeleton%20with%20%CE%94L%22%2C%20value%3DFalse)%0A%20%20%20%20annotated%20%3D%20mo.ui.checkbox(label%3D%22Added%20pins%2FDevRec%2Flabels%20as%20required%22%2C%20value%3DFalse)%0A%20%20%20%20saved%20%3D%20mo.ui.checkbox(label%3D%22Saved%20in%20openEBL%20repo%20%2B%20CI%20checked%22%2C%20value%3DFalse)%0A%20%20%20%20mo.vstack(%5Bplaced_blocks%2C%20routed%2C%20annotated%2C%20saved%5D)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20set_view%2C%20show_overview)%3A%0A%20%20%20%20mo.stop(not%20show_overview)%0A%20%20%20%20go_targets%20%3D%20mo.ui.button(%0A%20%20%20%20%20%20%20%20value%3D0%2C%0A%20%20%20%20%20%20%20%20kind%3D%22success%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Go%20to%20Build%20MZI%20%2B%20Targets%22%2C%0A%20%20%20%20%20%20%20%20on_click%3Dlambda%20v%3A%20(set_view(%22Build%20MZI%20%2B%20Targets%22)%2C%20(v%20or%200)%20%2B%201)%5B-1%5D%2C%0A%20%20%20%20)%0A%20%20%20%20go_skeleton%20%3D%20mo.ui.button(%0A%20%20%20%20%20%20%20%20value%3D0%2C%0A%20%20%20%20%20%20%20%20kind%3D%22neutral%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Go%20to%20Layout%20skeleton%22%2C%0A%20%20%20%20%20%20%20%20on_click%3Dlambda%20v%3A%20(set_view(%22Layout%20skeleton%22)%2C%20(v%20or%200)%20%2B%201)%5B-1%5D%2C%0A%20%20%20%20)%0A%20%20%20%20go_submission%20%3D%20mo.ui.button(%0A%20%20%20%20%20%20%20%20value%3D0%2C%0A%20%20%20%20%20%20%20%20kind%3D%22neutral%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Go%20to%20Submission%22%2C%0A%20%20%20%20%20%20%20%20on_click%3Dlambda%20v%3A%20(set_view(%22Submission%22)%2C%20(v%20or%200)%20%2B%201)%5B-1%5D%2C%0A%20%20%20%20)%0A%20%20%20%20mo.hstack(%5Bgo_targets%2C%20go_skeleton%2C%20go_submission%5D%2C%20justify%3D%22start%22%2C%20gap%3D1)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_targets)%3A%0A%20%20%20%20mo.stop(not%20show_targets)%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%3Ca%20id%3D%22targets%22%3E%3C%2Fa%3E%0A%20%20%20%20%23%23%20Build%20the%20MZI%20%2B%20targets%0A%0A%20%20%20%20Build%20the%20MZI%20from%20PDK%20components%2C%20render%20the%20layout%2C%20and%20then%20pick%20a%20%CE%94L%20that%0A%20%20%20%20matches%20your%20target%20FSR%20near%201550%20nm.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_targets)%3A%0A%20%20%20%20mo.stop(not%20show_targets)%0A%20%20%20%20import%20textwrap%0A%0A%20%20%20%20layout_code%20%3D%20textwrap.dedent(%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20%60%60%60python%0A%20%20%20%20%20%20%20%20%23%20Build%20MZI%2C%20add%20pins%2FDevRec%2Flabels%2Ffloorplan%2C%20and%20export%20a%20GDS.%0A%20%20%20%20%20%20%20%20from%20pathlib%20import%20Path%0A%20%20%20%20%20%20%20%20import%20gdsfactory%20as%20gf%0A%20%20%20%20%20%20%20%20from%20gdsfactory.add_ports%20import%20add_ports_from_markers_center%0A%20%20%20%20%20%20%20%20from%20gdsfactory.read%20import%20import_gds%0A%20%20%20%20%20%20%20%20from%20gdsfactory.port%20import%20auto_rename_ports_orientation%0A%0A%20%20%20%20%20%20%20%20if%20hasattr(gf%2C%20%22gpdk%22)%20and%20hasattr(gf.gpdk%2C%20%22PDK%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20gf.gpdk.PDK.activate()%0A%0A%20%20%20%20%20%20%20%20%23%201)%20Define%20the%20waveguide%20cross-section%20used%20for%20routing%20the%20MZI%20arms.%0A%20%20%20%20%20%20%20%20xs%20%3D%20gf.cross_section.strip(layer%3D(1%2C%200)%2C%20width%3D0.5)%0A%20%20%20%20%20%20%20%20pdk_gds%20%3D%20Path(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22SiEPIC_EBeam_PDK_public%2Fklayout%2FEBeam%2Fgds%2FEBeam%2Febeam_bdc_te1550.gds%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%23%202)%20Load%20the%20splitter%20PDK%20cell%20from%20the%20SiEPIC%20GDS%20and%20add%20ports%20from%20PinRec.%0A%20%20%20%20%20%20%20%20splitter%20%3D%20import_gds(pdk_gds%2C%20cellname%3D%22ebeam_bdc_te1550%22)%0A%20%20%20%20%20%20%20%20add_ports_from_markers_center(splitter%2C%20pin_layer%3D(1%2C%2010)%2C%20port_layer%3D(1%2C%200))%0A%20%20%20%20%20%20%20%20auto_rename_ports_orientation(splitter)%0A%0A%20%20%20%20%20%20%20%20%23%203)%20Build%20the%20MZI%20by%20connecting%20two%20splitters%20with%20routed%20waveguide%20arms.%0A%20%20%20%20%20%20%20%20mzi%20%3D%20gf.components.mzi(%0A%20%20%20%20%20%20%20%20%20%20%20%20splitter%3Dsplitter%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20combiner%3Dsplitter%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20cross_section%3Dxs%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20port_e1_splitter%3D%22oE1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20port_e0_splitter%3D%22oE0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20port_e1_combiner%3D%22oE1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20port_e0_combiner%3D%22oE0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20delta_length%3D50.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20length_x%3D60.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20length_y%3D10.0%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20gc_gds%20%3D%20Path(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22SiEPIC_EBeam_PDK_public%2Fklayout%2FEBeam%2Fgds%2FEBeam%2Febeam_gc_te1550.gds%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%23%204)%20Load%20the%20grating%20coupler%20cell%20and%20add%20ports%20so%20we%20can%20connect%20to%20I%2FO.%0A%20%20%20%20%20%20%20%20gc%20%3D%20import_gds(gc_gds%2C%20cellname%3D%22ebeam_gc_te1550%22)%0A%20%20%20%20%20%20%20%20add_ports_from_markers_center(gc%2C%20pin_layer%3D(1%2C%2010)%2C%20port_layer%3D(1%2C%200))%0A%20%20%20%20%20%20%20%20auto_rename_ports_orientation(gc)%0A%0A%20%20%20%20%20%20%20%20def%20pick_port(component%2C%20orientation%2C%20*%2C%20fallback_first%3DFalse)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20ports%20%3D%20component.ports%0A%20%20%20%20%20%20%20%20%20%20%20%20port_list%20%3D%20list(ports.values())%20if%20hasattr(ports%2C%20%22values%22)%20else%20list(ports)%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20port%20in%20port_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20port.orientation%20is%20not%20None%20and%20int(round(port.orientation))%20%3D%3D%20orientation%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20port%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20fallback_first%20and%20port_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20port_list%5B0%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(f%22No%20port%20with%20orientation%20%7Borientation%7D%20on%20%7Bcomponent.name%7D%22)%0A%0A%20%20%20%20%20%20%20%20%23%205)%20Assemble%20the%20final%20layout%20by%20connecting%20two%20GCs%20to%20the%20MZI%20I%2FO%20ports.%0A%20%20%20%20%20%20%20%20c%20%3D%20gf.Component()%0A%20%20%20%20%20%20%20%20mzi_ref%20%3D%20c%20%3C%3C%20mzi%0A%20%20%20%20%20%20%20%20mzi_in%20%3D%20pick_port(mzi_ref%2C%20180)%0A%20%20%20%20%20%20%20%20mzi_out%20%3D%20pick_port(mzi_ref%2C%200)%0A%20%20%20%20%20%20%20%20gc_port%20%3D%20pick_port(gc%2C%20180%2C%20fallback_first%3DTrue)%0A%20%20%20%20%20%20%20%20gc_in%20%3D%20c%20%3C%3C%20gc%0A%20%20%20%20%20%20%20%20gc_in.connect(gc_port.name%2C%20mzi_in)%0A%20%20%20%20%20%20%20%20gc_out%20%3D%20c%20%3C%3C%20gc%0A%20%20%20%20%20%20%20%20gc_out.connect(gc_port.name%2C%20mzi_out)%0A%0A%20%20%20%20%20%20%20%20%23%206)%20Add%20PinRec%20markers%20on%20each%20external%20port%20(required%20by%20openEBL).%0A%20%20%20%20%20%20%20%20pin_layer%20%3D%20(1%2C%2010)%0A%20%20%20%20%20%20%20%20pin_w%20%3D%202.0%0A%20%20%20%20%20%20%20%20pin_h%20%3D%201.0%0A%20%20%20%20%20%20%20%20for%20port%20in%20c.ports.values()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20cx%2C%20cy%20%3D%20port.center%0A%20%20%20%20%20%20%20%20%20%20%20%20c.add_polygon(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(cx%20-%20pin_w%20%2F%202%2C%20cy%20-%20pin_h%20%2F%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(cx%20%2B%20pin_w%20%2F%202%2C%20cy%20-%20pin_h%20%2F%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(cx%20%2B%20pin_w%20%2F%202%2C%20cy%20%2B%20pin_h%20%2F%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(cx%20-%20pin_w%20%2F%202%2C%20cy%20%2B%20pin_h%20%2F%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20layer%3Dpin_layer%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%23%207)%20Add%20DevRec%20and%20Floorplan%20boxes%20around%20the%20full%20layout%20bbox.%0A%20%20%20%20%20%20%20%20xmin%2C%20ymin%20%3D%20c.bbox%5B0%5D%0A%20%20%20%20%20%20%20%20xmax%2C%20ymax%20%3D%20c.bbox%5B1%5D%0A%20%20%20%20%20%20%20%20pad%20%3D%205.0%0A%20%20%20%20%20%20%20%20c.add_polygon(%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmin%20-%20pad%2C%20ymin%20-%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmax%20%2B%20pad%2C%20ymin%20-%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmax%20%2B%20pad%2C%20ymax%20%2B%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmin%20-%20pad%2C%20ymax%20%2B%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20layer%3D(68%2C%200)%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20c.add_polygon(%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmin%20-%20pad%2C%20ymin%20-%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmax%20%2B%20pad%2C%20ymin%20-%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmax%20%2B%20pad%2C%20ymax%20%2B%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmin%20-%20pad%2C%20ymax%20%2B%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20layer%3D(99%2C%200)%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%23%208)%20Add%20Text%20labels%20for%20top%20cell%20and%20measurement%20tags.%0A%20%20%20%20%20%20%20%20c.add_label(text%3D%22TOP%22%2C%20position%3D(xmin%2C%20ymax%20%2B%2010.0)%2C%20layer%3D(10%2C%200))%0A%20%20%20%20%20%20%20%20c.add_label(text%3D%22MZI%22%2C%20position%3D(xmin%2C%20ymin%20-%2010.0)%2C%20layer%3D(10%2C%200))%0A%0A%20%20%20%20%20%20%20%20%23%209)%20Export%20a%20submission-ready%20GDS%20to%20the%20openEBL%20submissions%20folder.%0A%20%20%20%20%20%20%20%20out%20%3D%20Path(%22openEBL-2026-02%2Fsubmissions%2FEBeam_username.gds%22)%0A%20%20%20%20%20%20%20%20out.parent.mkdir(parents%3DTrue%2C%20exist_ok%3DTrue)%0A%20%20%20%20%20%20%20%20c.write_gds(out)%0A%20%20%20%20%20%20%20%20%60%60%60%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20).strip()%0A%20%20%20%20mo.md(layout_code)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_targets)%3A%0A%20%20%20%20mo.stop(not%20show_targets)%0A%0A%20%20%20%20from%20_notebook_template%20import%20optional_import%20as%20optional_import_preview%0A%0A%20%20%20%20gf_preview%20%3D%20None%0A%20%20%20%20gf_preview%2C%20gf_preview_error%20%3D%20optional_import_preview(%22gdsfactory%22)%0A%20%20%20%20preview_output%20%3D%20None%0A%20%20%20%20if%20gf_preview%20is%20None%3A%0A%20%20%20%20%20%20%20%20preview_notice%20%3D%20%5Bmo.md(%22Layout%20preview%3A%20%60gdsfactory%60%20is%20not%20available%20in%20this%20environment.%22)%5D%0A%20%20%20%20%20%20%20%20if%20gf_preview_error%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20preview_notice.append(mo.md(f%22Details%3A%20%60%7Bgf_preview_error%7D%60%22))%0A%20%20%20%20%20%20%20%20preview_output%20%3D%20mo.vstack(preview_notice)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20import%20pathlib%20as%20pathlib_preview%0A%20%20%20%20%20%20%20%20%20%20%20%20from%20gdsfactory.add_ports%20import%20add_ports_from_markers_center%0A%20%20%20%20%20%20%20%20%20%20%20%20from%20gdsfactory.read%20import%20import_gds%0A%20%20%20%20%20%20%20%20%20%20%20%20from%20gdsfactory.port%20import%20auto_rename_ports_orientation%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20hasattr(gf_preview%2C%20%22gpdk%22)%20and%20hasattr(gf_preview.gpdk%2C%20%22PDK%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gf_preview.gpdk.PDK.activate()%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Build%20the%20MZI%20layout%20from%20PDK%20cells%20and%20prepare%20a%20preview%20image.%0A%20%20%20%20%20%20%20%20%20%20%20%20xs%20%3D%20gf_preview.cross_section.strip(layer%3D(1%2C%200)%2C%20width%3D0.5)%0A%20%20%20%20%20%20%20%20%20%20%20%20pdk_gds%20%3D%20pathlib_preview.Path(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22SiEPIC_EBeam_PDK_public%2Fklayout%2FEBeam%2Fgds%2FEBeam%2Febeam_bdc_te1550.gds%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20not%20pdk_gds.exists()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20FileNotFoundError(f%22SiEPIC%20PDK%20GDS%20not%20found%20at%20%7Bpdk_gds%7D%22)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20splitter%20%3D%20import_gds(pdk_gds%2C%20cellname%3D%22ebeam_bdc_te1550%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20add_ports_from_markers_center(splitter%2C%20pin_layer%3D(1%2C%2010)%2C%20port_layer%3D(1%2C%200))%0A%20%20%20%20%20%20%20%20%20%20%20%20auto_rename_ports_orientation(splitter)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Route%20the%20MZI%20using%20the%20SiEPIC%20splitter%20for%20both%20couplers.%0A%20%20%20%20%20%20%20%20%20%20%20%20mzi%20%3D%20gf_preview.components.mzi(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20splitter%3Dsplitter%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20combiner%3Dsplitter%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cross_section%3Dxs%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20port_e1_splitter%3D%22oE1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20port_e0_splitter%3D%22oE0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20port_e1_combiner%3D%22oE1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20port_e0_combiner%3D%22oE0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20delta_length%3D50.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20length_x%3D60.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20length_y%3D10.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20gc_gds%20%3D%20pathlib_preview.Path(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22SiEPIC_EBeam_PDK_public%2Fklayout%2FEBeam%2Fgds%2FEBeam%2Febeam_gc_te1550.gds%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20not%20gc_gds.exists()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20FileNotFoundError(f%22SiEPIC%20PDK%20GDS%20not%20found%20at%20%7Bgc_gds%7D%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20gc%20%3D%20import_gds(gc_gds%2C%20cellname%3D%22ebeam_gc_te1550%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20add_ports_from_markers_center(gc%2C%20pin_layer%3D(1%2C%2010)%2C%20port_layer%3D(1%2C%200))%0A%20%20%20%20%20%20%20%20%20%20%20%20auto_rename_ports_orientation(gc)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Attach%20grating%20couplers%20to%20the%20MZI%20input%20and%20output.%0A%20%20%20%20%20%20%20%20%20%20%20%20def%20pick_port(component%2C%20orientation%2C%20*%2C%20fallback_first%3DFalse)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ports%20%3D%20component.ports%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20port_list%20%3D%20list(ports.values())%20if%20hasattr(ports%2C%20%22values%22)%20else%20list(ports)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20port%20in%20port_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20port.orientation%20is%20not%20None%20and%20int(round(port.orientation))%20%3D%3D%20orientation%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20port%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20fallback_first%20and%20port_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20port_list%5B0%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(f%22No%20port%20with%20orientation%20%7Borientation%7D%20on%20%7Bcomponent.name%7D%22)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20c%20%3D%20gf_preview.Component()%0A%20%20%20%20%20%20%20%20%20%20%20%20mzi_ref%20%3D%20c%20%3C%3C%20mzi%0A%20%20%20%20%20%20%20%20%20%20%20%20mzi_in%20%3D%20pick_port(mzi_ref%2C%20180)%0A%20%20%20%20%20%20%20%20%20%20%20%20mzi_out%20%3D%20pick_port(mzi_ref%2C%200)%0A%20%20%20%20%20%20%20%20%20%20%20%20gc_port%20%3D%20pick_port(gc%2C%20180%2C%20fallback_first%3DTrue)%0A%20%20%20%20%20%20%20%20%20%20%20%20gc_in%20%3D%20c%20%3C%3C%20gc%0A%20%20%20%20%20%20%20%20%20%20%20%20gc_in.connect(gc_port.name%2C%20mzi_in)%0A%20%20%20%20%20%20%20%20%20%20%20%20gc_out%20%3D%20c%20%3C%3C%20gc%0A%20%20%20%20%20%20%20%20%20%20%20%20gc_out.connect(gc_port.name%2C%20mzi_out)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Render%20the%20layout%20as%20a%20PNG%20for%20display%20in%20the%20notebook.%0A%20%20%20%20%20%20%20%20%20%20%20%20fig%20%3D%20c.plot()%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20fig%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fig%20%3D%20plt.gcf()%0A%20%20%20%20%20%20%20%20%20%20%20%20from%20io%20import%20BytesIO%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20buf%20%3D%20BytesIO()%0A%20%20%20%20%20%20%20%20%20%20%20%20fig.savefig(buf%2C%20format%3D%22png%22%2C%20bbox_inches%3D%22tight%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20buf.seek(0)%0A%20%20%20%20%20%20%20%20%20%20%20%20preview_output%20%3D%20mo.vstack(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%22%23%23%23%20Final%20rendering%20(complete%20MZI%20cell)%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.image(buf)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20except%20Exception%20as%20e%3A%20%20%23%20pragma%3A%20no%20cover%0A%20%20%20%20%20%20%20%20%20%20%20%20preview_output%20%3D%20mo.md(f%22(Could%20not%20build%20preview%3A%20%60%7Btype(e).__name__%7D%3A%20%7Be%7D%60)%22)%0A%20%20%20%20preview_output%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(doc_callout_html%2C%20mo%2C%20show_targets)%3A%0A%20%20%20%20mo.stop(not%20show_targets)%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Targets%3A%20pick%20%CE%94L%20from%20an%20FSR%20target%20(1550%20nm%20default)%0A%0A%20%20%20%20Use%20the%20Week%202%20modelling%20notebook%20to%20build%20intuition%20and%20sanity-check%20values%3A%0A%20%20%20%20%60marimo_course%2Flessons%2Fw02_mzi_modelling.py%60.%0A%0A%20%20%20%20Rule-of-thumb%20near%20%CE%BB0%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathrm%7BFSR%7D%20%5Capprox%20%5Cfrac%7B%5Clambda_0%5E2%7D%7Bn_g%5C%2C%5CDelta%20L%7D.%0A%20%20%20%20%24%24%0A%20%20%20%20%22%22%22)%0A%0A%20%20%20%20doc_callout_html(%0A%20%20%20%20%20%20%20%20%22info%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Tip%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22What%20matters%20for%20FSR%22%2C%0A%20%20%20%20%20%20%20%20html%3D(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22-%20%CE%94L%20sets%20fringe%20spacing%20(FSR)%20approximately%20as%20%601%2F%CE%94L%60.%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%22-%20Base%20length%20doesn%E2%80%99t%20change%20FSR%20in%20the%20ideal%20model.%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%22-%20Use%20**1550%20nm**%20by%20default%3B%20treat%20**1310%20nm**%20as%20an%20extension.%22%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_targets)%3A%0A%20%20%20%20mo.stop(not%20show_targets)%0A%20%20%20%20wl0_nm%20%3D%20mo.ui.number(value%3D1550.0%2C%20label%3D%22%CE%BB0%20(nm)%22)%0A%20%20%20%20ng%20%3D%20mo.ui.number(value%3D4.19%2C%20label%3D%22ng%20(group%20index)%22)%0A%20%20%20%20deltaL_um%20%3D%20mo.ui.number(value%3D50.0%2C%20label%3D%22Planned%20%CE%94L%20(%C2%B5m)%22)%0A%20%20%20%20mo.hstack(%5Bwl0_nm%2C%20ng%2C%20deltaL_um%5D)%0A%20%20%20%20return%20deltaL_um%2C%20ng%2C%20wl0_nm%0A%0A%0A%40app.cell%0Adef%20_(deltaL_um%2C%20mo%2C%20ng%2C%20show_targets%2C%20wl0_nm)%3A%0A%20%20%20%20mo.stop(not%20show_targets)%0A%20%20%20%20wl0_um%20%3D%20float(wl0_nm.value)%20%2F%201e3%0A%20%20%20%20ng_val%20%3D%20float(ng.value)%0A%20%20%20%20delta_L_um%20%3D%20float(deltaL_um.value)%0A%20%20%20%20fsr_nm%20%3D%20(%0A%20%20%20%20%20%20%20%20None%0A%20%20%20%20%20%20%20%20if%20(delta_L_um%20%3C%3D%200%20or%20ng_val%20%3C%3D%200)%0A%20%20%20%20%20%20%20%20else%20(wl0_um%20*%20wl0_um)%20%2F%20(ng_val%20*%20delta_L_um)%20*%201e3%0A%20%20%20%20)%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%22FSR%20estimate%3A%20(enter%20positive%20%CE%94L%20and%20ng)%22%0A%20%20%20%20%20%20%20%20if%20fsr_nm%20is%20None%0A%20%20%20%20%20%20%20%20else%20f%22FSR%20estimate%3A%20**%7Bfsr_nm%3A.2f%7D%20nm**%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_targets)%3A%0A%20%20%20%20mo.stop(not%20show_targets)%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Notebook%20version%20of%20the%20openEBL%20pre-submission%20steps%0A%0A%20%20%20%20These%20mirror%20the%20typical%20PDK%20workflow%2C%20but%20are%20implemented%20directly%20in%20Python.%0A%20%20%20%20Use%20the%20toggles%20below%20to%20add%20required%20layers%20before%20exporting%20a%20GDS.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_targets)%3A%0A%20%20%20%20mo.stop(not%20show_targets)%0A%20%20%20%20add_pins%20%3D%20mo.ui.checkbox(label%3D%22Add%20PinRec%20markers%20(1%2F10)%22%2C%20value%3DTrue)%0A%20%20%20%20add_devrec%20%3D%20mo.ui.checkbox(label%3D%22Add%20DevRec%20box%20(68%2F0)%22%2C%20value%3DTrue)%0A%20%20%20%20add_floorplan%20%3D%20mo.ui.checkbox(label%3D%22Add%20Floorplan%20box%20(99%2F0)%22%2C%20value%3DFalse)%0A%20%20%20%20add_labels%20%3D%20mo.ui.checkbox(label%3D%22Add%20Text%20labels%20(10%2F0)%22%2C%20value%3DTrue)%0A%20%20%20%20export_path%20%3D%20mo.ui.text(%0A%20%20%20%20%20%20%20%20value%3D%22openEBL-2026-02%2Fsubmissions%2FEBeam_username.gds%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Export%20path%22%2C%0A%20%20%20%20)%0A%20%20%20%20mo.vstack(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.hstack(%5Badd_pins%2C%20add_devrec%2C%20add_floorplan%2C%20add_labels%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20export_path%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20return%20add_devrec%2C%20add_floorplan%2C%20add_labels%2C%20add_pins%2C%20export_path%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20add_devrec%2C%0A%20%20%20%20add_floorplan%2C%0A%20%20%20%20add_labels%2C%0A%20%20%20%20add_pins%2C%0A%20%20%20%20export_path%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20show_targets%2C%0A)%3A%0A%20%20%20%20mo.stop(not%20show_targets)%0A%0A%20%20%20%20from%20_notebook_template%20import%20optional_import%20as%20optional_import_export%0A%0A%20%20%20%20gf_export%20%3D%20None%0A%20%20%20%20gf_export%2C%20gf_export_error%20%3D%20optional_import_export(%22gdsfactory%22)%0A%20%20%20%20build_export_output%20%3D%20None%0A%20%20%20%20if%20gf_export%20is%20None%3A%0A%20%20%20%20%20%20%20%20export_notice%20%3D%20%5Bmo.md(%22Build%2Fexport%3A%20%60gdsfactory%60%20is%20not%20available%20in%20this%20environment.%22)%5D%0A%20%20%20%20%20%20%20%20if%20gf_export_error%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20export_notice.append(mo.md(f%22Details%3A%20%60%7Bgf_export_error%7D%60%22))%0A%20%20%20%20%20%20%20%20build_export_output%20%3D%20mo.vstack(export_notice)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20import%20pathlib%20as%20pathlib_export%0A%20%20%20%20%20%20%20%20%20%20%20%20from%20gdsfactory.add_ports%20import%20add_ports_from_markers_center%20as%20add_ports_export%0A%20%20%20%20%20%20%20%20%20%20%20%20from%20gdsfactory.read%20import%20import_gds%20as%20import_gds_export%0A%20%20%20%20%20%20%20%20%20%20%20%20from%20gdsfactory.port%20import%20auto_rename_ports_orientation%20as%20rename_ports_export%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20hasattr(gf_export%2C%20%22gpdk%22)%20and%20hasattr(gf_export.gpdk%2C%20%22PDK%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gf_export.gpdk.PDK.activate()%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Build%20the%20base%20MZI%20layout%20(same%20as%20preview)%20and%20then%20add%20submission%20layers.%0A%20%20%20%20%20%20%20%20%20%20%20%20xs_export%20%3D%20gf_export.cross_section.strip(layer%3D(1%2C%200)%2C%20width%3D0.5)%0A%20%20%20%20%20%20%20%20%20%20%20%20pdk_gds_export%20%3D%20pathlib_export.Path(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22SiEPIC_EBeam_PDK_public%2Fklayout%2FEBeam%2Fgds%2FEBeam%2Febeam_bdc_te1550.gds%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20not%20pdk_gds_export.exists()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20build_export_output%20%3D%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22(Build%2Fexport%20failed%3A%20SiEPIC%20splitter%20GDS%20not%20found%20at%20%60%7Bpdk_gds_export%7D%60)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Load%20the%20splitter%20cell%20from%20the%20PDK%20and%20make%20sure%20ports%20are%20available.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20splitter_export%20%3D%20import_gds_export(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pdk_gds_export%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cellname%3D%22ebeam_bdc_te1550%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rename_duplicated_cells%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20add_ports_export(splitter_export%2C%20pin_layer%3D(1%2C%2010)%2C%20port_layer%3D(1%2C%200))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rename_ports_export(splitter_export)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20splitter_export.name%20%3D%20%22ebeam_bdc_te1550_splitter%22%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mzi_export%20%3D%20gf_export.components.mzi(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20splitter%3Dsplitter_export%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20combiner%3Dsplitter_export%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cross_section%3Dxs_export%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20port_e1_splitter%3D%22oE1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20port_e0_splitter%3D%22oE0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20port_e1_combiner%3D%22oE1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20port_e0_combiner%3D%22oE0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20delta_length%3D50.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20length_x%3D60.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20length_y%3D10.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gc_gds_export%20%3D%20pathlib_export.Path(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22SiEPIC_EBeam_PDK_public%2Fklayout%2FEBeam%2Fgds%2FEBeam%2Febeam_gc_te1550.gds%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20not%20gc_gds_export.exists()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20build_export_output%20%3D%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22(Build%2Fexport%20failed%3A%20SiEPIC%20GC%20GDS%20not%20found%20at%20%60%7Bgc_gds_export%7D%60)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Load%20the%20grating%20coupler%20cell%20for%20I%2FO.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gc_export%20%3D%20import_gds_export(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gc_gds_export%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cellname%3D%22ebeam_gc_te1550%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rename_duplicated_cells%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20add_ports_export(gc_export%2C%20pin_layer%3D(1%2C%2010)%2C%20port_layer%3D(1%2C%200))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rename_ports_export(gc_export)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gc_export.name%20%3D%20%22ebeam_gc_te1550_gc%22%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20def%20pick_port_export(component%2C%20orientation%2C%20*%2C%20fallback_first%3DFalse)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ports%20%3D%20component.ports%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20port_list%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20list(ports.values())%20if%20hasattr(ports%2C%20%22values%22)%20else%20list(ports)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20port%20in%20port_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20port.orientation%20is%20not%20None%20and%20int(round(port.orientation))%20%3D%3D%20orientation%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20port%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20fallback_first%20and%20port_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20port_list%5B0%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22No%20port%20with%20orientation%20%7Borientation%7D%20on%20%7Bcomponent.name%7D%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Assemble%20the%20final%20layout%20by%20connecting%20GCs%20to%20the%20MZI%20ports.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c_export%20%3D%20gf_export.Component()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mzi_ref_export%20%3D%20c_export%20%3C%3C%20mzi_export%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mzi_in_export%20%3D%20pick_port_export(mzi_ref_export%2C%20180)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mzi_out_export%20%3D%20pick_port_export(mzi_ref_export%2C%200)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gc_port_export%20%3D%20pick_port_export(gc_export%2C%20180%2C%20fallback_first%3DTrue)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gc_in_export%20%3D%20c_export%20%3C%3C%20gc_export%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gc_in_export.connect(gc_port_export.name%2C%20mzi_in_export)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gc_out_export%20%3D%20c_export%20%3C%3C%20gc_export%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gc_out_export.connect(gc_port_export.name%2C%20mzi_out_export)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Add%20PinRec%20markers%20for%20all%20external%20ports%20(required%20for%20openEBL).%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20add_pins.value%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pin_layer%20%3D%20(1%2C%2010)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pin_w%20%3D%202.0%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pin_h%20%3D%201.0%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ports%20%3D%20c_export.ports%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20port_list%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20list(ports.values())%20if%20hasattr(ports%2C%20%22values%22)%20else%20list(ports)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20port%20in%20port_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cx%2C%20cy%20%3D%20port.center%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c_export.add_polygon(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(cx%20-%20pin_w%20%2F%202%2C%20cy%20-%20pin_h%20%2F%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(cx%20%2B%20pin_w%20%2F%202%2C%20cy%20-%20pin_h%20%2F%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(cx%20%2B%20pin_w%20%2F%202%2C%20cy%20%2B%20pin_h%20%2F%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(cx%20-%20pin_w%20%2F%202%2C%20cy%20%2B%20pin_h%20%2F%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20layer%3Dpin_layer%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20def%20get_bbox(component)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bbox%20%3D%20component.bbox()%20if%20callable(getattr(component%2C%20%22bbox%22%2C%20None))%20else%20component.bbox%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20hasattr(bbox%2C%20%22left%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20bbox.left%2C%20bbox.bottom%2C%20bbox.right%2C%20bbox.top%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20hasattr(bbox%2C%20%22__getitem__%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmin%2C%20ymin)%2C%20(xmax%2C%20ymax)%20%3D%20bbox%5B0%5D%2C%20bbox%5B1%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20xmin%2C%20ymin%2C%20xmax%2C%20ymax%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20TypeError(%22Unsupported%20bbox%20type%22)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Add%20DevRec%20and%20optional%20Floorplan%20around%20the%20layout%20bbox.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20add_devrec.value%20or%20add_floorplan.value%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20xmin%2C%20ymin%2C%20xmax%2C%20ymax%20%3D%20get_bbox(c_export)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pad%20%3D%205.0%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20add_devrec.value%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c_export.add_polygon(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmin%20-%20pad%2C%20ymin%20-%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmax%20%2B%20pad%2C%20ymin%20-%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmax%20%2B%20pad%2C%20ymax%20%2B%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmin%20-%20pad%2C%20ymax%20%2B%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20layer%3D(68%2C%200)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20add_floorplan.value%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c_export.add_polygon(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmin%20-%20pad%2C%20ymin%20-%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmax%20%2B%20pad%2C%20ymin%20-%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmax%20%2B%20pad%2C%20ymax%20%2B%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(xmin%20-%20pad%2C%20ymax%20%2B%20pad)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20layer%3D(99%2C%200)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Add%20Text%20labels%20for%20top-cell%20naming%20and%20identification.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20add_labels.value%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20xmin%2C%20ymin%2C%20xmax%2C%20ymax%20%3D%20get_bbox(c_export)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c_export.add_label(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20text%3D%22TOP%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20position%3D(xmin%2C%20ymax%20%2B%2010.0)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20layer%3D(10%2C%200)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c_export.add_label(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20text%3D%22MZI%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20position%3D(xmin%2C%20ymin%20-%2010.0)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20layer%3D(10%2C%200)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Export%20the%20final%20GDS%20to%20the%20openEBL%20submissions%20folder.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20out_export%20%3D%20pathlib_export.Path(str(export_path.value)).expanduser()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20out_export.parent.mkdir(parents%3DTrue%2C%20exist_ok%3DTrue)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20written_export%20%3D%20c_export.write_gds(out_export)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20build_export_output%20%3D%20mo.vstack(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(f%22Wrote%3A%20%60%7Bwritten_export%7D%60%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Reminder%3A%20verify%20the%20top-cell%20name%20and%20port%20labels%20in%20your%20layout%20viewer.%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20except%20Exception%20as%20e%3A%20%20%23%20pragma%3A%20no%20cover%0A%20%20%20%20%20%20%20%20%20%20%20%20build_export_output%20%3D%20mo.md(f%22(Build%2Fexport%20failed%3A%20%60%7Btype(e).__name__%7D%3A%20%7Be%7D%60)%22)%0A%20%20%20%20build_export_output%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_skeleton)%3A%0A%20%20%20%20mo.stop(not%20show_skeleton)%0A%20%20%20%20enable_gdsfactory%20%3D%20mo.ui.checkbox(%0A%20%20%20%20%20%20%20%20label%3D%22Enable%20gdsfactory%20helper%20(may%20take%20a%20while%20to%20import)%22%2C%0A%20%20%20%20%20%20%20%20value%3DFalse%2C%0A%20%20%20%20)%0A%20%20%20%20enable_gdsfactory%0A%20%20%20%20return%20(enable_gdsfactory%2C)%0A%0A%0A%40app.cell%0Adef%20_(enable_gdsfactory%2C%20mo%2C%20show_skeleton)%3A%0A%20%20%20%20mo.stop(not%20show_skeleton)%0A%20%20%20%20from%20_notebook_template%20import%20optional_import%20as%20optional_import_skeleton%0A%0A%20%20%20%20gf_mod%20%3D%20None%0A%20%20%20%20available%20%3D%20False%0A%20%20%20%20if%20not%20enable_gdsfactory.value%3A%0A%20%20%20%20%20%20%20%20msg%20%3D%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Optional%20gdsfactory%20helper%3A%20**disabled**%20(enable%20the%20checkbox%20to%20import)%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20gf_mod%2C%20gf_error%20%3D%20optional_import_skeleton(%22gdsfactory%22)%0A%20%20%20%20%20%20%20%20available%20%3D%20gf_mod%20is%20not%20None%0A%20%20%20%20%20%20%20%20msg%20%3D%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Optional%20gdsfactory%20helper%3A%20**available**%22%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20available%0A%20%20%20%20%20%20%20%20%20%20%20%20else%20f%22Optional%20gdsfactory%20helper%3A%20**not%20available**%20(%60%7Bgf_error%7D%60)%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20msg%0A%20%20%20%20return%20available%2C%20gf_mod%0A%0A%0A%40app.cell%0Adef%20_(available%2C%20mo%2C%20show_skeleton)%3A%0A%20%20%20%20mo.stop(not%20show_skeleton)%0A%20%20%20%20mo.stop(not%20available)%0A%0A%20%20%20%20%23%20Parameters%20for%20a%20quick%2C%20generic%20MZI%20skeleton%20export.%0A%20%20%20%20gds_out%20%3D%20mo.ui.text(value%3D%22marimo_course%2Fbuild%2Fweek2_mzi_skeleton.gds%22%2C%20label%3D%22GDS%20output%20path%22)%0A%20%20%20%20delta_length%20%3D%20mo.ui.number(value%3D50.0%2C%20label%3D%22%CE%94L%20(%C2%B5m)%22)%0A%20%20%20%20length_x%20%3D%20mo.ui.number(value%3D60.0%2C%20label%3D%22length_x%20(%C2%B5m)%22)%0A%20%20%20%20length_y%20%3D%20mo.ui.number(value%3D10.0%2C%20label%3D%22length_y%20(%C2%B5m)%22)%0A%20%20%20%20write%20%3D%20mo.ui.button(value%3D0%2C%20label%3D%22Write%20GDS%22%2C%20kind%3D%22success%22%2C%20on_click%3Dlambda%20v%3A%20(v%20or%200)%20%2B%201)%0A%20%20%20%20mo.vstack(%5Bmo.hstack(%5Bgds_out%2C%20write%5D)%2C%20mo.hstack(%5Bdelta_length%2C%20length_x%2C%20length_y%5D)%5D)%0A%20%20%20%20return%20delta_length%2C%20gds_out%2C%20length_x%2C%20length_y%2C%20write%0A%0A%0A%40app.cell%0Adef%20_(available%2C%20gf_mod%2C%20mo%2C%20show_skeleton)%3A%0A%20%20%20%20mo.stop(not%20show_skeleton)%0A%20%20%20%20mo.stop(not%20available)%0A%0A%20%20%20%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20def%20write_mzi_skeleton(*%2C%20out%3A%20Path%2C%20delta_length_um%3A%20float%2C%20length_x_um%3A%20float%2C%20length_y_um%3A%20float)%20-%3E%20Path%3A%0A%20%20%20%20%20%20%20%20gf%20%3D%20gf_mod%0A%20%20%20%20%20%20%20%20%23%20Create%20a%20generic%20MZI%20to%20visualize%20geometry%20only%20(not%20PDK-accurate).%0A%20%20%20%20%20%20%20%20mzi%20%3D%20gf.components.mzi(%0A%20%20%20%20%20%20%20%20%20%20%20%20delta_length%3Dfloat(delta_length_um)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20length_x%3Dfloat(length_x_um)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20length_y%3Dfloat(length_y_um)%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20out.parent.mkdir(parents%3DTrue%2C%20exist_ok%3DTrue)%0A%20%20%20%20%20%20%20%20written%20%3D%20mzi.write_gds(gdspath%3Dout)%0A%20%20%20%20%20%20%20%20return%20Path(written)%0A%20%20%20%20return%20Path%2C%20write_mzi_skeleton%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20Path%2C%0A%20%20%20%20available%2C%0A%20%20%20%20delta_length%2C%0A%20%20%20%20gds_out%2C%0A%20%20%20%20length_x%2C%0A%20%20%20%20length_y%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20show_skeleton%2C%0A%20%20%20%20write%2C%0A%20%20%20%20write_mzi_skeleton%2C%0A)%3A%0A%20%20%20%20mo.stop(not%20show_skeleton)%0A%20%20%20%20mo.stop(not%20available)%0A%0A%20%20%20%20blocks%20%3D%20%5B%5D%0A%20%20%20%20if%20int(write.value%20or%200)%20%3C%3D%200%3A%0A%20%20%20%20%20%20%20%20blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%22Click%20**Write%20GDS**%20to%20export%20a%20skeleton%20you%20can%20inspect%20in%20a%20layout%20viewer.%22)%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20out%20%3D%20Path(str(gds_out.value)).expanduser()%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Write%20the%20skeleton%20GDS%20file%20and%20report%20the%20path.%0A%20%20%20%20%20%20%20%20%20%20%20%20written%20%3D%20write_mzi_skeleton(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20out%3Dout%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20delta_length_um%3Dfloat(delta_length.value)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20length_x_um%3Dfloat(length_x.value)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20length_y_um%3Dfloat(length_y.value)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20blocks.append(mo.md(f%22Wrote%3A%20%60%7Bwritten%7D%60%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20blocks.append(mo.md(f%22Open%20in%20your%20layout%20viewer%3A%20%60%7Bwritten%7D%60%22))%0A%20%20%20%20%20%20%20%20except%20Exception%20as%20e%3A%20%20%23%20pragma%3A%20no%20cover%0A%20%20%20%20%20%20%20%20%20%20%20%20blocks.append(mo.md(f%22(GDS%20write%20failed%3A%20%60%7Btype(e).__name__%7D%3A%20%7Be%7D%60)%22))%0A%0A%20%20%20%20mo.vstack(blocks)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(doc_callout_list%2C%20mo%2C%20show_submission)%3A%0A%20%20%20%20mo.stop(not%20show_submission)%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%3Ca%20id%3D%22submission%22%3E%3C%2Fa%3E%0A%20%20%20%20%23%23%20Save%20%2B%20submission%20workflow%20(openEBL)%0A%0A%20%20%20%20The%20details%20depend%20on%20the%20specific%20openEBL%20run%20repository%20used%20this%20semester%2C%20but%20the%20structure%20is%20consistent%3A%0A%20%20%20%20save%20designs%20in%20the%20right%20folder%2C%20run%20checks%2C%20fix%20failures%2C%20and%20submit%20via%20PR.%0A%20%20%20%20%22%22%22)%0A%0A%20%20%20%20doc_callout_list(%0A%20%20%20%20%20%20%20%20%22info%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Checklist%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Before%20you%20push%22%2C%0A%20%20%20%20%20%20%20%20ordered%3DTrue%2C%0A%20%20%20%20%20%20%20%20items%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Confirm%20your%20layout%20file%20is%20inside%20the%20run%20repo%20(e.g.%2C%20%60openEBL-2026-02%2Fsubmissions%2F...%60).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Verify%20naming%20conventions%20and%20top-level%20cell%20structure%20match%20the%20run%20instructions.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Run%20local%20verification%20in%20your%20layout%20viewer%20if%20available.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Push%20to%20your%20fork%20and%20check%20GitHub%20Actions%20results%3B%20download%20artifacts%20when%20something%20fails.%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
1376639993a3a7fc961ea56dd2b12d5f