pyedb 0.55.0__py3-none-any.whl → 0.57.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 (107) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_data.py +3 -0
  3. pyedb/configuration/cfg_operations.py +2 -2
  4. pyedb/configuration/cfg_ports_sources.py +1 -1
  5. pyedb/configuration/cfg_terminals.py +232 -0
  6. pyedb/configuration/configuration.py +146 -3
  7. pyedb/dotnet/clr_module.py +1 -2
  8. pyedb/dotnet/database/Variables.py +56 -41
  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 +55 -52
  15. pyedb/dotnet/database/dotnet/database.py +1 -0
  16. pyedb/dotnet/database/edb_data/control_file.py +6 -3
  17. pyedb/dotnet/database/edb_data/nets_data.py +3 -3
  18. pyedb/dotnet/database/edb_data/padstacks_data.py +5 -2
  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/hfss.py +9 -8
  24. pyedb/dotnet/database/layout_validation.py +6 -3
  25. pyedb/dotnet/database/materials.py +1 -3
  26. pyedb/dotnet/database/modeler.py +7 -3
  27. pyedb/dotnet/database/nets.py +27 -19
  28. pyedb/dotnet/database/padstack.py +91 -2
  29. pyedb/dotnet/database/sim_setup_data/io/siwave.py +1 -1
  30. pyedb/dotnet/database/siwave.py +4 -3
  31. pyedb/dotnet/database/stackup.py +50 -26
  32. pyedb/dotnet/database/utilities/heatsink.py +0 -1
  33. pyedb/dotnet/database/utilities/simulation_setup.py +7 -5
  34. pyedb/dotnet/database/utilities/siwave_cpa_simulation_setup.py +1 -0
  35. pyedb/dotnet/database/utilities/siwave_simulation_setup.py +5 -2
  36. pyedb/dotnet/edb.py +41 -36
  37. pyedb/exceptions.py +1 -2
  38. pyedb/extensions/create_cell_array.py +408 -0
  39. pyedb/generic/data_handlers.py +17 -28
  40. pyedb/generic/design_types.py +25 -38
  41. pyedb/generic/filesystem.py +9 -4
  42. pyedb/generic/general_methods.py +6 -7
  43. pyedb/generic/plot.py +2 -2
  44. pyedb/generic/settings.py +4 -0
  45. pyedb/grpc/database/_typing.py +0 -0
  46. pyedb/grpc/database/components.py +30 -11
  47. pyedb/grpc/database/control_file.py +14 -35
  48. pyedb/grpc/database/definition/materials.py +1 -1
  49. pyedb/grpc/database/definition/package_def.py +6 -3
  50. pyedb/grpc/database/definition/padstack_def.py +4 -7
  51. pyedb/grpc/database/hfss.py +1 -4
  52. pyedb/grpc/database/hierarchy/component.py +3 -4
  53. pyedb/grpc/database/hierarchy/pingroup.py +16 -3
  54. pyedb/grpc/database/layers/layer.py +1 -2
  55. pyedb/grpc/database/layers/stackup_layer.py +42 -19
  56. pyedb/grpc/database/layout/layout.py +117 -28
  57. pyedb/grpc/database/layout/voltage_regulator.py +6 -1
  58. pyedb/grpc/database/layout_validation.py +7 -4
  59. pyedb/grpc/database/modeler.py +241 -256
  60. pyedb/grpc/database/net/differential_pair.py +9 -2
  61. pyedb/grpc/database/net/extended_net.py +24 -9
  62. pyedb/grpc/database/net/net.py +14 -5
  63. pyedb/grpc/database/net/net_class.py +24 -7
  64. pyedb/grpc/database/nets.py +11 -43
  65. pyedb/grpc/database/padstacks.py +92 -16
  66. pyedb/grpc/database/primitive/bondwire.py +3 -67
  67. pyedb/grpc/database/primitive/circle.py +42 -3
  68. pyedb/grpc/database/primitive/padstack_instance.py +17 -19
  69. pyedb/grpc/database/primitive/path.py +154 -5
  70. pyedb/grpc/database/primitive/polygon.py +75 -9
  71. pyedb/grpc/database/primitive/primitive.py +2 -2
  72. pyedb/grpc/database/primitive/rectangle.py +105 -4
  73. pyedb/grpc/database/simulation_setup/hfss_general_settings.py +0 -2
  74. pyedb/grpc/database/simulation_setup/hfss_settings_options.py +0 -4
  75. pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +4 -2
  76. pyedb/grpc/database/simulation_setup/sweep_data.py +1 -3
  77. pyedb/grpc/database/siwave.py +6 -13
  78. pyedb/grpc/database/source_excitations.py +49 -57
  79. pyedb/grpc/database/stackup.py +50 -27
  80. pyedb/grpc/database/terminal/bundle_terminal.py +10 -3
  81. pyedb/grpc/database/terminal/pingroup_terminal.py +8 -1
  82. pyedb/grpc/database/terminal/terminal.py +19 -8
  83. pyedb/grpc/database/utility/heat_sink.py +0 -1
  84. pyedb/grpc/database/utility/hfss_extent_info.py +2 -2
  85. pyedb/grpc/database/utility/value.py +1 -0
  86. pyedb/grpc/database/utility/xml_control_file.py +6 -3
  87. pyedb/grpc/edb.py +33 -24
  88. pyedb/grpc/edb_init.py +1 -0
  89. pyedb/grpc/rpc_session.py +4 -3
  90. pyedb/ipc2581/ecad/cad_data/layer_feature.py +6 -2
  91. pyedb/ipc2581/ecad/cad_data/step.py +1 -1
  92. pyedb/ipc2581/ipc2581.py +8 -7
  93. pyedb/libraries/common.py +3 -4
  94. pyedb/libraries/rf_libraries/base_functions.py +7 -16
  95. pyedb/libraries/rf_libraries/planar_antennas.py +3 -21
  96. pyedb/misc/downloads.py +1 -0
  97. pyedb/misc/misc.py +5 -2
  98. pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +1 -1
  99. pyedb/misc/utilities.py +0 -1
  100. pyedb/modeler/geometry_operators.py +9 -8
  101. pyedb/siwave.py +4 -6
  102. pyedb/siwave_core/__init__.py +0 -0
  103. pyedb/siwave_core/cpa/__init__.py +0 -0
  104. {pyedb-0.55.0.dist-info → pyedb-0.57.0.dist-info}/METADATA +3 -3
  105. {pyedb-0.55.0.dist-info → pyedb-0.57.0.dist-info}/RECORD +107 -102
  106. {pyedb-0.55.0.dist-info → pyedb-0.57.0.dist-info}/WHEEL +0 -0
  107. {pyedb-0.55.0.dist-info → pyedb-0.57.0.dist-info}/licenses/LICENSE +0 -0
