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
|
@@ -33,21 +33,158 @@ from pyedb.misc.misc import list_installed_ansysem
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
def convert_technology_file(tech_file, edbversion=None, control_file=None):
|
|
36
|
-
"""Convert a technology file to
|
|
36
|
+
"""Convert a technology file to EDB control file (XML).
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
tech_file : str
|
|
41
|
+
Full path to technology file.
|
|
42
|
+
edbversion : str, optional
|
|
43
|
+
EDB version to use. If ``None``, uses latest available version.
|
|
44
|
+
control_file : str, optional
|
|
45
|
+
Output control file path. If ``None``, uses same path and name as ``tech_file``.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
str or bool
|
|
50
|
+
Full path to created control file if successful, ``False`` otherwise.
|
|
51
|
+
|
|
52
|
+
Notes
|
|
53
|
+
-----
|
|
54
|
+
This function is only supported on Linux systems.
|
|
55
|
+
|
|
56
|
+
Example
|
|
57
|
+
-------
|
|
58
|
+
# Example 1: Converting a technology file to control file
|
|
59
|
+
>>> converted_file = convert_technology_file(
|
|
60
|
+
>>> tech_file="/path/to/tech.t",
|
|
61
|
+
>>> edbversion="2025.2",
|
|
62
|
+
>>> control_file="/path/to/output.xml"
|
|
63
|
+
>>> )
|
|
64
|
+
>>> if converted_file:
|
|
65
|
+
>>> print(f"Converted to: {converted_file}")
|
|
66
|
+
|
|
67
|
+
# Example 2: Creating a material
|
|
68
|
+
>>> from pyedb import ControlFileMaterial
|
|
69
|
+
>>> material = ControlFileMaterial(
|
|
70
|
+
>>> "Copper",
|
|
71
|
+
>>> {"Permittivity": 1.0, "Conductivity": 5.8e7}
|
|
72
|
+
>>> )
|
|
73
|
+
|
|
74
|
+
# Example 3: Creating a dielectric layer
|
|
75
|
+
>>> from pyedb import ControlFileDielectric
|
|
76
|
+
>>> dielectric = ControlFileDielectric(
|
|
77
|
+
>>> "Core",
|
|
78
|
+
>>> {"Thickness": "0.2mm", "Material": "FR4"}
|
|
79
|
+
>>> )
|
|
80
|
+
|
|
81
|
+
# Example 4: Creating a signal layer
|
|
82
|
+
>>> from pyedb import ControlFileLayer
|
|
83
|
+
>>> signal_layer = ControlFileLayer(
|
|
84
|
+
>>> "TopLayer",
|
|
85
|
+
>>> {"Type": "signal", "Material": "Copper", "Thickness": "0.035mm"}
|
|
86
|
+
>>> )
|
|
87
|
+
|
|
88
|
+
# Example 5: Creating a via layer
|
|
89
|
+
>>> from pyedb import ControlFileVia
|
|
90
|
+
>>> via_layer = ControlFileVia(
|
|
91
|
+
>>> "Via1",
|
|
92
|
+
>>> {"StartLayer": "TopLayer", "StopLayer": "BottomLayer"}
|
|
93
|
+
>>> )
|
|
94
|
+
>>> via_layer.create_via_group = True
|
|
95
|
+
>>> via_layer.tolerance = "0.1mm"
|
|
96
|
+
|
|
97
|
+
# Example 6: Managing stackup
|
|
98
|
+
>>> from pyedb import ControlFileStackup
|
|
99
|
+
>>> stackup = ControlFileStackup(units="mm")
|
|
100
|
+
>>> stackup.add_material("FR4", permittivity=4.4, dielectric_loss_tg=0.02)
|
|
101
|
+
>>> stackup.add_layer("L1", elevation=0, material="Copper", thickness=0.035)
|
|
102
|
+
>>> stackup.add_dielectric("Diel1", material="FR4", thickness=0.2)
|
|
103
|
+
>>> stackup.add_via("Via1", start_layer="L1", stop_layer="L2")
|
|
104
|
+
|
|
105
|
+
# Example 7: Configuring import options
|
|
106
|
+
>>> from pyedb import ControlFileImportOptions
|
|
107
|
+
>>> import_ops = ControlFileImportOptions()
|
|
108
|
+
>>> import_ops.auto_close = True
|
|
109
|
+
>>> import_ops.defeature_tolerance = 0.001
|
|
110
|
+
|
|
111
|
+
# Example 8: Setting up simulation extents
|
|
112
|
+
>>> from pyedb import ControlExtent
|
|
113
|
+
>>> extent = ControlExtent(
|
|
114
|
+
>>> type="Conforming",
|
|
115
|
+
>>> diel_hactor=0.3,
|
|
116
|
+
>>> airbox_hfactor=0.5
|
|
117
|
+
>>> )
|
|
118
|
+
|
|
119
|
+
# Example 9: Creating circuit ports
|
|
120
|
+
>>> from pyedb import ControlCircuitPt
|
|
121
|
+
>>> port = ControlCircuitPt("Port1", 0, 0, "TopLayer", 1, 0, "TopLayer", 50)
|
|
122
|
+
|
|
123
|
+
# Example 10: Managing components
|
|
124
|
+
>>> from pyedb import ControlFileComponent
|
|
125
|
+
>>> comp = ControlFileComponent()
|
|
126
|
+
>>> comp.refdes = "U1"
|
|
127
|
+
>>> comp.add_pin("Pin1", 0.5, 0.5, "TopLayer")
|
|
128
|
+
>>> comp.add_port("Port1", 50, "Pin1", refpin="GND")
|
|
129
|
+
|
|
130
|
+
# Example 11: Component management
|
|
131
|
+
>>> from pyedb import ControlFileComponents
|
|
132
|
+
>>> components = ControlFileComponents()
|
|
133
|
+
>>> ic = components.add_component("U1", "BGA", "IC", die_type="Flip chip")
|
|
134
|
+
>>> ic.add_pin("A1", 1.0, 1.0, "TopLayer")
|
|
135
|
+
|
|
136
|
+
# Example 12: Boundary setup
|
|
137
|
+
>>> from pyedb import ControlFileBoundaries
|
|
138
|
+
>>> boundaries = ControlFileBoundaries()
|
|
139
|
+
>>> boundaries.add_port("Port1", 0, 0, "L1", 1, 0, "L1", 50)
|
|
140
|
+
>>> boundaries.add_extent(diel_hactor=0.3)
|
|
141
|
+
|
|
142
|
+
# Example 13: Frequency sweep configuration
|
|
143
|
+
>>> from pyedb import ControlFileSweep
|
|
144
|
+
>>> sweep = ControlFileSweep(
|
|
145
|
+
>>> "Sweep1", "1GHz", "10GHz", "0.1GHz",
|
|
146
|
+
>>> "Interpolating", "LinearStep", True
|
|
147
|
+
>>> )
|
|
148
|
+
|
|
149
|
+
# Example 14: Mesh operation setup
|
|
150
|
+
>>> from pyedb import ControlFileMeshOp
|
|
151
|
+
>>> mesh_op = ControlFileMeshOp(
|
|
152
|
+
>>> "FineMesh", "Region1", "MeshOperationSkinDepth",
|
|
153
|
+
>>> {"Net1": "TopLayer"}
|
|
154
|
+
>>> )
|
|
155
|
+
>>> mesh_op.skin_depth = "1um"
|
|
156
|
+
|
|
157
|
+
# Example 15: Simulation setup configuration
|
|
158
|
+
>>> from pyedb import ControlFileSetup
|
|
159
|
+
>>> setup = ControlFileSetup("SimSetup1")
|
|
160
|
+
>>> setup.frequency = "5GHz"
|
|
161
|
+
>>> setup.add_sweep("Sweep1", "1GHz", "10GHz", "0.5GHz")
|
|
162
|
+
>>> setup.add_mesh_operation("Mesh1", "Chip", "MeshOperationLength", {"PWR": "Top"})
|
|
163
|
+
|
|
164
|
+
# Example 16: Setup management
|
|
165
|
+
>>> from pyedb import ControlFileSetups
|
|
166
|
+
>>> setups = ControlFileSetups()
|
|
167
|
+
>>> sim_setup = setups.add_setup("MySetup", "10GHz")
|
|
168
|
+
>>> sim_setup.add_sweep("Swp1", "1GHz", "20GHz", 100, step_type="LinearCount")
|
|
169
|
+
|
|
170
|
+
# Example 17: Main control file creation
|
|
171
|
+
>>> from pyedb import ControlFile
|
|
172
|
+
|
|
173
|
+
# Create from scratch
|
|
174
|
+
>>> ctrl = ControlFile()
|
|
175
|
+
>>> ctrl.stackup.add_material("Copper", conductivity=5.8e7)
|
|
176
|
+
>>> ctrl.stackup.add_layer("Signal", thickness=0.035, material="Copper")
|
|
177
|
+
>>> ctrl.boundaries.add_port("Input", 0, 0, "Signal", 1, 0, "Signal", 50)
|
|
178
|
+
>>> ctrl.write_xml("/path/to/control.xml")
|
|
179
|
+
|
|
180
|
+
# Parse existing file
|
|
181
|
+
>>> ctrl = ControlFile(xml_input="/path/to/existing.xml")
|
|
182
|
+
|
|
183
|
+
# Convert technology file
|
|
184
|
+
>>> ctrl = ControlFile(tecnhology="/path/to/tech.t")
|
|
185
|
+
|
|
186
|
+
# Apply layer mapping
|
|
187
|
+
>>> ctrl.parse_layer_map("/path/to/layer_map.txt")
|
|
51
188
|
"""
|
|
52
189
|
if is_linux: # pragma: no cover
|
|
53
190
|
if not edbversion:
|
|
@@ -56,7 +193,7 @@ def convert_technology_file(tech_file, edbversion=None, control_file=None):
|
|
|
56
193
|
base_path = env_path(edbversion)
|
|
57
194
|
sys.path.append(base_path)
|
|
58
195
|
else:
|
|
59
|
-
pyedb_logger.error("No
|
|
196
|
+
pyedb_logger.error("No EDB installation found. Check environment variables")
|
|
60
197
|
return False
|
|
61
198
|
os.environ["HELIC_ROOT"] = os.path.join(base_path, "helic")
|
|
62
199
|
if os.getenv("ANSYSLMD_LICENCE_FILE", None) is None:
|
|
@@ -103,13 +240,23 @@ def convert_technology_file(tech_file, edbversion=None, control_file=None):
|
|
|
103
240
|
p = subprocess.Popen(command, env=my_env)
|
|
104
241
|
p.wait()
|
|
105
242
|
if os.path.exists(control_file):
|
|
106
|
-
pyedb_logger.info("
|
|
243
|
+
pyedb_logger.info("XML file created.")
|
|
107
244
|
return control_file
|
|
108
245
|
pyedb_logger.error("Technology files are supported only in Linux. Use control file instead.")
|
|
109
246
|
return False
|
|
110
247
|
|
|
111
248
|
|
|
112
249
|
class ControlProperty:
|
|
250
|
+
"""Represents a property in the control file with name, value, and type.
|
|
251
|
+
|
|
252
|
+
Parameters
|
|
253
|
+
----------
|
|
254
|
+
property_name : str
|
|
255
|
+
Name of the property.
|
|
256
|
+
value : str, float, or list
|
|
257
|
+
Value of the property.
|
|
258
|
+
"""
|
|
259
|
+
|
|
113
260
|
def __init__(self, property_name, value):
|
|
114
261
|
self.name = property_name
|
|
115
262
|
self.value = value
|
|
@@ -125,6 +272,13 @@ class ControlProperty:
|
|
|
125
272
|
pass
|
|
126
273
|
|
|
127
274
|
def _write_xml(self, root):
|
|
275
|
+
"""Write the property to XML element.
|
|
276
|
+
|
|
277
|
+
Parameters
|
|
278
|
+
----------
|
|
279
|
+
root : xml.etree.ElementTree.Element
|
|
280
|
+
Parent XML element to append to.
|
|
281
|
+
"""
|
|
128
282
|
try:
|
|
129
283
|
if self.type == 0:
|
|
130
284
|
content = ET.SubElement(root, self.name)
|
|
@@ -137,6 +291,16 @@ class ControlProperty:
|
|
|
137
291
|
|
|
138
292
|
|
|
139
293
|
class ControlFileMaterial:
|
|
294
|
+
"""Represents a material in the control file.
|
|
295
|
+
|
|
296
|
+
Parameters
|
|
297
|
+
----------
|
|
298
|
+
name : str
|
|
299
|
+
Material name.
|
|
300
|
+
properties : dict
|
|
301
|
+
Material properties dictionary.
|
|
302
|
+
"""
|
|
303
|
+
|
|
140
304
|
def __init__(self, name, properties):
|
|
141
305
|
self.name = name
|
|
142
306
|
self.properties = {}
|
|
@@ -144,6 +308,13 @@ class ControlFileMaterial:
|
|
|
144
308
|
self.properties[name] = ControlProperty(name, property)
|
|
145
309
|
|
|
146
310
|
def _write_xml(self, root):
|
|
311
|
+
"""Write material to XML element.
|
|
312
|
+
|
|
313
|
+
Parameters
|
|
314
|
+
----------
|
|
315
|
+
root : xml.etree.ElementTree.Element
|
|
316
|
+
Parent XML element to append to.
|
|
317
|
+
"""
|
|
147
318
|
content = ET.SubElement(root, "Material")
|
|
148
319
|
content.set("Name", self.name)
|
|
149
320
|
for property_name, property in self.properties.items():
|
|
@@ -151,6 +322,16 @@ class ControlFileMaterial:
|
|
|
151
322
|
|
|
152
323
|
|
|
153
324
|
class ControlFileDielectric:
|
|
325
|
+
"""Represents a dielectric layer in the control file.
|
|
326
|
+
|
|
327
|
+
Parameters
|
|
328
|
+
----------
|
|
329
|
+
name : str
|
|
330
|
+
Layer name.
|
|
331
|
+
properties : dict
|
|
332
|
+
Layer properties dictionary.
|
|
333
|
+
"""
|
|
334
|
+
|
|
154
335
|
def __init__(self, name, properties):
|
|
155
336
|
self.name = name
|
|
156
337
|
self.properties = {}
|
|
@@ -158,6 +339,13 @@ class ControlFileDielectric:
|
|
|
158
339
|
self.properties[name] = prop
|
|
159
340
|
|
|
160
341
|
def _write_xml(self, root):
|
|
342
|
+
"""Write dielectric layer to XML element.
|
|
343
|
+
|
|
344
|
+
Parameters
|
|
345
|
+
----------
|
|
346
|
+
root : xml.etree.ElementTree.Element
|
|
347
|
+
Parent XML element to append to.
|
|
348
|
+
"""
|
|
161
349
|
content = ET.SubElement(root, "Layer")
|
|
162
350
|
for property_name, property in self.properties.items():
|
|
163
351
|
if not property_name == "Index":
|
|
@@ -165,6 +353,16 @@ class ControlFileDielectric:
|
|
|
165
353
|
|
|
166
354
|
|
|
167
355
|
class ControlFileLayer:
|
|
356
|
+
"""Represents a general layer in the control file.
|
|
357
|
+
|
|
358
|
+
Parameters
|
|
359
|
+
----------
|
|
360
|
+
name : str
|
|
361
|
+
Layer name.
|
|
362
|
+
properties : dict
|
|
363
|
+
Layer properties dictionary.
|
|
364
|
+
"""
|
|
365
|
+
|
|
168
366
|
def __init__(self, name, properties):
|
|
169
367
|
self.name = name
|
|
170
368
|
self.properties = {}
|
|
@@ -172,6 +370,13 @@ class ControlFileLayer:
|
|
|
172
370
|
self.properties[name] = prop
|
|
173
371
|
|
|
174
372
|
def _write_xml(self, root):
|
|
373
|
+
"""Write layer to XML element.
|
|
374
|
+
|
|
375
|
+
Parameters
|
|
376
|
+
----------
|
|
377
|
+
root : xml.etree.ElementTree.Element
|
|
378
|
+
Parent XML element to append to.
|
|
379
|
+
"""
|
|
175
380
|
content = ET.SubElement(root, "Layer")
|
|
176
381
|
content.set("Color", self.properties.get("Color", "#5c4300"))
|
|
177
382
|
if self.properties.get("Elevation"):
|
|
@@ -196,6 +401,16 @@ class ControlFileLayer:
|
|
|
196
401
|
|
|
197
402
|
|
|
198
403
|
class ControlFileVia(ControlFileLayer):
|
|
404
|
+
"""Represents a via layer in the control file.
|
|
405
|
+
|
|
406
|
+
Parameters
|
|
407
|
+
----------
|
|
408
|
+
name : str
|
|
409
|
+
Via name.
|
|
410
|
+
properties : dict
|
|
411
|
+
Via properties dictionary.
|
|
412
|
+
"""
|
|
413
|
+
|
|
199
414
|
def __init__(self, name, properties):
|
|
200
415
|
ControlFileLayer.__init__(self, name, properties)
|
|
201
416
|
self.create_via_group = False
|
|
@@ -209,6 +424,13 @@ class ControlFileVia(ControlFileLayer):
|
|
|
209
424
|
self.snap_tolerance = 3
|
|
210
425
|
|
|
211
426
|
def _write_xml(self, root):
|
|
427
|
+
"""Write via to XML element.
|
|
428
|
+
|
|
429
|
+
Parameters
|
|
430
|
+
----------
|
|
431
|
+
root : xml.etree.ElementTree.Element
|
|
432
|
+
Parent XML element to append to.
|
|
433
|
+
"""
|
|
212
434
|
content = ET.SubElement(root, "Layer")
|
|
213
435
|
content.set("Color", self.properties.get("Color", "#5c4300"))
|
|
214
436
|
if self.properties.get("Elevation"):
|
|
@@ -240,7 +462,13 @@ class ControlFileVia(ControlFileLayer):
|
|
|
240
462
|
|
|
241
463
|
|
|
242
464
|
class ControlFileStackup:
|
|
243
|
-
"""
|
|
465
|
+
"""Manages stackup information for the control file.
|
|
466
|
+
|
|
467
|
+
Parameters
|
|
468
|
+
----------
|
|
469
|
+
units : str, optional
|
|
470
|
+
Length units (e.g., "mm", "um"). Default is "mm".
|
|
471
|
+
"""
|
|
244
472
|
|
|
245
473
|
def __init__(self, units="mm"):
|
|
246
474
|
self._materials = {}
|
|
@@ -253,45 +481,42 @@ class ControlFileStackup:
|
|
|
253
481
|
|
|
254
482
|
@property
|
|
255
483
|
def vias(self):
|
|
256
|
-
"""
|
|
484
|
+
"""List of via objects.
|
|
257
485
|
|
|
258
486
|
Returns
|
|
259
487
|
-------
|
|
260
|
-
list of
|
|
261
|
-
|
|
488
|
+
list of ControlFileVia
|
|
262
489
|
"""
|
|
263
490
|
return self._vias
|
|
264
491
|
|
|
265
492
|
@property
|
|
266
493
|
def materials(self):
|
|
267
|
-
"""
|
|
494
|
+
"""Dictionary of material objects.
|
|
268
495
|
|
|
269
496
|
Returns
|
|
270
497
|
-------
|
|
271
|
-
|
|
272
|
-
|
|
498
|
+
dict
|
|
499
|
+
Dictionary of material names to ControlFileMaterial objects.
|
|
273
500
|
"""
|
|
274
501
|
return self._materials
|
|
275
502
|
|
|
276
503
|
@property
|
|
277
504
|
def dielectrics(self):
|
|
278
|
-
"""
|
|
505
|
+
"""List of dielectric layers.
|
|
279
506
|
|
|
280
507
|
Returns
|
|
281
508
|
-------
|
|
282
|
-
list of
|
|
283
|
-
|
|
509
|
+
list of ControlFileDielectric
|
|
284
510
|
"""
|
|
285
511
|
return self._dielectrics
|
|
286
512
|
|
|
287
513
|
@property
|
|
288
514
|
def layers(self):
|
|
289
|
-
"""
|
|
515
|
+
"""List of general layers.
|
|
290
516
|
|
|
291
517
|
Returns
|
|
292
518
|
-------
|
|
293
|
-
list of
|
|
294
|
-
|
|
519
|
+
list of ControlFileLayer
|
|
295
520
|
"""
|
|
296
521
|
return self._layers
|
|
297
522
|
|
|
@@ -304,27 +529,27 @@ class ControlFileStackup:
|
|
|
304
529
|
conductivity=0.0,
|
|
305
530
|
properties=None,
|
|
306
531
|
):
|
|
307
|
-
"""Add a new material
|
|
532
|
+
"""Add a new material.
|
|
308
533
|
|
|
309
534
|
Parameters
|
|
310
535
|
----------
|
|
311
536
|
material_name : str
|
|
312
537
|
Material name.
|
|
313
538
|
permittivity : float, optional
|
|
314
|
-
|
|
539
|
+
Relative permittivity. Default is ``1.0``.
|
|
315
540
|
dielectric_loss_tg : float, optional
|
|
316
|
-
|
|
541
|
+
Dielectric loss tangent. Default is ``0.0``.
|
|
317
542
|
permeability : float, optional
|
|
318
|
-
|
|
543
|
+
Relative permeability. Default is ``1.0``.
|
|
319
544
|
conductivity : float, optional
|
|
320
|
-
|
|
545
|
+
Conductivity (S/m). Default is ``0.0``.
|
|
321
546
|
properties : dict, optional
|
|
322
|
-
|
|
323
|
-
Dictionary with key and material property value.
|
|
547
|
+
Additional material properties. Overrides default parameters.
|
|
324
548
|
|
|
325
549
|
Returns
|
|
326
550
|
-------
|
|
327
|
-
|
|
551
|
+
ControlFileMaterial
|
|
552
|
+
Created material object.
|
|
328
553
|
"""
|
|
329
554
|
if isinstance(properties, dict):
|
|
330
555
|
self._materials[material_name] = ControlFileMaterial(material_name, properties)
|
|
@@ -359,26 +584,26 @@ class ControlFileStackup:
|
|
|
359
584
|
layer_name : str
|
|
360
585
|
Layer name.
|
|
361
586
|
elevation : float
|
|
362
|
-
Layer elevation.
|
|
587
|
+
Layer elevation (Z-position).
|
|
363
588
|
material : str
|
|
364
|
-
Material
|
|
589
|
+
Material name.
|
|
365
590
|
gds_type : int
|
|
366
|
-
GDS type
|
|
367
|
-
imported.
|
|
591
|
+
GDS data type for layer.
|
|
368
592
|
target_layer : str
|
|
369
|
-
|
|
593
|
+
Target layer name in EDB/HFSS.
|
|
370
594
|
thickness : float
|
|
371
|
-
Layer thickness
|
|
372
|
-
layer_type : str
|
|
373
|
-
|
|
374
|
-
solve_inside : bool
|
|
375
|
-
|
|
376
|
-
properties : dict
|
|
377
|
-
|
|
595
|
+
Layer thickness.
|
|
596
|
+
layer_type : str, optional
|
|
597
|
+
Layer type ("conductor", "signal", etc.). Default is "conductor".
|
|
598
|
+
solve_inside : bool, optional
|
|
599
|
+
Whether to solve inside metal. Default is ``True``.
|
|
600
|
+
properties : dict, optional
|
|
601
|
+
Additional layer properties. Overrides default parameters.
|
|
378
602
|
|
|
379
603
|
Returns
|
|
380
604
|
-------
|
|
381
|
-
|
|
605
|
+
ControlFileLayer
|
|
606
|
+
Created layer object.
|
|
382
607
|
"""
|
|
383
608
|
if isinstance(properties, dict):
|
|
384
609
|
self._layers.append(ControlFileLayer(layer_name, properties))
|
|
@@ -407,31 +632,29 @@ class ControlFileStackup:
|
|
|
407
632
|
base_layer=None,
|
|
408
633
|
add_on_top=True,
|
|
409
634
|
):
|
|
410
|
-
"""Add a new dielectric.
|
|
635
|
+
"""Add a new dielectric layer.
|
|
411
636
|
|
|
412
637
|
Parameters
|
|
413
638
|
----------
|
|
414
639
|
layer_name : str
|
|
415
|
-
|
|
640
|
+
Dielectric layer name.
|
|
416
641
|
layer_index : int, optional
|
|
417
|
-
|
|
642
|
+
Stacking order index. Auto-assigned if ``None``.
|
|
418
643
|
material : str
|
|
419
644
|
Material name.
|
|
420
645
|
thickness : float
|
|
421
646
|
Layer thickness.
|
|
422
|
-
properties : dict
|
|
423
|
-
|
|
424
|
-
base_layer : str,
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
on top of
|
|
428
|
-
method : bool, Optional.
|
|
429
|
-
Provides the method to use when the argument ``base_layer`` is provided. When ``True`` the layer is added
|
|
430
|
-
on top on the base layer, when ``False`` it will be added below.
|
|
647
|
+
properties : dict, optional
|
|
648
|
+
Additional properties. Overrides default parameters.
|
|
649
|
+
base_layer : str, optional
|
|
650
|
+
Existing layer name for relative placement.
|
|
651
|
+
add_on_top : bool, optional
|
|
652
|
+
Whether to add on top of base layer. Default is ``True``.
|
|
431
653
|
|
|
432
654
|
Returns
|
|
433
655
|
-------
|
|
434
|
-
|
|
656
|
+
ControlFileDielectric
|
|
657
|
+
Created dielectric layer object.
|
|
435
658
|
"""
|
|
436
659
|
if isinstance(properties, dict):
|
|
437
660
|
self._dielectrics.append(ControlFileDielectric(layer_name, properties))
|
|
@@ -481,35 +704,36 @@ class ControlFileStackup:
|
|
|
481
704
|
Parameters
|
|
482
705
|
----------
|
|
483
706
|
layer_name : str
|
|
484
|
-
|
|
707
|
+
Via layer name.
|
|
485
708
|
material : str
|
|
486
|
-
|
|
709
|
+
Material name.
|
|
487
710
|
gds_type : int
|
|
488
|
-
|
|
711
|
+
GDS data type for via layer.
|
|
489
712
|
target_layer : str
|
|
490
|
-
Target layer
|
|
713
|
+
Target layer name in EDB/HFSS.
|
|
491
714
|
start_layer : str
|
|
492
|
-
|
|
715
|
+
Starting layer name.
|
|
493
716
|
stop_layer : str
|
|
494
|
-
|
|
495
|
-
solve_inside : bool
|
|
496
|
-
|
|
497
|
-
via_group_method : str
|
|
498
|
-
|
|
499
|
-
via_group_tol : float
|
|
500
|
-
|
|
501
|
-
via_group_persistent : bool
|
|
502
|
-
|
|
503
|
-
snap_via_group_method : str
|
|
504
|
-
|
|
505
|
-
snap_via_group_tol : float
|
|
506
|
-
|
|
507
|
-
properties : dict
|
|
508
|
-
|
|
717
|
+
Stopping layer name.
|
|
718
|
+
solve_inside : bool, optional
|
|
719
|
+
Whether to solve inside via. Default is ``True``.
|
|
720
|
+
via_group_method : str, optional
|
|
721
|
+
Via grouping method. Default is "proximity".
|
|
722
|
+
via_group_tol : float, optional
|
|
723
|
+
Via grouping tolerance. Default is 1e-6.
|
|
724
|
+
via_group_persistent : bool, optional
|
|
725
|
+
Whether via groups are persistent. Default is ``True``.
|
|
726
|
+
snap_via_group_method : str, optional
|
|
727
|
+
Snap via group method. Default is "distance".
|
|
728
|
+
snap_via_group_tol : float, optional
|
|
729
|
+
Snap via group tolerance. Default is 10e-9.
|
|
730
|
+
properties : dict, optional
|
|
731
|
+
Additional properties. Overrides default parameters.
|
|
509
732
|
|
|
510
733
|
Returns
|
|
511
734
|
-------
|
|
512
|
-
|
|
735
|
+
ControlFileVia
|
|
736
|
+
Created via object.
|
|
513
737
|
"""
|
|
514
738
|
if isinstance(properties, dict):
|
|
515
739
|
self._vias.append(ControlFileVia(layer_name, properties))
|
|
@@ -533,6 +757,13 @@ class ControlFileStackup:
|
|
|
533
757
|
return self._vias[-1]
|
|
534
758
|
|
|
535
759
|
def _write_xml(self, root):
|
|
760
|
+
"""Write stackup to XML element.
|
|
761
|
+
|
|
762
|
+
Parameters
|
|
763
|
+
----------
|
|
764
|
+
root : xml.etree.ElementTree.Element
|
|
765
|
+
Parent XML element to append to.
|
|
766
|
+
"""
|
|
536
767
|
content = ET.SubElement(root, "Stackup")
|
|
537
768
|
content.set("schemaVersion", "1.0")
|
|
538
769
|
materials = ET.SubElement(content, "Materials")
|
|
@@ -559,7 +790,7 @@ class ControlFileStackup:
|
|
|
559
790
|
|
|
560
791
|
|
|
561
792
|
class ControlFileImportOptions:
|
|
562
|
-
"""
|
|
793
|
+
"""Manages import options for the control file."""
|
|
563
794
|
|
|
564
795
|
def __init__(self):
|
|
565
796
|
self.auto_close = False
|
|
@@ -579,6 +810,13 @@ class ControlFileImportOptions:
|
|
|
579
810
|
self.delte_empty_non_laminate_signal_layers = False
|
|
580
811
|
|
|
581
812
|
def _write_xml(self, root):
|
|
813
|
+
"""Write import options to XML element.
|
|
814
|
+
|
|
815
|
+
Parameters
|
|
816
|
+
----------
|
|
817
|
+
root : xml.etree.ElementTree.Element
|
|
818
|
+
Parent XML element to append to.
|
|
819
|
+
"""
|
|
582
820
|
content = ET.SubElement(root, "ImportOptions")
|
|
583
821
|
content.set("AutoClose", str(self.auto_close).lower())
|
|
584
822
|
if self.round_to != 0:
|
|
@@ -603,7 +841,29 @@ class ControlFileImportOptions:
|
|
|
603
841
|
|
|
604
842
|
|
|
605
843
|
class ControlExtent:
|
|
606
|
-
"""
|
|
844
|
+
"""Represents extent options for boundaries.
|
|
845
|
+
|
|
846
|
+
Parameters
|
|
847
|
+
----------
|
|
848
|
+
type : str, optional
|
|
849
|
+
Extent type. Default is "bbox".
|
|
850
|
+
dieltype : str, optional
|
|
851
|
+
Dielectric extent type. Default is "bbox".
|
|
852
|
+
diel_hactor : float, optional
|
|
853
|
+
Dielectric horizontal factor. Default is 0.25.
|
|
854
|
+
airbox_hfactor : float, optional
|
|
855
|
+
Airbox horizontal factor. Default is 0.25.
|
|
856
|
+
airbox_vr_p : float, optional
|
|
857
|
+
Airbox vertical factor (positive). Default is 0.25.
|
|
858
|
+
airbox_vr_n : float, optional
|
|
859
|
+
Airbox vertical factor (negative). Default is 0.25.
|
|
860
|
+
useradiation : bool, optional
|
|
861
|
+
Use radiation boundary. Default is ``True``.
|
|
862
|
+
honor_primitives : bool, optional
|
|
863
|
+
Honor primitives. Default is ``True``.
|
|
864
|
+
truncate_at_gnd : bool, optional
|
|
865
|
+
Truncate at ground. Default is ``True``.
|
|
866
|
+
"""
|
|
607
867
|
|
|
608
868
|
def __init__(
|
|
609
869
|
self,
|
|
@@ -628,6 +888,13 @@ class ControlExtent:
|
|
|
628
888
|
self.truncate_at_gnd = truncate_at_gnd
|
|
629
889
|
|
|
630
890
|
def _write_xml(self, root):
|
|
891
|
+
"""Write extent options to XML element.
|
|
892
|
+
|
|
893
|
+
Parameters
|
|
894
|
+
----------
|
|
895
|
+
root : xml.etree.ElementTree.Element
|
|
896
|
+
Parent XML element to append to.
|
|
897
|
+
"""
|
|
631
898
|
content = ET.SubElement(root, "Extents")
|
|
632
899
|
content.set("Type", self.type)
|
|
633
900
|
content.set("DielType", self.dieltype)
|
|
@@ -641,7 +908,27 @@ class ControlExtent:
|
|
|
641
908
|
|
|
642
909
|
|
|
643
910
|
class ControlCircuitPt:
|
|
644
|
-
"""
|
|
911
|
+
"""Represents a circuit port.
|
|
912
|
+
|
|
913
|
+
Parameters
|
|
914
|
+
----------
|
|
915
|
+
name : str
|
|
916
|
+
Port name.
|
|
917
|
+
x1 : float
|
|
918
|
+
X-coordinate of first point.
|
|
919
|
+
y1 : float
|
|
920
|
+
Y-coordinate of first point.
|
|
921
|
+
lay1 : str
|
|
922
|
+
Layer of first point.
|
|
923
|
+
x2 : float
|
|
924
|
+
X-coordinate of second point.
|
|
925
|
+
y2 : float
|
|
926
|
+
Y-coordinate of second point.
|
|
927
|
+
lay2 : str
|
|
928
|
+
Layer of second point.
|
|
929
|
+
z0 : float
|
|
930
|
+
Characteristic impedance.
|
|
931
|
+
"""
|
|
645
932
|
|
|
646
933
|
def __init__(self, name, x1, y1, lay1, x2, y2, lay2, z0):
|
|
647
934
|
self.name = name
|
|
@@ -654,6 +941,13 @@ class ControlCircuitPt:
|
|
|
654
941
|
self.z0 = z0
|
|
655
942
|
|
|
656
943
|
def _write_xml(self, root):
|
|
944
|
+
"""Write circuit port to XML element.
|
|
945
|
+
|
|
946
|
+
Parameters
|
|
947
|
+
----------
|
|
948
|
+
root : xml.etree.ElementTree.Element
|
|
949
|
+
Parent XML element to append to.
|
|
950
|
+
"""
|
|
657
951
|
content = ET.SubElement(root, "CircuitPortPt")
|
|
658
952
|
content.set("Name", self.name)
|
|
659
953
|
content.set("x1", self.x1)
|
|
@@ -666,7 +960,7 @@ class ControlCircuitPt:
|
|
|
666
960
|
|
|
667
961
|
|
|
668
962
|
class ControlFileComponent:
|
|
669
|
-
"""
|
|
963
|
+
"""Represents a component in the control file."""
|
|
670
964
|
|
|
671
965
|
def __init__(self):
|
|
672
966
|
self.refdes = "U1"
|
|
@@ -682,9 +976,39 @@ class ControlFileComponent:
|
|
|
682
976
|
self.ports = []
|
|
683
977
|
|
|
684
978
|
def add_pin(self, name, x, y, layer):
|
|
979
|
+
"""Add a pin to the component.
|
|
980
|
+
|
|
981
|
+
Parameters
|
|
982
|
+
----------
|
|
983
|
+
name : str
|
|
984
|
+
Pin name.
|
|
985
|
+
x : float
|
|
986
|
+
X-coordinate.
|
|
987
|
+
y : float
|
|
988
|
+
Y-coordinate.
|
|
989
|
+
layer : str
|
|
990
|
+
Layer name.
|
|
991
|
+
"""
|
|
685
992
|
self.pins.append({"Name": name, "x": x, "y": y, "Layer": layer})
|
|
686
993
|
|
|
687
994
|
def add_port(self, name, z0, pospin, refpin=None, pos_type="pin", ref_type="pin"):
|
|
995
|
+
"""Add a port to the component.
|
|
996
|
+
|
|
997
|
+
Parameters
|
|
998
|
+
----------
|
|
999
|
+
name : str
|
|
1000
|
+
Port name.
|
|
1001
|
+
z0 : float
|
|
1002
|
+
Characteristic impedance.
|
|
1003
|
+
pospin : str
|
|
1004
|
+
Positive pin/group name.
|
|
1005
|
+
refpin : str, optional
|
|
1006
|
+
Reference pin/group name.
|
|
1007
|
+
pos_type : str, optional
|
|
1008
|
+
Positive element type ("pin" or "pingroup"). Default is "pin".
|
|
1009
|
+
ref_type : str, optional
|
|
1010
|
+
Reference element type ("pin", "pingroup", or "net"). Default is "pin".
|
|
1011
|
+
"""
|
|
688
1012
|
args = {"Name": name, "Z0": z0}
|
|
689
1013
|
if pos_type == "pin":
|
|
690
1014
|
args["PosPin"] = pospin
|
|
@@ -700,6 +1024,13 @@ class ControlFileComponent:
|
|
|
700
1024
|
self.ports.append(args)
|
|
701
1025
|
|
|
702
1026
|
def _write_xml(self, root):
|
|
1027
|
+
"""Write component to XML element.
|
|
1028
|
+
|
|
1029
|
+
Parameters
|
|
1030
|
+
----------
|
|
1031
|
+
root : xml.etree.ElementTree.Element
|
|
1032
|
+
Parent XML element to append to.
|
|
1033
|
+
"""
|
|
703
1034
|
content = ET.SubElement(root, "GDS_COMPONENT")
|
|
704
1035
|
for p in self.pins:
|
|
705
1036
|
prop = ET.SubElement(content, "GDS_PIN")
|
|
@@ -725,31 +1056,32 @@ class ControlFileComponent:
|
|
|
725
1056
|
|
|
726
1057
|
|
|
727
1058
|
class ControlFileComponents:
|
|
728
|
-
"""
|
|
1059
|
+
"""Manages components for the control file."""
|
|
729
1060
|
|
|
730
1061
|
def __init__(self):
|
|
731
1062
|
self.units = "um"
|
|
732
1063
|
self.components = []
|
|
733
1064
|
|
|
734
1065
|
def add_component(self, ref_des, partname, component_type, die_type="None", solderball_shape="None"):
|
|
735
|
-
"""
|
|
1066
|
+
"""Add a new component.
|
|
736
1067
|
|
|
737
1068
|
Parameters
|
|
738
1069
|
----------
|
|
739
1070
|
ref_des : str
|
|
740
|
-
Reference
|
|
1071
|
+
Reference designator.
|
|
741
1072
|
partname : str
|
|
742
1073
|
Part name.
|
|
743
1074
|
component_type : str
|
|
744
|
-
Component
|
|
1075
|
+
Component type ("IC", "IO", or "Other").
|
|
745
1076
|
die_type : str, optional
|
|
746
|
-
Die
|
|
1077
|
+
Die type ("None", "Flip chip", or "Wire bond"). Default is "None".
|
|
747
1078
|
solderball_shape : str, optional
|
|
748
|
-
Solderball
|
|
1079
|
+
Solderball shape ("None", "Cylinder", or "Spheroid"). Default is "None".
|
|
749
1080
|
|
|
750
1081
|
Returns
|
|
751
1082
|
-------
|
|
752
|
-
|
|
1083
|
+
ControlFileComponent
|
|
1084
|
+
Created component object.
|
|
753
1085
|
"""
|
|
754
1086
|
comp = ControlFileComponent()
|
|
755
1087
|
comp.refdes = ref_des
|
|
@@ -762,7 +1094,13 @@ class ControlFileComponents:
|
|
|
762
1094
|
|
|
763
1095
|
|
|
764
1096
|
class ControlFileBoundaries:
|
|
765
|
-
"""
|
|
1097
|
+
"""Manages boundaries for the control file.
|
|
1098
|
+
|
|
1099
|
+
Parameters
|
|
1100
|
+
----------
|
|
1101
|
+
units : str, optional
|
|
1102
|
+
Length units. Default is "um".
|
|
1103
|
+
"""
|
|
766
1104
|
|
|
767
1105
|
def __init__(self, units="um"):
|
|
768
1106
|
self.ports = {}
|
|
@@ -772,30 +1110,31 @@ class ControlFileBoundaries:
|
|
|
772
1110
|
self.units = units
|
|
773
1111
|
|
|
774
1112
|
def add_port(self, name, x1, y1, layer1, x2, y2, layer2, z0=50):
|
|
775
|
-
"""Add a
|
|
1113
|
+
"""Add a port.
|
|
776
1114
|
|
|
777
1115
|
Parameters
|
|
778
1116
|
----------
|
|
779
1117
|
name : str
|
|
780
1118
|
Port name.
|
|
781
|
-
x1 :
|
|
782
|
-
|
|
783
|
-
y1 :
|
|
784
|
-
|
|
1119
|
+
x1 : float
|
|
1120
|
+
X-coordinate of first point.
|
|
1121
|
+
y1 : float
|
|
1122
|
+
Y-coordinate of first point.
|
|
785
1123
|
layer1 : str
|
|
786
|
-
|
|
787
|
-
x2 :
|
|
788
|
-
|
|
789
|
-
y2 :
|
|
790
|
-
|
|
1124
|
+
Layer of first point.
|
|
1125
|
+
x2 : float
|
|
1126
|
+
X-coordinate of second point.
|
|
1127
|
+
y2 : float
|
|
1128
|
+
Y-coordinate of second point.
|
|
791
1129
|
layer2 : str
|
|
792
|
-
|
|
793
|
-
z0 :
|
|
794
|
-
Characteristic impedance.
|
|
1130
|
+
Layer of second point.
|
|
1131
|
+
z0 : float, optional
|
|
1132
|
+
Characteristic impedance. Default is 50.
|
|
795
1133
|
|
|
796
1134
|
Returns
|
|
797
1135
|
-------
|
|
798
|
-
|
|
1136
|
+
ControlCircuitPt
|
|
1137
|
+
Created port object.
|
|
799
1138
|
"""
|
|
800
1139
|
self.ports[name] = ControlCircuitPt(name, str(x1), str(y1), layer1, str(x2), str(y2), layer2, str(z0))
|
|
801
1140
|
return self.ports[name]
|
|
@@ -812,23 +1151,33 @@ class ControlFileBoundaries:
|
|
|
812
1151
|
honor_primitives=True,
|
|
813
1152
|
truncate_at_gnd=True,
|
|
814
1153
|
):
|
|
815
|
-
"""Add
|
|
1154
|
+
"""Add an extent.
|
|
816
1155
|
|
|
817
1156
|
Parameters
|
|
818
1157
|
----------
|
|
819
|
-
type
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
1158
|
+
type : str, optional
|
|
1159
|
+
Extent type. Default is "bbox".
|
|
1160
|
+
dieltype : str, optional
|
|
1161
|
+
Dielectric extent type. Default is "bbox".
|
|
1162
|
+
diel_hactor : float, optional
|
|
1163
|
+
Dielectric horizontal factor. Default is 0.25.
|
|
1164
|
+
airbox_hfactor : float, optional
|
|
1165
|
+
Airbox horizontal factor. Default is 0.25.
|
|
1166
|
+
airbox_vr_p : float, optional
|
|
1167
|
+
Airbox vertical factor (positive). Default is 0.25.
|
|
1168
|
+
airbox_vr_n : float, optional
|
|
1169
|
+
Airbox vertical factor (negative). Default is 0.25.
|
|
1170
|
+
useradiation : bool, optional
|
|
1171
|
+
Use radiation boundary. Default is ``True``.
|
|
1172
|
+
honor_primitives : bool, optional
|
|
1173
|
+
Honor primitives. Default is ``True``.
|
|
1174
|
+
truncate_at_gnd : bool, optional
|
|
1175
|
+
Truncate at ground. Default is ``True``.
|
|
828
1176
|
|
|
829
1177
|
Returns
|
|
830
1178
|
-------
|
|
831
|
-
|
|
1179
|
+
ControlExtent
|
|
1180
|
+
Created extent object.
|
|
832
1181
|
"""
|
|
833
1182
|
self.extents.append(
|
|
834
1183
|
ControlExtent(
|
|
@@ -846,6 +1195,13 @@ class ControlFileBoundaries:
|
|
|
846
1195
|
return self.extents[-1]
|
|
847
1196
|
|
|
848
1197
|
def _write_xml(self, root):
|
|
1198
|
+
"""Write boundaries to XML element.
|
|
1199
|
+
|
|
1200
|
+
Parameters
|
|
1201
|
+
----------
|
|
1202
|
+
root : xml.etree.ElementTree.Element
|
|
1203
|
+
Parent XML element to append to.
|
|
1204
|
+
"""
|
|
849
1205
|
content = ET.SubElement(root, "Boundaries")
|
|
850
1206
|
content.set("LengthUnit", self.units)
|
|
851
1207
|
for p in self.circuit_models.values():
|
|
@@ -859,6 +1215,26 @@ class ControlFileBoundaries:
|
|
|
859
1215
|
|
|
860
1216
|
|
|
861
1217
|
class ControlFileSweep:
|
|
1218
|
+
"""Represents a frequency sweep.
|
|
1219
|
+
|
|
1220
|
+
Parameters
|
|
1221
|
+
----------
|
|
1222
|
+
name : str
|
|
1223
|
+
Sweep name.
|
|
1224
|
+
start : str
|
|
1225
|
+
Start frequency.
|
|
1226
|
+
stop : str
|
|
1227
|
+
Stop frequency.
|
|
1228
|
+
step : str
|
|
1229
|
+
Frequency step/count.
|
|
1230
|
+
sweep_type : str
|
|
1231
|
+
Sweep type ("Discrete" or "Interpolating").
|
|
1232
|
+
step_type : str
|
|
1233
|
+
Step type ("LinearStep", "DecadeCount", or "LinearCount").
|
|
1234
|
+
use_q3d : bool
|
|
1235
|
+
Whether to use Q3D for DC point.
|
|
1236
|
+
"""
|
|
1237
|
+
|
|
862
1238
|
def __init__(self, name, start, stop, step, sweep_type, step_type, use_q3d):
|
|
863
1239
|
self.name = name
|
|
864
1240
|
self.start = start
|
|
@@ -869,6 +1245,13 @@ class ControlFileSweep:
|
|
|
869
1245
|
self.use_q3d = use_q3d
|
|
870
1246
|
|
|
871
1247
|
def _write_xml(self, root):
|
|
1248
|
+
"""Write sweep to XML element.
|
|
1249
|
+
|
|
1250
|
+
Parameters
|
|
1251
|
+
----------
|
|
1252
|
+
root : xml.etree.ElementTree.Element
|
|
1253
|
+
Parent XML element to append to.
|
|
1254
|
+
"""
|
|
872
1255
|
sweep = ET.SubElement(root, "FreqSweep")
|
|
873
1256
|
prop = ET.SubElement(sweep, "Name")
|
|
874
1257
|
prop.text = self.name
|
|
@@ -889,6 +1272,20 @@ class ControlFileSweep:
|
|
|
889
1272
|
|
|
890
1273
|
|
|
891
1274
|
class ControlFileMeshOp:
|
|
1275
|
+
"""Represents a mesh operation.
|
|
1276
|
+
|
|
1277
|
+
Parameters
|
|
1278
|
+
----------
|
|
1279
|
+
name : str
|
|
1280
|
+
Operation name.
|
|
1281
|
+
region : str
|
|
1282
|
+
Region name.
|
|
1283
|
+
type : str
|
|
1284
|
+
Operation type ("MeshOperationLength" or "MeshOperationSkinDepth").
|
|
1285
|
+
nets_layers : dict
|
|
1286
|
+
Dictionary of nets and layers.
|
|
1287
|
+
"""
|
|
1288
|
+
|
|
892
1289
|
def __init__(self, name, region, type, nets_layers):
|
|
893
1290
|
self.name = name
|
|
894
1291
|
self.region = name
|
|
@@ -904,6 +1301,13 @@ class ControlFileMeshOp:
|
|
|
904
1301
|
self.region_solve_inside = False
|
|
905
1302
|
|
|
906
1303
|
def _write_xml(self, root):
|
|
1304
|
+
"""Write mesh operation to XML element.
|
|
1305
|
+
|
|
1306
|
+
Parameters
|
|
1307
|
+
----------
|
|
1308
|
+
root : xml.etree.ElementTree.Element
|
|
1309
|
+
Parent XML element to append to.
|
|
1310
|
+
"""
|
|
907
1311
|
mop = ET.SubElement(root, "MeshOperation")
|
|
908
1312
|
prop = ET.SubElement(mop, "Name")
|
|
909
1313
|
prop.text = self.name
|
|
@@ -941,7 +1345,13 @@ class ControlFileMeshOp:
|
|
|
941
1345
|
|
|
942
1346
|
|
|
943
1347
|
class ControlFileSetup:
|
|
944
|
-
"""
|
|
1348
|
+
"""Represents a simulation setup.
|
|
1349
|
+
|
|
1350
|
+
Parameters
|
|
1351
|
+
----------
|
|
1352
|
+
name : str
|
|
1353
|
+
Setup name.
|
|
1354
|
+
"""
|
|
945
1355
|
|
|
946
1356
|
def __init__(self, name):
|
|
947
1357
|
self.name = name
|
|
@@ -962,55 +1372,64 @@ class ControlFileSetup:
|
|
|
962
1372
|
self.sweeps = []
|
|
963
1373
|
|
|
964
1374
|
def add_sweep(self, name, start, stop, step, sweep_type="Interpolating", step_type="LinearStep", use_q3d=True):
|
|
965
|
-
"""Add a
|
|
1375
|
+
"""Add a frequency sweep.
|
|
966
1376
|
|
|
967
1377
|
Parameters
|
|
968
1378
|
----------
|
|
969
1379
|
name : str
|
|
970
1380
|
Sweep name.
|
|
971
1381
|
start : str
|
|
972
|
-
|
|
1382
|
+
Start frequency.
|
|
973
1383
|
stop : str
|
|
974
|
-
|
|
1384
|
+
Stop frequency.
|
|
975
1385
|
step : str
|
|
976
|
-
Frequency step
|
|
977
|
-
sweep_type : str
|
|
978
|
-
Sweep type
|
|
979
|
-
step_type : str
|
|
980
|
-
|
|
981
|
-
use_q3d
|
|
1386
|
+
Frequency step/count.
|
|
1387
|
+
sweep_type : str, optional
|
|
1388
|
+
Sweep type ("Discrete" or "Interpolating"). Default is "Interpolating".
|
|
1389
|
+
step_type : str, optional
|
|
1390
|
+
Step type ("LinearStep", "DecadeCount", or "LinearCount"). Default is "LinearStep".
|
|
1391
|
+
use_q3d : bool, optional
|
|
1392
|
+
Whether to use Q3D for DC point. Default is ``True``.
|
|
982
1393
|
|
|
983
1394
|
Returns
|
|
984
1395
|
-------
|
|
985
|
-
|
|
1396
|
+
ControlFileSweep
|
|
1397
|
+
Created sweep object.
|
|
986
1398
|
"""
|
|
987
1399
|
self.sweeps.append(ControlFileSweep(name, start, stop, step, sweep_type, step_type, use_q3d))
|
|
988
1400
|
return self.sweeps[-1]
|
|
989
1401
|
|
|
990
1402
|
def add_mesh_operation(self, name, region, type, nets_layers):
|
|
991
|
-
"""Add mesh
|
|
1403
|
+
"""Add a mesh operation.
|
|
992
1404
|
|
|
993
1405
|
Parameters
|
|
994
1406
|
----------
|
|
995
1407
|
name : str
|
|
996
|
-
|
|
1408
|
+
Operation name.
|
|
997
1409
|
region : str
|
|
998
|
-
Region
|
|
1410
|
+
Region name.
|
|
999
1411
|
type : str
|
|
1000
|
-
|
|
1412
|
+
Operation type ("MeshOperationLength" or "MeshOperationSkinDepth").
|
|
1001
1413
|
nets_layers : dict
|
|
1002
|
-
Dictionary
|
|
1414
|
+
Dictionary of nets and layers.
|
|
1003
1415
|
|
|
1004
1416
|
Returns
|
|
1005
1417
|
-------
|
|
1006
|
-
|
|
1007
|
-
|
|
1418
|
+
ControlFileMeshOp
|
|
1419
|
+
Created mesh operation object.
|
|
1008
1420
|
"""
|
|
1009
1421
|
mop = ControlFileMeshOp(name, region, type, nets_layers)
|
|
1010
1422
|
self.mesh_operations.append(mop)
|
|
1011
1423
|
return mop
|
|
1012
1424
|
|
|
1013
1425
|
def _write_xml(self, root):
|
|
1426
|
+
"""Write setup to XML element.
|
|
1427
|
+
|
|
1428
|
+
Parameters
|
|
1429
|
+
----------
|
|
1430
|
+
root : xml.etree.ElementTree.Element
|
|
1431
|
+
Parent XML element to append to.
|
|
1432
|
+
"""
|
|
1014
1433
|
setups = ET.SubElement(root, "HFSSSetup")
|
|
1015
1434
|
setups.set("schemaVersion", "1.0")
|
|
1016
1435
|
setups.set("Name", self.name)
|
|
@@ -1056,24 +1475,25 @@ class ControlFileSetup:
|
|
|
1056
1475
|
|
|
1057
1476
|
|
|
1058
1477
|
class ControlFileSetups:
|
|
1059
|
-
"""
|
|
1478
|
+
"""Manages simulation setups."""
|
|
1060
1479
|
|
|
1061
1480
|
def __init__(self):
|
|
1062
1481
|
self.setups = []
|
|
1063
1482
|
|
|
1064
1483
|
def add_setup(self, name, frequency):
|
|
1065
|
-
"""Add a
|
|
1484
|
+
"""Add a simulation setup.
|
|
1066
1485
|
|
|
1067
1486
|
Parameters
|
|
1068
1487
|
----------
|
|
1069
1488
|
name : str
|
|
1070
1489
|
Setup name.
|
|
1071
1490
|
frequency : str
|
|
1072
|
-
|
|
1491
|
+
Adaptive frequency.
|
|
1073
1492
|
|
|
1074
1493
|
Returns
|
|
1075
1494
|
-------
|
|
1076
|
-
|
|
1495
|
+
ControlFileSetup
|
|
1496
|
+
Created setup object.
|
|
1077
1497
|
"""
|
|
1078
1498
|
setup = ControlFileSetup(name)
|
|
1079
1499
|
setup.frequency = frequency
|
|
@@ -1081,13 +1501,30 @@ class ControlFileSetups:
|
|
|
1081
1501
|
return setup
|
|
1082
1502
|
|
|
1083
1503
|
def _write_xml(self, root):
|
|
1504
|
+
"""Write setups to XML element.
|
|
1505
|
+
|
|
1506
|
+
Parameters
|
|
1507
|
+
----------
|
|
1508
|
+
root : xml.etree.ElementTree.Element
|
|
1509
|
+
Parent XML element to append to.
|
|
1510
|
+
"""
|
|
1084
1511
|
content = ET.SubElement(root, "SimulationSetups")
|
|
1085
1512
|
for setup in self.setups:
|
|
1086
1513
|
setup._write_xml(content)
|
|
1087
1514
|
|
|
1088
1515
|
|
|
1089
1516
|
class ControlFile:
|
|
1090
|
-
"""
|
|
1517
|
+
"""Main class for EDB control file creation and management.
|
|
1518
|
+
|
|
1519
|
+
Parameters
|
|
1520
|
+
----------
|
|
1521
|
+
xml_input : str, optional
|
|
1522
|
+
Path to existing XML file to parse.
|
|
1523
|
+
tecnhology : str, optional
|
|
1524
|
+
Path to technology file to convert.
|
|
1525
|
+
layer_map : str, optional
|
|
1526
|
+
Path to layer map file.
|
|
1527
|
+
"""
|
|
1091
1528
|
|
|
1092
1529
|
def __init__(self, xml_input=None, tecnhology=None, layer_map=None):
|
|
1093
1530
|
self.stackup = ControlFileStackup()
|
|
@@ -1107,16 +1544,19 @@ class ControlFile:
|
|
|
1107
1544
|
pass
|
|
1108
1545
|
|
|
1109
1546
|
def parse_technology(self, tecnhology, edbversion=None):
|
|
1110
|
-
"""Parse technology
|
|
1547
|
+
"""Parse a technology file and convert to XML control file.
|
|
1111
1548
|
|
|
1112
1549
|
Parameters
|
|
1113
1550
|
----------
|
|
1114
|
-
|
|
1115
|
-
|
|
1551
|
+
tecnhology : str
|
|
1552
|
+
Path to technology file.
|
|
1553
|
+
edbversion : str, optional
|
|
1554
|
+
EDB version to use for conversion.
|
|
1116
1555
|
|
|
1117
1556
|
Returns
|
|
1118
1557
|
-------
|
|
1119
1558
|
bool
|
|
1559
|
+
``True`` if successful, ``False`` otherwise.
|
|
1120
1560
|
"""
|
|
1121
1561
|
xml_temp = os.path.splitext(tecnhology)[0] + "_temp.xml"
|
|
1122
1562
|
xml_temp = convert_technology_file(tech_file=tecnhology, edbversion=edbversion, control_file=xml_temp)
|
|
@@ -1124,17 +1564,17 @@ class ControlFile:
|
|
|
1124
1564
|
return self.parse_xml(xml_temp)
|
|
1125
1565
|
|
|
1126
1566
|
def parse_layer_map(self, layer_map):
|
|
1127
|
-
"""Parse layer map and
|
|
1128
|
-
This operation must be performed after a tech file is imported.
|
|
1567
|
+
"""Parse a layer map file and update stackup.
|
|
1129
1568
|
|
|
1130
1569
|
Parameters
|
|
1131
1570
|
----------
|
|
1132
1571
|
layer_map : str
|
|
1133
|
-
|
|
1572
|
+
Path to layer map file.
|
|
1134
1573
|
|
|
1135
1574
|
Returns
|
|
1136
1575
|
-------
|
|
1137
|
-
|
|
1576
|
+
bool
|
|
1577
|
+
``True`` if successful, ``False`` otherwise.
|
|
1138
1578
|
"""
|
|
1139
1579
|
with open(layer_map, "r") as f:
|
|
1140
1580
|
lines = f.readlines()
|
|
@@ -1174,16 +1614,17 @@ class ControlFile:
|
|
|
1174
1614
|
return True
|
|
1175
1615
|
|
|
1176
1616
|
def parse_xml(self, xml_input):
|
|
1177
|
-
"""Parse an
|
|
1617
|
+
"""Parse an XML control file and populate the object.
|
|
1178
1618
|
|
|
1179
1619
|
Parameters
|
|
1180
1620
|
----------
|
|
1181
1621
|
xml_input : str
|
|
1182
|
-
|
|
1622
|
+
Path to XML control file.
|
|
1183
1623
|
|
|
1184
1624
|
Returns
|
|
1185
1625
|
-------
|
|
1186
1626
|
bool
|
|
1627
|
+
``True`` if successful, ``False`` otherwise.
|
|
1187
1628
|
"""
|
|
1188
1629
|
tree = ET.parse(xml_input)
|
|
1189
1630
|
root = tree.getroot()
|
|
@@ -1244,16 +1685,17 @@ class ControlFile:
|
|
|
1244
1685
|
return True
|
|
1245
1686
|
|
|
1246
1687
|
def write_xml(self, xml_output):
|
|
1247
|
-
"""Write
|
|
1688
|
+
"""Write control file to XML.
|
|
1248
1689
|
|
|
1249
1690
|
Parameters
|
|
1250
1691
|
----------
|
|
1251
1692
|
xml_output : str
|
|
1252
|
-
|
|
1693
|
+
Output XML file path.
|
|
1253
1694
|
|
|
1254
1695
|
Returns
|
|
1255
1696
|
-------
|
|
1256
1697
|
bool
|
|
1698
|
+
``True`` if file created successfully, ``False`` otherwise.
|
|
1257
1699
|
"""
|
|
1258
1700
|
control = ET.Element("{http://www.ansys.com/control}Control", attrib={"schemaVersion": "1.0"})
|
|
1259
1701
|
self.stackup._write_xml(control)
|