pyedb 0.7.1__py3-none-any.whl → 0.8.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 +1 -1
- pyedb/dotnet/edb.py +1 -0
- pyedb/dotnet/edb_core/cell/hierarchy/model.py +1 -1
- pyedb/dotnet/edb_core/components.py +4 -1
- pyedb/dotnet/edb_core/configuration.py +37 -5
- pyedb/dotnet/edb_core/definition/component_def.py +1 -1
- pyedb/dotnet/edb_core/definition/component_model.py +1 -1
- pyedb/dotnet/edb_core/definition/definition_obj.py +1 -1
- pyedb/dotnet/edb_core/definition/definitions.py +8 -2
- pyedb/dotnet/edb_core/definition/package_def.py +34 -15
- pyedb/dotnet/edb_core/dotnet/database.py +5 -4
- pyedb/dotnet/edb_core/edb_data/components_data.py +1 -1
- pyedb/dotnet/edb_core/edb_data/connectable.py +1 -1
- pyedb/dotnet/edb_core/edb_data/layer_data.py +3 -2
- pyedb/dotnet/edb_core/edb_data/primitives_data.py +4 -2
- pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +6 -0
- pyedb/dotnet/edb_core/geometry/__init__.py +0 -0
- pyedb/dotnet/edb_core/{edb_data/obj_base.py → geometry/point_data.py} +12 -26
- pyedb/dotnet/edb_core/geometry/polygon_data.py +77 -0
- pyedb/dotnet/edb_core/materials.py +128 -106
- pyedb/dotnet/edb_core/nets.py +3 -3
- pyedb/dotnet/edb_core/obj_base.py +94 -0
- pyedb/dotnet/edb_core/siwave.py +2 -2
- pyedb/dotnet/edb_core/stackup.py +48 -41
- pyedb/dotnet/sim_setup_data/data/siw_dc_ir_settings.py +46 -0
- pyedb/edb_logger.py +15 -1
- pyedb/generic/settings.py +20 -8
- pyedb/siwave.py +50 -1
- {pyedb-0.7.1.dist-info → pyedb-0.8.0.dist-info}/METADATA +5 -5
- {pyedb-0.7.1.dist-info → pyedb-0.8.0.dist-info}/RECORD +32 -28
- {pyedb-0.7.1.dist-info → pyedb-0.8.0.dist-info}/LICENSE +0 -0
- {pyedb-0.7.1.dist-info → pyedb-0.8.0.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
|
|
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
|
-
|
|
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
|
-
|
|
998
|
-
|
|
999
|
-
|
|
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
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
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
|
pyedb/dotnet/edb_core/nets.py
CHANGED
|
@@ -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
|
pyedb/dotnet/edb_core/siwave.py
CHANGED
|
@@ -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
|
|
1199
|
+
pins : list[Edb.Cell.Primitive.PadstackInstance]
|
|
1200
|
+
List of EDB pins.
|
|
1201
1201
|
|
|
1202
1202
|
component_name : str
|
|
1203
1203
|
Component name.
|
pyedb/dotnet/edb_core/stackup.py
CHANGED
|
@@ -33,8 +33,6 @@ import logging
|
|
|
33
33
|
import math
|
|
34
34
|
import warnings
|
|
35
35
|
|
|
36
|
-
import matplotlib.colors
|
|
37
|
-
|
|
38
36
|
from pyedb.dotnet.edb_core.edb_data.layer_data import (
|
|
39
37
|
LayerEdbClass,
|
|
40
38
|
StackupLayerEdbClass,
|
|
@@ -48,9 +46,15 @@ from pyedb.generic.general_methods import (
|
|
|
48
46
|
)
|
|
49
47
|
from pyedb.misc.aedtlib_personalib_install import write_pretty_xml
|
|
50
48
|
|
|
49
|
+
colors = None
|
|
51
50
|
pd = None
|
|
52
51
|
np = None
|
|
53
52
|
if not is_ironpython:
|
|
53
|
+
try:
|
|
54
|
+
import matplotlib.colors as colors
|
|
55
|
+
except ImportError:
|
|
56
|
+
colors = None
|
|
57
|
+
|
|
54
58
|
try:
|
|
55
59
|
import numpy as np
|
|
56
60
|
except ImportError:
|
|
@@ -200,7 +204,7 @@ class Stackup(object):
|
|
|
200
204
|
inner_layer_thickness="17um",
|
|
201
205
|
outer_layer_thickness="50um",
|
|
202
206
|
dielectric_thickness="100um",
|
|
203
|
-
dielectric_material="
|
|
207
|
+
dielectric_material="FR4_epoxy",
|
|
204
208
|
soldermask=True,
|
|
205
209
|
soldermask_thickness="20um",
|
|
206
210
|
): # pragma: no cover
|
|
@@ -243,7 +247,7 @@ class Stackup(object):
|
|
|
243
247
|
self.add_layer(
|
|
244
248
|
"D" + str(int(layer_count / 2)),
|
|
245
249
|
None,
|
|
246
|
-
material="
|
|
250
|
+
material="FR4_epoxy",
|
|
247
251
|
thickness=dielectric_thickness,
|
|
248
252
|
layer_type="dielectric",
|
|
249
253
|
fillMaterial=dielectric_material,
|
|
@@ -259,7 +263,7 @@ class Stackup(object):
|
|
|
259
263
|
self.add_layer(
|
|
260
264
|
"SMT",
|
|
261
265
|
None,
|
|
262
|
-
material="
|
|
266
|
+
material="SolderMask",
|
|
263
267
|
thickness=soldermask_thickness,
|
|
264
268
|
layer_type="dielectric",
|
|
265
269
|
fillMaterial=dielectric_material,
|
|
@@ -267,14 +271,14 @@ class Stackup(object):
|
|
|
267
271
|
self.add_layer(
|
|
268
272
|
"SMB",
|
|
269
273
|
None,
|
|
270
|
-
material="
|
|
274
|
+
material="SolderMask",
|
|
271
275
|
thickness=soldermask_thickness,
|
|
272
276
|
layer_type="dielectric",
|
|
273
277
|
fillMaterial=dielectric_material,
|
|
274
278
|
method="add_on_bottom",
|
|
275
279
|
)
|
|
276
|
-
self.stackup_layers["TOP"].dielectric_fill = "
|
|
277
|
-
self.stackup_layers["BOT"].dielectric_fill = "
|
|
280
|
+
self.stackup_layers["TOP"].dielectric_fill = "SolderMask"
|
|
281
|
+
self.stackup_layers["BOT"].dielectric_fill = "SolderMask"
|
|
278
282
|
|
|
279
283
|
for layer_num in np.arange(int(layer_count / 2), 1, -1):
|
|
280
284
|
# Generate upper half
|
|
@@ -634,6 +638,7 @@ class Stackup(object):
|
|
|
634
638
|
else:
|
|
635
639
|
return False
|
|
636
640
|
|
|
641
|
+
# TODO: Update optional argument material into material_name and fillMaterial into fill_material_name
|
|
637
642
|
@pyedb_function_handler()
|
|
638
643
|
def add_layer(
|
|
639
644
|
self,
|
|
@@ -642,7 +647,7 @@ class Stackup(object):
|
|
|
642
647
|
method="add_on_top",
|
|
643
648
|
layer_type="signal",
|
|
644
649
|
material="copper",
|
|
645
|
-
fillMaterial="
|
|
650
|
+
fillMaterial="FR4_epoxy",
|
|
646
651
|
thickness="35um",
|
|
647
652
|
etch_factor=None,
|
|
648
653
|
is_negative=False,
|
|
@@ -686,25 +691,25 @@ class Stackup(object):
|
|
|
686
691
|
if layer_name in self.layers:
|
|
687
692
|
logger.error("layer {} exists.".format(layer_name))
|
|
688
693
|
return False
|
|
689
|
-
materials_lower = {m.lower(): m for m in list(self._pedb.materials.materials.keys())}
|
|
690
694
|
if not material:
|
|
691
|
-
if layer_type == "signal"
|
|
692
|
-
material = "copper"
|
|
693
|
-
else:
|
|
694
|
-
material = "fr4_epoxy"
|
|
695
|
+
material = "copper" if layer_type == "signal" else "FR4_epoxy"
|
|
695
696
|
if not fillMaterial:
|
|
696
|
-
fillMaterial = "
|
|
697
|
+
fillMaterial = "FR4_epoxy"
|
|
697
698
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
699
|
+
materials = self._pedb.materials
|
|
700
|
+
if material not in materials:
|
|
701
|
+
logger.warning(
|
|
702
|
+
f"Material '{material}' does not exist in material library. Intempt to create it from syslib."
|
|
703
|
+
)
|
|
704
|
+
material_properties = self._pedb.materials.read_syslib_material(material)
|
|
705
|
+
materials.add_material(material, **material_properties)
|
|
702
706
|
|
|
703
|
-
if layer_type != "dielectric":
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
707
|
+
if layer_type != "dielectric" and fillMaterial not in materials:
|
|
708
|
+
logger.warning(
|
|
709
|
+
f"Material '{fillMaterial}' does not exist in material library. Intempt to create it from syslib."
|
|
710
|
+
)
|
|
711
|
+
material_properties = self._pedb.materials.read_syslib_material(fillMaterial)
|
|
712
|
+
materials.add_material(fillMaterial, **material_properties)
|
|
708
713
|
|
|
709
714
|
if layer_type in ["signal", "dielectric"]:
|
|
710
715
|
new_layer = self._create_stackup_layer(layer_name, thickness, layer_type)
|
|
@@ -1716,7 +1721,7 @@ class Stackup(object):
|
|
|
1716
1721
|
"name": "default",
|
|
1717
1722
|
"type": "signal",
|
|
1718
1723
|
"material": "copper",
|
|
1719
|
-
"dielectric_fill": "
|
|
1724
|
+
"dielectric_fill": "FR4_epoxy",
|
|
1720
1725
|
"thickness": 3.5e-05,
|
|
1721
1726
|
"etch_factor": 0.0,
|
|
1722
1727
|
"roughness_enabled": False,
|
|
@@ -1747,7 +1752,7 @@ class Stackup(object):
|
|
|
1747
1752
|
"name": "default",
|
|
1748
1753
|
"type": "signal",
|
|
1749
1754
|
"material": "copper",
|
|
1750
|
-
"dielectric_fill": "
|
|
1755
|
+
"dielectric_fill": "FR4_epoxy",
|
|
1751
1756
|
"thickness": 3.5e-05,
|
|
1752
1757
|
"etch_factor": 0.0,
|
|
1753
1758
|
"roughness_enabled": False,
|
|
@@ -2072,25 +2077,24 @@ class Stackup(object):
|
|
|
2072
2077
|
|
|
2073
2078
|
@pyedb_function_handler()
|
|
2074
2079
|
def _add_materials_from_dictionary(self, material_dict):
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
self._pedb.materials.add_conductor_material(name, attr["Conductivity"])
|
|
2080
|
+
materials = self.self._pedb.materials.materials
|
|
2081
|
+
for name, material_properties in material_dict.items():
|
|
2082
|
+
if not name in materials:
|
|
2083
|
+
if "Conductivity" in material_properties:
|
|
2084
|
+
materials.add_conductor_material(name, material_properties["Conductivity"])
|
|
2081
2085
|
else:
|
|
2082
|
-
|
|
2086
|
+
materials.add_dielectric_material(
|
|
2083
2087
|
name,
|
|
2084
|
-
|
|
2085
|
-
|
|
2088
|
+
material_properties["Permittivity"],
|
|
2089
|
+
material_properties["DielectricLossTangent"],
|
|
2086
2090
|
)
|
|
2087
2091
|
else:
|
|
2088
|
-
|
|
2089
|
-
if "Conductivity" in
|
|
2090
|
-
|
|
2092
|
+
material = materials[name]
|
|
2093
|
+
if "Conductivity" in material_properties:
|
|
2094
|
+
material.conductivity = material_properties["Conductivity"]
|
|
2091
2095
|
else:
|
|
2092
|
-
|
|
2093
|
-
|
|
2096
|
+
material.permittivity = material_properties["Permittivity"]
|
|
2097
|
+
material.loss_tanget = material_properties["DielectricLossTangent"]
|
|
2094
2098
|
return True
|
|
2095
2099
|
|
|
2096
2100
|
@pyedb_function_handler()
|
|
@@ -2110,6 +2114,9 @@ class Stackup(object):
|
|
|
2110
2114
|
bool
|
|
2111
2115
|
``True`` when successful, ``False`` when failed.
|
|
2112
2116
|
"""
|
|
2117
|
+
if not colors:
|
|
2118
|
+
self._pedb.logger.error("Matplotlib is needed. Please, install it first.")
|
|
2119
|
+
return False
|
|
2113
2120
|
tree = ET.parse(file_path)
|
|
2114
2121
|
root = tree.getroot()
|
|
2115
2122
|
stackup = root.find("Stackup")
|
|
@@ -2130,7 +2137,7 @@ class Stackup(object):
|
|
|
2130
2137
|
layer = {"name": l.attrib["Name"]}
|
|
2131
2138
|
for k, v in l.attrib.items():
|
|
2132
2139
|
if k == "Color":
|
|
2133
|
-
layer[k.lower()] = [int(x * 255) for x in list(
|
|
2140
|
+
layer[k.lower()] = [int(x * 255) for x in list(colors.to_rgb(v))]
|
|
2134
2141
|
elif k == "Thickness":
|
|
2135
2142
|
layer[k.lower()] = v + length_unit
|
|
2136
2143
|
elif v == "conductor":
|