pyedb 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyedb might be problematic. Click here for more details.

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