pyedb 0.7.0__py3-none-any.whl → 0.7.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.
- pyedb/__init__.py +1 -1
- pyedb/dotnet/clr_module.py +1 -1
- pyedb/dotnet/edb.py +6 -7
- pyedb/dotnet/edb_core/components.py +11 -11
- pyedb/dotnet/edb_core/configuration.py +199 -24
- pyedb/dotnet/edb_core/definition/component_def.py +9 -0
- pyedb/dotnet/edb_core/definition/package_def.py +27 -0
- pyedb/dotnet/edb_core/edb_data/components_data.py +2 -1
- pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +14 -13
- pyedb/dotnet/edb_core/edb_data/hfss_simulation_setup_data.py +2 -2
- pyedb/dotnet/edb_core/edb_data/layer_data.py +8 -3
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py +6 -5
- pyedb/dotnet/edb_core/edb_data/primitives_data.py +12 -11
- pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +1 -1
- pyedb/dotnet/edb_core/edb_data/sources.py +10 -0
- pyedb/dotnet/edb_core/layout.py +59 -0
- pyedb/dotnet/edb_core/materials.py +637 -541
- pyedb/dotnet/edb_core/padstack.py +57 -6
- pyedb/dotnet/edb_core/siwave.py +9 -2
- pyedb/dotnet/edb_core/stackup.py +108 -94
- pyedb/dotnet/edb_core/utilities/__init__.py +3 -0
- pyedb/dotnet/edb_core/utilities/heatsink.py +69 -0
- pyedb/exceptions.py +6 -0
- pyedb/generic/filesystem.py +7 -3
- pyedb/generic/general_methods.py +4 -0
- pyedb/generic/process.py +4 -1
- pyedb/generic/settings.py +10 -0
- {pyedb-0.7.0.dist-info → pyedb-0.7.1.dist-info}/METADATA +31 -53
- {pyedb-0.7.0.dist-info → pyedb-0.7.1.dist-info}/RECORD +32 -29
- /pyedb/dotnet/edb_core/{edb_data → utilities}/simulation_setup.py +0 -0
- {pyedb-0.7.0.dist-info → pyedb-0.7.1.dist-info}/LICENSE +0 -0
- {pyedb-0.7.0.dist-info → pyedb-0.7.1.dist-info}/WHEEL +0 -0
|
@@ -212,7 +212,7 @@ class EdbPadstacks(object):
|
|
|
212
212
|
|
|
213
213
|
Returns
|
|
214
214
|
-------
|
|
215
|
-
dict[
|
|
215
|
+
dict[int, :class:`dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance`]
|
|
216
216
|
List of padstack instances.
|
|
217
217
|
|
|
218
218
|
"""
|
|
@@ -223,6 +223,24 @@ class EdbPadstacks(object):
|
|
|
223
223
|
padstack_instances[edb_padstack_instance.GetId()] = EDBPadstackInstance(edb_padstack_instance, self._pedb)
|
|
224
224
|
return padstack_instances
|
|
225
225
|
|
|
226
|
+
@property
|
|
227
|
+
def instances_by_name(self):
|
|
228
|
+
"""Dictionary of all padstack instances (vias and pins) by name.
|
|
229
|
+
|
|
230
|
+
Returns
|
|
231
|
+
-------
|
|
232
|
+
dict[str, :class:`dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance`]
|
|
233
|
+
List of padstack instances.
|
|
234
|
+
|
|
235
|
+
"""
|
|
236
|
+
padstack_instances = {}
|
|
237
|
+
for _, edb_padstack_instance in self._pedb.padstacks.instances.items():
|
|
238
|
+
if edb_padstack_instance.aedt_name:
|
|
239
|
+
padstack_instances[edb_padstack_instance.aedt_name] = EDBPadstackInstance(
|
|
240
|
+
edb_padstack_instance, self._pedb
|
|
241
|
+
)
|
|
242
|
+
return padstack_instances
|
|
243
|
+
|
|
226
244
|
@property
|
|
227
245
|
def pins(self):
|
|
228
246
|
"""Dictionary of all pins instances (belonging to component).
|
|
@@ -1332,6 +1350,42 @@ class EdbPadstacks(object):
|
|
|
1332
1350
|
self.definitions[padstack_name].edb_padstack.SetData(new_padstack_def)
|
|
1333
1351
|
return True
|
|
1334
1352
|
|
|
1353
|
+
@pyedb_function_handler()
|
|
1354
|
+
def get_instances(self, name=None, pid=None, definition_name=None, net_name=None):
|
|
1355
|
+
"""Get padstack instances by conditions.
|
|
1356
|
+
|
|
1357
|
+
Parameters
|
|
1358
|
+
----------
|
|
1359
|
+
name : str, optional
|
|
1360
|
+
Name of the padstack.
|
|
1361
|
+
pid : int, optional
|
|
1362
|
+
Id of the padstack.
|
|
1363
|
+
definition_name : str, list, optional
|
|
1364
|
+
Name of the padstack definition.
|
|
1365
|
+
net_name : str, optional
|
|
1366
|
+
The net name to be used for filtering padstack instances.
|
|
1367
|
+
|
|
1368
|
+
Returns
|
|
1369
|
+
-------
|
|
1370
|
+
list
|
|
1371
|
+
List of :class:`dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance`.
|
|
1372
|
+
"""
|
|
1373
|
+
|
|
1374
|
+
instances_by_id = self.instances
|
|
1375
|
+
if pid:
|
|
1376
|
+
return instances_by_id[pid]
|
|
1377
|
+
elif name:
|
|
1378
|
+
return self.instances_by_name[name]
|
|
1379
|
+
else:
|
|
1380
|
+
instances = list(instances_by_id.values())
|
|
1381
|
+
if definition_name:
|
|
1382
|
+
definition_name = definition_name if isinstance(definition_name, list) else [definition_name]
|
|
1383
|
+
instances = [inst for inst in instances if inst.padstack_definition in definition_name]
|
|
1384
|
+
if net_name:
|
|
1385
|
+
net_name = net_name if isinstance(net_name, list) else [net_name]
|
|
1386
|
+
instances = [inst for inst in instances if inst.net_name in net_name]
|
|
1387
|
+
return instances
|
|
1388
|
+
|
|
1335
1389
|
@pyedb_function_handler()
|
|
1336
1390
|
def get_padstack_instance_by_net_name(self, net_name):
|
|
1337
1391
|
"""Get a list of padstack instances by net name.
|
|
@@ -1346,11 +1400,8 @@ class EdbPadstacks(object):
|
|
|
1346
1400
|
list
|
|
1347
1401
|
List of :class:`dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance`.
|
|
1348
1402
|
"""
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
if inst.net_name == net_name:
|
|
1352
|
-
padstack_instances.append(inst)
|
|
1353
|
-
return padstack_instances
|
|
1403
|
+
warnings.warn("Use new property :func:`get_padstack_instance` instead.", DeprecationWarning)
|
|
1404
|
+
return self.get_instances(net_name=net_name)
|
|
1354
1405
|
|
|
1355
1406
|
@pyedb_function_handler()
|
|
1356
1407
|
def get_reference_pins(
|
pyedb/dotnet/edb_core/siwave.py
CHANGED
|
@@ -27,6 +27,7 @@ This module contains these classes: ``CircuitPort``, ``CurrentSource``, ``EdbSiw
|
|
|
27
27
|
import os
|
|
28
28
|
import time
|
|
29
29
|
|
|
30
|
+
from pyedb.dotnet.edb_core.edb_data.padstacks_data import EDBPadstackInstance
|
|
30
31
|
from pyedb.dotnet.edb_core.edb_data.simulation_configuration import (
|
|
31
32
|
SimulationConfiguration,
|
|
32
33
|
SourceType,
|
|
@@ -140,8 +141,14 @@ class EdbSiwave(object):
|
|
|
140
141
|
Name of the source.
|
|
141
142
|
|
|
142
143
|
"""
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
if isinstance(source.positive_node.node_pins, EDBPadstackInstance):
|
|
145
|
+
pos_pin = source.positive_node.node_pins._edb_padstackinstance
|
|
146
|
+
else:
|
|
147
|
+
pos_pin = source.positive_node.node_pins
|
|
148
|
+
if isinstance(source.negative_node.node_pins, EDBPadstackInstance):
|
|
149
|
+
neg_pin = source.negative_node.node_pins._edb_padstackinstance
|
|
150
|
+
else:
|
|
151
|
+
neg_pin = source.negative_node.node_pins
|
|
145
152
|
|
|
146
153
|
res, fromLayer_pos, toLayer_pos = pos_pin.GetLayerRange()
|
|
147
154
|
res, fromLayer_neg, toLayer_neg = neg_pin.GetLayerRange()
|
pyedb/dotnet/edb_core/stackup.py
CHANGED
|
@@ -31,9 +31,10 @@ from collections import OrderedDict
|
|
|
31
31
|
import json
|
|
32
32
|
import logging
|
|
33
33
|
import math
|
|
34
|
-
import re
|
|
35
34
|
import warnings
|
|
36
35
|
|
|
36
|
+
import matplotlib.colors
|
|
37
|
+
|
|
37
38
|
from pyedb.dotnet.edb_core.edb_data.layer_data import (
|
|
38
39
|
LayerEdbClass,
|
|
39
40
|
StackupLayerEdbClass,
|
|
@@ -878,6 +879,7 @@ class Stackup(object):
|
|
|
878
879
|
else:
|
|
879
880
|
return False
|
|
880
881
|
|
|
882
|
+
# TODO: This method might need some refactoring
|
|
881
883
|
@pyedb_function_handler()
|
|
882
884
|
def _import_layer_stackup(self, input_file=None):
|
|
883
885
|
if input_file:
|
|
@@ -886,7 +888,12 @@ class Stackup(object):
|
|
|
886
888
|
for k, v in json_dict.items():
|
|
887
889
|
if k == "materials":
|
|
888
890
|
for material in v.values():
|
|
889
|
-
|
|
891
|
+
material_name = material["name"]
|
|
892
|
+
del material["name"]
|
|
893
|
+
if material_name not in self._pedb.materials:
|
|
894
|
+
self._pedb.materials.add_material(material_name, **material)
|
|
895
|
+
else:
|
|
896
|
+
self._pedb.materials.update_material(material_name, material)
|
|
890
897
|
if k == "layers":
|
|
891
898
|
if len(list(v.values())) == len(list(self.stackup_layers.values())):
|
|
892
899
|
imported_layers_list = [l_dict["name"] for l_dict in list(v.values())]
|
|
@@ -1667,36 +1674,63 @@ class Stackup(object):
|
|
|
1667
1674
|
temp_data = {name: area / outline_area * 100 for name, area in temp_data.items()}
|
|
1668
1675
|
return temp_data
|
|
1669
1676
|
|
|
1677
|
+
# TODO: This method might need some refactoring
|
|
1670
1678
|
@pyedb_function_handler()
|
|
1671
|
-
def _import_dict(self, json_dict):
|
|
1679
|
+
def _import_dict(self, json_dict, rename=False):
|
|
1672
1680
|
"""Import stackup from a dictionary."""
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
self.
|
|
1676
|
-
|
|
1681
|
+
if not "materials" in json_dict:
|
|
1682
|
+
self._logger.warning("Configuration file does not have material definition")
|
|
1683
|
+
self._logger.warning(
|
|
1684
|
+
"Please check your json or xml file, if no material are defined your project will"
|
|
1685
|
+
"likely fail to simulate"
|
|
1686
|
+
)
|
|
1687
|
+
else:
|
|
1688
|
+
mats = json_dict["materials"]
|
|
1689
|
+
for material in mats.values():
|
|
1690
|
+
material_name = material["name"]
|
|
1691
|
+
del material["name"]
|
|
1692
|
+
if material_name not in self._pedb.materials:
|
|
1693
|
+
self._pedb.materials.add_material(material_name, **material)
|
|
1694
|
+
else:
|
|
1695
|
+
self._pedb.materials.update_material(material_name, material)
|
|
1677
1696
|
temp = {i: j for i, j in json_dict["layers"].items() if j["type"] in ["signal", "dielectric"]}
|
|
1697
|
+
config_file_layers = list(temp.keys())
|
|
1698
|
+
layout_layers = list(self.stackup_layers.keys())
|
|
1699
|
+
renamed_layers = {}
|
|
1700
|
+
if rename and len(config_file_layers) == len(layout_layers):
|
|
1701
|
+
for lay_ind in range(len(list(temp.keys()))):
|
|
1702
|
+
if not config_file_layers[lay_ind] == layout_layers[lay_ind]:
|
|
1703
|
+
renamed_layers[layout_layers[lay_ind]] = config_file_layers[lay_ind]
|
|
1678
1704
|
for name in list(self.stackup_layers.keys()):
|
|
1705
|
+
layer = None
|
|
1679
1706
|
if name in temp:
|
|
1680
1707
|
layer = temp[name]
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1708
|
+
elif name in renamed_layers:
|
|
1709
|
+
layer = temp[renamed_layers[name]]
|
|
1710
|
+
self.stackup_layers[name].name = renamed_layers[name]
|
|
1711
|
+
name = renamed_layers[name]
|
|
1712
|
+
else: # Remove layers not in config file.
|
|
1713
|
+
self.remove_layer(name)
|
|
1714
|
+
self._logger.warning(f"Layer {name} were not found in configuration file, removing layer")
|
|
1715
|
+
default_layer = {
|
|
1716
|
+
"name": "default",
|
|
1717
|
+
"type": "signal",
|
|
1718
|
+
"material": "copper",
|
|
1719
|
+
"dielectric_fill": "fr4_epoxy",
|
|
1720
|
+
"thickness": 3.5e-05,
|
|
1721
|
+
"etch_factor": 0.0,
|
|
1722
|
+
"roughness_enabled": False,
|
|
1723
|
+
"top_hallhuray_nodule_radius": 0.0,
|
|
1724
|
+
"top_hallhuray_surface_ratio": 0.0,
|
|
1725
|
+
"bottom_hallhuray_nodule_radius": 0.0,
|
|
1726
|
+
"bottom_hallhuray_surface_ratio": 0.0,
|
|
1727
|
+
"side_hallhuray_nodule_radius": 0.0,
|
|
1728
|
+
"side_hallhuray_surface_ratio": 0.0,
|
|
1729
|
+
"upper_elevation": 0.0,
|
|
1730
|
+
"lower_elevation": 0.0,
|
|
1731
|
+
"color": [242, 140, 102],
|
|
1732
|
+
}
|
|
1733
|
+
if layer:
|
|
1700
1734
|
if "color" in layer:
|
|
1701
1735
|
default_layer["color"] = layer["color"]
|
|
1702
1736
|
elif not layer["type"] == "signal":
|
|
@@ -1704,15 +1738,11 @@ class Stackup(object):
|
|
|
1704
1738
|
|
|
1705
1739
|
for k, v in layer.items():
|
|
1706
1740
|
default_layer[k] = v
|
|
1707
|
-
|
|
1708
1741
|
self.stackup_layers[name]._load_layer(default_layer)
|
|
1709
|
-
|
|
1710
|
-
self.remove_layer(name)
|
|
1711
|
-
|
|
1712
|
-
for layer_name, layer in temp.items():
|
|
1742
|
+
for layer_name, layer in temp.items(): # looping over potential new layers to add
|
|
1713
1743
|
if layer_name in self.stackup_layers:
|
|
1714
1744
|
continue # if layer exist, skip
|
|
1715
|
-
|
|
1745
|
+
# adding layer
|
|
1716
1746
|
default_layer = {
|
|
1717
1747
|
"name": "default",
|
|
1718
1748
|
"type": "signal",
|
|
@@ -1786,12 +1816,12 @@ class Stackup(object):
|
|
|
1786
1816
|
return True
|
|
1787
1817
|
|
|
1788
1818
|
@pyedb_function_handler()
|
|
1789
|
-
def _import_json(self, file_path):
|
|
1819
|
+
def _import_json(self, file_path, rename=False):
|
|
1790
1820
|
"""Import stackup from a json file."""
|
|
1791
1821
|
if file_path:
|
|
1792
1822
|
f = open(file_path)
|
|
1793
1823
|
json_dict = json.load(f) # pragma: no cover
|
|
1794
|
-
return self._import_dict(json_dict)
|
|
1824
|
+
return self._import_dict(json_dict, rename)
|
|
1795
1825
|
|
|
1796
1826
|
@pyedb_function_handler()
|
|
1797
1827
|
def _import_csv(self, file_path):
|
|
@@ -2035,7 +2065,7 @@ class Stackup(object):
|
|
|
2035
2065
|
material["Conductivity"] = val.conductivity
|
|
2036
2066
|
else:
|
|
2037
2067
|
material["Permittivity"] = val.permittivity
|
|
2038
|
-
material["DielectricLossTangent"] = val.
|
|
2068
|
+
material["DielectricLossTangent"] = val.dielectric_loss_tangent
|
|
2039
2069
|
materials[name] = material
|
|
2040
2070
|
|
|
2041
2071
|
return layers, materials, roughness_models, non_stackup_layers
|
|
@@ -2064,11 +2094,11 @@ class Stackup(object):
|
|
|
2064
2094
|
return True
|
|
2065
2095
|
|
|
2066
2096
|
@pyedb_function_handler()
|
|
2067
|
-
def _import_xml(self, file_path):
|
|
2068
|
-
"""Read external xml file and
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2097
|
+
def _import_xml(self, file_path, rename=False):
|
|
2098
|
+
"""Read external xml file and convert into json file.
|
|
2099
|
+
You can use xml file to import layer stackup but using json file is recommended.
|
|
2100
|
+
see :class:`pyedb.dotnet.edb_core.edb_data.simulation_configuration.SimulationConfiguration´ class to
|
|
2101
|
+
generate files`.
|
|
2072
2102
|
|
|
2073
2103
|
Parameters
|
|
2074
2104
|
----------
|
|
@@ -2081,59 +2111,38 @@ class Stackup(object):
|
|
|
2081
2111
|
``True`` when successful, ``False`` when failed.
|
|
2082
2112
|
"""
|
|
2083
2113
|
tree = ET.parse(file_path)
|
|
2084
|
-
material_dict = {}
|
|
2085
2114
|
root = tree.getroot()
|
|
2086
2115
|
stackup = root.find("Stackup")
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
if
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
if name in self.layers:
|
|
2118
|
-
layer = self.layers[name]
|
|
2119
|
-
layer.type = layer_type
|
|
2120
|
-
else:
|
|
2121
|
-
layer = self.add_layer(name, layer_type=layer_type, material="copper", fillMaterial="copper")
|
|
2122
|
-
|
|
2123
|
-
if l.IsStackupLayer():
|
|
2124
|
-
layer.material = l.GetMaterial()
|
|
2125
|
-
layer.thickness = l.GetThicknessValue().ToDouble()
|
|
2126
|
-
layer.dielectric_fill = l.GetFillMaterial()
|
|
2127
|
-
layer.etch_factor = l.GetEtchFactor().ToDouble()
|
|
2128
|
-
|
|
2129
|
-
lc_new = self._pedb.edb_api.Cell.LayerCollection()
|
|
2130
|
-
for name, _ in dumy_layers.items():
|
|
2131
|
-
layer = self.layers[name]
|
|
2132
|
-
lc_new.AddLayerBottom(layer._edb_layer)
|
|
2133
|
-
|
|
2134
|
-
self._pedb.layout.layer_collection = lc_new
|
|
2135
|
-
self.refresh_layer_collection()
|
|
2136
|
-
return True
|
|
2116
|
+
stackup_dict = {}
|
|
2117
|
+
if stackup.find("Materials"):
|
|
2118
|
+
stackup_dict["materials"] = {}
|
|
2119
|
+
for m in stackup.find("Materials").findall("Material"):
|
|
2120
|
+
material = {"name": m.attrib["Name"]}
|
|
2121
|
+
for i in list(m):
|
|
2122
|
+
material[i.tag.lower()] = float(list(i)[0].text)
|
|
2123
|
+
if material:
|
|
2124
|
+
stackup_dict["materials"][material["name"]] = material
|
|
2125
|
+
stackup_section = stackup.find("Layers")
|
|
2126
|
+
if stackup_section:
|
|
2127
|
+
length_unit = stackup_section.attrib["LengthUnit"]
|
|
2128
|
+
stackup_dict["layers"] = {}
|
|
2129
|
+
for l in stackup.find("Layers").findall("Layer"):
|
|
2130
|
+
layer = {"name": l.attrib["Name"]}
|
|
2131
|
+
for k, v in l.attrib.items():
|
|
2132
|
+
if k == "Color":
|
|
2133
|
+
layer[k.lower()] = [int(x * 255) for x in list(matplotlib.colors.to_rgb(v))]
|
|
2134
|
+
elif k == "Thickness":
|
|
2135
|
+
layer[k.lower()] = v + length_unit
|
|
2136
|
+
elif v == "conductor":
|
|
2137
|
+
layer[k.lower()] = "signal"
|
|
2138
|
+
elif k == "FillMaterial":
|
|
2139
|
+
layer["dielectric_fill"] = v
|
|
2140
|
+
else:
|
|
2141
|
+
layer[k.lower()] = v
|
|
2142
|
+
if layer:
|
|
2143
|
+
if layer["type"] == "signal" or layer["type"] == "dielectric":
|
|
2144
|
+
stackup_dict["layers"][layer["name"]] = layer
|
|
2145
|
+
return self._import_dict(stackup_dict, rename=rename)
|
|
2137
2146
|
|
|
2138
2147
|
@pyedb_function_handler()
|
|
2139
2148
|
def _export_xml(self, file_path):
|
|
@@ -2187,7 +2196,7 @@ class Stackup(object):
|
|
|
2187
2196
|
return True
|
|
2188
2197
|
|
|
2189
2198
|
@pyedb_function_handler()
|
|
2190
|
-
def load(self, file_path):
|
|
2199
|
+
def load(self, file_path, rename=False):
|
|
2191
2200
|
"""Import stackup from a file. The file format can be XML, CSV, or JSON.
|
|
2192
2201
|
|
|
2193
2202
|
|
|
@@ -2195,6 +2204,11 @@ class Stackup(object):
|
|
|
2195
2204
|
----------
|
|
2196
2205
|
file_path : str
|
|
2197
2206
|
Path to stackup file.
|
|
2207
|
+
rename : bool
|
|
2208
|
+
If rename is ``False`` then layer in layout not found in the stackup file are deleted.
|
|
2209
|
+
Otherwise, if the number of layer in the stackup file equals the number of stackup layer
|
|
2210
|
+
in the layout, layers are renamed according the the file.
|
|
2211
|
+
Note that layer order matters, and has to be writtent from top to bottom layer in the file.
|
|
2198
2212
|
|
|
2199
2213
|
Returns
|
|
2200
2214
|
-------
|
|
@@ -2213,9 +2227,9 @@ class Stackup(object):
|
|
|
2213
2227
|
elif file_path.endswith(".csv"):
|
|
2214
2228
|
return self._import_csv(file_path)
|
|
2215
2229
|
elif file_path.endswith(".json"):
|
|
2216
|
-
return self._import_json(file_path)
|
|
2230
|
+
return self._import_json(file_path, rename=rename)
|
|
2217
2231
|
elif file_path.endswith(".xml"):
|
|
2218
|
-
return self._import_xml(file_path)
|
|
2232
|
+
return self._import_xml(file_path, rename=rename)
|
|
2219
2233
|
else:
|
|
2220
2234
|
return False
|
|
2221
2235
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
class HeatSink:
|
|
2
|
+
|
|
3
|
+
"""Heatsink model description.
|
|
4
|
+
|
|
5
|
+
Parameters
|
|
6
|
+
----------
|
|
7
|
+
pedb : :class:`pyedb.dotnet.edb.Edb`
|
|
8
|
+
Inherited object.
|
|
9
|
+
edb_object : :class:`Ansys.Ansoft.Edb.Utility.HeatSink`,
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, pedb, edb_object=None):
|
|
13
|
+
self._pedb = pedb
|
|
14
|
+
self._fin_orientation_type = {
|
|
15
|
+
"x_oriented": self._pedb.edb_api.utility.utility.HeatSinkFinOrientation.XOriented,
|
|
16
|
+
"y_oriented": self._pedb.edb_api.utility.utility.HeatSinkFinOrientation.YOriented,
|
|
17
|
+
"other_oriented": self._pedb.edb_api.utility.utility.HeatSinkFinOrientation.OtherOriented,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if edb_object:
|
|
21
|
+
self._edb_object = edb_object
|
|
22
|
+
else:
|
|
23
|
+
self._edb_object = self._pedb.edb_api.utility.utility.HeatSink()
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def fin_base_height(self):
|
|
27
|
+
"""The base elevation of the fins."""
|
|
28
|
+
return self._edb_object.FinBaseHeight.ToDouble()
|
|
29
|
+
|
|
30
|
+
@fin_base_height.setter
|
|
31
|
+
def fin_base_height(self, value):
|
|
32
|
+
self._edb_object.FinBaseHeight = self._pedb.edb_value(value)
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def fin_height(self):
|
|
36
|
+
"""The fin height."""
|
|
37
|
+
return self._edb_object.FinHeight.ToDouble()
|
|
38
|
+
|
|
39
|
+
@fin_height.setter
|
|
40
|
+
def fin_height(self, value):
|
|
41
|
+
self._edb_object.FinHeight = self._pedb.edb_value(value)
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def fin_orientation(self):
|
|
45
|
+
"""The fin orientation."""
|
|
46
|
+
temp = self._edb_object.FinOrientation
|
|
47
|
+
return list(self._fin_orientation_type.keys())[list(self._fin_orientation_type.values()).index(temp)]
|
|
48
|
+
|
|
49
|
+
@fin_orientation.setter
|
|
50
|
+
def fin_orientation(self, value):
|
|
51
|
+
self._edb_object.FinOrientation = self._fin_orientation_type[value]
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def fin_spacing(self):
|
|
55
|
+
"""The fin spacing."""
|
|
56
|
+
return self._edb_object.FinSpacing.ToDouble()
|
|
57
|
+
|
|
58
|
+
@fin_spacing.setter
|
|
59
|
+
def fin_spacing(self, value):
|
|
60
|
+
self._edb_object.FinSpacing = self._pedb.edb_value(value)
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def fin_thickness(self):
|
|
64
|
+
"""The fin thickness."""
|
|
65
|
+
return self._edb_object.FinThickness.ToDouble()
|
|
66
|
+
|
|
67
|
+
@fin_thickness.setter
|
|
68
|
+
def fin_thickness(self, value):
|
|
69
|
+
self._edb_object.FinThickness = self._pedb.edb_value(value)
|
pyedb/exceptions.py
ADDED
pyedb/generic/filesystem.py
CHANGED
|
@@ -108,7 +108,7 @@ class Scratch:
|
|
|
108
108
|
|
|
109
109
|
return dst_file
|
|
110
110
|
|
|
111
|
-
def copyfolder(self, src_folder, destfolder):
|
|
111
|
+
def copyfolder(self, src_folder, destfolder=None):
|
|
112
112
|
"""
|
|
113
113
|
|
|
114
114
|
Parameters
|
|
@@ -124,8 +124,12 @@ class Scratch:
|
|
|
124
124
|
"""
|
|
125
125
|
from distutils.dir_util import copy_tree
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
if destfolder:
|
|
128
|
+
copy_tree(src_folder, destfolder)
|
|
129
|
+
else:
|
|
130
|
+
destfolder = os.path.join(self.path, os.path.split(src_folder)[-1])
|
|
131
|
+
copy_tree(src_folder, destfolder)
|
|
132
|
+
return destfolder
|
|
129
133
|
|
|
130
134
|
def __enter__(self):
|
|
131
135
|
return self
|
pyedb/generic/general_methods.py
CHANGED
|
@@ -44,6 +44,7 @@ import tempfile
|
|
|
44
44
|
import time
|
|
45
45
|
import traceback
|
|
46
46
|
|
|
47
|
+
from pyedb.exceptions import MaterialModelException
|
|
47
48
|
from pyedb.generic.constants import CSS4_COLORS
|
|
48
49
|
from pyedb.generic.settings import settings
|
|
49
50
|
|
|
@@ -179,6 +180,9 @@ def _function_handler_wrapper(user_function): # pragma: no cover
|
|
|
179
180
|
except IOError:
|
|
180
181
|
_exception(sys.exc_info(), user_function, args, kwargs, "IO Error")
|
|
181
182
|
return False
|
|
183
|
+
except MaterialModelException:
|
|
184
|
+
_exception(sys.exc_info(), user_function, args, kwargs, "Material Model")
|
|
185
|
+
return False
|
|
182
186
|
|
|
183
187
|
return wrapper
|
|
184
188
|
|
pyedb/generic/process.py
CHANGED
|
@@ -95,7 +95,10 @@ class SiwaveSolve(object):
|
|
|
95
95
|
command.append(self._project_path)
|
|
96
96
|
command.append(exec_file)
|
|
97
97
|
command.append("-formatOutput -useSubdir")
|
|
98
|
-
|
|
98
|
+
if os.name == "posix":
|
|
99
|
+
p = subprocess.Popen(command)
|
|
100
|
+
else:
|
|
101
|
+
p = subprocess.Popen(" ".join(command))
|
|
99
102
|
p.wait()
|
|
100
103
|
|
|
101
104
|
def export_3d_cad(
|
pyedb/generic/settings.py
CHANGED
|
@@ -52,6 +52,7 @@ class Settings(object):
|
|
|
52
52
|
self._force_error_on_missing_project = False
|
|
53
53
|
self._enable_pandas_output = False
|
|
54
54
|
self.time_tick = time.time()
|
|
55
|
+
self.retry_n_times_time_interval = 0.1
|
|
55
56
|
self._global_log_file_name = "pyedb_{}.log".format(os.path.split(os.path.expanduser("~"))[-1])
|
|
56
57
|
self._enable_global_log_file = True
|
|
57
58
|
self._enable_local_log_file = False
|
|
@@ -240,5 +241,14 @@ class Settings(object):
|
|
|
240
241
|
if os.path.exists(value):
|
|
241
242
|
self._edb_dll_path = value
|
|
242
243
|
|
|
244
|
+
@property
|
|
245
|
+
def retry_n_times_time_interval(self):
|
|
246
|
+
"""Time interval between the retries by the ``_retry_n_times`` method."""
|
|
247
|
+
return self._retry_n_times_time_interval
|
|
248
|
+
|
|
249
|
+
@retry_n_times_time_interval.setter
|
|
250
|
+
def retry_n_times_time_interval(self, value):
|
|
251
|
+
self._retry_n_times_time_interval = float(value)
|
|
252
|
+
|
|
243
253
|
|
|
244
254
|
settings = Settings()
|