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