diff --git a/docs/_config.yml b/docs/_config.yml index 0c14cc08..5fdc019e 100755 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -22,7 +22,6 @@ execute: - "*03_numerical_implantation*" - "*02_model_extraction*" - "*palace*" - - "*elmer_01_electrostatic*" - "*fdtdz*" # - "*sax_01_sax*" # - "*20_schematic_driven_layout*" diff --git a/docs/notebooks/elmer_01_electrostatic.py b/docs/notebooks/elmer_01_electrostatic.py index 12d2b3d8..b6b99e90 100644 --- a/docs/notebooks/elmer_01_electrostatic.py +++ b/docs/notebooks/elmer_01_electrostatic.py @@ -93,7 +93,6 @@ c.add_ports(cap.ports) substrate = gf.components.bbox(bbox=simulation_box, layer=LAYER.WAFER) c << substrate -c = c.flatten() c.plot() # %% [markdown] @@ -135,7 +134,7 @@ "resolution": 40, }, **{ - f"bw{port}": { + f"bw__{port}": { # `__` is used as the layer–port delimiter for Elmer "resolution": 20, "DistMax": 30, "DistMin": 10, diff --git a/docs/notebooks/palace_01_electrostatic.py b/docs/notebooks/palace_01_electrostatic.py index 9ec75d83..961f7e76 100644 --- a/docs/notebooks/palace_01_electrostatic.py +++ b/docs/notebooks/palace_01_electrostatic.py @@ -91,7 +91,7 @@ c.add_ports(cap.ports) substrate = gf.components.bbox(bbox=simulation_box, layer=LAYER.WAFER) c << substrate -c.flatten() +c.plot() # %% [markdown] # ## Running the simulation @@ -132,7 +132,7 @@ "resolution": 40, }, **{ - f"bw{port}": { + f"bw__{port}": { # `__` is used as the layer–port delimiter for Palace "resolution": 20, "DistMax": 30, "DistMin": 10, diff --git a/docs/notebooks/palace_02_fullwave.py b/docs/notebooks/palace_02_fullwave.py index 2f0c4a7b..eceb5b4d 100644 --- a/docs/notebooks/palace_02_fullwave.py +++ b/docs/notebooks/palace_02_fullwave.py @@ -129,7 +129,6 @@ substrate = gf.components.bbox(bbox=simulation_box, layer=LAYER.WAFER) c << substrate -c.flatten() c.show() # %% [markdown] diff --git a/gplugins/elmer/get_capacitance.py b/gplugins/elmer/get_capacitance.py index e37aaa5b..d44b174c 100644 --- a/gplugins/elmer/get_capacitance.py +++ b/gplugins/elmer/get_capacitance.py @@ -216,6 +216,7 @@ def run_capacitive_simulation_elmer( simulation_folder = Path(simulation_folder or temp_dir.name) simulation_folder.mkdir(exist_ok=True, parents=True) + port_delimiter = "__" # won't cause trouble unlike # filename = component.name + ".msh" if mesh_file: shutil.copyfile(str(mesh_file), str(simulation_folder / filename)) @@ -225,7 +226,7 @@ def run_capacitive_simulation_elmer( type="3D", filename=simulation_folder / filename, layer_stack=layer_stack, - **(mesh_parameters or {}), + **((mesh_parameters or {}) | {"layer_port_delimiter": port_delimiter}), ) # `interruptible` works on gmsh versions >= 4.11.2 @@ -248,9 +249,6 @@ def run_capacitive_simulation_elmer( next(k for k, v in layer_stack.layers.items() if v.layer == port.layer) for port in component.get_ports() } # ports allowed only on metal - # TODO infer port delimiter from somewhere - # TODO raise error for port delimiters not supported by Elmer MATC or find how to escape - port_delimiter = "__" metal_surfaces = [ e for e in mesh_surface_entities if any(ground in e for ground in ground_layers) ] diff --git a/gplugins/elmer/tests/test_elmer.py b/gplugins/elmer/tests/test_elmer.py index 1c15f9fd..94bc70ee 100644 --- a/gplugins/elmer/tests/test_elmer.py +++ b/gplugins/elmer/tests/test_elmer.py @@ -80,7 +80,6 @@ def get_reasonable_mesh_parameters(c: Component): ) -@pytest.mark.skip(reason="FIXME") def test_elmer_capacitance_simulation_runs(geometry) -> None: c = geometry run_capacitive_simulation_elmer( @@ -91,8 +90,7 @@ def test_elmer_capacitance_simulation_runs(geometry) -> None: ) -@pytest.mark.skip(reason="FIXME") -@pytest.mark.parametrize("n_processes", [(1), (2), (4)]) +@pytest.mark.parametrize("n_processes", [(1), (2)]) def test_elmer_capacitance_simulation_n_processes(geometry, n_processes): c = geometry run_capacitive_simulation_elmer( @@ -104,7 +102,6 @@ def test_elmer_capacitance_simulation_n_processes(geometry, n_processes): ) -@pytest.mark.skip(reason="FIXME") @pytest.mark.parametrize("element_order", [(1), (2), (3)]) def test_elmer_capacitance_simulation_element_order(geometry, element_order) -> None: c = geometry diff --git a/gplugins/gmsh/xy_xsection_mesh.py b/gplugins/gmsh/xy_xsection_mesh.py index 71f3c09c..0c163642 100644 --- a/gplugins/gmsh/xy_xsection_mesh.py +++ b/gplugins/gmsh/xy_xsection_mesh.py @@ -73,6 +73,7 @@ def xy_xsection_mesh( n_threads: int = get_number_of_cores(), port_names: list[str] | None = None, gmsh_version: float | None = None, + layer_port_delimiter: str | None = None, ): """Mesh xy cross-section of component at height z. @@ -93,6 +94,7 @@ def xy_xsection_mesh( round_tol: during gds --> mesh conversion cleanup, number of decimal points at which to round the gdsfactory/shapely points before introducing to gmsh simplify_tol: during gds --> mesh conversion cleanup, shapely "simplify" tolerance (make it so all points are at least separated by this amount) atol: tolerance used to establish equivalency between vertices + layer_port_delimiter: Delimiter to use for new layers generated for ports: "layer{delimiter}port_name". """ if port_names: mesh_component = gf.Component() @@ -102,6 +104,7 @@ def xy_xsection_mesh( component=mesh_component, port_names=port_names, layer_stack=layer_stack, + **(dict(delimiter=layer_port_delimiter) if layer_port_delimiter else {}), ) # Fuse and cleanup polygons of same layer in case user overlapped them diff --git a/gplugins/gmsh/xyz_mesh.py b/gplugins/gmsh/xyz_mesh.py index 8f7ef227..97e50601 100644 --- a/gplugins/gmsh/xyz_mesh.py +++ b/gplugins/gmsh/xyz_mesh.py @@ -151,6 +151,7 @@ def xyz_mesh( port_names: List[str] | None = None, edge_ports: List[str] | None = None, gmsh_version: float | None = None, + layer_port_delimiter: str | None = None, ) -> bool: """Full 3D mesh of component. @@ -184,6 +185,7 @@ def xyz_mesh( } gmsh_version: Gmsh mesh format version. For example, Palace requires an older version of 2.2, see https://mfem.org/mesh-formats/#gmsh-mesh-formats. + layer_port_delimiter: Delimiter to use for new layers generated for ports: "layer{delimiter}port_name". """ if port_names: mesh_component = gf.Component() @@ -193,6 +195,7 @@ def xyz_mesh( component=mesh_component, port_names=port_names, layer_stack=layer_stack, + **(dict(delimiter=layer_port_delimiter) if layer_port_delimiter else {}), ) # Fuse and cleanup polygons of same layer in case user overlapped them diff --git a/gplugins/palace/get_capacitance.py b/gplugins/palace/get_capacitance.py index dc3147f8..b3038092 100644 --- a/gplugins/palace/get_capacitance.py +++ b/gplugins/palace/get_capacitance.py @@ -233,6 +233,7 @@ def run_capacitive_simulation_palace( simulation_folder = Path(simulation_folder or temp_dir.name) simulation_folder.mkdir(exist_ok=True, parents=True) + port_delimiter = "__" # won't cause trouble unlike # filename = component.name + ".msh" if mesh_file: shutil.copyfile(str(mesh_file), str(simulation_folder / filename)) @@ -244,7 +245,7 @@ def run_capacitive_simulation_palace( layer_stack=layer_stack, n_threads=n_processes, gmsh_version=2.2, # see https://mfem.org/mesh-formats/#gmsh-mesh-formats - **(mesh_parameters or {}), + **((mesh_parameters or {}) | {"layer_port_delimiter": port_delimiter}), ) # re-read the mesh @@ -267,8 +268,6 @@ def run_capacitive_simulation_palace( next(k for k, v in layer_stack.layers.items() if v.layer == port.layer) for port in component.get_ports() } # ports allowed only on metal - # TODO infer port delimiter from somewhere - port_delimiter = "__" metal_surfaces = [ e for e in mesh_surface_entities if any(ground in e for ground in ground_layers) ]