Skip to content

Commit fe7af1a

Browse files
authored
Added Components Catalog indexing to Nexxim and TwinBuilder (#865)
* Added Components Catalog indexing to Nexxim and TwinBuilder * Added Components Catalog indexing to Nexxim and TwinBuilder * Added Components Catalog indexing to Nexxim and TwinBuilder Co-authored-by: maxcapodi78 <Shark78>
1 parent 0704e53 commit fe7af1a

File tree

7 files changed

+212
-9
lines changed

7 files changed

+212
-9
lines changed

_unittest/test_21_Circuit.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,3 +302,11 @@ def test_25_zoom_to_fit(self):
302302
myres = self.aedtapp.modeler.components.create_resistor("R100", 50)
303303
mycap = self.aedtapp.modeler.components.create_capacitor("C100", 1e-12)
304304
self.aedtapp.modeler.zoom_to_fit()
305+
306+
def test_26_component_catalog(self):
307+
comp_catalog = self.aedtapp.modeler.components.components_catalog
308+
assert comp_catalog["Capacitors:Cap_"]
309+
assert comp_catalog["capacitors:cAp_"]
310+
assert isinstance(comp_catalog.find_components("cap"), list)
311+
assert comp_catalog["LISN:CISPR25_LISN"].place("Lisn1")
312+
assert not comp_catalog["Capacitors"]

pyaedt/application/Design.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ def project_properies(self):
484484
start = time.time()
485485
if not self._project_dictionary and os.path.exists(self.project_file):
486486
self._project_dictionary = load_entire_aedt_file(self.project_file)
487-
self._logger.info("AEDT Load time {}".format(time.time() - start))
487+
self._logger.info("aedt file load time {}".format(time.time() - start))
488488
return self._project_dictionary
489489

490490
@property

pyaedt/generic/LoadAEDTFile.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# -*- coding: utf-8 -*-
22
import re
3-
from pyaedt.generic.general_methods import time_fn
43

54
# --------------------------------------------------------------------
65
# public interface
@@ -16,7 +15,7 @@ def load_entire_aedt_file(filename):
1615
1716
Returns
1817
-------
19-
type
18+
dict
2019
dictionary containing the decoded AEDT file
2120
2221
"""
@@ -342,7 +341,7 @@ def _load_entire_aedt_file(filename):
342341
343342
"""
344343
global _count
345-
time_fn(_read_aedt_file, filename)
344+
_read_aedt_file(filename)
346345
main_dict = {}
347346
# load the aedt file
348347
while _count < _len_all_lines:

pyaedt/generic/general_methods.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import inspect
1313
import itertools
1414
import re
15+
import fnmatch
1516

1617
try:
1718
logger = logging.getLogger("Global")
@@ -566,3 +567,41 @@ def _create_pattern(k1, k2):
566567
if m:
567568
return True
568569
return False
570+
571+
572+
@aedt_exception_handler
573+
def filter_string(value, search_key1):
574+
"""Filter a string"""
575+
ignore_case = True
576+
577+
def _create_pattern(k1):
578+
k1a = re.sub(r"\?", r".", k1)
579+
k1b = re.sub(r"\*", r".*?", k1a)
580+
pattern = r"^{}$".format(k1b)
581+
return pattern
582+
583+
if ignore_case:
584+
compiled_re = re.compile(_create_pattern(search_key1), re.IGNORECASE)
585+
else:
586+
compiled_re = re.compile(_create_pattern(search_key1)) # pragma: no cover
587+
588+
m = compiled_re.search(value)
589+
if m:
590+
return True
591+
return False
592+
593+
594+
@aedt_exception_handler
595+
def recursive_glob(startpath, filepattern):
596+
"""Return a list of files matching a pattern, searching recursively from a start path.
597+
598+
Keyword Arguments:
599+
startpath -- starting path (directory)
600+
filepattern -- fnmatch-style filename pattern
601+
"""
602+
return [
603+
os.path.join(dirpath, filename)
604+
for dirpath, _, filenames in os.walk(startpath)
605+
for filename in filenames
606+
if fnmatch.fnmatch(filename, filepattern)
607+
]

pyaedt/modeler/PrimitivesCircuit.py

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,18 @@
33
import os
44
import math
55

6-
from pyaedt.generic.general_methods import aedt_exception_handler, _retry_ntimes, generate_unique_name
6+
7+
from pyaedt.generic.general_methods import (
8+
aedt_exception_handler,
9+
_retry_ntimes,
10+
generate_unique_name,
11+
recursive_glob,
12+
filter_string,
13+
)
714
from pyaedt.modeler.Object3d import CircuitComponent
815
from pyaedt.generic.constants import AEDT_UNITS
916
from pyaedt.generic.TouchstoneParser import _parse_ports_name
17+
from pyaedt.generic.LoadAEDTFile import load_entire_aedt_file
1018

1119

1220
class CircuitComponents(object):
@@ -1229,3 +1237,124 @@ def arg_with_dim(self, Value, sUnits=None):
12291237
val = "{0}{1}".format(Value, sUnits)
12301238

12311239
return val
1240+
1241+
1242+
class ComponentInfo(object):
1243+
"""Class that manage Circuit Catalog info."""
1244+
1245+
def __init__(self, name, component_manager, props):
1246+
self._component_manager = component_manager
1247+
self.props = props
1248+
self.name = name
1249+
self.component_library = self.props.get("ComponentLibrary", None)
1250+
1251+
def place(self, inst_name, location=[], angle=0, use_instance_id_netlist=False):
1252+
"""Create a component from a library.
1253+
1254+
Parameters
1255+
----------
1256+
inst_name : str, optional
1257+
Name of the instance. The default is ``None.``
1258+
location : list of float, optional
1259+
Position on the X axis and Y axis.
1260+
angle : optional
1261+
Angle rotation in degrees. The default is ``0``.
1262+
use_instance_id_netlist : bool, optional
1263+
Whether to enable the instance ID in the net list.
1264+
The default is ``False``.
1265+
1266+
Returns
1267+
-------
1268+
:class:`pyaedt.modeler.Object3d.CircuitComponent`
1269+
Circuit Component Object.
1270+
1271+
References
1272+
----------
1273+
1274+
>>> oEditor.CreateComponent
1275+
"""
1276+
return self._component_manager.create_component(
1277+
inst_name=inst_name,
1278+
component_library=self.component_library,
1279+
component_name=self.name,
1280+
location=location,
1281+
angle=angle,
1282+
use_instance_id_netlist=use_instance_id_netlist,
1283+
)
1284+
1285+
1286+
class ComponentCatalog(object):
1287+
"""Class that indexes Circuit Sys Catalog."""
1288+
1289+
@aedt_exception_handler
1290+
def __getitem__(self, compname):
1291+
"""Get component from name.
1292+
1293+
Parameters
1294+
----------
1295+
compname : str
1296+
ID or name of the object.
1297+
1298+
Returns
1299+
-------
1300+
:class:`pyaedt.modeler.PrimitivesCircuit.ComponentInfo`
1301+
Circuit Component Info.
1302+
1303+
"""
1304+
items = self.find_components("*" + compname)
1305+
if items and len(items) == 1:
1306+
return self.components[items[0]]
1307+
elif len(items) > 1:
1308+
self._component_manager._logger.warning("Multiple components found.")
1309+
return None
1310+
else:
1311+
self._component_manager._logger.warning("Component not found.")
1312+
return None
1313+
1314+
def __init__(self, component_manager):
1315+
self._component_manager = component_manager
1316+
self._app = self._component_manager._app
1317+
self.components = {}
1318+
self._index_components()
1319+
1320+
@aedt_exception_handler
1321+
def _index_components(self, library_path=None):
1322+
if library_path:
1323+
sys_files = recursive_glob(library_path, "*.aclb")
1324+
root = os.path.normpath(library_path).split(os.path.sep)[-1]
1325+
else:
1326+
sys_files = recursive_glob(os.path.join(self._app.syslib, self._component_manager.design_libray), "*.aclb")
1327+
root = os.path.normpath(self._app.syslib).split(os.path.sep)[-1]
1328+
for file in sys_files:
1329+
comps = load_entire_aedt_file(file)
1330+
for compname, comp_value in comps.items():
1331+
if compname not in ["$base_index$", "$index$", "DefInfo"]:
1332+
root_name, ext = os.path.splitext(os.path.basename(file))
1333+
full_path = os.path.normpath(file).split(os.path.sep)
1334+
id = full_path.index(root) + 1
1335+
if self._component_manager.design_libray in full_path[id:]:
1336+
id += 1
1337+
full_path[-1] = full_path[-1].replace(".aclb", "")
1338+
comp_value["ComponentLibrary"] = "\\".join(full_path[id:])
1339+
self.components["{}:{}".format(root_name, compname)] = ComponentInfo(
1340+
compname, self._component_manager, comp_value
1341+
)
1342+
1343+
@aedt_exception_handler
1344+
def find_components(self, filter_str="*"):
1345+
"""Find all components with given filter wildcards.
1346+
1347+
Parameters
1348+
----------
1349+
filter_str : str
1350+
Filter String to search.
1351+
1352+
Returns
1353+
list
1354+
List of matching component names.
1355+
"""
1356+
c = []
1357+
for el in list(self.components.keys()):
1358+
if filter_string(el, filter_str):
1359+
c.append(el)
1360+
return c

pyaedt/modeler/PrimitivesNexxim.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import os
33

44
from pyaedt.generic.general_methods import aedt_exception_handler, generate_unique_name
5-
from pyaedt.modeler.PrimitivesCircuit import CircuitComponents
5+
from pyaedt.modeler.PrimitivesCircuit import CircuitComponents, ComponentCatalog
66
from pyaedt.modeler.Object3d import CircuitComponent
77

88

@@ -52,12 +52,28 @@ def __getitem__(self, partname):
5252

5353
return None
5454

55+
@property
56+
def _logger(self):
57+
return self._app.logger
58+
5559
def __init__(self, modeler):
5660
CircuitComponents.__init__(self, modeler)
5761
self._app = modeler._app
5862
self._modeler = modeler
5963
self._currentId = 0
60-
pass
64+
self._components_catalog = None
65+
66+
@property
67+
def components_catalog(self):
68+
"""Return the syslib component catalog with all info.
69+
70+
Returns
71+
-------
72+
:class:`pyaedt.modeler.PrimitivesCircuit.ComponentCatalog`
73+
"""
74+
if not self._components_catalog:
75+
self._components_catalog = ComponentCatalog(self)
76+
return self._components_catalog
6177

6278
@aedt_exception_handler
6379
def connect_components_in_series(self, components_to_connect):

pyaedt/modeler/PrimitivesSimplorer.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from pyaedt.generic.general_methods import aedt_exception_handler
2-
from pyaedt.modeler.PrimitivesCircuit import CircuitComponents
2+
from pyaedt.modeler.PrimitivesCircuit import CircuitComponents, ComponentCatalog
33

44

55
class SimplorerComponents(CircuitComponents):
@@ -60,7 +60,19 @@ def __init__(self, modeler):
6060
self._app = modeler._app
6161
self._modeler = modeler
6262
self._currentId = 0
63-
pass
63+
self._components_catalog = None
64+
65+
@property
66+
def components_catalog(self):
67+
"""Return the syslib component catalog with all info.
68+
69+
Returns
70+
-------
71+
:class:`pyaedt.modeler.PrimitivesCircuit.ComponentCatalog`
72+
"""
73+
if not self._components_catalog:
74+
self._components_catalog = ComponentCatalog(self)
75+
return self._components_catalog
6476

6577
@aedt_exception_handler
6678
def create_resistor(self, compname=None, value=50, location=[], angle=0, use_instance_id_netlist=False):

0 commit comments

Comments
 (0)