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.

Files changed (105) hide show
  1. pyedb/__init__.py +1 -8
  2. pyedb/configuration/cfg_boundaries.py +69 -151
  3. pyedb/configuration/cfg_components.py +201 -460
  4. pyedb/configuration/cfg_data.py +4 -2
  5. pyedb/configuration/cfg_general.py +13 -36
  6. pyedb/configuration/cfg_modeler.py +2 -1
  7. pyedb/configuration/cfg_nets.py +21 -35
  8. pyedb/configuration/cfg_operations.py +22 -151
  9. pyedb/configuration/cfg_package_definition.py +56 -112
  10. pyedb/configuration/cfg_padstacks.py +292 -688
  11. pyedb/configuration/cfg_pin_groups.py +32 -79
  12. pyedb/configuration/cfg_ports_sources.py +19 -6
  13. pyedb/configuration/cfg_s_parameter_models.py +67 -172
  14. pyedb/configuration/cfg_setup.py +102 -295
  15. pyedb/configuration/configuration.py +64 -5
  16. pyedb/dotnet/database/Variables.py +26 -19
  17. pyedb/dotnet/database/cell/connectable.py +38 -9
  18. pyedb/dotnet/database/cell/hierarchy/component.py +28 -28
  19. pyedb/dotnet/database/cell/hierarchy/model.py +1 -1
  20. pyedb/dotnet/database/cell/layout.py +63 -2
  21. pyedb/dotnet/database/cell/layout_obj.py +2 -2
  22. pyedb/dotnet/database/cell/primitive/path.py +6 -8
  23. pyedb/dotnet/database/cell/primitive/primitive.py +3 -24
  24. pyedb/dotnet/database/cell/terminal/edge_terminal.py +2 -2
  25. pyedb/dotnet/database/cell/terminal/padstack_instance_terminal.py +1 -1
  26. pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
  27. pyedb/dotnet/database/cell/terminal/point_terminal.py +1 -1
  28. pyedb/dotnet/database/cell/terminal/terminal.py +24 -24
  29. pyedb/dotnet/database/cell/voltage_regulator.py +0 -21
  30. pyedb/dotnet/database/components.py +137 -124
  31. pyedb/dotnet/database/definition/component_def.py +4 -4
  32. pyedb/dotnet/database/definition/component_model.py +1 -1
  33. pyedb/dotnet/database/definition/package_def.py +2 -3
  34. pyedb/dotnet/database/dotnet/database.py +3 -199
  35. pyedb/dotnet/database/dotnet/primitive.py +3 -3
  36. pyedb/dotnet/database/edb_data/control_file.py +5 -5
  37. pyedb/dotnet/database/edb_data/hfss_extent_info.py +6 -6
  38. pyedb/dotnet/database/edb_data/layer_data.py +23 -23
  39. pyedb/dotnet/database/edb_data/padstacks_data.py +63 -88
  40. pyedb/dotnet/database/edb_data/primitives_data.py +5 -5
  41. pyedb/dotnet/database/edb_data/sources.py +6 -6
  42. pyedb/dotnet/database/edb_data/variables.py +1 -1
  43. pyedb/dotnet/database/geometry/point_data.py +14 -10
  44. pyedb/dotnet/database/geometry/polygon_data.py +3 -3
  45. pyedb/dotnet/database/hfss.py +46 -48
  46. pyedb/dotnet/database/layout_validation.py +14 -11
  47. pyedb/dotnet/database/materials.py +10 -11
  48. pyedb/dotnet/database/modeler.py +97 -91
  49. pyedb/dotnet/database/nets.py +19 -22
  50. pyedb/dotnet/database/padstack.py +171 -83
  51. pyedb/dotnet/database/siwave.py +42 -42
  52. pyedb/dotnet/database/stackup.py +140 -72
  53. pyedb/dotnet/database/utilities/heatsink.py +4 -4
  54. pyedb/dotnet/database/utilities/obj_base.py +2 -2
  55. pyedb/dotnet/database/utilities/simulation_setup.py +2 -2
  56. pyedb/dotnet/database/utilities/value.py +16 -16
  57. pyedb/dotnet/edb.py +230 -152
  58. pyedb/edb_logger.py +12 -27
  59. pyedb/extensions/create_cell_array.py +394 -0
  60. pyedb/extensions/via_design_backend.py +6 -3
  61. pyedb/generic/data_handlers.py +6 -7
  62. pyedb/generic/design_types.py +81 -30
  63. pyedb/generic/filesystem.py +5 -2
  64. pyedb/generic/general_methods.py +2 -122
  65. pyedb/generic/process.py +44 -108
  66. pyedb/generic/settings.py +79 -19
  67. pyedb/grpc/database/components.py +26 -4
  68. pyedb/grpc/database/control_file.py +5 -5
  69. pyedb/grpc/database/definition/materials.py +1 -1
  70. pyedb/grpc/database/definition/package_def.py +3 -3
  71. pyedb/grpc/database/definition/padstack_def.py +53 -0
  72. pyedb/grpc/database/geometry/polygon_data.py +1 -1
  73. pyedb/grpc/database/layout/layout.py +81 -5
  74. pyedb/grpc/database/layout_validation.py +5 -5
  75. pyedb/grpc/database/modeler.py +24 -16
  76. pyedb/grpc/database/net/net.py +15 -14
  77. pyedb/grpc/database/nets.py +70 -0
  78. pyedb/grpc/database/padstacks.py +122 -17
  79. pyedb/grpc/database/primitive/padstack_instance.py +175 -7
  80. pyedb/grpc/database/primitive/polygon.py +2 -2
  81. pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +3 -2
  82. pyedb/grpc/database/siwave.py +1 -1
  83. pyedb/grpc/database/source_excitations.py +12 -5
  84. pyedb/grpc/database/stackup.py +1 -1
  85. pyedb/grpc/database/terminal/bundle_terminal.py +1 -1
  86. pyedb/grpc/database/terminal/padstack_instance_terminal.py +1 -1
  87. pyedb/grpc/database/terminal/pingroup_terminal.py +1 -1
  88. pyedb/grpc/database/utility/value.py +1 -0
  89. pyedb/grpc/database/utility/xml_control_file.py +5 -5
  90. pyedb/grpc/edb.py +80 -30
  91. pyedb/grpc/edb_init.py +3 -3
  92. pyedb/grpc/rpc_session.py +14 -13
  93. pyedb/libraries/common.py +366 -0
  94. pyedb/libraries/rf_libraries/base_functions.py +1358 -0
  95. pyedb/libraries/rf_libraries/planar_antennas.py +628 -0
  96. pyedb/misc/decorators.py +61 -0
  97. pyedb/misc/misc.py +0 -13
  98. pyedb/modeler/geometry_operators.py +6 -6
  99. pyedb/siwave.py +6 -8
  100. pyedb/siwave_core/__init__.py +0 -0
  101. pyedb/siwave_core/cpa/__init__.py +0 -0
  102. {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/METADATA +1 -2
  103. {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/RECORD +105 -98
  104. {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/WHEEL +0 -0
  105. {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/licenses/LICENSE +0 -0
@@ -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.misc.misc import list_installed_ansysem
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
- edbversion=None,
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
- edbversion : str, optional
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 not edbversion: # pragma: no cover
262
- try:
263
- version = "20{}.{}".format(list_installed_ansysem()[0][-3:-1], list_installed_ansysem()[0][-1:])
264
- except IndexError:
265
- raise Exception("No ANSYSEM_ROOTxxx is found.")
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
- version = edbversion
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
- from pyedb.dotnet.edb import Edb as app
280
- return app(
281
- edbpath=edbpath,
282
- cellname=cellname,
283
- isreadonly=isreadonly,
284
- edbversion=version,
285
- isaedtowned=isaedtowned,
286
- oproject=oproject,
287
- student_version=student_version,
288
- use_ppe=use_ppe,
289
- technology_file=technology_file,
290
- control_file=control_file,
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(
@@ -1,5 +1,5 @@
1
1
  import os
2
- import random
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
- self._scratch_path = os.path.normpath(os.path.join(local_path, "scratch" + "".join(random.sample(char_set, 6))))
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()
@@ -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(random.choice(char_set) for _ in range(n))
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 env_path, is_linux, is_windows
5
+ from pyedb.generic.general_methods import is_linux
5
6
 
6
7
 
7
8
  class SiwaveSolve(object):
8
- def __init__(self, aedb_path="", aedt_version="2021.2", aedt_installer_path=None):
9
- self._project_path = aedb_path
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 siwave_exe(self):
31
- return self._exe
32
-
33
- @siwave_exe.setter
34
- def siwave_exe(self, value):
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 execfile(self):
47
- return self._exec_path
48
-
49
- @execfile.setter
50
- def execfile(self, value):
51
- self._exec_path = value
52
-
53
- @property
54
- def nbcores(self):
55
- return self._nbcores
56
-
57
- @nbcores.setter
58
- def nbcores(self, value):
59
- self._nbcores = value
60
-
61
- @property
62
- def nongraphical(self):
63
- return self._ng
64
-
65
- @nongraphical.setter
66
- def nongraphical(self, value):
67
- self._ng = value
68
-
69
- def solve(self):
70
- # supporting non graphical solve only
71
- if self.nongraphical:
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=None, aedt_file_name=None, hidden=False
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.projectpath)
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.projectpath))
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
- _exe = os.path.join(self.installer_path, "siwave")
148
- if is_windows:
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.projectpath)
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
- if is_linux:
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('"' + scriptname + '"')
216
+ command.append(scriptname)
277
217
  print(command)
278
- if os.name == "posix":
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._use_pyaedt_log = False
62
- self._logger = None
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
- @property
74
- def use_pyaedt_log(self):
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()