Skip to content

Commit

Permalink
Merge pull request #436 from gdsfactory/update_path_length_analysis
Browse files Browse the repository at this point in the history
Update path length analysis
  • Loading branch information
joamatab authored Jul 10, 2024
2 parents cc95a1c + 846f285 commit 4c81dab
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 32 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ gplugins/klayout/layers.lyp
gplugins/klayout/tech.lyt

# C extensions
*.csv
*.html
*.png
*.so
*.stl
*.fsp
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ elmer:
sudo apt-get update
sudo apt-get install -y elmerfem-csc mpich

meep:
conda install -c conda-forge pymeep=*=mpi_mpich_* nlopt -y\

test:
pytest

Expand Down
6 changes: 4 additions & 2 deletions gplugins/gmeep/get_meep_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ def get_meep_geometry_from_component(
component_with_booleans = layer_stack.get_component_with_derived_layers(component)

geometry = []
layer_to_polygons = component_with_booleans.get_polygons(by_spec=True)
layer_to_polygons = component_with_booleans.get_polygons_points()

ordered_layer_stack_keys = order_layer_stack(layer_stack)[::-1]
for layername in ordered_layer_stack_keys:
layer = layer_stack.layers[layername].layer
polygons = layer_to_polygons[layer_stack.layers[layername].layer]
if layer not in layer_to_polygons:
continue
polygons = layer_to_polygons[layer]
if layer in layer_to_thickness and layer in layer_to_material:
height = layer_to_thickness[layer] if is_3d else mp.inf
zmin_um = layer_to_zmin[layer] if is_3d else 0
Expand Down
21 changes: 10 additions & 11 deletions gplugins/gmeep/get_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import meep as mp
import numpy as np
from gdsfactory.component import Component
from gdsfactory.components.extension import move_polar_rad_copy
from gdsfactory.components.extension import extend_ports, move_polar_rad_copy
from gdsfactory.pdk import get_layer_stack
from gdsfactory.technology import LayerStack

Expand Down Expand Up @@ -141,7 +141,8 @@ def get_simulation(
layer_stack = layer_stack or get_layer_stack()
layer_to_thickness = layer_stack.get_layer_to_thickness()

component_ref = component.ref()
dummy_component = gf.Component()
component_ref = dummy_component << component
component_ref.dx = 0
component_ref.dy = 0

Expand All @@ -161,15 +162,13 @@ def get_simulation(
), f"component needs to be a gf.Component, got Type {type(component)}"

component_extended = (
gf.components.extension.extend_ports(
component=component, length=extend_ports_length, centered=True
)
extend_ports(component=component, length=extend_ports_length, centered=True)
if extend_ports_length
else component
)

component_extended.show()
component_extended = component_extended.flatten()
# component_extended.flatten()

# geometry_center = [component_extended.x, component_extended.y]
# geometry_center = [0, 0]
Expand All @@ -193,8 +192,8 @@ def get_simulation(
cell_thickness = tpml + zmargin_bot + t_core + zmargin_top + tpml if is_3d else 0

cell_size = mp.Vector3(
component.xsize + 2 * tpml,
component.ysize + 2 * tpml,
component.dxsize + 2 * tpml,
component.dysize + 2 * tpml,
cell_thickness,
)

Expand Down Expand Up @@ -250,7 +249,7 @@ def get_simulation(
eig_band=port_source_mode + 1,
eig_parity=mp.NO_PARITY if is_3d else mp.EVEN_Y + mp.ODD_Z,
eig_match_freq=True,
eig_kpoint=-1 * mp.Vector3(x=1).drotate(mp.Vector3(z=1), angle_rad),
eig_kpoint=-1 * mp.Vector3(x=1).rotate(mp.Vector3(z=1), angle_rad),
direction=direction,
)
]
Expand All @@ -271,8 +270,8 @@ def get_simulation(

# Add port monitors dict
monitors = {}
for port_name in component_ref.ports.keys():
port = component_ref.ports[port_name]
for port in component_ref:
port_name = port.name
angle_rad = np.radians(port.orientation)
width = port.width + 2 * port_margin
size_x = width * abs(np.sin(angle_rad))
Expand Down
8 changes: 3 additions & 5 deletions gplugins/gmeep/write_sparameters_meep.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import gdsfactory as gf
import meep as mp
import numpy as np
import pydantic
import yaml
from gdsfactory import logger
from gdsfactory.component import Component
Expand Down Expand Up @@ -114,7 +113,6 @@ def parse_port_eigenmode_coeff(
return coeff_in, coeff_out


@pydantic.validate_arguments
def write_sparameters_meep(
component: ComponentSpec,
port_source_names: list[str] | None = None,
Expand Down Expand Up @@ -349,9 +347,10 @@ def write_sparameters_meep(
right=xmargin_right,
)

component_ref = component.ref()
dummy = Component()
component_ref = dummy << component
ports = component_ref.ports
port_names = [port.name for port in list(ports.values())]
port_names = [port.name for port in ports]
port_source_names = port_source_names or port_names
port_source_modes = port_source_modes or {key: [0] for key in port_source_names}
port_modes = port_modes or [0]
Expand Down Expand Up @@ -402,7 +401,6 @@ def write_sparameters_meep(
sp = {} # Sparameters dict
start = time.time()

@pydantic.validate_arguments
def sparameter_calculation(
port_source_name: str,
component: Component,
Expand Down
5 changes: 2 additions & 3 deletions gplugins/gmeep/write_sparameters_meep_batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@

import gdsfactory as gf
import numpy as np
import pydantic
from gdsfactory import logger, sparameters_path
from gdsfactory import logger
from gdsfactory.component import Component
from gdsfactory.config import sparameters_path
from gdsfactory.pdk import get_layer_stack
from gdsfactory.technology import LayerStack
from tqdm.auto import tqdm
Expand All @@ -33,7 +33,6 @@
temp_dir_default = Path(sparameters_path) / "temp"


@pydantic.validate_arguments
def write_sparameters_meep_batch(
jobs: list[dict],
cores_per_run: int = 2,
Expand Down
2 changes: 0 additions & 2 deletions gplugins/gmeep/write_sparameters_meep_mpi.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from pathlib import Path

import gdsfactory as gf
import pydantic
from gdsfactory import logger
from gdsfactory.component import Component
from gdsfactory.config import GDSDIR_TEMP
Expand All @@ -40,7 +39,6 @@ def _python() -> str:
return sys.executable


@pydantic.validate_arguments
def write_sparameters_meep_mpi(
component: ComponentSpec,
layer_stack: LayerStack | None = None,
Expand Down
53 changes: 51 additions & 2 deletions gplugins/path_length_analysis/path_length_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,17 @@ def _get_edge_based_route_attr_graph(
netlist=None,
netlists=None,
) -> nx.Graph:
connections = netlist["connections"]
""" Gets a connectivity graph for the circuit, with all path attributes on edges and ports as nodes.
Args:
component: the component to generate a graph from.
recursive: True to expand all hierarchy. False to only report top-level connectivity.
component_connectivity: a function to report connectivity for base components.\
None to treat as black boxes with no internal connectivity.
netlist: a netlist dictionary. If None, will be generated from the component.
netlists: a dictionary of netlists for each subcomponent.
"""
connections = netlist["nets"]
top_level_ports = netlist["ports"]
g = nx.Graph()
inst_route_attrs = {}
Expand Down Expand Up @@ -264,7 +274,7 @@ def _get_edge_based_route_attr_graph(
node_attrs[pname] = n_attrs
g.add_node(pname, **n_attrs)
# nx.set_node_attributes(g, node_attrs)
g.add_edges_from(connections.items(), weight=0.0001)
g.add_edges_from(connections, weight=0.0001)

# connect all internal ports for devices with connectivity defined
# currently we only do this for routing components, but could do it more generally in the future
Expand Down Expand Up @@ -577,3 +587,42 @@ def visualize_graph(
result_dir.mkdir(exist_ok=True, parents=True)
output_file(result_dir / f"{pic.name}.html")
show(layout)


if __name__ == "__main__":
import gdsfactory as gf

xs_top = [0, 10, 20, 40, 50, 80]
pitch = 127.0
N = len(xs_top)
xs_bottom = [(i - N / 2) * pitch for i in range(N)]
layer = (1, 0)

top_ports = [
gf.Port(
f"top_{i}", center=(xs_top[i], 0), width=0.5, orientation=270, layer=layer
)
for i in range(N)
]

bot_ports = [
gf.Port(
f"bot_{i}",
center=(xs_bottom[i], -300),
width=0.5,
orientation=90,
layer=layer,
)
for i in range(N)
]

c = gf.Component()
routes = gf.routing.route_bundle(
c, top_ports, bot_ports, separation=5.0, end_straight_length=100
)

report_pathlengths(
pic=c,
result_dir=Path("rib_strip_pathlengths"),
visualize=True,
)
27 changes: 20 additions & 7 deletions gplugins/path_length_analysis/path_length_analysis_from_gds.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,15 @@ def extract_path(
filter_function: optional Function to filter the centerline.
under_sampling: under sampling factor.
"""
points = component.get_polygons(by_spec=layer)[0]
layer = gf.get_layer(layer)

polygons_by_layer = component.get_polygons_points(merge=True)

if layer not in polygons_by_layer:
raise ValueError(f"Layer {layer} not found in component")

points = polygons_by_layer[layer]
points = np.concatenate(points)

# Assume the points are ordered and the first half is the outer curve, the second half is the inner curve
# This assumption might need to be adjusted based on your specific geometry
Expand All @@ -34,9 +42,16 @@ def extract_path(
inner_points = points[mid_index:]
inner_points = inner_points[::-1]

inner_points = inner_points[::under_sampling]
outer_points = outer_points[::under_sampling]
# Ensure outer_points and inner_points have the same length
min_length = min(len(outer_points), len(inner_points))
outer_points = outer_points[:min_length]
inner_points = inner_points[:min_length]

# Apply under-sampling
outer_points = np.array(outer_points[::under_sampling])
inner_points = np.array(inner_points[::under_sampling])

# Calculate the centerline
centerline = np.mean([outer_points, inner_points], axis=0)

if filter_function is not None:
Expand Down Expand Up @@ -130,15 +145,13 @@ def _demo_routes():
left_ports.reverse()

c = gf.Component(name="connect_bundle_v2")
routes = gf.routing.route_bundle(
gf.routing.route_bundle(
c,
left_ports,
right_ports,
sort_ports=True,
start_straight_length=100,
enforce_port_ordering=False,
)
for route in routes:
c.add(route.references)
return c


Expand Down

0 comments on commit 4c81dab

Please sign in to comment.