pyedb 0.54.0__py3-none-any.whl → 0.56.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyedb might be problematic. Click here for more details.
- pyedb/__init__.py +1 -8
- pyedb/configuration/cfg_boundaries.py +69 -151
- pyedb/configuration/cfg_components.py +201 -460
- pyedb/configuration/cfg_data.py +4 -2
- pyedb/configuration/cfg_general.py +13 -36
- pyedb/configuration/cfg_modeler.py +2 -1
- pyedb/configuration/cfg_nets.py +21 -35
- pyedb/configuration/cfg_operations.py +22 -151
- pyedb/configuration/cfg_package_definition.py +56 -112
- pyedb/configuration/cfg_padstacks.py +292 -688
- pyedb/configuration/cfg_pin_groups.py +32 -79
- pyedb/configuration/cfg_ports_sources.py +19 -6
- pyedb/configuration/cfg_s_parameter_models.py +67 -172
- pyedb/configuration/cfg_setup.py +102 -295
- pyedb/configuration/configuration.py +64 -5
- pyedb/dotnet/database/Variables.py +26 -19
- pyedb/dotnet/database/cell/connectable.py +38 -9
- pyedb/dotnet/database/cell/hierarchy/component.py +28 -28
- pyedb/dotnet/database/cell/hierarchy/model.py +1 -1
- pyedb/dotnet/database/cell/layout.py +63 -2
- pyedb/dotnet/database/cell/layout_obj.py +2 -2
- pyedb/dotnet/database/cell/primitive/path.py +6 -8
- pyedb/dotnet/database/cell/primitive/primitive.py +3 -24
- pyedb/dotnet/database/cell/terminal/edge_terminal.py +2 -2
- pyedb/dotnet/database/cell/terminal/padstack_instance_terminal.py +1 -1
- pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
- pyedb/dotnet/database/cell/terminal/point_terminal.py +1 -1
- pyedb/dotnet/database/cell/terminal/terminal.py +24 -24
- pyedb/dotnet/database/cell/voltage_regulator.py +0 -21
- pyedb/dotnet/database/components.py +137 -124
- pyedb/dotnet/database/definition/component_def.py +4 -4
- pyedb/dotnet/database/definition/component_model.py +1 -1
- pyedb/dotnet/database/definition/package_def.py +2 -3
- pyedb/dotnet/database/dotnet/database.py +3 -199
- pyedb/dotnet/database/dotnet/primitive.py +3 -3
- pyedb/dotnet/database/edb_data/control_file.py +5 -5
- pyedb/dotnet/database/edb_data/hfss_extent_info.py +6 -6
- pyedb/dotnet/database/edb_data/layer_data.py +23 -23
- pyedb/dotnet/database/edb_data/padstacks_data.py +63 -88
- pyedb/dotnet/database/edb_data/primitives_data.py +5 -5
- pyedb/dotnet/database/edb_data/sources.py +6 -6
- pyedb/dotnet/database/edb_data/variables.py +1 -1
- pyedb/dotnet/database/geometry/point_data.py +14 -10
- pyedb/dotnet/database/geometry/polygon_data.py +3 -3
- pyedb/dotnet/database/hfss.py +46 -48
- pyedb/dotnet/database/layout_validation.py +14 -11
- pyedb/dotnet/database/materials.py +10 -11
- pyedb/dotnet/database/modeler.py +97 -91
- pyedb/dotnet/database/nets.py +19 -22
- pyedb/dotnet/database/padstack.py +171 -83
- pyedb/dotnet/database/siwave.py +42 -42
- pyedb/dotnet/database/stackup.py +140 -72
- pyedb/dotnet/database/utilities/heatsink.py +4 -4
- pyedb/dotnet/database/utilities/obj_base.py +2 -2
- pyedb/dotnet/database/utilities/simulation_setup.py +2 -2
- pyedb/dotnet/database/utilities/value.py +16 -16
- pyedb/dotnet/edb.py +230 -152
- pyedb/edb_logger.py +12 -27
- pyedb/extensions/create_cell_array.py +394 -0
- pyedb/extensions/via_design_backend.py +6 -3
- pyedb/generic/data_handlers.py +6 -7
- pyedb/generic/design_types.py +81 -30
- pyedb/generic/filesystem.py +5 -2
- pyedb/generic/general_methods.py +2 -122
- pyedb/generic/process.py +44 -108
- pyedb/generic/settings.py +79 -19
- pyedb/grpc/database/components.py +26 -4
- pyedb/grpc/database/control_file.py +5 -5
- pyedb/grpc/database/definition/materials.py +1 -1
- pyedb/grpc/database/definition/package_def.py +3 -3
- pyedb/grpc/database/definition/padstack_def.py +53 -0
- pyedb/grpc/database/geometry/polygon_data.py +1 -1
- pyedb/grpc/database/layout/layout.py +81 -5
- pyedb/grpc/database/layout_validation.py +5 -5
- pyedb/grpc/database/modeler.py +24 -16
- pyedb/grpc/database/net/net.py +15 -14
- pyedb/grpc/database/nets.py +70 -0
- pyedb/grpc/database/padstacks.py +122 -17
- pyedb/grpc/database/primitive/padstack_instance.py +175 -7
- pyedb/grpc/database/primitive/polygon.py +2 -2
- pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +3 -2
- pyedb/grpc/database/siwave.py +1 -1
- pyedb/grpc/database/source_excitations.py +12 -5
- pyedb/grpc/database/stackup.py +1 -1
- pyedb/grpc/database/terminal/bundle_terminal.py +1 -1
- pyedb/grpc/database/terminal/padstack_instance_terminal.py +1 -1
- pyedb/grpc/database/terminal/pingroup_terminal.py +1 -1
- pyedb/grpc/database/utility/value.py +1 -0
- pyedb/grpc/database/utility/xml_control_file.py +5 -5
- pyedb/grpc/edb.py +80 -30
- pyedb/grpc/edb_init.py +3 -3
- pyedb/grpc/rpc_session.py +14 -13
- pyedb/libraries/common.py +366 -0
- pyedb/libraries/rf_libraries/base_functions.py +1358 -0
- pyedb/libraries/rf_libraries/planar_antennas.py +628 -0
- pyedb/misc/decorators.py +61 -0
- pyedb/misc/misc.py +0 -13
- pyedb/modeler/geometry_operators.py +6 -6
- pyedb/siwave.py +6 -8
- pyedb/siwave_core/__init__.py +0 -0
- pyedb/siwave_core/cpa/__init__.py +0 -0
- {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/METADATA +1 -2
- {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/RECORD +105 -98
- {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/WHEEL +0 -0
- {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/licenses/LICENSE +0 -0
pyedb/generic/design_types.py
CHANGED
|
@@ -23,7 +23,8 @@ from typing import TYPE_CHECKING, Literal, Union, overload
|
|
|
23
23
|
import warnings
|
|
24
24
|
|
|
25
25
|
from pyedb.generic.grpc_warnings import GRPC_GENERAL_WARNING
|
|
26
|
-
from pyedb.
|
|
26
|
+
from pyedb.generic.settings import settings
|
|
27
|
+
from pyedb.misc.decorators import deprecate_argument_name
|
|
27
28
|
|
|
28
29
|
if TYPE_CHECKING:
|
|
29
30
|
from pyedb.dotnet.edb import Edb as EdbDotnet
|
|
@@ -46,18 +47,21 @@ def Edb(*, grpc: bool, **kwargs) -> Union["EdbGrpc", "EdbDotnet"]:
|
|
|
46
47
|
|
|
47
48
|
|
|
48
49
|
# lazy imports
|
|
50
|
+
@deprecate_argument_name({"edbversion": "version"})
|
|
49
51
|
def Edb(
|
|
50
52
|
edbpath=None,
|
|
51
53
|
cellname=None,
|
|
52
54
|
isreadonly=False,
|
|
53
|
-
|
|
55
|
+
version=None,
|
|
54
56
|
isaedtowned=False,
|
|
55
57
|
oproject=None,
|
|
56
58
|
student_version=False,
|
|
57
59
|
use_ppe=False,
|
|
60
|
+
map_file=None,
|
|
58
61
|
technology_file=None,
|
|
59
62
|
grpc=False,
|
|
60
63
|
control_file=None,
|
|
64
|
+
layer_filter=None,
|
|
61
65
|
):
|
|
62
66
|
"""Provides the EDB application interface.
|
|
63
67
|
|
|
@@ -76,7 +80,7 @@ def Edb(
|
|
|
76
80
|
isreadonly : bool, optional
|
|
77
81
|
Whether to open EBD in read-only mode when it is
|
|
78
82
|
owned by HFSS 3D Layout. The default is ``False``.
|
|
79
|
-
|
|
83
|
+
version : str, optional
|
|
80
84
|
Version of EDB to use. The default is ``"2021.2"``.
|
|
81
85
|
isaedtowned : bool, optional
|
|
82
86
|
Whether to launch EDB from HFSS 3D Layout. The
|
|
@@ -85,10 +89,20 @@ def Edb(
|
|
|
85
89
|
Reference to the AEDT project object.
|
|
86
90
|
student_version : bool, optional
|
|
87
91
|
Whether to open the AEDT student version. The default is ``False.``
|
|
92
|
+
use_ppe : bool, optional
|
|
93
|
+
Whether to use PPE license. The default is ``False``.
|
|
88
94
|
technology_file : str, optional
|
|
89
95
|
Full path to technology file to be converted to xml before importing or xml. Supported by GDS format only.
|
|
90
96
|
grpc : bool, optional
|
|
91
97
|
Whether to enable gRPC. Default value is ``False``.
|
|
98
|
+
layer_filter: str,optional
|
|
99
|
+
Layer filter .txt file.
|
|
100
|
+
map_file : str, optional
|
|
101
|
+
Layer map .map file.
|
|
102
|
+
control_file : str, optional
|
|
103
|
+
Path to the XML file. The default is ``None``, in which case an attempt is made to find
|
|
104
|
+
the XML file in the same directory as the board file. To succeed, the XML file and board file
|
|
105
|
+
must have the same name. Only the extension differs.
|
|
92
106
|
|
|
93
107
|
Returns
|
|
94
108
|
-------
|
|
@@ -257,38 +271,75 @@ def Edb(
|
|
|
257
271
|
>>> workflow.run()
|
|
258
272
|
|
|
259
273
|
"""
|
|
260
|
-
|
|
261
|
-
if
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
274
|
+
settings.is_student_version = student_version
|
|
275
|
+
if grpc is False and settings.edb_dll_path is not None:
|
|
276
|
+
# Check if the user specified a .dll path
|
|
277
|
+
settings.logger.info(f"Force to use .dll from {settings.edb_dll_path} defined in settings.")
|
|
278
|
+
elif version is None:
|
|
279
|
+
if settings.specified_version is not None:
|
|
280
|
+
settings.logger.info(f"Use {settings.specified_version} defined in settings.")
|
|
281
|
+
# Use the latest version
|
|
282
|
+
elif student_version:
|
|
283
|
+
if settings.LATEST_STUDENT_VERSION is None:
|
|
284
|
+
raise RuntimeWarning("AEDT is not properly installed.")
|
|
285
|
+
else:
|
|
286
|
+
settings.specified_version = settings.LATEST_STUDENT_VERSION
|
|
287
|
+
else:
|
|
288
|
+
if settings.LATEST_VERSION is None:
|
|
289
|
+
raise RuntimeWarning("AEDT is not properly installed.")
|
|
290
|
+
else:
|
|
291
|
+
settings.specified_version = settings.LATEST_VERSION
|
|
266
292
|
else:
|
|
267
|
-
|
|
293
|
+
# Version is specified
|
|
294
|
+
version = str(version)
|
|
295
|
+
if student_version:
|
|
296
|
+
if version not in settings.INSTALLED_STUDENT_VERSIONS:
|
|
297
|
+
raise RuntimeWarning(f"AEDT student version {version} is not properly installed.")
|
|
298
|
+
else:
|
|
299
|
+
settings.specified_version = version
|
|
300
|
+
else:
|
|
301
|
+
if version not in settings.INSTALLED_VERSIONS:
|
|
302
|
+
raise RuntimeWarning(f"AEDT version {version} is not properly installed.")
|
|
303
|
+
else:
|
|
304
|
+
settings.specified_version = version
|
|
268
305
|
|
|
269
|
-
# Use EDB legacy (default choice)
|
|
270
|
-
if float(version) >= 2025.2:
|
|
271
|
-
if not grpc:
|
|
272
|
-
warnings.warn(GRPC_GENERAL_WARNING, UserWarning)
|
|
273
|
-
else:
|
|
274
|
-
if grpc:
|
|
275
|
-
raise ValueError(f"gRPC flag was enabled however your ANSYS AEDT version {version} is not compatible")
|
|
276
306
|
if grpc:
|
|
307
|
+
if float(settings.specified_version) < 2025.2:
|
|
308
|
+
raise ValueError(
|
|
309
|
+
f"gRPC flag was enabled however your ANSYS AEDT version {settings.specified_version} is not compatible"
|
|
310
|
+
)
|
|
311
|
+
|
|
277
312
|
from pyedb.grpc.edb import Edb as app
|
|
313
|
+
|
|
314
|
+
return app(
|
|
315
|
+
edbpath=edbpath,
|
|
316
|
+
cellname=cellname,
|
|
317
|
+
isreadonly=isreadonly,
|
|
318
|
+
edbversion=version,
|
|
319
|
+
isaedtowned=isaedtowned,
|
|
320
|
+
oproject=oproject,
|
|
321
|
+
use_ppe=use_ppe,
|
|
322
|
+
technology_file=technology_file,
|
|
323
|
+
control_file=control_file,
|
|
324
|
+
)
|
|
278
325
|
else:
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
326
|
+
if float(settings.specified_version) >= 2025.2:
|
|
327
|
+
warnings.warn(GRPC_GENERAL_WARNING, UserWarning)
|
|
328
|
+
|
|
329
|
+
from pyedb.dotnet.edb import Edb
|
|
330
|
+
|
|
331
|
+
return Edb(
|
|
332
|
+
edbpath=edbpath,
|
|
333
|
+
cellname=cellname,
|
|
334
|
+
isreadonly=isreadonly,
|
|
335
|
+
isaedtowned=isaedtowned,
|
|
336
|
+
oproject=oproject,
|
|
337
|
+
use_ppe=use_ppe,
|
|
338
|
+
control_file=control_file,
|
|
339
|
+
map_file=map_file,
|
|
340
|
+
technology_file=technology_file,
|
|
341
|
+
layer_filter=layer_filter,
|
|
342
|
+
)
|
|
292
343
|
|
|
293
344
|
|
|
294
345
|
def Siwave(
|
pyedb/generic/filesystem.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import
|
|
2
|
+
import secrets
|
|
3
3
|
import shutil
|
|
4
4
|
import string
|
|
5
5
|
|
|
@@ -44,7 +44,10 @@ class Scratch:
|
|
|
44
44
|
self._volatile = volatile
|
|
45
45
|
self._cleaned = True
|
|
46
46
|
char_set = string.ascii_uppercase + string.digits
|
|
47
|
-
|
|
47
|
+
generator = secrets.SystemRandom()
|
|
48
|
+
self._scratch_path = os.path.normpath(
|
|
49
|
+
os.path.join(local_path, "scratch" + "".join(secrets.SystemRandom.sample(generator, char_set, 6)))
|
|
50
|
+
)
|
|
48
51
|
if os.path.exists(self._scratch_path):
|
|
49
52
|
try:
|
|
50
53
|
self.remove()
|
pyedb/generic/general_methods.py
CHANGED
|
@@ -35,15 +35,14 @@ import itertools
|
|
|
35
35
|
import logging
|
|
36
36
|
import math
|
|
37
37
|
import os
|
|
38
|
-
import random
|
|
39
38
|
import re
|
|
39
|
+
import secrets
|
|
40
40
|
import string
|
|
41
41
|
import sys
|
|
42
42
|
import tempfile
|
|
43
43
|
import time
|
|
44
44
|
import traceback
|
|
45
45
|
|
|
46
|
-
from pyedb.exceptions import MaterialModelException
|
|
47
46
|
from pyedb.generic.constants import CSS4_COLORS
|
|
48
47
|
from pyedb.generic.settings import settings
|
|
49
48
|
|
|
@@ -141,82 +140,6 @@ def _exception(ex_info, func, args, kwargs, message="Type Error"):
|
|
|
141
140
|
)
|
|
142
141
|
|
|
143
142
|
|
|
144
|
-
def _function_handler_wrapper(user_function): # pragma: no cover
|
|
145
|
-
def wrapper(*args, **kwargs): # pragma: no cover
|
|
146
|
-
if not settings.enable_error_handler:
|
|
147
|
-
result = user_function(*args, **kwargs)
|
|
148
|
-
return result
|
|
149
|
-
else:
|
|
150
|
-
try:
|
|
151
|
-
settings.time_tick = time.time()
|
|
152
|
-
out = user_function(*args, **kwargs)
|
|
153
|
-
if settings.enable_debug_logger or settings.enable_debug_edb_logger:
|
|
154
|
-
_log_method(user_function, args, kwargs)
|
|
155
|
-
return out
|
|
156
|
-
except TypeError:
|
|
157
|
-
_exception(sys.exc_info(), user_function, args, kwargs, "Type Error")
|
|
158
|
-
return False
|
|
159
|
-
except ValueError:
|
|
160
|
-
_exception(sys.exc_info(), user_function, args, kwargs, "Value Error")
|
|
161
|
-
return False
|
|
162
|
-
except AttributeError:
|
|
163
|
-
_exception(sys.exc_info(), user_function, args, kwargs, "Attribute Error")
|
|
164
|
-
return False
|
|
165
|
-
except KeyError:
|
|
166
|
-
_exception(sys.exc_info(), user_function, args, kwargs, "Key Error")
|
|
167
|
-
return False
|
|
168
|
-
except IndexError:
|
|
169
|
-
_exception(sys.exc_info(), user_function, args, kwargs, "Index Error")
|
|
170
|
-
return False
|
|
171
|
-
except AssertionError:
|
|
172
|
-
_exception(sys.exc_info(), user_function, args, kwargs, "Assertion Error")
|
|
173
|
-
return False
|
|
174
|
-
except NameError:
|
|
175
|
-
_exception(sys.exc_info(), user_function, args, kwargs, "Name Error")
|
|
176
|
-
return False
|
|
177
|
-
except IOError:
|
|
178
|
-
_exception(sys.exc_info(), user_function, args, kwargs, "IO Error")
|
|
179
|
-
return False
|
|
180
|
-
except MaterialModelException:
|
|
181
|
-
_exception(sys.exc_info(), user_function, args, kwargs, "Material Model")
|
|
182
|
-
return False
|
|
183
|
-
|
|
184
|
-
return wrapper
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
import functools
|
|
188
|
-
import warnings
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def deprecate_argument_name(argument_map):
|
|
192
|
-
"""Decorator to deprecate certain argument names in favor of new ones."""
|
|
193
|
-
|
|
194
|
-
def decorator(func):
|
|
195
|
-
"""Decorator that wraps the function to handle deprecated arguments."""
|
|
196
|
-
|
|
197
|
-
@functools.wraps(func)
|
|
198
|
-
def wrapper(*args, **kwargs):
|
|
199
|
-
"""Wrapper function that checks for deprecated arguments."""
|
|
200
|
-
func_name = func.__name__
|
|
201
|
-
for old_arg, new_arg in argument_map.items():
|
|
202
|
-
if old_arg in kwargs:
|
|
203
|
-
warnings.warn(
|
|
204
|
-
f"Argument `{old_arg}` is deprecated for method `{func_name}`; use `{new_arg}` instead.",
|
|
205
|
-
DeprecationWarning,
|
|
206
|
-
stacklevel=2,
|
|
207
|
-
)
|
|
208
|
-
# NOTE: Use old argument if new argument is not provided
|
|
209
|
-
if new_arg not in kwargs:
|
|
210
|
-
kwargs[new_arg] = kwargs.pop(old_arg)
|
|
211
|
-
else:
|
|
212
|
-
kwargs.pop(old_arg)
|
|
213
|
-
return func(*args, **kwargs)
|
|
214
|
-
|
|
215
|
-
return wrapper
|
|
216
|
-
|
|
217
|
-
return decorator
|
|
218
|
-
|
|
219
|
-
|
|
220
143
|
def get_filename_without_extension(path):
|
|
221
144
|
"""Get the filename without its extension.
|
|
222
145
|
|
|
@@ -242,49 +165,6 @@ def _write_mes(mes_text):
|
|
|
242
165
|
settings.logger.error(el)
|
|
243
166
|
|
|
244
167
|
|
|
245
|
-
def _log_method(func, new_args, new_kwargs): # pragma: no cover
|
|
246
|
-
if not settings.enable_debug_internal_methods_logger and str(func.__name__)[0] == "_":
|
|
247
|
-
return
|
|
248
|
-
if not settings.enable_debug_geometry_operator_logger and "GeometryOperators" in str(func):
|
|
249
|
-
return
|
|
250
|
-
if (
|
|
251
|
-
not settings.enable_debug_edb_logger
|
|
252
|
-
and "Edb" in str(func) + str(new_args)
|
|
253
|
-
or "database" in str(func) + str(new_args)
|
|
254
|
-
):
|
|
255
|
-
return
|
|
256
|
-
line_begin = "ARGUMENTS: "
|
|
257
|
-
message = []
|
|
258
|
-
delta = time.time() - settings.time_tick
|
|
259
|
-
m, s = divmod(delta, 60)
|
|
260
|
-
h, m = divmod(m, 60)
|
|
261
|
-
d, h = divmod(h, 24)
|
|
262
|
-
msec = (s - int(s)) * 1000
|
|
263
|
-
if d > 0:
|
|
264
|
-
time_msg = " {}days {}h {}m {}sec.".format(d, h, m, int(s))
|
|
265
|
-
elif h > 0:
|
|
266
|
-
time_msg = " {}h {}m {}sec.".format(h, m, int(s))
|
|
267
|
-
else:
|
|
268
|
-
time_msg = " {}m {}sec {}msec.".format(m, int(s), int(msec))
|
|
269
|
-
if settings.enable_debug_methods_argument_logger:
|
|
270
|
-
args_dict = _get_args_dicts(func, new_args, new_kwargs)
|
|
271
|
-
id = 0
|
|
272
|
-
if new_args:
|
|
273
|
-
object_name = str([new_args[0]])[1:-1]
|
|
274
|
-
id = object_name.find(" object at ")
|
|
275
|
-
if id > 0:
|
|
276
|
-
object_name = object_name[1:id]
|
|
277
|
-
message.append("'{}' was run in {}".format(object_name + "." + str(func.__name__), time_msg))
|
|
278
|
-
else:
|
|
279
|
-
message.append("'{}' was run in {}".format(str(func.__name__), time_msg))
|
|
280
|
-
message.append(line_begin)
|
|
281
|
-
for k, v in args_dict.items():
|
|
282
|
-
if k != "self":
|
|
283
|
-
message.append(" {} = {}".format(k, v))
|
|
284
|
-
for m in message:
|
|
285
|
-
settings.logger.debug(m)
|
|
286
|
-
|
|
287
|
-
|
|
288
168
|
def _get_args_dicts(func, args, kwargs):
|
|
289
169
|
if int(sys.version[0]) > 2:
|
|
290
170
|
args_name = list(OrderedDict.fromkeys(inspect.getfullargspec(func)[0] + list(kwargs.keys())))
|
|
@@ -374,7 +254,7 @@ def generate_unique_name(rootname, suffix="", n=6):
|
|
|
374
254
|
|
|
375
255
|
"""
|
|
376
256
|
char_set = string.ascii_uppercase + string.digits
|
|
377
|
-
uName = "".join(
|
|
257
|
+
uName = "".join(secrets.choice(char_set) for _ in range(n))
|
|
378
258
|
unique_name = rootname + "_" + uName
|
|
379
259
|
if suffix:
|
|
380
260
|
unique_name += "_" + suffix
|
pyedb/generic/process.py
CHANGED
|
@@ -1,104 +1,51 @@
|
|
|
1
1
|
import os.path
|
|
2
|
+
from pathlib import Path
|
|
2
3
|
import subprocess
|
|
3
4
|
|
|
4
|
-
from pyedb.generic.general_methods import
|
|
5
|
+
from pyedb.generic.general_methods import is_linux
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class SiwaveSolve(object):
|
|
8
|
-
def __init__(self,
|
|
9
|
-
self.
|
|
10
|
-
self._exec_path = ""
|
|
11
|
-
self._nbcores = 4
|
|
12
|
-
self._ng = True
|
|
13
|
-
if aedt_installer_path:
|
|
14
|
-
self.installer_path = aedt_installer_path
|
|
15
|
-
else:
|
|
16
|
-
try:
|
|
17
|
-
self.installer_path = env_path(aedt_version)
|
|
18
|
-
except:
|
|
19
|
-
raise Exception("Either a valid aedt version or full path has to be provided")
|
|
20
|
-
if self._ng:
|
|
21
|
-
executable = "siwave_ng"
|
|
22
|
-
else:
|
|
23
|
-
executable = "siwave"
|
|
24
|
-
if is_linux:
|
|
25
|
-
self._exe = os.path.join(self.installer_path, executable)
|
|
26
|
-
else:
|
|
27
|
-
self._exe = os.path.join(self.installer_path, executable + ".exe")
|
|
9
|
+
def __init__(self, pedb):
|
|
10
|
+
self._pedb = pedb
|
|
28
11
|
|
|
29
12
|
@property
|
|
30
|
-
def
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
self._exe = value
|
|
36
|
-
|
|
37
|
-
@property
|
|
38
|
-
def projectpath(self):
|
|
39
|
-
return self._project_path
|
|
40
|
-
|
|
41
|
-
@projectpath.setter
|
|
42
|
-
def projectpath(self, value):
|
|
43
|
-
self._project_path = value
|
|
13
|
+
def __siwave_exe_path(self):
|
|
14
|
+
executable = "siwave"
|
|
15
|
+
executable = executable if is_linux else executable + ".exe"
|
|
16
|
+
full_path = Path(self._pedb.ansys_em_path) / executable
|
|
17
|
+
return str(full_path)
|
|
44
18
|
|
|
45
19
|
@property
|
|
46
|
-
def
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
self.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if is_linux:
|
|
73
|
-
exe_path = os.path.join(self.installer_path, "siwave_ng")
|
|
74
|
-
else:
|
|
75
|
-
exe_path = os.path.join(self.installer_path, "siwave_ng.exe")
|
|
76
|
-
exec_file = os.path.splitext(self._project_path)[0] + ".exec"
|
|
77
|
-
if os.path.exists(exec_file):
|
|
78
|
-
with open(exec_file, "r+") as f:
|
|
79
|
-
content = f.readlines()
|
|
80
|
-
if "SetNumCpus" not in content:
|
|
81
|
-
f.writelines(str.format("SetNumCpus {}", str(self.nbcores)) + "\n")
|
|
82
|
-
f.writelines("SaveSiw")
|
|
83
|
-
else:
|
|
84
|
-
fstarts = [i for i in range(len(content)) if content[i].startswith("SetNumCpus")]
|
|
85
|
-
content[fstarts[0]] = str.format("SetNumCpus {}", str(self.nbcores))
|
|
86
|
-
f.close()
|
|
87
|
-
os.remove(exec_file)
|
|
88
|
-
f = open(exec_file, "w")
|
|
89
|
-
f.writelines(content)
|
|
90
|
-
command = [exe_path]
|
|
91
|
-
command.append(self._project_path)
|
|
92
|
-
command.append(exec_file)
|
|
93
|
-
command.append("-formatOutput -useSubdir")
|
|
94
|
-
if os.name == "posix":
|
|
95
|
-
p = subprocess.Popen(command)
|
|
96
|
-
else:
|
|
97
|
-
p = subprocess.Popen(" ".join(command))
|
|
98
|
-
p.wait()
|
|
20
|
+
def __siwave_ng_exe_path(self):
|
|
21
|
+
executable = "siwave_ng"
|
|
22
|
+
executable = executable if is_linux else executable + ".exe"
|
|
23
|
+
full_path = Path(self._pedb.ansys_em_path) / executable
|
|
24
|
+
return str(full_path)
|
|
25
|
+
|
|
26
|
+
def solve(self, num_of_cores=4):
|
|
27
|
+
exec_file = os.path.splitext(self._pedb.edbpath)[0] + ".exec"
|
|
28
|
+
if os.path.exists(exec_file):
|
|
29
|
+
with open(exec_file, "r+") as f:
|
|
30
|
+
content = f.readlines()
|
|
31
|
+
if "SetNumCpus" not in content:
|
|
32
|
+
f.writelines(str.format("SetNumCpus {}", str(num_of_cores)) + "\n")
|
|
33
|
+
f.writelines("SaveSiw")
|
|
34
|
+
else:
|
|
35
|
+
fstarts = [i for i in range(len(content)) if content[i].startswith("SetNumCpus")]
|
|
36
|
+
content[fstarts[0]] = str.format("SetNumCpus {}", str(num_of_cores))
|
|
37
|
+
f.close()
|
|
38
|
+
os.remove(exec_file)
|
|
39
|
+
f = open(exec_file, "w")
|
|
40
|
+
f.writelines(content)
|
|
41
|
+
command = [self.__siwave_ng_exe_path, self._pedb.edbpath, exec_file, "-formatOutput -useSubdir"]
|
|
42
|
+
command_ = command if os.name == "posix" else " ".join(command)
|
|
43
|
+
# p = subprocess.Popen(command_)
|
|
44
|
+
p = subprocess.Popen(command)
|
|
45
|
+
p.wait()
|
|
99
46
|
|
|
100
47
|
def export_3d_cad(
|
|
101
|
-
self, format_3d="Q3D", output_folder=None, net_list=None, num_cores=
|
|
48
|
+
self, format_3d="Q3D", output_folder=None, net_list=None, num_cores=4, aedt_file_name=None, hidden=False
|
|
102
49
|
): # pragma: no cover
|
|
103
50
|
"""Export edb to Q3D or HFSS
|
|
104
51
|
|
|
@@ -119,11 +66,11 @@ class SiwaveSolve(object):
|
|
|
119
66
|
path to aedt file
|
|
120
67
|
"""
|
|
121
68
|
if not output_folder:
|
|
122
|
-
output_folder = os.path.dirname(self.
|
|
69
|
+
output_folder = os.path.dirname(self._pedb.edbpath)
|
|
123
70
|
scriptname = os.path.join(output_folder, "export_cad.py")
|
|
124
71
|
with open(scriptname, "w") as f:
|
|
125
72
|
f.write("import os\n")
|
|
126
|
-
f.write("edbpath = r'{}'\n".format(self.
|
|
73
|
+
f.write("edbpath = r'{}'\n".format(self._pedb.edbpath))
|
|
127
74
|
f.write("exportOptions = os.path.join(r'{}', 'options.config')\n".format(output_folder))
|
|
128
75
|
f.write("oDoc.ScrImportEDB(edbpath)\n")
|
|
129
76
|
f.write("oDoc.ScrSaveProjectAs(os.path.join(r'{}','{}'))\n".format(output_folder, "test.siw"))
|
|
@@ -140,14 +87,11 @@ class SiwaveSolve(object):
|
|
|
140
87
|
f.write("q3d_filename = os.path.join(r'{}', '{}')\n".format(output_folder, aedt_file_name))
|
|
141
88
|
if num_cores:
|
|
142
89
|
f.write("oDoc.ScrSetNumCpusToUse('{}')\n".format(num_cores))
|
|
143
|
-
self.nbcores = num_cores
|
|
144
90
|
f.write("oDoc.ScrExport3DModel('{}', q3d_filename)\n".format(format_3d))
|
|
145
91
|
f.write("oDoc.ScrCloseProject()\n")
|
|
146
92
|
f.write("oApp.Quit()\n")
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
_exe += ".exe"
|
|
150
|
-
command = [_exe]
|
|
93
|
+
|
|
94
|
+
command = [self.__siwave_exe_path]
|
|
151
95
|
if hidden:
|
|
152
96
|
command.append("-embedding")
|
|
153
97
|
command += ["-RunScriptAndExit", scriptname]
|
|
@@ -204,7 +148,7 @@ class SiwaveSolve(object):
|
|
|
204
148
|
list of files generated.
|
|
205
149
|
"""
|
|
206
150
|
if not output_folder:
|
|
207
|
-
output_folder = os.path.dirname(self.
|
|
151
|
+
output_folder = os.path.dirname(self._pedb.edbpath)
|
|
208
152
|
output_list = []
|
|
209
153
|
scriptname = os.path.normpath(os.path.join(os.path.normpath(output_folder), "export_results.py"))
|
|
210
154
|
with open(scriptname, "w") as f:
|
|
@@ -265,20 +209,12 @@ class SiwaveSolve(object):
|
|
|
265
209
|
f.write("proj.ScrCloseProject()\n")
|
|
266
210
|
|
|
267
211
|
f.write("oApp.Quit()\n")
|
|
268
|
-
|
|
269
|
-
_exe = '"' + os.path.join(self.installer_path, "siwave") + '"'
|
|
270
|
-
else:
|
|
271
|
-
_exe = '"' + os.path.join(self.installer_path, "siwave.exe") + '"'
|
|
272
|
-
command = [_exe]
|
|
212
|
+
command = [self.__siwave_exe_path]
|
|
273
213
|
if hidden:
|
|
274
214
|
command.append("-embedding")
|
|
275
215
|
command.append("-RunScriptAndExit")
|
|
276
|
-
command.append(
|
|
216
|
+
command.append(scriptname)
|
|
277
217
|
print(command)
|
|
278
|
-
|
|
279
|
-
p = subprocess.Popen(command)
|
|
280
|
-
|
|
281
|
-
else:
|
|
282
|
-
p = subprocess.Popen(" ".join(command))
|
|
218
|
+
p = subprocess.Popen(command)
|
|
283
219
|
p.wait()
|
|
284
220
|
return output_list
|
pyedb/generic/settings.py
CHANGED
|
@@ -21,12 +21,25 @@
|
|
|
21
21
|
# SOFTWARE.
|
|
22
22
|
|
|
23
23
|
import os
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
import re
|
|
26
|
+
import sys
|
|
24
27
|
import time
|
|
28
|
+
import warnings
|
|
25
29
|
|
|
26
30
|
|
|
27
31
|
class Settings(object):
|
|
28
32
|
"""Manages all PyEDB environment variables and global settings."""
|
|
29
33
|
|
|
34
|
+
INSTALLED_VERSIONS = None
|
|
35
|
+
INSTALLED_STUDENT_VERSIONS = None
|
|
36
|
+
INSTALLED_CLIENT_VERSIONS = None
|
|
37
|
+
LATEST_VERSION = None
|
|
38
|
+
LATEST_STUDENT_VERSION = None
|
|
39
|
+
|
|
40
|
+
specified_version = None
|
|
41
|
+
is_student_version = False
|
|
42
|
+
|
|
30
43
|
def __init__(self):
|
|
31
44
|
self.remote_rpc_session = False
|
|
32
45
|
self._enable_screen_logs = True
|
|
@@ -58,26 +71,12 @@ class Settings(object):
|
|
|
58
71
|
self._global_log_file_size = 10
|
|
59
72
|
self._lsf_queue = None
|
|
60
73
|
self._edb_environment_variables = {}
|
|
61
|
-
self.
|
|
62
|
-
self.
|
|
63
|
-
|
|
64
|
-
@property
|
|
65
|
-
def logger(self):
|
|
66
|
-
"""Active logger."""
|
|
67
|
-
return self._logger
|
|
68
|
-
|
|
69
|
-
@logger.setter
|
|
70
|
-
def logger(self, val):
|
|
71
|
-
self._logger = val
|
|
74
|
+
self.logger = None
|
|
75
|
+
self.log_file = None
|
|
76
|
+
self._aedt_version = None
|
|
72
77
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"""Flag that disable Edb log when PyAEDT is used."""
|
|
76
|
-
return self._use_pyaedt_log
|
|
77
|
-
|
|
78
|
-
@use_pyaedt_log.setter
|
|
79
|
-
def use_pyaedt_log(self, value):
|
|
80
|
-
self._use_pyaedt_log = value
|
|
78
|
+
self.__get_version_information()
|
|
79
|
+
self.__init_logger()
|
|
81
80
|
|
|
82
81
|
@property
|
|
83
82
|
def edb_environment_variables(self):
|
|
@@ -250,6 +249,9 @@ class Settings(object):
|
|
|
250
249
|
@edb_dll_path.setter
|
|
251
250
|
def edb_dll_path(self, value):
|
|
252
251
|
if os.path.exists(value):
|
|
252
|
+
ver = Path(value).parts[-2]
|
|
253
|
+
version, release = ver[-3:-1], ver[-1]
|
|
254
|
+
self.specified_version = f"20{version}.{release}"
|
|
253
255
|
self._edb_dll_path = value
|
|
254
256
|
|
|
255
257
|
@property
|
|
@@ -261,5 +263,63 @@ class Settings(object):
|
|
|
261
263
|
def retry_n_times_time_interval(self, value):
|
|
262
264
|
self._retry_n_times_time_interval = float(value)
|
|
263
265
|
|
|
266
|
+
def __get_version_information(self):
|
|
267
|
+
"""Get the installed AEDT versions.
|
|
268
|
+
|
|
269
|
+
This method returns a dictionary, with the version as the key and the installation path
|
|
270
|
+
as the value."""
|
|
271
|
+
version_pattern = re.compile(r"^(ANSYSEM_ROOT|ANSYSEM_PY_CLIENT_ROOT|ANSYSEMSV_ROOT)\d{3}$")
|
|
272
|
+
env_list = sorted([x for x in os.environ if version_pattern.match(x)], reverse=True)
|
|
273
|
+
if not env_list: # pragma: no cover
|
|
274
|
+
warnings.warn("No installed versions of AEDT are found in the system environment variables.")
|
|
275
|
+
return
|
|
276
|
+
|
|
277
|
+
aedt_system_env_variables = {i: os.environ[i] for i in env_list}
|
|
278
|
+
|
|
279
|
+
standard_versions = {}
|
|
280
|
+
client_versions = {}
|
|
281
|
+
student_versions = {}
|
|
282
|
+
# version_list is ordered: first normal versions, then client versions, finally student versions
|
|
283
|
+
for var_name, aedt_path in aedt_system_env_variables.items():
|
|
284
|
+
version_id = var_name[-3:]
|
|
285
|
+
version, release = version_id[0:2], version_id[2]
|
|
286
|
+
version_name = f"20{version}.{release}"
|
|
287
|
+
if "ANSYSEM_ROOT" in var_name:
|
|
288
|
+
standard_versions[version_name] = aedt_path
|
|
289
|
+
elif "ANSYSEM_PY_CLIENT_ROOT" in var_name:
|
|
290
|
+
client_versions[version_name] = aedt_path
|
|
291
|
+
else:
|
|
292
|
+
student_versions[version_name] = aedt_path
|
|
293
|
+
self.INSTALLED_VERSIONS = standard_versions
|
|
294
|
+
self.INSTALLED_STUDENT_VERSIONS = student_versions
|
|
295
|
+
self.INSTALLED_CLIENT_VERSIONS = client_versions
|
|
296
|
+
|
|
297
|
+
if len(self.INSTALLED_VERSIONS):
|
|
298
|
+
self.LATEST_VERSION = max(standard_versions.keys(), key=lambda x: tuple(map(int, x.split("."))))
|
|
299
|
+
if len(self.INSTALLED_STUDENT_VERSIONS):
|
|
300
|
+
self.LATEST_STUDENT_VERSION = max(student_versions.keys(), key=lambda x: tuple(map(int, x.split("."))))
|
|
301
|
+
|
|
302
|
+
@property
|
|
303
|
+
def aedt_installation_path(self):
|
|
304
|
+
if self.edb_dll_path:
|
|
305
|
+
return self.edb_dll_path
|
|
306
|
+
elif self.is_student_version:
|
|
307
|
+
return self.INSTALLED_STUDENT_VERSIONS[self.specified_version]
|
|
308
|
+
elif self.specified_version in self.INSTALLED_VERSIONS.keys():
|
|
309
|
+
return self.INSTALLED_VERSIONS[self.specified_version]
|
|
310
|
+
elif os.name == "posix":
|
|
311
|
+
main = sys.modules["__main__"]
|
|
312
|
+
if "oDesktop" in dir(main):
|
|
313
|
+
return main.oDesktop.GetExeDir()
|
|
314
|
+
else:
|
|
315
|
+
raise RuntimeError(f"Version {self.specified_version} is not installed on the system. ")
|
|
316
|
+
else:
|
|
317
|
+
raise RuntimeError(f"Version {self.specified_version} is not installed on the system. ")
|
|
318
|
+
|
|
319
|
+
def __init_logger(self):
|
|
320
|
+
from pyedb.edb_logger import EdbLogger
|
|
321
|
+
|
|
322
|
+
self.logger = EdbLogger(to_stdout=self.enable_screen_logs, settings=self)
|
|
323
|
+
|
|
264
324
|
|
|
265
325
|
settings = Settings()
|