pyedb 0.35.0__py3-none-any.whl → 0.37.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyedb might be problematic. Click here for more details.

pyedb/__init__.py CHANGED
@@ -44,7 +44,7 @@ deprecation_warning()
44
44
  #
45
45
 
46
46
  pyedb_path = os.path.dirname(__file__)
47
- __version__ = "0.35.0"
47
+ __version__ = "0.37.0"
48
48
  version = __version__
49
49
 
50
50
  #
@@ -33,6 +33,9 @@ class CfgTerminalInfo(CfgBase):
33
33
  self._pedb = pedb
34
34
  self.type = list(kwargs.keys())[0]
35
35
  self.value = kwargs[self.type]
36
+ self.contact_radius = kwargs.get("contact_radius", None)
37
+ self.num_of_contact = kwargs.get("num_of_contact", 1)
38
+ self.inline = kwargs.get("inline", False)
36
39
 
37
40
  def export_properties(self):
38
41
  return {self.type: self.value}
@@ -244,6 +247,7 @@ class CfgCircuitElement(CfgBase):
244
247
  point = [self.positive_terminal_info.point_x, self.positive_terminal_info.point_y]
245
248
  net_name = self.positive_terminal_info.net
246
249
  pos_coor_terminal[self.name] = self._pedb.get_point_terminal(self.name, net_name, point, layer)
250
+
247
251
  elif pos_type == "pin_group":
248
252
  if self.distributed:
249
253
  pins = self._get_pins(pos_type, pos_value)
@@ -276,7 +280,7 @@ class CfgCircuitElement(CfgBase):
276
280
 
277
281
  if neg_type == "coordinates":
278
282
  layer = self.negative_terminal_info.layer
279
- point = [self.negative_terminal_info.point_x, self.positive_terminal_info.point_y]
283
+ point = [self.negative_terminal_info.point_x, self.negative_terminal_info.point_y]
280
284
  net_name = self.negative_terminal_info.net
281
285
  self.neg_terminal = self._pedb.get_point_terminal(self.name + "_ref", net_name, point, layer)
282
286
  elif neg_type == "nearest_pin":
@@ -378,6 +382,7 @@ class CfgSource(CfgCircuitElement):
378
382
  super().__init__(pedb, **kwargs)
379
383
 
380
384
  self.magnitude = kwargs.get("magnitude", 0.001)
385
+ self.equipotential = kwargs.get("equipotential", False)
381
386
 
382
387
  def set_parameters_to_edb(self):
383
388
  """Create sources."""
@@ -397,6 +402,37 @@ class CfgSource(CfgCircuitElement):
397
402
  elem.name = f"{self.name}_{elem.name}"
398
403
  elem.magnitude = self.magnitude / self._elem_num
399
404
  circuit_elements.append(elem)
405
+ for terminal in circuit_elements:
406
+ if self.equipotential:
407
+ terms = [terminal, terminal.ref_terminal] if terminal.ref_terminal else [terminal]
408
+ for t in terms:
409
+ if not t.is_reference_terminal:
410
+ radius = self.positive_terminal_info.contact_radius
411
+ num_of_contact = self.positive_terminal_info.num_of_contact
412
+ inline = self.positive_terminal_info.inline
413
+ else:
414
+ radius = self.negative_terminal_info.contact_radius
415
+ num_of_contact = self.negative_terminal_info.num_of_contact
416
+ inline = self.negative_terminal_info.inline
417
+
418
+ pads = []
419
+ if t.terminal_type == "PadstackInstanceTerminal":
420
+ pads.append(t.reference_object)
421
+ elif t.terminal_type == "PinGroupTerminal":
422
+ name = t._edb_object.GetPinGroup().GetName()
423
+ pg = self._pedb.siwave.pin_groups[name]
424
+ pads.extend([i for _, i in pg.pins.items()])
425
+ elif t.terminal_type == "PointTerminal" and radius:
426
+ temp = [i for i in self._pedb.layout.terminals if i.name == t.name][0]
427
+ if radius is not None:
428
+ prim = self._pedb.modeler.create_circle(
429
+ temp.layer.name, temp.location[0], temp.location[1], radius, temp.net_name
430
+ )
431
+ prim.dcir_equipotential_region = True
432
+
433
+ for i in pads:
434
+ i._set_equipotential(contact_radius=radius, inline=inline, num_of_contact=num_of_contact)
435
+
400
436
  return circuit_elements
401
437
 
402
438
  def export_properties(self):