@@ -85,11 +85,13 @@ class RaptorXSimulationSetup(SimulationSetup):
85
85
  Examples
86
86
  --------
87
87
  >>> setup1 = edbapp.create_hfss_setup("setup1")
88
- >>> setup1.add_frequency_sweep(frequency_sweep=[
89
- ... ["linear count", "0", "1kHz", 1],
90
- ... ["log scale", "1kHz", "0.1GHz", 10],
91
- ... ["linear scale", "0.1GHz", "10GHz", "0.1GHz"],
92
- ... ])
88
+ >>> setup1.add_frequency_sweep(
89
+ ... frequency_sweep=[
90
+ ... ["linear count", "0", "1kHz", 1],
91
+ ... ["log scale", "1kHz", "0.1GHz", 10],
92
+ ... ["linear scale", "0.1GHz", "10GHz", "0.1GHz"],
93
+ ... ]
94
+ ... )
93
95
  """
94
96
  if name in self.frequency_sweeps:
95
97
  return False
@@ -234,9 +236,7 @@ class RaptorXSimulationAdvancedSettings(object):
234
236
  if isinstance(value, list):
235
237
  self._advanced_settings.NetSettingsOptions = convert_py_list_to_net_list(value)
236
238
  else:
237
- self.logger.error(
238
- f"RaptorX setup net_settings_options input setter must be a list. " f"Provided value {value}"
239
- )
239
+ self.logger.error(f"RaptorX setup net_settings_options input setter must be a list. Provided value {value}")
240
240
 
241
241
  @property
242
242
  def override_shrink_fac(self):
@@ -276,7 +276,7 @@ class RaptorXSimulationAdvancedSettings(object):
276
276
  self._advanced_settings.UseAccelerateViaExtraction = value
277
277
  else:
278
278
  self.logger.error(
279
- "RaptorX setup use_accelerate_via_extraction setter input must be boolean." f"Provided value {value}"
279
+ f"RaptorX setup use_accelerate_via_extraction setter input must be boolean. Provided value {value}"
280
280
  )
281
281
 
282
282
  @property
@@ -290,7 +290,7 @@ class RaptorXSimulationAdvancedSettings(object):
290
290
  self._advanced_settings.UseAutoRemovalSliverPoly = value
291
291
  else:
292
292
  self.logger.error(
293
- f"RaptorX setup use_auto_removal_sliver_poly setter must be a boolean. " f"Provided value {value}"
293
+ f"RaptorX setup use_auto_removal_sliver_poly setter must be a boolean. Provided value {value}"
294
294
  )
295
295
 
296
296
  @property
@@ -334,7 +334,7 @@ class RaptorXSimulationAdvancedSettings(object):
334
334
  self._advanced_settings.UseEliminateSlitPerHoles = value
335
335
  else:
336
336
  self.logger.error(
337
- f"RaptorX setup use_eliminate_slit_per_holes setter must be a boolean. " f"Provided value {value}"
337
+ f"RaptorX setup use_eliminate_slit_per_holes setter must be a boolean. Provided value {value}"
338
338
  )
339
339
 
340
340
  @property
@@ -350,7 +350,7 @@ class RaptorXSimulationAdvancedSettings(object):
350
350
  self._advanced_settings.UseEnableAdvancedCapEffects = value
351
351
  else:
352
352
  self.logger.error(
353
- f"RaptorX setup use_enable_advanced_cap_effects setter must be a boolean. " f"Provided value {value}"
353
+ f"RaptorX setup use_enable_advanced_cap_effects setter must be a boolean. Provided value {value}"
354
354
  )
355
355
 
356
356
  @property
@@ -366,7 +366,7 @@ class RaptorXSimulationAdvancedSettings(object):
366
366
  self._advanced_settings.UseEnableEtchTransform = value
367
367
  else:
368
368
  self.logger.error(
369
- f"RaptorX setup use_enable_etch_transform setter must be a boolean. " f"Provided value {value}"
369
+ f"RaptorX setup use_enable_etch_transform setter must be a boolean. Provided value {value}"
370
370
  )
371
371
 
372
372
  @property
@@ -382,7 +382,7 @@ class RaptorXSimulationAdvancedSettings(object):
382
382
  self._advanced_settings.UseEnableHybridExtraction = value
383
383
  else:
384
384
  self.logger.error(
385
- f"RaptorX setup use_enable_hybrid_extraction setter must be a boolean. " f"Provided value {value}"
385
+ f"RaptorX setup use_enable_hybrid_extraction setter must be a boolean. Provided value {value}"
386
386
  )
387
387
 
388
388
  @property
@@ -414,7 +414,7 @@ class RaptorXSimulationAdvancedSettings(object):
414
414
  self._advanced_settings.UseExtractFloatingMetalsDummy = value
415
415
  else:
416
416
  self.logger.error(
417
- f"RaptorX setup use_extract_floating_metals_dummy setter must be a boolean. " f"Provided value {value}"
417
+ f"RaptorX setup use_extract_floating_metals_dummy setter must be a boolean. Provided value {value}"
418
418
  )
419
419
 
420
420
  @property
@@ -430,8 +430,7 @@ class RaptorXSimulationAdvancedSettings(object):
430
430
  self._advanced_settings.UseExtractFloatingMetalsFloating = value
431
431
  else:
432
432
  self.logger.error(
433
- f"RaptorX setup use_extract_floating_metals_floating setter must be a boolean. "
434
- f"Provided value {value}"
433
+ f"RaptorX setup use_extract_floating_metals_floating setter must be a boolean. Provided value {value}"
435
434
  )
436
435
 
437
436
  @property
@@ -493,7 +492,7 @@ class RaptorXSimulationAdvancedSettings(object):
493
492
  self._advanced_settings.UsePlaneProjectionFactor = value
494
493
  else:
495
494
  self.logger.error(
496
- f"RaptorX setup use_plane_projection_factor setter must be a boolean. " f"Provided value {value}"
495
+ f"RaptorX setup use_plane_projection_factor setter must be a boolean. Provided value {value}"
497
496
  )
498
497
 
499
498
  @property
@@ -506,4 +505,4 @@ class RaptorXSimulationAdvancedSettings(object):
506
505
  if isinstance(value, bool):
507
506
  self._advanced_settings.UseRelaxedZAxis = value
508
507
  else:
509
- self.logger.error(f"RaptorX setup use_relaxed_z_axis setter must be a boolean. " f"Provided value {value}")
508
+ self.logger.error(f"RaptorX setup use_relaxed_z_axis setter must be a boolean. Provided value {value}")
@@ -2132,7 +2132,7 @@ class SimulationConfiguration(object):
2132
2132
 
2133
2133
  Defined the radiation box type, Conformal, Bounding box and ConvexHull are supported (HFSS only).
2134
2134
 
2135
- >>> sim_setup.max_num_passes= 30
2135
+ >>> sim_setup.max_num_passes = 30
2136
2136
 
2137
2137
  Default value is 30, specify the maximum number of adaptive passes (only HFSS). Reasonable high value is recommended
2138
2138
  to force the solver reaching the convergence criteria.
@@ -2147,7 +2147,7 @@ class SimulationConfiguration(object):
2147
2147
  local minima.
2148
2148
 
2149
2149
  >>> from dotnet.generic.constants import BasisOrder
2150
- >>> sim_setup.basis_order = BasisOrder.Single
2150
+ >>> sim_setup.basis_order = BasisOrder.Single
2151
2151
 
2152
2152
  Select the order basis (HFSS only), Zero, Single, Double and Mixed are supported. For Signal integrity Single or
2153
2153
  Mixed should be used.
@@ -2229,7 +2229,7 @@ class SimulationConfiguration(object):
2229
2229
 
2230
2230
  Activate the loop resistance usage per pin when ``True``
2231
2231
 
2232
- >>> sim_setup.dc_via_report_path = 'C:\\temp\\via_report_file'
2232
+ >>> sim_setup.dc_via_report_path = "C:\\temp\\via_report_file"
2233
2233
 
2234
2234
  Define the via report path file.
2235
2235
 
@@ -23,6 +23,7 @@
23
23
  """
24
24
  This module contains the ``EdbHfss`` class.
25
25
  """
26
+
26
27
  import math
27
28
 
28
29
  from pyedb.dotnet.database.edb_data.hfss_extent_info import HfssExtentInfo
@@ -174,8 +175,8 @@ class EdbHfss(object):
174
175
 
175
176
  >>> from pyedb import Edb
176
177
  >>> edbapp = Edb("myaedbfolder", "project name", "release version")
177
- >>> pins =edbapp.components.get_pin_from_component("U2A5")
178
- >>> edbapp.hfss.create_circuit_port_on_pin(pins[0], pins[1],50,"port_name")
178
+ >>> pins = edbapp.components.get_pin_from_component("U2A5")
179
+ >>> edbapp.hfss.create_circuit_port_on_pin(pins[0], pins[1], 50, "port_name")
179
180
 
180
181
  Returns
181
182
  -------
@@ -211,8 +212,8 @@ class EdbHfss(object):
211
212
 
212
213
  >>> from pyedb import Edb
213
214
  >>> edbapp = Edb("myaedbfolder", "project name", "release version")
214
- >>> pins =edbapp.components.get_pin_from_component("U2A5")
215
- >>> edbapp.hfss.create_voltage_source_on_pin(pins[0], pins[1],50,"source_name")
215
+ >>> pins = edbapp.components.get_pin_from_component("U2A5")
216
+ >>> edbapp.hfss.create_voltage_source_on_pin(pins[0], pins[1], 50, "source_name")
216
217
  """
217
218
  return self._pedb.siwave.create_voltage_source_on_pin(pos_pin, neg_pin, voltage_value, phase_value, source_name)
218
219
 
@@ -242,8 +243,8 @@ class EdbHfss(object):
242
243
 
243
244
  >>> from pyedb import Edb
244
245
  >>> edbapp = Edb("myaedbfolder", "project name", "release version")
245
- >>> pins =edbapp.components.get_pin_from_component("U2A5")
246
- >>> edbapp.hfss.create_current_source_on_pin(pins[0], pins[1],50,"source_name")
246
+ >>> pins = edbapp.components.get_pin_from_component("U2A5")
247
+ >>> edbapp.hfss.create_current_source_on_pin(pins[0], pins[1], 50, "source_name")
247
248
  """
248
249
 
249
250
  return self._pedb.siwave.create_current_source_on_pin(pos_pin, neg_pin, current_value, phase_value, source_name)
@@ -272,8 +273,8 @@ class EdbHfss(object):
272
273
 
273
274
  >>> from pyedb import Edb
274
275
  >>> edbapp = Edb("myaedbfolder", "project name", "release version")
275
- >>> pins =edbapp.components.get_pin_from_component("U2A5")
276
- >>> edbapp.hfss.create_resistor_on_pin(pins[0], pins[1],50,"res_name")
276
+ >>> pins = edbapp.components.get_pin_from_component("U2A5")
277
+ >>> edbapp.hfss.create_resistor_on_pin(pins[0], pins[1], 50, "res_name")
277
278
  """
278
279
  return self._pedb.siwave.create_resistor_on_pin(pos_pin, neg_pin, rvalue, resistor_name)
279
280
 
@@ -155,7 +155,7 @@ class LayoutValidation:
155
155
  Examples
156
156
  --------
157
157
 
158
- >>> renamed_nets = edb.layout_validation.disjoint_nets(["GND","Net2"])
158
+ >>> renamed_nets = edb.layout_validation.disjoint_nets(["GND", "Net2"])
159
159
  """
160
160
 
161
161
  if not net_list:
@@ -208,8 +208,11 @@ class LayoutValidation:
208
208
  if isinstance(obj_dict[el], Primitive):
209
209
  if not obj_dict[el].is_void:
210
210
  sum += obj_dict[el].area()
211
- except:
212
- pass
211
+ except Exception as e:
212
+ self._pedb.logger.warning(
213
+ f"A(n) {type(e).__name__} error occurred while calculating area "
214
+ f"for element {elem} - Default value of 0 is used: {str(e)}"
215
+ )
213
216
  return sum
214
217
 
215
218
  if order_by_area:
@@ -243,9 +243,7 @@ class Material(object):
243
243
  if self.__dc_model and value:
244
244
  self.__dc_model.SetDCRelativePermitivity(value)
245
245
  else:
246
- self.__edb.logger.error(
247
- f"DC permittivity cannot be updated in material without DC model or value {value}." f""
248
- )
246
+ self.__edb.logger.error(f"DC permittivity cannot be updated in material without DC model or value {value}.")
249
247
 
250
248
  @property
251
249
  def dielectric_model_frequency(self):
@@ -23,6 +23,7 @@
23
23
  """
24
24
  This module contains these classes: `EdbLayout` and `Shape`.
25
25
  """
26
+
26
27
  import math
27
28
  import warnings
28
29
 
@@ -355,8 +356,11 @@ class Modeler(object):
355
356
  bounding_box.Item2.X.ToDouble(),
356
357
  bounding_box.Item2.Y.ToDouble(),
357
358
  ]
358
- except:
359
- pass
359
+ except Exception as e:
360
+ self._logger.warning(
361
+ f"A(n) {type(e).__name__} error occurred while retrieving bounding box for polygon {polygon} - "
362
+ f"Empty list is returned: {str(e)}"
363
+ )
360
364
  return bounding
361
365
 
362
366
  def get_polygon_points(self, polygon):
@@ -383,7 +387,7 @@ class Modeler(object):
383
387
  --------
384
388
 
385
389
  >>> poly = database.modeler.get_polygons_by_layer("GND")
386
- >>> points = database.modeler.get_polygon_points(poly[0])
390
+ >>> points = database.modeler.get_polygon_points(poly[0])
387
391
 
388
392
  """
389
393
  points = []
@@ -308,22 +308,30 @@ class EdbNets(CommonNets):
308
308
  val_value = cmp.rlc_values
309
309
  if refdes in exception_list:
310
310
  pass
311
- elif (
312
- val_type == "Inductor"
313
- and self._pedb.edb_value(val_value[1]).ToDouble() <= self._pedb.edb_value(inductor_below).ToDouble()
314
- ):
315
- pass
316
- elif (
317
- val_type == "Resistor"
318
- and self._pedb.edb_value(val_value[0]).ToDouble() <= self._pedb.edb_value(resistor_below).ToDouble()
319
- ):
320
- pass
321
- elif (
322
- val_type == "Capacitor"
323
- and self._pedb.edb_value(val_value[2]).ToDouble()
324
- >= self._pedb.edb_value(capacitor_above).ToDouble()
325
- ):
326
- pass
311
+ elif val_type == "Inductor":
312
+ if val_value[1] is None:
313
+ continue
314
+ elif (
315
+ not self._pedb.edb_value(val_value[1]).ToDouble()
316
+ <= self._pedb.edb_value(inductor_below).ToDouble()
317
+ ):
318
+ continue
319
+ elif val_type == "Resistor":
320
+ if val_value[0] is None:
321
+ continue
322
+ elif (
323
+ not self._pedb.edb_value(val_value[0]).ToDouble()
324
+ <= self._pedb.edb_value(resistor_below).ToDouble()
325
+ ):
326
+ continue
327
+ elif val_type == "Capacitor":
328
+ if val_value[2] is None:
329
+ continue
330
+ elif (
331
+ not self._pedb.edb_value(val_value[2]).ToDouble()
332
+ >= self._pedb.edb_value(capacitor_above).ToDouble()
333
+ ):
334
+ continue
327
335
  else:
328
336
  continue
329
337
 
@@ -575,7 +583,7 @@ class EdbNets(CommonNets):
575
583
  Examples
576
584
  --------
577
585
 
578
- >>> deleted_nets = database.nets.delete(["Net1","Net2"])
586
+ >>> deleted_nets = database.nets.delete(["Net1", "Net2"])
579
587
  """
580
588
  warnings.warn("Use :func:`delete` method instead.", DeprecationWarning)
581
589
  return self.delete(netlist=netlist)
@@ -596,7 +604,7 @@ class EdbNets(CommonNets):
596
604
  Examples
597
605
  --------
598
606
 
599
- >>> deleted_nets = database.nets.delete(["Net1","Net2"])
607
+ >>> deleted_nets = database.nets.delete(["Net1", "Net2"])
600
608
  """
601
609
  if isinstance(netlist, str):
602
610
  netlist = [netlist]
@@ -733,7 +741,7 @@ class EdbNets(CommonNets):
733
741
  Examples
734
742
  --------
735
743
 
736
- >>> renamed_nets = database.nets.find_and_fix_disjoint_nets(["GND","Net2"])
744
+ >>> renamed_nets = database.nets.find_and_fix_disjoint_nets(["GND", "Net2"])
737
745
  """
738
746
  warnings.warn("Use new function :func:`edb.layout_validation.disjoint_nets` instead.", DeprecationWarning)
739
747
  return self._pedb.layout_validation.disjoint_nets(
@@ -23,6 +23,7 @@
23
23
  """
24
24
  This module contains the `EdbPadstacks` class.
25
25
  """
26
+
26
27
  from collections import defaultdict
27
28
  import math
28
29
  from typing import Dict, List
@@ -708,8 +709,9 @@ class EdbPadstacks(object):
708
709
  )
709
710
  else: # pragma no cover
710
711
  self._logger.error(
711
- "Failed to reassign anti-pad value {} on Pads-stack definition {},"
712
- " layer{}".format(str(value), padstack.edb_padstack.GetName(), layer)
712
+ "Failed to reassign anti-pad value {} on Pads-stack definition {}, layer{}".format(
713
+ str(value), padstack.edb_padstack.GetName(), layer
714
+ )
713
715
  )
714
716
  all_succeed = False
715
717
  padstack.edb_padstack.SetData(cloned_padstack_data)
@@ -1943,3 +1945,90 @@ class EdbPadstacks(object):
1943
1945
  clusters[int(label)].append(padstack_ids[i])
1944
1946
 
1945
1947
  return dict(clusters)
1948
+
1949
+ def reduce_via_by_density(
1950
+ self, padstacks: List[int], cell_size_x: float = 1e-3, cell_size_y: float = 1e-3, delete: bool = False
1951
+ ) -> tuple[List[int], List[List[List[float]]]]:
1952
+ """
1953
+ Reduce the number of vias by density. Keep only one via which is closest to the center of the cell. The cells
1954
+ are automatically populated based on the input vias.
1955
+
1956
+ Parameters
1957
+ ----------
1958
+ padstacks: List[int]
1959
+ List of padstack ids to be reduced.
1960
+
1961
+ cell_size_x : float
1962
+ Width of each grid cell (default is 1e-3).
1963
+
1964
+ cell_size_y : float
1965
+ Height of each grid cell (default is 1e-3).
1966
+
1967
+ delete: bool
1968
+ If True, delete vias that are not kept (default is False).
1969
+
1970
+ Returns
1971
+ -------
1972
+ List[int]
1973
+ IDs of vias kept after reduction.
1974
+
1975
+ List[List[float]]
1976
+ coordinates for grid lines (for plotting).
1977
+
1978
+ """
1979
+ to_keep = set()
1980
+
1981
+ all_instances = self.instances
1982
+ positions = np.array([all_instances[_id].position for _id in padstacks])
1983
+
1984
+ x_coords, y_coords = positions[:, 0], positions[:, 1]
1985
+ x_min, x_max = np.min(x_coords), np.max(x_coords)
1986
+ y_min, y_max = np.min(y_coords), np.max(y_coords)
1987
+
1988
+ padstacks_array = np.array(padstacks)
1989
+ cell_map = {} # {(cell_x, cell_y): [(id1, [x1, y1]), (id2, [x2, y2), ...]}
1990
+ grid = []
1991
+
1992
+ for idx, pos in enumerate(positions):
1993
+ i = int((pos[0] - x_min) // cell_size_x)
1994
+ j = int((pos[1] - y_min) // cell_size_y)
1995
+ cell_key = (i, j)
1996
+ cell_map.setdefault(cell_key, []).append((padstacks_array[idx], pos))
1997
+
1998
+ for (i, j), items in cell_map.items():
1999
+ # cell center
2000
+ cell_x_min = x_min + i * cell_size_x
2001
+ cell_y_min = y_min + j * cell_size_y
2002
+ cell_x_mid = cell_x_min + 0.5 * cell_size_x
2003
+ cell_y_mid = cell_y_min + 0.5 * cell_size_y
2004
+
2005
+ grid.append(
2006
+ [
2007
+ [
2008
+ cell_x_min,
2009
+ cell_x_min + cell_size_x,
2010
+ cell_x_min + cell_size_x,
2011
+ cell_x_min,
2012
+ cell_x_min,
2013
+ ],
2014
+ [
2015
+ cell_y_min,
2016
+ cell_y_min,
2017
+ cell_y_min + cell_size_y,
2018
+ cell_y_min + cell_size_y,
2019
+ cell_y_min,
2020
+ ],
2021
+ ]
2022
+ )
2023
+
2024
+ # Find closest via to cell center
2025
+ distances = [np.linalg.norm(pos - [cell_x_mid, cell_y_mid]) for _, pos in items]
2026
+ closest_idx = np.argmin(distances)
2027
+ to_keep.add(items[closest_idx][0])
2028
+
2029
+ if delete:
2030
+ to_delete = set(padstacks) - to_keep
2031
+ for _id in to_delete:
2032
+ all_instances[_id].delete()
2033
+
2034
+ return list(to_keep), grid
@@ -349,7 +349,7 @@ class AdvancedSettings(SettingsBase):
349
349
  ``True`` if automatic mesh is used, ``False`` otherwise.
350
350
  """
351
351
  warnings.warn(
352
- "`automatic_mesh` is deprecated." "Use `mesh_automatic` instead.",
352
+ "`automatic_mesh` is deprecated. Use `mesh_automatic` instead.",
353
353
  DeprecationWarning,
354
354
  )
355
355
  return self.sim_setup_info.simulation_settings.AdvancedSettings.MeshAutoMatic
@@ -24,6 +24,7 @@
24
24
  This module contains these classes: ``CircuitPort``, ``CurrentSource``, ``EdbSiwave``,
25
25
  ``PinGroup``, ``ResistorSource``, ``Source``, ``SourceType``, and ``VoltageSource``.
26
26
  """
27
+
27
28
  import os
28
29
  import time
29
30
 
@@ -483,8 +484,8 @@ class EdbSiwave(object):
483
484
 
484
485
  >>> from pyedb import Edb
485
486
  >>> edbapp = Edb("myaedbfolder", "project name", "release version")
486
- >>> pins =edbapp.components.get_pin_from_component("U2A5")
487
- >>> edbapp.siwave.create_resistor_on_pin(pins[0], pins[1],50,"res_name")
487
+ >>> pins = edbapp.components.get_pin_from_component("U2A5")
488
+ >>> edbapp.siwave.create_resistor_on_pin(pins[0], pins[1], 50, "res_name")
488
489
  """
489
490
  resistor = ResistorSource()
490
491
  resistor.positive_node.net = pos_pin.net_name
@@ -625,7 +626,7 @@ class EdbSiwave(object):
625
626
 
626
627
  >>> from pyedb import Edb
627
628
  >>> edbapp = Edb("myaedbfolder", "project name", "release version")
628
- >>> edb.siwave.create_voltage_source_on_net("U2A5","V1P5_S3","U2A5","GND",3.3,0,"source_name")
629
+ >>> edb.siwave.create_voltage_source_on_net("U2A5", "V1P5_S3", "U2A5", "GND", 3.3, 0, "source_name")
629
630
  """
630
631
  if not negative_component_name:
631
632
  negative_component_name = positive_component_name
@@ -1137,7 +1137,7 @@ class Stackup(LayerCollection):
1137
1137
 
1138
1138
  Examples
1139
1139
  --------
1140
- >>> edb = Edb(edbpath=targetfile, edbversion="2021.2")
1140
+ >>> edb = Edb(edbpath=targetfile, edbversion="2021.2")
1141
1141
  >>> edb.stackup.flip_design()
1142
1142
  >>> edb.save()
1143
1143
  >>> edb.close_edb()
@@ -1227,8 +1227,11 @@ class Stackup(LayerCollection):
1227
1227
  sball_prop = cmp_prop.GetSolderBallProperty().Clone()
1228
1228
  sball_prop.SetPlacement(self._pedb.definition.SolderballPlacement.AbovePadstack)
1229
1229
  cmp_prop.SetSolderBallProperty(sball_prop)
1230
- except:
1231
- pass
1230
+ except Exception as e:
1231
+ self._logger.warning(
1232
+ f"A(n) {type(e).__name__} error occurred while attempting to update "
1233
+ f"SolderBallProperty for component {cmp}: {str(e)}"
1234
+ )
1232
1235
  if cmp_type == self._pedb.definition.ComponentType.IC:
1233
1236
  die_prop = cmp_prop.GetDieProperty().Clone()
1234
1237
  chip_orientation = die_prop.GetOrientation()
@@ -1356,22 +1359,28 @@ class Stackup(LayerCollection):
1356
1359
 
1357
1360
  Examples
1358
1361
  --------
1359
- >>> edb1 = Edb(edbpath=targetfile1, edbversion="2021.2")
1362
+ >>> edb1 = Edb(edbpath=targetfile1, edbversion="2021.2")
1360
1363
  >>> edb2 = Edb(edbpath=targetfile2, edbversion="2021.2")
1361
1364
 
1362
1365
  >>> hosting_cmp = edb1.components.get_component_by_name("U100")
1363
1366
  >>> mounted_cmp = edb2.components.get_component_by_name("BGA")
1364
1367
 
1365
1368
  >>> vector, rotation, solder_ball_height = edb1.components.get_component_placement_vector(
1366
- ... mounted_component=mounted_cmp,
1367
- ... hosting_component=hosting_cmp,
1368
- ... mounted_component_pin1="A12",
1369
- ... mounted_component_pin2="A14",
1370
- ... hosting_component_pin1="A12",
1371
- ... hosting_component_pin2="A14")
1372
- >>> edb2.stackup.place_in_layout(edb1.active_cell, angle=0.0, offset_x=vector[0],
1373
- ... offset_y=vector[1], flipped_stackup=False, place_on_top=True,
1374
- ... )
1369
+ ... mounted_component=mounted_cmp,
1370
+ ... hosting_component=hosting_cmp,
1371
+ ... mounted_component_pin1="A12",
1372
+ ... mounted_component_pin2="A14",
1373
+ ... hosting_component_pin1="A12",
1374
+ ... hosting_component_pin2="A14",
1375
+ ... )
1376
+ >>> edb2.stackup.place_in_layout(
1377
+ ... edb1.active_cell,
1378
+ ... angle=0.0,
1379
+ ... offset_x=vector[0],
1380
+ ... offset_y=vector[1],
1381
+ ... flipped_stackup=False,
1382
+ ... place_on_top=True,
1383
+ ... )
1375
1384
  """
1376
1385
  # if flipped_stackup and place_on_top or (not flipped_stackup and not place_on_top):
1377
1386
  self.adjust_solder_dielectrics()
@@ -1453,13 +1462,18 @@ class Stackup(LayerCollection):
1453
1462
 
1454
1463
  Examples
1455
1464
  --------
1456
- >>> edb1 = Edb(edbpath=targetfile1, edbversion="2021.2")
1465
+ >>> edb1 = Edb(edbpath=targetfile1, edbversion="2021.2")
1457
1466
  >>> edb2 = Edb(edbpath=targetfile2, edbversion="2021.2")
1458
1467
  >>> hosting_cmp = edb1.components.get_component_by_name("U100")
1459
1468
  >>> mounted_cmp = edb2.components.get_component_by_name("BGA")
1460
- >>> edb2.stackup.place_in_layout(edb1.active_cell, angle=0.0, offset_x="1mm",
1461
- ... offset_y="2mm", flipped_stackup=False, place_on_top=True,
1462
- ... )
1469
+ >>> edb2.stackup.place_in_layout(
1470
+ ... edb1.active_cell,
1471
+ ... angle=0.0,
1472
+ ... offset_x="1mm",
1473
+ ... offset_y="2mm",
1474
+ ... flipped_stackup=False,
1475
+ ... place_on_top=True,
1476
+ ... )
1463
1477
  """
1464
1478
  _angle = angle * math.pi / 180.0
1465
1479
 
@@ -1592,13 +1606,18 @@ class Stackup(LayerCollection):
1592
1606
 
1593
1607
  Examples
1594
1608
  --------
1595
- >>> edb1 = Edb(edbpath=targetfile1, edbversion="2021.2")
1609
+ >>> edb1 = Edb(edbpath=targetfile1, edbversion="2021.2")
1596
1610
  >>> edb2 = Edb(edbpath=targetfile2, edbversion="2021.2")
1597
1611
  >>> hosting_cmp = edb1.components.get_component_by_name("U100")
1598
1612
  >>> mounted_cmp = edb2.components.get_component_by_name("BGA")
1599
- >>> edb1.stackup.place_instance(edb2, angle=0.0, offset_x="1mm",
1600
- ... offset_y="2mm", flipped_stackup=False, place_on_top=True,
1601
- ... )
1613
+ >>> edb1.stackup.place_instance(
1614
+ ... edb2,
1615
+ ... angle=0.0,
1616
+ ... offset_x="1mm",
1617
+ ... offset_y="2mm",
1618
+ ... flipped_stackup=False,
1619
+ ... place_on_top=True,
1620
+ ... )
1602
1621
  """
1603
1622
  _angle = angle * math.pi / 180.0
1604
1623
 
@@ -1736,11 +1755,16 @@ class Stackup(LayerCollection):
1736
1755
 
1737
1756
  Examples
1738
1757
  --------
1739
- >>> edb1 = Edb(edbpath=targetfile1, edbversion="2021.2")
1758
+ >>> edb1 = Edb(edbpath=targetfile1, edbversion="2021.2")
1740
1759
  >>> a3dcomp_path = "connector.a3dcomp"
1741
- >>> edb1.stackup.place_a3dcomp_3d_placement(a3dcomp_path, angle=0.0, offset_x="1mm",
1742
- ... offset_y="2mm", flipped_stackup=False, place_on_top=True,
1743
- ... )
1760
+ >>> edb1.stackup.place_a3dcomp_3d_placement(
1761
+ ... a3dcomp_path,
1762
+ ... angle=0.0,
1763
+ ... offset_x="1mm",
1764
+ ... offset_y="2mm",
1765
+ ... flipped_stackup=False,
1766
+ ... place_on_top=True,
1767
+ ... )
1744
1768
  """
1745
1769
  zero_data = self._edb_value(0.0)
1746
1770
  one_data = self._edb_value(1.0)
@@ -1795,7 +1819,7 @@ class Stackup(LayerCollection):
1795
1819
 
1796
1820
  Examples
1797
1821
  --------
1798
- >>> edb = Edb(edbpath=targetfile1, edbversion="2021.2")
1822
+ >>> edb = Edb(edbpath=targetfile1, edbversion="2021.2")
1799
1823
  >>> edb.stackup.residual_copper_area_per_layer()
1800
1824
  """
1801
1825
  temp_data = {name: 0 for name, _ in self.signal_layers.items()}
@@ -1,5 +1,4 @@
1
1
  class HeatSink:
2
-
3
2
  """Heatsink model description.
4
3
 
5
4
  Parameters
@@ -371,11 +371,13 @@ class SimulationSetup(object):
371
371
  Examples
372
372
  --------
373
373
  >>> setup1 = edbapp.create_siwave_syz_setup("setup1")
374
- >>> setup1.add_frequency_sweep(frequency_sweep=[
375
- ... ["linear count", "0", "1kHz", 1],
376
- ... ["log scale", "1kHz", "0.1GHz", 10],
377
- ... ["linear scale", "0.1GHz", "10GHz", "0.1GHz"],
378
- ... ])
374
+ >>> setup1.add_frequency_sweep(
375
+ ... frequency_sweep=[
376
+ ... ["linear count", "0", "1kHz", 1],
377
+ ... ["log scale", "1kHz", "0.1GHz", 10],
378
+ ... ["linear scale", "0.1GHz", "10GHz", "0.1GHz"],
379
+ ... ]
380
+ ... )
379
381
  """
380
382
  warnings.warn("`add_frequency_sweep` is deprecated. Use `add_sweep` method instead.", DeprecationWarning)
381
383
  return self.add_sweep(name, frequency_sweep)
@@ -691,6 +691,7 @@ class SIWaveCPASimulationSetup:
691
691
  self._pedb = pedb
692
692
  self._channel_setup = ChannelSetup(pedb)
693
693
  self._solver_options = SolverOptions(pedb)
694
+ self.type = "cpa"
694
695
  if isinstance(siwave_cpa_setup_class, SIwaveCpaSetup):
695
696
  self._apply_cfg_object(siwave_cpa_setup_class)
696
697
  else: