pyedb 0.41.0__py3-none-any.whl → 0.43.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 +149 -63
- pyedb/configuration/cfg_components.py +333 -97
- pyedb/configuration/cfg_general.py +30 -12
- pyedb/configuration/cfg_modeler.py +161 -67
- pyedb/configuration/cfg_nets.py +33 -17
- pyedb/configuration/cfg_operations.py +63 -31
- pyedb/configuration/cfg_package_definition.py +72 -51
- pyedb/configuration/cfg_pin_groups.py +78 -26
- pyedb/configuration/cfg_s_parameter_models.py +95 -70
- pyedb/configuration/cfg_setup.py +230 -185
- pyedb/configuration/cfg_stackup.py +122 -90
- pyedb/configuration/configuration.py +342 -194
- pyedb/dotnet/database/cell/terminal/padstack_instance_terminal.py +5 -0
- pyedb/dotnet/database/cell/terminal/point_terminal.py +12 -0
- pyedb/dotnet/database/cell/terminal/terminal.py +0 -14
- pyedb/dotnet/database/dotnet/database.py +2 -0
- pyedb/dotnet/database/edb_data/padstacks_data.py +7 -2
- pyedb/dotnet/database/sim_setup_data/data/sweep_data.py +63 -10
- pyedb/dotnet/database/siwave.py +4 -1
- pyedb/dotnet/database/utilities/simulation_setup.py +15 -16
- pyedb/dotnet/edb.py +77 -110
- pyedb/grpc/database/components.py +1 -2
- pyedb/grpc/database/hierarchy/component.py +9 -1
- pyedb/grpc/database/hierarchy/s_parameter_model.py +2 -2
- pyedb/grpc/database/hierarchy/spice_model.py +4 -0
- pyedb/grpc/database/utility/hfss_extent_info.py +31 -20
- {pyedb-0.41.0.dist-info → pyedb-0.43.0.dist-info}/METADATA +1 -1
- {pyedb-0.41.0.dist-info → pyedb-0.43.0.dist-info}/RECORD +31 -31
- {pyedb-0.41.0.dist-info → pyedb-0.43.0.dist-info}/LICENSE +0 -0
- {pyedb-0.41.0.dist-info → pyedb-0.43.0.dist-info}/WHEEL +0 -0
|
@@ -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):
|
pyedb/dotnet/database/siwave.py
CHANGED
|
@@ -811,6 +811,7 @@ class EdbSiwave(object):
|
|
|
811
811
|
|
|
812
812
|
def add_siwave_syz_analysis(
|
|
813
813
|
self,
|
|
814
|
+
name=None,
|
|
814
815
|
accuracy_level=1,
|
|
815
816
|
decade_count=10,
|
|
816
817
|
sweeptype=1,
|
|
@@ -823,6 +824,8 @@ class EdbSiwave(object):
|
|
|
823
824
|
|
|
824
825
|
Parameters
|
|
825
826
|
----------
|
|
827
|
+
name : str optional
|
|
828
|
+
Setup name.
|
|
826
829
|
accuracy_level : int, optional
|
|
827
830
|
Level of accuracy of SI slider. The default is ``1``.
|
|
828
831
|
decade_count : int
|
|
@@ -849,7 +852,7 @@ class EdbSiwave(object):
|
|
|
849
852
|
:class:`pyedb.dotnet.database.edb_data.siwave_simulation_setup_data.SiwaveSYZSimulationSetup`
|
|
850
853
|
Setup object class.
|
|
851
854
|
"""
|
|
852
|
-
setup = self._pedb.create_siwave_syz_setup()
|
|
855
|
+
setup = self._pedb.create_siwave_syz_setup(name=name)
|
|
853
856
|
sweep = "linear count"
|
|
854
857
|
if sweeptype == 2:
|
|
855
858
|
sweep = "log scale"
|
|
@@ -239,7 +239,7 @@ class SimulationSetup(object):
|
|
|
239
239
|
"""List of frequency sweeps."""
|
|
240
240
|
return {i.name: i for i in self.sim_setup_info.sweep_data_list}
|
|
241
241
|
|
|
242
|
-
def add_sweep(self, name, frequency_set: list = None, **kwargs):
|
|
242
|
+
def add_sweep(self, name, frequency_set: list = None, sweep_type: str = "interpolation", **kwargs):
|
|
243
243
|
"""Add frequency sweep.
|
|
244
244
|
|
|
245
245
|
Parameters
|
|
@@ -248,7 +248,8 @@ class SimulationSetup(object):
|
|
|
248
248
|
Name of the frequency sweep. The default is ``None``.
|
|
249
249
|
frequency_set : list, optional
|
|
250
250
|
List of frequency points. The default is ``None``.
|
|
251
|
-
|
|
251
|
+
sweep_type : str, optional
|
|
252
|
+
Sweep type. The default is ``"interpolation"``. Options are ``"discrete"``,"discrete"``.
|
|
252
253
|
Returns
|
|
253
254
|
-------
|
|
254
255
|
|
|
@@ -265,26 +266,24 @@ class SimulationSetup(object):
|
|
|
265
266
|
for k, v in kwargs.items():
|
|
266
267
|
if k in dir(sweep_data):
|
|
267
268
|
setattr(sweep_data, k, v)
|
|
268
|
-
sweep_data.
|
|
269
|
+
sweep_data.type = sweep_type
|
|
269
270
|
|
|
270
|
-
if frequency_set
|
|
271
|
+
if frequency_set in [None, []]:
|
|
271
272
|
sweep_type = "linear_scale"
|
|
272
273
|
start, stop, increment = "50MHz", "5GHz", "50MHz"
|
|
274
|
+
frequency_set = [[sweep_type, start, stop, increment]]
|
|
275
|
+
elif not isinstance(frequency_set[0], list):
|
|
276
|
+
frequency_set = [frequency_set]
|
|
277
|
+
|
|
278
|
+
for fs in frequency_set:
|
|
279
|
+
sweep_type, start, stop, increment = fs
|
|
273
280
|
sweep_data.add(sweep_type, start, stop, increment)
|
|
274
|
-
elif len(frequency_set) == 0:
|
|
275
|
-
pass
|
|
276
|
-
else:
|
|
277
|
-
if not isinstance(frequency_set[0], list):
|
|
278
|
-
frequency_set = [frequency_set]
|
|
279
|
-
for fs in frequency_set:
|
|
280
|
-
sweep_data.add(*fs)
|
|
281
|
-
|
|
282
|
-
ss_info = self.sim_setup_info
|
|
283
|
-
ss_info.add_sweep_data(sweep_data)
|
|
284
|
-
self.set_sim_setup_info(ss_info)
|
|
285
|
-
self._update_setup()
|
|
286
281
|
return sweep_data
|
|
287
282
|
|
|
283
|
+
def delete(self):
|
|
284
|
+
"""Delete current simulation setup."""
|
|
285
|
+
self._pedb.layout.cell.DeleteSimulationSetup(self.name)
|
|
286
|
+
|
|
288
287
|
def _add_frequency_sweep(self, sweep_data):
|
|
289
288
|
"""Add a frequency sweep.
|
|
290
289
|
|
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:])
|
|
@@ -278,7 +274,7 @@ class Edb(Database):
|
|
|
278
274
|
if self.active_cell:
|
|
279
275
|
self.logger.info("EDB initialized.")
|
|
280
276
|
else:
|
|
281
|
-
|
|
277
|
+
raise AttributeError("Failed to initialize DLLs.")
|
|
282
278
|
|
|
283
279
|
def __enter__(self):
|
|
284
280
|
return self
|
|
@@ -549,10 +545,7 @@ class Edb(Database):
|
|
|
549
545
|
self.run_as_standalone(self.standalone)
|
|
550
546
|
|
|
551
547
|
# self.logger.info("EDB Standalone %s", self.standalone)
|
|
552
|
-
|
|
553
|
-
self.open(self.edbpath, self.isreadonly)
|
|
554
|
-
except Exception as e:
|
|
555
|
-
self.logger.error("Builder is not Initialized.")
|
|
548
|
+
self.open(self.edbpath, self.isreadonly)
|
|
556
549
|
if not self.active_db:
|
|
557
550
|
self.logger.warning("Error Opening db")
|
|
558
551
|
self._active_cell = None
|
|
@@ -613,6 +606,65 @@ class Edb(Database):
|
|
|
613
606
|
anstranslator_full_path="",
|
|
614
607
|
use_ppe=False,
|
|
615
608
|
control_file=None,
|
|
609
|
+
map_file=None,
|
|
610
|
+
tech_file=None,
|
|
611
|
+
layer_filter=None,
|
|
612
|
+
):
|
|
613
|
+
"""Import a board file and generate an ``edb.def`` file in the working directory.
|
|
614
|
+
|
|
615
|
+
.. deprecated:: 0.42.0
|
|
616
|
+
Use :func:`import_layout_file` method instead.
|
|
617
|
+
|
|
618
|
+
This function supports all AEDT formats, including DXF, GDS, SML (IPC2581), BRD, MCM, SIP, ZIP and TGZ.
|
|
619
|
+
|
|
620
|
+
Parameters
|
|
621
|
+
----------
|
|
622
|
+
input_file : str
|
|
623
|
+
Full path to the board file.
|
|
624
|
+
working_dir : str, optional
|
|
625
|
+
Directory in which to create the ``aedb`` folder. The name given to the AEDB file
|
|
626
|
+
is the same as the name of the board file.
|
|
627
|
+
anstranslator_full_path : str, optional
|
|
628
|
+
Full path to the Ansys translator. The default is ``""``.
|
|
629
|
+
use_ppe : bool
|
|
630
|
+
Whether to use the PPE License. The default is ``False``.
|
|
631
|
+
control_file : str, optional
|
|
632
|
+
Path to the XML file. The default is ``None``, in which case an attempt is made to find
|
|
633
|
+
the XML file in the same directory as the board file. To succeed, the XML file and board file
|
|
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,
|
|
616
668
|
):
|
|
617
669
|
"""Import a board file and generate an ``edb.def`` file in the working directory.
|
|
618
670
|
|
|
@@ -633,6 +685,12 @@ class Edb(Database):
|
|
|
633
685
|
Path to the XML file. The default is ``None``, in which case an attempt is made to find
|
|
634
686
|
the XML file in the same directory as the board file. To succeed, the XML file and board file
|
|
635
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.
|
|
636
694
|
|
|
637
695
|
Returns
|
|
638
696
|
-------
|
|
@@ -669,6 +727,12 @@ class Edb(Database):
|
|
|
669
727
|
cmd_translator.append("-c={}".format(control_file))
|
|
670
728
|
else:
|
|
671
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))
|
|
672
736
|
p = subprocess.Popen(cmd_translator)
|
|
673
737
|
p.wait()
|
|
674
738
|
if not os.path.exists(os.path.join(working_dir, aedb_name)):
|
|
@@ -1469,7 +1533,7 @@ class Edb(Database):
|
|
|
1469
1533
|
``True`` when successful, ``False`` when failed.
|
|
1470
1534
|
|
|
1471
1535
|
"""
|
|
1472
|
-
if self.
|
|
1536
|
+
if self.import_layout_file(
|
|
1473
1537
|
inputBrd,
|
|
1474
1538
|
working_dir=WorkDir,
|
|
1475
1539
|
anstranslator_full_path=anstranslator_full_path,
|
|
@@ -1479,103 +1543,6 @@ class Edb(Database):
|
|
|
1479
1543
|
else:
|
|
1480
1544
|
return False
|
|
1481
1545
|
|
|
1482
|
-
def import_gds_file(
|
|
1483
|
-
self,
|
|
1484
|
-
inputGDS,
|
|
1485
|
-
anstranslator_full_path="",
|
|
1486
|
-
use_ppe=False,
|
|
1487
|
-
control_file=None,
|
|
1488
|
-
tech_file=None,
|
|
1489
|
-
map_file=None,
|
|
1490
|
-
layer_filter=None,
|
|
1491
|
-
):
|
|
1492
|
-
"""Import a GDS file and generate an ``edb.def`` file in the working directory.
|
|
1493
|
-
|
|
1494
|
-
..note::
|
|
1495
|
-
`ANSYSLMD_LICENSE_FILE` is needed to run the translator.
|
|
1496
|
-
|
|
1497
|
-
Parameters
|
|
1498
|
-
----------
|
|
1499
|
-
inputGDS : str
|
|
1500
|
-
Full path to the GDS file.
|
|
1501
|
-
anstranslator_full_path : str, optional
|
|
1502
|
-
Full path to the Ansys translator.
|
|
1503
|
-
use_ppe : bool, optional
|
|
1504
|
-
Whether to use the PPE License. The default is ``False``.
|
|
1505
|
-
control_file : str, optional
|
|
1506
|
-
Path to the XML file. The default is ``None``, in which case an attempt is made to find
|
|
1507
|
-
the XML file in the same directory as the GDS file. To succeed, the XML file and GDS file must
|
|
1508
|
-
have the same name. Only the extension differs.
|
|
1509
|
-
tech_file : str, optional
|
|
1510
|
-
Technology file. For versions<2024.1 it uses Helic to convert tech file to xml and then imports
|
|
1511
|
-
the gds. Works on Linux only.
|
|
1512
|
-
For versions>=2024.1 it can directly parse through supported foundry tech files.
|
|
1513
|
-
map_file : str, optional
|
|
1514
|
-
Layer map file.
|
|
1515
|
-
layer_filter:str,optional
|
|
1516
|
-
Layer filter file.
|
|
1517
|
-
|
|
1518
|
-
"""
|
|
1519
|
-
control_file_temp = os.path.join(tempfile.gettempdir(), os.path.split(inputGDS)[-1][:-3] + "xml")
|
|
1520
|
-
if float(self.edbversion) < 2024.1:
|
|
1521
|
-
if not is_linux and tech_file:
|
|
1522
|
-
self.logger.error("Technology files are supported only in Linux. Use control file instead.")
|
|
1523
|
-
return False
|
|
1524
|
-
|
|
1525
|
-
ControlFile(xml_input=control_file, tecnhology=tech_file, layer_map=map_file).write_xml(control_file_temp)
|
|
1526
|
-
if self.import_layout_pcb(
|
|
1527
|
-
inputGDS,
|
|
1528
|
-
anstranslator_full_path=anstranslator_full_path,
|
|
1529
|
-
use_ppe=use_ppe,
|
|
1530
|
-
control_file=control_file_temp,
|
|
1531
|
-
):
|
|
1532
|
-
return True
|
|
1533
|
-
else:
|
|
1534
|
-
return False
|
|
1535
|
-
else:
|
|
1536
|
-
if anstranslator_full_path and os.path.exists(anstranslator_full_path):
|
|
1537
|
-
path = anstranslator_full_path
|
|
1538
|
-
else:
|
|
1539
|
-
path = os.path.join(self.base_path, "anstranslator")
|
|
1540
|
-
if is_windows:
|
|
1541
|
-
path += ".exe"
|
|
1542
|
-
|
|
1543
|
-
temp_map_file = os.path.splitext(inputGDS)[0] + ".map"
|
|
1544
|
-
temp_layermap_file = os.path.splitext(inputGDS)[0] + ".layermap"
|
|
1545
|
-
|
|
1546
|
-
if map_file is None:
|
|
1547
|
-
if os.path.isfile(temp_map_file):
|
|
1548
|
-
map_file = temp_map_file
|
|
1549
|
-
elif os.path.isfile(temp_layermap_file):
|
|
1550
|
-
map_file = temp_layermap_file
|
|
1551
|
-
else:
|
|
1552
|
-
self.logger.error("Unable to define map file.")
|
|
1553
|
-
|
|
1554
|
-
if tech_file is None:
|
|
1555
|
-
if control_file is None:
|
|
1556
|
-
temp_control_file = os.path.splitext(inputGDS)[0] + ".xml"
|
|
1557
|
-
if os.path.isfile(temp_control_file):
|
|
1558
|
-
control_file = temp_control_file
|
|
1559
|
-
else:
|
|
1560
|
-
self.logger.error("Unable to define control file.")
|
|
1561
|
-
|
|
1562
|
-
command = [path, inputGDS, f'-g="{map_file}"', f'-c="{control_file}"']
|
|
1563
|
-
else:
|
|
1564
|
-
command = [
|
|
1565
|
-
path,
|
|
1566
|
-
inputGDS,
|
|
1567
|
-
f'-o="{control_file_temp}"' f'-t="{tech_file}"',
|
|
1568
|
-
f'-g="{map_file}"',
|
|
1569
|
-
f'-f="{layer_filter}"',
|
|
1570
|
-
]
|
|
1571
|
-
|
|
1572
|
-
result = subprocess.run(command, capture_output=True, text=True, shell=True)
|
|
1573
|
-
print(result.stdout)
|
|
1574
|
-
print(command)
|
|
1575
|
-
temp_inputGDS = inputGDS.split(".gds")[0]
|
|
1576
|
-
self.edbpath = temp_inputGDS + ".aedb"
|
|
1577
|
-
return self.open_edb()
|
|
1578
|
-
|
|
1579
1546
|
def _create_extent(
|
|
1580
1547
|
self,
|
|
1581
1548
|
net_signals,
|
|
@@ -2274,8 +2274,7 @@ class Components(object):
|
|
|
2274
2274
|
pingroup = PinGroup.create(self._active_layout, group_name, pins)
|
|
2275
2275
|
|
|
2276
2276
|
if pingroup.is_null: # pragma: no cover
|
|
2277
|
-
|
|
2278
|
-
return False
|
|
2277
|
+
raise RuntimeError(f"Failed to create pin group {group_name}.")
|
|
2279
2278
|
else:
|
|
2280
2279
|
for pin in pins:
|
|
2281
2280
|
if not pin.net.is_null:
|
|
@@ -41,6 +41,7 @@ from ansys.edb.core.hierarchy.pin_pair_model import PinPairModel as GrpcPinPairM
|
|
|
41
41
|
from ansys.edb.core.hierarchy.sparameter_model import (
|
|
42
42
|
SParameterModel as GrpcSParameterModel,
|
|
43
43
|
)
|
|
44
|
+
from ansys.edb.core.hierarchy.spice_model import SPICEModel as GrpcSPICEModel
|
|
44
45
|
from ansys.edb.core.primitive.primitive import PadstackInstance as GrpcPadstackInstance
|
|
45
46
|
from ansys.edb.core.terminal.terminals import (
|
|
46
47
|
PadstackInstanceTerminal as GrpcPadstackInstanceTerminal,
|
|
@@ -49,6 +50,7 @@ from ansys.edb.core.utility.rlc import Rlc as GrpcRlc
|
|
|
49
50
|
from ansys.edb.core.utility.value import Value as GrpcValue
|
|
50
51
|
|
|
51
52
|
from pyedb.grpc.database.hierarchy.pin_pair_model import PinPairModel
|
|
53
|
+
from pyedb.grpc.database.hierarchy.s_parameter_model import SparamModel
|
|
52
54
|
from pyedb.grpc.database.hierarchy.spice_model import SpiceModel
|
|
53
55
|
from pyedb.grpc.database.layers.stackup_layer import StackupLayer
|
|
54
56
|
from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
|
|
@@ -204,7 +206,13 @@ class Component(GrpcComponentGroup):
|
|
|
204
206
|
:class:`Model <ansys.edb.core.hierarchy.model.Model>`
|
|
205
207
|
|
|
206
208
|
"""
|
|
207
|
-
|
|
209
|
+
|
|
210
|
+
if isinstance(self.component_property.model, GrpcSPICEModel):
|
|
211
|
+
return SpiceModel(edb_object=self.component_property.model.msg)
|
|
212
|
+
elif isinstance(self.component_property.model, GrpcSParameterModel):
|
|
213
|
+
return SparamModel(edb_object=self.component_property.model.msg)
|
|
214
|
+
else:
|
|
215
|
+
return self.component_property.model
|
|
208
216
|
|
|
209
217
|
@model.setter
|
|
210
218
|
def model(self, value):
|
|
@@ -28,6 +28,6 @@ from ansys.edb.core.hierarchy.sparameter_model import (
|
|
|
28
28
|
class SparamModel(GrpcSParameterModel): # pragma: no cover
|
|
29
29
|
"""Manage :class:`SParameterModel <ansys.edb.core.hierarchy.sparameter_model.SParameterModel>`"""
|
|
30
30
|
|
|
31
|
-
def __init__(self,
|
|
31
|
+
def __init__(self, edb_object):
|
|
32
32
|
super().__init__(self.msg)
|
|
33
|
-
self._edb_model =
|
|
33
|
+
self._edb_model = edb_object
|
|
@@ -81,12 +81,12 @@ class HfssExtentInfo(GrpcHfssExtentInfo):
|
|
|
81
81
|
float
|
|
82
82
|
Air box horizontal extent value.
|
|
83
83
|
"""
|
|
84
|
-
return self._hfss_extent_info.
|
|
84
|
+
return self._hfss_extent_info.airbox_horizontal[0]
|
|
85
85
|
|
|
86
86
|
@air_box_horizontal_extent.setter
|
|
87
87
|
def air_box_horizontal_extent(self, value):
|
|
88
88
|
hfss_extent = self._hfss_extent_info
|
|
89
|
-
hfss_extent.
|
|
89
|
+
hfss_extent.airbox_horizontal = (float(value), True)
|
|
90
90
|
self._update_hfss_extent_info(hfss_extent)
|
|
91
91
|
|
|
92
92
|
@property
|
|
@@ -98,12 +98,12 @@ class HfssExtentInfo(GrpcHfssExtentInfo):
|
|
|
98
98
|
bool.
|
|
99
99
|
|
|
100
100
|
"""
|
|
101
|
-
return self._hfss_extent_info.
|
|
101
|
+
return self._hfss_extent_info.airbox_vertical_positive[1]
|
|
102
102
|
|
|
103
103
|
@air_box_positive_vertical_extent_enabled.setter
|
|
104
104
|
def air_box_positive_vertical_extent_enabled(self, value):
|
|
105
105
|
hfss_exent = self._hfss_extent_info
|
|
106
|
-
hfss_exent.
|
|
106
|
+
hfss_exent.airbox_vertical_positive = (0.15, value)
|
|
107
107
|
self._update_hfss_extent_info(hfss_exent)
|
|
108
108
|
|
|
109
109
|
@property
|
|
@@ -116,12 +116,12 @@ class HfssExtentInfo(GrpcHfssExtentInfo):
|
|
|
116
116
|
Air box positive vertical extent value.
|
|
117
117
|
|
|
118
118
|
"""
|
|
119
|
-
return self._hfss_extent_info.
|
|
119
|
+
return self._hfss_extent_info.airbox_vertical_positive[0]
|
|
120
120
|
|
|
121
121
|
@air_box_positive_vertical_extent.setter
|
|
122
122
|
def air_box_positive_vertical_extent(self, value):
|
|
123
123
|
hfss_extent = self._hfss_extent_info
|
|
124
|
-
hfss_extent.
|
|
124
|
+
hfss_extent.airbox_vertical_positive = (float(value), True)
|
|
125
125
|
self._update_hfss_extent_info(hfss_extent)
|
|
126
126
|
|
|
127
127
|
@property
|
|
@@ -133,12 +133,12 @@ class HfssExtentInfo(GrpcHfssExtentInfo):
|
|
|
133
133
|
bool.
|
|
134
134
|
|
|
135
135
|
"""
|
|
136
|
-
return self._hfss_extent_info.
|
|
136
|
+
return self._hfss_extent_info.airbox_vertical_negative[1]
|
|
137
137
|
|
|
138
138
|
@air_box_negative_vertical_extent_enabled.setter
|
|
139
139
|
def air_box_negative_vertical_extent_enabled(self, value):
|
|
140
140
|
hfss_extent = self._hfss_extent_info
|
|
141
|
-
hfss_extent.
|
|
141
|
+
hfss_extent.airbox_vertical_negative = (0.15, value)
|
|
142
142
|
self._update_hfss_extent_info(hfss_extent)
|
|
143
143
|
|
|
144
144
|
@property
|
|
@@ -151,12 +151,12 @@ class HfssExtentInfo(GrpcHfssExtentInfo):
|
|
|
151
151
|
Air box negative vertical extent value.
|
|
152
152
|
|
|
153
153
|
"""
|
|
154
|
-
return self._hfss_extent_info.
|
|
154
|
+
return self._hfss_extent_info.airbox_vertical_negative[0]
|
|
155
155
|
|
|
156
156
|
@air_box_negative_vertical_extent.setter
|
|
157
157
|
def air_box_negative_vertical_extent(self, value):
|
|
158
158
|
hfss_extent = self._hfss_extent_info
|
|
159
|
-
hfss_extent.
|
|
159
|
+
hfss_extent.airbox_vertical_negative = (float(value), True)
|
|
160
160
|
self._update_hfss_extent_info(hfss_extent)
|
|
161
161
|
|
|
162
162
|
@property
|
|
@@ -183,7 +183,7 @@ class HfssExtentInfo(GrpcHfssExtentInfo):
|
|
|
183
183
|
-------
|
|
184
184
|
:class:`Polygon <pyedb.grpc.database.primitive.polygon.Polygon>`
|
|
185
185
|
"""
|
|
186
|
-
return
|
|
186
|
+
return super().dielectric_base_polygon
|
|
187
187
|
|
|
188
188
|
@dielectric_base_polygon.setter
|
|
189
189
|
def dielectric_base_polygon(self, value):
|
|
@@ -216,12 +216,12 @@ class HfssExtentInfo(GrpcHfssExtentInfo):
|
|
|
216
216
|
float
|
|
217
217
|
Dielectric extent size value.
|
|
218
218
|
"""
|
|
219
|
-
return self._hfss_extent_info.
|
|
219
|
+
return self._hfss_extent_info.dielectric[0]
|
|
220
220
|
|
|
221
221
|
@dielectric_extent_size.setter
|
|
222
222
|
def dielectric_extent_size(self, value):
|
|
223
223
|
hfss_extent = self._hfss_extent_info
|
|
224
|
-
hfss_extent.
|
|
224
|
+
hfss_extent.dielectric = (value, True)
|
|
225
225
|
self._update_hfss_extent_info(hfss_extent)
|
|
226
226
|
|
|
227
227
|
@property
|
|
@@ -256,6 +256,17 @@ class HfssExtentInfo(GrpcHfssExtentInfo):
|
|
|
256
256
|
@extent_type.setter
|
|
257
257
|
def extent_type(self, value):
|
|
258
258
|
hfss_extent = self._hfss_extent_info
|
|
259
|
+
if isinstance(value, str):
|
|
260
|
+
if value.lower() == "bounding_box":
|
|
261
|
+
value = GrpcHfssExtentInfo.HFSSExtentInfoType.BOUNDING_BOX
|
|
262
|
+
elif value.lower() == "conforming":
|
|
263
|
+
value = GrpcHfssExtentInfo.HFSSExtentInfoType.CONFORMING
|
|
264
|
+
elif value.lower() == "convex_hul":
|
|
265
|
+
value = GrpcHfssExtentInfo.HFSSExtentInfoType.CONVEX_HUL
|
|
266
|
+
elif value.lower() == "polygon":
|
|
267
|
+
value = GrpcHfssExtentInfo.HFSSExtentInfoType.POLYGON
|
|
268
|
+
else:
|
|
269
|
+
raise f"Invalid extent type : {value}"
|
|
259
270
|
hfss_extent.extent_type = value
|
|
260
271
|
self._update_hfss_extent_info(hfss_extent)
|
|
261
272
|
|
|
@@ -328,7 +339,7 @@ class HfssExtentInfo(GrpcHfssExtentInfo):
|
|
|
328
339
|
self._update_hfss_extent_info(hfss_extent)
|
|
329
340
|
|
|
330
341
|
@property
|
|
331
|
-
def
|
|
342
|
+
def pml_radiation_factor(self):
|
|
332
343
|
"""PML Radiation level to calculate the thickness of boundary.
|
|
333
344
|
|
|
334
345
|
Returns
|
|
@@ -337,12 +348,12 @@ class HfssExtentInfo(GrpcHfssExtentInfo):
|
|
|
337
348
|
Boundary thickness value.
|
|
338
349
|
|
|
339
350
|
"""
|
|
340
|
-
return
|
|
351
|
+
return self._hfss_extent_info.radiation_level.value
|
|
341
352
|
|
|
342
|
-
@
|
|
343
|
-
def
|
|
353
|
+
@pml_radiation_factor.setter
|
|
354
|
+
def pml_radiation_factor(self, value):
|
|
344
355
|
hfss_extent = self._hfss_extent_info
|
|
345
|
-
hfss_extent.
|
|
356
|
+
hfss_extent.radiation_level = GrpcValue(value)
|
|
346
357
|
self._update_hfss_extent_info(hfss_extent)
|
|
347
358
|
|
|
348
359
|
@property
|
|
@@ -373,12 +384,12 @@ class HfssExtentInfo(GrpcHfssExtentInfo):
|
|
|
373
384
|
Truncate air box at ground.
|
|
374
385
|
|
|
375
386
|
"""
|
|
376
|
-
return self._hfss_extent_info.
|
|
387
|
+
return self._hfss_extent_info.airbox_truncate_at_ground
|
|
377
388
|
|
|
378
389
|
@truncate_air_box_at_ground.setter
|
|
379
390
|
def truncate_air_box_at_ground(self, value):
|
|
380
391
|
hfss_extent = self._hfss_extent_info
|
|
381
|
-
hfss_extent.
|
|
392
|
+
hfss_extent.airbox_truncate_at_ground = value
|
|
382
393
|
self._update_hfss_extent_info(hfss_extent)
|
|
383
394
|
|
|
384
395
|
@property
|