Skip to content

Commit 5868755

Browse files
committed
all tests fixed
1 parent ec4a1b8 commit 5868755

File tree

2 files changed

+59
-41
lines changed

2 files changed

+59
-41
lines changed

src/pyedb/grpc/database/primitive/padstack_instance.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,11 @@ def layer_range_names(self) -> list[str]:
531531
List of layer names.
532532
533533
"""
534-
start_layer, stop_layer = self.get_layer_range()
534+
layer_range = self.get_layer_range()
535+
if layer_range:
536+
start_layer, stop_layer = layer_range
537+
else:
538+
return []
535539
started = False
536540
layer_list = []
537541
start_layer_name = start_layer.name

src/pyedb/workflows/drc/drc.py

Lines changed: 54 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ def _rule_min_clearance(
517517
pid = prim.id
518518
bbox = prim.bbox
519519
if self.edb.grpc:
520-
points = [[pt.x, pt.y] for pt in prim.polygon_data.without_arcs().points]
520+
points = [[pt.x.value, pt.y.value] for pt in prim.polygon_data.without_arcs().points]
521521
else:
522522
points = prim.polygon_data.points_without_arcs
523523

@@ -631,16 +631,23 @@ def _rule_min_annular_ring(self, rule: MinAnnularRing, max_workers: int = None):
631631
via_def = padstacks_definitions[via.padstack_definition]
632632

633633
# Skip if no hole properties (non-drilled padstack)
634-
if not via_def.hole_properties:
635-
continue
634+
if self.edb.grpc:
635+
if not via_def.hole_diameter:
636+
continue
637+
else:
638+
if not via_def.hole_properties:
639+
continue
636640

637641
# Some padstacks may not have pad shapes either
638642
if not via_def.pad_by_layer:
639643
continue
640644

641645
first_pad = next(iter(via_def.pad_by_layer.values()))
642646
od = first_pad.parameters_values[0]
643-
id_ = via_def.hole_properties[0]
647+
if self.edb.grpc:
648+
id_ = via_def.id
649+
else:
650+
id_ = via_def.hole_properties[0]
644651
via_data.append({"via_name": via.name, "od": od, "id": id_})
645652

646653
# === STEP 2: Multi-threaded computation ===
@@ -664,32 +671,31 @@ def check_via(via_entry):
664671
def _rule_copper_balance(self, rule: CopperBalance):
665672
max_imbalance = self.edb.value(rule.max_percent)
666673

667-
# Snapshot data for thread safety
674+
# Snapshot data
668675
primitives_by_layer = dict(self.edb.modeler.primitives_by_layer)
669676
layout_outline = [prim for prim in self.edb.modeler.primitives if prim.layer.name.lower() == "outline"]
670677
if not layout_outline:
671678
raise ValueError("No outline primitive found in the layout.")
672-
area_board = layout_outline[0].polygon_data.area
679+
if self.edb.grpc:
680+
area_board = layout_outline[0].polygon_data.area()
681+
else:
682+
area_board = layout_outline[0].polygon_data.area
673683

674-
def check_layer(layer, prim_list):
675-
area_copper = sum(prim.polygon_data.area for prim in prim_list)
684+
for layer, prim_list in primitives_by_layer.items():
685+
if self.edb.grpc:
686+
area_copper = sum(prim.polygon_data.area() for prim in prim_list)
687+
else:
688+
area_copper = sum(prim.polygon_data.area for prim in prim_list)
676689
imbalance = abs(area_copper - area_board / 2) / (area_board / 2) * 100
677690
if imbalance > max_imbalance:
678-
return {
679-
"rule": "copper_balance",
680-
"layer": layer,
681-
"imbalance_pct": imbalance,
682-
"limit_pct": max_imbalance,
683-
}
684-
return None
685-
686-
workers = max(1, (os.cpu_count() or 2) - 1)
687-
688-
with ThreadPoolExecutor(max_workers=workers) as executor:
689-
results = list(executor.map(lambda kv: check_layer(kv[0], kv[1]), primitives_by_layer.items()))
690-
691-
# Append results in the main thread only (lock-free)
692-
self.violations.extend(r for r in results if r is not None)
691+
self.violations.append(
692+
{
693+
"rule": "copper_balance",
694+
"layer": layer,
695+
"imbalance_pct": imbalance,
696+
"limit_pct": max_imbalance,
697+
}
698+
)
693699

694700
# High-speed rules
695701
def _rule_diff_pair_length_match(self, rule: DiffPairLengthMatch):
@@ -727,33 +733,38 @@ def check_pair(pair):
727733
def _rule_back_drill_stub_length(self, rule: BackDrillStubLength):
728734
max_stub = self.edb.value(rule.value)
729735

730-
# Snapshot data for thread safety
736+
# Snapshot data for safety
731737
padstack_instances = list(self.edb.padstacks.instances.values())
732738
layers = dict(self.edb.stackup.layers)
733739

734-
def check_via(via):
735-
start = via.layer_range_names[0]
736-
stop = via.layer_range_names[-1]
737-
if via.backdrill_parameters:
740+
for via in padstack_instances:
741+
layer_range = via.layer_range_names
742+
if layer_range:
743+
start = layer_range[0]
744+
stop = layer_range[-1]
745+
746+
is_backdrilled = False
747+
if self.edb.grpc:
748+
if via.backdrill_diameter:
749+
is_backdrilled = True
750+
else:
751+
if via.backdrill_parameters:
752+
is_backdrilled = True
753+
754+
if is_backdrilled:
738755
via_length = abs(layers[start].upper_elevation - layers[stop].lower_elevation)
739756
if via.backdrill_type == "layer_drill":
740757
if via.backdrill_bottom:
741758
stub = abs(via_length - layers[via.backdrill_parameters[0]].lower_elevation)
742759
else:
743760
stub = abs(via_length - layers[via.backdrill_parameters[0]].upper_elevation)
744761
else:
745-
stub = 0 # If other drill types exist, handle here
746-
if stub > max_stub:
747-
return {"rule": "back_drill_stub_length", "via": via.name, "stub_um": stub, "limit_um": max_stub}
748-
return None
762+
stub = 0 # other drill types can be handled here
749763

750-
workers = max(1, (os.cpu_count() or 2) - 1)
751-
752-
with ThreadPoolExecutor(max_workers=workers) as executor:
753-
results = list(executor.map(check_via, padstack_instances))
754-
755-
# Merge results lock-free in main thread
756-
self.violations.extend(r for r in results if r is not None)
764+
if stub > max_stub:
765+
self.violations.append(
766+
{"rule": "back_drill_stub_length", "via": via.name, "stub_um": stub, "limit_um": max_stub}
767+
)
757768

758769
# Export utilities
759770
def to_ipc356a(self, file_path: str) -> None:
@@ -786,7 +797,10 @@ def to_ipc356a(self, file_path: str) -> None:
786797
f.write(f"NET {net_name}\n")
787798
for prim in net.primitives:
788799
if hasattr(prim, "polygon_data"):
789-
points = prim.polygon_data.points_without_arcs
800+
if self.edb.grpc:
801+
points = [[pt.x.value, pt.y.value] for pt in prim.polygon_data.without_arcs().points]
802+
else:
803+
points = prim.polygon_data.points_without_arcs
790804
if points:
791805
coords = " ".join(f"x:{x}, y:{y}" for x, y in points)
792806
f.write(f" P {coords}\n")

0 commit comments

Comments
 (0)