pyedb 0.47.1__py3-none-any.whl → 0.48.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_stackup.py +35 -1
- pyedb/configuration/configuration.py +13 -13
- pyedb/dotnet/database/cell/primitive/primitive.py +8 -1
- pyedb/dotnet/database/cell/terminal/terminal.py +22 -4
- pyedb/dotnet/database/components.py +22 -3
- pyedb/dotnet/database/dotnet/database.py +18 -0
- pyedb/dotnet/database/edb_data/padstacks_data.py +20 -0
- pyedb/dotnet/database/edb_data/ports.py +14 -0
- pyedb/dotnet/database/edb_data/utilities.py +1 -1
- pyedb/dotnet/database/geometry/polygon_data.py +1 -1
- pyedb/dotnet/database/hfss.py +11 -1
- pyedb/dotnet/database/materials.py +78 -0
- pyedb/dotnet/database/modeler.py +9 -5
- pyedb/dotnet/database/sim_setup_data/data/mesh_operation.py +24 -0
- pyedb/dotnet/database/siwave.py +1 -1
- pyedb/dotnet/database/utilities/simulation_setup.py +51 -9
- pyedb/dotnet/edb.py +67 -8
- pyedb/grpc/database/components.py +19 -13
- pyedb/grpc/database/hfss.py +3 -3
- pyedb/grpc/database/modeler.py +4 -4
- pyedb/grpc/database/padstacks.py +3 -1
- pyedb/grpc/database/ports/ports.py +4 -0
- pyedb/grpc/database/primitive/path.py +2 -2
- pyedb/grpc/database/primitive/primitive.py +6 -1
- pyedb/grpc/database/source_excitations.py +16 -8
- pyedb/grpc/database/terminal/bundle_terminal.py +1 -1
- pyedb/grpc/edb.py +125 -32
- {pyedb-0.47.1.dist-info → pyedb-0.48.0.dist-info}/METADATA +1 -1
- {pyedb-0.47.1.dist-info → pyedb-0.48.0.dist-info}/RECORD +32 -32
- {pyedb-0.47.1.dist-info → pyedb-0.48.0.dist-info}/LICENSE +0 -0
- {pyedb-0.47.1.dist-info → pyedb-0.48.0.dist-info}/WHEEL +0 -0
pyedb/dotnet/edb.py
CHANGED
|
@@ -1451,13 +1451,28 @@ class Edb(Database):
|
|
|
1451
1451
|
def close_edb(self):
|
|
1452
1452
|
"""Close EDB and cleanup variables.
|
|
1453
1453
|
|
|
1454
|
+
. deprecated:: pyedb 0.47.0
|
|
1455
|
+
Use: func:`close` instead.
|
|
1456
|
+
|
|
1457
|
+
Returns
|
|
1458
|
+
-------
|
|
1459
|
+
bool
|
|
1460
|
+
``True`` when successful, ``False`` when failed.
|
|
1461
|
+
|
|
1462
|
+
"""
|
|
1463
|
+
warnings.warn("Use new property :func:`close` instead.", DeprecationWarning)
|
|
1464
|
+
return self.close()
|
|
1465
|
+
|
|
1466
|
+
def close(self):
|
|
1467
|
+
"""Close EDB and cleanup variables.
|
|
1468
|
+
|
|
1454
1469
|
Returns
|
|
1455
1470
|
-------
|
|
1456
1471
|
bool
|
|
1457
1472
|
``True`` when successful, ``False`` when failed.
|
|
1458
1473
|
|
|
1459
1474
|
"""
|
|
1460
|
-
|
|
1475
|
+
Database.close(self)
|
|
1461
1476
|
|
|
1462
1477
|
if self.log_name and settings.enable_local_log_file:
|
|
1463
1478
|
self._logger.remove_all_file_loggers()
|
|
@@ -1471,25 +1486,62 @@ class Edb(Database):
|
|
|
1471
1486
|
def save_edb(self):
|
|
1472
1487
|
"""Save the EDB file.
|
|
1473
1488
|
|
|
1489
|
+
. deprecated:: pyedb 0.47.0
|
|
1490
|
+
Use: func:`save` instead.
|
|
1491
|
+
|
|
1492
|
+
Returns
|
|
1493
|
+
-------
|
|
1494
|
+
bool
|
|
1495
|
+
``True`` when successful, ``False`` when failed.
|
|
1496
|
+
|
|
1497
|
+
"""
|
|
1498
|
+
warnings.warn("Use new method :func:`save` instead.", DeprecationWarning)
|
|
1499
|
+
return self.save()
|
|
1500
|
+
|
|
1501
|
+
def save(self):
|
|
1502
|
+
"""Save the EDB file.
|
|
1503
|
+
|
|
1474
1504
|
Returns
|
|
1475
1505
|
-------
|
|
1476
1506
|
bool
|
|
1477
1507
|
``True`` when successful, ``False`` when failed.
|
|
1478
1508
|
|
|
1479
1509
|
"""
|
|
1480
|
-
|
|
1510
|
+
|
|
1511
|
+
Database.save(self)
|
|
1481
1512
|
start_time = time.time()
|
|
1482
1513
|
self._wait_for_file_release()
|
|
1483
1514
|
elapsed_time = time.time() - start_time
|
|
1484
1515
|
self.logger.info("EDB file save time: {0:.2f}ms".format(elapsed_time * 1000.0))
|
|
1485
1516
|
return True
|
|
1486
1517
|
|
|
1487
|
-
def save_edb_as(self,
|
|
1518
|
+
def save_edb_as(self, path):
|
|
1519
|
+
"""Save the EDB file as another file.
|
|
1520
|
+
|
|
1521
|
+
. deprecated:: pyedb 0.47.0
|
|
1522
|
+
Use: func:`save_as` instead.
|
|
1523
|
+
|
|
1524
|
+
|
|
1525
|
+
Parameters
|
|
1526
|
+
----------
|
|
1527
|
+
path : str
|
|
1528
|
+
Name of the new file to save to.
|
|
1529
|
+
|
|
1530
|
+
Returns
|
|
1531
|
+
-------
|
|
1532
|
+
bool
|
|
1533
|
+
``True`` when successful, ``False`` when failed.
|
|
1534
|
+
|
|
1535
|
+
"""
|
|
1536
|
+
warnings.warn("Use new property :func:`save_as` instead.", DeprecationWarning)
|
|
1537
|
+
return self.save_as(path)
|
|
1538
|
+
|
|
1539
|
+
def save_as(self, path, version=""):
|
|
1488
1540
|
"""Save the EDB file as another file.
|
|
1489
1541
|
|
|
1490
1542
|
Parameters
|
|
1491
1543
|
----------
|
|
1492
|
-
|
|
1544
|
+
path : str
|
|
1493
1545
|
Name of the new file to save to.
|
|
1494
1546
|
|
|
1495
1547
|
Returns
|
|
@@ -1499,7 +1551,7 @@ class Edb(Database):
|
|
|
1499
1551
|
|
|
1500
1552
|
"""
|
|
1501
1553
|
origin_name = "pyedb_" + os.path.splitext(os.path.split(self.edbpath)[-1])[0]
|
|
1502
|
-
|
|
1554
|
+
Database.save_as(self, path)
|
|
1503
1555
|
start_time = time.time()
|
|
1504
1556
|
self._wait_for_file_release()
|
|
1505
1557
|
elapsed_time = time.time() - start_time
|
|
@@ -1509,8 +1561,8 @@ class Edb(Database):
|
|
|
1509
1561
|
self._logger.remove_file_logger(os.path.splitext(os.path.split(self.log_name)[-1])[0])
|
|
1510
1562
|
|
|
1511
1563
|
self.log_name = os.path.join(
|
|
1512
|
-
os.path.dirname(
|
|
1513
|
-
"pyedb_" + os.path.splitext(os.path.split(
|
|
1564
|
+
os.path.dirname(path),
|
|
1565
|
+
"pyedb_" + os.path.splitext(os.path.split(path)[-1])[0] + ".log",
|
|
1514
1566
|
)
|
|
1515
1567
|
if settings.enable_local_log_file:
|
|
1516
1568
|
self._logger.add_file_logger(self.log_name, "Edb")
|
|
@@ -1800,7 +1852,7 @@ class Edb(Database):
|
|
|
1800
1852
|
output_aedb_path=None,
|
|
1801
1853
|
open_cutout_at_end=True,
|
|
1802
1854
|
use_pyaedt_cutout=True,
|
|
1803
|
-
number_of_threads=
|
|
1855
|
+
number_of_threads=1,
|
|
1804
1856
|
use_pyaedt_extent_computing=True,
|
|
1805
1857
|
extent_defeature=0,
|
|
1806
1858
|
remove_single_pin_components=False,
|
|
@@ -4668,3 +4720,10 @@ class Edb(Database):
|
|
|
4668
4720
|
ET.indent(tree, space="\t", level=0)
|
|
4669
4721
|
tree.write(control_path)
|
|
4670
4722
|
return True if os.path.exists(control_path) else False
|
|
4723
|
+
|
|
4724
|
+
def get_variable_value(self, variable_name):
|
|
4725
|
+
"""Added to get closer architecture as for grpc."""
|
|
4726
|
+
if variable_name in self.variables:
|
|
4727
|
+
return self.variables[variable_name].value
|
|
4728
|
+
else:
|
|
4729
|
+
return False
|
|
@@ -276,20 +276,26 @@ class Components(object):
|
|
|
276
276
|
self._others = {}
|
|
277
277
|
for i in self._pedb.layout.groups:
|
|
278
278
|
self._cmp[i.name] = i
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
279
|
+
try:
|
|
280
|
+
if i.type == "resistor":
|
|
281
|
+
self._res[i.name] = i
|
|
282
|
+
elif i.type == "capacitor":
|
|
283
|
+
self._cap[i.name] = i
|
|
284
|
+
elif i.type == "inductor":
|
|
285
|
+
self._ind[i.name] = i
|
|
286
|
+
elif i.type == "ic":
|
|
287
|
+
self._ics[i.name] = i
|
|
288
|
+
elif i.type == "io":
|
|
289
|
+
self._ios[i.name] = i
|
|
290
|
+
elif i.type == "other":
|
|
291
|
+
self._others[i.name] = i
|
|
292
|
+
else:
|
|
293
|
+
self._logger.warning(
|
|
294
|
+
f"Unknown component type {i.name} found while refreshing components, will ignore"
|
|
295
|
+
)
|
|
296
|
+
except:
|
|
297
|
+
self._logger.warning(f"Assigning component {i.name} as default type other.")
|
|
290
298
|
self._others[i.name] = i
|
|
291
|
-
else:
|
|
292
|
-
self._logger.warning(f"Unknown component type {i.name} found while refreshing components, will ignore")
|
|
293
299
|
return True
|
|
294
300
|
|
|
295
301
|
@property
|
pyedb/grpc/database/hfss.py
CHANGED
|
@@ -527,7 +527,7 @@ class Hfss(object):
|
|
|
527
527
|
"`pyedb.grpc.core.excitations.create_differential_wave_port` instead.",
|
|
528
528
|
DeprecationWarning,
|
|
529
529
|
)
|
|
530
|
-
return self._pedb.
|
|
530
|
+
return self._pedb.source_excitation.create_differential_wave_port(
|
|
531
531
|
positive_primitive_id,
|
|
532
532
|
positive_points_on_edge,
|
|
533
533
|
negative_primitive_id,
|
|
@@ -579,7 +579,7 @@ class Hfss(object):
|
|
|
579
579
|
"`pyedb.grpc.core.excitations.create_bundle_wave_port` instead.",
|
|
580
580
|
DeprecationWarning,
|
|
581
581
|
)
|
|
582
|
-
self._pedb.
|
|
582
|
+
return self._pedb.source_excitation.create_bundle_wave_port(
|
|
583
583
|
primitives_id, points_on_edge, port_name, horizontal_extent_factor, vertical_extent_factor, pec_launch_width
|
|
584
584
|
)
|
|
585
585
|
|
|
@@ -720,7 +720,7 @@ class Hfss(object):
|
|
|
720
720
|
"`pyedb.grpc.core.excitations.create_source_on_component` instead.",
|
|
721
721
|
DeprecationWarning,
|
|
722
722
|
)
|
|
723
|
-
self._pedb.source_excitation.create_wave_port(
|
|
723
|
+
return self._pedb.source_excitation.create_wave_port(
|
|
724
724
|
prim_id,
|
|
725
725
|
point_on_edge,
|
|
726
726
|
port_name,
|
pyedb/grpc/database/modeler.py
CHANGED
|
@@ -1272,7 +1272,7 @@ class Modeler(object):
|
|
|
1272
1272
|
stat_model.num_resistors = len(self._pedb.components.resistors)
|
|
1273
1273
|
stat_model.num_inductors = len(self._pedb.components.inductors)
|
|
1274
1274
|
bbox = self._pedb._hfss.get_layout_bounding_box(self._active_layout)
|
|
1275
|
-
stat_model._layout_size = bbox[2] - bbox[0], bbox[3] - bbox[1]
|
|
1275
|
+
stat_model._layout_size = round(bbox[2] - bbox[0], 6), round(bbox[3] - bbox[1], 6)
|
|
1276
1276
|
stat_model.num_discrete_components = (
|
|
1277
1277
|
len(self._pedb.components.Others) + len(self._pedb.components.ICs) + len(self._pedb.components.IOs)
|
|
1278
1278
|
)
|
|
@@ -1283,7 +1283,7 @@ class Modeler(object):
|
|
|
1283
1283
|
stat_model.num_traces = len(self._pedb.modeler.paths)
|
|
1284
1284
|
stat_model.num_polygons = len(self._pedb.modeler.polygons)
|
|
1285
1285
|
stat_model.num_vias = len(self._pedb.padstacks.instances)
|
|
1286
|
-
stat_model.stackup_thickness = self._pedb.stackup.get_layout_thickness()
|
|
1286
|
+
stat_model.stackup_thickness = round(self._pedb.stackup.get_layout_thickness(), 6)
|
|
1287
1287
|
if evaluate_area:
|
|
1288
1288
|
outline_surface = stat_model.layout_size[0] * stat_model.layout_size[1]
|
|
1289
1289
|
if net_list:
|
|
@@ -1298,8 +1298,8 @@ class Modeler(object):
|
|
|
1298
1298
|
surface += Path(self._pedb, prim).length * prim.cast().width.value
|
|
1299
1299
|
if prim.primitive_type.name == "POLYGON":
|
|
1300
1300
|
surface += prim.polygon_data.area()
|
|
1301
|
-
stat_model.occupying_surface[layer] = surface
|
|
1302
|
-
stat_model.occupying_ratio[layer] = surface / outline_surface
|
|
1301
|
+
stat_model.occupying_surface[layer] = round(surface, 6)
|
|
1302
|
+
stat_model.occupying_ratio[layer] = round(surface / outline_surface, 6)
|
|
1303
1303
|
return stat_model
|
|
1304
1304
|
|
|
1305
1305
|
def create_bondwire(
|
pyedb/grpc/database/padstacks.py
CHANGED
|
@@ -506,7 +506,9 @@ class Padstacks(object):
|
|
|
506
506
|
"`pyedb.grpc.core.excitations.create_coax_port` instead.",
|
|
507
507
|
DeprecationWarning,
|
|
508
508
|
)
|
|
509
|
-
self._pedb.
|
|
509
|
+
self._pedb.source_excitation.create_coax_port(
|
|
510
|
+
self, padstackinstance, use_dot_separator=use_dot_separator, name=name
|
|
511
|
+
)
|
|
510
512
|
|
|
511
513
|
def get_pin_from_component_and_net(self, refdes=None, netname=None):
|
|
512
514
|
"""Retrieve pins given a component's reference designator and net name.
|
|
@@ -108,6 +108,10 @@ class GapPort(EdgeTerminal):
|
|
|
108
108
|
self._edb_object.port_post_processing_prop.renormalizion_z0[1],
|
|
109
109
|
)
|
|
110
110
|
|
|
111
|
+
@property
|
|
112
|
+
def terminal_type(self):
|
|
113
|
+
return self._edb_object.terminal_type
|
|
114
|
+
|
|
111
115
|
|
|
112
116
|
class CircuitPort(GapPort):
|
|
113
117
|
"""Manages gap port properties.
|
|
@@ -62,7 +62,7 @@ class Path(GrpcPath, Primitive):
|
|
|
62
62
|
"""
|
|
63
63
|
center_line_arcs = self._edb_object.cast().center_line.arc_data
|
|
64
64
|
path_length = 0.0
|
|
65
|
-
for arc in center_line_arcs:
|
|
65
|
+
for arc in center_line_arcs[: int(len(center_line_arcs) / 2)]:
|
|
66
66
|
path_length += arc.length
|
|
67
67
|
end_cap_style = self.get_end_cap_style()
|
|
68
68
|
if end_cap_style:
|
|
@@ -181,7 +181,7 @@ class Path(GrpcPath, Primitive):
|
|
|
181
181
|
# )
|
|
182
182
|
# else:
|
|
183
183
|
return self._pedb.hfss.create_edge_port_vertical(
|
|
184
|
-
self.
|
|
184
|
+
self.edb_uid,
|
|
185
185
|
pos,
|
|
186
186
|
name,
|
|
187
187
|
50,
|
|
@@ -253,7 +253,12 @@ class Primitive(GrpcPrimitive):
|
|
|
253
253
|
|
|
254
254
|
"""
|
|
255
255
|
bbox = self.cast().polygon_data.bbox()
|
|
256
|
-
return [
|
|
256
|
+
return [
|
|
257
|
+
round(bbox[0].x.value, 6),
|
|
258
|
+
round(bbox[0].y.value, 6),
|
|
259
|
+
round(bbox[1].x.value, 6),
|
|
260
|
+
round(bbox[1].y.value, 6),
|
|
261
|
+
]
|
|
257
262
|
|
|
258
263
|
def convert_to_polygon(self):
|
|
259
264
|
"""Convert path to polygon.
|
|
@@ -353,6 +353,14 @@ class SourceExcitation:
|
|
|
353
353
|
>>> port_type=SourceType.CoaxPort, do_pingroup=False, refnet="GND")
|
|
354
354
|
|
|
355
355
|
"""
|
|
356
|
+
if isinstance(port_type, int):
|
|
357
|
+
# Adding DotNet backward compatibility with SourceType
|
|
358
|
+
type_mapping = {0: "coax_port", 1: "circuit_port"}
|
|
359
|
+
if port_type in type_mapping:
|
|
360
|
+
port_type = type_mapping[port_type]
|
|
361
|
+
else:
|
|
362
|
+
self._logger.error(f"unsupported port type with method.")
|
|
363
|
+
return False
|
|
356
364
|
if isinstance(component, str):
|
|
357
365
|
component = self._pedb.components.instances[component]
|
|
358
366
|
if not isinstance(net_list, list):
|
|
@@ -395,7 +403,7 @@ class SourceExcitation:
|
|
|
395
403
|
"outside the component when not found if argument extend_reference_pins_outside_component is True."
|
|
396
404
|
)
|
|
397
405
|
return False
|
|
398
|
-
pad_params = self._pedb.
|
|
406
|
+
pad_params = self._pedb.padstacks.get_pad_parameters(pin=cmp_pins[0], layername=pin_layers[0], pad_type=0)
|
|
399
407
|
if not pad_params[0] == 7:
|
|
400
408
|
if not solder_balls_size: # pragma no cover
|
|
401
409
|
sball_diam = min([GrpcValue(val).value for val in pad_params[1]])
|
|
@@ -431,7 +439,7 @@ class SourceExcitation:
|
|
|
431
439
|
shape=sball_shape,
|
|
432
440
|
)
|
|
433
441
|
for pin in cmp_pins:
|
|
434
|
-
self._pedb.
|
|
442
|
+
self._pedb.source_excitation.create_coax_port(padstackinstance=pin, name=port_name)
|
|
435
443
|
|
|
436
444
|
elif port_type == "circuit_port": # pragma no cover
|
|
437
445
|
ref_pins = [p for p in list(component.pins.values()) if p.net_name in reference_net]
|
|
@@ -794,7 +802,7 @@ class SourceExcitation:
|
|
|
794
802
|
port_name = generate_unique_name(port_name, n=2)
|
|
795
803
|
self._logger.info("An existing port already has this same name. Renaming to {}.".format(port_name))
|
|
796
804
|
PadstackInstanceTerminal.create(
|
|
797
|
-
layout=self._pedb.
|
|
805
|
+
layout=self._pedb.active_layout,
|
|
798
806
|
name=port_name,
|
|
799
807
|
padstack_instance=padstackinstance,
|
|
800
808
|
layer=terminal_layer,
|
|
@@ -831,7 +839,7 @@ class SourceExcitation:
|
|
|
831
839
|
terminal_name = generate_unique_name("Terminal_")
|
|
832
840
|
if isinstance(point_on_edge, tuple):
|
|
833
841
|
point_on_edge = GrpcPointData(point_on_edge)
|
|
834
|
-
prim = [i for i in self._pedb.modeler.primitives if i.
|
|
842
|
+
prim = [i for i in self._pedb.modeler.primitives if i.edb_uid == prim_id]
|
|
835
843
|
if not prim:
|
|
836
844
|
self._pedb.logger.error(f"No primitive found for ID {prim_id}")
|
|
837
845
|
return False
|
|
@@ -1580,10 +1588,10 @@ class SourceExcitation:
|
|
|
1580
1588
|
port_name = generate_unique_name("diff")
|
|
1581
1589
|
|
|
1582
1590
|
if isinstance(positive_primitive_id, Primitive):
|
|
1583
|
-
positive_primitive_id = positive_primitive_id.
|
|
1591
|
+
positive_primitive_id = positive_primitive_id.edb_uid
|
|
1584
1592
|
|
|
1585
1593
|
if isinstance(negative_primitive_id, Primitive):
|
|
1586
|
-
negative_primitive_id = negative_primitive_id.
|
|
1594
|
+
negative_primitive_id = negative_primitive_id.edb_uid
|
|
1587
1595
|
|
|
1588
1596
|
_, pos_term = self.create_wave_port(
|
|
1589
1597
|
positive_primitive_id,
|
|
@@ -1652,7 +1660,7 @@ class SourceExcitation:
|
|
|
1652
1660
|
port_name = generate_unique_name("Terminal_")
|
|
1653
1661
|
|
|
1654
1662
|
if isinstance(prim_id, Primitive):
|
|
1655
|
-
prim_id = prim_id.
|
|
1663
|
+
prim_id = prim_id.edb_uid
|
|
1656
1664
|
pos_edge_term = self._create_edge_terminal(prim_id, point_on_edge, port_name)
|
|
1657
1665
|
pos_edge_term.impedance = GrpcValue(impedance)
|
|
1658
1666
|
wave_port = WavePort(self._pedb, pos_edge_term)
|
|
@@ -2027,7 +2035,7 @@ class SourceExcitation:
|
|
|
2027
2035
|
port_name = generate_unique_name("bundle_port")
|
|
2028
2036
|
|
|
2029
2037
|
if isinstance(primitives_id[0], Primitive):
|
|
2030
|
-
primitives_id = [i.
|
|
2038
|
+
primitives_id = [i.edb_uid for i in primitives_id]
|
|
2031
2039
|
|
|
2032
2040
|
terminals = []
|
|
2033
2041
|
_port_name = port_name
|
pyedb/grpc/edb.py
CHANGED
|
@@ -35,6 +35,7 @@ import sys
|
|
|
35
35
|
import tempfile
|
|
36
36
|
import time
|
|
37
37
|
import traceback
|
|
38
|
+
from typing import Union
|
|
38
39
|
import warnings
|
|
39
40
|
from zipfile import ZipFile as zpf
|
|
40
41
|
|
|
@@ -57,7 +58,7 @@ from pyedb.generic.general_methods import (
|
|
|
57
58
|
from pyedb.generic.process import SiwaveSolve
|
|
58
59
|
from pyedb.generic.settings import settings
|
|
59
60
|
from pyedb.grpc.database.components import Components
|
|
60
|
-
from pyedb.grpc.database.control_file import ControlFile
|
|
61
|
+
from pyedb.grpc.database.control_file import ControlFile
|
|
61
62
|
from pyedb.grpc.database.definition.materials import Materials
|
|
62
63
|
from pyedb.grpc.database.hfss import Hfss
|
|
63
64
|
from pyedb.grpc.database.layout.layout import Layout
|
|
@@ -110,7 +111,7 @@ class Edb(EdbInit):
|
|
|
110
111
|
edbpath : str, optional
|
|
111
112
|
Full path to the ``aedb`` folder. The variable can also contain
|
|
112
113
|
the path to a layout to import. Allowed formats are BRD, MCM,
|
|
113
|
-
XML (IPC2581), GDS, and DXF. The default is ``None``.
|
|
114
|
+
XML (IPC2581), GDS, ODB++(TGZ and ZIP) and DXF. The default is ``None``.
|
|
114
115
|
For GDS import, the Ansys control file (also XML) should have the same
|
|
115
116
|
name as the GDS file. Only the file extension differs.
|
|
116
117
|
cellname : str, optional
|
|
@@ -120,14 +121,25 @@ class Edb(EdbInit):
|
|
|
120
121
|
owned by HFSS 3D Layout. The default is ``False``.
|
|
121
122
|
edbversion : str, int, float, optional
|
|
122
123
|
Version of EDB to use. The default is ``None``.
|
|
123
|
-
Examples of input values are ``
|
|
124
|
+
Examples of input values are ``232``, ``23.2``, ``2023.2``, ``"2023.2"``.
|
|
124
125
|
isaedtowned : bool, optional
|
|
125
126
|
Whether to launch EDB from HFSS 3D Layout. The
|
|
126
127
|
default is ``False``.
|
|
127
128
|
oproject : optional
|
|
128
129
|
Reference to the AEDT project object.
|
|
130
|
+
student_version : bool, optional
|
|
131
|
+
Whether to open the AEDT student version. The default is ``False.``
|
|
132
|
+
control_file : str, optional
|
|
133
|
+
Path to the XML file. The default is ``None``, in which case an attempt is made to find
|
|
134
|
+
the XML file in the same directory as the board file. To succeed, the XML file and board file
|
|
135
|
+
must have the same name. Only the extension differs.
|
|
136
|
+
map_file : str, optional
|
|
137
|
+
Layer map .map file.
|
|
129
138
|
technology_file : str, optional
|
|
130
|
-
|
|
139
|
+
Full path to technology file to be converted to xml before importing or xml.
|
|
140
|
+
Supported by GDS format only.
|
|
141
|
+
layer_filter:str,optional
|
|
142
|
+
Layer filter .txt file.
|
|
131
143
|
restart_rpc_server : bool, optional
|
|
132
144
|
``True`` RPC server is terminated and restarted. This will close all open EDB. RPC server is running on single
|
|
133
145
|
instance loading all EDB, enabling this option should be used with caution but can be a solution to release
|
|
@@ -188,15 +200,19 @@ class Edb(EdbInit):
|
|
|
188
200
|
|
|
189
201
|
def __init__(
|
|
190
202
|
self,
|
|
191
|
-
edbpath=None,
|
|
192
|
-
cellname=None,
|
|
193
|
-
isreadonly=False,
|
|
194
|
-
edbversion=None,
|
|
195
|
-
isaedtowned=False,
|
|
203
|
+
edbpath: Union[str, Path] = None,
|
|
204
|
+
cellname: str = None,
|
|
205
|
+
isreadonly: bool = False,
|
|
206
|
+
edbversion: str = None,
|
|
207
|
+
isaedtowned: bool = False,
|
|
196
208
|
oproject=None,
|
|
197
209
|
student_version: bool = False,
|
|
198
|
-
use_ppe=False,
|
|
199
|
-
|
|
210
|
+
use_ppe: bool = False,
|
|
211
|
+
control_file: str = None,
|
|
212
|
+
map_file: str = None,
|
|
213
|
+
technology_file: str = None,
|
|
214
|
+
layer_filter: str = None,
|
|
215
|
+
remove_existing_aedt: bool = False,
|
|
200
216
|
restart_rpc_server=False,
|
|
201
217
|
):
|
|
202
218
|
edbversion = get_string_version(edbversion)
|
|
@@ -247,14 +263,18 @@ class Edb(EdbInit):
|
|
|
247
263
|
zipped_file.extractall(edbpath[:-4])
|
|
248
264
|
self.logger.info("ODB++ unzipped successfully.")
|
|
249
265
|
zipped_file.close()
|
|
250
|
-
control_file = None
|
|
251
|
-
if technology_file:
|
|
252
|
-
if os.path.splitext(technology_file)[1] == ".xml":
|
|
253
|
-
control_file = technology_file
|
|
254
|
-
else:
|
|
255
|
-
control_file = convert_technology_file(technology_file, edbversion=edbversion)
|
|
256
266
|
self.logger.info("Translating ODB++ to EDB...")
|
|
257
|
-
self.
|
|
267
|
+
if not self.import_layout_file(
|
|
268
|
+
edbpath[:-4],
|
|
269
|
+
working_dir,
|
|
270
|
+
use_ppe=use_ppe,
|
|
271
|
+
control_file=control_file,
|
|
272
|
+
tech_file=technology_file,
|
|
273
|
+
layer_filter=layer_filter,
|
|
274
|
+
map_file=map_file,
|
|
275
|
+
):
|
|
276
|
+
raise AttributeError("Translation was unsuccessful")
|
|
277
|
+
return False
|
|
258
278
|
if settings.enable_local_log_file and self.log_name:
|
|
259
279
|
self.logger.add_file_logger(self.log_name, "Edb")
|
|
260
280
|
self.logger.info("EDB %s was created correctly from %s file.", self.edbpath, edbpath)
|
|
@@ -262,14 +282,17 @@ class Edb(EdbInit):
|
|
|
262
282
|
elif edbpath[-3:] in ["brd", "mcm", "gds", "xml", "dxf", "tgz"]:
|
|
263
283
|
self.edbpath = edbpath[:-4] + ".aedb"
|
|
264
284
|
working_dir = os.path.dirname(edbpath)
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
285
|
+
if not self.import_layout_file(
|
|
286
|
+
edbpath,
|
|
287
|
+
working_dir,
|
|
288
|
+
use_ppe=use_ppe,
|
|
289
|
+
control_file=control_file,
|
|
290
|
+
tech_file=technology_file,
|
|
291
|
+
layer_filter=layer_filter,
|
|
292
|
+
map_file=map_file,
|
|
293
|
+
):
|
|
294
|
+
raise AttributeError("Translation was unsuccessful")
|
|
295
|
+
return False
|
|
273
296
|
elif edbpath.endswith("edb.def"):
|
|
274
297
|
self.edbpath = os.path.dirname(edbpath)
|
|
275
298
|
self.open_edb(restart_rpc_server=restart_rpc_server)
|
|
@@ -638,10 +661,69 @@ class Edb(EdbInit):
|
|
|
638
661
|
def import_layout_pcb(
|
|
639
662
|
self,
|
|
640
663
|
input_file,
|
|
641
|
-
working_dir,
|
|
664
|
+
working_dir="",
|
|
665
|
+
anstranslator_full_path="",
|
|
666
|
+
use_ppe=False,
|
|
667
|
+
control_file=None,
|
|
668
|
+
map_file=None,
|
|
669
|
+
tech_file=None,
|
|
670
|
+
layer_filter=None,
|
|
671
|
+
):
|
|
672
|
+
"""Import a board file and generate an ``edb.def`` file in the working directory.
|
|
673
|
+
|
|
674
|
+
.. deprecated:: 0.42.0
|
|
675
|
+
Use :func:`import_layout_file` method instead.
|
|
676
|
+
|
|
677
|
+
This function supports all AEDT formats, including DXF, GDS, SML (IPC2581), BRD, MCM, SIP, ZIP and TGZ.
|
|
678
|
+
|
|
679
|
+
Parameters
|
|
680
|
+
----------
|
|
681
|
+
input_file : str
|
|
682
|
+
Full path to the board file.
|
|
683
|
+
working_dir : str, optional
|
|
684
|
+
Directory in which to create the ``aedb`` folder. The name given to the AEDB file
|
|
685
|
+
is the same as the name of the board file.
|
|
686
|
+
anstranslator_full_path : str, optional
|
|
687
|
+
Full path to the Ansys translator. The default is ``""``.
|
|
688
|
+
use_ppe : bool
|
|
689
|
+
Whether to use the PPE License. The default is ``False``.
|
|
690
|
+
control_file : str, optional
|
|
691
|
+
Path to the XML file. The default is ``None``, in which case an attempt is made to find
|
|
692
|
+
the XML file in the same directory as the board file. To succeed, the XML file and board file
|
|
693
|
+
must have the same name. Only the extension differs.
|
|
694
|
+
tech_file : str, optional
|
|
695
|
+
Technology file. The file can be *.ircx, *.vlc.tech, or *.itf
|
|
696
|
+
map_file : str, optional
|
|
697
|
+
Layer map .map file.
|
|
698
|
+
layer_filter:str,optional
|
|
699
|
+
Layer filter .txt file.
|
|
700
|
+
|
|
701
|
+
Returns
|
|
702
|
+
-------
|
|
703
|
+
Full path to the AEDB file : str
|
|
704
|
+
"""
|
|
705
|
+
self.logger.warning("import_layout_pcb method is deprecated, use import_layout_file instead.")
|
|
706
|
+
return self.import_layout_file(
|
|
707
|
+
input_file,
|
|
708
|
+
working_dir,
|
|
709
|
+
anstranslator_full_path,
|
|
710
|
+
use_ppe,
|
|
711
|
+
control_file,
|
|
712
|
+
map_file,
|
|
713
|
+
tech_file,
|
|
714
|
+
layer_filter,
|
|
715
|
+
)
|
|
716
|
+
|
|
717
|
+
def import_layout_file(
|
|
718
|
+
self,
|
|
719
|
+
input_file,
|
|
720
|
+
working_dir="",
|
|
642
721
|
anstranslator_full_path="",
|
|
643
722
|
use_ppe=False,
|
|
644
723
|
control_file=None,
|
|
724
|
+
map_file=None,
|
|
725
|
+
tech_file=None,
|
|
726
|
+
layer_filter=None,
|
|
645
727
|
):
|
|
646
728
|
"""Import a board file and generate an ``edb.def`` file in the working directory.
|
|
647
729
|
|
|
@@ -651,7 +733,7 @@ class Edb(EdbInit):
|
|
|
651
733
|
----------
|
|
652
734
|
input_file : str
|
|
653
735
|
Full path to the board file.
|
|
654
|
-
working_dir : str
|
|
736
|
+
working_dir : str, optional
|
|
655
737
|
Directory in which to create the ``aedb`` folder. The name given to the AEDB file
|
|
656
738
|
is the same as the name of the board file.
|
|
657
739
|
anstranslator_full_path : str, optional
|
|
@@ -662,10 +744,16 @@ class Edb(EdbInit):
|
|
|
662
744
|
Path to the XML file. The default is ``None``, in which case an attempt is made to find
|
|
663
745
|
the XML file in the same directory as the board file. To succeed, the XML file and board file
|
|
664
746
|
must have the same name. Only the extension differs.
|
|
747
|
+
tech_file : str, optional
|
|
748
|
+
Technology file. The file can be *.ircx, *.vlc.tech, or *.itf
|
|
749
|
+
map_file : str, optional
|
|
750
|
+
Layer map .map file.
|
|
751
|
+
layer_filter:str,optional
|
|
752
|
+
Layer filter .txt file.
|
|
665
753
|
|
|
666
754
|
Returns
|
|
667
755
|
-------
|
|
668
|
-
|
|
756
|
+
Full path to the AEDB file : str
|
|
669
757
|
|
|
670
758
|
"""
|
|
671
759
|
self._components = None
|
|
@@ -693,13 +781,18 @@ class Edb(EdbInit):
|
|
|
693
781
|
]
|
|
694
782
|
if not use_ppe:
|
|
695
783
|
cmd_translator.append("-ppe=false")
|
|
696
|
-
if control_file and input_file[-3:] not in ["brd", "mcm"]:
|
|
784
|
+
if control_file and input_file[-3:] not in ["brd", "mcm", "sip"]:
|
|
697
785
|
if is_linux:
|
|
698
786
|
cmd_translator.append("-c={}".format(control_file))
|
|
699
787
|
else:
|
|
700
788
|
cmd_translator.append('-c="{}"'.format(control_file))
|
|
701
|
-
|
|
702
|
-
|
|
789
|
+
if map_file:
|
|
790
|
+
cmd_translator.append('-g="{}"'.format(map_file))
|
|
791
|
+
if tech_file:
|
|
792
|
+
cmd_translator.append('-t="{}"'.format(tech_file))
|
|
793
|
+
if layer_filter:
|
|
794
|
+
cmd_translator.append('-f="{}"'.format(layer_filter))
|
|
795
|
+
subprocess.run(cmd_translator)
|
|
703
796
|
if not os.path.exists(os.path.join(working_dir, aedb_name)):
|
|
704
797
|
self.logger.error("Translator failed to translate.")
|
|
705
798
|
return False
|