pyedb 0.42.0__py3-none-any.whl → 0.44.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/configuration/cfg_boundaries.py +155 -72
- pyedb/configuration/cfg_components.py +1 -1
- pyedb/configuration/cfg_general.py +34 -16
- pyedb/configuration/cfg_modeler.py +162 -67
- pyedb/configuration/cfg_nets.py +33 -17
- pyedb/configuration/cfg_operations.py +63 -31
- pyedb/configuration/cfg_package_definition.py +113 -52
- pyedb/configuration/cfg_padstacks.py +611 -256
- pyedb/configuration/cfg_pin_groups.py +75 -33
- pyedb/configuration/cfg_ports_sources.py +75 -15
- pyedb/configuration/cfg_s_parameter_models.py +125 -70
- pyedb/configuration/cfg_setup.py +301 -257
- pyedb/configuration/cfg_stackup.py +166 -90
- pyedb/configuration/configuration.py +342 -209
- pyedb/dotnet/database/edb_data/design_options.py +19 -1
- pyedb/dotnet/database/edb_data/padstacks_data.py +16 -6
- pyedb/dotnet/database/geometry/polygon_data.py +4 -2
- pyedb/dotnet/database/padstack.py +6 -2
- pyedb/dotnet/database/sim_setup_data/data/sweep_data.py +63 -10
- pyedb/dotnet/database/utilities/simulation_setup.py +14 -30
- pyedb/dotnet/database/utilities/siwave_simulation_setup.py +30 -0
- pyedb/dotnet/edb.py +75 -105
- pyedb/grpc/database/components.py +1 -1
- pyedb/grpc/database/definition/component_def.py +15 -0
- pyedb/grpc/database/definition/component_pin.py +1 -1
- pyedb/grpc/database/definition/materials.py +27 -0
- pyedb/grpc/database/definition/package_def.py +20 -2
- pyedb/grpc/database/definition/padstack_def.py +5 -2
- pyedb/grpc/database/hierarchy/component.py +4 -2
- pyedb/grpc/database/hierarchy/pingroup.py +12 -8
- pyedb/grpc/database/layers/layer.py +28 -0
- pyedb/grpc/database/layers/stackup_layer.py +281 -40
- pyedb/grpc/database/layout/layout.py +12 -6
- pyedb/grpc/database/modeler.py +8 -8
- pyedb/grpc/database/primitive/bondwire.py +3 -3
- pyedb/grpc/database/primitive/circle.py +1 -1
- pyedb/grpc/database/primitive/padstack_instance.py +13 -3
- pyedb/grpc/database/primitive/path.py +2 -2
- pyedb/grpc/database/primitive/polygon.py +3 -3
- pyedb/grpc/database/primitive/primitive.py +1 -1
- pyedb/grpc/database/primitive/rectangle.py +2 -2
- pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +73 -30
- pyedb/grpc/database/source_excitations.py +7 -7
- pyedb/grpc/database/stackup.py +14 -6
- pyedb/grpc/database/terminal/bundle_terminal.py +3 -3
- pyedb/grpc/database/terminal/edge_terminal.py +2 -2
- pyedb/grpc/database/terminal/padstack_instance_terminal.py +42 -2
- pyedb/grpc/database/terminal/pingroup_terminal.py +35 -2
- pyedb/grpc/database/terminal/point_terminal.py +10 -1
- pyedb/grpc/database/terminal/terminal.py +4 -4
- pyedb/grpc/database/utility/hfss_extent_info.py +14 -10
- pyedb/grpc/edb.py +8 -8
- pyedb/misc/misc.py +13 -0
- {pyedb-0.42.0.dist-info → pyedb-0.44.0.dist-info}/METADATA +1 -1
- {pyedb-0.42.0.dist-info → pyedb-0.44.0.dist-info}/RECORD +58 -58
- {pyedb-0.42.0.dist-info → pyedb-0.44.0.dist-info}/LICENSE +0 -0
- {pyedb-0.42.0.dist-info → pyedb-0.44.0.dist-info}/WHEEL +0 -0
|
@@ -89,8 +89,10 @@ class PolygonData:
|
|
|
89
89
|
def create_from_points(self, points, closed=True):
|
|
90
90
|
list_of_point_data = []
|
|
91
91
|
for pt in points:
|
|
92
|
-
list_of_point_data.append(PointData(self._pedb, x=pt[0], y=pt[1]))
|
|
93
|
-
return self._pedb.edb_api.geometry.api_class.PolygonData(
|
|
92
|
+
list_of_point_data.append(PointData(self._pedb, x=pt[0], y=pt[1])._edb_object)
|
|
93
|
+
return self._pedb.edb_api.geometry.api_class.PolygonData(
|
|
94
|
+
convert_py_list_to_net_list(list_of_point_data), closed
|
|
95
|
+
)
|
|
94
96
|
|
|
95
97
|
def create_from_bounding_box(self, points):
|
|
96
98
|
bbox = BBox(self._pedb, point_1=points[0], point_2=points[1])
|
|
@@ -1153,7 +1153,7 @@ class EdbPadstacks(object):
|
|
|
1153
1153
|
Name of the net. The default is ``""``.
|
|
1154
1154
|
via_name : str, optional
|
|
1155
1155
|
The default is ``""``.
|
|
1156
|
-
rotation : float, optional
|
|
1156
|
+
rotation : float, str, optional
|
|
1157
1157
|
Rotation of the padstack in degrees. The default
|
|
1158
1158
|
is ``0``.
|
|
1159
1159
|
fromlayer :
|
|
@@ -1175,7 +1175,11 @@ class EdbPadstacks(object):
|
|
|
1175
1175
|
padstack = self.definitions[pad].edb_padstack
|
|
1176
1176
|
position = self._edb.geometry.point_data(position[0], position[1])
|
|
1177
1177
|
net = self._pedb.nets.find_or_create_net(net_name)
|
|
1178
|
-
rotation =
|
|
1178
|
+
rotation = (
|
|
1179
|
+
self._get_edb_value(rotation * math.pi / 180)
|
|
1180
|
+
if not isinstance(rotation, str)
|
|
1181
|
+
else self._get_edb_value(rotation)
|
|
1182
|
+
)
|
|
1179
1183
|
sign_layers_values = {i: v for i, v in self._pedb.stackup.signal_layers.items()}
|
|
1180
1184
|
sign_layers = list(sign_layers_values.keys())
|
|
1181
1185
|
if not fromlayer:
|
|
@@ -19,7 +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
|
-
|
|
22
|
+
import re
|
|
23
23
|
import warnings
|
|
24
24
|
|
|
25
25
|
|
|
@@ -524,23 +524,76 @@ class SweepData(object):
|
|
|
524
524
|
|
|
525
525
|
def add(self, sweep_type, start, stop, increment):
|
|
526
526
|
sweep_type = sweep_type.replace(" ", "_")
|
|
527
|
-
start =
|
|
528
|
-
stop =
|
|
529
|
-
|
|
530
|
-
if sweep_type
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
freqs = list(self._edb_object.SetLogFrequencies(start, stop, increment))
|
|
527
|
+
start = f"{self._pedb.edb_value(start).ToDouble() / 1e9}GHz"
|
|
528
|
+
stop = f"{self._pedb.edb_value(stop).ToDouble() / 1e9}GHz"
|
|
529
|
+
|
|
530
|
+
if sweep_type == "linear_scale":
|
|
531
|
+
increment = f"{self._pedb.edb_value(increment).ToDouble() / 1e9}GHz"
|
|
532
|
+
frequencty_string = f"LIN {start} {stop} {increment}"
|
|
534
533
|
else:
|
|
535
|
-
|
|
536
|
-
|
|
534
|
+
increment = int(increment)
|
|
535
|
+
if sweep_type == "log_scale":
|
|
536
|
+
frequencty_string = f"DEC {start} {stop} {increment}"
|
|
537
|
+
elif sweep_type == "linear_count":
|
|
538
|
+
frequencty_string = f"LINC {start} {stop} {increment}"
|
|
539
|
+
else:
|
|
540
|
+
raise ValueError("sweep_type must be either 'linear_count', 'linear_scale' or 'log_scale")
|
|
541
|
+
temp = self.frequency_string
|
|
542
|
+
temp.append(frequencty_string)
|
|
543
|
+
self.frequency_string = temp
|
|
544
|
+
return self.frequencies
|
|
545
|
+
|
|
546
|
+
@property
|
|
547
|
+
def frequency_string(self):
|
|
548
|
+
"""A string describing the frequency sweep. Below is an example.
|
|
549
|
+
['LIN 0GHz 20GHz 0.05GHz', 'LINC 20GHz 30GHz 10', 'DEC 40GHz 50GHz 10']
|
|
550
|
+
"""
|
|
551
|
+
pattern = r"(?:LIN[C]?|DEC) [^ ]+ [^ ]+ [^ ]+"
|
|
552
|
+
grouped = re.findall(pattern, self._edb_object.FrequencyString)
|
|
553
|
+
return grouped
|
|
554
|
+
|
|
555
|
+
@frequency_string.setter
|
|
556
|
+
def frequency_string(self, value):
|
|
557
|
+
value = value if isinstance(value, list) else [value]
|
|
558
|
+
temp = []
|
|
559
|
+
for i in value:
|
|
560
|
+
sweep_type, start, stop, increment = i.split(" ")
|
|
561
|
+
start = start.replace("k", "K").replace("h", "H").replace("Z", "z").replace("g", "G")
|
|
562
|
+
stop = stop.replace("k", "K").replace("h", "H").replace("Z", "z").replace("g", "G")
|
|
563
|
+
temp.append(" ".join([sweep_type, start, stop, increment]))
|
|
564
|
+
value = temp
|
|
565
|
+
self._edb_object.FrequencyString = " ".join(value)
|
|
566
|
+
|
|
567
|
+
frequencies = []
|
|
568
|
+
for i in value:
|
|
569
|
+
sweep_type, start, stop, increment = i.split(" ")
|
|
570
|
+
if sweep_type == "LIN":
|
|
571
|
+
frequencies.extend(self._edb_object.SetFrequencies(start, stop, increment))
|
|
572
|
+
else:
|
|
573
|
+
increment = int(increment)
|
|
574
|
+
if sweep_type == "DEC":
|
|
575
|
+
frequencies.extend(self._edb_object.SetLogFrequencies(start, stop, increment))
|
|
576
|
+
elif sweep_type == "LINC":
|
|
577
|
+
frequencies.extend(self._edb_object.SetFrequencies(start, stop, increment))
|
|
578
|
+
|
|
579
|
+
self.clear()
|
|
580
|
+
self.add_frequencies(frequencies)
|
|
537
581
|
|
|
538
582
|
def add_frequencies(self, frequencies):
|
|
539
583
|
if not isinstance(frequencies, list):
|
|
540
584
|
frequencies = [frequencies]
|
|
585
|
+
|
|
586
|
+
temp = []
|
|
587
|
+
for i in frequencies:
|
|
588
|
+
i = self._pedb.edb_value(i).ToDouble()
|
|
589
|
+
if i not in temp and i not in self.frequencies:
|
|
590
|
+
temp.append(i)
|
|
591
|
+
frequencies = temp
|
|
592
|
+
|
|
541
593
|
for i in frequencies:
|
|
542
594
|
i = self._pedb.edb_value(i).ToString()
|
|
543
595
|
self._edb_object.Frequencies.Add(i)
|
|
596
|
+
self._update_sweep()
|
|
544
597
|
return list(self._edb_object.Frequencies)
|
|
545
598
|
|
|
546
599
|
def clear(self):
|
|
@@ -96,8 +96,6 @@ class SimulationSetup(object):
|
|
|
96
96
|
if self._edb_object:
|
|
97
97
|
self._name = self._edb_object.GetName()
|
|
98
98
|
|
|
99
|
-
self._sweep_list = {}
|
|
100
|
-
|
|
101
99
|
@property
|
|
102
100
|
def sim_setup_info(self):
|
|
103
101
|
return SimSetupInfo(self._pedb, sim_setup=self, edb_object=self._edb_object.GetSimSetupInfo())
|
|
@@ -239,7 +237,7 @@ class SimulationSetup(object):
|
|
|
239
237
|
"""List of frequency sweeps."""
|
|
240
238
|
return {i.name: i for i in self.sim_setup_info.sweep_data_list}
|
|
241
239
|
|
|
242
|
-
def add_sweep(self, name, frequency_set: list = None, sweep_type: str = "interpolation", **kwargs):
|
|
240
|
+
def add_sweep(self, name: str = None, frequency_set: list = None, sweep_type: str = "interpolation", **kwargs):
|
|
243
241
|
"""Add frequency sweep.
|
|
244
242
|
|
|
245
243
|
Parameters
|
|
@@ -268,22 +266,16 @@ class SimulationSetup(object):
|
|
|
268
266
|
setattr(sweep_data, k, v)
|
|
269
267
|
sweep_data.type = sweep_type
|
|
270
268
|
|
|
271
|
-
if frequency_set
|
|
269
|
+
if frequency_set in [None, []]:
|
|
272
270
|
sweep_type = "linear_scale"
|
|
273
271
|
start, stop, increment = "50MHz", "5GHz", "50MHz"
|
|
272
|
+
frequency_set = [[sweep_type, start, stop, increment]]
|
|
273
|
+
elif not isinstance(frequency_set[0], list):
|
|
274
|
+
frequency_set = [frequency_set]
|
|
275
|
+
|
|
276
|
+
for fs in frequency_set:
|
|
277
|
+
sweep_type, start, stop, increment = fs
|
|
274
278
|
sweep_data.add(sweep_type, start, stop, increment)
|
|
275
|
-
elif len(frequency_set) == 0:
|
|
276
|
-
pass
|
|
277
|
-
else:
|
|
278
|
-
if not isinstance(frequency_set[0], list):
|
|
279
|
-
frequency_set = [frequency_set]
|
|
280
|
-
for fs in frequency_set:
|
|
281
|
-
sweep_data.add(*fs)
|
|
282
|
-
|
|
283
|
-
ss_info = self.sim_setup_info
|
|
284
|
-
ss_info.add_sweep_data(sweep_data)
|
|
285
|
-
self.set_sim_setup_info(ss_info)
|
|
286
|
-
self._update_setup()
|
|
287
279
|
return sweep_data
|
|
288
280
|
|
|
289
281
|
def delete(self):
|
|
@@ -298,15 +290,7 @@ class SimulationSetup(object):
|
|
|
298
290
|
sweep_data: SweepData
|
|
299
291
|
"""
|
|
300
292
|
warnings.warn("Use new property :func:`add_sweep_data` instead.", DeprecationWarning)
|
|
301
|
-
self.
|
|
302
|
-
edb_setup_info = self.sim_setup_info
|
|
303
|
-
|
|
304
|
-
if self._setup_type in ["kSIwave", "kHFSS", "kRaptorX", "kHFSSPI"]:
|
|
305
|
-
for _, v in self._sweep_list.items():
|
|
306
|
-
edb_setup_info.SweepDataList.Add(v._edb_object)
|
|
307
|
-
|
|
308
|
-
self._edb_object = self._set_edb_setup_info(edb_setup_info)
|
|
309
|
-
self._update_setup()
|
|
293
|
+
return self.sim_setup_info.add_sweep_data(sweep_data)
|
|
310
294
|
|
|
311
295
|
def delete_frequency_sweep(self, sweep_data):
|
|
312
296
|
"""Delete a frequency sweep.
|
|
@@ -316,17 +300,17 @@ class SimulationSetup(object):
|
|
|
316
300
|
sweep_data : EdbFrequencySweep.
|
|
317
301
|
"""
|
|
318
302
|
name = sweep_data.name
|
|
319
|
-
if name in self.
|
|
320
|
-
self.
|
|
303
|
+
if name in self.sweeps:
|
|
304
|
+
self.sweeps.pop(name)
|
|
321
305
|
|
|
322
306
|
fsweep = []
|
|
323
|
-
if self.
|
|
324
|
-
fsweep = [val for key, val in self.
|
|
307
|
+
if self.sweeps:
|
|
308
|
+
fsweep = [val for key, val in self.sweeps.items() if not key == name]
|
|
325
309
|
self.sim_setup_info._edb_object.SweepDataList.Clear()
|
|
326
310
|
for i in fsweep:
|
|
327
311
|
self.sim_setup_info._edb_object.SweepDataList.Add(i._edb_object)
|
|
328
312
|
self._update_setup()
|
|
329
|
-
return
|
|
313
|
+
return False if name in self.sweeps else True
|
|
330
314
|
|
|
331
315
|
def add_frequency_sweep(self, name=None, frequency_sweep=None):
|
|
332
316
|
"""Add frequency sweep.
|
|
@@ -95,6 +95,8 @@ class SiwaveSimulationSetup(SimulationSetup):
|
|
|
95
95
|
self._edb_object = self._simulation_setup_builder(sim_setup_info._edb_object)
|
|
96
96
|
self._update_setup()
|
|
97
97
|
|
|
98
|
+
self._siwave_sweeps_list = []
|
|
99
|
+
|
|
98
100
|
def create(self, name=None):
|
|
99
101
|
"""Create a SIwave SYZ setup.
|
|
100
102
|
|
|
@@ -248,6 +250,34 @@ class SiwaveSimulationSetup(SimulationSetup):
|
|
|
248
250
|
self._edb_object = self._set_edb_setup_info(edb_setup_info)
|
|
249
251
|
self._update_setup()
|
|
250
252
|
|
|
253
|
+
def add_sweep(self, name: str = None, frequency_set: list = None, sweep_type: str = "interpolation", **kwargs):
|
|
254
|
+
"""Add frequency sweep.
|
|
255
|
+
|
|
256
|
+
Parameters
|
|
257
|
+
----------
|
|
258
|
+
name : str, optional
|
|
259
|
+
Name of the frequency sweep. The default is ``None``.
|
|
260
|
+
frequency_set : list, optional
|
|
261
|
+
List of frequency points. The default is ``None``.
|
|
262
|
+
sweep_type : str, optional
|
|
263
|
+
Sweep type. The default is ``"interpolation"``. Options are ``"discrete"``,"discrete"``.
|
|
264
|
+
Returns
|
|
265
|
+
-------
|
|
266
|
+
|
|
267
|
+
Examples
|
|
268
|
+
--------
|
|
269
|
+
>>> setup1 = edbapp.create_siwave_syz_setup("setup1")
|
|
270
|
+
>>> setup1.add_sweep(name="sw1", frequency_set=["linear count", "1MHz", "100MHz", 10])
|
|
271
|
+
"""
|
|
272
|
+
sweep_data = SimulationSetup.add_sweep(self, name, frequency_set, sweep_type, **kwargs)
|
|
273
|
+
self._siwave_sweeps_list.append(sweep_data)
|
|
274
|
+
return sweep_data
|
|
275
|
+
|
|
276
|
+
@property
|
|
277
|
+
def sweeps(self):
|
|
278
|
+
"""List of frequency sweeps."""
|
|
279
|
+
return {i.name: i for i in self._siwave_sweeps_list}
|
|
280
|
+
|
|
251
281
|
|
|
252
282
|
class SiwaveDCSimulationSetup(SimulationSetup):
|
|
253
283
|
"""Manages EDB methods for SIwave DC simulation setup."""
|
pyedb/dotnet/edb.py
CHANGED
|
@@ -32,7 +32,6 @@ import re
|
|
|
32
32
|
import shutil
|
|
33
33
|
import subprocess
|
|
34
34
|
import sys
|
|
35
|
-
import tempfile
|
|
36
35
|
import time
|
|
37
36
|
import traceback
|
|
38
37
|
from typing import Union
|
|
@@ -48,10 +47,7 @@ from pyedb.dotnet.database.cell.terminal.terminal import Terminal
|
|
|
48
47
|
from pyedb.dotnet.database.components import Components
|
|
49
48
|
import pyedb.dotnet.database.dotnet.database
|
|
50
49
|
from pyedb.dotnet.database.dotnet.database import Database
|
|
51
|
-
from pyedb.dotnet.database.edb_data.control_file import
|
|
52
|
-
ControlFile,
|
|
53
|
-
convert_technology_file,
|
|
54
|
-
)
|
|
50
|
+
from pyedb.dotnet.database.edb_data.control_file import convert_technology_file
|
|
55
51
|
from pyedb.dotnet.database.edb_data.design_options import EdbDesignOptions
|
|
56
52
|
from pyedb.dotnet.database.edb_data.edbvalue import EdbValue
|
|
57
53
|
from pyedb.dotnet.database.edb_data.ports import (
|
|
@@ -243,7 +239,7 @@ class Edb(Database):
|
|
|
243
239
|
else:
|
|
244
240
|
control_file = convert_technology_file(technology_file, edbversion=edbversion)
|
|
245
241
|
self.logger.info("Translating ODB++ to EDB...")
|
|
246
|
-
self.
|
|
242
|
+
self.import_layout_file(edbpath[:-4], working_dir, use_ppe=use_ppe, control_file=control_file)
|
|
247
243
|
if settings.enable_local_log_file and self.log_name:
|
|
248
244
|
self._logger.add_file_logger(self.log_name, "Edb")
|
|
249
245
|
self.logger.info("EDB %s was created correctly from %s file.", self.edbpath, edbpath)
|
|
@@ -256,7 +252,7 @@ class Edb(Database):
|
|
|
256
252
|
control_file = technology_file
|
|
257
253
|
else:
|
|
258
254
|
control_file = convert_technology_file(technology_file, edbversion=edbversion)
|
|
259
|
-
self.
|
|
255
|
+
self.import_layout_file(edbpath, working_dir, use_ppe=use_ppe, control_file=control_file)
|
|
260
256
|
if settings.enable_local_log_file and self.log_name:
|
|
261
257
|
self._logger.add_file_logger(self.log_name, "Edb")
|
|
262
258
|
self.logger.info("EDB %s was created correctly from %s file.", self.edbpath, edbpath[-2:])
|
|
@@ -610,9 +606,15 @@ class Edb(Database):
|
|
|
610
606
|
anstranslator_full_path="",
|
|
611
607
|
use_ppe=False,
|
|
612
608
|
control_file=None,
|
|
609
|
+
map_file=None,
|
|
610
|
+
tech_file=None,
|
|
611
|
+
layer_filter=None,
|
|
613
612
|
):
|
|
614
613
|
"""Import a board file and generate an ``edb.def`` file in the working directory.
|
|
615
614
|
|
|
615
|
+
.. deprecated:: 0.42.0
|
|
616
|
+
Use :func:`import_layout_file` method instead.
|
|
617
|
+
|
|
616
618
|
This function supports all AEDT formats, including DXF, GDS, SML (IPC2581), BRD, MCM, SIP, ZIP and TGZ.
|
|
617
619
|
|
|
618
620
|
Parameters
|
|
@@ -630,6 +632,65 @@ class Edb(Database):
|
|
|
630
632
|
Path to the XML file. The default is ``None``, in which case an attempt is made to find
|
|
631
633
|
the XML file in the same directory as the board file. To succeed, the XML file and board file
|
|
632
634
|
must have the same name. Only the extension differs.
|
|
635
|
+
tech_file : str, optional
|
|
636
|
+
Technology file. The file can be *.ircx, *.vlc.tech, or *.itf
|
|
637
|
+
map_file : str, optional
|
|
638
|
+
Layer map .map file.
|
|
639
|
+
layer_filter:str,optional
|
|
640
|
+
Layer filter .txt file.
|
|
641
|
+
|
|
642
|
+
Returns
|
|
643
|
+
-------
|
|
644
|
+
Full path to the AEDB file : str
|
|
645
|
+
"""
|
|
646
|
+
self.logger.warning("import_layout_pcb method is deprecated, use import_layout_file instead.")
|
|
647
|
+
return self.import_layout_file(
|
|
648
|
+
input_file,
|
|
649
|
+
working_dir,
|
|
650
|
+
anstranslator_full_path,
|
|
651
|
+
use_ppe,
|
|
652
|
+
control_file,
|
|
653
|
+
map_file,
|
|
654
|
+
tech_file,
|
|
655
|
+
layer_filter,
|
|
656
|
+
)
|
|
657
|
+
|
|
658
|
+
def import_layout_file(
|
|
659
|
+
self,
|
|
660
|
+
input_file,
|
|
661
|
+
working_dir="",
|
|
662
|
+
anstranslator_full_path="",
|
|
663
|
+
use_ppe=False,
|
|
664
|
+
control_file=None,
|
|
665
|
+
map_file=None,
|
|
666
|
+
tech_file=None,
|
|
667
|
+
layer_filter=None,
|
|
668
|
+
):
|
|
669
|
+
"""Import a board file and generate an ``edb.def`` file in the working directory.
|
|
670
|
+
|
|
671
|
+
This function supports all AEDT formats, including DXF, GDS, SML (IPC2581), BRD, MCM, SIP, ZIP and TGZ.
|
|
672
|
+
|
|
673
|
+
Parameters
|
|
674
|
+
----------
|
|
675
|
+
input_file : str
|
|
676
|
+
Full path to the board file.
|
|
677
|
+
working_dir : str, optional
|
|
678
|
+
Directory in which to create the ``aedb`` folder. The name given to the AEDB file
|
|
679
|
+
is the same as the name of the board file.
|
|
680
|
+
anstranslator_full_path : str, optional
|
|
681
|
+
Full path to the Ansys translator. The default is ``""``.
|
|
682
|
+
use_ppe : bool
|
|
683
|
+
Whether to use the PPE License. The default is ``False``.
|
|
684
|
+
control_file : str, optional
|
|
685
|
+
Path to the XML file. The default is ``None``, in which case an attempt is made to find
|
|
686
|
+
the XML file in the same directory as the board file. To succeed, the XML file and board file
|
|
687
|
+
must have the same name. Only the extension differs.
|
|
688
|
+
tech_file : str, optional
|
|
689
|
+
Technology file. The file can be *.ircx, *.vlc.tech, or *.itf
|
|
690
|
+
map_file : str, optional
|
|
691
|
+
Layer map .map file.
|
|
692
|
+
layer_filter:str,optional
|
|
693
|
+
Layer filter .txt file.
|
|
633
694
|
|
|
634
695
|
Returns
|
|
635
696
|
-------
|
|
@@ -666,6 +727,12 @@ class Edb(Database):
|
|
|
666
727
|
cmd_translator.append("-c={}".format(control_file))
|
|
667
728
|
else:
|
|
668
729
|
cmd_translator.append('-c="{}"'.format(control_file))
|
|
730
|
+
if map_file:
|
|
731
|
+
cmd_translator.append('-g="{}"'.format(map_file))
|
|
732
|
+
if tech_file:
|
|
733
|
+
cmd_translator.append('-t="{}"'.format(tech_file))
|
|
734
|
+
if layer_filter:
|
|
735
|
+
cmd_translator.append('-f="{}"'.format(layer_filter))
|
|
669
736
|
p = subprocess.Popen(cmd_translator)
|
|
670
737
|
p.wait()
|
|
671
738
|
if not os.path.exists(os.path.join(working_dir, aedb_name)):
|
|
@@ -1466,7 +1533,7 @@ class Edb(Database):
|
|
|
1466
1533
|
``True`` when successful, ``False`` when failed.
|
|
1467
1534
|
|
|
1468
1535
|
"""
|
|
1469
|
-
if self.
|
|
1536
|
+
if self.import_layout_file(
|
|
1470
1537
|
inputBrd,
|
|
1471
1538
|
working_dir=WorkDir,
|
|
1472
1539
|
anstranslator_full_path=anstranslator_full_path,
|
|
@@ -1476,103 +1543,6 @@ class Edb(Database):
|
|
|
1476
1543
|
else:
|
|
1477
1544
|
return False
|
|
1478
1545
|
|
|
1479
|
-
def import_gds_file(
|
|
1480
|
-
self,
|
|
1481
|
-
inputGDS,
|
|
1482
|
-
anstranslator_full_path="",
|
|
1483
|
-
use_ppe=False,
|
|
1484
|
-
control_file=None,
|
|
1485
|
-
tech_file=None,
|
|
1486
|
-
map_file=None,
|
|
1487
|
-
layer_filter=None,
|
|
1488
|
-
):
|
|
1489
|
-
"""Import a GDS file and generate an ``edb.def`` file in the working directory.
|
|
1490
|
-
|
|
1491
|
-
..note::
|
|
1492
|
-
`ANSYSLMD_LICENSE_FILE` is needed to run the translator.
|
|
1493
|
-
|
|
1494
|
-
Parameters
|
|
1495
|
-
----------
|
|
1496
|
-
inputGDS : str
|
|
1497
|
-
Full path to the GDS file.
|
|
1498
|
-
anstranslator_full_path : str, optional
|
|
1499
|
-
Full path to the Ansys translator.
|
|
1500
|
-
use_ppe : bool, optional
|
|
1501
|
-
Whether to use the PPE License. The default is ``False``.
|
|
1502
|
-
control_file : str, optional
|
|
1503
|
-
Path to the XML file. The default is ``None``, in which case an attempt is made to find
|
|
1504
|
-
the XML file in the same directory as the GDS file. To succeed, the XML file and GDS file must
|
|
1505
|
-
have the same name. Only the extension differs.
|
|
1506
|
-
tech_file : str, optional
|
|
1507
|
-
Technology file. For versions<2024.1 it uses Helic to convert tech file to xml and then imports
|
|
1508
|
-
the gds. Works on Linux only.
|
|
1509
|
-
For versions>=2024.1 it can directly parse through supported foundry tech files.
|
|
1510
|
-
map_file : str, optional
|
|
1511
|
-
Layer map file.
|
|
1512
|
-
layer_filter:str,optional
|
|
1513
|
-
Layer filter file.
|
|
1514
|
-
|
|
1515
|
-
"""
|
|
1516
|
-
control_file_temp = os.path.join(tempfile.gettempdir(), os.path.split(inputGDS)[-1][:-3] + "xml")
|
|
1517
|
-
if float(self.edbversion) < 2024.1:
|
|
1518
|
-
if not is_linux and tech_file:
|
|
1519
|
-
self.logger.error("Technology files are supported only in Linux. Use control file instead.")
|
|
1520
|
-
return False
|
|
1521
|
-
|
|
1522
|
-
ControlFile(xml_input=control_file, tecnhology=tech_file, layer_map=map_file).write_xml(control_file_temp)
|
|
1523
|
-
if self.import_layout_pcb(
|
|
1524
|
-
inputGDS,
|
|
1525
|
-
anstranslator_full_path=anstranslator_full_path,
|
|
1526
|
-
use_ppe=use_ppe,
|
|
1527
|
-
control_file=control_file_temp,
|
|
1528
|
-
):
|
|
1529
|
-
return True
|
|
1530
|
-
else:
|
|
1531
|
-
return False
|
|
1532
|
-
else:
|
|
1533
|
-
if anstranslator_full_path and os.path.exists(anstranslator_full_path):
|
|
1534
|
-
path = anstranslator_full_path
|
|
1535
|
-
else:
|
|
1536
|
-
path = os.path.join(self.base_path, "anstranslator")
|
|
1537
|
-
if is_windows:
|
|
1538
|
-
path += ".exe"
|
|
1539
|
-
|
|
1540
|
-
temp_map_file = os.path.splitext(inputGDS)[0] + ".map"
|
|
1541
|
-
temp_layermap_file = os.path.splitext(inputGDS)[0] + ".layermap"
|
|
1542
|
-
|
|
1543
|
-
if map_file is None:
|
|
1544
|
-
if os.path.isfile(temp_map_file):
|
|
1545
|
-
map_file = temp_map_file
|
|
1546
|
-
elif os.path.isfile(temp_layermap_file):
|
|
1547
|
-
map_file = temp_layermap_file
|
|
1548
|
-
else:
|
|
1549
|
-
self.logger.error("Unable to define map file.")
|
|
1550
|
-
|
|
1551
|
-
if tech_file is None:
|
|
1552
|
-
if control_file is None:
|
|
1553
|
-
temp_control_file = os.path.splitext(inputGDS)[0] + ".xml"
|
|
1554
|
-
if os.path.isfile(temp_control_file):
|
|
1555
|
-
control_file = temp_control_file
|
|
1556
|
-
else:
|
|
1557
|
-
self.logger.error("Unable to define control file.")
|
|
1558
|
-
|
|
1559
|
-
command = [path, inputGDS, f'-g="{map_file}"', f'-c="{control_file}"']
|
|
1560
|
-
else:
|
|
1561
|
-
command = [
|
|
1562
|
-
path,
|
|
1563
|
-
inputGDS,
|
|
1564
|
-
f'-o="{control_file_temp}"' f'-t="{tech_file}"',
|
|
1565
|
-
f'-g="{map_file}"',
|
|
1566
|
-
f'-f="{layer_filter}"',
|
|
1567
|
-
]
|
|
1568
|
-
|
|
1569
|
-
result = subprocess.run(command, capture_output=True, text=True, shell=True)
|
|
1570
|
-
print(result.stdout)
|
|
1571
|
-
print(command)
|
|
1572
|
-
temp_inputGDS = inputGDS.split(".gds")[0]
|
|
1573
|
-
self.edbpath = temp_inputGDS + ".aedb"
|
|
1574
|
-
return self.open_edb()
|
|
1575
|
-
|
|
1576
1546
|
def _create_extent(
|
|
1577
1547
|
self,
|
|
1578
1548
|
net_signals,
|
|
@@ -2280,7 +2280,7 @@ class Components(object):
|
|
|
2280
2280
|
if not pin.net.is_null:
|
|
2281
2281
|
if pin.net.name:
|
|
2282
2282
|
pingroup.net = pin.net
|
|
2283
|
-
return group_name
|
|
2283
|
+
return group_name, PinGroup(self._pedb, pingroup)
|
|
2284
2284
|
return False
|
|
2285
2285
|
|
|
2286
2286
|
def create_pin_group_on_net(self, reference_designator, net_name, group_name=None):
|
|
@@ -216,3 +216,18 @@ class ComponentDef(GrpcComponentDef):
|
|
|
216
216
|
n_port_model.reference_file = fpath
|
|
217
217
|
self.add_component_model(n_port_model)
|
|
218
218
|
return n_port_model
|
|
219
|
+
|
|
220
|
+
def get_properties(self):
|
|
221
|
+
data = {}
|
|
222
|
+
temp = []
|
|
223
|
+
for i in self.component_pins:
|
|
224
|
+
temp.append(i.name)
|
|
225
|
+
data["pin_order"] = temp
|
|
226
|
+
return data
|
|
227
|
+
|
|
228
|
+
def set_properties(self, **kwargs):
|
|
229
|
+
pin_order = kwargs.get("pin_order")
|
|
230
|
+
if pin_order:
|
|
231
|
+
old = {i.name: i for i in self.component_pins}
|
|
232
|
+
temp = [old[str(i)] for i in pin_order]
|
|
233
|
+
self.component_pins = temp
|
|
@@ -28,5 +28,5 @@ class ComponentPin(GrpcComponentPin):
|
|
|
28
28
|
"""Class managing :class:`ComponentPin <ansys.edb.core.definition.component_pin.ComponentPin>`."""
|
|
29
29
|
|
|
30
30
|
def __init__(self, pedb, edb_object):
|
|
31
|
-
super().__init__(edb_object)
|
|
31
|
+
super().__init__(edb_object.msg)
|
|
32
32
|
self._pedb = pedb
|
|
@@ -587,6 +587,33 @@ class Material(GrpcMaterialDef):
|
|
|
587
587
|
class Materials(object):
|
|
588
588
|
"""Manages EDB methods for material management accessible from `Edb.materials` property."""
|
|
589
589
|
|
|
590
|
+
default_conductor_property_values = {
|
|
591
|
+
"conductivity": 58000000,
|
|
592
|
+
"dielectric_loss_tangent": 0,
|
|
593
|
+
"magnetic_loss_tangent": 0,
|
|
594
|
+
"mass_density": 8933,
|
|
595
|
+
"permittivity": 1,
|
|
596
|
+
"permeability": 0.999991,
|
|
597
|
+
"poisson_ratio": 0.38,
|
|
598
|
+
"specific_heat": 385,
|
|
599
|
+
"thermal_conductivity": 400,
|
|
600
|
+
"youngs_modulus": 120000000000,
|
|
601
|
+
"thermal_expansion_coefficient": 1.77e-05,
|
|
602
|
+
}
|
|
603
|
+
default_dielectric_property_values = {
|
|
604
|
+
"conductivity": 0,
|
|
605
|
+
"dielectric_loss_tangent": 0.02,
|
|
606
|
+
"magnetic_loss_tangent": 0,
|
|
607
|
+
"mass_density": 1900,
|
|
608
|
+
"permittivity": 4.4,
|
|
609
|
+
"permeability": 1,
|
|
610
|
+
"poisson_ratio": 0.28,
|
|
611
|
+
"specific_heat": 1150,
|
|
612
|
+
"thermal_conductivity": 0.294,
|
|
613
|
+
"youngs_modulus": 11000000000,
|
|
614
|
+
"thermal_expansion_coefficient": 1.5e-05,
|
|
615
|
+
}
|
|
616
|
+
|
|
590
617
|
def __init__(self, edb: Edb):
|
|
591
618
|
self.__edb = edb
|
|
592
619
|
self.__syslib = os.path.join(self.__edb.base_path, "syslib")
|
|
@@ -26,6 +26,7 @@ from ansys.edb.core.utility.value import Value as GrpcValue
|
|
|
26
26
|
|
|
27
27
|
from pyedb.edb_logger import pyedb_logger
|
|
28
28
|
from pyedb.grpc.database.utility.heat_sink import HeatSink
|
|
29
|
+
from pyedb.misc.misc import deprecated_property
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
class PackageDef(GrpcPackageDef):
|
|
@@ -45,6 +46,11 @@ class PackageDef(GrpcPackageDef):
|
|
|
45
46
|
"""
|
|
46
47
|
|
|
47
48
|
def __init__(self, pedb, edb_object=None, name=None, component_part_name=None, extent_bounding_box=None):
|
|
49
|
+
if not edb_object:
|
|
50
|
+
if name:
|
|
51
|
+
edb_object = GrpcPackageDef.create(db=pedb.active_db, name=name)
|
|
52
|
+
else:
|
|
53
|
+
raise AttributeError("Name must be provided to create and instantiate a PackageDef object.")
|
|
48
54
|
super(GrpcPackageDef, self).__init__(edb_object.msg)
|
|
49
55
|
self._pedb = pedb
|
|
50
56
|
self._edb_object = edb_object
|
|
@@ -129,7 +135,6 @@ class PackageDef(GrpcPackageDef):
|
|
|
129
135
|
|
|
130
136
|
@therm_cond.setter
|
|
131
137
|
def therm_cond(self, value):
|
|
132
|
-
self.therm_cond = GrpcValue(value)
|
|
133
138
|
super(PackageDef, self.__class__).thermal_conductivity.__set__(self, GrpcValue(value))
|
|
134
139
|
|
|
135
140
|
@property
|
|
@@ -186,7 +191,20 @@ class PackageDef(GrpcPackageDef):
|
|
|
186
191
|
:class:`HeatSink <pyedb.grpc.database.utility.heat_sink.HeatSink>`
|
|
187
192
|
HeatSink object.
|
|
188
193
|
"""
|
|
189
|
-
|
|
194
|
+
try:
|
|
195
|
+
return HeatSink(self._pedb, super().heat_sink)
|
|
196
|
+
except:
|
|
197
|
+
pass
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
@deprecated_property
|
|
201
|
+
def heatsink(self):
|
|
202
|
+
"""Property added for .NET compatibility.
|
|
203
|
+
. deprecated:: pyedb 0.43.0
|
|
204
|
+
Use :func:`heat_sink` instead.
|
|
205
|
+
|
|
206
|
+
"""
|
|
207
|
+
return self.heat_sink
|
|
190
208
|
|
|
191
209
|
def set_heatsink(self, fin_base_height, fin_height, fin_orientation, fin_spacing, fin_thickness):
|
|
192
210
|
"""Set Heat sink.
|
|
@@ -34,7 +34,7 @@ import ansys.edb.core.geometry.polygon_data
|
|
|
34
34
|
from ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData
|
|
35
35
|
from ansys.edb.core.hierarchy.structure3d import MeshClosure as GrpcMeshClosure
|
|
36
36
|
from ansys.edb.core.hierarchy.structure3d import Structure3D as GrpcStructure3D
|
|
37
|
-
from ansys.edb.core.primitive.
|
|
37
|
+
from ansys.edb.core.primitive.circle import Circle as GrpcCircle
|
|
38
38
|
from ansys.edb.core.utility.value import Value as GrpcValue
|
|
39
39
|
|
|
40
40
|
from pyedb.generic.general_methods import generate_unique_name
|
|
@@ -577,7 +577,10 @@ class PadstackDef(GrpcPadstackDef):
|
|
|
577
577
|
Possible returned values are ``"through"``, ``"begin_on_upper_pad"``,
|
|
578
578
|
``"end_on_lower_pad"``, ``"upper_pad_to_lower_pad"``, and ``"undefined"``.
|
|
579
579
|
"""
|
|
580
|
-
|
|
580
|
+
try:
|
|
581
|
+
return self.data.hole_range.name.lower()
|
|
582
|
+
except:
|
|
583
|
+
return None
|
|
581
584
|
|
|
582
585
|
@hole_range.setter
|
|
583
586
|
def hole_range(self, value):
|
|
@@ -42,8 +42,10 @@ from ansys.edb.core.hierarchy.sparameter_model import (
|
|
|
42
42
|
SParameterModel as GrpcSParameterModel,
|
|
43
43
|
)
|
|
44
44
|
from ansys.edb.core.hierarchy.spice_model import SPICEModel as GrpcSPICEModel
|
|
45
|
-
from ansys.edb.core.primitive.
|
|
46
|
-
|
|
45
|
+
from ansys.edb.core.primitive.padstack_instance import (
|
|
46
|
+
PadstackInstance as GrpcPadstackInstance,
|
|
47
|
+
)
|
|
48
|
+
from ansys.edb.core.terminal.padstack_instance_terminal import (
|
|
47
49
|
PadstackInstanceTerminal as GrpcPadstackInstanceTerminal,
|
|
48
50
|
)
|
|
49
51
|
from ansys.edb.core.utility.rlc import Rlc as GrpcRlc
|