pyedb 0.53.0__py3-none-any.whl → 0.55.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 +20 -9
- pyedb/configuration/cfg_s_parameter_models.py +67 -172
- pyedb/configuration/cfg_setup.py +102 -295
- pyedb/configuration/configuration.py +66 -6
- 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 +64 -3
- pyedb/dotnet/database/cell/layout_obj.py +3 -3
- pyedb/dotnet/database/cell/primitive/path.py +6 -8
- pyedb/dotnet/database/cell/primitive/primitive.py +10 -31
- 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 +26 -28
- pyedb/dotnet/database/cell/voltage_regulator.py +0 -21
- pyedb/dotnet/database/components.py +99 -91
- 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 +27 -218
- pyedb/dotnet/database/dotnet/primitive.py +16 -16
- 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 +35 -35
- pyedb/dotnet/database/edb_data/padstacks_data.py +65 -90
- 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 +8 -4
- pyedb/dotnet/database/geometry/point_data.py +14 -10
- pyedb/dotnet/database/geometry/polygon_data.py +3 -5
- pyedb/dotnet/database/hfss.py +50 -52
- pyedb/dotnet/database/layout_validation.py +14 -11
- pyedb/dotnet/database/materials.py +10 -11
- pyedb/dotnet/database/modeler.py +104 -101
- pyedb/dotnet/database/nets.py +20 -23
- pyedb/dotnet/database/padstack.py +156 -84
- pyedb/dotnet/database/sim_setup_data/data/settings.py +24 -0
- pyedb/dotnet/database/sim_setup_data/io/siwave.py +26 -1
- pyedb/dotnet/database/siwave.py +47 -47
- pyedb/dotnet/database/stackup.py +152 -87
- pyedb/dotnet/database/utilities/heatsink.py +4 -4
- pyedb/dotnet/database/utilities/obj_base.py +3 -3
- pyedb/dotnet/database/utilities/simulation_setup.py +2 -2
- pyedb/dotnet/database/utilities/value.py +116 -0
- pyedb/dotnet/edb.py +248 -170
- pyedb/edb_logger.py +12 -27
- pyedb/extensions/via_design_backend.py +6 -3
- pyedb/generic/design_types.py +68 -21
- pyedb/generic/general_methods.py +0 -120
- pyedb/generic/process.py +44 -108
- pyedb/generic/settings.py +75 -19
- pyedb/grpc/__init__.py +0 -0
- pyedb/grpc/database/components.py +55 -17
- pyedb/grpc/database/control_file.py +5 -5
- pyedb/grpc/database/definition/materials.py +24 -31
- pyedb/grpc/database/definition/package_def.py +18 -18
- pyedb/grpc/database/definition/padstack_def.py +104 -51
- pyedb/grpc/database/geometry/arc_data.py +7 -5
- pyedb/grpc/database/geometry/point_3d_data.py +8 -7
- pyedb/grpc/database/geometry/polygon_data.py +4 -3
- pyedb/grpc/database/hierarchy/component.py +43 -38
- pyedb/grpc/database/hierarchy/pin_pair_model.py +15 -14
- pyedb/grpc/database/hierarchy/pingroup.py +9 -9
- pyedb/grpc/database/layers/stackup_layer.py +45 -44
- pyedb/grpc/database/layout/layout.py +17 -13
- pyedb/grpc/database/layout/voltage_regulator.py +7 -7
- pyedb/grpc/database/layout_validation.py +16 -15
- pyedb/grpc/database/modeler.py +60 -58
- pyedb/grpc/database/net/net.py +15 -14
- pyedb/grpc/database/nets.py +112 -31
- pyedb/grpc/database/padstacks.py +303 -190
- pyedb/grpc/database/ports/ports.py +5 -6
- pyedb/grpc/database/primitive/bondwire.py +8 -7
- pyedb/grpc/database/primitive/circle.py +4 -4
- pyedb/grpc/database/primitive/padstack_instance.py +191 -23
- pyedb/grpc/database/primitive/path.py +7 -7
- pyedb/grpc/database/primitive/polygon.py +3 -3
- pyedb/grpc/database/primitive/primitive.py +13 -17
- pyedb/grpc/database/primitive/rectangle.py +13 -13
- pyedb/grpc/database/simulation_setup/hfss_general_settings.py +1 -1
- pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +10 -0
- pyedb/grpc/database/simulation_setup/siwave_simulation_setup.py +17 -1
- pyedb/grpc/database/siwave.py +31 -25
- pyedb/grpc/database/source_excitations.py +335 -233
- pyedb/grpc/database/stackup.py +165 -148
- pyedb/grpc/database/terminal/bundle_terminal.py +18 -8
- pyedb/grpc/database/terminal/edge_terminal.py +10 -0
- pyedb/grpc/database/terminal/padstack_instance_terminal.py +16 -5
- pyedb/grpc/database/terminal/pingroup_terminal.py +12 -11
- pyedb/grpc/database/terminal/point_terminal.py +4 -3
- pyedb/grpc/database/terminal/terminal.py +9 -9
- pyedb/grpc/database/utility/value.py +109 -0
- pyedb/grpc/database/utility/xml_control_file.py +5 -5
- pyedb/grpc/edb.py +130 -63
- pyedb/grpc/edb_init.py +3 -10
- pyedb/grpc/rpc_session.py +10 -10
- 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/siwave.py +2 -2
- {pyedb-0.53.0.dist-info → pyedb-0.55.0.dist-info}/METADATA +2 -3
- {pyedb-0.53.0.dist-info → pyedb-0.55.0.dist-info}/RECORD +119 -112
- {pyedb-0.53.0.dist-info → pyedb-0.55.0.dist-info}/WHEEL +0 -0
- {pyedb-0.53.0.dist-info → pyedb-0.55.0.dist-info}/licenses/LICENSE +0 -0
pyedb/dotnet/edb.py
CHANGED
|
@@ -48,7 +48,6 @@ from pyedb.dotnet.database.cell.layout import Layout
|
|
|
48
48
|
from pyedb.dotnet.database.cell.terminal.terminal import Terminal
|
|
49
49
|
from pyedb.dotnet.database.components import Components
|
|
50
50
|
import pyedb.dotnet.database.dotnet.database
|
|
51
|
-
from pyedb.dotnet.database.dotnet.database import Database
|
|
52
51
|
from pyedb.dotnet.database.edb_data.design_options import EdbDesignOptions
|
|
53
52
|
from pyedb.dotnet.database.edb_data.ports import (
|
|
54
53
|
BundleWavePort,
|
|
@@ -92,23 +91,19 @@ from pyedb.dotnet.database.utilities.siwave_simulation_setup import (
|
|
|
92
91
|
SiwaveDCSimulationSetup,
|
|
93
92
|
SiwaveSimulationSetup,
|
|
94
93
|
)
|
|
95
|
-
from pyedb.
|
|
94
|
+
from pyedb.dotnet.database.utilities.value import Value
|
|
96
95
|
from pyedb.generic.constants import AEDT_UNITS, SolverType, unit_converter
|
|
97
|
-
from pyedb.generic.general_methods import
|
|
98
|
-
generate_unique_name,
|
|
99
|
-
get_string_version,
|
|
100
|
-
is_linux,
|
|
101
|
-
is_windows,
|
|
102
|
-
)
|
|
96
|
+
from pyedb.generic.general_methods import generate_unique_name, is_linux, is_windows
|
|
103
97
|
from pyedb.generic.process import SiwaveSolve
|
|
104
98
|
from pyedb.generic.settings import settings
|
|
105
99
|
from pyedb.ipc2581.ipc2581 import Ipc2581
|
|
100
|
+
from pyedb.misc.decorators import execution_timer
|
|
106
101
|
from pyedb.modeler.geometry_operators import GeometryOperators
|
|
107
102
|
from pyedb.siwave_core.product_properties import SIwaveProperties
|
|
108
103
|
from pyedb.workflow import Workflow
|
|
109
104
|
|
|
110
105
|
|
|
111
|
-
class Edb
|
|
106
|
+
class Edb:
|
|
112
107
|
"""Provides the EDB application interface.
|
|
113
108
|
|
|
114
109
|
This module inherits all objects that belong to EDB.
|
|
@@ -126,7 +121,7 @@ class Edb(Database):
|
|
|
126
121
|
isreadonly : bool, optional
|
|
127
122
|
Whether to open EBD in read-only mode when it is
|
|
128
123
|
owned by HFSS 3D Layout. The default is ``False``.
|
|
129
|
-
|
|
124
|
+
version : str, int, float, optional
|
|
130
125
|
Version of EDB to use. The default is ``None``.
|
|
131
126
|
Examples of input values are ``232``, ``23.2``, ``2023.2``, ``"2023.2"``.
|
|
132
127
|
isaedtowned : bool, optional
|
|
@@ -182,15 +177,28 @@ class Edb(Database):
|
|
|
182
177
|
|
|
183
178
|
"""
|
|
184
179
|
|
|
180
|
+
_db = None
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def logger(self):
|
|
184
|
+
return settings.logger
|
|
185
|
+
|
|
186
|
+
@property
|
|
187
|
+
def version(self):
|
|
188
|
+
return settings.specified_version
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def base_path(self):
|
|
192
|
+
return settings.aedt_installation_path
|
|
193
|
+
|
|
194
|
+
@execution_timer("EDB initialization")
|
|
185
195
|
def __init__(
|
|
186
196
|
self,
|
|
187
197
|
edbpath: Union[str, Path] = None,
|
|
188
198
|
cellname: str = None,
|
|
189
199
|
isreadonly: bool = False,
|
|
190
|
-
edbversion: str = None,
|
|
191
200
|
isaedtowned: bool = False,
|
|
192
201
|
oproject=None,
|
|
193
|
-
student_version: bool = False,
|
|
194
202
|
use_ppe: bool = False,
|
|
195
203
|
control_file: str = None,
|
|
196
204
|
map_file: str = None,
|
|
@@ -198,16 +206,15 @@ class Edb(Database):
|
|
|
198
206
|
layer_filter: str = None,
|
|
199
207
|
remove_existing_aedt: bool = False,
|
|
200
208
|
):
|
|
201
|
-
self._logger = pyedb_logger
|
|
202
209
|
now = datetime.now()
|
|
203
210
|
self.logger.info(f"Star initializing Edb {now.time()}")
|
|
204
211
|
|
|
205
212
|
if isinstance(edbpath, Path):
|
|
206
213
|
edbpath = str(edbpath)
|
|
207
214
|
|
|
208
|
-
edbversion = get_string_version(edbversion)
|
|
209
215
|
self._clean_variables()
|
|
210
|
-
|
|
216
|
+
self.__initialization()
|
|
217
|
+
|
|
211
218
|
self.standalone = True
|
|
212
219
|
self.oproject = oproject
|
|
213
220
|
self._main = sys.modules["__main__"]
|
|
@@ -260,9 +267,8 @@ class Edb(Database):
|
|
|
260
267
|
map_file=map_file,
|
|
261
268
|
):
|
|
262
269
|
raise AttributeError("Translation was unsuccessful")
|
|
263
|
-
return False
|
|
264
270
|
if settings.enable_local_log_file and self.log_name:
|
|
265
|
-
self.
|
|
271
|
+
self.logger.add_file_logger(self.log_name, "Edb")
|
|
266
272
|
self.logger.info("EDB %s was created correctly from %s file.", self.edbpath, edbpath)
|
|
267
273
|
elif edbpath[-3:] in ["brd", "mcm", "sip", "gds", "xml", "dxf", "tgz", "anf"]:
|
|
268
274
|
self.edbpath = edbpath[:-4] + ".aedb"
|
|
@@ -277,28 +283,25 @@ class Edb(Database):
|
|
|
277
283
|
map_file=map_file,
|
|
278
284
|
):
|
|
279
285
|
raise AttributeError("Translation was unsuccessful")
|
|
280
|
-
return False
|
|
281
286
|
if settings.enable_local_log_file and self.log_name:
|
|
282
|
-
self.
|
|
287
|
+
self.logger.add_file_logger(self.log_name, "Edb")
|
|
283
288
|
self.logger.info("EDB %s was created correctly from %s file.", self.edbpath, edbpath[-2:])
|
|
284
289
|
elif edbpath.endswith("edb.def"):
|
|
285
290
|
self.edbpath = os.path.dirname(edbpath)
|
|
286
291
|
if settings.enable_local_log_file and self.log_name:
|
|
287
|
-
self.
|
|
292
|
+
self.logger.add_file_logger(self.log_name, "Edb")
|
|
288
293
|
self.open_edb()
|
|
289
294
|
elif not os.path.exists(os.path.join(self.edbpath, "edb.def")):
|
|
290
295
|
self.create_edb()
|
|
291
296
|
if settings.enable_local_log_file and self.log_name:
|
|
292
|
-
self.
|
|
297
|
+
self.logger.add_file_logger(self.log_name, "Edb")
|
|
293
298
|
self.logger.info("EDB %s created correctly.", self.edbpath)
|
|
294
299
|
elif ".aedb" in edbpath:
|
|
295
300
|
self.edbpath = edbpath
|
|
296
301
|
if settings.enable_local_log_file and self.log_name:
|
|
297
|
-
self.
|
|
302
|
+
self.logger.add_file_logger(self.log_name, "Edb")
|
|
298
303
|
self.open_edb()
|
|
299
|
-
if self.active_cell:
|
|
300
|
-
self.logger.info(f"EDB initialized.Time lapse {datetime.now() - now}")
|
|
301
|
-
else:
|
|
304
|
+
if not self.active_cell:
|
|
302
305
|
raise AttributeError("Failed to initialize DLLs.")
|
|
303
306
|
|
|
304
307
|
def __enter__(self):
|
|
@@ -350,6 +353,35 @@ class Edb(Database):
|
|
|
350
353
|
if description: # Add the variable description if a two-item list is passed for variable_value.
|
|
351
354
|
self.__getitem__(variable_name).description = description
|
|
352
355
|
|
|
356
|
+
def __initialization(self):
|
|
357
|
+
self.logger.info(f"Edb version {self.version}")
|
|
358
|
+
|
|
359
|
+
"""Initialize DLLs."""
|
|
360
|
+
from pyedb import __version__
|
|
361
|
+
from pyedb.dotnet.clr_module import _clr, edb_initialized
|
|
362
|
+
|
|
363
|
+
if not edb_initialized: # pragma: no cover
|
|
364
|
+
raise RuntimeWarning("Failed to initialize Dlls.")
|
|
365
|
+
self.logger.info(f"Logger is initialized. Log file is saved to {self.logger.log_file}.")
|
|
366
|
+
self.logger.info("legacy v%s", __version__)
|
|
367
|
+
self.logger.info("Python version %s", sys.version)
|
|
368
|
+
|
|
369
|
+
sys.path.append(self.base_path)
|
|
370
|
+
|
|
371
|
+
_clr.AddReference("Ansys.Ansoft.Edb")
|
|
372
|
+
_clr.AddReference("Ansys.Ansoft.EdbBuilderUtils")
|
|
373
|
+
_clr.AddReference("Ansys.Ansoft.SimSetupData")
|
|
374
|
+
os.environ["ECAD_TRANSLATORS_INSTALL_DIR"] = self.base_path
|
|
375
|
+
oaDirectory = os.path.join(self.base_path, "common", "oa")
|
|
376
|
+
os.environ["ANSYS_OADIR"] = oaDirectory
|
|
377
|
+
os.environ["PATH"] = "{};{}".format(os.environ["PATH"], self.base_path)
|
|
378
|
+
edb = __import__("Ansys.Ansoft.Edb")
|
|
379
|
+
edbbuilder = __import__("Ansys.Ansoft.EdbBuilderUtils")
|
|
380
|
+
self.simSetup = __import__("Ansys.Ansoft.SimSetupData")
|
|
381
|
+
self._edb = edb.Ansoft.Edb
|
|
382
|
+
self.edbutils = edbbuilder.Ansoft.EdbBuilderUtils
|
|
383
|
+
self.simsetupdata = self.simSetup.Ansoft.SimSetupData.Data
|
|
384
|
+
|
|
353
385
|
def _check_remove_project_files(self, edbpath: str, remove_existing_aedt: bool) -> None:
|
|
354
386
|
aedt_file = os.path.splitext(edbpath)[0] + ".aedt"
|
|
355
387
|
files = [aedt_file, aedt_file + ".lock"]
|
|
@@ -400,6 +432,11 @@ class Edb(Database):
|
|
|
400
432
|
def pedb_class(self):
|
|
401
433
|
return pyedb.dotnet
|
|
402
434
|
|
|
435
|
+
def value(self, val):
|
|
436
|
+
"""Convert a value into a pyedb value."""
|
|
437
|
+
val_ = val if isinstance(val, self._edb.Utility.Value) else self.edb_value(val)
|
|
438
|
+
return Value(self, val_)
|
|
439
|
+
|
|
403
440
|
@property
|
|
404
441
|
def grpc(self):
|
|
405
442
|
"""grpc flag."""
|
|
@@ -414,7 +451,7 @@ class Edb(Database):
|
|
|
414
451
|
list of cell names : List[str]
|
|
415
452
|
"""
|
|
416
453
|
names = []
|
|
417
|
-
for cell in self.
|
|
454
|
+
for cell in [i for i in list(self._db.CircuitCells)]:
|
|
418
455
|
names.append(cell.GetName())
|
|
419
456
|
return names
|
|
420
457
|
|
|
@@ -431,6 +468,10 @@ class Edb(Database):
|
|
|
431
468
|
d_var[i] = Variable(self, i)
|
|
432
469
|
return d_var
|
|
433
470
|
|
|
471
|
+
@property
|
|
472
|
+
def ansys_em_path(self):
|
|
473
|
+
return self.base_path
|
|
474
|
+
|
|
434
475
|
@property
|
|
435
476
|
def project_variables(self):
|
|
436
477
|
"""Get all project variables.
|
|
@@ -441,7 +482,7 @@ class Edb(Database):
|
|
|
441
482
|
|
|
442
483
|
"""
|
|
443
484
|
p_var = dict()
|
|
444
|
-
for i in self.
|
|
485
|
+
for i in self._db.GetVariableServer().GetAllVariableNames():
|
|
445
486
|
p_var[i] = Variable(self, i)
|
|
446
487
|
return p_var
|
|
447
488
|
|
|
@@ -559,6 +600,7 @@ class Edb(Database):
|
|
|
559
600
|
temp[name] = val
|
|
560
601
|
return temp
|
|
561
602
|
|
|
603
|
+
@execution_timer("open_edb")
|
|
562
604
|
def open_edb(self):
|
|
563
605
|
"""Open EDB.
|
|
564
606
|
|
|
@@ -567,32 +609,32 @@ class Edb(Database):
|
|
|
567
609
|
``True`` when succeed ``False`` if failed : bool
|
|
568
610
|
"""
|
|
569
611
|
# self.logger.info("EDB Path is %s", self.edbpath)
|
|
570
|
-
# self.logger.info("EDB Version is %s", self.
|
|
571
|
-
# if self.
|
|
612
|
+
# self.logger.info("EDB Version is %s", self.version)
|
|
613
|
+
# if self.version > "2023.1":
|
|
572
614
|
# self.standalone = False
|
|
573
615
|
|
|
574
|
-
self.
|
|
616
|
+
self.core.Database.SetRunAsStandAlone(self.standalone)
|
|
617
|
+
self._db = self.core.Database.Open(
|
|
618
|
+
self.edbpath,
|
|
619
|
+
self.isreadonly,
|
|
620
|
+
)
|
|
621
|
+
if self._db.IsNull():
|
|
622
|
+
raise AttributeError(f"Failed to open edb file {self.edbpath}")
|
|
575
623
|
|
|
576
|
-
|
|
577
|
-
self.open(self.edbpath, self.isreadonly)
|
|
578
|
-
if not self.active_db:
|
|
579
|
-
self.logger.warning("Error Opening db")
|
|
580
|
-
self._active_cell = None
|
|
581
|
-
return None
|
|
582
|
-
self.logger.info("Database {} Opened in {}".format(os.path.split(self.edbpath)[-1], self.edbversion))
|
|
624
|
+
self.logger.info("Database {} Opened in {}".format(os.path.split(self.edbpath)[-1], self.version))
|
|
583
625
|
|
|
584
626
|
self._active_cell = None
|
|
585
627
|
if self.cellname:
|
|
586
|
-
for cell in list(self.
|
|
628
|
+
for cell in [i for i in list(self._db.TopCircuitCells)]:
|
|
587
629
|
if cell.GetName() == self.cellname:
|
|
588
630
|
self._active_cell = cell
|
|
589
631
|
if self._active_cell is None:
|
|
590
|
-
for cell in list(self.
|
|
632
|
+
for cell in [i for i in list(self._db.CircuitCells)]:
|
|
591
633
|
if cell.GetName() == self.cellname:
|
|
592
634
|
self._active_cell = cell
|
|
593
635
|
# if self._active_cell is still None, set it to default cell
|
|
594
636
|
if self._active_cell is None:
|
|
595
|
-
self._active_cell = list(self.
|
|
637
|
+
self._active_cell = list(self._db.TopCircuitCells)[0]
|
|
596
638
|
self.logger.info("Cell %s Opened", self._active_cell.GetName())
|
|
597
639
|
if self._active_cell:
|
|
598
640
|
self._init_objects()
|
|
@@ -602,6 +644,17 @@ class Edb(Database):
|
|
|
602
644
|
|
|
603
645
|
return True
|
|
604
646
|
|
|
647
|
+
@property
|
|
648
|
+
def core(self):
|
|
649
|
+
"""Edb Dotnet Api class.
|
|
650
|
+
|
|
651
|
+
Returns
|
|
652
|
+
-------
|
|
653
|
+
:class:`pyedb.dotnet.database.dotnet.database.CellDotNet`
|
|
654
|
+
"""
|
|
655
|
+
return self._edb
|
|
656
|
+
|
|
657
|
+
@execution_timer("create_edb")
|
|
605
658
|
def create_edb(self):
|
|
606
659
|
"""Create EDB.
|
|
607
660
|
|
|
@@ -609,20 +662,20 @@ class Edb(Database):
|
|
|
609
662
|
-------
|
|
610
663
|
``True`` when succeed ``False`` if failed : bool
|
|
611
664
|
"""
|
|
612
|
-
# if self.
|
|
665
|
+
# if self.version > "2023.1":
|
|
613
666
|
# self.standalone = False
|
|
614
667
|
|
|
615
|
-
self.
|
|
616
|
-
|
|
617
|
-
|
|
668
|
+
self.core.Database.SetRunAsStandAlone(self.standalone)
|
|
669
|
+
|
|
670
|
+
self._db = self.core.Database.Create(self.edbpath)
|
|
671
|
+
|
|
672
|
+
if not self._db:
|
|
618
673
|
self.logger.warning("Error creating the database.")
|
|
619
674
|
self._active_cell = None
|
|
620
675
|
return None
|
|
621
676
|
if not self.cellname:
|
|
622
677
|
self.cellname = generate_unique_name("Cell")
|
|
623
|
-
self._active_cell = self.
|
|
624
|
-
self.active_db, self.edb_api.cell.CellType.CircuitCell, self.cellname
|
|
625
|
-
)
|
|
678
|
+
self._active_cell = self.core.Cell.Cell.Create(self._db, self.core.Cell.CellType.CircuitCell, self.cellname)
|
|
626
679
|
if self._active_cell:
|
|
627
680
|
self._init_objects()
|
|
628
681
|
return True
|
|
@@ -684,6 +737,7 @@ class Edb(Database):
|
|
|
684
737
|
layer_filter,
|
|
685
738
|
)
|
|
686
739
|
|
|
740
|
+
@execution_timer("import_layout_file")
|
|
687
741
|
def import_layout_file(
|
|
688
742
|
self,
|
|
689
743
|
input_file,
|
|
@@ -764,8 +818,7 @@ class Edb(Database):
|
|
|
764
818
|
cmd_translator.append('-f="{}"'.format(layer_filter))
|
|
765
819
|
subprocess.run(cmd_translator)
|
|
766
820
|
if not os.path.exists(os.path.join(working_dir, aedb_name)):
|
|
767
|
-
|
|
768
|
-
return False
|
|
821
|
+
raise RuntimeWarning(f"Translator failed. command : {' '.join(cmd_translator)}")
|
|
769
822
|
else:
|
|
770
823
|
self.logger.info("Translation correctly completed")
|
|
771
824
|
self.edbpath = os.path.join(working_dir, aedb_name)
|
|
@@ -847,7 +900,7 @@ class Edb(Database):
|
|
|
847
900
|
@property
|
|
848
901
|
def active_db(self):
|
|
849
902
|
"""Database object."""
|
|
850
|
-
return self.
|
|
903
|
+
return self._db
|
|
851
904
|
|
|
852
905
|
@property
|
|
853
906
|
def active_cell(self):
|
|
@@ -905,7 +958,7 @@ class Edb(Database):
|
|
|
905
958
|
>>> edbapp = Edb("myproject.aedb")
|
|
906
959
|
>>> comp = edbapp.components.get_component_by_name("J1")
|
|
907
960
|
"""
|
|
908
|
-
if not self._components and self.
|
|
961
|
+
if not self._components and self._db:
|
|
909
962
|
self._components = Components(self)
|
|
910
963
|
return self._components
|
|
911
964
|
|
|
@@ -920,7 +973,7 @@ class Edb(Database):
|
|
|
920
973
|
mess = "`core_stackup` is deprecated.\n"
|
|
921
974
|
mess += " Use `app.stackup` directly to instantiate new stackup methods."
|
|
922
975
|
warnings.warn(mess, DeprecationWarning)
|
|
923
|
-
if not self._stackup and self.
|
|
976
|
+
if not self._stackup and self._db:
|
|
924
977
|
self._stackup = Stackup(self)
|
|
925
978
|
return self._stackup
|
|
926
979
|
|
|
@@ -968,7 +1021,7 @@ class Edb(Database):
|
|
|
968
1021
|
>>> edbapp.materials.add_debye_material("debye_mat", 5, 3, 0.02, 0.05, 1e5, 1e9)
|
|
969
1022
|
>>> edbapp.materials.add_djordjevicsarkar_material("djord_mat", 3.3, 0.02, 3.3)
|
|
970
1023
|
"""
|
|
971
|
-
if not self._materials and self.
|
|
1024
|
+
if not self._materials and self._db:
|
|
972
1025
|
self._materials = Materials(self)
|
|
973
1026
|
return self._materials
|
|
974
1027
|
|
|
@@ -1016,7 +1069,7 @@ class Edb(Database):
|
|
|
1016
1069
|
>>> ... )
|
|
1017
1070
|
"""
|
|
1018
1071
|
|
|
1019
|
-
if not self._padstack and self.
|
|
1072
|
+
if not self._padstack and self._db:
|
|
1020
1073
|
self._padstack = EdbPadstacks(self)
|
|
1021
1074
|
return self._padstack
|
|
1022
1075
|
|
|
@@ -1054,7 +1107,7 @@ class Edb(Database):
|
|
|
1054
1107
|
>>> edbapp = Edb("myproject.aedb")
|
|
1055
1108
|
>>> p2 = edbapp.siwave.create_circuit_port_on_net("U2A5", "V3P3_S0", "U2A5", "GND", 50, "test")
|
|
1056
1109
|
"""
|
|
1057
|
-
if not self._siwave and self.
|
|
1110
|
+
if not self._siwave and self._db:
|
|
1058
1111
|
self._siwave = EdbSiwave(self)
|
|
1059
1112
|
return self._siwave
|
|
1060
1113
|
|
|
@@ -1098,7 +1151,7 @@ class Edb(Database):
|
|
|
1098
1151
|
>>> sim_config.mesh_freq = "10Ghz"
|
|
1099
1152
|
>>> edbapp.hfss.configure_hfss_analysis_setup(sim_config)
|
|
1100
1153
|
"""
|
|
1101
|
-
if not self._hfss and self.
|
|
1154
|
+
if not self._hfss and self._db:
|
|
1102
1155
|
self._hfss = EdbHfss(self)
|
|
1103
1156
|
return self._hfss
|
|
1104
1157
|
|
|
@@ -1139,7 +1192,7 @@ class Edb(Database):
|
|
|
1139
1192
|
>>> edbapp.nets.find_and_fix_disjoint_nets("GND", keep_only_main_net=True)
|
|
1140
1193
|
"""
|
|
1141
1194
|
|
|
1142
|
-
if not self._nets and self.
|
|
1195
|
+
if not self._nets and self._db:
|
|
1143
1196
|
raise Exception("")
|
|
1144
1197
|
self._nets = EdbNets(self)
|
|
1145
1198
|
return self._nets
|
|
@@ -1159,7 +1212,7 @@ class Edb(Database):
|
|
|
1159
1212
|
>>> edbapp.net_classes
|
|
1160
1213
|
"""
|
|
1161
1214
|
|
|
1162
|
-
if self.
|
|
1215
|
+
if self._db:
|
|
1163
1216
|
return EdbNetClasses(self)
|
|
1164
1217
|
|
|
1165
1218
|
@property
|
|
@@ -1177,7 +1230,7 @@ class Edb(Database):
|
|
|
1177
1230
|
>>> edbapp.extended_nets
|
|
1178
1231
|
"""
|
|
1179
1232
|
|
|
1180
|
-
if self.
|
|
1233
|
+
if self._db:
|
|
1181
1234
|
return EdbExtendedNets(self)
|
|
1182
1235
|
|
|
1183
1236
|
@property
|
|
@@ -1194,7 +1247,7 @@ class Edb(Database):
|
|
|
1194
1247
|
>>> edbapp = Edb("myproject.aedb")
|
|
1195
1248
|
>>> edbapp.differential_pairs
|
|
1196
1249
|
"""
|
|
1197
|
-
if self.
|
|
1250
|
+
if self._db:
|
|
1198
1251
|
return EdbDifferentialPairs(self)
|
|
1199
1252
|
else: # pragma: no cover
|
|
1200
1253
|
return
|
|
@@ -1233,7 +1286,7 @@ class Edb(Database):
|
|
|
1233
1286
|
>>> edbapp = Edb("myproject.aedb")
|
|
1234
1287
|
>>> top_prims = edbapp.modeler.primitives_by_layer["TOP"]
|
|
1235
1288
|
"""
|
|
1236
|
-
if not self._core_primitives and self.
|
|
1289
|
+
if not self._core_primitives and self._db:
|
|
1237
1290
|
self._core_primitives = Modeler(self)
|
|
1238
1291
|
return self._core_primitives
|
|
1239
1292
|
|
|
@@ -1353,12 +1406,12 @@ class Edb(Database):
|
|
|
1353
1406
|
VoltageProbe,
|
|
1354
1407
|
) = range(0, 9)
|
|
1355
1408
|
|
|
1356
|
-
def edb_value(self,
|
|
1409
|
+
def edb_value(self, value, var_server=None):
|
|
1357
1410
|
"""Convert a value to an EDB value. Value can be a string, float or integer. Mainly used in internal calls.
|
|
1358
1411
|
|
|
1359
1412
|
Parameters
|
|
1360
1413
|
----------
|
|
1361
|
-
|
|
1414
|
+
value : str, float, int
|
|
1362
1415
|
|
|
1363
1416
|
|
|
1364
1417
|
Returns
|
|
@@ -1366,7 +1419,26 @@ class Edb(Database):
|
|
|
1366
1419
|
Instance of `Edb.Utility.Value`
|
|
1367
1420
|
|
|
1368
1421
|
"""
|
|
1369
|
-
|
|
1422
|
+
if isinstance(value, self.core.Utility.Value):
|
|
1423
|
+
return value
|
|
1424
|
+
if var_server:
|
|
1425
|
+
return self.core.Utility.Value(value, var_server)
|
|
1426
|
+
if isinstance(value, (int, float)):
|
|
1427
|
+
return self.core.Utility.Value(value)
|
|
1428
|
+
m1 = re.findall(r"(?<=[/+-/*//^/(/[])([a-z_A-Z/$]\w*)", str(value).replace(" ", ""))
|
|
1429
|
+
m2 = re.findall(r"^([a-z_A-Z/$]\w*)", str(value).replace(" ", ""))
|
|
1430
|
+
val_decomposed = list(set(m1).union(m2))
|
|
1431
|
+
if not val_decomposed:
|
|
1432
|
+
return self.core.Utility.Value(value)
|
|
1433
|
+
var_server_db = self._db.GetVariableServer()
|
|
1434
|
+
var_names = var_server_db.GetAllVariableNames()
|
|
1435
|
+
var_server_cell = self.active_cell.GetVariableServer()
|
|
1436
|
+
var_names_cell = var_server_cell.GetAllVariableNames()
|
|
1437
|
+
if set(val_decomposed).intersection(var_names_cell):
|
|
1438
|
+
return self.core.Utility.Value(value, var_server_cell)
|
|
1439
|
+
if set(val_decomposed).intersection(var_names):
|
|
1440
|
+
return self.core.Utility.Value(value, var_server_db)
|
|
1441
|
+
return self.core.Utility.Value(value)
|
|
1370
1442
|
|
|
1371
1443
|
def point_3d(self, x, y, z=0.0):
|
|
1372
1444
|
"""Compute the Edb 3d Point Data.
|
|
@@ -1384,7 +1456,25 @@ class Edb(Database):
|
|
|
1384
1456
|
-------
|
|
1385
1457
|
``Geometry.Point3DData``.
|
|
1386
1458
|
"""
|
|
1387
|
-
return self.
|
|
1459
|
+
return self.core.Geometry.Point3DData(self.edb_value(x), self.edb_value(y), self.edb_value(z))
|
|
1460
|
+
|
|
1461
|
+
def copy_cells(self, cells_to_copy):
|
|
1462
|
+
"""Copy Cells from other Databases or this Database into this Database.
|
|
1463
|
+
|
|
1464
|
+
Parameters
|
|
1465
|
+
----------
|
|
1466
|
+
cells_to_copy : list[:class:`Cell <ansys.edb.layout.Cell>`]
|
|
1467
|
+
Cells to copy.
|
|
1468
|
+
|
|
1469
|
+
Returns
|
|
1470
|
+
-------
|
|
1471
|
+
list[:class:`Cell <ansys.edb.layout.Cell>`]
|
|
1472
|
+
New Cells created in this Database.
|
|
1473
|
+
"""
|
|
1474
|
+
if not isinstance(cells_to_copy, list):
|
|
1475
|
+
cells_to_copy = [cells_to_copy]
|
|
1476
|
+
_dbCells = convert_py_list_to_net_list(cells_to_copy)
|
|
1477
|
+
return self._db.CopyCells(_dbCells)
|
|
1388
1478
|
|
|
1389
1479
|
def point_data(self, x, y=None):
|
|
1390
1480
|
"""Compute the Edb Point Data.
|
|
@@ -1402,9 +1492,9 @@ class Edb(Database):
|
|
|
1402
1492
|
``Geometry.PointData``.
|
|
1403
1493
|
"""
|
|
1404
1494
|
if y is None:
|
|
1405
|
-
return self.
|
|
1495
|
+
return self.core.Geometry.PointData(self.edb_value(x))
|
|
1406
1496
|
else:
|
|
1407
|
-
return self.
|
|
1497
|
+
return self.core.Geometry.PointData(self.edb_value(x), self.edb_value(y))
|
|
1408
1498
|
|
|
1409
1499
|
def _is_file_existing_and_released(self, filename):
|
|
1410
1500
|
if os.path.exists(filename):
|
|
@@ -1468,7 +1558,8 @@ class Edb(Database):
|
|
|
1468
1558
|
warnings.warn("Use new property :func:`close` instead.", DeprecationWarning)
|
|
1469
1559
|
return self.close()
|
|
1470
1560
|
|
|
1471
|
-
|
|
1561
|
+
@execution_timer("Close Edb file")
|
|
1562
|
+
def close(self, **kwargs):
|
|
1472
1563
|
"""Close EDB and cleanup variables.
|
|
1473
1564
|
|
|
1474
1565
|
Returns
|
|
@@ -1477,14 +1568,11 @@ class Edb(Database):
|
|
|
1477
1568
|
``True`` when successful, ``False`` when failed.
|
|
1478
1569
|
|
|
1479
1570
|
"""
|
|
1480
|
-
|
|
1571
|
+
self._db.Close()
|
|
1481
1572
|
|
|
1482
1573
|
if self.log_name and settings.enable_local_log_file:
|
|
1483
|
-
self.
|
|
1484
|
-
start_time = time.time()
|
|
1574
|
+
self.logger.remove_all_file_loggers()
|
|
1485
1575
|
self._wait_for_file_release()
|
|
1486
|
-
elapsed_time = time.time() - start_time
|
|
1487
|
-
self.logger.info("EDB file release time: {0:.2f}ms".format(elapsed_time * 1000.0))
|
|
1488
1576
|
self._clean_variables()
|
|
1489
1577
|
return True
|
|
1490
1578
|
|
|
@@ -1503,6 +1591,7 @@ class Edb(Database):
|
|
|
1503
1591
|
warnings.warn("Use new method :func:`save` instead.", DeprecationWarning)
|
|
1504
1592
|
return self.save()
|
|
1505
1593
|
|
|
1594
|
+
@execution_timer("Save Edb file")
|
|
1506
1595
|
def save(self):
|
|
1507
1596
|
"""Save the EDB file.
|
|
1508
1597
|
|
|
@@ -1513,11 +1602,8 @@ class Edb(Database):
|
|
|
1513
1602
|
|
|
1514
1603
|
"""
|
|
1515
1604
|
|
|
1516
|
-
|
|
1517
|
-
start_time = time.time()
|
|
1605
|
+
self._db.Save()
|
|
1518
1606
|
self._wait_for_file_release()
|
|
1519
|
-
elapsed_time = time.time() - start_time
|
|
1520
|
-
self.logger.info("EDB file save time: {0:.2f}ms".format(elapsed_time * 1000.0))
|
|
1521
1607
|
return True
|
|
1522
1608
|
|
|
1523
1609
|
def save_edb_as(self, path):
|
|
@@ -1541,7 +1627,8 @@ class Edb(Database):
|
|
|
1541
1627
|
warnings.warn("Use new property :func:`save_as` instead.", DeprecationWarning)
|
|
1542
1628
|
return self.save_as(path)
|
|
1543
1629
|
|
|
1544
|
-
|
|
1630
|
+
@execution_timer("EDB file save")
|
|
1631
|
+
def save_as(self, path):
|
|
1545
1632
|
"""Save the EDB file as another file.
|
|
1546
1633
|
|
|
1547
1634
|
Parameters
|
|
@@ -1556,22 +1643,19 @@ class Edb(Database):
|
|
|
1556
1643
|
|
|
1557
1644
|
"""
|
|
1558
1645
|
origin_name = "pyedb_" + os.path.splitext(os.path.split(self.edbpath)[-1])[0]
|
|
1559
|
-
|
|
1560
|
-
start_time = time.time()
|
|
1646
|
+
self._db.SaveAs(path, "")
|
|
1561
1647
|
self._wait_for_file_release()
|
|
1562
|
-
|
|
1563
|
-
self.logger.info("EDB file save time: {0:.2f}ms".format(elapsed_time * 1000.0))
|
|
1564
|
-
self.edbpath = self.directory
|
|
1648
|
+
self.edbpath = self._db.GetDirectory()
|
|
1565
1649
|
if self.log_name:
|
|
1566
|
-
self.
|
|
1650
|
+
self.logger.remove_file_logger(os.path.splitext(os.path.split(self.log_name)[-1])[0])
|
|
1567
1651
|
|
|
1568
1652
|
self.log_name = os.path.join(
|
|
1569
1653
|
os.path.dirname(path),
|
|
1570
1654
|
"pyedb_" + os.path.splitext(os.path.split(path)[-1])[0] + ".log",
|
|
1571
1655
|
)
|
|
1572
1656
|
if settings.enable_local_log_file:
|
|
1573
|
-
self.
|
|
1574
|
-
self.
|
|
1657
|
+
self.logger.add_file_logger(self.log_name, "Edb")
|
|
1658
|
+
self.logger.remove_file_logger(origin_name)
|
|
1575
1659
|
return True
|
|
1576
1660
|
|
|
1577
1661
|
def execute(self, func):
|
|
@@ -1589,7 +1673,7 @@ class Edb(Database):
|
|
|
1589
1673
|
``True`` when successful, ``False`` when failed.
|
|
1590
1674
|
|
|
1591
1675
|
"""
|
|
1592
|
-
return self.
|
|
1676
|
+
return self.core.utility.utility.Command.Execute(func)
|
|
1593
1677
|
|
|
1594
1678
|
def import_cadence_file(self, inputBrd, WorkDir=None, anstranslator_full_path="", use_ppe=False):
|
|
1595
1679
|
"""Import a board file and generate an ``edb.def`` file in the working directory.
|
|
@@ -1638,7 +1722,7 @@ class Edb(Database):
|
|
|
1638
1722
|
):
|
|
1639
1723
|
if extent_type in [
|
|
1640
1724
|
"Conforming",
|
|
1641
|
-
self.
|
|
1725
|
+
self.core.Geometry.ExtentType.Conforming,
|
|
1642
1726
|
1,
|
|
1643
1727
|
]:
|
|
1644
1728
|
if use_pyaedt_extent:
|
|
@@ -1656,7 +1740,7 @@ class Edb(Database):
|
|
|
1656
1740
|
else:
|
|
1657
1741
|
_poly = self.layout.expanded_extent(
|
|
1658
1742
|
net_signals,
|
|
1659
|
-
self.
|
|
1743
|
+
self.core.Geometry.ExtentType.Conforming,
|
|
1660
1744
|
expansion_size,
|
|
1661
1745
|
False,
|
|
1662
1746
|
use_round_corner,
|
|
@@ -1664,12 +1748,12 @@ class Edb(Database):
|
|
|
1664
1748
|
)
|
|
1665
1749
|
elif extent_type in [
|
|
1666
1750
|
"Bounding",
|
|
1667
|
-
self.
|
|
1751
|
+
self.core.Geometry.ExtentType.BoundingBox,
|
|
1668
1752
|
0,
|
|
1669
1753
|
]:
|
|
1670
1754
|
_poly = self.layout.expanded_extent(
|
|
1671
1755
|
net_signals,
|
|
1672
|
-
self.
|
|
1756
|
+
self.core.Geometry.ExtentType.BoundingBox,
|
|
1673
1757
|
expansion_size,
|
|
1674
1758
|
False,
|
|
1675
1759
|
use_round_corner,
|
|
@@ -1690,14 +1774,14 @@ class Edb(Database):
|
|
|
1690
1774
|
else:
|
|
1691
1775
|
_poly = self.layout.expanded_extent(
|
|
1692
1776
|
net_signals,
|
|
1693
|
-
self.
|
|
1777
|
+
self.core.Geometry.ExtentType.Conforming,
|
|
1694
1778
|
expansion_size,
|
|
1695
1779
|
False,
|
|
1696
1780
|
use_round_corner,
|
|
1697
1781
|
1,
|
|
1698
1782
|
)
|
|
1699
1783
|
_poly_list = convert_py_list_to_net_list([_poly])
|
|
1700
|
-
_poly = self.
|
|
1784
|
+
_poly = self.core.geometry.polygon_data.get_convex_hull_of_polygons(_poly_list)
|
|
1701
1785
|
return _poly
|
|
1702
1786
|
|
|
1703
1787
|
def _create_conformal(
|
|
@@ -1772,7 +1856,7 @@ class Edb(Database):
|
|
|
1772
1856
|
pass
|
|
1773
1857
|
finally:
|
|
1774
1858
|
unite_polys.extend(list(obj_data))
|
|
1775
|
-
_poly_unite = self.
|
|
1859
|
+
_poly_unite = self.core.Geometry.PolygonData.Unite(convert_py_list_to_net_list(unite_polys))
|
|
1776
1860
|
if len(_poly_unite) == 1:
|
|
1777
1861
|
self.logger.info("Correctly computed Extension at first iteration.")
|
|
1778
1862
|
return _poly_unite[0]
|
|
@@ -1797,20 +1881,20 @@ class Edb(Database):
|
|
|
1797
1881
|
pd = term._edb_object.GetParameters()[1]
|
|
1798
1882
|
locations.append([pd.X.ToDouble(), pd.Y.ToDouble()])
|
|
1799
1883
|
for point in locations:
|
|
1800
|
-
pointA = self.
|
|
1884
|
+
pointA = self.core.geometry.point_data(
|
|
1801
1885
|
self.edb_value(point[0] - expansion_size),
|
|
1802
1886
|
self.edb_value(point[1] - expansion_size),
|
|
1803
1887
|
)
|
|
1804
|
-
pointB = self.
|
|
1888
|
+
pointB = self.core.geometry.point_data(
|
|
1805
1889
|
self.edb_value(point[0] + expansion_size),
|
|
1806
1890
|
self.edb_value(point[1] + expansion_size),
|
|
1807
1891
|
)
|
|
1808
1892
|
|
|
1809
1893
|
points = Tuple[
|
|
1810
|
-
self.
|
|
1811
|
-
self.
|
|
1894
|
+
self.core.geometry.geometry.PointData,
|
|
1895
|
+
self.core.geometry.geometry.PointData,
|
|
1812
1896
|
](pointA, pointB)
|
|
1813
|
-
_polys.append(self.
|
|
1897
|
+
_polys.append(self.core.geometry.polygon_data.create_from_bbox(points))
|
|
1814
1898
|
return _polys
|
|
1815
1899
|
|
|
1816
1900
|
def _create_convex_hull(
|
|
@@ -1843,7 +1927,7 @@ class Edb(Database):
|
|
|
1843
1927
|
if smart_cut:
|
|
1844
1928
|
objs_data = self._smart_cut(reference_list, expansion_size)
|
|
1845
1929
|
_polys.extend(objs_data)
|
|
1846
|
-
_poly = self.
|
|
1930
|
+
_poly = self.core.Geometry.PolygonData.GetConvexHullOfPolygons(convert_py_list_to_net_list(_polys))
|
|
1847
1931
|
_poly = _poly.Expand(expansion_size, tolerance, round_corner, round_extension)[0]
|
|
1848
1932
|
return _poly
|
|
1849
1933
|
|
|
@@ -1964,7 +2048,7 @@ class Edb(Database):
|
|
|
1964
2048
|
Examples
|
|
1965
2049
|
--------
|
|
1966
2050
|
>>> from pyedb import Edb
|
|
1967
|
-
>>> edb = Edb(r'C:\\test.aedb',
|
|
2051
|
+
>>> edb = Edb(r'C:\\test.aedb', version="2022.2")
|
|
1968
2052
|
>>> edb.logger.info_timer("Edb Opening")
|
|
1969
2053
|
>>> edb.logger.reset_timer()
|
|
1970
2054
|
>>> start = time.time()
|
|
@@ -1978,8 +2062,8 @@ class Edb(Database):
|
|
|
1978
2062
|
>>> edb.logger.info("Total legacy cutout time in min %s", end_time)
|
|
1979
2063
|
>>> edb.nets.plot(signal_list, None, color_by_net=True)
|
|
1980
2064
|
>>> edb.nets.plot(power_list, None, color_by_net=True)
|
|
1981
|
-
>>> edb.
|
|
1982
|
-
>>> edb.
|
|
2065
|
+
>>> edb.save()
|
|
2066
|
+
>>> edb.close()
|
|
1983
2067
|
|
|
1984
2068
|
|
|
1985
2069
|
"""
|
|
@@ -2019,7 +2103,7 @@ class Edb(Database):
|
|
|
2019
2103
|
legacy_path = self.edbpath
|
|
2020
2104
|
if expansion_factor > 0 and not custom_extent:
|
|
2021
2105
|
start = time.time()
|
|
2022
|
-
self.
|
|
2106
|
+
self.save()
|
|
2023
2107
|
dummy_path = self.edbpath.replace(".aedb", "_smart_cutout_temp.aedb")
|
|
2024
2108
|
working_cutout = False
|
|
2025
2109
|
i = 1
|
|
@@ -2051,12 +2135,12 @@ class Edb(Database):
|
|
|
2051
2135
|
)
|
|
2052
2136
|
if self.are_port_reference_terminals_connected():
|
|
2053
2137
|
if output_aedb_path:
|
|
2054
|
-
self.
|
|
2138
|
+
self.save_as(output_aedb_path)
|
|
2055
2139
|
else:
|
|
2056
|
-
self.
|
|
2140
|
+
self.save_as(legacy_path)
|
|
2057
2141
|
working_cutout = True
|
|
2058
2142
|
break
|
|
2059
|
-
self.
|
|
2143
|
+
self.close()
|
|
2060
2144
|
self.edbpath = legacy_path
|
|
2061
2145
|
self.open_edb()
|
|
2062
2146
|
i += 1
|
|
@@ -2091,8 +2175,8 @@ class Edb(Database):
|
|
|
2091
2175
|
inlcude_voids_in_extents=include_voids_in_extents,
|
|
2092
2176
|
)
|
|
2093
2177
|
if result and not open_cutout_at_end and self.edbpath != legacy_path:
|
|
2094
|
-
self.
|
|
2095
|
-
self.
|
|
2178
|
+
self.save()
|
|
2179
|
+
self.close()
|
|
2096
2180
|
self.edbpath = legacy_path
|
|
2097
2181
|
self.open_edb()
|
|
2098
2182
|
return result
|
|
@@ -2165,7 +2249,7 @@ class Edb(Database):
|
|
|
2165
2249
|
_dbCells = [_cutout]
|
|
2166
2250
|
|
|
2167
2251
|
if output_aedb_path:
|
|
2168
|
-
db2 = self.
|
|
2252
|
+
db2 = self.core.Database.Create(output_aedb_path)
|
|
2169
2253
|
_success = db2.Save()
|
|
2170
2254
|
_dbCells = convert_py_list_to_net_list(_dbCells)
|
|
2171
2255
|
db2.CopyCells(_dbCells) # Copies cutout cell/design to db2 project
|
|
@@ -2174,7 +2258,7 @@ class Edb(Database):
|
|
|
2174
2258
|
if not net.GetName() in included_nets_list:
|
|
2175
2259
|
net.Delete()
|
|
2176
2260
|
_success = db2.Save()
|
|
2177
|
-
for c in list(self.
|
|
2261
|
+
for c in list(self._db.TopCircuitCells):
|
|
2178
2262
|
if c.GetName() == _cutout.GetName():
|
|
2179
2263
|
c.Delete()
|
|
2180
2264
|
if open_cutout_at_end: # pragma: no cover
|
|
@@ -2199,7 +2283,7 @@ class Edb(Database):
|
|
|
2199
2283
|
for _cmp in _cmps:
|
|
2200
2284
|
_cmp.Delete()
|
|
2201
2285
|
except:
|
|
2202
|
-
self.
|
|
2286
|
+
self.logger.error("Failed to remove single pin components.")
|
|
2203
2287
|
db2.Close()
|
|
2204
2288
|
source = os.path.join(output_aedb_path, "edb.def.tmp")
|
|
2205
2289
|
target = os.path.join(output_aedb_path, "edb.def")
|
|
@@ -2304,7 +2388,7 @@ class Edb(Database):
|
|
|
2304
2388
|
from concurrent.futures import ThreadPoolExecutor
|
|
2305
2389
|
|
|
2306
2390
|
if output_aedb_path:
|
|
2307
|
-
self.
|
|
2391
|
+
self.save_as(output_aedb_path)
|
|
2308
2392
|
self.logger.info("Cutout Multithread started.")
|
|
2309
2393
|
expansion_size = self.edb_value(expansion_size).ToDouble()
|
|
2310
2394
|
|
|
@@ -2416,7 +2500,7 @@ class Edb(Database):
|
|
|
2416
2500
|
pins_to_preserve=pins_to_preserve,
|
|
2417
2501
|
inlcude_voids_in_extents=inlcude_voids_in_extents,
|
|
2418
2502
|
)
|
|
2419
|
-
if extent_type in ["Conforming", self.
|
|
2503
|
+
if extent_type in ["Conforming", self.core.Geometry.ExtentType.Conforming, 1]:
|
|
2420
2504
|
if extent_defeature > 0:
|
|
2421
2505
|
_poly = _poly.Defeature(extent_defeature)
|
|
2422
2506
|
_poly1 = _poly.CreateFromArcs(_poly.GetArcData(), True)
|
|
@@ -2427,7 +2511,7 @@ class Edb(Database):
|
|
|
2427
2511
|
self.logger.info(f"Number of voids included:{len(list(_poly1.Holes))}")
|
|
2428
2512
|
_poly = _poly1
|
|
2429
2513
|
if not _poly or _poly.IsNull():
|
|
2430
|
-
self.
|
|
2514
|
+
self.logger.error("Failed to create Extent.")
|
|
2431
2515
|
return []
|
|
2432
2516
|
self.logger.info_timer("Extent Creation")
|
|
2433
2517
|
self.logger.reset_timer()
|
|
@@ -2624,7 +2708,7 @@ class Edb(Database):
|
|
|
2624
2708
|
Examples
|
|
2625
2709
|
--------
|
|
2626
2710
|
>>> from pyedb import Edb
|
|
2627
|
-
>>> edb = Edb(r'C:\\test.aedb',
|
|
2711
|
+
>>> edb = Edb(r'C:\\test.aedb', version="2022.2")
|
|
2628
2712
|
>>> edb.logger.info_timer("Edb Opening")
|
|
2629
2713
|
>>> edb.logger.reset_timer()
|
|
2630
2714
|
>>> start = time.time()
|
|
@@ -2681,14 +2765,10 @@ class Edb(Database):
|
|
|
2681
2765
|
via.pin.Delete()
|
|
2682
2766
|
if netlist:
|
|
2683
2767
|
nets = [net.net_obj for net in temp_edb.layout.nets if net.name in netlist]
|
|
2684
|
-
_poly = temp_edb.layout.expanded_extent(
|
|
2685
|
-
nets, self.edb_api.geometry.extent_type.Conforming, 0.0, True, True, 1
|
|
2686
|
-
)
|
|
2768
|
+
_poly = temp_edb.layout.expanded_extent(nets, self.core.Geometry.ExtentType.Conforming, 0.0, True, True, 1)
|
|
2687
2769
|
else:
|
|
2688
2770
|
nets = [net.api_object for net in temp_edb.layout.nets if "gnd" in net.name.lower()]
|
|
2689
|
-
_poly = temp_edb.layout.expanded_extent(
|
|
2690
|
-
nets, self.edb_api.geometry.extent_type.Conforming, 0.0, True, True, 1
|
|
2691
|
-
)
|
|
2771
|
+
_poly = temp_edb.layout.expanded_extent(nets, self.core.Geometry.ExtentType.Conforming, 0.0, True, True, 1)
|
|
2692
2772
|
temp_edb.close_edb()
|
|
2693
2773
|
if _poly:
|
|
2694
2774
|
return _poly
|
|
@@ -2789,9 +2869,7 @@ class Edb(Database):
|
|
|
2789
2869
|
p_missing = [i for i in pinstance_to_add if i.id not in ids]
|
|
2790
2870
|
self.logger.info("Added {} padstack instances after cutout".format(len(p_missing)))
|
|
2791
2871
|
for p in p_missing:
|
|
2792
|
-
position = self.
|
|
2793
|
-
self.edb_value(p.position[0]), self.edb_value(p.position[1])
|
|
2794
|
-
)
|
|
2872
|
+
position = self.core.geometry.point_data(self.edb_value(p.position[0]), self.edb_value(p.position[1]))
|
|
2795
2873
|
net = self.nets.find_or_create_net(p.net_name)
|
|
2796
2874
|
rotation = self.edb_value(p.rotation)
|
|
2797
2875
|
sign_layers = list(self.stackup.signal_layers.keys())
|
|
@@ -2808,7 +2886,7 @@ class Edb(Database):
|
|
|
2808
2886
|
for pad in list(self.padstacks.definitions.keys()):
|
|
2809
2887
|
if pad == p.padstack_definition:
|
|
2810
2888
|
padstack = self.padstacks.definitions[pad].edb_padstack
|
|
2811
|
-
padstack_instance = self.
|
|
2889
|
+
padstack_instance = self.core.Cell.primitive.padstack_instance.create(
|
|
2812
2890
|
_cutout.GetLayout(),
|
|
2813
2891
|
net,
|
|
2814
2892
|
p.name,
|
|
@@ -2831,7 +2909,7 @@ class Edb(Database):
|
|
|
2831
2909
|
center_y,
|
|
2832
2910
|
radius,
|
|
2833
2911
|
) = void_circle.primitive_object.GetParameters(0.0, 0.0, 0.0)
|
|
2834
|
-
cloned_circle = self.
|
|
2912
|
+
cloned_circle = self.core.Cell.primitive.circle.create(
|
|
2835
2913
|
layout,
|
|
2836
2914
|
void_circle.layer_name,
|
|
2837
2915
|
void_circle.net,
|
|
@@ -2841,7 +2919,7 @@ class Edb(Database):
|
|
|
2841
2919
|
)
|
|
2842
2920
|
cloned_circle.SetIsNegative(True)
|
|
2843
2921
|
elif void_circle.type == "Polygon":
|
|
2844
|
-
cloned_polygon = self.
|
|
2922
|
+
cloned_polygon = self.core.Cell.primitive.polygon.create(
|
|
2845
2923
|
layout,
|
|
2846
2924
|
void_circle.layer_name,
|
|
2847
2925
|
void_circle.net,
|
|
@@ -2871,7 +2949,7 @@ class Edb(Database):
|
|
|
2871
2949
|
|
|
2872
2950
|
_dbCells = [_cutout]
|
|
2873
2951
|
if output_aedb_path:
|
|
2874
|
-
db2 = self.
|
|
2952
|
+
db2 = self.core.Database.Create(output_aedb_path)
|
|
2875
2953
|
if not db2.Save():
|
|
2876
2954
|
self.logger.error("Failed to create new Edb. Check if the path already exists and remove it.")
|
|
2877
2955
|
return []
|
|
@@ -2880,7 +2958,7 @@ class Edb(Database):
|
|
|
2880
2958
|
cell = list(cell_copied)[0]
|
|
2881
2959
|
cell.SetName(os.path.basename(output_aedb_path[:-5]))
|
|
2882
2960
|
db2.Save()
|
|
2883
|
-
for c in list(self.
|
|
2961
|
+
for c in list(self._db.TopCircuitCells):
|
|
2884
2962
|
if c.GetName() == _cutout.GetName():
|
|
2885
2963
|
c.Delete()
|
|
2886
2964
|
if open_cutout_at_end: # pragma: no cover
|
|
@@ -3027,13 +3105,13 @@ class Edb(Database):
|
|
|
3027
3105
|
--------
|
|
3028
3106
|
|
|
3029
3107
|
>>> from pyedb import Edb
|
|
3030
|
-
>>> edb = Edb(edbpath="C:\\temp\\myproject.aedb",
|
|
3108
|
+
>>> edb = Edb(edbpath="C:\\temp\\myproject.aedb", version="2023.2")
|
|
3031
3109
|
|
|
3032
3110
|
>>> options_config = {'UNITE_NETS' : 1, 'LAUNCH_Q3D' : 0}
|
|
3033
3111
|
>>> edb.write_export3d_option_config_file(r"C:\\temp", options_config)
|
|
3034
3112
|
>>> edb.export_hfss(r"C:\\temp")
|
|
3035
3113
|
"""
|
|
3036
|
-
siwave_s = SiwaveSolve(self
|
|
3114
|
+
siwave_s = SiwaveSolve(self)
|
|
3037
3115
|
return siwave_s.export_3d_cad("HFSS", path_to_output, net_list, num_cores, aedt_file_name, hidden=hidden)
|
|
3038
3116
|
|
|
3039
3117
|
def export_q3d(
|
|
@@ -3070,13 +3148,13 @@ class Edb(Database):
|
|
|
3070
3148
|
--------
|
|
3071
3149
|
|
|
3072
3150
|
>>> from pyedb import Edb
|
|
3073
|
-
>>> edb = Edb(edbpath="C:\\temp\\myproject.aedb",
|
|
3151
|
+
>>> edb = Edb(edbpath="C:\\temp\\myproject.aedb", version="2021.2")
|
|
3074
3152
|
>>> options_config = {'UNITE_NETS' : 1, 'LAUNCH_Q3D' : 0}
|
|
3075
3153
|
>>> edb.write_export3d_option_config_file("C:\\temp", options_config)
|
|
3076
3154
|
>>> edb.export_q3d("C:\\temp")
|
|
3077
3155
|
"""
|
|
3078
3156
|
|
|
3079
|
-
siwave_s = SiwaveSolve(self
|
|
3157
|
+
siwave_s = SiwaveSolve(self)
|
|
3080
3158
|
return siwave_s.export_3d_cad(
|
|
3081
3159
|
"Q3D",
|
|
3082
3160
|
path_to_output,
|
|
@@ -3121,13 +3199,13 @@ class Edb(Database):
|
|
|
3121
3199
|
|
|
3122
3200
|
>>> from pyedb import Edb
|
|
3123
3201
|
|
|
3124
|
-
>>> edb = Edb(edbpath="C:\\temp\\myproject.aedb",
|
|
3202
|
+
>>> edb = Edb(edbpath="C:\\temp\\myproject.aedb", version="2021.2")
|
|
3125
3203
|
|
|
3126
3204
|
>>> options_config = {'UNITE_NETS' : 1, 'LAUNCH_Q3D' : 0}
|
|
3127
3205
|
>>> edb.write_export3d_option_config_file("C:\\temp", options_config)
|
|
3128
3206
|
>>> edb.export_maxwell("C:\\temp")
|
|
3129
3207
|
"""
|
|
3130
|
-
siwave_s = SiwaveSolve(self
|
|
3208
|
+
siwave_s = SiwaveSolve(self)
|
|
3131
3209
|
return siwave_s.export_3d_cad(
|
|
3132
3210
|
"Maxwell",
|
|
3133
3211
|
path_to_output,
|
|
@@ -3145,11 +3223,8 @@ class Edb(Database):
|
|
|
3145
3223
|
str
|
|
3146
3224
|
Siwave project path.
|
|
3147
3225
|
"""
|
|
3148
|
-
process = SiwaveSolve(self
|
|
3149
|
-
|
|
3150
|
-
self.close()
|
|
3151
|
-
except:
|
|
3152
|
-
pass
|
|
3226
|
+
process = SiwaveSolve(self)
|
|
3227
|
+
self.close()
|
|
3153
3228
|
process.solve()
|
|
3154
3229
|
return self.edbpath[:-5] + ".siw"
|
|
3155
3230
|
|
|
@@ -3196,11 +3271,8 @@ class Edb(Database):
|
|
|
3196
3271
|
list
|
|
3197
3272
|
List of files generated.
|
|
3198
3273
|
"""
|
|
3199
|
-
process = SiwaveSolve(self
|
|
3200
|
-
|
|
3201
|
-
self.close()
|
|
3202
|
-
except:
|
|
3203
|
-
pass
|
|
3274
|
+
process = SiwaveSolve(self)
|
|
3275
|
+
self.close()
|
|
3204
3276
|
return process.export_dc_report(
|
|
3205
3277
|
siwave_project,
|
|
3206
3278
|
solution_name,
|
|
@@ -3226,7 +3298,7 @@ class Edb(Database):
|
|
|
3226
3298
|
"""
|
|
3227
3299
|
if "$" in variable_name:
|
|
3228
3300
|
if variable_name.index("$") == 0:
|
|
3229
|
-
var_server = self.
|
|
3301
|
+
var_server = self._db.GetVariableServer()
|
|
3230
3302
|
|
|
3231
3303
|
else:
|
|
3232
3304
|
var_server = self.active_cell.GetVariableServer()
|
|
@@ -3239,6 +3311,17 @@ class Edb(Database):
|
|
|
3239
3311
|
return True, var_server
|
|
3240
3312
|
return False, var_server
|
|
3241
3313
|
|
|
3314
|
+
def get_all_variable_names(self):
|
|
3315
|
+
"""Method added for compatibility with grpc.
|
|
3316
|
+
|
|
3317
|
+
Returns
|
|
3318
|
+
-------
|
|
3319
|
+
List[Str]
|
|
3320
|
+
List of variables name.
|
|
3321
|
+
|
|
3322
|
+
"""
|
|
3323
|
+
return list(self.variable_exists("")[1].GetAllVariableNames())
|
|
3324
|
+
|
|
3242
3325
|
def get_variable(self, variable_name):
|
|
3243
3326
|
"""Return Variable Value if variable exists.
|
|
3244
3327
|
|
|
@@ -3457,8 +3540,8 @@ class Edb(Database):
|
|
|
3457
3540
|
):
|
|
3458
3541
|
self.logger.info("Cutout processed.")
|
|
3459
3542
|
old_cell = self.active_cell.FindByName(
|
|
3460
|
-
self.
|
|
3461
|
-
self.
|
|
3543
|
+
self._db,
|
|
3544
|
+
self.core.Cell.CellType.CircuitCell,
|
|
3462
3545
|
old_cell_name,
|
|
3463
3546
|
)
|
|
3464
3547
|
if old_cell:
|
|
@@ -3798,7 +3881,7 @@ class Edb(Database):
|
|
|
3798
3881
|
if name in self.setups:
|
|
3799
3882
|
self.logger.error("Setup name already used in the layout")
|
|
3800
3883
|
return False
|
|
3801
|
-
version = self.
|
|
3884
|
+
version = self.version.split(".")
|
|
3802
3885
|
if int(version[0]) >= 2024 and int(version[-1]) >= 2 or int(version[0]) > 2024:
|
|
3803
3886
|
setup = RaptorXSimulationSetup(self).create(name)
|
|
3804
3887
|
return setup
|
|
@@ -3823,8 +3906,7 @@ class Edb(Database):
|
|
|
3823
3906
|
if name in self.setups:
|
|
3824
3907
|
self.logger.error("Setup name already used in the layout")
|
|
3825
3908
|
return False
|
|
3826
|
-
version
|
|
3827
|
-
if float(self.edbversion) < 2024.2:
|
|
3909
|
+
if float(self.version) < 2024.2:
|
|
3828
3910
|
self.logger.error("HFSSPI simulation only supported with Ansys release 2024R2 and higher")
|
|
3829
3911
|
return False
|
|
3830
3912
|
return HFSSPISimulationSetup(self, name=name)
|
|
@@ -3890,6 +3972,7 @@ class Edb(Database):
|
|
|
3890
3972
|
setattr(setup, k, v)
|
|
3891
3973
|
return setup
|
|
3892
3974
|
|
|
3975
|
+
@execution_timer("calculate_initial_extent")
|
|
3893
3976
|
def calculate_initial_extent(self, expansion_factor):
|
|
3894
3977
|
"""Compute a float representing the larger number between the dielectric thickness or trace width
|
|
3895
3978
|
multiplied by the nW factor. The trace width search is limited to nets with ports attached.
|
|
@@ -3996,7 +4079,7 @@ class Edb(Database):
|
|
|
3996
4079
|
defined_ports = {}
|
|
3997
4080
|
project_connexions = None
|
|
3998
4081
|
for edb_path, zone_info in zone_dict.items():
|
|
3999
|
-
edb = Edb(
|
|
4082
|
+
edb = Edb(edbpath=edb_path)
|
|
4000
4083
|
edb.cutout(
|
|
4001
4084
|
use_pyaedt_cutout=True,
|
|
4002
4085
|
custom_extent=zone_info[1],
|
|
@@ -4568,10 +4651,9 @@ class Edb(Database):
|
|
|
4568
4651
|
``True`` when succeeded, ``False`` if failed.
|
|
4569
4652
|
"""
|
|
4570
4653
|
if not temp_directory:
|
|
4571
|
-
|
|
4572
|
-
return False
|
|
4654
|
+
raise RuntimeWarning("Temp directory must be provided when creating model foe arbitrary wave port")
|
|
4573
4655
|
if mounting_side not in ["top", "bottom"]:
|
|
4574
|
-
|
|
4656
|
+
raise RuntimeWarning(
|
|
4575
4657
|
"Mounting side must be provided and only `top` or `bottom` are supported. Setting to "
|
|
4576
4658
|
"`top` will take the top layer from the current design as reference. Setting to `bottom` "
|
|
4577
4659
|
"will take the bottom one."
|
|
@@ -4604,11 +4686,10 @@ class Edb(Database):
|
|
|
4604
4686
|
if poly.layer_name == reference_layer and poly.type == "Polygon" and poly.has_voids
|
|
4605
4687
|
]
|
|
4606
4688
|
if not polys:
|
|
4607
|
-
|
|
4689
|
+
raise RuntimeWarning(
|
|
4608
4690
|
f"No polygon found with voids on layer {reference_layer} during model creation for "
|
|
4609
4691
|
f"arbitrary wave ports"
|
|
4610
4692
|
)
|
|
4611
|
-
return False
|
|
4612
4693
|
void_padstacks = []
|
|
4613
4694
|
for poly in polys:
|
|
4614
4695
|
for void in poly.voids:
|
|
@@ -4623,11 +4704,10 @@ class Edb(Database):
|
|
|
4623
4704
|
void_padstacks.append((void, [self.padstacks.instances[edb_id] for edb_id in included_instances]))
|
|
4624
4705
|
|
|
4625
4706
|
if not void_padstacks:
|
|
4626
|
-
|
|
4707
|
+
raise RuntimeWarning(
|
|
4627
4708
|
"No padstack instances found inside evaluated voids during model creation for arbitrary" "waveports"
|
|
4628
4709
|
)
|
|
4629
|
-
|
|
4630
|
-
cloned_edb = Edb(edbpath=output_edb, edbversion=self.edbversion)
|
|
4710
|
+
cloned_edb = Edb(edbpath=output_edb)
|
|
4631
4711
|
|
|
4632
4712
|
cloned_edb.stackup.add_layer(
|
|
4633
4713
|
layer_name="ports",
|
|
@@ -4681,7 +4761,7 @@ class Edb(Database):
|
|
|
4681
4761
|
net_name=inst.net_name,
|
|
4682
4762
|
)
|
|
4683
4763
|
if not _temp_circle:
|
|
4684
|
-
|
|
4764
|
+
raise RuntimeWarning(
|
|
4685
4765
|
f"Failed to create circle for terminal during create_model_for_arbitrary_wave_ports"
|
|
4686
4766
|
)
|
|
4687
4767
|
cloned_edb.save_as(output_edb)
|
|
@@ -4764,7 +4844,6 @@ class Edb(Database):
|
|
|
4764
4844
|
bool
|
|
4765
4845
|
``True`` when successful, ``False`` when failed.
|
|
4766
4846
|
"""
|
|
4767
|
-
self.save()
|
|
4768
4847
|
if not results:
|
|
4769
4848
|
results = self.edbpath[:-5] + "_compare_results"
|
|
4770
4849
|
os.mkdir(results)
|
|
@@ -4774,11 +4853,10 @@ class Edb(Database):
|
|
|
4774
4853
|
cmd_input = [mono_path, command, input_file, self.edbpath, results]
|
|
4775
4854
|
else:
|
|
4776
4855
|
cmd_input = [command, input_file, self.edbpath, results]
|
|
4777
|
-
subprocess.run(cmd_input)
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
self.logger.error("Comparison execution failed")
|
|
4781
|
-
return False
|
|
4856
|
+
p = subprocess.run(cmd_input)
|
|
4857
|
+
if p.returncode == 0:
|
|
4858
|
+
return str(Path(self.base_path).joinpath("EDBDiff.exe"))
|
|
4782
4859
|
else:
|
|
4783
|
-
|
|
4784
|
-
|
|
4860
|
+
raise RuntimeError(
|
|
4861
|
+
"EDBDiff.exe execution failed. Please check if the executable is present in the base path."
|
|
4862
|
+
)
|