pyedb/dotnet/edb.py CHANGED
@@ -603,7 +603,7 @@ class Edb(Database):
603
603
  def import_layout_pcb(
604
604
  self,
605
605
  input_file,
606
- working_dir,
606
+ working_dir="",
607
607
  anstranslator_full_path="",
608
608
  use_ppe=False,
609
609
  control_file=None,
@@ -616,7 +616,7 @@ class Edb(Database):
616
616
  ----------
617
617
  input_file : str
618
618
  Full path to the board file.
619
- working_dir : str
619
+ working_dir : str, optional
620
620
  Directory in which to create the ``aedb`` folder. The name given to the AEDB file
621
621
  is the same as the name of the board file.
622
622
  anstranslator_full_path : str, optional
@@ -1510,6 +1510,13 @@ class Edb(Database):
1510
1510
  else:
1511
1511
  return False
1512
1512
  else:
1513
+ if anstranslator_full_path and os.path.exists(anstranslator_full_path):
1514
+ path = anstranslator_full_path
1515
+ else:
1516
+ path = os.path.join(self.base_path, "anstranslator")
1517
+ if is_windows:
1518
+ path += ".exe"
1519
+
1513
1520
  temp_map_file = os.path.splitext(inputGDS)[0] + ".map"
1514
1521
  temp_layermap_file = os.path.splitext(inputGDS)[0] + ".layermap"
1515
1522
 
@@ -1529,10 +1536,10 @@ class Edb(Database):
1529
1536
  else:
1530
1537
  self.logger.error("Unable to define control file.")
1531
1538
 
1532
- command = [anstranslator_full_path, inputGDS, f'-g="{map_file}"', f'-c="{control_file}"']
1539
+ command = [path, inputGDS, f'-g="{map_file}"', f'-c="{control_file}"']
1533
1540
  else:
1534
1541
  command = [
1535
- anstranslator_full_path,
1542
+ path,
1536
1543
  inputGDS,
1537
1544
  f'-o="{control_file_temp}"' f'-t="{tech_file}"',
1538
1545
  f'-g="{map_file}"',
@@ -220,7 +220,7 @@ class Layout(ObjBase):
220
220
  -------
221
221
  """
222
222
 
223
- return [EDBNetsData(net, self._pedb) for net in self._edb_object.Nets]
223
+ return [EDBNetsData(net, self._pedb) for net in self._edb_object.Nets if net]
224
224
 
225
225
  @property
226
226
  def primitives(self):
@@ -230,7 +230,7 @@ class Layout(ObjBase):
230
230
  -------
231
231
  list of :class:`dotnet.edb_core.dotnet.primitive.PrimitiveDotNet` cast objects.
232
232
  """
233
- return [primitive_cast(self._pedb, p) for p in self._edb_object.Primitives]
233
+ return [primitive_cast(self._pedb, p) for p in self._edb_object.Primitives if p]
234
234
 
235
235
  @property
236
236
  def bondwires(self):
@@ -331,16 +331,32 @@ class Layout(ObjBase):
331
331
  obj = self._pedb._edb.Cell.Hierarchy.Component.FindByName(self._edb_object, value)
332
332
  return EDBComponent(self._pedb, obj) if obj is not None else None
333
333
 
334
- def find_primitive(self, layer_name: Union[str, list]) -> list:
334
+ def find_primitive(
335
+ self, layer_name: Union[str, list] = None, name: Union[str, list] = None, net_name: Union[str, list] = None
336
+ ) -> list:
335
337
  """Find a primitive objects by layer name.
336
338
 
337
339
  Parameters
338
340
  ----------
339
- layer_name : str, list
341
+ layer_name : str, list, optional
340
342
  Name of the layer.
343
+ name : str, list, optional
344
+ Name of the primitive
345
+ net_name : str, list, optional
346
+ Name of the primitive
341
347
  Returns
342
348
  -------
343
349
  list
344
350
  """
345
- layer_name = layer_name if isinstance(layer_name, list) else [layer_name]
346
- return [i for i in self.primitives if i.layer_name in layer_name]
351
+ if layer_name is not None:
352
+ layer_name = layer_name if isinstance(layer_name, list) else [layer_name]
353
+ if name is not None:
354
+ name = name if isinstance(name, list) else [name]
355
+ if net_name is not None:
356
+ net_name = net_name if isinstance(net_name, list) else [net_name]
357
+
358
+ prims = self.primitives
359
+ prims = [i for i in prims if i.aedt_name in name] if name is not None else prims
360
+ prims = [i for i in prims if i.layer_name in layer_name] if layer_name is not None else prims
361
+ prims = [i for i in prims if i.net_name in net_name] if net_name is not None else prims
362
+ return prims
@@ -19,6 +19,7 @@
19
19
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
+ import re
22
23
 
23
24
  from pyedb.dotnet.edb_core.cell.connectable import Connectable
24
25
  from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
@@ -787,3 +788,66 @@ class Primitive(Connectable):
787
788
  self.polygon_data = polygon_data
788
789
  return True
789
790
  return False
791
+
792
+ @property
793
+ def _em_properties(self):
794
+ """Get EM properties."""
795
+ default = (
796
+ r"$begin 'EM properties'\n"
797
+ r"\tType('Mesh')\n"
798
+ r"\tDataId='EM properties1'\n"
799
+ r"\t$begin 'Properties'\n"
800
+ r"\t\tGeneral=''\n"
801
+ r"\t\tModeled='true'\n"
802
+ r"\t\tUnion='true'\n"
803
+ r"\t\t'Use Precedence'='false'\n"
804
+ r"\t\t'Precedence Value'='1'\n"
805
+ r"\t\tPlanarEM=''\n"
806
+ r"\t\tRefined='true'\n"
807
+ r"\t\tRefineFactor='1'\n"
808
+ r"\t\tNoEdgeMesh='false'\n"
809
+ r"\t\tHFSS=''\n"
810
+ r"\t\t'Solve Inside'='false'\n"
811
+ r"\t\tSIwave=''\n"
812
+ r"\t\t'DCIR Equipotential Region'='false'\n"
813
+ r"\t$end 'Properties'\n"
814
+ r"$end 'EM properties'\n"
815
+ )
816
+
817
+ pid = self._pedb.edb_api.ProductId.Designer
818
+ _, p = self._edb_object.GetProductProperty(pid, 18, "")
819
+ if p:
820
+ return p
821
+ else:
822
+ return default
823
+
824
+ @_em_properties.setter
825
+ def _em_properties(self, em_prop):
826
+ """Set EM properties"""
827
+ pid = self._pedb.edb_api.ProductId.Designer
828
+ self._edb_object.SetProductProperty(pid, 18, em_prop)
829
+
830
+ @property
831
+ def dcir_equipotential_region(self):
832
+ """Check whether dcir equipotential region is enabled.
833
+
834
+ Returns
835
+ -------
836
+ bool
837
+ """
838
+ pattern = r"'DCIR Equipotential Region'='([^']+)'"
839
+ em_pp = self._em_properties
840
+ result = re.search(pattern, em_pp).group(1)
841
+ if result == "true":
842
+ return True
843
+ else:
844
+ return False
845
+
846
+ @dcir_equipotential_region.setter
847
+ def dcir_equipotential_region(self, value):
848
+ """Set dcir equipotential region."""
849
+ pp = r"'DCIR Equipotential Region'='true'" if value else r"'DCIR Equipotential Region'='false'"
850
+ em_pp = self._em_properties
851
+ pattern = r"'DCIR Equipotential Region'='([^']+)'"
852
+ new_em_pp = re.sub(pattern, pp, em_pp)
853
+ self._em_properties = new_em_pp
@@ -25,6 +25,7 @@ import os
25
25
  import re
26
26
  import subprocess
27
27
  import sys
28
+ import xml
28
29
 
29
30
  from pyedb.edb_logger import pyedb_logger
30
31
  from pyedb.generic.general_methods import ET, env_path, env_value, is_linux
@@ -964,14 +965,14 @@ class ControlFileMeshOp:
964
965
  class ControlFileSetup:
965
966
  """Setup Class."""
966
967
 
967
- def __init__(self, name):
968
+ def __init__(self, name, adapt_freq="1GHz", maxdelta=0.02, maxpasses=10):
968
969
  self.name = name
969
970
  self.enabled = True
970
971
  self.save_fields = False
971
972
  self.save_rad_fields = False
972
- self.frequency = "1GHz"
973
- self.maxpasses = 10
974
- self.max_delta = 0.02
973
+ self.frequency = adapt_freq
974
+ self.maxpasses = maxpasses
975
+ self.max_delta = maxdelta
975
976
  self.union_polygons = True
976
977
  self.small_voids_area = 0
977
978
  self.mode_type = "IC"
@@ -1082,22 +1083,25 @@ class ControlFileSetups:
1082
1083
  def __init__(self):
1083
1084
  self.setups = []
1084
1085
 
1085
- def add_setup(self, name, frequency):
1086
+ def add_setup(self, name, adapt_freq, maxdelta, maxpasses):
1086
1087
  """Add a new setup
1087
1088
 
1088
1089
  Parameters
1089
1090
  ----------
1090
1091
  name : str
1091
- Setup name.
1092
- frequency : str
1092
+ Setup Name.
1093
+ adapt_freq : str, optional
1093
1094
  Setup Frequency.
1095
+ maxdelta : float, optional
1096
+ Maximum Delta.
1097
+ maxpasses : int, optional
1098
+ Maximum Number of Passes.
1094
1099
 
1095
1100
  Returns
1096
1101
  -------
1097
1102
  :class:`pyedb.dotnet.edb_core.edb_data.control_file.ControlFileSetup`
1098
1103
  """
1099
- setup = ControlFileSetup(name)
1100
- setup.frequency = frequency
1104
+ setup = ControlFileSetup(name, adapt_freq, maxdelta, maxpasses)
1101
1105
  self.setups.append(setup)
1102
1106
  return setup
1103
1107
 
@@ -1112,17 +1116,17 @@ class ControlFile:
1112
1116
 
1113
1117
  def __init__(self, xml_input=None, tecnhology=None, layer_map=None):
1114
1118
  self.stackup = ControlFileStackup()
1119
+ self.boundaries = ControlFileBoundaries()
1120
+ self.setups = ControlFileSetups()
1115
1121
  if xml_input:
1116
1122
  self.parse_xml(xml_input)
1117
1123
  if tecnhology:
1118
1124
  self.parse_technology(tecnhology)
1119
1125
  if layer_map:
1120
1126
  self.parse_layer_map(layer_map)
1121
- self.boundaries = ControlFileBoundaries()
1122
1127
  self.remove_holes = False
1123
1128
  self.remove_holes_area_minimum = 30
1124
1129
  self.remove_holes_units = "um"
1125
- self.setups = ControlFileSetups()
1126
1130
  self.components = ControlFileComponents()
1127
1131
  self.import_options = ControlFileImportOptions()
1128
1132
  pass
@@ -1262,6 +1266,50 @@ class ControlFile:
1262
1266
  via.remove_unconnected = (
1263
1267
  True if i.attrib["RemoveUnconnected"] == "true" else False
1264
1268
  )
1269
+ if el.tag == "Boundaries":
1270
+ for port_el in el:
1271
+ if port_el.tag == "CircuitPortPt":
1272
+ self.boundaries.add_port(
1273
+ name=port_el.attrib["Name"],
1274
+ x1=port_el.attrib["x1"],
1275
+ y1=port_el.attrib["y1"],
1276
+ layer1=port_el.attrib["Layer1"],
1277
+ x2=port_el.attrib["x2"],
1278
+ y2=port_el.attrib["y2"],
1279
+ layer2=port_el.attrib["Layer2"],
1280
+ z0=port_el.attrib["Z0"],
1281
+ )
1282
+ setups = root.find("SimulationSetups")
1283
+ if setups:
1284
+ hfsssetup = setups.find("HFSSSetup")
1285
+ if hfsssetup:
1286
+ if "Name" in hfsssetup.attrib:
1287
+ name = hfsssetup.attrib["Name"]
1288
+ hfsssimset = hfsssetup.find("HFSSSimulationSettings")
1289
+ if hfsssimset:
1290
+ hfssadaptset = hfsssimset.find("HFSSAdaptiveSettings")
1291
+ if hfssadaptset:
1292
+ adaptset = hfssadaptset.find("AdaptiveSettings")
1293
+ if adaptset:
1294
+ singlefreqdatalist = adaptset.find("SingleFrequencyDataList")
1295
+ if singlefreqdatalist:
1296
+ adaptfreqdata = singlefreqdatalist.find("AdaptiveFrequencyData")
1297
+ if adaptfreqdata:
1298
+ if isinstance(
1299
+ adaptfreqdata.find("AdaptiveFrequency"), xml.etree.ElementTree.Element
1300
+ ):
1301
+ adapt_freq = adaptfreqdata.find("AdaptiveFrequency").text
1302
+ else:
1303
+ adapt_freq = "1GHz"
1304
+ if isinstance(adaptfreqdata.find("MaxDelta"), xml.etree.ElementTree.Element):
1305
+ maxdelta = adaptfreqdata.find("MaxDelta").text
1306
+ else:
1307
+ maxdelta = 0.02
1308
+ if isinstance(adaptfreqdata.find("MaxPasses"), xml.etree.ElementTree.Element):
1309
+ maxpasses = adaptfreqdata.find("MaxPasses").text
1310
+ else:
1311
+ maxpasses = 10
1312
+ self.setups.add_setup(name, adapt_freq, maxdelta, maxpasses)
1265
1313
  return True
1266
1314
 
1267
1315
  def write_xml(self, xml_output):
@@ -1278,8 +1326,7 @@ class ControlFile:
1278
1326
  """
1279
1327
  control = ET.Element("{http://www.ansys.com/control}Control", attrib={"schemaVersion": "1.0"})
1280
1328
  self.stackup._write_xml(control)
1281
- if self.boundaries.ports or self.boundaries.extents:
1282
- self.boundaries._write_xml(control)
1329
+ self.boundaries._write_xml(control)
1283
1330
  if self.remove_holes:
1284
1331
  hole = ET.SubElement(control, "RemoveHoles")
1285
1332
  hole.set("HoleAreaMinimum", str(self.remove_holes_area_minimum))
@@ -59,7 +59,7 @@ class EDBNetsData(NetDotNet):
59
59
  """
60
60
  from pyedb.dotnet.edb_core.cell.layout import primitive_cast
61
61
 
62
- return [primitive_cast(self._app, i) for i in self.net_object.Primitives]
62
+ return [primitive_cast(self._app, i) for i in self.net_object.Primitives if i]
63
63
  # return [self._app.layout.find_object_by_id(i.GetId()) for i in self.net_object.Primitives]
64
64
 
65
65
  @property
@@ -22,9 +22,10 @@
22
22
 
23
23
  from collections import OrderedDict
24
24
  import math
25
- import re
26
25
  import warnings
27
26
 
27
+ import numpy as np
28
+
28
29
  from pyedb.dotnet.clr_module import String
29
30
  from pyedb.dotnet.edb_core.cell.primitive.primitive import Primitive
30
31
  from pyedb.dotnet.edb_core.dotnet.database import PolygonDataDotNet
@@ -1248,68 +1249,77 @@ class EDBPadstackInstance(Primitive):
1248
1249
 
1249
1250
  return self._pedb.create_port(terminal, ref_terminal, is_circuit_port)
1250
1251
 
1251
- @property
1252
- def _em_properties(self):
1253
- """Get EM properties."""
1254
- default = (
1255
- r"$begin 'EM properties'\n"
1256
- r"\tType('Mesh')\n"
1257
- r"\tDataId='EM properties1'\n"
1258
- r"\t$begin 'Properties'\n"
1259
- r"\t\tGeneral=''\n"
1260
- r"\t\tModeled='true'\n"
1261
- r"\t\tUnion='true'\n"
1262
- r"\t\t'Use Precedence'='false'\n"
1263
- r"\t\t'Precedence Value'='1'\n"
1264
- r"\t\tPlanarEM=''\n"
1265
- r"\t\tRefined='true'\n"
1266
- r"\t\tRefineFactor='1'\n"
1267
- r"\t\tNoEdgeMesh='false'\n"
1268
- r"\t\tHFSS=''\n"
1269
- r"\t\t'Solve Inside'='false'\n"
1270
- r"\t\tSIwave=''\n"
1271
- r"\t\t'DCIR Equipotential Region'='false'\n"
1272
- r"\t$end 'Properties'\n"
1273
- r"$end 'EM properties'\n"
1274
- )
1275
-
1276
- pid = self._pedb.edb_api.ProductId.Designer
1277
- _, p = self._edb_padstackinstance.GetProductProperty(pid, 18, "")
1278
- if p:
1279
- return p
1280
- else:
1281
- return default
1252
+ def _set_equipotential(self, contact_radius=None, inline=False, num_of_contact=1):
1253
+ """Workaround solution. Remove when EDBAPI bug is fixed for dcir_equipotential_region."""
1254
+ pad = self.definition.pad_by_layer[self.start_layer]
1282
1255
 
1283
- @_em_properties.setter
1284
- def _em_properties(self, em_prop):
1285
- """Set EM properties"""
1286
- pid = self._pedb.edb_api.ProductId.Designer
1287
- self._edb_padstackinstance.SetProductProperty(pid, 18, em_prop)
1256
+ pos_x, pos_y = self.position
1257
+ comp_rotation = self._pedb.edb_value(self.component.rotation).ToDouble() % 3.141592653589793
1288
1258
 
1289
- @property
1290
- def dcir_equipotential_region(self):
1291
- """Check whether dcir equipotential region is enabled.
1259
+ if contact_radius is not None:
1260
+ if num_of_contact == 1:
1261
+ prim = self._pedb.modeler.create_circle(pad.layer_name, pos_x, pos_y, contact_radius, self.net_name)
1262
+ prim.dcir_equipotential_region = True
1263
+ else:
1264
+ if pad.shape.lower() in ["rectangle", "oval"]:
1265
+ width, height = pad.parameters_values[0:2]
1266
+ radius = self._pedb.edb_value(contact_radius).ToDouble()
1267
+ else:
1268
+ return
1269
+
1270
+ if inline is False:
1271
+ x_offset = width / 2 - radius if comp_rotation == 0 else height / 2 - radius
1272
+ y_offset = height / 2 - radius if comp_rotation == 0 else width / 2 - radius
1273
+ positions = []
1274
+ for x, y in [[1, 1], [-1, 1], [1, -1], [-1, -1]]:
1275
+ positions.append([x_offset * x, y_offset * y])
1276
+ else:
1277
+ if width > height:
1278
+ offset = (width - radius * 2) / (num_of_contact - 1)
1279
+ else:
1280
+ offset = (height - radius * 2) / (num_of_contact - 1)
1281
+
1282
+ start_pos = (num_of_contact - 1) / 2
1283
+ offset = [offset * i for i in np.arange(start_pos * -1, start_pos + 1)]
1284
+
1285
+ if (width > height and comp_rotation == 0) or (width < height and comp_rotation != 0):
1286
+ positions = list(zip(offset, [0] * num_of_contact))
1287
+ else:
1288
+ positions = list(zip([0] * num_of_contact, offset))
1289
+
1290
+ for x, y in positions:
1291
+ prim = self._pedb.modeler.create_circle(pad.layer_name, pos_x + x, pos_y + y, radius, self.net_name)
1292
+ prim.dcir_equipotential_region = True
1293
+ return
1292
1294
 
1293
- Returns
1294
- -------
1295
- bool
1296
- """
1297
- pattern = r"'DCIR Equipotential Region'='([^']+)'"
1298
- em_pp = self._em_properties
1299
- result = re.search(pattern, em_pp).group(1)
1300
- if result == "true":
1301
- return True
1295
+ elif pad.shape.lower() == "circle":
1296
+ ra = self._pedb.edb_value(pad.parameters_values[0] / 2)
1297
+ pos = self.position
1298
+ prim = self._pedb.modeler.create_circle(pad.layer_name, pos[0], pos[1], ra, self.net_name)
1299
+ elif pad.shape.lower() == "rectangle":
1300
+ width, height = pad.parameters_values
1301
+ prim = self._pedb.modeler.create_rectangle(
1302
+ pad.layer_name,
1303
+ self.net_name,
1304
+ width=width,
1305
+ height=height,
1306
+ representation_type="CenterWidthHeight",
1307
+ center_point=self.position,
1308
+ rotation=self.component.rotation,
1309
+ )
1310
+ elif pad.shape.lower() == "oval":
1311
+ width, height, _ = pad.parameters_values
1312
+ prim = self._pedb.modeler.create_circle(
1313
+ pad.layer_name, self.position[0], self.position[1], height / 2, self.net_name
1314
+ )
1315
+ elif pad.polygon_data:
1316
+ prim = self._pedb.modeler.create_polygon(
1317
+ pad.polygon_data._edb_object, self.start_layer, net_name=self.net_name
1318
+ )
1319
+ prim.move(self.position)
1302
1320
  else:
1303
- return False
1304
-
1305
- @dcir_equipotential_region.setter
1306
- def dcir_equipotential_region(self, value):
1307
- """Set dcir equipotential region."""
1308
- pp = r"'DCIR Equipotential Region'='true'" if value else r"'DCIR Equipotential Region'='false'"
1309
- em_pp = self._em_properties
1310
- pattern = r"'DCIR Equipotential Region'='([^']+)'"
1311
- new_em_pp = re.sub(pattern, pp, em_pp)
1312
- self._em_properties = new_em_pp
1321
+ return
1322
+ prim.dcir_equipotential_region = True
1313
1323
 
1314
1324
  @property
1315
1325
  def object_instance(self):
@@ -1577,7 +1587,6 @@ class EDBPadstackInstance(Primitive):
1577
1587
  str
1578
1588
  Name of the starting layer.
1579
1589
  """
1580
- layer = self._pedb.edb_api.cell.layer("", self._pedb.edb_api.cell.layer_type.SignalLayer)
1581
1590
  _, start_layer, stop_layer = self._edb_object.GetLayerRange()
1582
1591
 
1583
1592
  if start_layer:
@@ -1599,7 +1608,6 @@ class EDBPadstackInstance(Primitive):
1599
1608
  str
1600
1609
  Name of the stopping layer.
1601
1610
  """
1602
- layer = self._pedb.edb_api.cell.layer("", self._pedb.edb_api.cell.layer_type.SignalLayer)
1603
1611
  _, start_layer, stop_layer = self._edb_padstackinstance.GetLayerRange()
1604
1612
 
1605
1613
  if stop_layer:
@@ -1620,7 +1628,7 @@ class EDBPadstackInstance(Primitive):
1620
1628
  layer_list = []
1621
1629
  start_layer_name = start_layer.GetName()
1622
1630
  stop_layer_name = stop_layer.GetName()
1623
- for layer_name in list(self._pedb.stackup.layers.keys()):
1631
+ for layer_name in list(self._pedb.stackup.signal_layers.keys()):
1624
1632
  if started:
1625
1633
  layer_list.append(layer_name)
1626
1634
  if layer_name == stop_layer_name or layer_name == start_layer_name:
@@ -1705,7 +1713,6 @@ class EDBPadstackInstance(Primitive):
1705
1713
  float
1706
1714
  Rotatation value for the padstack instance.
1707
1715
  """
1708
- point_data = self._pedb.edb_api.geometry.point_data(self._pedb.edb_value(0.0), self._pedb.edb_value(0.0))
1709
1716
  out = self._edb_padstackinstance.GetPositionAndRotationValue()
1710
1717
 
1711
1718
  if out[0]:
@@ -19,6 +19,7 @@
19
19
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
+ from typing import Union
22
23
 
23
24
  from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
24
25
  from pyedb.dotnet.edb_core.geometry.point_data import PointData
@@ -128,3 +129,7 @@ class PolygonData:
128
129
  arcs = convert_py_list_to_net_list(arcs)
129
130
  poly = self._edb_object.CreateFromArcs(arcs, flag)
130
131
  return PolygonData(self._pedb, poly)
132
+
133
+ def point_in_polygon(self, x: Union[str, float], y: Union[str, float]) -> bool:
134
+ """Determines whether a point is inside the polygon."""
135
+ return self._edb_object.PointInPolygon(self._pedb.point_data(x, y))
@@ -661,8 +661,7 @@ class Modeler(object):
661
661
  else:
662
662
  polygonData = main_shape
663
663
  if not polygonData or polygonData.IsNull():
664
- self._logger.error("Failed to create main shape polygon data")
665
- return False
664
+ raise RuntimeError("Failed to create main shape polygon data")
666
665
  for void in voids:
667
666
  if isinstance(void, list):
668
667
  void = self.Shape("polygon", points=void)
@@ -1636,14 +1636,12 @@ class EdbPadstacks(object):
1636
1636
  merged_via_ids = []
1637
1637
  if not contour_boxes:
1638
1638
  raise Exception("No contour box provided, you need to pass a nested list as argument.")
1639
- if not start_layer:
1640
- start_layer = list(self._pedb.stackup.layers.values())[0].name
1641
- if not stop_layer:
1642
- stop_layer = list(self._pedb.stackup.layers.values())[-1].name
1639
+
1643
1640
  instances_index = {}
1644
1641
  for id, inst in self.instances.items():
1645
1642
  instances_index[id] = inst.position
1646
1643
  for contour_box in contour_boxes:
1644
+ all_instances = self.instances
1647
1645
  instances = self.get_padstack_instances_id_intersecting_polygon(
1648
1646
  points=contour_box, padstack_instances_index=instances_index
1649
1647
  )
@@ -1651,7 +1649,28 @@ class EdbPadstacks(object):
1651
1649
  raise Exception(f"No padstack instances found inside {contour_box}")
1652
1650
  else:
1653
1651
  if net_filter:
1654
- instances = [id for id in instances if not self.instances[id].net_name in net_filter]
1652
+ # instances = [id for id in instances if not self.instances[id].net_name in net_filter]
1653
+ instances = [id for id in instances if all_instances[id].net_name not in net_filter]
1654
+ # filter instances by start and stop layer
1655
+ if start_layer:
1656
+ if start_layer not in self._pedb.stackup.layers.keys():
1657
+ raise Exception(f"{start_layer} not exist")
1658
+ else:
1659
+ instances = [id for id in instances if all_instances[id].start_layer == start_layer]
1660
+ if stop_layer:
1661
+ if stop_layer not in self._pedb.stackup.layers.keys():
1662
+ raise Exception(f"{stop_layer} not exist")
1663
+ else:
1664
+ instances = [id for id in instances if all_instances[id].stop_layer == stop_layer]
1665
+ if not instances:
1666
+ raise Exception(
1667
+ f"No padstack instances found inside {contour_box} between {start_layer} and {stop_layer}"
1668
+ )
1669
+
1670
+ if not start_layer:
1671
+ start_layer = list(self._pedb.stackup.layers.values())[0].name
1672
+ if not stop_layer:
1673
+ stop_layer = list(self._pedb.stackup.layers.values())[-1].name
1655
1674
 
1656
1675
  net = self.instances[instances[0]].net_name
1657
1676
  x_values = []
@@ -1692,7 +1711,7 @@ class EdbPadstacks(object):
1692
1711
  merged_instance.stop_layer = stop_layer
1693
1712
 
1694
1713
  merged_via_ids.append(merged_instance.id)
1695
- [self.instances[id].delete() for id in instances]
1714
+ _ = [all_instances[id].delete() for id in instances]
1696
1715
  return merged_via_ids
1697
1716
 
1698
1717
  def merge_via_along_lines(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pyedb
3
- Version: 0.35.0
3
+ Version: 0.37.0
4
4
  Summary: Higher-Level Pythonic Ansys Electronics Data Base
5
5
  Author-email: "ANSYS, Inc." <pyansys.core@ansys.com>
6
6
  Maintainer-email: PyEDB developers <simon.vandenbrouck@ansys.com>
@@ -1,4 +1,4 @@
1
- pyedb/__init__.py,sha256=QJGYOhTvr2BmugtK2s-wdaTRzp_3L2rc1RWwDKYu0yU,1525
1
+ pyedb/__init__.py,sha256=bTsJ4CBHXe9DwW7gVeft0iIBTaHaGYTd7KW5dij8NdU,1525
2
2
  pyedb/edb_logger.py,sha256=7KXPvAMCKzlzJ5zioiNO5A3zkqbpCHhWHB4aXKfgu5Y,14959
3
3
  pyedb/exceptions.py,sha256=n94xluzUks6BA24vd_L6HkrvoP_H_l6__hQmqzdCyPo,111
4
4
  pyedb/siwave.py,sha256=Mgg5ZGzOUOtNdlePHcnrgN3rletQ7jrqRi3WfxF58uU,17727
@@ -18,7 +18,7 @@ pyedb/configuration/cfg_operations.py,sha256=CFLBdM2kQBsW6f7W0NHWbV56RDMHSnaNQl3
18
18
  pyedb/configuration/cfg_package_definition.py,sha256=f_RRT9R-3H5kHBlc4QSpjq9uQgYbaKQ78XXXrc_r3kg,5296
19
19
  pyedb/configuration/cfg_padstacks.py,sha256=zZSEc92TwSqa7KSZBmDb4Sybm4ivM5lrvb8uMxFho8k,18292
20
20
  pyedb/configuration/cfg_pin_groups.py,sha256=zNKfVP-fd1qUxS2wNb0ZTLGonkUnBmiXb4Rss1Rr7sE,3714
21
- pyedb/configuration/cfg_ports_sources.py,sha256=p6pauq8r14N4whuzxirSkKTS2lu4ViRMxB0KbIcBj5c,20944
21
+ pyedb/configuration/cfg_ports_sources.py,sha256=1ngvubH02qQBHjkRI90BvpdRq4HMHRfbeFRKWEjEtAM,22988
22
22
  pyedb/configuration/cfg_s_parameter_models.py,sha256=DgBprcEYR2r_3BY4f_CuwuhJw_QFEag3xaAlLTRfMuE,5356
23
23
  pyedb/configuration/cfg_setup.py,sha256=QGKQHAEeo196TYtKMvIMb2-p8KC4U8fmHx0yn0SpgMo,10351
24
24
  pyedb/configuration/cfg_spice_models.py,sha256=Q_5j2-V6cepSFcnijot8iypTqzanLp7HOz-agmnwKns,2570
@@ -26,7 +26,7 @@ pyedb/configuration/cfg_stackup.py,sha256=Ie2mdHfCgPn3F7BSdLlYZoZ3exhCDgPrhlYwxH
26
26
  pyedb/configuration/configuration.py,sha256=kQvUa9pkrdIw5gZE6RlaVdQOiioH0T0JkqUzb8fvdnU,15635
27
27
  pyedb/dotnet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  pyedb/dotnet/clr_module.py,sha256=EabqZgZgBZOhJD9_V8Ll8sEKgBFj9xe9zARNYIvYM_s,5304
29
- pyedb/dotnet/edb.py,sha256=vl2Jbwq55eI3vdSq9Je-iklZBhnb7ccKC806s67kSrE,186428
29
+ pyedb/dotnet/edb.py,sha256=EDXhqDKk8uif6EVpZld3ggdmxs3uukgvpX-cjXAfAAk,186688
30
30
  pyedb/dotnet/application/Variables.py,sha256=awNhyiLASBYrNjWIyW8IJowgqt7FfFPKF9UElRWyjZg,77750
31
31
  pyedb/dotnet/application/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  pyedb/dotnet/edb_core/__init__.py,sha256=nIRLJ8VZLcMAp12zmGsnZ5x2BEEl7q_Kj_KAOXxVjpQ,52
@@ -36,15 +36,15 @@ pyedb/dotnet/edb_core/hfss.py,sha256=oQFC6PwRbjAwfR60RoklwpZ_2sDI4OheNNdwaqY23ok
36
36
  pyedb/dotnet/edb_core/layout_obj_instance.py,sha256=Pd8rfdO3b6HLFGwXBMw-tfE4LPIcW_9_X5KEdFaiito,1407
37
37
  pyedb/dotnet/edb_core/layout_validation.py,sha256=S0IFx9t5toVpuTLTI2Cs9vvgR4BCebJLXnj0ydW2Op8,13597
38
38
  pyedb/dotnet/edb_core/materials.py,sha256=s105DUTFkQoQRWgtRMp02DKcU2YcSrfLbJoi8hcTQII,42293
39
- pyedb/dotnet/edb_core/modeler.py,sha256=rVJ-eh3eKOnCHENaBLZ8D7duH7tUtUqZJNLKGLFsZ_M,55519
39
+ pyedb/dotnet/edb_core/modeler.py,sha256=XKlKzgTRtFll5ZZlhC4JEfKkO5AZvooAtgbV49VYbZc,55494
40
40
  pyedb/dotnet/edb_core/net_class.py,sha256=4U6Cc1Gn7ZJ_ub9uKmtrsoz5wD1XS42afci3Y3ewRp0,11354
41
41
  pyedb/dotnet/edb_core/nets.py,sha256=Wc84urZG6nM3fZYqMj2HzM6CgNz_B4s4O3WmMGr-5H0,25199
42
- pyedb/dotnet/edb_core/padstack.py,sha256=Qp5nSQNo1Ze0u8GUE3FjtbSYD73uQcNJhEOoUAHXLBo,72102
42
+ pyedb/dotnet/edb_core/padstack.py,sha256=eUlIO6pBCfknjvToWWjdvxyz0zpFpyDdwFIMgyLVprk,73173
43
43
  pyedb/dotnet/edb_core/siwave.py,sha256=QF4JyVNWoDeNQRRBBExlCxxVUt1-5DpKIlpuYkXd4k0,64286
44
44
  pyedb/dotnet/edb_core/stackup.py,sha256=b56leXg7X7dEVPP2DUD9n8LZIakWcjIsjiqqkIWsyZU,120035
45
45
  pyedb/dotnet/edb_core/cell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
46
  pyedb/dotnet/edb_core/cell/connectable.py,sha256=gc5jhWx4DX718T7koL6oZZzfS4EdQNTiFX76ZJ2c83E,2864
47
- pyedb/dotnet/edb_core/cell/layout.py,sha256=Bh8WKMwCB0qn9ehP-_rShRTpN7KGgI72K5h_JdkOd6Y,12413
47
+ pyedb/dotnet/edb_core/cell/layout.py,sha256=zMTqjA_8I9vlJGNgZ6fgqmfs6B0krq2v1KlgXw1ZBJs,13172
48
48
  pyedb/dotnet/edb_core/cell/layout_obj.py,sha256=S42rdiI6gVqO77DV3ikc4YxTNufTuqW_X1G-2zkWArA,2765
49
49
  pyedb/dotnet/edb_core/cell/voltage_regulator.py,sha256=-uAzuyERV6ca0bFRzdH4SllcpGY2D9JEdpS7RYaQt6c,5387
50
50
  pyedb/dotnet/edb_core/cell/hierarchy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -58,7 +58,7 @@ pyedb/dotnet/edb_core/cell/hierarchy/spice_model.py,sha256=SGiUcan2l0n8DGk3GtwCs
58
58
  pyedb/dotnet/edb_core/cell/primitive/__init__.py,sha256=8jByHkoaowAYQTCww-zRrTQmN061fLz_OHjTLSrzQQY,58
59
59
  pyedb/dotnet/edb_core/cell/primitive/bondwire.py,sha256=fqIMdv0bNvk591DG6De5c--w9Rpkl5AOeo_qgzoPE6M,7322
60
60
  pyedb/dotnet/edb_core/cell/primitive/path.py,sha256=XVN7dOVpccoBP28M8l5iMzK5QSQdHqpKqC4jK76UTis,12543
61
- pyedb/dotnet/edb_core/cell/primitive/primitive.py,sha256=wZcHylKr_OVnXzVfNtce_WuCTreXEDxeLhinp2Xh7ZA,26709
61
+ pyedb/dotnet/edb_core/cell/primitive/primitive.py,sha256=nn2T3cG2r_qA4OEswTT-QLzS6HiYrkWh7YztGmZVZkE,28796
62
62
  pyedb/dotnet/edb_core/cell/terminal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
63
  pyedb/dotnet/edb_core/cell/terminal/bundle_terminal.py,sha256=qM0wEXkZ-DpoJ6vlVa560Ce8IgOdp4vyIJPedvoa3O0,1977
64
64
  pyedb/dotnet/edb_core/cell/terminal/edge_terminal.py,sha256=lafPRrvsDPYKcysvrkO-5tEZXF3h4IcTXdeJgTjleuI,2158
@@ -76,13 +76,13 @@ pyedb/dotnet/edb_core/dotnet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
76
76
  pyedb/dotnet/edb_core/dotnet/database.py,sha256=9mfEg451IX3Y8PKnyhbVPApqtgmB9R4VTeWyfux8Q0A,36691
77
77
  pyedb/dotnet/edb_core/dotnet/primitive.py,sha256=2Mhh-pwnLzZUGLVRSCiBMtcxfvmrU40cASbpfXe1Ecs,49944
78
78
  pyedb/dotnet/edb_core/edb_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
- pyedb/dotnet/edb_core/edb_data/control_file.py,sha256=qIXBJG0V_dvpvSqIycQcNOb8UrjJiGmlfOE6rwU0Ifo,49679
79
+ pyedb/dotnet/edb_core/edb_data/control_file.py,sha256=OhvB8bffgSeBYbpN_lqOsC_RvRYX77-yn-GbIyTRl0M,52550
80
80
  pyedb/dotnet/edb_core/edb_data/design_options.py,sha256=RO9ip-T5Bfxpsl97_QEk0qDZsza3tLzIX2t25XLutys,2057
81
81
  pyedb/dotnet/edb_core/edb_data/edbvalue.py,sha256=Vj_11HXsQUNavizKp5FicORm6cjhXRh9uvxhv_D_RJc,1977
82
82
  pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py,sha256=wIKH4it1uYkEae4OimS3YE6QoSf8rAAIhxdTwtR9cqU,13040
83
83
  pyedb/dotnet/edb_core/edb_data/layer_data.py,sha256=4Z_eaHSfGfwQBKETEmGSwMvwGzvirtwYw4G4TwonNiA,34314
84
- pyedb/dotnet/edb_core/edb_data/nets_data.py,sha256=fXJ1U18ZLm9xI7MJD3UcTsI8XNZSq5kf20KF2IMib4o,10137
85
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py,sha256=1j_GG552iwvzvx6TKI3Yx6C3RXOWiSNehdlbD8AuzaI,78474
84
+ pyedb/dotnet/edb_core/edb_data/nets_data.py,sha256=k15gL8A9yACRxw5UaMFZamijMLo19MR8YZbZb06tYMA,10142
85
+ pyedb/dotnet/edb_core/edb_data/padstacks_data.py,sha256=n9dsAcimNQdKpxFqfFB1-96KTGhZ6mz0vilAEHDKd4M,79557
86
86
  pyedb/dotnet/edb_core/edb_data/ports.py,sha256=wr2RQi8VExuNIVmnp7c4VpTIhODgthmJmHr01zO4ueo,8873
87
87
  pyedb/dotnet/edb_core/edb_data/primitives_data.py,sha256=kIXkd5SXeN881eJqdJ2KxEZebpimB4qFEed1g6w-Raw,16826
88
88
  pyedb/dotnet/edb_core/edb_data/raptor_x_simulation_setup_data.py,sha256=P37-OIsc8TuTC_s3CXRmvZcJqxAftHA7SATfEyoAnMM,20953
@@ -92,7 +92,7 @@ pyedb/dotnet/edb_core/edb_data/utilities.py,sha256=3wZqOJ35eisOwOPKOs-bvJ8kmd62e
92
92
  pyedb/dotnet/edb_core/edb_data/variables.py,sha256=LS1jZPOYgRvf4cyKf_x8hI9Brs-qbh4wrHu_QGLElrg,3501
93
93
  pyedb/dotnet/edb_core/geometry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
94
94
  pyedb/dotnet/edb_core/geometry/point_data.py,sha256=hC9cRuSnX4cwg09Jr0ZK7ZTjFf_4NwXJMGbZ3s-ULpQ,1590
95
- pyedb/dotnet/edb_core/geometry/polygon_data.py,sha256=u4qWf7guWpJFRmHhh_31vmVyaEceHhjuPxIttmX0lZQ,5022
95
+ pyedb/dotnet/edb_core/geometry/polygon_data.py,sha256=qZ1dRQHMo2JNZaWiPkrqrE009YZU3IOCr8UGQ1MXot8,5272
96
96
  pyedb/dotnet/edb_core/sim_setup_data/__init__.py,sha256=8jByHkoaowAYQTCww-zRrTQmN061fLz_OHjTLSrzQQY,58
97
97
  pyedb/dotnet/edb_core/sim_setup_data/data/__init__.py,sha256=8jByHkoaowAYQTCww-zRrTQmN061fLz_OHjTLSrzQQY,58
98
98
  pyedb/dotnet/edb_core/sim_setup_data/data/adaptive_frequency_data.py,sha256=tlHI7PUUoseNnJAtihpjb1PwXYNr-4ztAAnunlLLWVQ,2463
@@ -188,7 +188,7 @@ pyedb/misc/siw_feature_config/xtalk_scan/scan_config.py,sha256=YmYI6WTQulL5Uf8Wx
188
188
  pyedb/misc/siw_feature_config/xtalk_scan/td_xtalk_config.py,sha256=KHa-UqcXuabiVfT2CV-UvWl5Q2qGYHF2Ye9azcAlnXc,3966
189
189
  pyedb/modeler/geometry_operators.py,sha256=g_Sy7a6R23sP6RtboJn1rl8uTuo8oeLmMF21rNkzwjk,74198
190
190
  pyedb/siwave_core/icepak.py,sha256=WnZ-t8mik7LDY06V8hZFV-TxRZJQWK7bu_8Ichx-oBs,5206
191
- pyedb-0.35.0.dist-info/LICENSE,sha256=qQWivZ12ETN5l3QxvTARY-QI5eoRRlyHdwLlAj0Bg5I,1089
192
- pyedb-0.35.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
193
- pyedb-0.35.0.dist-info/METADATA,sha256=FuDrrBF8NzY_z8cYDUfz0hI2iVKmUn2AwxXR4NBbdRQ,8513
194
- pyedb-0.35.0.dist-info/RECORD,,
191
+ pyedb-0.37.0.dist-info/LICENSE,sha256=qQWivZ12ETN5l3QxvTARY-QI5eoRRlyHdwLlAj0Bg5I,1089
192
+ pyedb-0.37.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
193
+ pyedb-0.37.0.dist-info/METADATA,sha256=IwWf3GCdS37oFKRCZh99M_me8qd3vx0-QbUAvNpXME8,8513
194
+ pyedb-0.37.0.dist-info/RECORD,,
File without changes