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.

Files changed (58) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_boundaries.py +155 -72
  3. pyedb/configuration/cfg_components.py +1 -1
  4. pyedb/configuration/cfg_general.py +34 -16
  5. pyedb/configuration/cfg_modeler.py +162 -67
  6. pyedb/configuration/cfg_nets.py +33 -17
  7. pyedb/configuration/cfg_operations.py +63 -31
  8. pyedb/configuration/cfg_package_definition.py +113 -52
  9. pyedb/configuration/cfg_padstacks.py +611 -256
  10. pyedb/configuration/cfg_pin_groups.py +75 -33
  11. pyedb/configuration/cfg_ports_sources.py +75 -15
  12. pyedb/configuration/cfg_s_parameter_models.py +125 -70
  13. pyedb/configuration/cfg_setup.py +301 -257
  14. pyedb/configuration/cfg_stackup.py +166 -90
  15. pyedb/configuration/configuration.py +342 -209
  16. pyedb/dotnet/database/edb_data/design_options.py +19 -1
  17. pyedb/dotnet/database/edb_data/padstacks_data.py +16 -6
  18. pyedb/dotnet/database/geometry/polygon_data.py +4 -2
  19. pyedb/dotnet/database/padstack.py +6 -2
  20. pyedb/dotnet/database/sim_setup_data/data/sweep_data.py +63 -10
  21. pyedb/dotnet/database/utilities/simulation_setup.py +14 -30
  22. pyedb/dotnet/database/utilities/siwave_simulation_setup.py +30 -0
  23. pyedb/dotnet/edb.py +75 -105
  24. pyedb/grpc/database/components.py +1 -1
  25. pyedb/grpc/database/definition/component_def.py +15 -0
  26. pyedb/grpc/database/definition/component_pin.py +1 -1
  27. pyedb/grpc/database/definition/materials.py +27 -0
  28. pyedb/grpc/database/definition/package_def.py +20 -2
  29. pyedb/grpc/database/definition/padstack_def.py +5 -2
  30. pyedb/grpc/database/hierarchy/component.py +4 -2
  31. pyedb/grpc/database/hierarchy/pingroup.py +12 -8
  32. pyedb/grpc/database/layers/layer.py +28 -0
  33. pyedb/grpc/database/layers/stackup_layer.py +281 -40
  34. pyedb/grpc/database/layout/layout.py +12 -6
  35. pyedb/grpc/database/modeler.py +8 -8
  36. pyedb/grpc/database/primitive/bondwire.py +3 -3
  37. pyedb/grpc/database/primitive/circle.py +1 -1
  38. pyedb/grpc/database/primitive/padstack_instance.py +13 -3
  39. pyedb/grpc/database/primitive/path.py +2 -2
  40. pyedb/grpc/database/primitive/polygon.py +3 -3
  41. pyedb/grpc/database/primitive/primitive.py +1 -1
  42. pyedb/grpc/database/primitive/rectangle.py +2 -2
  43. pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +73 -30
  44. pyedb/grpc/database/source_excitations.py +7 -7
  45. pyedb/grpc/database/stackup.py +14 -6
  46. pyedb/grpc/database/terminal/bundle_terminal.py +3 -3
  47. pyedb/grpc/database/terminal/edge_terminal.py +2 -2
  48. pyedb/grpc/database/terminal/padstack_instance_terminal.py +42 -2
  49. pyedb/grpc/database/terminal/pingroup_terminal.py +35 -2
  50. pyedb/grpc/database/terminal/point_terminal.py +10 -1
  51. pyedb/grpc/database/terminal/terminal.py +4 -4
  52. pyedb/grpc/database/utility/hfss_extent_info.py +14 -10
  53. pyedb/grpc/edb.py +8 -8
  54. pyedb/misc/misc.py +13 -0
  55. {pyedb-0.42.0.dist-info → pyedb-0.44.0.dist-info}/METADATA +1 -1
  56. {pyedb-0.42.0.dist-info → pyedb-0.44.0.dist-info}/RECORD +58 -58
  57. {pyedb-0.42.0.dist-info → pyedb-0.44.0.dist-info}/LICENSE +0 -0
  58. {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(list_of_point_data, closed)
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 = self._get_edb_value(rotation * math.pi / 180)
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 = start.upper().replace("Z", "z") if isinstance(start, str) else str(start)
528
- stop = stop.upper().replace("Z", "z") if isinstance(stop, str) else str(stop)
529
- increment = increment.upper().replace("Z", "z") if isinstance(increment, str) else int(increment)
530
- if sweep_type in ["linear_count", "linear_scale"]:
531
- freqs = list(self._edb_object.SetFrequencies(start, stop, increment))
532
- elif sweep_type == "log_scale":
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
- raise ValueError("sweep_type must be either 'linear_count', 'linear_scale' or 'log_scale")
536
- return self.add_frequencies(freqs)
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 is None:
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._sweep_list[sweep_data.name] = sweep_data
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._sweep_list:
320
- self._sweep_list.pop(name)
303
+ if name in self.sweeps:
304
+ self.sweeps.pop(name)
321
305
 
322
306
  fsweep = []
323
- if self.frequency_sweeps:
324
- fsweep = [val for key, val in self.frequency_sweeps.items() if not key == name]
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 True if name in self.frequency_sweeps else False
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.import_layout_pcb(edbpath[:-4], working_dir, use_ppe=use_ppe, control_file=control_file)
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.import_layout_pcb(edbpath, working_dir, use_ppe=use_ppe, control_file=control_file)
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.import_layout_pcb(
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
- return HeatSink(self._pedb, super().heat_sink)
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.primitive import Circle as GrpcCircle
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
- return self.data.hole_range.name.lower()
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.primitive import PadstackInstance as GrpcPadstackInstance
46
- from ansys.edb.core.terminal.terminals import (
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