pyedb 0.56.0__py3-none-any.whl → 0.58.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 (110) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_data.py +3 -0
  3. pyedb/configuration/cfg_pin_groups.py +2 -0
  4. pyedb/configuration/cfg_terminals.py +232 -0
  5. pyedb/configuration/configuration.py +146 -3
  6. pyedb/dotnet/clr_module.py +1 -2
  7. pyedb/dotnet/database/Variables.py +30 -22
  8. pyedb/dotnet/database/cell/hierarchy/component.py +2 -8
  9. pyedb/dotnet/database/cell/layout.py +5 -1
  10. pyedb/dotnet/database/cell/primitive/primitive.py +2 -2
  11. pyedb/dotnet/database/cell/terminal/bundle_terminal.py +12 -0
  12. pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
  13. pyedb/dotnet/database/cell/terminal/terminal.py +38 -0
  14. pyedb/dotnet/database/components.py +15 -19
  15. pyedb/dotnet/database/dotnet/database.py +1 -0
  16. pyedb/dotnet/database/edb_data/control_file.py +19 -8
  17. pyedb/dotnet/database/edb_data/nets_data.py +3 -3
  18. pyedb/dotnet/database/edb_data/padstacks_data.py +39 -14
  19. pyedb/dotnet/database/edb_data/ports.py +0 -25
  20. pyedb/dotnet/database/edb_data/primitives_data.py +3 -3
  21. pyedb/dotnet/database/edb_data/raptor_x_simulation_setup_data.py +18 -19
  22. pyedb/dotnet/database/edb_data/simulation_configuration.py +3 -3
  23. pyedb/dotnet/database/edb_data/sources.py +21 -2
  24. pyedb/dotnet/database/general.py +1 -6
  25. pyedb/dotnet/database/hfss.py +9 -8
  26. pyedb/dotnet/database/layout_validation.py +14 -3
  27. pyedb/dotnet/database/materials.py +1 -3
  28. pyedb/dotnet/database/modeler.py +7 -3
  29. pyedb/dotnet/database/nets.py +27 -19
  30. pyedb/dotnet/database/padstack.py +4 -2
  31. pyedb/dotnet/database/sim_setup_data/io/siwave.py +54 -1
  32. pyedb/dotnet/database/siwave.py +4 -3
  33. pyedb/dotnet/database/stackup.py +55 -58
  34. pyedb/dotnet/database/utilities/heatsink.py +0 -1
  35. pyedb/dotnet/database/utilities/hfss_simulation_setup.py +81 -0
  36. pyedb/dotnet/database/utilities/simulation_setup.py +7 -5
  37. pyedb/dotnet/database/utilities/siwave_cpa_simulation_setup.py +1 -0
  38. pyedb/dotnet/database/utilities/siwave_simulation_setup.py +264 -13
  39. pyedb/dotnet/edb.py +65 -47
  40. pyedb/exceptions.py +1 -2
  41. pyedb/extensions/create_cell_array.py +67 -49
  42. pyedb/generic/data_handlers.py +13 -23
  43. pyedb/generic/design_types.py +9 -35
  44. pyedb/generic/filesystem.py +4 -2
  45. pyedb/generic/general_methods.py +28 -41
  46. pyedb/generic/plot.py +8 -23
  47. pyedb/generic/process.py +78 -10
  48. pyedb/grpc/database/_typing.py +0 -0
  49. pyedb/grpc/database/components.py +14 -13
  50. pyedb/grpc/database/control_file.py +27 -40
  51. pyedb/grpc/database/definition/materials.py +1 -1
  52. pyedb/grpc/database/definition/package_def.py +6 -3
  53. pyedb/grpc/database/definition/padstack_def.py +14 -12
  54. pyedb/grpc/database/hfss.py +1 -4
  55. pyedb/grpc/database/hierarchy/component.py +5 -13
  56. pyedb/grpc/database/hierarchy/pingroup.py +16 -3
  57. pyedb/grpc/database/layers/layer.py +1 -2
  58. pyedb/grpc/database/layers/stackup_layer.py +42 -19
  59. pyedb/grpc/database/layout/layout.py +43 -27
  60. pyedb/grpc/database/layout/voltage_regulator.py +6 -1
  61. pyedb/grpc/database/layout_validation.py +5 -2
  62. pyedb/grpc/database/modeler.py +254 -252
  63. pyedb/grpc/database/net/differential_pair.py +9 -2
  64. pyedb/grpc/database/net/extended_net.py +24 -9
  65. pyedb/grpc/database/net/net.py +14 -5
  66. pyedb/grpc/database/net/net_class.py +24 -7
  67. pyedb/grpc/database/nets.py +11 -43
  68. pyedb/grpc/database/padstacks.py +67 -119
  69. pyedb/grpc/database/primitive/bondwire.py +3 -67
  70. pyedb/grpc/database/primitive/circle.py +42 -3
  71. pyedb/grpc/database/primitive/padstack_instance.py +58 -31
  72. pyedb/grpc/database/primitive/path.py +160 -11
  73. pyedb/grpc/database/primitive/polygon.py +73 -7
  74. pyedb/grpc/database/primitive/primitive.py +2 -2
  75. pyedb/grpc/database/primitive/rectangle.py +105 -4
  76. pyedb/grpc/database/simulation_setup/hfss_general_settings.py +0 -2
  77. pyedb/grpc/database/simulation_setup/hfss_settings_options.py +0 -4
  78. pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +79 -0
  79. pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +1 -0
  80. pyedb/grpc/database/simulation_setup/sweep_data.py +1 -3
  81. pyedb/grpc/database/siwave.py +6 -13
  82. pyedb/grpc/database/source_excitations.py +46 -63
  83. pyedb/grpc/database/stackup.py +55 -60
  84. pyedb/grpc/database/terminal/bundle_terminal.py +10 -3
  85. pyedb/grpc/database/terminal/padstack_instance_terminal.py +9 -11
  86. pyedb/grpc/database/terminal/pingroup_terminal.py +8 -1
  87. pyedb/grpc/database/terminal/point_terminal.py +30 -0
  88. pyedb/grpc/database/terminal/terminal.py +35 -10
  89. pyedb/grpc/database/utility/heat_sink.py +0 -1
  90. pyedb/grpc/database/utility/hfss_extent_info.py +2 -2
  91. pyedb/grpc/database/utility/xml_control_file.py +19 -8
  92. pyedb/grpc/edb.py +63 -32
  93. pyedb/grpc/edb_init.py +1 -0
  94. pyedb/ipc2581/ecad/cad_data/layer_feature.py +6 -2
  95. pyedb/ipc2581/ecad/cad_data/step.py +1 -1
  96. pyedb/ipc2581/ipc2581.py +8 -7
  97. pyedb/libraries/common.py +3 -4
  98. pyedb/libraries/rf_libraries/base_functions.py +7 -16
  99. pyedb/libraries/rf_libraries/planar_antennas.py +3 -21
  100. pyedb/misc/aedtlib_personalib_install.py +2 -2
  101. pyedb/misc/downloads.py +19 -3
  102. pyedb/misc/misc.py +5 -2
  103. pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +3 -2
  104. pyedb/misc/siw_feature_config/xtalk_scan/scan_config.py +0 -1
  105. pyedb/misc/utilities.py +0 -1
  106. pyedb/modeler/geometry_operators.py +3 -2
  107. {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/METADATA +6 -7
  108. {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/RECORD +110 -108
  109. {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/WHEEL +0 -0
  110. {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/licenses/LICENSE +0 -0
pyedb/__init__.py CHANGED
@@ -37,7 +37,7 @@ deprecation_warning()
37
37
  #
38
38
 
39
39
  pyedb_path = os.path.dirname(__file__)
40
- __version__ = "0.56.0"
40
+ __version__ = "0.58.0"
41
41
  version = __version__
42
42
 
43
43
  #
@@ -36,6 +36,7 @@ from pyedb.configuration.cfg_s_parameter_models import CfgSParameters
36
36
  from pyedb.configuration.cfg_setup import CfgSetups
37
37
  from pyedb.configuration.cfg_spice_models import CfgSpiceModel
38
38
  from pyedb.configuration.cfg_stackup import CfgStackup
39
+ from pyedb.configuration.cfg_terminals import CfgTerminals
39
40
 
40
41
 
41
42
  class CfgData(object):
@@ -59,6 +60,8 @@ class CfgData(object):
59
60
 
60
61
  self.pin_groups = CfgPinGroups(self._pedb, pingroup_data=kwargs.get("pin_groups", []))
61
62
 
63
+ self.terminals = CfgTerminals.create(terminals=kwargs.get("terminals", []))
64
+
62
65
  self.ports = CfgPorts(self._pedb, ports_data=kwargs.get("ports", []))
63
66
 
64
67
  self.sources = CfgSources(self._pedb, sources_data=kwargs.get("sources", []))
@@ -35,6 +35,8 @@ class CfgPinGroups:
35
35
  layout_pin_groups = self._pedb.siwave.pin_groups
36
36
  for pg_name, pg_obj in layout_pin_groups.items():
37
37
  pins = list(pg_obj.pins.keys())
38
+ if len(pins) == 0: # pragma: no cover
39
+ continue
38
40
  refdes = list(pg_obj.pins.values())[0].component.name
39
41
  cfg_pg = CfgPinGroup(
40
42
  self._pedb,
@@ -0,0 +1,232 @@
1
+ from typing import List, Literal, Optional, Union
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class CfgBase(BaseModel):
7
+ model_config = {
8
+ "populate_by_name": True,
9
+ "extra": "forbid",
10
+ }
11
+
12
+
13
+ class CfgTerminal(CfgBase):
14
+ name: str
15
+ impedance: Union[float, int, str]
16
+ is_circuit_port: bool
17
+ reference_terminal: Optional[str] = None
18
+ amplitude: Optional[Union[float, int, str]] = 1
19
+ phase: Optional[Union[float, int, str]] = 0
20
+ terminal_to_ground: Optional[Literal["kNoGround", "kNegative", "kPositive"]] = "kNoGround"
21
+ boundary_type: Literal[
22
+ "PortBoundary",
23
+ "PecBoundary",
24
+ "RlcBoundary",
25
+ "kCurrentSource",
26
+ "kVoltageSource",
27
+ "kNexximGround",
28
+ "kNexximPort",
29
+ "kDcTerminal",
30
+ "kVoltageProbe",
31
+ "InvalidBoundary",
32
+ ]
33
+ hfss_type: Literal["Wave", "Gap", None]
34
+
35
+
36
+ class CfgPadstackInstanceTerminal(CfgTerminal):
37
+ terminal_type: str = "padstack_instance"
38
+ padstack_instance: str
39
+ padstack_instance_id: Optional[int] = None
40
+ layer: Optional[Union[str, None]] = None
41
+
42
+
43
+ class CfgPinGroupTerminal(CfgTerminal):
44
+ terminal_type: str = "pin_group"
45
+ is_circuit_port: bool = True
46
+ pin_group: str
47
+
48
+
49
+ class CfgPointTerminal(CfgTerminal):
50
+ terminal_type: str = "point"
51
+ x: Union[float, int, str]
52
+ y: Union[float, int, str]
53
+ layer: str
54
+ net: str
55
+
56
+
57
+ class CfgEdgeTerminal(CfgTerminal):
58
+ terminal_type: str = "edge"
59
+ name: str
60
+ primitive: str
61
+ point_on_edge_x: Union[float, int, str]
62
+ point_on_edge_y: Union[float, int, str]
63
+ horizontal_extent_factor: Union[int, str]
64
+ vertical_extent_factor: Union[int, str]
65
+ pec_launch_width: Union[int, str]
66
+
67
+
68
+ class CfgBundleTerminal(CfgBase):
69
+ terminal_type: str = "bundle"
70
+ terminals: List[str]
71
+ name: str
72
+
73
+
74
+ class CfgTerminals(CfgBase):
75
+ terminals: List[
76
+ Union[
77
+ CfgPadstackInstanceTerminal, CfgPinGroupTerminal, CfgPointTerminal, CfgEdgeTerminal, CfgBundleTerminal, dict
78
+ ]
79
+ ]
80
+
81
+ @classmethod
82
+ def create(cls, terminals: List[dict]):
83
+ manager = cls(terminals=[])
84
+ for i in terminals:
85
+ terminal_type = i.pop("terminal_type")
86
+ if terminal_type == "padstack_instance":
87
+ manager.add_padstack_instance_terminal(**i)
88
+ elif terminal_type == "pin_group":
89
+ manager.add_pin_group_terminal(**i)
90
+ elif terminal_type == "point":
91
+ manager.add_point_terminal(**i)
92
+ elif terminal_type == "edge":
93
+ manager.add_edge_terminal(**i)
94
+ elif terminal_type == "bundle":
95
+ manager.add_bundle_terminal(**i)
96
+ else: # pragma: no cover
97
+ raise ValueError(f"Unknown terminal type: {terminal_type}")
98
+ return manager
99
+
100
+ def add_padstack_instance_terminal(
101
+ self,
102
+ padstack_instance,
103
+ name,
104
+ impedance,
105
+ is_circuit_port,
106
+ boundary_type,
107
+ hfss_type,
108
+ reference_terminal=None,
109
+ amplitude=1,
110
+ phase=0,
111
+ terminal_to_ground="kNoGround",
112
+ padstack_instance_id=None,
113
+ layer=None,
114
+ ):
115
+ terminal = CfgPadstackInstanceTerminal(
116
+ padstack_instance=padstack_instance,
117
+ name=name,
118
+ impedance=impedance,
119
+ is_circuit_port=is_circuit_port,
120
+ boundary_type=boundary_type,
121
+ reference_terminal=reference_terminal,
122
+ amplitude=amplitude,
123
+ phase=phase,
124
+ terminal_to_ground=terminal_to_ground,
125
+ layer=layer,
126
+ hfss_type=hfss_type,
127
+ padstack_instance_id=padstack_instance_id,
128
+ )
129
+ self.terminals.append(terminal)
130
+
131
+ def add_pin_group_terminal(
132
+ self,
133
+ pin_group,
134
+ name,
135
+ impedance,
136
+ boundary_type,
137
+ reference_terminal=None,
138
+ amplitude=1,
139
+ phase=0,
140
+ terminal_to_ground="kNoGround",
141
+ ):
142
+ terminal = CfgPinGroupTerminal(
143
+ pin_group=pin_group,
144
+ name=name,
145
+ impedance=impedance,
146
+ is_circuit_port=True,
147
+ boundary_type=boundary_type,
148
+ reference_terminal=reference_terminal,
149
+ amplitude=amplitude,
150
+ phase=phase,
151
+ terminal_to_ground=terminal_to_ground,
152
+ hfss_type=None,
153
+ )
154
+ self.terminals.append(terminal)
155
+
156
+ def add_point_terminal(
157
+ self,
158
+ x,
159
+ y,
160
+ layer,
161
+ name,
162
+ impedance,
163
+ boundary_type,
164
+ net,
165
+ reference_terminal=None,
166
+ amplitude=1,
167
+ phase=0,
168
+ terminal_to_ground="kNoGround",
169
+ ):
170
+ terminal = CfgPointTerminal(
171
+ x=x,
172
+ y=y,
173
+ layer=layer,
174
+ name=name,
175
+ impedance=impedance,
176
+ is_circuit_port=True,
177
+ boundary_type=boundary_type,
178
+ reference_terminal=reference_terminal,
179
+ amplitude=amplitude,
180
+ phase=phase,
181
+ net=net,
182
+ terminal_to_ground=terminal_to_ground,
183
+ hfss_type=None,
184
+ )
185
+ self.terminals.append(terminal)
186
+
187
+ def add_edge_terminal(
188
+ self,
189
+ name,
190
+ impedance,
191
+ is_circuit_port,
192
+ boundary_type,
193
+ primitive,
194
+ point_on_edge_x,
195
+ point_on_edge_y,
196
+ horizontal_extent_factor=6,
197
+ vertical_extent_factor=8,
198
+ pec_launch_width="0.02mm",
199
+ reference_terminal=None,
200
+ amplitude=1,
201
+ phase=0,
202
+ terminal_to_ground="kNoGround",
203
+ ):
204
+ terminal = CfgEdgeTerminal(
205
+ name=name,
206
+ impedance=impedance,
207
+ is_circuit_port=is_circuit_port,
208
+ boundary_type=boundary_type,
209
+ reference_terminal=reference_terminal,
210
+ amplitude=amplitude,
211
+ phase=phase,
212
+ terminal_to_ground=terminal_to_ground,
213
+ primitive=primitive,
214
+ point_on_edge_x=point_on_edge_x,
215
+ point_on_edge_y=point_on_edge_y,
216
+ horizontal_extent_factor=horizontal_extent_factor,
217
+ vertical_extent_factor=vertical_extent_factor,
218
+ pec_launch_width=pec_launch_width,
219
+ hfss_type="Wave",
220
+ )
221
+ self.terminals.append(terminal)
222
+
223
+ def add_bundle_terminal(
224
+ self,
225
+ terminals,
226
+ name,
227
+ ):
228
+ terminal = CfgBundleTerminal(
229
+ terminals=terminals,
230
+ name=name,
231
+ )
232
+ self.terminals.append(terminal)
@@ -29,6 +29,8 @@ import toml
29
29
 
30
30
  from pyedb import Edb
31
31
  from pyedb.configuration.cfg_data import CfgData
32
+ from pyedb.dotnet.database.general import convert_py_list_to_net_list
33
+ from pyedb.misc.decorators import execution_timer
32
34
 
33
35
 
34
36
  class Configuration:
@@ -146,8 +148,9 @@ class Configuration:
146
148
  self.__apply_with_logging("Applying package definitions", self.cfg_data.package_definitions.apply)
147
149
  self.__apply_with_logging("Applying modeler", self.apply_modeler)
148
150
  self.__apply_with_logging("Placing ports", self.cfg_data.ports.apply)
151
+ self.apply_terminals()
149
152
  self.__apply_with_logging("Placing probes", self.cfg_data.probes.apply)
150
- self.__apply_with_logging("Applying operations", self.apply_operations)
153
+ self.apply_operations()
151
154
 
152
155
  return True
153
156
 
@@ -433,6 +436,9 @@ class Configuration:
433
436
  setups = self.cfg_data.setups
434
437
  setups.retrieve_parameters_from_edb()
435
438
  data["setups"] = setups.to_dict()
439
+ if kwargs.get("terminals", False):
440
+ self.get_terminals()
441
+ data.update(self.cfg_data.terminals.model_dump(exclude_none=True))
436
442
  if kwargs.get("sources", False):
437
443
  data["sources"] = self.cfg_data.sources.get_data_from_db()
438
444
  if kwargs.get("ports", False):
@@ -472,6 +478,7 @@ class Configuration:
472
478
 
473
479
  return data
474
480
 
481
+ @execution_timer("Applying operations")
475
482
  def apply_operations(self):
476
483
  """Apply operations to the current design."""
477
484
  op_cutout = self.cfg_data.operations.cutout
@@ -530,6 +537,138 @@ class Configuration:
530
537
  signal_list=signal_list,
531
538
  )
532
539
 
540
+ @execution_timer("Placing terminals")
541
+ def apply_terminals(self):
542
+ terminals_dict = {}
543
+ bungle_terminals = []
544
+ edge_terminals = {}
545
+ for cfg_terminal in self.cfg_data.terminals.terminals:
546
+ if cfg_terminal.terminal_type == "padstack_instance":
547
+ if cfg_terminal.padstack_instance_id:
548
+ pds = self._pedb.layout.find_padstack_instances(
549
+ instance_id=cfg_terminal.padstack_instance_id,
550
+ aedt_name=None,
551
+ component_name=None,
552
+ component_pin_name=None,
553
+ )[0]
554
+ else:
555
+ pds = self._pedb.layout.find_padstack_instances(
556
+ instance_id=None,
557
+ aedt_name=cfg_terminal.padstack_instance,
558
+ component_name=None,
559
+ component_pin_name=None,
560
+ )[0]
561
+ terminal = pds.create_terminal(name=cfg_terminal.name)
562
+
563
+ elif cfg_terminal.terminal_type == "pin_group":
564
+ pg = self._pedb.siwave.pin_groups[cfg_terminal.pin_group]
565
+ terminal = pg.create_terminal(name=cfg_terminal.name)
566
+ elif cfg_terminal.terminal_type == "point":
567
+ terminal = self._pedb.get_point_terminal(
568
+ cfg_terminal.name, cfg_terminal.net, [cfg_terminal.x, cfg_terminal.y], cfg_terminal.layer
569
+ )
570
+ elif cfg_terminal.terminal_type == "edge":
571
+ pt = self._pedb.pedb_class.database.geometry.point_data.PointData.create_from_xy(
572
+ self._pedb, x=cfg_terminal.point_on_edge_x, y=cfg_terminal.point_on_edge_y
573
+ )
574
+ primitive = self._pedb.layout.primitives_by_aedt_name[cfg_terminal.primitive]
575
+ edge = self._pedb.core.Cell.Terminal.PrimitiveEdge.Create(primitive._edb_object, pt._edb_object)
576
+ edge = convert_py_list_to_net_list(edge, self._pedb.core.Cell.Terminal.Edge)
577
+ _terminal = self._pedb.core.Cell.Terminal.EdgeTerminal.Create(
578
+ primitive._edb_object.GetLayout(),
579
+ primitive._edb_object.GetNet(),
580
+ cfg_terminal.name,
581
+ edge,
582
+ isRef=False,
583
+ )
584
+ terminal = self._pedb.pedb_class.database.cell.terminal.edge_terminal.EdgeTerminal(
585
+ self._pedb, _terminal
586
+ )
587
+ terminal.horizontal_extent_factor = terminal.horizontal_extent_factor
588
+ terminal.vertical_extent_factor = terminal.vertical_extent_factor
589
+ terminal.pec_launch_width = terminal.pec_launch_width
590
+ terminal.do_renormalize = True
591
+ edge_terminals[cfg_terminal.name] = terminal
592
+ elif cfg_terminal.terminal_type == "bundle":
593
+ bungle_terminals.append(cfg_terminal)
594
+ continue
595
+ else:
596
+ self._pedb.logger.warning(f"Terminal type {cfg_terminal.terminal_type} not supported.")
597
+ continue
598
+
599
+ terminal.impedance = cfg_terminal.impedance
600
+ terminal.is_circuit_port = cfg_terminal.is_circuit_port
601
+ terminal.boundary_type = cfg_terminal.boundary_type
602
+ terminal.source_amplitude = cfg_terminal.amplitude
603
+ terminal.source_phase = cfg_terminal.phase
604
+ terminal.terminal_to_ground = cfg_terminal.terminal_to_ground
605
+
606
+ terminals_dict[cfg_terminal.name] = cfg_terminal, terminal
607
+
608
+ for _, obj in terminals_dict.items():
609
+ cfg, obj = obj
610
+ if cfg.reference_terminal:
611
+ obj.reference_terminal = terminals_dict[cfg.reference_terminal][1]
612
+
613
+ for i in bungle_terminals:
614
+ boundle_terminal = self._pedb.pedb_class.database.cell.terminal.bundle_terminal.BundleTerminal.create(
615
+ self._pedb, i.name, i.terminals
616
+ )
617
+ bundle_term = boundle_terminal.terminals
618
+ bundle_term[0].name = i.name + ":T1"
619
+ bundle_term[1].mame = i.name + ":T2"
620
+
621
+ @execution_timer("Retrieving terminal information")
622
+ def get_terminals(self):
623
+ manager = self.cfg_data.terminals
624
+ manager.terminals = []
625
+ for i in self._pedb.terminals.values():
626
+ if i.terminal_type == "PadstackInstanceTerminal":
627
+ manager.add_padstack_instance_terminal(
628
+ padstack_instance=i.padstack_instance.aedt_name,
629
+ padstack_instance_id=i.padstack_instance.id,
630
+ name=i.name,
631
+ impedance=i.impedance,
632
+ is_circuit_port=i.is_circuit_port,
633
+ boundary_type=i.boundary_type,
634
+ amplitude=i.source_amplitude,
635
+ phase=i.source_phase,
636
+ terminal_to_ground=i.terminal_to_ground,
637
+ reference_terminal=i.reference_terminal.name if i.reference_terminal else None,
638
+ hfss_type=i.hfss_type if i.hfss_type else "Wave",
639
+ )
640
+ elif i.terminal_type == "PinGroupTerminal":
641
+ manager.add_pin_group_terminal(
642
+ pin_group=i.pin_group().name,
643
+ name=i.name,
644
+ impedance=i.impedance,
645
+ boundary_type=i.boundary_type,
646
+ reference_terminal=i.reference_terminal.name if i.reference_terminal else None,
647
+ amplitude=i.source_amplitude,
648
+ phase=i.source_phase,
649
+ terminal_to_ground=i.terminal_to_ground,
650
+ )
651
+ elif i.terminal_type == "PointTerminal":
652
+ manager.add_point_terminal(
653
+ x=i.location[0],
654
+ y=i.location[1],
655
+ layer=i.layer.name,
656
+ name=i.name,
657
+ impedance=i.impedance,
658
+ boundary_type=i.boundary_type,
659
+ reference_terminal=i.reference_terminal.name if i.reference_terminal else None,
660
+ amplitude=i.source_amplitude,
661
+ phase=i.source_phase,
662
+ terminal_to_ground=i.terminal_to_ground,
663
+ net=i.net_name,
664
+ )
665
+ elif i.terminal_type == "EdgeTerminal":
666
+ pass
667
+ elif i.terminal_type == "BundleTerminal":
668
+ pass
669
+ else: # pragma: no cover
670
+ raise RuntimeError(f"Terminal type {i.terminal_type} not supported.")
671
+
533
672
  def export(
534
673
  self,
535
674
  file_path,
@@ -547,6 +686,7 @@ class Configuration:
547
686
  padstacks=True,
548
687
  general=True,
549
688
  variables=True,
689
+ terminals=False,
550
690
  ):
551
691
  """Export the configuration data from layout to a file.
552
692
 
@@ -561,9 +701,9 @@ class Configuration:
561
701
  setups : bool
562
702
  Whether to export setups or not.
563
703
  sources : bool
564
- Whether to export sources or not.
704
+ Whether to export sources or not. Alternative to terminals.
565
705
  ports : bool
566
- Whether to export ports or not.
706
+ Whether to export ports or not. Alternative to terminals.
567
707
  nets : bool
568
708
  Whether to export nets.
569
709
  pin_groups : bool
@@ -582,6 +722,8 @@ class Configuration:
582
722
  Whether to export general information.
583
723
  variables : bool
584
724
  Whether to export variable.
725
+ terminals : bool
726
+ Whether to export terminals. Alternative to ports and sources.
585
727
  Returns
586
728
  -------
587
729
  bool
@@ -601,6 +743,7 @@ class Configuration:
601
743
  padstacks=padstacks,
602
744
  general=general,
603
745
  variables=variables,
746
+ terminals=terminals,
604
747
  )
605
748
 
606
749
  file_path = file_path if isinstance(file_path, Path) else Path(file_path)
@@ -51,8 +51,7 @@ if is_linux: # pragma: no cover
51
51
  # TODO: Fall backing to dotnetcore2 should be removed in a near future.
52
52
  except Exception:
53
53
  warnings.warn(
54
- "Unable to set .NET root and locate the runtime configuration file. "
55
- "Falling back to using dotnetcore2."
54
+ "Unable to set .NET root and locate the runtime configuration file. Falling back to using dotnetcore2."
56
55
  )
57
56
  warnings.warn(LINUX_WARNING)
58
57
 
@@ -35,9 +35,12 @@ Examples
35
35
 
36
36
  """
37
37
 
38
- from __future__ import absolute_import # noreorder
39
- from __future__ import division
38
+ from __future__ import (
39
+ absolute_import, # noreorder
40
+ division,
41
+ )
40
42
 
43
+ import ast
41
44
  import os
42
45
  import re
43
46
  import types
@@ -493,13 +496,13 @@ class VariableManager(object):
493
496
  --------
494
497
  >>> hfss = Hfss()
495
498
  >>> print(hfss.variable_manager.decompose("5mm"))
496
- >>> (5.0, 'mm')
499
+ >>> (5.0, "mm")
497
500
  >>> hfss["v1"] = "3N"
498
501
  >>> print(hfss.variable_manager.decompose("v1"))
499
- >>> (3.0, 'N')
502
+ >>> (3.0, "N")
500
503
  >>> hfss["v2"] = "2*v1"
501
504
  >>> print(hfss.variable_manager.decompose("v2"))
502
- >>> (6.0, 'N')
505
+ >>> (6.0, "N")
503
506
  """
504
507
  if variable_value in self.independent_variable_names:
505
508
  val, unit = decompose_variable_value(self[variable_value].expression)
@@ -1009,8 +1012,13 @@ class VariableManager(object):
1009
1012
  creating the property if it does not already exist. Also make
1010
1013
  it read-only and hidden and add a description.
1011
1014
 
1012
- >>> aedtapp.variable_manager.set_variable(variable_name="p2", expression="10mm", readonly=True, hidden=True,
1013
- ... description="This is the description of this variable.")
1015
+ >>> aedtapp.variable_manager.set_variable(
1016
+ ... variable_name="p2",
1017
+ ... expression="10mm",
1018
+ ... readonly=True,
1019
+ ... hidden=True,
1020
+ ... description="This is the description of this variable.",
1021
+ ... )
1014
1022
 
1015
1023
  Set the value of the project variable ``$p1`` to ``"30mm"``,
1016
1024
  creating the variable if it does not exist.
@@ -1073,8 +1081,8 @@ class VariableManager(object):
1073
1081
  desktop_object.Undo()
1074
1082
  self._logger.clear_messages()
1075
1083
  return
1076
- except:
1077
- pass
1084
+ except Exception:
1085
+ self._logger.debug(f"Something went wrong when deleting '{variable_name}'.")
1078
1086
  else:
1079
1087
  raise Exception("Unhandled input type to the design property or project variable.") # pragma: no cover
1080
1088
 
@@ -1204,8 +1212,8 @@ class VariableManager(object):
1204
1212
  ]
1205
1213
  )
1206
1214
  return True
1207
- except:
1208
- pass
1215
+ except Exception:
1216
+ self._logger.debug("Failed to change desktop object property.")
1209
1217
  return False
1210
1218
 
1211
1219
  def delete_variable(self, var_name): # pragma: no cover
@@ -1244,8 +1252,8 @@ class VariableManager(object):
1244
1252
  ],
1245
1253
  ]
1246
1254
  )
1247
- except: # pragma: no cover
1248
- pass
1255
+ except Exception: # pragma: no cover
1256
+ self._logger.debug("Failed to change desktop object property.")
1249
1257
  else:
1250
1258
  self._cleanup_variables()
1251
1259
  return True
@@ -1411,8 +1419,8 @@ class Variable(object):
1411
1419
  if result:
1412
1420
  break
1413
1421
  i += 1
1414
- except:
1415
- pass
1422
+ except Exception:
1423
+ self._app.logger.debug(f"Failed to set property '{prop}' value.")
1416
1424
 
1417
1425
  def _get_prop_val(self, prop): # pragma: no cover
1418
1426
  if self._app.design_type == "Maxwell Circuit":
@@ -1432,8 +1440,8 @@ class Variable(object):
1432
1440
  else:
1433
1441
  name = "LocalVariables"
1434
1442
  return self._app.get_oo_object(self._aedt_obj, "{}/{}".format(name, self._variable_name)).GetPropValue(prop)
1435
- except:
1436
- pass
1443
+ except Exception:
1444
+ self._app.logger.debug(f"Failed to get property '{prop}' value.")
1437
1445
 
1438
1446
  @property
1439
1447
  def name(self): # pragma: no cover
@@ -1642,7 +1650,7 @@ class Variable(object):
1642
1650
  def numeric_value(self): # pragma: no cover
1643
1651
  """Numeric part of the expression as a float value."""
1644
1652
  if is_array(self._value):
1645
- return list(eval(self._value))
1653
+ return list(ast.literal_eval(self._value))
1646
1654
  try:
1647
1655
  var_obj = self._aedt_obj.GetChildObject("Variables").GetChildObject(self._variable_name)
1648
1656
  val, _ = decompose_variable_value(var_obj.GetPropEvaluatedValue("EvaluatedValue"))
@@ -1708,7 +1716,7 @@ class Variable(object):
1708
1716
  >>> hfss = Hfss()
1709
1717
  >>> hfss["v1"] = "3N"
1710
1718
  >>> print(hfss.variable_manager["v1"].decompose("v1"))
1711
- >>> (3.0, 'N')
1719
+ >>> (3.0, "N")
1712
1720
 
1713
1721
  """
1714
1722
  return decompose_variable_value(self.evaluated_value)
@@ -1760,9 +1768,9 @@ class Variable(object):
1760
1768
  >>> from pyedb.dotnet.database.Variables import Variable
1761
1769
 
1762
1770
  >>> v = Variable("10W")
1763
- >>> assert v.format("f") == '10.000000W'
1764
- >>> assert v.format("06.2f") == '010.00W'
1765
- >>> assert v.format("6.2f") == ' 10.00W'
1771
+ >>> assert v.format("f") == "10.000000W"
1772
+ >>> assert v.format("06.2f") == "010.00W"
1773
+ >>> assert v.format("6.2f") == " 10.00W"
1766
1774
 
1767
1775
  """
1768
1776
  return ("{0:" + format + "}{1}").format(self.numeric_value, self._units)
@@ -25,6 +25,8 @@ import re
25
25
  from typing import Optional
26
26
  import warnings
27
27
 
28
+ import numpy as np
29
+
28
30
  from pyedb.dotnet.database.cell.hierarchy.hierarchy_obj import Group
29
31
  from pyedb.dotnet.database.cell.hierarchy.model import PinPairModel, SPICEModel
30
32
  from pyedb.dotnet.database.cell.hierarchy.netlist_model import NetlistModel
@@ -33,14 +35,6 @@ from pyedb.dotnet.database.cell.hierarchy.s_parameter_model import SparamModel
33
35
  from pyedb.dotnet.database.cell.hierarchy.spice_model import SpiceModel
34
36
  from pyedb.dotnet.database.definition.package_def import PackageDef
35
37
  from pyedb.dotnet.database.edb_data.padstacks_data import EDBPadstackInstance
36
-
37
- try:
38
- import numpy as np
39
- except ImportError:
40
- warnings.warn(
41
- "The NumPy module is required to run some functionalities of EDB.\n"
42
- "Install with \n\npip install numpy\n\nRequires CPython."
43
- )
44
38
  from pyedb.generic.general_methods import get_filename_without_extension
45
39
 
46
40
 
@@ -23,6 +23,7 @@
23
23
  """
24
24
  This module contains these classes: `EdbLayout` and `Shape`.
25
25
  """
26
+
26
27
  from typing import List, Union
27
28
 
28
29
  from pyedb.dotnet.database.cell.hierarchy.component import EDBComponent
@@ -55,6 +56,8 @@ from pyedb.dotnet.database.utilities.obj_base import ObjBase
55
56
 
56
57
 
57
58
  def primitive_cast(pedb, edb_object):
59
+ if not hasattr(edb_object, "GetPrimitiveType"):
60
+ return
58
61
  if edb_object.GetPrimitiveType().ToString() == "Rectangle":
59
62
  return EdbRectangle(edb_object, pedb)
60
63
  elif edb_object.GetPrimitiveType().ToString() == "Circle":
@@ -234,7 +237,7 @@ class Layout(ObjBase):
234
237
  primitives = list(self._edb_object.Primitives)
235
238
  if len(primitives) != len(self._primitives):
236
239
  self._primitives = [primitive_cast(self._pedb, p) for p in primitives]
237
- return self._primitives
240
+ return [p for p in self._primitives if p is not None] # non stackup primitives are None
238
241
 
239
242
  @property
240
243
  def primitives_by_aedt_name(self) -> dict:
@@ -407,6 +410,7 @@ class Layout(ObjBase):
407
410
  candidates = self.padstack_instances
408
411
  if instance_id is not None:
409
412
  value = instance_id if isinstance(instance_id, list) else [instance_id]
413
+ value = [int(i) for i in value]
410
414
  candidates = [i for i in candidates if i.id in value]
411
415
 
412
416
  if aedt_name is not None: