pyedb 0.50.0__py3-none-any.whl → 0.51.2__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 (75) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_ports_sources.py +79 -239
  3. pyedb/configuration/configuration.py +27 -0
  4. pyedb/dotnet/clr_module.py +9 -3
  5. pyedb/dotnet/database/cell/hierarchy/component.py +3 -3
  6. pyedb/dotnet/database/cell/layout.py +10 -1
  7. pyedb/dotnet/database/dotnet/database.py +0 -2
  8. pyedb/dotnet/database/edb_data/padstacks_data.py +13 -0
  9. pyedb/dotnet/database/layout_validation.py +17 -13
  10. pyedb/dotnet/database/modeler.py +0 -1
  11. pyedb/dotnet/edb.py +7 -1
  12. pyedb/generic/design_types.py +183 -62
  13. pyedb/grpc/database/components.py +604 -652
  14. pyedb/grpc/database/control_file.py +597 -155
  15. pyedb/grpc/database/definition/component_def.py +17 -14
  16. pyedb/grpc/database/definition/materials.py +27 -27
  17. pyedb/grpc/database/definition/package_def.py +8 -8
  18. pyedb/grpc/database/definition/padstack_def.py +31 -33
  19. pyedb/grpc/database/definitions.py +36 -2
  20. pyedb/grpc/database/geometry/arc_data.py +5 -5
  21. pyedb/grpc/database/geometry/point_3d_data.py +3 -3
  22. pyedb/grpc/database/geometry/polygon_data.py +5 -5
  23. pyedb/grpc/database/hfss.py +412 -395
  24. pyedb/grpc/database/hierarchy/component.py +67 -58
  25. pyedb/grpc/database/hierarchy/pin_pair_model.py +6 -6
  26. pyedb/grpc/database/hierarchy/pingroup.py +13 -11
  27. pyedb/grpc/database/hierarchy/s_parameter_model.py +1 -1
  28. pyedb/grpc/database/hierarchy/spice_model.py +1 -1
  29. pyedb/grpc/database/layers/layer.py +2 -2
  30. pyedb/grpc/database/layers/stackup_layer.py +26 -23
  31. pyedb/grpc/database/layout/layout.py +12 -12
  32. pyedb/grpc/database/layout/voltage_regulator.py +8 -8
  33. pyedb/grpc/database/layout_validation.py +58 -7
  34. pyedb/grpc/database/modeler.py +248 -245
  35. pyedb/grpc/database/net/differential_pair.py +4 -4
  36. pyedb/grpc/database/net/extended_net.py +7 -8
  37. pyedb/grpc/database/net/net.py +57 -46
  38. pyedb/grpc/database/nets.py +362 -116
  39. pyedb/grpc/database/padstacks.py +259 -178
  40. pyedb/grpc/database/ports/ports.py +23 -17
  41. pyedb/grpc/database/primitive/padstack_instance.py +45 -30
  42. pyedb/grpc/database/primitive/path.py +6 -6
  43. pyedb/grpc/database/primitive/polygon.py +9 -9
  44. pyedb/grpc/database/primitive/primitive.py +21 -21
  45. pyedb/grpc/database/primitive/rectangle.py +1 -1
  46. pyedb/grpc/database/simulation_setup/hfss_advanced_settings.py +1 -1
  47. pyedb/grpc/database/simulation_setup/hfss_general_settings.py +1 -1
  48. pyedb/grpc/database/simulation_setup/hfss_settings_options.py +1 -1
  49. pyedb/grpc/database/simulation_setup/hfss_simulation_settings.py +6 -6
  50. pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +2 -2
  51. pyedb/grpc/database/simulation_setup/raptor_x_simulation_settings.py +2 -2
  52. pyedb/grpc/database/simulation_setup/raptor_x_simulation_setup.py +1 -1
  53. pyedb/grpc/database/simulation_setup/siwave_simulation_setup.py +3 -3
  54. pyedb/grpc/database/siwave.py +226 -214
  55. pyedb/grpc/database/source_excitations.py +307 -40
  56. pyedb/grpc/database/stackup.py +461 -283
  57. pyedb/grpc/database/terminal/bundle_terminal.py +12 -12
  58. pyedb/grpc/database/terminal/edge_terminal.py +6 -5
  59. pyedb/grpc/database/terminal/padstack_instance_terminal.py +13 -13
  60. pyedb/grpc/database/terminal/pingroup_terminal.py +12 -12
  61. pyedb/grpc/database/terminal/point_terminal.py +6 -6
  62. pyedb/grpc/database/terminal/terminal.py +26 -26
  63. pyedb/grpc/database/utility/heat_sink.py +5 -5
  64. pyedb/grpc/database/utility/hfss_extent_info.py +21 -21
  65. pyedb/grpc/database/utility/layout_statistics.py +13 -13
  66. pyedb/grpc/database/utility/rlc.py +3 -3
  67. pyedb/grpc/database/utility/sources.py +1 -1
  68. pyedb/grpc/database/utility/sweep_data_distribution.py +1 -1
  69. pyedb/grpc/edb.py +542 -739
  70. pyedb/grpc/edb_init.py +50 -3
  71. {pyedb-0.50.0.dist-info → pyedb-0.51.2.dist-info}/METADATA +1 -1
  72. {pyedb-0.50.0.dist-info → pyedb-0.51.2.dist-info}/RECORD +74 -75
  73. pyedb/grpc/database/utility/simulation_configuration.py +0 -3305
  74. {pyedb-0.50.0.dist-info → pyedb-0.51.2.dist-info}/LICENSE +0 -0
  75. {pyedb-0.50.0.dist-info → pyedb-0.51.2.dist-info}/WHEEL +0 -0
@@ -1,3305 +0,0 @@
1
- # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
2
- # SPDX-License-Identifier: MIT
3
- #
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
22
-
23
- from collections import OrderedDict
24
- import json
25
- import os
26
-
27
- from ansys.edb.core.hierarchy.component_group import ComponentType as GrpcComponentType
28
- from ansys.edb.core.utility.value import Value as GrpcValue
29
-
30
- # from pyedb.dotnet.database.edb_data.sources import Source, SourceType
31
- # from pyedb.dotnet.database.utilities.simulation_setup import AdaptiveType
32
- from pyedb.generic.constants import (
33
- BasisOrder,
34
- CutoutSubdesignType,
35
- RadiationBoxType,
36
- SolverType,
37
- SweepType,
38
- validate_enum_class_value,
39
- )
40
- from pyedb.generic.general_methods import generate_unique_name
41
-
42
-
43
- class SimulationConfigurationBatch(object):
44
- """Contains all Cutout and Batch analysis settings.
45
- The class is part of `SimulationConfiguration` class as a property.
46
-
47
-
48
- """
49
-
50
- def __init__(self):
51
- self._signal_nets = []
52
- self._power_nets = []
53
- self._components = []
54
- self._cutout_subdesign_type = CutoutSubdesignType.Conformal # Conformal
55
- self._cutout_subdesign_expansion = 0.001
56
- self._cutout_subdesign_round_corner = True
57
- self._use_default_cutout = False
58
- self._generate_excitations = True
59
- self._add_frequency_sweep = True
60
- self._include_only_selected_nets = False
61
- self._generate_solder_balls = True
62
- self._coax_solder_ball_diameter = []
63
- self._use_default_coax_port_radial_extension = True
64
- self._trim_reference_size = False
65
- self._output_aedb = None
66
- self._signal_layers_properties = {}
67
- self._coplanar_instances = []
68
- self._signal_layer_etching_instances = []
69
- self._etching_factor_instances = []
70
- self._use_dielectric_extent_multiple = True
71
- self._dielectric_extent = 0.001
72
- self._use_airbox_horizontal_multiple = True
73
- self._airbox_horizontal_extent = 0.1
74
- self._use_airbox_negative_vertical_extent_multiple = True
75
- self._airbox_negative_vertical_extent = 0.1
76
- self._use_airbox_positive_vertical_extent_multiple = True
77
- self._airbox_positive_vertical_extent = 0.1
78
- self._honor_user_dielectric = False
79
- self._truncate_airbox_at_ground = False
80
- self._use_radiation_boundary = True
81
- self._do_cutout_subdesign = True
82
- self._do_pin_group = True
83
- self._sources = []
84
-
85
- @property
86
- def coplanar_instances(self): # pragma: no cover
87
- """Retrieve the list of component to be replaced by circuit ports (obsolete).
88
-
89
- Returns
90
- -------
91
- list[str]
92
- List of component name.
93
- """
94
- return self._coplanar_instances
95
-
96
- @coplanar_instances.setter
97
- def coplanar_instances(self, value): # pragma: no cover
98
- if isinstance(value, list):
99
- self._coplanar_instances = value
100
-
101
- @property
102
- def signal_layer_etching_instances(self): # pragma: no cover
103
- """Retrieve the list of layers which has layer etching activated.
104
-
105
- Returns
106
- -------
107
- list[str]
108
- List of layer name.
109
- """
110
- return self._signal_layer_etching_instances
111
-
112
- @signal_layer_etching_instances.setter
113
- def signal_layer_etching_instances(self, value): # pragma: no cover
114
- if isinstance(value, list):
115
- self._signal_layer_etching_instances = value
116
-
117
- @property
118
- def etching_factor_instances(self): # pragma: no cover
119
- """Retrieve the list of etching factor with associated layers.
120
-
121
- Returns
122
- -------
123
- list[str]
124
- list etching parameters with layer name.
125
- """
126
- return self._etching_factor_instances
127
-
128
- @etching_factor_instances.setter
129
- def etching_factor_instances(self, value): # pragma: no cover
130
- if isinstance(value, list):
131
- self._etching_factor_instances = value
132
-
133
- @property
134
- def dielectric_extent(self): # pragma: no cover
135
- """Retrieve the value of dielectric extent.
136
-
137
- Returns
138
- -------
139
- float
140
- Value of the dielectric extent. When absolute dimensions are used,
141
- the values are in meters.
142
- """
143
- return self._dielectric_extent
144
-
145
- @dielectric_extent.setter
146
- def dielectric_extent(self, value): # pragma: no cover
147
- if isinstance(value, (int, float)):
148
- self._dielectric_extent = value
149
-
150
- @property
151
- def use_dielectric_extent_multiple(self):
152
- """Whether the multiple value of the dielectric extent is used.
153
-
154
- Returns
155
- -------
156
- bool
157
- ``True`` when the multiple value (extent factor) is used. ``False`` when
158
- absolute dimensions are used.
159
- """
160
- return self._use_dielectric_extent_multiple
161
-
162
- @use_dielectric_extent_multiple.setter
163
- def use_dielectric_extent_multiple(self, value):
164
- if isinstance(value, bool):
165
- self._use_dielectric_extent_multiple = value
166
-
167
- @property
168
- def airbox_horizontal_extent(self): # pragma: no cover
169
- """Horizontal extent of the airbox for HFSS. When absolute dimensions are used,
170
- the values are in meters.
171
-
172
- Returns
173
- -------
174
- float
175
- Value of the air box horizontal extent.
176
- """
177
- return self._airbox_horizontal_extent
178
-
179
- @airbox_horizontal_extent.setter
180
- def airbox_horizontal_extent(self, value): # pragma: no cover
181
- if isinstance(value, (int, float)):
182
- self._airbox_horizontal_extent = value
183
-
184
- @property
185
- def use_airbox_horizontal_extent_multiple(self):
186
- """Whether the multiple value is used for the horizontal extent of the air box.
187
-
188
- Returns
189
- -------
190
- bool
191
- ``True`` when the multiple value (extent factor) is used. ``False`` when
192
- absolute dimensions are used.
193
-
194
- """
195
- return self._use_airbox_horizontal_multiple
196
-
197
- @use_airbox_horizontal_extent_multiple.setter
198
- def use_airbox_horizontal_extent_multiple(self, value):
199
- if isinstance(value, bool):
200
- self._use_airbox_horizontal_multiple = value
201
-
202
- @property
203
- def airbox_negative_vertical_extent(self): # pragma: no cover
204
- """Negative vertical extent of the airbox for HFSS. When absolute dimensions
205
- are used, the values are in meters.
206
-
207
- Returns
208
- -------
209
- float
210
- Value of the air box negative vertical extent.
211
- """
212
- return self._airbox_negative_vertical_extent
213
-
214
- @airbox_negative_vertical_extent.setter
215
- def airbox_negative_vertical_extent(self, value): # pragma: no cover
216
- if isinstance(value, (int, float)):
217
- self._airbox_negative_vertical_extent = value
218
-
219
- @property
220
- def use_airbox_negative_vertical_extent_multiple(self):
221
- """Multiple value for the negative extent of the airbox.
222
-
223
- Returns
224
- -------
225
- bool
226
- ``True`` when the multiple value (extent factor) is used. ``False`` when
227
- absolute dimensions are used.
228
-
229
- """
230
- return self._use_airbox_negative_vertical_extent_multiple
231
-
232
- @use_airbox_negative_vertical_extent_multiple.setter
233
- def use_airbox_negative_vertical_extent_multiple(self, value):
234
- if isinstance(value, bool):
235
- self._use_airbox_negative_vertical_extent_multiple = value
236
-
237
- @property
238
- def airbox_positive_vertical_extent(self): # pragma: no cover
239
- """Positive vertical extent of the airbox for HFSS. When absolute dimensions are
240
- used, the values are in meters.
241
-
242
- Returns
243
- -------
244
- float
245
- Value of the air box positive vertical extent.
246
- """
247
- return self._airbox_positive_vertical_extent
248
-
249
- @airbox_positive_vertical_extent.setter
250
- def airbox_positive_vertical_extent(self, value): # pragma: no cover
251
- if isinstance(value, (int, float)):
252
- self._airbox_positive_vertical_extent = value
253
-
254
- @property
255
- def use_airbox_positive_vertical_extent_multiple(self):
256
- """Whether the multiple value for the positive extent of the airbox is used.
257
-
258
- Returns
259
- -------
260
- bool
261
- ``True`` when the multiple value (extent factor) is used. ``False`` when
262
- absolute dimensions are used.
263
- """
264
- return self._use_airbox_positive_vertical_extent_multiple
265
-
266
- @use_airbox_positive_vertical_extent_multiple.setter
267
- def use_airbox_positive_vertical_extent_multiple(self, value):
268
- if isinstance(value, bool):
269
- self._use_airbox_positive_vertical_extent_multiple = value
270
-
271
- @property
272
- def use_pyaedt_cutout(self):
273
- """Whether the default EDB cutout or a new PyAEDT cutout is used.
274
-
275
- Returns
276
- -------
277
- bool
278
- """
279
- return not self._use_default_cutout
280
-
281
- @use_pyaedt_cutout.setter
282
- def use_pyaedt_cutout(self, value):
283
- self._use_default_cutout = not value
284
-
285
- @property
286
- def use_default_cutout(self): # pragma: no cover
287
- """Whether to use the default EDB cutout. The default is ``False``, in which case
288
- a new PyAEDT cutout is used.
289
-
290
- Returns
291
- -------
292
- bool
293
- """
294
-
295
- return self._use_default_cutout
296
-
297
- @use_default_cutout.setter
298
- def use_default_cutout(self, value): # pragma: no cover
299
- self._use_default_cutout = value
300
-
301
- @property
302
- def do_pingroup(self): # pragma: no cover
303
- """Do pingroup on multi-pin component. ``True`` all pins from the same net are grouped, ``False`` one port
304
- is created for each pin.
305
-
306
- Returns
307
- -------
308
- bool
309
- """
310
- return self._do_pin_group
311
-
312
- @do_pingroup.setter
313
- def do_pingroup(self, value): # pragma: no cover
314
- self._do_pin_group = value
315
-
316
- @property
317
- def generate_solder_balls(self): # pragma: no cover
318
- """Retrieve the boolean for applying solder balls.
319
-
320
- Returns
321
- -------
322
- bool
323
- ``True`` when applied ``False`` if not.
324
- """
325
- return self._generate_solder_balls
326
-
327
- @generate_solder_balls.setter
328
- def generate_solder_balls(self, value):
329
- if isinstance(value, bool): # pragma: no cover
330
- self._generate_solder_balls = value
331
-
332
- @property
333
- def signal_nets(self):
334
- """Retrieve the list of signal net names.
335
-
336
- Returns
337
- -------
338
- List[str]
339
- List of signal net names.
340
- """
341
-
342
- return self._signal_nets
343
-
344
- @signal_nets.setter
345
- def signal_nets(self, value):
346
- if isinstance(value, list): # pragma: no cover
347
- self._signal_nets = value
348
-
349
- @property
350
- def power_nets(self):
351
- """Retrieve the list of power and reference net names.
352
-
353
- Returns
354
- -------
355
- list[str]
356
- List of the net name.
357
- """
358
- return self._power_nets
359
-
360
- @power_nets.setter
361
- def power_nets(self, value):
362
- if isinstance(value, list):
363
- self._power_nets = value
364
-
365
- @property
366
- def components(self):
367
- """Retrieve the list component name to be included in the simulation.
368
-
369
- Returns
370
- -------
371
- list[str]
372
- List of the component name.
373
- """
374
- return self._components
375
-
376
- @components.setter
377
- def components(self, value):
378
- if isinstance(value, list):
379
- self._components = value
380
-
381
- @property
382
- def coax_solder_ball_diameter(self): # pragma: no cover
383
- """Retrieve the list of solder balls diameter values when the auto evaluated one is overwritten.
384
-
385
- Returns
386
- -------
387
- list[float]
388
- List of the solder balls diameter.
389
- """
390
- return self._coax_solder_ball_diameter
391
-
392
- @coax_solder_ball_diameter.setter
393
- def coax_solder_ball_diameter(self, value): # pragma: no cover
394
- if isinstance(value, list):
395
- self._coax_solder_ball_diameter = value
396
-
397
- @property
398
- def use_default_coax_port_radial_extension(self):
399
- """Retrieve the boolean for using the default coaxial port extension value.
400
-
401
- Returns
402
- -------
403
- bool
404
- ``True`` when the default value is used ``False`` if not.
405
- """
406
- return self._use_default_coax_port_radial_extension
407
-
408
- @use_default_coax_port_radial_extension.setter
409
- def use_default_coax_port_radial_extension(self, value): # pragma: no cover
410
- if isinstance(value, bool):
411
- self._use_default_coax_port_radial_extension = value
412
-
413
- @property
414
- def trim_reference_size(self):
415
- """Retrieve the trim reference size when used.
416
-
417
- Returns
418
- -------
419
- float
420
- The size value.
421
- """
422
- return self._trim_reference_size
423
-
424
- @trim_reference_size.setter
425
- def trim_reference_size(self, value): # pragma: no cover
426
- if isinstance(value, bool):
427
- self._trim_reference_size = value
428
-
429
- @property
430
- def do_cutout_subdesign(self):
431
- """Retrieve boolean to perform the cutout during the project build.
432
-
433
- Returns
434
- -------
435
- bool
436
- ``True`` when clipping the design is applied ``False`` is not.
437
- """
438
- return self._do_cutout_subdesign
439
-
440
- @do_cutout_subdesign.setter
441
- def do_cutout_subdesign(self, value): # pragma: no cover
442
- if isinstance(value, bool):
443
- self._do_cutout_subdesign = value
444
-
445
- @property
446
- def cutout_subdesign_type(self):
447
- """Retrieve the CutoutSubdesignType selection for clipping the design.
448
-
449
- Returns
450
- -------
451
- CutoutSubdesignType object
452
- """
453
- return self._cutout_subdesign_type
454
-
455
- @cutout_subdesign_type.setter
456
- def cutout_subdesign_type(self, value): # pragma: no cover
457
- if validate_enum_class_value(CutoutSubdesignType, value):
458
- self._cutout_subdesign_type = value
459
-
460
- @property
461
- def cutout_subdesign_expansion(self):
462
- """Retrieve expansion factor used for clipping the design.
463
-
464
- Returns
465
- -------
466
- float
467
- The value used as a ratio.
468
- """
469
-
470
- return self._cutout_subdesign_expansion
471
-
472
- @cutout_subdesign_expansion.setter
473
- def cutout_subdesign_expansion(self, value): # pragma: no cover
474
- self._cutout_subdesign_expansion = value
475
-
476
- @property
477
- def cutout_subdesign_round_corner(self):
478
- """Retrieve boolean to perform the design clipping using round corner for the extent generation.
479
-
480
- Returns
481
- -------
482
- bool
483
- ``True`` when using round corner, ``False`` if not.
484
- """
485
-
486
- return self._cutout_subdesign_round_corner
487
-
488
- @cutout_subdesign_round_corner.setter
489
- def cutout_subdesign_round_corner(self, value): # pragma: no cover
490
- if isinstance(value, bool):
491
- self._cutout_subdesign_round_corner = value
492
-
493
- @property
494
- def output_aedb(self): # pragma: no cover
495
- """Retrieve the path for the output aedb folder. When provided will copy the initial aedb to the specified
496
- path. This is used especially to preserve the initial project when several files have to be build based on
497
- the last one. When the path is None, the initial project will be overwritten. So when cutout is applied mand
498
- you want to preserve the project make sure you provide the full path for the new aedb folder.
499
-
500
- Returns
501
- -------
502
- str
503
- Absolute path for the created aedb folder.
504
- """
505
- return self._output_aedb
506
-
507
- @output_aedb.setter
508
- def output_aedb(self, value): # pragma: no cover
509
- if isinstance(value, str):
510
- self._output_aedb = value
511
-
512
- @property
513
- def sources(self): # pragma: no cover
514
- """Retrieve the source list.
515
-
516
- Returns
517
- -------
518
- :class:`dotnet.database.edb_data.sources.Source`
519
- """
520
- return self._sources
521
-
522
- @sources.setter
523
- def sources(self, value): # pragma: no cover
524
- if isinstance(value, Source):
525
- value = [value]
526
- if isinstance(value, list):
527
- if len([src for src in value if isinstance(src, Source)]) == len(value):
528
- self._sources = value
529
-
530
- def add_source(self, source=None): # pragma: no cover
531
- """Add a new source to configuration.
532
-
533
- Parameters
534
- ----------
535
- source : :class:`pyedb.dotnet.database.edb_data.sources.Source`
536
-
537
- """
538
- if isinstance(source, Source):
539
- self._sources.append(source)
540
-
541
- @property
542
- def honor_user_dielectric(self): # pragma: no cover
543
- """Retrieve the boolean to activate the feature "'Honor user dielectric'".
544
-
545
- Returns
546
- -------
547
- bool
548
- ``True`` activated, ``False`` deactivated.
549
- """
550
- return self._honor_user_dielectric
551
-
552
- @honor_user_dielectric.setter
553
- def honor_user_dielectric(self, value): # pragma: no cover
554
- if isinstance(value, bool):
555
- self._honor_user_dielectric = value
556
-
557
- @property
558
- def truncate_airbox_at_ground(self): # pragma: no cover
559
- """Retrieve the boolean to truncate hfss air box at ground.
560
-
561
- Returns
562
- -------
563
- bool
564
- ``True`` activated, ``False`` deactivated.
565
- """
566
- return self._truncate_airbox_at_ground
567
-
568
- @truncate_airbox_at_ground.setter
569
- def truncate_airbox_at_ground(self, value): # pragma: no cover
570
- if isinstance(value, bool):
571
- self._truncate_airbox_at_ground = value
572
-
573
- @property
574
- def use_radiation_boundary(self): # pragma: no cover
575
- """Retrieve the boolean to use radiation boundary with HFSS.
576
-
577
- Returns
578
- -------
579
- bool
580
- ``True`` activated, ``False`` deactivated.
581
- """
582
- return self._use_radiation_boundary
583
-
584
- @use_radiation_boundary.setter
585
- def use_radiation_boundary(self, value): # pragma: no cover
586
- if isinstance(value, bool):
587
- self._use_radiation_boundary = value
588
-
589
- @property
590
- def signal_layers_properties(self): # pragma: no cover
591
- """Retrieve the list of layers to have properties changes.
592
-
593
- Returns
594
- -------
595
- list[str]
596
- List of layer name.
597
- """
598
- return self._signal_layers_properties
599
-
600
- @signal_layers_properties.setter
601
- def signal_layers_properties(self, value): # pragma: no cover
602
- if isinstance(value, dict):
603
- self._signal_layers_properties = value
604
-
605
- @property
606
- def generate_excitations(self):
607
- """Activate ports and sources for DC generation when build project with the class.
608
-
609
- Returns
610
- -------
611
- bool
612
- ``True`` ports are created, ``False`` skip port generation. Default value is ``True``.
613
-
614
- """
615
- return self._generate_excitations
616
-
617
- @generate_excitations.setter
618
- def generate_excitations(self, value):
619
- if isinstance(value, bool):
620
- self._generate_excitations = value
621
-
622
- @property
623
- def add_frequency_sweep(self):
624
- """Activate the frequency sweep creation when build project with the class.
625
-
626
- Returns
627
- -------
628
- bool
629
- ``True`` frequency sweep is created, ``False`` skip sweep adding. Default value is ``True``.
630
- """
631
- return self._add_frequency_sweep
632
-
633
- @add_frequency_sweep.setter
634
- def add_frequency_sweep(self, value):
635
- if isinstance(value, bool):
636
- self._add_frequency_sweep = value
637
-
638
- @property
639
- def include_only_selected_nets(self):
640
- """Include only net selection in the project. It is only used when ``do_cutout`` is set to ``False``.
641
- Will also be ignored if signal_nets and power_nets are ``None``, resulting project will have all nets included.
642
-
643
- Returns
644
- -------
645
- bool
646
- ``True`` or ``False``. Default value is ``False``.
647
-
648
- """
649
- return self._include_only_selected_nets
650
-
651
- @include_only_selected_nets.setter
652
- def include_only_selected_nets(self, value):
653
- if isinstance(value, bool):
654
- self._include_only_selected_nets = value
655
-
656
-
657
- class SimulationConfigurationDc(object):
658
- """Contains all DC analysis settings.
659
- The class is part of `SimulationConfiguration` class as a property.
660
-
661
- """
662
-
663
- def __init__(self):
664
- self._dc_compute_inductance = False
665
- self._dc_contact_radius = "100um"
666
- self._dc_slide_position = 1
667
- self._dc_use_dc_custom_settings = False
668
- self._dc_plot_jv = True
669
- self._dc_min_plane_area_to_mesh = "8mil2"
670
- self._dc_min_void_area_to_mesh = "0.734mil2"
671
- self._dc_error_energy = 0.02
672
- self._dc_max_init_mesh_edge_length = "5.0mm"
673
- self._dc_max_num_pass = 5
674
- self._dc_min_num_pass = 1
675
- self._dc_mesh_bondwires = True
676
- self._dc_num_bondwire_sides = 8
677
- self._dc_mesh_vias = True
678
- self._dc_num_via_sides = 8
679
- self._dc_percent_local_refinement = 0.2
680
- self._dc_perform_adaptive_refinement = True
681
- self._dc_refine_bondwires = True
682
- self._dc_refine_vias = True
683
- self._dc_report_config_file = ""
684
- self._dc_report_show_Active_devices = True
685
- self._dc_export_thermal_data = True
686
- self._dc_full_report_path = ""
687
- self._dc_icepak_temp_file = ""
688
- self._dc_import_thermal_data = False
689
- self._dc_per_pin_res_path = ""
690
- self._dc_per_pin_use_pin_format = True
691
- self._dc_use_loop_res_for_per_pin = True
692
- self._dc_via_report_path = ""
693
- self._dc_source_terms_to_ground = Dictionary[str, int]()
694
-
695
- @property
696
- def dc_min_plane_area_to_mesh(self): # pragma: no cover
697
- """Retrieve the value of the minimum plane area to be meshed by Siwave for DC solution.
698
-
699
- Returns
700
- -------
701
- float
702
- The value of the minimum plane area.
703
- """
704
- return self._dc_min_plane_area_to_mesh
705
-
706
- @dc_min_plane_area_to_mesh.setter
707
- def dc_min_plane_area_to_mesh(self, value): # pragma: no cover
708
- if isinstance(value, str):
709
- self._dc_min_plane_area_to_mesh = value
710
-
711
- @property
712
- def dc_compute_inductance(self):
713
- """Return the boolean for computing the inductance with SIwave DC solver.
714
-
715
- Returns
716
- -------
717
- bool
718
- ``True`` activate ``False`` deactivated.
719
- """
720
- return self._dc_compute_inductance
721
-
722
- @dc_compute_inductance.setter
723
- def dc_compute_inductance(self, value):
724
- if isinstance(value, bool):
725
- self._dc_compute_inductance = value
726
-
727
- @property
728
- def dc_contact_radius(self):
729
- """Retrieve the value for SIwave DC contact radius.
730
-
731
- Returns
732
- -------
733
- str
734
- The contact radius value.
735
-
736
- """
737
- return self._dc_contact_radius
738
-
739
- @dc_contact_radius.setter
740
- def dc_contact_radius(self, value):
741
- if isinstance(value, str):
742
- self._dc_contact_radius = value
743
-
744
- @dc_compute_inductance.setter
745
- def dc_compute_inductance(self, value):
746
- if isinstance(value, str):
747
- self._dc_contact_radius = value
748
-
749
- @property
750
- def dc_slide_position(self):
751
- """Retrieve the SIwave DC slide position value.
752
-
753
- Returns
754
- -------
755
- int
756
- The position value, 0 Optimum speed, 1 balanced, 2 optimum accuracy.
757
- """
758
- return self._dc_slide_position
759
-
760
- @dc_slide_position.setter
761
- def dc_slide_position(self, value):
762
- if isinstance(value, int):
763
- self._dc_slide_position = value
764
-
765
- @property
766
- def dc_use_dc_custom_settings(self):
767
- """Retrieve the value for using DC custom settings.
768
-
769
- Returns
770
- -------
771
- bool
772
- ``True`` when activated, ``False`` deactivated.
773
-
774
- """
775
- return self._dc_use_dc_custom_settings
776
-
777
- @dc_use_dc_custom_settings.setter
778
- def dc_use_dc_custom_settings(self, value):
779
- if isinstance(value, bool):
780
- self._dc_use_dc_custom_settings = value
781
-
782
- @property
783
- def dc_plot_jv(self):
784
- """Retrieve the value for computing current density and voltage distribution.
785
-
786
- Returns
787
- -------
788
- bool
789
- ``True`` when activated, ``False`` deactivated. Default value True
790
-
791
- """
792
- return self._dc_plot_jv
793
-
794
- @dc_plot_jv.setter
795
- def dc_plot_jv(self, value):
796
- if isinstance(value, bool):
797
- self._dc_plot_jv = value
798
-
799
- @property
800
- def dc_min_void_area_to_mesh(self):
801
- """Retrieve the value for the minimum void surface to mesh.
802
-
803
- Returns
804
- -------
805
- str
806
- The area value.
807
-
808
- """
809
- return self._dc_min_void_area_to_mesh
810
-
811
- @dc_min_void_area_to_mesh.setter
812
- def dc_min_void_area_to_mesh(self, value):
813
- if isinstance(value, str):
814
- self._dc_min_void_area_to_mesh = value
815
-
816
- @property
817
- def dc_error_energy(self):
818
- """Retrieve the value for the DC error energy.
819
-
820
- Returns
821
- -------
822
- float
823
- The error energy value, 0.2 as default.
824
-
825
- """
826
- return self._dc_error_energy
827
-
828
- @dc_error_energy.setter
829
- def dc_error_energy(self, value):
830
- if isinstance(value, (int, float)):
831
- self._dc_error_energy = value
832
-
833
- @property
834
- def dc_max_init_mesh_edge_length(self):
835
- """Retrieve the maximum initial mesh edge value.
836
-
837
- Returns
838
- -------
839
- str
840
- maximum mesh length.
841
-
842
- """
843
- return self._dc_max_init_mesh_edge_length
844
-
845
- @dc_max_init_mesh_edge_length.setter
846
- def dc_max_init_mesh_edge_length(self, value):
847
- if isinstance(value, str):
848
- self._dc_max_init_mesh_edge_length = value
849
-
850
- @property
851
- def dc_max_num_pass(self):
852
- """Retrieve the maximum number of adaptive passes.
853
-
854
- Returns
855
- -------
856
- int
857
- number of passes.
858
- """
859
- return self._dc_max_num_pass
860
-
861
- @dc_max_num_pass.setter
862
- def dc_max_num_pass(self, value):
863
- if isinstance(value, int):
864
- self._dc_max_num_pass = value
865
-
866
- @property
867
- def dc_min_num_pass(self):
868
- """Retrieve the minimum number of adaptive passes.
869
-
870
- Returns
871
- -------
872
- int
873
- number of passes.
874
- """
875
- return self._dc_min_num_pass
876
-
877
- @dc_min_num_pass.setter
878
- def dc_min_num_pass(self, value):
879
- if isinstance(value, int):
880
- self._dc_min_num_pass = value
881
-
882
- @property
883
- def dc_mesh_bondwires(self):
884
- """Retrieve the value for meshing bondwires.
885
-
886
- Returns
887
- -------
888
- bool
889
- ``True`` when activated, ``False`` deactivated.
890
-
891
- """
892
- return self._dc_mesh_bondwires
893
-
894
- @dc_mesh_bondwires.setter
895
- def dc_mesh_bondwires(self, value):
896
- if isinstance(value, bool):
897
- self._dc_mesh_bondwires = value
898
-
899
- @property
900
- def dc_num_bondwire_sides(self):
901
- """Retrieve the number of sides used for cylinder discretization.
902
-
903
- Returns
904
- -------
905
- int
906
- Number of sides.
907
-
908
- """
909
- return self._dc_num_bondwire_sides
910
-
911
- @dc_num_bondwire_sides.setter
912
- def dc_num_bondwire_sides(self, value):
913
- if isinstance(value, int):
914
- self._dc_num_bondwire_sides = value
915
-
916
- @property
917
- def dc_mesh_vias(self):
918
- """Retrieve the value for meshing vias.
919
-
920
- Returns
921
- -------
922
- bool
923
- ``True`` when activated, ``False`` deactivated.
924
-
925
- """
926
- return self._dc_mesh_vias
927
-
928
- @dc_mesh_vias.setter
929
- def dc_mesh_vias(self, value):
930
- if isinstance(value, bool):
931
- self._dc_mesh_vias = value
932
-
933
- @property
934
- def dc_num_via_sides(self):
935
- """Retrieve the number of sides used for cylinder discretization.
936
-
937
- Returns
938
- -------
939
- int
940
- Number of sides.
941
-
942
- """
943
- return self._dc_num_via_sides
944
-
945
- @dc_num_via_sides.setter
946
- def dc_num_via_sides(self, value):
947
- if isinstance(value, int):
948
- self._dc_num_via_sides = value
949
-
950
- @property
951
- def dc_percent_local_refinement(self):
952
- """Retrieve the value for local mesh refinement.
953
-
954
- Returns
955
- -------
956
- float
957
- The refinement value, 0.2 (20%) as default.
958
-
959
- """
960
- return self._dc_percent_local_refinement
961
-
962
- @dc_percent_local_refinement.setter
963
- def dc_percent_local_refinement(self, value):
964
- if isinstance(value, (int, float)):
965
- self._dc_percent_local_refinement = value
966
-
967
- @property
968
- def dc_perform_adaptive_refinement(self):
969
- """Retrieve the value for performing adaptive meshing.
970
-
971
- Returns
972
- -------
973
- bool
974
- ``True`` when activated, ``False`` deactivated.
975
-
976
- """
977
- return self._dc_perform_adaptive_refinement
978
-
979
- @dc_perform_adaptive_refinement.setter
980
- def dc_perform_adaptive_refinement(self, value):
981
- if isinstance(value, bool):
982
- self._dc_perform_adaptive_refinement = value
983
-
984
- @property
985
- def dc_refine_bondwires(self):
986
- """Retrieve the value for performing bond wire refinement.
987
-
988
- Returns
989
- -------
990
- bool
991
- ``True`` when activated, ``False`` deactivated.
992
-
993
- """
994
- return self._dc_refine_bondwires
995
-
996
- @dc_refine_bondwires.setter
997
- def dc_refine_bondwires(self, value):
998
- if isinstance(value, bool):
999
- self._dc_refine_bondwires = value
1000
-
1001
- @property
1002
- def dc_refine_vias(self):
1003
- """Retrieve the value for performing vias refinement.
1004
-
1005
- Returns
1006
- -------
1007
- bool
1008
- ``True`` when activated, ``False`` deactivated.
1009
-
1010
- """
1011
- return self._dc_refine_vias
1012
-
1013
- @dc_refine_vias.setter
1014
- def dc_refine_vias(self, value):
1015
- if isinstance(value, bool):
1016
- self._dc_refine_vias = value
1017
-
1018
- @property
1019
- def dc_report_config_file(self):
1020
- """Retrieve the report configuration file path.
1021
-
1022
- Returns
1023
- -------
1024
- str
1025
- The file path.
1026
-
1027
- """
1028
- return self._dc_report_config_file
1029
-
1030
- @dc_report_config_file.setter
1031
- def dc_report_config_file(self, value):
1032
- if isinstance(value, str):
1033
- self._dc_report_config_file = value
1034
-
1035
- @property
1036
- def dc_report_show_Active_devices(self):
1037
- """Retrieve the value for showing active devices.
1038
-
1039
- Returns
1040
- -------
1041
- bool
1042
- ``True`` when activated, ``False`` deactivated.
1043
-
1044
- """
1045
- return self._dc_report_show_Active_devices
1046
-
1047
- @dc_report_show_Active_devices.setter
1048
- def dc_report_show_Active_devices(self, value):
1049
- if isinstance(value, bool):
1050
- self._dc_report_show_Active_devices = value
1051
-
1052
- @property
1053
- def dc_export_thermal_data(self):
1054
- """Retrieve the value for using external data.
1055
-
1056
- Returns
1057
- -------
1058
- bool
1059
- ``True`` when activated, ``False`` deactivated.
1060
-
1061
- """
1062
- return self._dc_export_thermal_data
1063
-
1064
- @dc_export_thermal_data.setter
1065
- def dc_export_thermal_data(self, value):
1066
- if isinstance(value, bool):
1067
- self._dc_export_thermal_data = value
1068
-
1069
- @property
1070
- def dc_full_report_path(self):
1071
- """Retrieve the path for the report.
1072
-
1073
- Returns
1074
- -------
1075
- str
1076
- File path.
1077
-
1078
- """
1079
- return self._dc_full_report_path
1080
-
1081
- @dc_full_report_path.setter
1082
- def dc_full_report_path(self, value):
1083
- if isinstance(value, str):
1084
- self._dc_full_report_path = value
1085
-
1086
- @property
1087
- def dc_icepak_temp_file(self):
1088
- """Retrieve the icepak temp file path.
1089
-
1090
- Returns
1091
- -------
1092
- str
1093
- File path.
1094
- """
1095
- return self._dc_icepak_temp_file
1096
-
1097
- @dc_icepak_temp_file.setter
1098
- def dc_icepak_temp_file(self, value):
1099
- if isinstance(value, str):
1100
- self._dc_icepak_temp_file = value
1101
-
1102
- @property
1103
- def dc_import_thermal_data(self):
1104
- """Retrieve the value for importing thermal data.
1105
-
1106
- Returns
1107
- -------
1108
- bool
1109
- ``True`` when activated,``False`` deactivated.
1110
-
1111
- """
1112
- return self._dc_import_thermal_data
1113
-
1114
- @dc_import_thermal_data.setter
1115
- def dc_import_thermal_data(self, value):
1116
- if isinstance(value, bool):
1117
- self._dc_import_thermal_data = value
1118
-
1119
- @property
1120
- def dc_per_pin_res_path(self):
1121
- """Retrieve the file path.
1122
-
1123
- Returns
1124
- -------
1125
- str
1126
- The file path.
1127
- """
1128
- return self._dc_per_pin_res_path
1129
-
1130
- @dc_per_pin_res_path.setter
1131
- def dc_per_pin_res_path(self, value):
1132
- if isinstance(value, str):
1133
- self._dc_per_pin_res_path = value
1134
-
1135
- @property
1136
- def dc_per_pin_use_pin_format(self):
1137
- """Retrieve the value for using pin format.
1138
-
1139
- Returns
1140
- -------
1141
- bool
1142
- """
1143
- return self._dc_per_pin_use_pin_format
1144
-
1145
- @dc_per_pin_use_pin_format.setter
1146
- def dc_per_pin_use_pin_format(self, value):
1147
- if isinstance(value, bool):
1148
- self._dc_per_pin_use_pin_format = value
1149
-
1150
- @property
1151
- def dc_use_loop_res_for_per_pin(self):
1152
- """Retrieve the value for using the loop resistor per pin.
1153
-
1154
- Returns
1155
- -------
1156
- bool
1157
- """
1158
- return self._dc_use_loop_res_for_per_pin
1159
-
1160
- @dc_use_loop_res_for_per_pin.setter
1161
- def dc_use_loop_res_for_per_pin(self, value):
1162
- if isinstance(value, bool):
1163
- self._dc_use_loop_res_for_per_pin = value
1164
-
1165
- @property
1166
- def dc_via_report_path(self):
1167
- """Retrieve the via report file path.
1168
-
1169
- Returns
1170
- -------
1171
- str
1172
- The file path.
1173
-
1174
- """
1175
- return self._dc_via_report_path
1176
-
1177
- @dc_via_report_path.setter
1178
- def dc_via_report_path(self, value):
1179
- if isinstance(value, str):
1180
- self._dc_via_report_path = value
1181
-
1182
- @dc_via_report_path.setter
1183
- def dc_via_report_path(self, value):
1184
- if isinstance(value, str):
1185
- self._dc_via_report_path = value
1186
-
1187
- @property
1188
- def dc_source_terms_to_ground(self):
1189
- """Retrieve the dictionary of grounded terminals.
1190
-
1191
- Returns
1192
- -------
1193
- Dictionary
1194
- {str, int}, keys is source name, value int 0 unspecified, 1 negative node, 2 positive one.
1195
-
1196
- """
1197
- return self._dc_source_terms_to_ground
1198
-
1199
- @dc_source_terms_to_ground.setter
1200
- def dc_source_terms_to_ground(self, value): # pragma: no cover
1201
- if isinstance(value, OrderedDict):
1202
- if len([k for k in value.keys() if isinstance(k, str)]) == len(value.keys()):
1203
- if len([v for v in value.values() if isinstance(v, int)]) == len(value.values()):
1204
- self._dc_source_terms_to_ground = value
1205
-
1206
-
1207
- class SimulationConfigurationAc(object):
1208
- """Contains all AC analysis settings.
1209
- The class is part of `SimulationConfiguration` class as a property.
1210
-
1211
- """
1212
-
1213
- def __init__(self):
1214
- self._sweep_interpolating = True
1215
- self._use_q3d_for_dc = False
1216
- self._relative_error = 0.005
1217
- self._use_error_z0 = False
1218
- self._percentage_error_z0 = 1
1219
- self._enforce_causality = True
1220
- self._enforce_passivity = False
1221
- self._passivity_tolerance = 0.0001
1222
- self._sweep_name = "Sweep1"
1223
- self._radiation_box = RadiationBoxType.ConvexHull # 'ConvexHull'
1224
- self._start_freq = "0.0GHz" # 0.0
1225
- self._stop_freq = "10.0GHz" # 10e9
1226
- self._sweep_type = SweepType.Linear # 'Linear'
1227
- self._step_freq = "0.025GHz" # 10e6
1228
- self._decade_count = 100 # Newly Added
1229
- self._mesh_freq = "3GHz" # 5e9
1230
- self._max_num_passes = 30
1231
- self._max_mag_delta_s = 0.03
1232
- self._min_num_passes = 1
1233
- self._basis_order = BasisOrder.Mixed # 'Mixed'
1234
- self._do_lambda_refinement = True
1235
- self._arc_angle = "30deg" # 30
1236
- self._start_azimuth = 0
1237
- self._max_arc_points = 8
1238
- self._use_arc_to_chord_error = True
1239
- self._arc_to_chord_error = "1um" # 1e-6
1240
- self._defeature_abs_length = "1um" # 1e-6
1241
- self._defeature_layout = True
1242
- self._minimum_void_surface = 0
1243
- self._max_suf_dev = 1e-3
1244
- self._process_padstack_definitions = False
1245
- self._return_current_distribution = True
1246
- self._ignore_non_functional_pads = True
1247
- self._include_inter_plane_coupling = True
1248
- self._xtalk_threshold = -50
1249
- self._min_void_area = "0.01mm2"
1250
- self._min_pad_area_to_mesh = "0.01mm2"
1251
- self._snap_length_threshold = "2.5um"
1252
- self._min_plane_area_to_mesh = "4mil2" # Newly Added
1253
- self._mesh_sizefactor = 0.0
1254
- self._adaptive_type = AdaptiveType.SingleFrequency
1255
- self._adaptive_low_freq = "0GHz"
1256
- self._adaptive_high_freq = "20GHz"
1257
-
1258
- @property
1259
- def sweep_interpolating(self): # pragma: no cover
1260
- """Retrieve boolean to add a sweep interpolating sweep.
1261
-
1262
- Returns
1263
- -------
1264
- bool
1265
- ``True`` when a sweep interpolating is defined, ``False`` when a discrete one is defined instead.
1266
- """
1267
-
1268
- return self._sweep_interpolating
1269
-
1270
- @sweep_interpolating.setter
1271
- def sweep_interpolating(self, value): # pragma: no cover
1272
- if isinstance(value, bool):
1273
- self._sweep_interpolating = value
1274
-
1275
- @property
1276
- def use_q3d_for_dc(self): # pragma: no cover
1277
- """Retrieve boolean to Q3D solver for DC point value computation.
1278
-
1279
- Returns
1280
- -------
1281
- bool
1282
- ``True`` when Q3D solver is used ``False`` when interpolating value is used instead.
1283
- """
1284
-
1285
- return self._use_q3d_for_dc
1286
-
1287
- @use_q3d_for_dc.setter
1288
- def use_q3d_for_dc(self, value): # pragma: no cover
1289
- if isinstance(value, bool):
1290
- self._use_q3d_for_dc = value
1291
-
1292
- @property
1293
- def relative_error(self): # pragma: no cover
1294
- """Retrieve relative error used for the interpolating sweep convergence.
1295
-
1296
- Returns
1297
- -------
1298
- float
1299
- The value of the error interpolating sweep to reach the convergence criteria.
1300
- """
1301
-
1302
- return self._relative_error
1303
-
1304
- @relative_error.setter
1305
- def relative_error(self, value): # pragma: no cover
1306
- if isinstance(value, (int, float)):
1307
- self._relative_error = value
1308
-
1309
- @property
1310
- def use_error_z0(self): # pragma: no cover
1311
- """Retrieve value for the error on Z0 for the port.
1312
-
1313
- Returns
1314
- -------
1315
- float
1316
- The Z0 value.
1317
- """
1318
-
1319
- return self._use_error_z0
1320
-
1321
- @use_error_z0.setter
1322
- def use_error_z0(self, value): # pragma: no cover
1323
- if isinstance(value, bool):
1324
- self._use_error_z0 = value
1325
-
1326
- @property
1327
- def percentage_error_z0(self): # pragma: no cover
1328
- """Retrieve boolean to perform the cutout during the project build.
1329
-
1330
- Returns
1331
- -------
1332
- bool
1333
- ``True`` when clipping the design is applied ``False`` if not.
1334
- """
1335
-
1336
- return self._percentage_error_z0
1337
-
1338
- @percentage_error_z0.setter
1339
- def percentage_error_z0(self, value): # pragma: no cover
1340
- if isinstance(value, (int, float)):
1341
- self._percentage_error_z0 = value
1342
-
1343
- @property
1344
- def enforce_causality(self): # pragma: no cover
1345
- """Retrieve boolean to enforce causality for the frequency sweep.
1346
-
1347
- Returns
1348
- -------
1349
- bool
1350
- ``True`` when causality is enforced ``False`` if not.
1351
- """
1352
-
1353
- return self._enforce_causality
1354
-
1355
- @enforce_causality.setter
1356
- def enforce_causality(self, value): # pragma: no cover
1357
- if isinstance(value, bool):
1358
- self._enforce_causality = value
1359
-
1360
- @property
1361
- def enforce_passivity(self): # pragma: no cover
1362
- """Retrieve boolean to enforce passivity for the frequency sweep.
1363
-
1364
- Returns
1365
- -------
1366
- bool
1367
- ``True`` when passivity is enforced ``False`` if not.
1368
- """
1369
- return self._enforce_passivity
1370
-
1371
- @enforce_passivity.setter
1372
- def enforce_passivity(self, value): # pragma: no cover
1373
- if isinstance(value, bool):
1374
- self._enforce_passivity = value
1375
-
1376
- @property
1377
- def passivity_tolerance(self): # pragma: no cover
1378
- """Retrieve the value for the passivity tolerance when used.
1379
-
1380
- Returns
1381
- -------
1382
- float
1383
- The passivity tolerance criteria for the frequency sweep.
1384
- """
1385
- return self._passivity_tolerance
1386
-
1387
- @passivity_tolerance.setter
1388
- def passivity_tolerance(self, value): # pragma: no cover
1389
- if isinstance(value, (int, float)):
1390
- self._passivity_tolerance = value
1391
-
1392
- @property
1393
- def sweep_name(self): # pragma: no cover
1394
- """Retrieve frequency sweep name.
1395
-
1396
- Returns
1397
- -------
1398
- str
1399
- The name of the frequency sweep defined in the project.
1400
- """
1401
- return self._sweep_name
1402
-
1403
- @sweep_name.setter
1404
- def sweep_name(self, value): # pragma: no cover
1405
- if isinstance(value, str):
1406
- self._sweep_name = value
1407
-
1408
- @property
1409
- def radiation_box(self): # pragma: no cover
1410
- """Retrieve RadiationBoxType object selection defined for the radiation box type.
1411
-
1412
- Returns
1413
- -------
1414
- RadiationBoxType object
1415
- 3 values can be chosen, Conformal, BoundingBox or ConvexHull.
1416
- """
1417
- return self._radiation_box
1418
-
1419
- @radiation_box.setter
1420
- def radiation_box(self, value):
1421
- if validate_enum_class_value(RadiationBoxType, value):
1422
- self._radiation_box = value
1423
-
1424
- @property
1425
- def start_freq(self): # pragma: no cover
1426
- """Starting frequency for the frequency sweep.
1427
-
1428
- Returns
1429
- -------
1430
- float
1431
- Value of the frequency point.
1432
- """
1433
- return self._start_freq
1434
-
1435
- @start_freq.setter
1436
- def start_freq(self, value): # pragma: no cover
1437
- if isinstance(value, str):
1438
- self._start_freq = value
1439
-
1440
- @property
1441
- def stop_freq(self): # pragma: no cover
1442
- """Retrieve stop frequency for the frequency sweep.
1443
-
1444
- Returns
1445
- -------
1446
- float
1447
- The value of the frequency point.
1448
- """
1449
- return self._stop_freq
1450
-
1451
- @stop_freq.setter
1452
- def stop_freq(self, value): # pragma: no cover
1453
- if isinstance(value, str):
1454
- self._stop_freq = value
1455
-
1456
- @property
1457
- def sweep_type(self): # pragma: no cover
1458
- """Retrieve SweepType object for the frequency sweep.
1459
-
1460
- Returns
1461
- -------
1462
- SweepType
1463
- The SweepType object,2 selections are supported Linear and LogCount.
1464
- """
1465
- return self._sweep_type
1466
-
1467
- @sweep_type.setter
1468
- def sweep_type(self, value): # pragma: no cover
1469
- if validate_enum_class_value(SweepType, value):
1470
- self._sweep_type = value
1471
-
1472
- @property
1473
- def step_freq(self): # pragma: no cover
1474
- """Retrieve step frequency for the frequency sweep.
1475
-
1476
- Returns
1477
- -------
1478
- float
1479
- The value of the frequency point.
1480
- """
1481
- return self._step_freq
1482
-
1483
- @step_freq.setter
1484
- def step_freq(self, value): # pragma: no cover
1485
- if isinstance(value, str):
1486
- self._step_freq = value
1487
-
1488
- @property
1489
- def decade_count(self): # pragma: no cover
1490
- """Retrieve decade count number for the frequency sweep in case of a log sweep selected.
1491
-
1492
- Returns
1493
- -------
1494
- int
1495
- The value of the decade count number.
1496
- """
1497
- return self._decade_count
1498
-
1499
- @decade_count.setter
1500
- def decade_count(self, value): # pragma: no cover
1501
- if isinstance(value, int):
1502
- self._decade_count = value
1503
-
1504
- @property
1505
- def mesh_freq(self):
1506
- """Retrieve the meshing frequency for the HFSS adaptive convergence.
1507
-
1508
- Returns
1509
- -------
1510
- float
1511
- The value of the frequency point.
1512
- """
1513
- return self._mesh_freq
1514
-
1515
- @mesh_freq.setter
1516
- def mesh_freq(self, value): # pragma: no cover
1517
- if isinstance(value, str):
1518
- self._mesh_freq = value
1519
-
1520
- @property
1521
- def max_num_passes(self): # pragma: no cover
1522
- """Retrieve maximum of points for the HFSS adaptive meshing.
1523
-
1524
- Returns
1525
- -------
1526
- int
1527
- The maximum number of adaptive passes value.
1528
- """
1529
- return self._max_num_passes
1530
-
1531
- @max_num_passes.setter
1532
- def max_num_passes(self, value): # pragma: no cover
1533
- if isinstance(value, int):
1534
- self._max_num_passes = value
1535
-
1536
- @property
1537
- def max_mag_delta_s(self): # pragma: no cover
1538
- """Retrieve the magnitude of the delta S convergence criteria for the interpolating sweep.
1539
-
1540
- Returns
1541
- -------
1542
- float
1543
- The value of convergence criteria.
1544
- """
1545
- return self._max_mag_delta_s
1546
-
1547
- @max_mag_delta_s.setter
1548
- def max_mag_delta_s(self, value): # pragma: no cover
1549
- if isinstance(value, (int, float)):
1550
- self._max_mag_delta_s = value
1551
-
1552
- @property
1553
- def min_num_passes(self): # pragma: no cover
1554
- """Retrieve the minimum number of adaptive passes for HFSS convergence.
1555
-
1556
- Returns
1557
- -------
1558
- int
1559
- The value of minimum number of adaptive passes.
1560
- """
1561
- return self._min_num_passes
1562
-
1563
- @min_num_passes.setter
1564
- def min_num_passes(self, value): # pragma: no cover
1565
- if isinstance(value, int):
1566
- self._min_num_passes = value
1567
-
1568
- @property
1569
- def basis_order(self): # pragma: no cover
1570
- """Retrieve the BasisOrder object.
1571
-
1572
- Returns
1573
- -------
1574
- BasisOrder class
1575
- This class supports 4 selections Mixed, Zero, single and Double for the HFSS order matrix.
1576
- """
1577
- return self._basis_order
1578
-
1579
- @basis_order.setter
1580
- def basis_order(self, value): # pragma: no cover
1581
- if validate_enum_class_value(BasisOrder, value):
1582
- self._basis_order = value
1583
-
1584
- @property
1585
- def do_lambda_refinement(self): # pragma: no cover
1586
- """Retrieve boolean to activate the lambda refinement.
1587
-
1588
- Returns
1589
- -------
1590
- bool
1591
- ``True`` Enable the lambda meshing refinement with HFSS, ``False`` deactivate.
1592
- """
1593
- return self._do_lambda_refinement
1594
-
1595
- @do_lambda_refinement.setter
1596
- def do_lambda_refinement(self, value): # pragma: no cover
1597
- if isinstance(value, bool):
1598
- self._do_lambda_refinement = value
1599
-
1600
- @property
1601
- def arc_angle(self): # pragma: no cover
1602
- """Retrieve the value for the HFSS meshing arc angle.
1603
-
1604
- Returns
1605
- -------
1606
- float
1607
- Value of the arc angle.
1608
- """
1609
- return self._arc_angle
1610
-
1611
- @arc_angle.setter
1612
- def arc_angle(self, value): # pragma: no cover
1613
- if isinstance(value, str):
1614
- self._arc_angle = value
1615
-
1616
- @property
1617
- def start_azimuth(self): # pragma: no cover
1618
- """Retrieve the value of the starting azimuth for the HFSS meshing.
1619
-
1620
- Returns
1621
- -------
1622
- float
1623
- Value of the starting azimuth.
1624
- """
1625
- return self._start_azimuth
1626
-
1627
- @start_azimuth.setter
1628
- def start_azimuth(self, value): # pragma: no cover
1629
- if isinstance(value, (int, float)):
1630
- self._start_azimuth = value
1631
-
1632
- @property
1633
- def max_arc_points(self): # pragma: no cover
1634
- """Retrieve the value of the maximum arc points number for the HFSS meshing.
1635
-
1636
- Returns
1637
- -------
1638
- int
1639
- Value of the maximum arc point number.
1640
- """
1641
- return self._max_arc_points
1642
-
1643
- @max_arc_points.setter
1644
- def max_arc_points(self, value): # pragma: no cover
1645
- if isinstance(value, int):
1646
- self._max_arc_points = value
1647
-
1648
- @property
1649
- def use_arc_to_chord_error(self): # pragma: no cover
1650
- """Retrieve the boolean for activating the arc to chord for HFSS meshing.
1651
-
1652
- Returns
1653
- -------
1654
- bool
1655
- Activate when ``True``, deactivated when ``False``.
1656
- """
1657
- return self._use_arc_to_chord_error
1658
-
1659
- @use_arc_to_chord_error.setter
1660
- def use_arc_to_chord_error(self, value): # pragma: no cover
1661
- if isinstance(value, bool):
1662
- self._use_arc_to_chord_error = value
1663
-
1664
- @property
1665
- def arc_to_chord_error(self): # pragma: no cover
1666
- """Retrieve the value of arc to chord error for HFSS meshing.
1667
-
1668
- Returns
1669
- -------
1670
- flot
1671
- Value of the arc to chord error.
1672
- """
1673
- return self._arc_to_chord_error
1674
-
1675
- @arc_to_chord_error.setter
1676
- def arc_to_chord_error(self, value): # pragma: no cover
1677
- if isinstance(value, str):
1678
- self._arc_to_chord_error = value
1679
-
1680
- @property
1681
- def defeature_abs_length(self): # pragma: no cover
1682
- """Retrieve the value of arc to chord for HFSS meshing.
1683
-
1684
- Returns
1685
- -------
1686
- flot
1687
- Value of the arc to chord error.
1688
- """
1689
- return self._defeature_abs_length
1690
-
1691
- @defeature_abs_length.setter
1692
- def defeature_abs_length(self, value): # pragma: no cover
1693
- if isinstance(value, str):
1694
- self._defeature_abs_length = value
1695
-
1696
- @property
1697
- def defeature_layout(self): # pragma: no cover
1698
- """Retrieve the boolean to activate the layout defeaturing.This method has been developed to simplify polygons
1699
- with reducing the number of points to simplify the meshing with controlling its surface deviation. This method
1700
- should be used at last resort when other methods failed.
1701
-
1702
- Returns
1703
- -------
1704
- bool
1705
- ``True`` when activated 'False when deactivated.
1706
- """
1707
- return self._defeature_layout
1708
-
1709
- @defeature_layout.setter
1710
- def defeature_layout(self, value): # pragma: no cover
1711
- if isinstance(value, bool):
1712
- self._defeature_layout = value
1713
-
1714
- @property
1715
- def minimum_void_surface(self): # pragma: no cover
1716
- """Retrieve the minimum void surface to be considered for the layout defeaturing.
1717
- Voids below this value will be ignored.
1718
-
1719
- Returns
1720
- -------
1721
- flot
1722
- Value of the minimum surface.
1723
- """
1724
- return self._minimum_void_surface
1725
-
1726
- @minimum_void_surface.setter
1727
- def minimum_void_surface(self, value): # pragma: no cover
1728
- if isinstance(value, (int, float)):
1729
- self._minimum_void_surface = value
1730
-
1731
- @property
1732
- def max_suf_dev(self): # pragma: no cover
1733
- """Retrieve the value for the maximum surface deviation for the layout defeaturing.
1734
-
1735
- Returns
1736
- -------
1737
- flot
1738
- Value of maximum surface deviation.
1739
- """
1740
- return self._max_suf_dev
1741
-
1742
- @max_suf_dev.setter
1743
- def max_suf_dev(self, value): # pragma: no cover
1744
- if isinstance(value, (int, float)):
1745
- self._max_suf_dev = value
1746
-
1747
- @property
1748
- def process_padstack_definitions(self): # pragma: no cover
1749
- """Retrieve the boolean for activating the padstack definition processing.
1750
-
1751
- Returns
1752
- -------
1753
- flot
1754
- Value of the arc to chord error.
1755
- """
1756
- return self._process_padstack_definitions
1757
-
1758
- @process_padstack_definitions.setter
1759
- def process_padstack_definitions(self, value): # pragma: no cover
1760
- if isinstance(value, bool):
1761
- self._process_padstack_definitions = value
1762
-
1763
- @property
1764
- def return_current_distribution(self): # pragma: no cover
1765
- """Boolean to activate the current distribution return with Siwave.
1766
-
1767
- Returns
1768
- -------
1769
- flot
1770
- Value of the arc to chord error.
1771
- """
1772
- return self._return_current_distribution
1773
-
1774
- @return_current_distribution.setter
1775
- def return_current_distribution(self, value): # pragma: no cover
1776
- if isinstance(value, bool):
1777
- self._return_current_distribution = value
1778
-
1779
- @property
1780
- def ignore_non_functional_pads(self): # pragma: no cover
1781
- """Boolean to ignore nonfunctional pads with Siwave.
1782
-
1783
- Returns
1784
- -------
1785
- flot
1786
- Value of the arc to chord error.
1787
- """
1788
- return self._ignore_non_functional_pads
1789
-
1790
- @ignore_non_functional_pads.setter
1791
- def ignore_non_functional_pads(self, value): # pragma: no cover
1792
- if isinstance(value, bool):
1793
- self._ignore_non_functional_pads = value
1794
-
1795
- @property
1796
- def include_inter_plane_coupling(self): # pragma: no cover
1797
- """Boolean to activate the inter-plane coupling with Siwave.
1798
-
1799
- Returns
1800
- -------
1801
- bool
1802
- ``True`` activated ``False`` deactivated.
1803
- """
1804
- return self._include_inter_plane_coupling
1805
-
1806
- @include_inter_plane_coupling.setter
1807
- def include_inter_plane_coupling(self, value): # pragma: no cover
1808
- if isinstance(value, bool):
1809
- self._include_inter_plane_coupling = value
1810
-
1811
- @property
1812
- def xtalk_threshold(self): # pragma: no cover
1813
- """Return the value for Siwave cross talk threshold. THis value specifies the distance for the solver to
1814
- consider lines coupled during the cross-section computation. Decreasing the value below -60dB can
1815
- potentially cause solver failure.
1816
-
1817
- Returns
1818
- -------
1819
- flot
1820
- Value of cross-talk threshold.
1821
- """
1822
- return self._xtalk_threshold
1823
-
1824
- @xtalk_threshold.setter
1825
- def xtalk_threshold(self, value): # pragma: no cover
1826
- if isinstance(value, (int, float)):
1827
- self._xtalk_threshold = value
1828
-
1829
- @property
1830
- def min_void_area(self): # pragma: no cover
1831
- """Retrieve the value of minimum void area to be considered by Siwave.
1832
-
1833
- Returns
1834
- -------
1835
- flot
1836
- Value of the arc to chord error.
1837
- """
1838
- return self._min_void_area
1839
-
1840
- @min_void_area.setter
1841
- def min_void_area(self, value): # pragma: no cover
1842
- if isinstance(value, str):
1843
- self._min_void_area = value
1844
-
1845
- @property
1846
- def min_pad_area_to_mesh(self): # pragma: no cover
1847
- """Retrieve the value of minimum pad area to be meshed by Siwave.
1848
-
1849
- Returns
1850
- -------
1851
- flot
1852
- Value of minimum pad surface.
1853
- """
1854
- return self._min_pad_area_to_mesh
1855
-
1856
- @min_pad_area_to_mesh.setter
1857
- def min_pad_area_to_mesh(self, value): # pragma: no cover
1858
- if isinstance(value, str):
1859
- self._min_pad_area_to_mesh = value
1860
-
1861
- @property
1862
- def snap_length_threshold(self): # pragma: no cover
1863
- """Retrieve the boolean to activate the snapping threshold feature.
1864
-
1865
- Returns
1866
- -------
1867
- bool
1868
- ``True`` activate ``False`` deactivated.
1869
- """
1870
- return self._snap_length_threshold
1871
-
1872
- @snap_length_threshold.setter
1873
- def snap_length_threshold(self, value): # pragma: no cover
1874
- if isinstance(value, str):
1875
- self._snap_length_threshold = value
1876
-
1877
- @property
1878
- def min_plane_area_to_mesh(self): # pragma: no cover
1879
- """Retrieve the minimum plane area to be meshed by Siwave.
1880
-
1881
- Returns
1882
- -------
1883
- flot
1884
- Value of the minimum plane area.
1885
- """
1886
- return self._min_plane_area_to_mesh
1887
-
1888
- @min_plane_area_to_mesh.setter
1889
- def min_plane_area_to_mesh(self, value): # pragma: no cover
1890
- if isinstance(value, str):
1891
- self._min_plane_area_to_mesh = value
1892
-
1893
- @property
1894
- def mesh_sizefactor(self):
1895
- """Retrieve the Mesh Size factor value.
1896
-
1897
- Returns
1898
- -------
1899
- float
1900
- """
1901
- return self._mesh_sizefactor
1902
-
1903
- @mesh_sizefactor.setter
1904
- def mesh_sizefactor(self, value):
1905
- if isinstance(value, (int, float)):
1906
- self._mesh_sizefactor = value
1907
- if value > 0.0:
1908
- self._do_lambda_refinement = False
1909
-
1910
- @property
1911
- def adaptive_type(self):
1912
- """HFSS adaptive type.
1913
-
1914
- Returns
1915
- -------
1916
- class: pyedb.dotnet.database.edb_data.simulation_setup.AdaptiveType
1917
- """
1918
- return self._adaptive_type
1919
-
1920
- @adaptive_type.setter
1921
- def adaptive_type(self, value):
1922
- if isinstance(value, int) and value in range(3):
1923
- self._adaptive_type = value
1924
-
1925
- @property
1926
- def adaptive_low_freq(self):
1927
- """HFSS broadband low frequency adaptive meshing.
1928
-
1929
- Returns
1930
- -------
1931
- str
1932
- """
1933
- return self._adaptive_low_freq
1934
-
1935
- @adaptive_low_freq.setter
1936
- def adaptive_low_freq(self, value):
1937
- if isinstance(value, str):
1938
- self._adaptive_low_freq = value
1939
-
1940
- @property
1941
- def adaptive_high_freq(self):
1942
- """HFSS broadband high frequency adaptive meshing.
1943
-
1944
- Returns
1945
- -------
1946
- str
1947
- """
1948
- return self._adaptive_high_freq
1949
-
1950
- @adaptive_high_freq.setter
1951
- def adaptive_high_freq(self, value):
1952
- if isinstance(value, str):
1953
- self._adaptive_high_freq = value
1954
-
1955
-
1956
- class SimulationConfiguration(object):
1957
- """Provides an ASCII simulation configuration file parser.
1958
-
1959
- This parser supports all types of inputs for setting up and automating any kind
1960
- of SI or PI simulation with HFSS 3D Layout or Siwave. If fields are omitted, default
1961
- values are applied. This class can be instantiated directly from
1962
- Configuration file.
1963
-
1964
- Examples
1965
- --------
1966
- This class is very convenient to build HFSS and SIwave simulation projects from layout.
1967
- It is leveraging EDB commands from Pyaedt but with keeping high level parameters making more easy PCB automation
1968
- flow. SYZ and DC simulation can be addressed with this class.
1969
-
1970
- The class is instantiated from an open edb:
1971
-
1972
- >>> from pyedb import Edb
1973
- >>> edb = Edb()
1974
- >>> sim_setup = edb.new_simulation_configuration()
1975
-
1976
- The returned object sim_setup is a SimulationConfiguration object.
1977
- From this class you can assign a lot of parameters related the project configuration but also solver options.
1978
- Here is the list of parameters available:
1979
-
1980
- >>> from pyedb.generic.constants import SolverType
1981
- >>> sim_setup.solver_type = SolverType.Hfss3dLayout
1982
-
1983
- Solver type can be selected, HFSS 3D Layout and Siwave are supported.
1984
-
1985
-
1986
- >>> sim_setup.signal_nets = ["net1", "net2"]
1987
-
1988
- Set the list of net names you want to include for the simulation. These nets will
1989
- have excitations ports created if corresponding pins are found on selected component. We usually refer to signal
1990
- nets but power / reference nets can also be passed into this list if user wants to have ports created on these ones.
1991
-
1992
- >>> sim_setup.power_nets = ["gnd", "vcc"]
1993
-
1994
- Set the list on power and reference nets. These nets won't have excitation ports created
1995
- on them and will be clipped during the project build if the cutout option is enabled.
1996
-
1997
- >>> sim_setup.components = ["comp1", "comp2"]
1998
-
1999
- Set the list of components which will be included in the simulation. These components will have ports created on
2000
- pins belonging to the net list.
2001
-
2002
- >>> sim_setup.do_cutout_subdesign = True
2003
-
2004
- When true activates the layout cutout based on net signal net selection and cutout expansion.
2005
-
2006
- >>> from pyedb.generic.constants import CutoutSubdesignType
2007
- >>> sim_setup.cutout_subdesign_type = CutoutSubdesignType.Conformal
2008
-
2009
- Define the type of cutout used for computing the clippingextent polygon. CutoutSubdesignType.Conformal
2010
- CutoutSubdesignType.BBox are surpported.
2011
-
2012
- >>> sim_setup.cutout_subdesign_expansion = "4mm"
2013
-
2014
- Define the distance used for computing the extent polygon. Integer or string can be passed.
2015
- For example 0.001 is in meter so here 1mm. You can also pass the string "1mm" for the same result.
2016
-
2017
- >>> sim_setup.cutout_subdesign_round_corner = True
2018
-
2019
- Boolean to allow using rounded corner for the cutout extent or not.
2020
-
2021
- >>> sim_setup.use_default_cutout = False
2022
-
2023
- When True use the native edb API command to process the cutout. Using False uses
2024
- the Pyaedt one which improves the cutout speed.
2025
-
2026
- >>> sim_setup.generate_solder_balls = True
2027
-
2028
- Boolean to activate the solder ball generation on components. When HFSS solver is selected in combination with this
2029
- parameter, coaxial ports will be created on solder balls for pins belonging to selected signal nets. If Siwave
2030
- solver is selected this parameter will be ignored.
2031
-
2032
- >>> sim_setup.use_default_coax_port_radial_extension = True
2033
-
2034
- When ``True`` the default coaxial extent is used for the ports (only for HFSS).
2035
- When the design is having dense solder balls close to each other (like typically package design), the default value
2036
- might be too large and cause port overlapping, then solver failure. To prevent this issue set this parameter to
2037
- ``False`` will use a smaller value.
2038
-
2039
- >>> sim_setup.output_aedb = r"C:\temp\my_edb.aedb"
2040
-
2041
- Specify the output edb file after building the project. The parameter must be the complete file path.
2042
- leaving this parameter blank will oervwritte the current open edb.
2043
-
2044
- >>> sim_setup.dielectric_extent = 0.01
2045
-
2046
- Gives the dielectric extent after cutout, keeping default value is advised unless for
2047
- very specific application.
2048
-
2049
- >>> sim_setup.airbox_horizontal_extent = "5mm"
2050
-
2051
- Provide the air box horizonzal extent values. Unitless float value will be
2052
- treated as ratio but string value like "5mm" is also supported.
2053
-
2054
- >>> sim_setup.airbox_negative_vertical_extent = "5mm"
2055
-
2056
- Provide the air box negative vertical extent values. Unitless float value will be
2057
- treated as ratio but string value like "5mm" is also supported.
2058
-
2059
- >>> sim_setup.airbox_positive_vertical_extent = "5mm"
2060
-
2061
- Provide the air box positive vertical extent values. Unitless float value will be
2062
- treated as ratio but string value like "5mm" is also supported.
2063
-
2064
- >>> sim_setup.use_radiation_boundary = True
2065
-
2066
- When ``True`` use radiation airbox boundary condition and perfect metal box when
2067
- set to ``False``. Default value is ``True``, using enclosed metal box will greatly change simulation results.
2068
- Setting this parameter as ``False`` must be used cautiously.
2069
-
2070
- >>> sim_setup.do_cutout_subdesign = True
2071
-
2072
- ``True`` activates the cutout with associated parameters. Setting ``False`` will
2073
- keep the entire layout.
2074
- Setting to ``False`` can impact the simulation run time or even memory failure if HFSS solver is used.
2075
-
2076
- >>> sim_setup.do_pin_group = False
2077
-
2078
- When circuit ports are used, setting to ``True`` will force to create pin groups on
2079
- components having pins belonging to same net. Setting to ``False`` will generate port on each signal pin with
2080
- taking the closest reference pin. The last configuration is more often used when users are creating ports on PDN
2081
- (Power delivery Network) and want to connect all pins individually.
2082
-
2083
- >>> from pyedb.generic.constants import SweepType
2084
- >>> sim_setup.sweep_type = SweepType.Linear
2085
-
2086
- Specify the frequency sweep type, Linear or Log sweep can be defined.
2087
-
2088
- SimulationCOnfiguration also inherit from SimulationConfigurationAc class for High frequency settings.
2089
-
2090
- >>> sim_setup.start_freq = "OHz"
2091
-
2092
- Define the start frequency from the sweep.
2093
-
2094
- >>> sim_setup.stop_freq = "40GHz"
2095
-
2096
- Define the stop frequency from the sweep.
2097
-
2098
- >>> sim_setup.step_freq = "10MHz"
2099
-
2100
- Define the step frequency from the sweep.
2101
-
2102
- >>> sim_setup.decade_count = 100
2103
-
2104
- Used when log sweep is defined and specify the number of points per decade.
2105
-
2106
- >>> sim_setup.enforce_causality = True
2107
-
2108
- Activate the option ``Enforce Causality`` for the solver, recommended for signal integrity application
2109
-
2110
- >>> sim_setup.enforce_passivity = True
2111
-
2112
- Activate the option ``Enforce Passivity`` for the solver, recommended for signal integrity application
2113
-
2114
- >>> sim_setup.do_lambda_refinement = True
2115
-
2116
- Activate the lambda refinement for the initial mesh (only for HFSS), default value is ``True``. Keeping this
2117
- activated is highly recommended.
2118
-
2119
- >>> sim_setup.use_q3d_for_dc = False
2120
-
2121
- Enable when ``True`` the Q3D DC point computation. Only needed when very high accuracy is required for DC point.
2122
- Can eventually cause extra computation time.
2123
-
2124
- >>> sim_setup.sweep_name = "Test_sweep"
2125
-
2126
- Define the frequency sweep name.
2127
-
2128
- >>> sim_setup.mesh_freq = "10GHz"
2129
-
2130
- Define the frequency used for adaptive meshing (available for both HFSS and SIwave).
2131
-
2132
- >>> from pyedb.generic.constants import RadiationBoxType
2133
- >>> sim_setup.radiation_box = RadiationBoxType.ConvexHull
2134
-
2135
- Defined the radiation box type, Conformal, Bounding box and ConvexHull are supported (HFSS only).
2136
-
2137
- >>> sim_setup.max_num_passes= 30
2138
-
2139
- Default value is 30, specify the maximum number of adaptive passes (only HFSS). Reasonable high value is recommended
2140
- to force the solver reaching the convergence criteria.
2141
-
2142
- >>> sim_setup.max_mag_delta_s = 0.02
2143
-
2144
- Define the convergence criteria
2145
-
2146
- >>> sim_setup.min_num_passes = 2
2147
-
2148
- specify the minimum number of consecutive coberged passes. Setting to 2 is a good practice to avoid converging on
2149
- local minima.
2150
-
2151
- >>> from pyedb.generic.constants import BasisOrder
2152
- >>> sim_setup.basis_order = BasisOrder.Single
2153
-
2154
- Select the order basis (HFSS only), Zero, Single, Double and Mixed are supported. For Signal integrity Single or
2155
- Mixed should be used.
2156
-
2157
- >>> sim_setup.minimum_void_surface = 0
2158
-
2159
- Only for Siwave, specify the minimum void surface to be meshed. Void with lower surface value will be ignored by
2160
- meshing.
2161
-
2162
- SimulationConfiguration also inherits from SimulationDc class to handle DC simulation projects.
2163
-
2164
- >>> sim_setup.dc_compute_inductance = True
2165
-
2166
- ``True`` activate the DC loop inductance computation (Siwave only), ``False`` is deactivated.
2167
-
2168
- >>> sim_setup.dc_slide_position = 1
2169
-
2170
- The provided value must be between 0 and 2 and correspond ti the SIwave DC slide position in GUI.
2171
- 0 : coarse
2172
- 1 : medium accuracy
2173
- 2 : high accuracy
2174
-
2175
- >>> sim_setup.dc_plot_jv = True
2176
-
2177
- ``True`` activate the current / voltage plot with Siwave DC solver, ``False`` deactivate.
2178
-
2179
- >>> sim_setup.dc_error_energy = 0.02
2180
-
2181
- Fix the DC error convergence criteria. In this example 2% is defined.
2182
-
2183
- >>> sim_setup.dc_max_num_pass = 6
2184
-
2185
- Provide the maximum number of passes during Siwave DC adaptive meshing.
2186
-
2187
- >>> sim_setup.dc_min_num_pass = 1
2188
-
2189
- Provide the minimum number of passes during Siwave DC adaptive meshing.
2190
-
2191
- >>> sim_setup.dc_mesh_bondwires = True
2192
-
2193
- ``True`` bondwires are meshed, ``False`` bond wires are ignored during meshing.
2194
-
2195
- >>> sim_setup.dc_num_bondwire_sides = 8
2196
-
2197
- Gives the number of facets wirebonds are discretized.
2198
-
2199
- >>> sim_setup.dc_refine_vias = True
2200
-
2201
- ``True`` meshing refinement on nondwires activated during meshing process. Deactivated when set to ``False``.
2202
-
2203
- >>> sim_setup.dc_report_show_Active_devices = True
2204
-
2205
- Activate when ``True`` the components showing in the DC report.
2206
-
2207
- >>> sim_setup.dc_export_thermal_data = True
2208
-
2209
- ``True`` thermal data are exported for Icepak simulation.
2210
-
2211
- >>> sim_setup.dc_full_report_path = r"C:\temp\my_report.html"
2212
-
2213
- Provides the file path for the DC report.
2214
-
2215
- >>> sim_setup.dc_icepak_temp_file = r"C:\temp\my_file"
2216
-
2217
- Provides icepak temporary files location.
2218
-
2219
- >>> sim_setup.dc_import_thermal_data = False
2220
-
2221
- Import DC thermal data when `True``
2222
-
2223
- >>> sim_setup.dc_per_pin_res_path = r"C:\temp\dc_pin_res_file"
2224
- Provides the resistance per pin file path.
2225
-
2226
- >>> sim_setup.dc_per_pin_use_pin_format = True
2227
-
2228
- When ``True`` activate the pin format.
2229
-
2230
- >>> sim_setup.dc_use_loop_res_for_per_pin = True
2231
-
2232
- Activate the loop resistance usage per pin when ``True``
2233
-
2234
- >>> sim_setup.dc_via_report_path = 'C:\\temp\\via_report_file'
2235
-
2236
- Define the via report path file.
2237
-
2238
- >>> sim_setup.add_current_source(name="test_isrc",
2239
- >>> current_value=1.2,
2240
- >>> phase_value=0.0,
2241
- >>> impedance=5e7,
2242
- >>> positive_node_component="comp1",
2243
- >>> positive_node_net="net1",
2244
- >>> negative_node_component="comp2",
2245
- >>> negative_node_net="net2"
2246
- >>> )
2247
-
2248
- Define a current source.
2249
-
2250
- >>> sim_setup.add_dc_ground_source_term(source_name="test_isrc", node_to_ground=1)
2251
-
2252
- Define the pin from a source which has to be set to reference for DC simulation.
2253
-
2254
- >>> sim_setup.add_voltage_source(name="test_vsrc",
2255
- >>> current_value=1.33,
2256
- >>> phase_value=0.0,
2257
- >>> impedance=1e-6,
2258
- >>> positive_node_component="comp1",
2259
- >>> positive_node_net="net1",
2260
- >>> negative_node_component="comp2",
2261
- >>> negative_node_net="net2"
2262
- >>> )
2263
-
2264
- Define a voltage source.
2265
-
2266
- >>> sim_setup.add_dc_ground_source_term(source_name="test_vsrc", node_to_ground=1)
2267
-
2268
- Define the pin from a source which has to be set to reference for DC simulation.
2269
-
2270
- >>> edb.build_simulation_project(sim_setup)
2271
-
2272
- Will build and save your project.
2273
- """
2274
-
2275
- def __getattr__(self, item):
2276
- if item in dir(self):
2277
- return self.__getattribute__(item)
2278
- elif item in dir(self.dc_settings):
2279
- return self.dc_settings.__getattribute__(item)
2280
- elif item in dir(self.ac_settings):
2281
- return self.ac_settings.__getattribute__(item)
2282
- elif item in dir(self.batch_solve_settings):
2283
- return self.batch_solve_settings.__getattribute__(item)
2284
- else:
2285
- raise AttributeError("Attribute {} not present.".format(item))
2286
-
2287
- def __setattr__(self, key, value):
2288
- if "_dc_settings" in dir(self) and key in dir(self._dc_settings):
2289
- return self.dc_settings.__setattr__(key, value)
2290
- elif "_ac_settings" in dir(self) and key in dir(self._ac_settings):
2291
- return self.ac_settings.__setattr__(key, value)
2292
- elif "_batch_solve_settings" in dir(self) and key in dir(self._batch_solve_settings):
2293
- return self.batch_solve_settings.__setattr__(key, value)
2294
- else:
2295
- return super(SimulationConfiguration, self).__setattr__(key, value)
2296
-
2297
- def __init__(self, filename=None, edb=None):
2298
- self._filename = filename
2299
- self._open_edb_after_build = True
2300
- self._dc_settings = SimulationConfigurationDc()
2301
- self._ac_settings = SimulationConfigurationAc()
2302
- self._batch_solve_settings = SimulationConfigurationBatch()
2303
- self._setup_name = "Pyaedt_setup"
2304
- self._solver_type = SolverType.Hfss3dLayout
2305
- if self._filename and os.path.splitext(self._filename)[1] == ".json":
2306
- self.import_json(filename)
2307
- self._read_cfg()
2308
- self._pedb = edb
2309
- self.SOLVER_TYPE = SolverType
2310
-
2311
- @property
2312
- def open_edb_after_build(self):
2313
- """Either if open the Edb after the build or not.
2314
-
2315
- Returns
2316
- -------
2317
- bool
2318
- """
2319
- return self._open_edb_after_build
2320
-
2321
- @open_edb_after_build.setter
2322
- def open_edb_after_build(self, value):
2323
- if isinstance(value, bool):
2324
- self._open_edb_after_build = value
2325
-
2326
- @property
2327
- def dc_settings(self):
2328
- # type: () -> SimulationConfigurationDc
2329
- """DC Settings class.
2330
-
2331
- Returns
2332
- -------
2333
- :class:`pyedb.dotnet.database.edb_data.simulation_configuration.SimulationConfigurationDc`
2334
- """
2335
- return self._dc_settings
2336
-
2337
- @property
2338
- def ac_settings(self):
2339
- # type: () -> SimulationConfigurationAc
2340
- """AC Settings class.
2341
-
2342
- Returns
2343
- -------
2344
- :class:`pyedb.dotnet.database.edb_data.simulation_configuration.SimulationConfigurationAc`
2345
- """
2346
- return self._ac_settings
2347
-
2348
- @property
2349
- def batch_solve_settings(self):
2350
- # type: () -> SimulationConfigurationBatch
2351
- """Cutout and Batch Settings class.
2352
-
2353
- Returns
2354
- -------
2355
- :class:`pyedb.dotnet.database.edb_data.simulation_configuration.SimulationConfigurationBatch`
2356
- """
2357
- return self._batch_solve_settings
2358
-
2359
- def build_simulation_project(self):
2360
- """Build active simulation project. This method requires to be run inside Edb Class.
2361
-
2362
- Returns
2363
- -------
2364
- bool"""
2365
- return self._pedb.build_simulation_project(self)
2366
-
2367
- @property
2368
- def solver_type(self): # pragma: no cover
2369
- """Retrieve the SolverType class to select the solver to be called during the project build.
2370
-
2371
- Returns
2372
- -------
2373
- :class:`dotnet.generic.constants.SolverType`
2374
- selections are supported, Hfss3dLayout and Siwave.
2375
- """
2376
- return self._solver_type
2377
-
2378
- @solver_type.setter
2379
- def solver_type(self, value): # pragma: no cover
2380
- if isinstance(value, int):
2381
- self._solver_type = value
2382
-
2383
- @property
2384
- def filename(self): # pragma: no cover
2385
- """Retrieve the file name loaded for mapping properties value.
2386
-
2387
- Returns
2388
- -------
2389
- str
2390
- the absolute path for the filename.
2391
- """
2392
- return self._filename
2393
-
2394
- @filename.setter
2395
- def filename(self, value):
2396
- if isinstance(value, str): # pragma: no cover
2397
- self._filename = value
2398
-
2399
- @property
2400
- def setup_name(self):
2401
- """Retrieve setup name for the simulation.
2402
-
2403
- Returns
2404
- -------
2405
- str
2406
- Setup name.
2407
- """
2408
- return self._setup_name
2409
-
2410
- @setup_name.setter
2411
- def setup_name(self, value):
2412
- if isinstance(value, str): # pragma: no cover
2413
- self._setup_name = value
2414
-
2415
- def _get_bool_value(self, value): # pragma: no cover
2416
- val = value.lower()
2417
- if val in ("y", "yes", "t", "true", "on", "1"):
2418
- return True
2419
- elif val in ("n", "no", "f", "false", "off", "0"):
2420
- return False
2421
- else:
2422
- raise ValueError("Invalid truth value %r" % (val,))
2423
-
2424
- def _get_list_value(self, value): # pragma: no cover
2425
- value = value[1:-1]
2426
- if len(value) == 0:
2427
- return []
2428
- else:
2429
- value = value.split(",")
2430
- if isinstance(value, list):
2431
- prop_values = [i.strip() for i in value]
2432
- else:
2433
- prop_values = [value.strip()]
2434
- return prop_values
2435
-
2436
- def add_dc_ground_source_term(self, source_name=None, node_to_ground=1):
2437
- """Add a dc ground source terminal for Siwave.
2438
-
2439
- Parameters
2440
- ----------
2441
- source_name : str, optional
2442
- The source name to assign the reference node to.
2443
- Default value is ``None``.
2444
-
2445
- node_to_ground : int, optional
2446
- Value must be ``0``: unspecified, ``1``: negative node, ``2``: positive node.
2447
- Default value is ``1``.
2448
-
2449
- """
2450
- if source_name:
2451
- if node_to_ground in [0, 1, 2]:
2452
- self._dc_source_terms_to_ground[source_name] = node_to_ground
2453
-
2454
- def _read_cfg(self): # pragma: no cover
2455
- if not self.filename or not os.path.exists(self.filename):
2456
- # raise Exception("{} does not exist.".format(self.filename))
2457
- return
2458
-
2459
- try:
2460
- with open(self.filename) as cfg_file:
2461
- cfg_lines = cfg_file.read().split("\n")
2462
- for line in cfg_lines:
2463
- if line.strip() != "":
2464
- if line.find("=") > 0:
2465
- i, prop_value = line.strip().split("=")
2466
- value = prop_value.replace("'", "").strip()
2467
- if i.lower().startswith("generatesolderballs"):
2468
- self.generate_solder_balls = self._get_bool_value(value)
2469
- elif i.lower().startswith("signalnets"):
2470
- self.signal_nets = value[1:-1].split(",") if value[0] == "[" else value.split(",")
2471
- self.signal_nets = [item.strip() for item in self.signal_nets]
2472
- elif i.lower().startswith("powernets"):
2473
- self.power_nets = value[1:-1].split(",") if value[0] == "[" else value.split(",")
2474
- self.power_nets = [item.strip() for item in self.power_nets]
2475
- elif i.lower().startswith("components"):
2476
- self.components = value[1:-1].split(",") if value[0] == "[" else value.split(",")
2477
- self.components = [item.strip() for item in self.components]
2478
- elif i.lower().startswith("coaxsolderballsdiams"):
2479
- self.coax_solder_ball_diameter = (
2480
- value[1:-1].split(",") if value[0] == "[" else value.split(",")
2481
- )
2482
- self.coax_solder_ball_diameter = [
2483
- item.strip() for item in self.coax_solder_ball_diameter
2484
- ]
2485
- elif i.lower().startswith("usedefaultcoaxportradialextentfactor"):
2486
- self.signal_nets = self._get_bool_value(value)
2487
- elif i.lower().startswith("trimrefsize"):
2488
- self.trim_reference_size = self._get_bool_value(value)
2489
- elif i.lower().startswith("cutoutsubdesigntype"):
2490
- if value.lower().startswith("conformal"):
2491
- self.cutout_subdesign_type = CutoutSubdesignType.Conformal
2492
- elif value.lower().startswith("boundingbox"):
2493
- self.cutout_subdesign_type = CutoutSubdesignType.BoundingBox
2494
- else:
2495
- print("Unprocessed value for CutoutSubdesignType '{0}'".format(value))
2496
- elif i.lower().startswith("cutoutsubdesignexpansion"):
2497
- self.cutout_subdesign_expansion = value
2498
- elif i.lower().startswith("cutoutsubdesignroundcorners"):
2499
- self.cutout_subdesign_round_corner = self._get_bool_value(value)
2500
- elif i.lower().startswith("sweepinterpolating"):
2501
- self.sweep_interpolating = self._get_bool_value(value)
2502
- elif i.lower().startswith("useq3dfordc"):
2503
- self.use_q3d_for_dc = self._get_bool_value(value)
2504
- elif i.lower().startswith("relativeerrors"):
2505
- self.relative_error = float(value)
2506
- elif i.lower().startswith("useerrorz0"):
2507
- self.use_error_z0 = self._get_bool_value(value)
2508
- elif i.lower().startswith("percenterrorz0"):
2509
- self.percentage_error_z0 = float(value)
2510
- elif i.lower().startswith("enforcecausality"):
2511
- self.enforce_causality = self._get_bool_value(value)
2512
- elif i.lower().startswith("enforcepassivity"):
2513
- self.enforce_passivity = self._get_bool_value(value)
2514
- elif i.lower().startswith("passivitytolerance"):
2515
- self.passivity_tolerance = float(value)
2516
- elif i.lower().startswith("sweepname"):
2517
- self.sweep_name = value
2518
- elif i.lower().startswith("radiationbox"):
2519
- if value.lower().startswith("conformal"):
2520
- self.radiation_box = RadiationBoxType.Conformal
2521
- elif value.lower().startswith("boundingbox"):
2522
- self.radiation_box = RadiationBoxType.BoundingBox
2523
- elif value.lower().startswith("convexhull"):
2524
- self.radiation_box = RadiationBoxType.ConvexHull
2525
- else:
2526
- print("Unprocessed value for RadiationBox '{0}'".format(value))
2527
- elif i.lower().startswith("startfreq"):
2528
- self.start_freq = value
2529
- elif i.lower().startswith("stopfreq"):
2530
- self.stop_freq = value
2531
- elif i.lower().startswith("sweeptype"):
2532
- if value.lower().startswith("linear"):
2533
- self.sweep_type = SweepType.Linear
2534
- elif value.lower().startswith("logcount"):
2535
- self.sweep_type = SweepType.LogCount
2536
- else:
2537
- print("Unprocessed value for SweepType '{0}'".format(value))
2538
- elif i.lower().startswith("stepfreq"):
2539
- self.step_freq = value
2540
- elif i.lower().startswith("decadecount"):
2541
- self.decade_count = int(value)
2542
- elif i.lower().startswith("mesh_freq"):
2543
- self.mesh_freq = value
2544
- elif i.lower().startswith("maxnumpasses"):
2545
- self.max_num_passes = int(value)
2546
- elif i.lower().startswith("maxmagdeltas"):
2547
- self.max_mag_delta_s = float(value)
2548
- elif i.lower().startswith("minnumpasses"):
2549
- self.min_num_passes = int(value)
2550
- elif i.lower().startswith("basisorder"):
2551
- if value.lower().startswith("mixed"):
2552
- self.basis_order = BasisOrder.Mixed
2553
- elif value.lower().startswith("zero"):
2554
- self.basis_order = BasisOrder.Zero
2555
- elif value.lower().startswith("first"): # single
2556
- self.basis_order = BasisOrder.Single
2557
- elif value.lower().startswith("second"): # double
2558
- self.basis_order = BasisOrder.Double
2559
- else:
2560
- print("Unprocessed value for BasisOrder '{0}'".format(value))
2561
- elif i.lower().startswith("dolambdarefinement"):
2562
- self.do_lambda_refinement = self._get_bool_value(value)
2563
- elif i.lower().startswith("arcangle"):
2564
- self.arc_angle = value
2565
- elif i.lower().startswith("startazimuth"):
2566
- self.start_azimuth = float(value)
2567
- elif i.lower().startswith("maxarcpoints"):
2568
- self.max_arc_points = int(value)
2569
- elif i.lower().startswith("usearctochorderror"):
2570
- self.use_arc_to_chord_error = self._get_bool_value(value)
2571
- elif i.lower().startswith("arctochorderror"):
2572
- self.arc_to_chord_error = value
2573
- elif i.lower().startswith("defeatureabsLength"):
2574
- self.defeature_abs_length = value
2575
- elif i.lower().startswith("defeaturelayout"):
2576
- self.defeature_layout = self._get_bool_value(value)
2577
- elif i.lower().startswith("minimumvoidsurface"):
2578
- self.minimum_void_surface = float(value)
2579
- elif i.lower().startswith("maxsurfdev"):
2580
- self.max_suf_dev = float(value)
2581
- elif i.lower().startswith("processpadstackdefinitions"):
2582
- self.process_padstack_definitions = self._get_bool_value(value)
2583
- elif i.lower().startswith("returncurrentdistribution"):
2584
- self.return_current_distribution = self._get_bool_value(value)
2585
- elif i.lower().startswith("ignorenonfunctionalpads"):
2586
- self.ignore_non_functional_pads = self._get_bool_value(value)
2587
- elif i.lower().startswith("includeinterplanecoupling"):
2588
- self.include_inter_plane_coupling = self._get_bool_value(value)
2589
- elif i.lower().startswith("xtalkthreshold"):
2590
- self.xtalk_threshold = float(value)
2591
- elif i.lower().startswith("minvoidarea"):
2592
- self.min_void_area = value
2593
- elif i.lower().startswith("minpadareatomesh"):
2594
- self.min_pad_area_to_mesh = value
2595
- elif i.lower().startswith("snaplengththreshold"):
2596
- self.snap_length_threshold = value
2597
- elif i.lower().startswith("minplaneareatomesh"):
2598
- self.min_plane_area_to_mesh = value
2599
- elif i.lower().startswith("dcminplaneareatomesh"):
2600
- self.dc_min_plane_area_to_mesh = value
2601
- elif i.lower().startswith("maxinitmeshedgelength"):
2602
- self.max_init_mesh_edge_length = value
2603
- elif i.lower().startswith("signallayersproperties"):
2604
- self._parse_signal_layer_properties = value[1:-1] if value[0] == "[" else value
2605
- self._parse_signal_layer_properties = [
2606
- item.strip() for item in self._parse_signal_layer_properties
2607
- ]
2608
- elif i.lower().startswith("coplanar_instances"):
2609
- self.coplanar_instances = value[1:-1] if value[0] == "[" else value
2610
- self.coplanar_instances = [item.strip() for item in self.coplanar_instances]
2611
- elif i.lower().startswith("signallayersetching"):
2612
- self.signal_layer_etching_instances = value[1:-1] if value[0] == "[" else value
2613
- self.signal_layer_etching_instances = [
2614
- item.strip() for item in self.signal_layer_etching_instances
2615
- ]
2616
- elif i.lower().startswith("etchingfactor"):
2617
- self.etching_factor_instances = value[1:-1] if value[0] == "[" else value
2618
- self.etching_factor_instances = [item.strip() for item in self.etching_factor_instances]
2619
- elif i.lower().startswith("docutoutsubdesign"):
2620
- self.do_cutout_subdesign = self._get_bool_value(value)
2621
- elif i.lower().startswith("solvertype"):
2622
- if value.lower() == "hfss":
2623
- self.solver_type = 0
2624
- if value.lower() == "hfss3dlayout":
2625
- self.solver_type = 6
2626
- elif value.lower().startswith("siwavesyz"):
2627
- self.solver_type = 7
2628
- elif value.lower().startswith("siwavedc"):
2629
- self.solver_type = 8
2630
- elif value.lower().startswith("q3d"):
2631
- self.solver_type = 2
2632
- elif value.lower().startswith("nexxim"):
2633
- self.solver_type = 4
2634
- elif value.lower().startswith("maxwell"):
2635
- self.solver_type = 3
2636
- elif value.lower().startswith("twinbuilder"):
2637
- self.solver_type = 5
2638
- else:
2639
- self.solver_type = SolverType.Hfss3dLayout
2640
- else:
2641
- print("Unprocessed line in cfg file: {0}".format(line))
2642
- else:
2643
- continue
2644
- except EnvironmentError as e:
2645
- print("Error reading cfg file: {}".format(e.message))
2646
- raise
2647
-
2648
- def _dict_to_json(self, dict_out, dict_in=None):
2649
- exclude = ["_pedb", "SOLVER_TYPE"]
2650
- for k, v in dict_in.items():
2651
- if k in exclude:
2652
- continue
2653
- if k[0] == "_":
2654
- if k[1:] in ["dc_settings", "ac_settings", "batch_solve_settings"]:
2655
- dict_out[k[1:]] = {}
2656
- dict_out[k[1:]] = self._dict_to_json(dict_out[k[1:]], self.__getattr__(k).__dict__)
2657
- elif k == "_sources":
2658
- sources_out = [src._json_format() for src in v]
2659
- dict_out[k[1:]] = sources_out
2660
- elif k == "_dc_source_terms_to_ground":
2661
- dc_term_gnd = {}
2662
- for k2 in list(v.Keys): # pragma: no cover
2663
- dc_term_gnd[k2] = v[k2]
2664
- dict_out[k[1:]] = dc_term_gnd
2665
- else:
2666
- dict_out[k[1:]] = v
2667
- else:
2668
- dict_out[k] = v
2669
- return dict_out
2670
-
2671
- def _json_to_dict(self, json_dict):
2672
- for k, v in json_dict.items():
2673
- if k == "sources":
2674
- for src in json_dict[k]: # pragma: no cover
2675
- source = Source()
2676
- source._read_json(src)
2677
- self.batch_solve_settings.sources.append(source)
2678
- elif k == "dc_source_terms_to_ground":
2679
- dc_term_gnd = Dictionary[str, int]()
2680
- for k1, v1 in json_dict[k]: # pragma: no cover
2681
- dc_term_gnd[k1] = v1
2682
- self.dc_source_terms_to_ground = dc_term_gnd
2683
- elif k in ["dc_settings", "ac_settings", "batch_solve_settings"]:
2684
- self._json_to_dict(v)
2685
- else:
2686
- self.__setattr__(k, v)
2687
-
2688
- def export_json(self, output_file):
2689
- """Export Json file from SimulationConfiguration object.
2690
-
2691
- Parameters
2692
- ----------
2693
- output_file : str
2694
- Json file name.
2695
-
2696
- Returns
2697
- -------
2698
- bool
2699
- True when succeeded False when file name not provided.
2700
-
2701
- Examples
2702
- --------
2703
-
2704
- >>> from pyedb.grpc.database.utility.simulation_configuration import SimulationConfiguration
2705
- >>> config = SimulationConfiguration()
2706
- >>> config.export_json(r"C:\Temp\test_json\test.json")
2707
- """
2708
- dict_out = {}
2709
- dict_out = self._dict_to_json(dict_out, self.__dict__)
2710
- if output_file:
2711
- with open(output_file, "w") as write_file:
2712
- json.dump(dict_out, write_file, indent=4)
2713
- return True
2714
- else:
2715
- return False
2716
-
2717
- def import_json(self, input_file):
2718
- """Import Json file into SimulationConfiguration object instance.
2719
-
2720
- Parameters
2721
- ----------
2722
- input_file : str
2723
- Json file name.
2724
-
2725
- Returns
2726
- -------
2727
- bool
2728
- True when succeeded False when file name not provided.
2729
-
2730
- Examples
2731
- --------
2732
- >>> from pyedb.grpc.database.utility.simulation_configuration import SimulationConfiguration
2733
- >>> test = SimulationConfiguration()
2734
- >>> test.import_json(r"C:\Temp\test_json\test.json")
2735
- """
2736
- if input_file:
2737
- f = open(input_file)
2738
- json_dict = json.load(f) # pragma: no cover
2739
- self._json_to_dict(json_dict)
2740
- self.filename = input_file
2741
- return True
2742
- else:
2743
- return False
2744
-
2745
- def add_voltage_source(
2746
- self,
2747
- name="",
2748
- voltage_value=1,
2749
- phase_value=0,
2750
- impedance=1e-6,
2751
- positive_node_component="",
2752
- positive_node_net="",
2753
- negative_node_component="",
2754
- negative_node_net="",
2755
- ):
2756
- """Add a voltage source for the current SimulationConfiguration instance.
2757
-
2758
- Parameters
2759
- ----------
2760
- name : str
2761
- Source name.
2762
-
2763
- voltage_value : float
2764
- Amplitude value of the source. Either amperes for current source or volts for
2765
- voltage source.
2766
-
2767
- phase_value : float
2768
- Phase value of the source.
2769
-
2770
- impedance : float
2771
- Impedance value of the source.
2772
-
2773
- positive_node_component : str
2774
- Name of the component used for the positive node.
2775
-
2776
- negative_node_component : str
2777
- Name of the component used for the negative node.
2778
-
2779
- positive_node_net : str
2780
- Net used for the positive node.
2781
-
2782
- negative_node_net : str
2783
- Net used for the negative node.
2784
-
2785
- Returns
2786
- -------
2787
- bool
2788
- ``True`` when successful, ``False`` when failed.
2789
-
2790
- Examples
2791
- --------
2792
- >>> edb = Edb(target_file)
2793
- >>> sim_setup = SimulationConfiguration()
2794
- >>> sim_setup.add_voltage_source(voltage_value=1.0, phase_value=0, positive_node_component="V1",
2795
- >>> positive_node_net="HSG", negative_node_component="V1", negative_node_net="SW")
2796
-
2797
- """
2798
- if name == "": # pragma: no cover
2799
- name = generate_unique_name("v_source")
2800
- source = Source()
2801
- source.source_type = SourceType.Vsource
2802
- source.name = name
2803
- source.amplitude = voltage_value
2804
- source.phase = phase_value
2805
- source.positive_node.component = positive_node_component
2806
- source.positive_node.net = positive_node_net
2807
- source.negative_node.component = negative_node_component
2808
- source.negative_node.net = negative_node_net
2809
- source.impedance_value = impedance
2810
- try: # pragma: no cover
2811
- self.sources.append(source)
2812
- return True
2813
- except: # pragma: no cover
2814
- return False
2815
-
2816
- def add_current_source(
2817
- self,
2818
- name="",
2819
- current_value=0.1,
2820
- phase_value=0,
2821
- impedance=5e7,
2822
- positive_node_component="",
2823
- positive_node_net="",
2824
- negative_node_component="",
2825
- negative_node_net="",
2826
- ):
2827
- """Add a current source for the current SimulationConfiguration instance.
2828
-
2829
- Parameters
2830
- ----------
2831
- name : str
2832
- Source name.
2833
-
2834
- current_value : float
2835
- Amplitude value of the source. Either amperes for current source or volts for
2836
- voltage source.
2837
-
2838
- phase_value : float
2839
- Phase value of the source.
2840
-
2841
- impedance : float
2842
- Impedance value of the source.
2843
-
2844
- positive_node_component : str
2845
- Name of the component used for the positive node.
2846
-
2847
- negative_node_component : str
2848
- Name of the component used for the negative node.
2849
-
2850
- positive_node_net : str
2851
- Net used for the positive node.
2852
-
2853
- negative_node_net : str
2854
- Net used for the negative node.
2855
-
2856
- Returns
2857
- -------
2858
- bool
2859
- ``True`` when successful, ``False`` when failed.
2860
-
2861
- Examples
2862
- --------
2863
- >>> edb = Edb(target_file)
2864
- >>> sim_setup = SimulationConfiguration()
2865
- >>> sim_setup.add_voltage_source(voltage_value=1.0, phase_value=0, positive_node_component="V1",
2866
- >>> positive_node_net="HSG", negative_node_component="V1", negative_node_net="SW")
2867
- """
2868
-
2869
- if name == "": # pragma: no cover
2870
- name = generate_unique_name("I_source")
2871
- source = Source()
2872
- source.source_type = SourceType.Isource
2873
- source.name = name
2874
- source.amplitude = current_value
2875
- source.phase = phase_value
2876
- source.positive_node.component = positive_node_component
2877
- source.positive_node.net = positive_node_net
2878
- source.negative_node.component = negative_node_component
2879
- source.negative_node.net = negative_node_net
2880
- source.impedance_value = impedance
2881
- try: # pragma: no cover
2882
- self.sources.append(source)
2883
- return True
2884
- except: # pragma: no cover
2885
- return False
2886
-
2887
- def add_rlc(
2888
- self,
2889
- name="",
2890
- r_value=1.0,
2891
- c_value=0.0,
2892
- l_value=0.0,
2893
- positive_node_component="",
2894
- positive_node_net="",
2895
- negative_node_component="",
2896
- negative_node_net="",
2897
- create_physical_rlc=True,
2898
- ):
2899
- """Add a voltage source for the current SimulationConfiguration instance.
2900
-
2901
- Parameters
2902
- ----------
2903
- name : str
2904
- Source name.
2905
-
2906
- r_value : float
2907
- Resistor value in Ohms.
2908
-
2909
- l_value : float
2910
- Inductance value in Henry.
2911
-
2912
- c_value : float
2913
- Capacitance value in Farrad.
2914
-
2915
- positive_node_component : str
2916
- Name of the component used for the positive node.
2917
-
2918
- negative_node_component : str
2919
- Name of the component used for the negative node.
2920
-
2921
- positive_node_net : str
2922
- Net used for the positive node.
2923
-
2924
- negative_node_net : str
2925
- Net used for the negative node.
2926
-
2927
- create_physical_rlc : bool
2928
- When True create a physical Rlc component. Recommended setting to True to be compatible with Siwave.
2929
-
2930
- Returns
2931
- -------
2932
- bool
2933
- ``True`` when successful, ``False`` when failed.
2934
-
2935
- Examples
2936
- --------
2937
- >>> edb = Edb(target_file)
2938
- >>> sim_setup = SimulationConfiguration()
2939
- >>> sim_setup.add_voltage_source(voltage_value=1.0, phase_value=0, positive_node_component="V1",
2940
- >>> positive_node_net="HSG", negative_node_component="V1", negative_node_net="SW")
2941
- """
2942
-
2943
- if name == "": # pragma: no cover
2944
- name = generate_unique_name("Rlc")
2945
- source = Source()
2946
- source.source_type = SourceType.Rlc
2947
- source.name = name
2948
- source.r_value = r_value
2949
- source.l_value = l_value
2950
- source.c_value = c_value
2951
- source.create_physical_resistor = create_physical_rlc
2952
- source.positive_node.component = positive_node_component
2953
- source.positive_node.net = positive_node_net
2954
- source.negative_node.component = negative_node_component
2955
- source.negative_node.net = negative_node_net
2956
- try: # pragma: no cover
2957
- self.sources.append(source)
2958
- return True
2959
- except: # pragma: no cover
2960
- return False
2961
-
2962
-
2963
- class ProcessSimulationConfiguration(object):
2964
- @staticmethod
2965
- def configure_hfss_extents(self, simulation_setup=None):
2966
- """Configure the HFSS extent box.
2967
-
2968
- Parameters
2969
- ----------
2970
- simulation_setup :
2971
- Edb_DATA.SimulationConfiguration object
2972
-
2973
- Returns
2974
- -------
2975
- bool
2976
- True when succeeded, False when failed.
2977
- """
2978
-
2979
- if not isinstance(simulation_setup, SimulationConfiguration):
2980
- self._logger.error(
2981
- "Configure HFSS extent requires edb_data.simulation_configuration.SimulationConfiguration object"
2982
- )
2983
- return False
2984
- hfss_extent = self._edb.utility.utility.HFSSExtentInfo()
2985
- if simulation_setup.radiation_box == RadiationBoxType.BoundingBox:
2986
- hfss_extent.ExtentType = self._edb.utility.utility.HFSSExtentInfoType.BoundingBox
2987
- elif simulation_setup.radiation_box == RadiationBoxType.Conformal:
2988
- hfss_extent.ExtentType = self._edb.utility.utility.HFSSExtentInfoType.Conforming
2989
- else:
2990
- hfss_extent.ExtentType = self._edb.utility.utility.HFSSExtentInfoType.ConvexHull
2991
- hfss_extent.dielectric_extent_size = (
2992
- simulation_setup.dielectric_extent,
2993
- simulation_setup.use_dielectric_extent_multiple,
2994
- )
2995
- hfss_extent.air_box_horizontal_extent = (
2996
- simulation_setup.airbox_horizontal_extent,
2997
- simulation_setup.use_airbox_horizontal_extent_multiple,
2998
- )
2999
- hfss_extent.air_box_negative_vertical_extent = (
3000
- simulation_setup.airbox_negative_vertical_extent,
3001
- simulation_setup.use_airbox_negative_vertical_extent_multiple,
3002
- )
3003
- hfss_extent.AirBoxPositiveVerticalExtent = (
3004
- simulation_setup.airbox_positive_vertical_extent,
3005
- simulation_setup.use_airbox_positive_vertical_extent_multiple,
3006
- )
3007
- hfss_extent.HonorUserDielectric = simulation_setup.honor_user_dielectric
3008
- hfss_extent.TruncateAirBoxAtGround = simulation_setup.truncate_airbox_at_ground
3009
- hfss_extent.UseOpenRegion = simulation_setup.use_radiation_boundary
3010
- self._layout.cell.SetHFSSExtentInfo(hfss_extent) # returns void
3011
- return True
3012
-
3013
- @staticmethod
3014
- def configure_hfss_analysis_setup(self, simulation_setup=None):
3015
- """
3016
- Configure HFSS analysis setup.
3017
-
3018
- Parameters
3019
- ----------
3020
- simulation_setup :
3021
- Edb_DATA.SimulationConfiguration object
3022
-
3023
- Returns
3024
- -------
3025
- bool
3026
- True when succeeded, False when failed.
3027
- """
3028
- if not isinstance(simulation_setup, SimulationConfiguration):
3029
- self._logger.error(
3030
- "Configure HFSS analysis requires and edb_data.simulation_configuration.SimulationConfiguration object \
3031
- as argument"
3032
- )
3033
- return False
3034
- simsetup_info = self._pedb.simsetupdata.SimSetupInfo[self._pedb.simsetupdata.HFSSSimulationSettings]()
3035
- simsetup_info.Name = simulation_setup.setup_name
3036
-
3037
- if simulation_setup.ac_settings.adaptive_type == 0:
3038
- adapt = self._pedb.simsetupdata.AdaptiveFrequencyData()
3039
- adapt.AdaptiveFrequency = simulation_setup.mesh_freq
3040
- adapt.MaxPasses = int(simulation_setup.max_num_passes)
3041
- adapt.MaxDelta = str(simulation_setup.max_mag_delta_s)
3042
- simsetup_info.SimulationSettings.AdaptiveSettings.AdaptiveFrequencyDataList = convert_py_list_to_net_list(
3043
- [adapt]
3044
- )
3045
- elif simulation_setup.ac_settings.adaptive_type == 2:
3046
- low_freq_adapt_data = self._pedb.simsetupdata.AdaptiveFrequencyData()
3047
- low_freq_adapt_data.MaxDelta = str(simulation_setup.max_mag_delta_s)
3048
- low_freq_adapt_data.MaxPasses = int(simulation_setup.max_num_passes)
3049
- low_freq_adapt_data.AdaptiveFrequency = simulation_setup.ac_settings.adaptive_low_freq
3050
- high_freq_adapt_data = self._pedb.simsetupdata.AdaptiveFrequencyData()
3051
- high_freq_adapt_data.MaxDelta = str(simulation_setup.max_mag_delta_s)
3052
- high_freq_adapt_data.MaxPasses = int(simulation_setup.max_num_passes)
3053
- high_freq_adapt_data.AdaptiveFrequency = simulation_setup.ac_settings.adaptive_high_freq
3054
- simsetup_info.SimulationSettings.AdaptiveSettings.AdaptType = (
3055
- self._pedb.simsetupdata.AdaptiveSettings.TAdaptType.kBroadband
3056
- )
3057
- simsetup_info.SimulationSettings.AdaptiveSettings.AdaptiveFrequencyDataList.Clear()
3058
- simsetup_info.SimulationSettings.AdaptiveSettings.AdaptiveFrequencyDataList.Add(low_freq_adapt_data)
3059
- simsetup_info.SimulationSettings.AdaptiveSettings.AdaptiveFrequencyDataList.Add(high_freq_adapt_data)
3060
-
3061
- simsetup_info.SimulationSettings.CurveApproxSettings.ArcAngle = simulation_setup.arc_angle
3062
- simsetup_info.SimulationSettings.CurveApproxSettings.UseArcToChordError = (
3063
- simulation_setup.use_arc_to_chord_error
3064
- )
3065
- simsetup_info.SimulationSettings.CurveApproxSettings.ArcToChordError = simulation_setup.arc_to_chord_error
3066
-
3067
- simsetup_info.SimulationSettings.InitialMeshSettings.LambdaRefine = simulation_setup.do_lambda_refinement
3068
- if simulation_setup.mesh_sizefactor > 0.0:
3069
- simsetup_info.SimulationSettings.InitialMeshSettings.MeshSizefactor = simulation_setup.mesh_sizefactor
3070
- simsetup_info.SimulationSettings.InitialMeshSettings.LambdaRefine = False
3071
- simsetup_info.SimulationSettings.AdaptiveSettings.MaxRefinePerPass = 30
3072
- simsetup_info.SimulationSettings.AdaptiveSettings.MinPasses = simulation_setup.min_num_passes
3073
- simsetup_info.SimulationSettings.AdaptiveSettings.MinConvergedPasses = 1
3074
- simsetup_info.SimulationSettings.HFSSSolverSettings.OrderBasis = simulation_setup.basis_order
3075
- simsetup_info.SimulationSettings.HFSSSolverSettings.UseHFSSIterativeSolver = False
3076
- simsetup_info.SimulationSettings.DefeatureSettings.UseDefeature = False # set True when using defeature ratio
3077
- simsetup_info.SimulationSettings.DefeatureSettings.UseDefeatureAbsLength = simulation_setup.defeature_layout
3078
- simsetup_info.SimulationSettings.DefeatureSettings.DefeatureAbsLength = simulation_setup.defeature_abs_length
3079
-
3080
- try:
3081
- if simulation_setup.add_frequency_sweep:
3082
- self._logger.info("Adding frequency sweep")
3083
- sweep = self._pedb.simsetupdata.SweepData(simulation_setup.sweep_name)
3084
- sweep.IsDiscrete = False
3085
- sweep.UseQ3DForDC = simulation_setup.use_q3d_for_dc
3086
- sweep.RelativeSError = simulation_setup.relative_error
3087
- sweep.InterpUsePortImpedance = False
3088
- sweep.EnforceCausality = simulation_setup.enforce_causality
3089
- # sweep.EnforceCausality = False
3090
- sweep.EnforcePassivity = simulation_setup.enforce_passivity
3091
- sweep.PassivityTolerance = simulation_setup.passivity_tolerance
3092
- sweep.Frequencies.Clear()
3093
-
3094
- if simulation_setup.sweep_type == SweepType.LogCount: # setup_info.SweepType == 'DecadeCount'
3095
- self._setup_decade_count_sweep(
3096
- sweep,
3097
- str(simulation_setup.start_freq),
3098
- str(simulation_setup.stop_freq),
3099
- str(simulation_setup.decade_count),
3100
- ) # Added DecadeCount as a new attribute
3101
-
3102
- else:
3103
- sweep.Frequencies = self._pedb.simsetupdata.SweepData.SetFrequencies(
3104
- simulation_setup.start_freq,
3105
- simulation_setup.stop_freq,
3106
- simulation_setup.step_freq,
3107
- )
3108
-
3109
- simsetup_info.SweepDataList.Add(sweep)
3110
- else:
3111
- self._logger.info("Adding frequency sweep disabled")
3112
-
3113
- except Exception as err:
3114
- self._logger.error("Exception in Sweep configuration: {0}".format(err))
3115
-
3116
- sim_setup = self._edb.utility.utility.HFSSSimulationSetup(simsetup_info)
3117
- for setup in self._layout.cell.SimulationSetups:
3118
- self._layout.cell.DeleteSimulationSetup(setup.GetName())
3119
- self._logger.warning("Setup {} has been deleted".format(setup.GetName()))
3120
- return self._layout.cell.AddSimulationSetup(sim_setup)
3121
-
3122
- def trim_component_reference_size(self, simulation_setup=None, trim_to_terminals=False):
3123
- """Trim the common component reference to the minimally acceptable size.
3124
-
3125
- Parameters
3126
- ----------
3127
- simulation_setup :
3128
- Edb_DATA.SimulationConfiguration object
3129
-
3130
- trim_to_terminals :
3131
- bool.
3132
- True, reduce the reference to a box covering only the active terminals (i.e. those with
3133
- ports).
3134
- False, reduce the reference to the minimal size needed to cover all pins
3135
-
3136
- Returns
3137
- -------
3138
- bool
3139
- True when succeeded, False when failed.
3140
- """
3141
-
3142
- if not isinstance(simulation_setup, SimulationConfiguration):
3143
- self._logger.error(
3144
- "Trim component reference size requires an edb_data.simulation_configuration.SimulationConfiguration \
3145
- object as argument"
3146
- )
3147
- return False
3148
-
3149
- if not simulation_setup.components: # pragma: no cover
3150
- return
3151
-
3152
- layout = self._cell.layout
3153
- l_inst = layout.layout_instance
3154
-
3155
- for inst in simulation_setup.components: # pragma: no cover
3156
- comp = self._pedb.components.instances[inst]
3157
- terms_bbox_pts = self._get_terminals_bbox(comp, l_inst, trim_to_terminals)
3158
- if not terms_bbox_pts:
3159
- continue
3160
-
3161
- terms_bbox = self._edb.geometry.polygon_data.create_from_bbox(terms_bbox_pts)
3162
-
3163
- if trim_to_terminals:
3164
- # Remove any pins that aren't interior to the Terminals bbox
3165
- pin_list = [
3166
- obj
3167
- for obj in list(comp.LayoutObjs)
3168
- if obj.GetObjType() == self._edb.cell.layout_object_type.PadstackInstance
3169
- ]
3170
- for pin in pin_list:
3171
- loi = l_inst.GetLayoutObjInstance(pin, None)
3172
- bb_c = loi.GetCenter()
3173
- if not terms_bbox.PointInPolygon(bb_c):
3174
- comp.RemoveMember(pin)
3175
-
3176
- # Set the port property reference size
3177
- cmp_prop = comp.GetComponentProperty().Clone()
3178
- port_prop = cmp_prop.GetPortProperty().Clone()
3179
- port_prop.SetReferenceSizeAuto(False)
3180
- port_prop.SetReferenceSize(
3181
- terms_bbox_pts.Item2.X.ToDouble() - terms_bbox_pts.Item1.X.ToDouble(),
3182
- terms_bbox_pts.Item2.Y.ToDouble() - terms_bbox_pts.Item1.Y.ToDouble(),
3183
- )
3184
- cmp_prop.SetPortProperty(port_prop)
3185
- comp.SetComponentProperty(cmp_prop)
3186
- return True
3187
-
3188
- def set_coax_port_attributes(self, simulation_setup=None):
3189
- """Set coaxial port attribute with forcing default impedance to 50 Ohms and adjusting the coaxial extent radius.
3190
-
3191
- Parameters
3192
- ----------
3193
- simulation_setup :
3194
- Edb_DATA.SimulationConfiguration object.
3195
-
3196
- Returns
3197
- -------
3198
- bool
3199
- True when succeeded, False when failed.
3200
- """
3201
-
3202
- if not isinstance(simulation_setup, SimulationConfiguration):
3203
- self._logger.error(
3204
- "Set coax port attribute requires an edb_data.simulation_configuration.SimulationConfiguration object \
3205
- as argument."
3206
- )
3207
- return False
3208
-
3209
- net_names = [net.name for net in self._pedb.layout.nets if not net.is_power_ground]
3210
- if simulation_setup.components and isinstance(simulation_setup.components[0], str):
3211
- cmp_names = (
3212
- simulation_setup.components
3213
- if simulation_setup.components
3214
- else [gg.name for gg in self._pedb.layout.groups]
3215
- )
3216
- elif (
3217
- simulation_setup.components
3218
- and isinstance(simulation_setup.components[0], dict)
3219
- and "refdes" in simulation_setup.components[0]
3220
- ):
3221
- cmp_names = [cmp["refdes"] for cmp in simulation_setup.components]
3222
- else:
3223
- cmp_names = []
3224
- ii = 0
3225
- for cc in cmp_names:
3226
- cmp = self._pedb.components.instances[cc]
3227
- if cmp.is_null:
3228
- self._logger.warning("RenamePorts: could not find component {0}".format(cc))
3229
- continue
3230
- terms = [pin for pin in cmp.pins if not pin.get_padstack_instance_terminal().is_null]
3231
- for nn in net_names:
3232
- for tt in [term for term in terms if term.net.name == nn]:
3233
- tt.impedance = GrpcValue("50ohm")
3234
- ii += 1
3235
-
3236
- if not simulation_setup.use_default_coax_port_radial_extension:
3237
- # Set the Radial Extent Factor
3238
- typ = cmp.type
3239
- if typ in [
3240
- GrpcComponentType.OTHER,
3241
- GrpcComponentType.IC,
3242
- GrpcComponentType.IO,
3243
- ]:
3244
- cmp_prop = cmp.component_property
3245
- solder_ball_diam = cmp_prop.solder_ball_property.diameter()
3246
- if solder_ball_diam[0] and solder_ball_diam[1] > 0: # pragma: no cover
3247
- option = (
3248
- "HFSS('HFSS Type'='**Invalid**', "
3249
- "Orientation='**Invalid**', "
3250
- "'Layer Alignment'='Upper', "
3251
- "'Horizontal Extent Factor'='5', "
3252
- "'Vertical Extent Factor'='3', "
3253
- "'Radial Extent Factor'='0.25', "
3254
- "'PEC Launch Width'='0mm')"
3255
- )
3256
- for tt in terms:
3257
- tt.set_product_solver_option(GrpcComponentType.DESIGNER, "HFSS", option)
3258
- return True
3259
-
3260
- def layout_defeaturing(self, simulation_setup=None):
3261
- """Defeature the layout by reducing the number of points for polygons based on surface deviation criteria.
3262
-
3263
- Parameters
3264
- ----------
3265
- simulation_setup : Edb_DATA.SimulationConfiguration object
3266
-
3267
- Returns
3268
- -------
3269
- bool
3270
- ``True`` when successful, ``False`` when failed.
3271
-
3272
- """
3273
- if not isinstance(simulation_setup, SimulationConfiguration):
3274
- self._logger.error(
3275
- "Layout defeaturing requires an edb_data.simulation_configuration.SimulationConfiguration object."
3276
- )
3277
- return False
3278
- self._logger.info("Starting Layout Defeaturing")
3279
- polygon_list = self._pedb.modeler.polygons
3280
- polygon_with_voids = self._pedb.core_layout.get_poly_with_voids(polygon_list)
3281
- self._logger.info("Number of polygons with voids found: {0}".format(str(polygon_with_voids.Count)))
3282
- for _poly in polygon_list:
3283
- voids_from_current_poly = _poly.Voids
3284
- new_poly_data = self._pedb.core_layout.defeature_polygon(setup_info=simulation_setup, poly=_poly)
3285
- _poly.SetPolygonData(new_poly_data)
3286
- if len(voids_from_current_poly) > 0:
3287
- for void in voids_from_current_poly:
3288
- void_data = void.GetPolygonData()
3289
- if void_data.Area() < float(simulation_setup.minimum_void_surface):
3290
- void.Delete()
3291
- self._logger.warning(
3292
- "Defeaturing Polygon {0}: Deleting Void {1} area is lower than the minimum criteria".format(
3293
- str(_poly.GetId()), str(void.GetId())
3294
- )
3295
- )
3296
- else:
3297
- self._logger.info(
3298
- "Defeaturing polygon {0}: void {1}".format(str(_poly.GetId()), str(void.GetId()))
3299
- )
3300
- new_void_data = self._pedb.core_layout.defeature_polygon(
3301
- setup_info=simulation_setup, poly=void_data
3302
- )
3303
- void.SetPolygonData(new_void_data)
3304
-
3305
- return True