pyedb 0.7.1__py3-none-any.whl → 0.8.1__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.

Files changed (32) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/dotnet/edb.py +1 -0
  3. pyedb/dotnet/edb_core/cell/hierarchy/model.py +1 -1
  4. pyedb/dotnet/edb_core/components.py +15 -12
  5. pyedb/dotnet/edb_core/configuration.py +37 -5
  6. pyedb/dotnet/edb_core/definition/component_def.py +1 -1
  7. pyedb/dotnet/edb_core/definition/component_model.py +1 -1
  8. pyedb/dotnet/edb_core/definition/definition_obj.py +1 -1
  9. pyedb/dotnet/edb_core/definition/definitions.py +8 -2
  10. pyedb/dotnet/edb_core/definition/package_def.py +34 -15
  11. pyedb/dotnet/edb_core/dotnet/database.py +5 -4
  12. pyedb/dotnet/edb_core/edb_data/components_data.py +1 -1
  13. pyedb/dotnet/edb_core/edb_data/connectable.py +1 -1
  14. pyedb/dotnet/edb_core/edb_data/layer_data.py +3 -2
  15. pyedb/dotnet/edb_core/edb_data/primitives_data.py +4 -2
  16. pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +6 -0
  17. pyedb/dotnet/edb_core/geometry/__init__.py +0 -0
  18. pyedb/dotnet/edb_core/{edb_data/obj_base.py → geometry/point_data.py} +12 -26
  19. pyedb/dotnet/edb_core/geometry/polygon_data.py +77 -0
  20. pyedb/dotnet/edb_core/materials.py +128 -106
  21. pyedb/dotnet/edb_core/nets.py +3 -3
  22. pyedb/dotnet/edb_core/obj_base.py +94 -0
  23. pyedb/dotnet/edb_core/siwave.py +33 -2
  24. pyedb/dotnet/edb_core/stackup.py +49 -42
  25. pyedb/dotnet/sim_setup_data/data/siw_dc_ir_settings.py +46 -0
  26. pyedb/edb_logger.py +15 -1
  27. pyedb/generic/settings.py +20 -9
  28. pyedb/siwave.py +50 -1
  29. {pyedb-0.7.1.dist-info → pyedb-0.8.1.dist-info}/METADATA +5 -5
  30. {pyedb-0.7.1.dist-info → pyedb-0.8.1.dist-info}/RECORD +32 -28
  31. {pyedb-0.7.1.dist-info → pyedb-0.8.1.dist-info}/LICENSE +0 -0
  32. {pyedb-0.7.1.dist-info → pyedb-0.8.1.dist-info}/WHEEL +0 -0
@@ -73,6 +73,19 @@ DC_ATTRIBUTES = [
73
73
  ]
74
74
 
75
75
 
76
+ def get_line_float_value(line):
77
+ """Retrieve the float value expected in the line of an AMAT file.
78
+
79
+ The associated string is expected to follow one of the following cases:
80
+ - simple('permittivity', 12.)
81
+ - permittivity='12'.
82
+ """
83
+ try:
84
+ return float(re.split(",|=", line)[-1].strip("'\n)"))
85
+ except ValueError:
86
+ return None
87
+
88
+
76
89
  class MaterialProperties(BaseModel):
77
90
  """Store material properties."""
78
91
 
@@ -400,7 +413,7 @@ class Material(object):
400
413
  for attribute in ATTRIBUTES:
401
414
  if attribute in input_dict:
402
415
  setattr(self, attribute, input_dict[attribute])
403
- if "loss_tangent" in input_dict:
416
+ if "loss_tangent" in input_dict: # pragma: no cover
404
417
  setattr(self, "loss_tangent", input_dict["loss_tangent"])
405
418
 
406
419
  # Update DS model
@@ -521,7 +534,7 @@ class Materials(object):
521
534
  material_def = self.__edb_definition.MaterialDef.Create(self.__edb.active_db, name)
522
535
  material = Material(self.__edb, material_def)
523
536
  attributes_input_dict = {key: val for (key, val) in kwargs.items() if key in ATTRIBUTES + DC_ATTRIBUTES}
524
- if "loss_tangent" in kwargs:
537
+ if "loss_tangent" in kwargs: # pragma: no cover
525
538
  warnings.warn(
526
539
  "This key is deprecated in versions >0.7.0 and will soon be removed. "
527
540
  "Use key dielectric_loss_tangent instead.",
@@ -550,14 +563,10 @@ class Materials(object):
550
563
  :class:`pyedb.dotnet.edb_core.materials.Material`
551
564
 
552
565
  """
553
- if name in self.__materials:
554
- raise ValueError(f"Material {name} already exists in material library.")
555
-
556
566
  extended_kwargs = {key: value for (key, value) in kwargs.items()}
557
567
  extended_kwargs["conductivity"] = conductivity
558
568
  material = self.add_material(name, **extended_kwargs)
559
569
 
560
- self.__materials[name] = material
561
570
  return material
562
571
 
563
572
  @pyedb_function_handler()
@@ -577,15 +586,11 @@ class Materials(object):
577
586
  -------
578
587
  :class:`pyedb.dotnet.edb_core.materials.Material`
579
588
  """
580
- if name in self.__materials:
581
- raise ValueError(f"Material {name} already exists in material library.")
582
-
583
589
  extended_kwargs = {key: value for (key, value) in kwargs.items()}
584
590
  extended_kwargs["permittivity"] = permittivity
585
591
  extended_kwargs["dielectric_loss_tangent"] = dielectric_loss_tangent
586
592
  material = self.add_material(name, **extended_kwargs)
587
593
 
588
- self.__materials[name] = material
589
594
  return material
590
595
 
591
596
  @pyedb_function_handler()
@@ -632,7 +637,7 @@ class Materials(object):
632
637
  material = self.__add_dielectric_material_model(name, material_model)
633
638
  for key, value in kwargs.items():
634
639
  setattr(material, key, value)
635
- if "loss_tangent" in kwargs:
640
+ if "loss_tangent" in kwargs: # pragma: no cover
636
641
  warnings.warn(
637
642
  "This key is deprecated in versions >0.7.0 and will soon be removed. "
638
643
  "Use key dielectric_loss_tangent instead.",
@@ -698,7 +703,7 @@ class Materials(object):
698
703
  material = self.__add_dielectric_material_model(name, material_model)
699
704
  for key, value in kwargs.items():
700
705
  setattr(material, key, value)
701
- if "loss_tangent" in kwargs:
706
+ if "loss_tangent" in kwargs: # pragma: no cover
702
707
  warnings.warn(
703
708
  "This key is deprecated in versions >0.7.0 and will soon be removed. "
704
709
  "Use key dielectric_loss_tangent instead.",
@@ -761,7 +766,7 @@ class Materials(object):
761
766
  material = self.__add_dielectric_material_model(name, material_model)
762
767
  for key, value in kwargs.items():
763
768
  setattr(material, key, value)
764
- if "loss_tangent" in kwargs:
769
+ if "loss_tangent" in kwargs: # pragma: no cover
765
770
  warnings.warn(
766
771
  "This key is deprecated in versions >0.7.0 and will soon be removed. "
767
772
  "Use key dielectric_loss_tangent instead.",
@@ -837,7 +842,7 @@ class Materials(object):
837
842
 
838
843
  material = self[material_name]
839
844
  attributes_input_dict = {key: val for (key, val) in input_dict.items() if key in ATTRIBUTES + DC_ATTRIBUTES}
840
- if "loss_tangent" in input_dict:
845
+ if "loss_tangent" in input_dict: # pragma: no cover
841
846
  warnings.warn(
842
847
  "This key is deprecated in versions >0.7.0 and will soon be removed. "
843
848
  "Use key dielectric_loss_tangent instead.",
@@ -852,26 +857,6 @@ class Materials(object):
852
857
  @pyedb_function_handler()
853
858
  def load_material(self, material):
854
859
  """Load material."""
855
- if self.materials:
856
- mat_keys = [i.lower() for i in self.materials.keys()]
857
- mat_keys_case = [i for i in self.materials.keys()]
858
- else:
859
- mat_keys = []
860
- mat_keys_case = []
861
-
862
- if not material:
863
- return
864
- if material["name"].lower() not in mat_keys:
865
- if "conductivity" not in material:
866
- self.add_dielectric_material(material["name"], material["permittivity"], material["loss_tangent"])
867
- elif material["conductivity"] > 1e4:
868
- self.add_conductor_material(material["name"], material["conductivity"])
869
- else:
870
- self.add_dielectric_material(material["name"], material["permittivity"], material["loss_tangent"])
871
- self.materials[material["name"]]._load(material)
872
- else:
873
- self.materials[mat_keys_case[mat_keys.index(material["name"].lower())]]._load(material)
874
-
875
860
  if material:
876
861
  material_name = material["name"]
877
862
  material_conductivity = material.get("conductivity", None)
@@ -879,7 +864,7 @@ class Materials(object):
879
864
  self.add_conductor_material(material_name, material_conductivity)
880
865
  else:
881
866
  material_permittivity = material["permittivity"]
882
- if "loss_tangent" in material:
867
+ if "loss_tangent" in material: # pragma: no cover
883
868
  warnings.warn(
884
869
  "This key is deprecated in versions >0.7.0 and will soon be removed. "
885
870
  "Use key dielectric_loss_tangent instead.",
@@ -953,7 +938,7 @@ class Materials(object):
953
938
  if "tangent_delta" in material_properties:
954
939
  material_properties["dielectric_loss_tangent"] = material_properties["tangent_delta"]
955
940
  del material_properties["tangent_delta"]
956
- elif "loss_tangent" in material_properties:
941
+ elif "loss_tangent" in material_properties: # pragma: no cover
957
942
  warnings.warn(
958
943
  "This key is deprecated in versions >0.7.0 and will soon be removed. "
959
944
  "Use key dielectric_loss_tangent instead.",
@@ -966,9 +951,83 @@ class Materials(object):
966
951
  self.__edb.logger.warning(f"Material {material_name} already exist and was not loaded from AMAT file.")
967
952
  return True
968
953
 
969
- @staticmethod
970
954
  @pyedb_function_handler()
971
- def read_materials(amat_file):
955
+ def iterate_materials_in_amat(self, amat_file=None):
956
+ """Iterate over material description in an AMAT file.
957
+
958
+ Parameters
959
+ ----------
960
+ amat_file : str
961
+ Full path to the AMAT file to read.
962
+
963
+ Yields
964
+ ------
965
+ dict
966
+ """
967
+ if amat_file is None:
968
+ amat_file = os.path.join(self.__edb.base_path, "syslib", "Materials.amat")
969
+
970
+ begin_regex = re.compile(r"^\$begin '(.+)'")
971
+ end_regex = re.compile(r"^\$end '(.+)'")
972
+ material_properties = ATTRIBUTES.copy()
973
+ # Remove cases manually handled
974
+ material_properties.remove("conductivity")
975
+
976
+ with open(amat_file, "r") as amat_fh:
977
+ in_material_def = False
978
+ material_description = {}
979
+ for line in amat_fh:
980
+ if in_material_def:
981
+ # Yield material definition
982
+ if end_regex.search(line):
983
+ in_material_def = False
984
+ yield material_description
985
+ material_description = {}
986
+ # Extend material definition if possible
987
+ else:
988
+ for material_property in material_properties:
989
+ if material_property in line:
990
+ value = get_line_float_value(line)
991
+ if value is not None:
992
+ material_description[material_property] = value
993
+ break
994
+ # Extra case to cover bug in syslib AMAT file (see #364)
995
+ if "thermal_expansion_coeffcient" in line:
996
+ value = get_line_float_value(line)
997
+ if value is not None:
998
+ material_description["thermal_expansion_coefficient"] = value
999
+ # Extra case to avoid confusion ("conductivity" is included in "thermal_conductivity")
1000
+ if "conductivity" in line and "thermal_conductivity" not in line:
1001
+ value = get_line_float_value(line)
1002
+ if value is not None:
1003
+ material_description["conductivity"] = value
1004
+ # Extra case to avoid confusion ("conductivity" is included in "thermal_conductivity")
1005
+ if (
1006
+ "loss_tangent" in line
1007
+ and "dielectric_loss_tangent" not in line
1008
+ and "magnetic_loss_tangent" not in line
1009
+ ):
1010
+ warnings.warn(
1011
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
1012
+ "Use key dielectric_loss_tangent instead.",
1013
+ DeprecationWarning,
1014
+ )
1015
+ value = get_line_float_value(line)
1016
+ if value is not None:
1017
+ material_description["dielectric_loss_tangent"] = value
1018
+ # Check if we reach the beginning of a material description
1019
+ else:
1020
+ match = begin_regex.search(line)
1021
+ if match:
1022
+ material_name = match.group(1)
1023
+ # Skip unwanted data
1024
+ if material_name in ("$index$", "$base_index$"):
1025
+ continue
1026
+ material_description["name"] = match.group(1)
1027
+ in_material_def = True
1028
+
1029
+ @pyedb_function_handler()
1030
+ def read_materials(self, amat_file):
972
1031
  """Read materials from an AMAT file.
973
1032
 
974
1033
  Parameters
@@ -981,76 +1040,39 @@ class Materials(object):
981
1040
  dict
982
1041
  {material name: dict of material properties}.
983
1042
  """
1043
+ res = {}
1044
+ for material in self.iterate_materials_in_amat(amat_file):
1045
+ material_name = material["name"]
1046
+ res[material_name] = {}
1047
+ for material_property, value in material.items():
1048
+ if material_property != "name":
1049
+ res[material_name][material_property] = value
984
1050
 
985
- def get_line_float_value(line):
986
- """Retrieve the float value expected in the line of an AMAT file.
987
-
988
- The associated string is expected to follow one of the following cases:
989
- - simple('permittivity', 12.)
990
- - permittivity='12'.
991
- """
992
- try:
993
- return float(re.split(",|=", line)[-1].strip(")'"))
994
- except ValueError:
995
- return None
1051
+ return res
996
1052
 
997
- res = {}
998
- _begin_search = re.compile(r"^\$begin '(.+)'")
999
- _end_search = re.compile(r"^\$end '(.+)'")
1000
- material_properties = [
1001
- "thermal_conductivity",
1002
- "permittivity",
1003
- "dielectric_loss_tangent",
1004
- "permeability",
1005
- "magnetic_loss_tangent",
1006
- "thermal_expansion_coeffcient",
1007
- "specific_heat",
1008
- "mass_density",
1009
- ]
1053
+ @pyedb_function_handler()
1054
+ def read_syslib_material(self, material_name):
1055
+ """Read a specific material from syslib AMAT file.
1010
1056
 
1011
- with open(amat_file, "r") as amat_fh:
1012
- raw_lines = amat_fh.read().splitlines()
1013
- material_name = ""
1014
- for line in raw_lines:
1015
- b = _begin_search.search(line)
1016
- if b: # walk down a level
1017
- material_name = b.group(1)
1018
- res.setdefault(material_name, {})
1019
- if len(res) > 165:
1020
- pass
1021
- if material_name:
1022
- for material_property in material_properties:
1023
- if material_property in line:
1024
- value = get_line_float_value(line)
1025
- if value is not None:
1026
- res[material_name][material_property] = value
1027
- break
1028
- # Extra case to avoid confusion ("conductivity" is included in "thermal_conductivity")
1029
- if "conductivity" in line and "thermal_conductivity" not in line:
1030
- value = get_line_float_value(line)
1031
- if value is not None:
1032
- res[material_name]["conductivity"] = value
1033
- # Extra case to avoid confusion ("conductivity" is included in "thermal_conductivity")
1034
- if (
1035
- "loss_tangent" in line
1036
- and "dielectric_loss_tangent" not in line
1037
- and "magnetic_loss_tangent" not in line
1038
- ):
1039
- warnings.warn(
1040
- "This key is deprecated in versions >0.7.0 and will soon be removed. "
1041
- "Use key dielectric_loss_tangent instead.",
1042
- DeprecationWarning,
1043
- )
1044
- value = get_line_float_value(line)
1045
- if value is not None:
1046
- res[material_name]["dielectric_loss_tangent"] = value
1047
- end = _end_search.search(line)
1048
- if end:
1049
- material_name = ""
1050
-
1051
- # Clean unwanted data
1052
- for key in ("$index$", "$base_index$"):
1053
- if key in res:
1054
- del res[key]
1057
+ Parameters
1058
+ ----------
1059
+ material_name : str
1060
+ Name of the material.
1055
1061
 
1062
+ Returns
1063
+ -------
1064
+ dict
1065
+ {material name: dict of material properties}.
1066
+ """
1067
+ res = {}
1068
+ amat_file = os.path.join(self.__edb.base_path, "syslib", "Materials.amat")
1069
+ for material in self.iterate_materials_in_amat(amat_file):
1070
+ iter_material_name = material["name"]
1071
+ if iter_material_name == material_name:
1072
+ for material_property, value in material.items():
1073
+ if material_property != "name":
1074
+ res[material_property] = value
1075
+ return res
1076
+
1077
+ self.__edb.logger.error(f"Material {material_name} does not exist in syslib AMAT file.")
1056
1078
  return res
@@ -472,7 +472,7 @@ class EdbNets(object):
472
472
  @pyedb_function_handler()
473
473
  def get_plot_data(
474
474
  self,
475
- nets,
475
+ nets=None,
476
476
  layers=None,
477
477
  color_by_net=False,
478
478
  outline=None,
@@ -483,8 +483,8 @@ class EdbNets(object):
483
483
 
484
484
  Parameters
485
485
  ----------
486
- nets : str, list
487
- Name of the net or list of nets to plot. If `None` all nets will be plotted.
486
+ nets : str, list, optional
487
+ Name of the net or list of nets to plot. If `None` (default value) all nets will be plotted.
488
488
  layers : str, list, optional
489
489
  Name of the layers to include in the plot. If `None` all the signal layers will be considered.
490
490
  color_by_net : bool, optional
@@ -0,0 +1,94 @@
1
+ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
2
+ # SPDX-License-Identifier: MIT
3
+ #
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ from pyedb.dotnet.clr_module import Tuple
24
+ from pyedb.dotnet.edb_core.geometry.point_data import PointData
25
+
26
+
27
+ class BBox:
28
+ """Bounding box."""
29
+
30
+ def __init__(self, pedb, edb_object=None, point_1=None, point_2=None):
31
+ self._pedb = pedb
32
+ if edb_object:
33
+ self._edb_object = edb_object
34
+ else:
35
+ point_1 = PointData(self._pedb, x=point_1[0], y=point_1[1])
36
+ point_2 = PointData(self._pedb, x=point_2[0], y=point_2[1])
37
+ self._edb_object = Tuple[self._pedb.edb_api.Geometry.PointData, self._pedb.edb_api.Geometry.PointData](
38
+ point_1._edb_object, point_2._edb_object
39
+ )
40
+
41
+ @property
42
+ def point_1(self):
43
+ return [self._edb_object.Item1.X.ToDouble(), self._edb_object.Item1.Y.ToDouble()]
44
+
45
+ @property
46
+ def point_2(self):
47
+ return [self._edb_object.Item2.X.ToDouble(), self._edb_object.Item2.Y.ToDouble()]
48
+
49
+ @property
50
+ def corner_points(self):
51
+ return [self.point_1, self.point_2]
52
+
53
+
54
+ class ObjBase(object):
55
+ """Manages EDB functionalities for a base object."""
56
+
57
+ def __init__(self, pedb, edb_object):
58
+ self._pedb = pedb
59
+ self._edb_object = edb_object
60
+
61
+ @property
62
+ def is_null(self):
63
+ """Flag indicating if this object is null."""
64
+ return self._edb_object.IsNull()
65
+
66
+ @property
67
+ def type(self):
68
+ """Type of the edb object."""
69
+ try:
70
+ return self._edb_object.GetType()
71
+ except AttributeError: # pragma: no cover
72
+ return None
73
+
74
+ @property
75
+ def name(self):
76
+ """Name of the definition."""
77
+ return self._edb_object.GetName()
78
+
79
+ @name.setter
80
+ def name(self, value):
81
+ self._edb_object.SetName(value)
82
+
83
+ @property
84
+ def bounding_box(self):
85
+ """Bounding box.
86
+
87
+ Returns
88
+ -------
89
+ List[float]
90
+ List of coordinates for the component's bounding box, with the list of
91
+ coordinates in this order: [X lower left corner, Y lower left corner,
92
+ X upper right corner, Y upper right corner].
93
+ """
94
+ return BBox(self._pedb, self._edb_object.GetBBox()).corner_points
@@ -1196,8 +1196,8 @@ class EdbSiwave(object):
1196
1196
 
1197
1197
  Parameters
1198
1198
  ----------
1199
- pins : list[Edb.Primitive.PadstackInstance]
1200
- List of EDB pins, length must be 2, since only 2 pins component are currently supported.
1199
+ pins : list[Edb.Cell.Primitive.PadstackInstance]
1200
+ List of EDB pins.
1201
1201
 
1202
1202
  component_name : str
1203
1203
  Component name.
@@ -1454,3 +1454,34 @@ class EdbSiwave(object):
1454
1454
  p_terminal = self._pedb.get_point_terminal(name, positive_net_name, positive_location, positive_layer)
1455
1455
  n_terminal = self._pedb.get_point_terminal(name + "_ref", negative_net_name, negative_location, negative_layer)
1456
1456
  return self._pedb.create_voltage_probe(p_terminal, n_terminal)
1457
+
1458
+ @property
1459
+ def icepak_use_minimal_comp_defaults(self):
1460
+ """Icepak default setting. If "True", only resistor are active in Icepak simulation.
1461
+ The power dissipation of the resistors are calculated from DC results.
1462
+ """
1463
+ siwave_id = self._pedb.edb_api.ProductId.SIWave
1464
+ cell = self._pedb.active_cell._active_cell
1465
+ _, value = cell.GetProductProperty(siwave_id, 422, "")
1466
+ return bool(value)
1467
+
1468
+ @icepak_use_minimal_comp_defaults.setter
1469
+ def icepak_use_minimal_comp_defaults(self, value):
1470
+ value = "True" if bool(value) else ""
1471
+ siwave_id = self._pedb.edb_api.ProductId.SIWave
1472
+ cell = self._pedb.active_cell._active_cell
1473
+ cell.SetProductProperty(siwave_id, 422, value)
1474
+
1475
+ @property
1476
+ def icepak_component_file(self):
1477
+ """Icepak component file path."""
1478
+ siwave_id = self._pedb.edb_api.ProductId.SIWave
1479
+ cell = self._pedb.active_cell._active_cell
1480
+ _, value = cell.GetProductProperty(siwave_id, 420, "")
1481
+ return value
1482
+
1483
+ @icepak_component_file.setter
1484
+ def icepak_component_file(self, value):
1485
+ siwave_id = self._pedb.edb_api.ProductId.SIWave
1486
+ cell = self._pedb.active_cell._active_cell
1487
+ cell.SetProductProperty(siwave_id, 420, value)