Skip to content

Added Components Catalog indexing to Nexxim and TwinBuilder #865

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions _unittest/test_21_Circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,3 +302,11 @@ def test_25_zoom_to_fit(self):
myres = self.aedtapp.modeler.components.create_resistor("R100", 50)
mycap = self.aedtapp.modeler.components.create_capacitor("C100", 1e-12)
self.aedtapp.modeler.zoom_to_fit()

def test_26_component_catalog(self):
comp_catalog = self.aedtapp.modeler.components.components_catalog
assert comp_catalog["Capacitors:Cap_"]
assert comp_catalog["capacitors:cAp_"]
assert isinstance(comp_catalog.find_components("cap"), list)
assert comp_catalog["LISN:CISPR25_LISN"].place("Lisn1")
assert not comp_catalog["Capacitors"]
2 changes: 1 addition & 1 deletion pyaedt/application/Design.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ def project_properies(self):
start = time.time()
if not self._project_dictionary and os.path.exists(self.project_file):
self._project_dictionary = load_entire_aedt_file(self.project_file)
self._logger.info("AEDT Load time {}".format(time.time() - start))
self._logger.info("aedt file load time {}".format(time.time() - start))
return self._project_dictionary

@property
Expand Down
5 changes: 2 additions & 3 deletions pyaedt/generic/LoadAEDTFile.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
import re
from pyaedt.generic.general_methods import time_fn

# --------------------------------------------------------------------
# public interface
Expand All @@ -16,7 +15,7 @@ def load_entire_aedt_file(filename):

Returns
-------
type
dict
dictionary containing the decoded AEDT file

"""
Expand Down Expand Up @@ -342,7 +341,7 @@ def _load_entire_aedt_file(filename):

"""
global _count
time_fn(_read_aedt_file, filename)
_read_aedt_file(filename)
main_dict = {}
# load the aedt file
while _count < _len_all_lines:
Expand Down
39 changes: 39 additions & 0 deletions pyaedt/generic/general_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import inspect
import itertools
import re
import fnmatch

try:
logger = logging.getLogger("Global")
Expand Down Expand Up @@ -566,3 +567,41 @@ def _create_pattern(k1, k2):
if m:
return True
return False


@aedt_exception_handler
def filter_string(value, search_key1):
"""Filter a string"""
ignore_case = True

def _create_pattern(k1):
k1a = re.sub(r"\?", r".", k1)
k1b = re.sub(r"\*", r".*?", k1a)
pattern = r"^{}$".format(k1b)
return pattern

if ignore_case:
compiled_re = re.compile(_create_pattern(search_key1), re.IGNORECASE)
else:
compiled_re = re.compile(_create_pattern(search_key1)) # pragma: no cover

m = compiled_re.search(value)
if m:
return True
return False


@aedt_exception_handler
def recursive_glob(startpath, filepattern):
"""Return a list of files matching a pattern, searching recursively from a start path.

Keyword Arguments:
startpath -- starting path (directory)
filepattern -- fnmatch-style filename pattern
"""
return [
os.path.join(dirpath, filename)
for dirpath, _, filenames in os.walk(startpath)
for filename in filenames
if fnmatch.fnmatch(filename, filepattern)
]
131 changes: 130 additions & 1 deletion pyaedt/modeler/PrimitivesCircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,18 @@
import os
import math

from pyaedt.generic.general_methods import aedt_exception_handler, _retry_ntimes, generate_unique_name

from pyaedt.generic.general_methods import (
aedt_exception_handler,
_retry_ntimes,
generate_unique_name,
recursive_glob,
filter_string,
)
from pyaedt.modeler.Object3d import CircuitComponent
from pyaedt.generic.constants import AEDT_UNITS
from pyaedt.generic.TouchstoneParser import _parse_ports_name
from pyaedt.generic.LoadAEDTFile import load_entire_aedt_file


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

return val


class ComponentInfo(object):
"""Class that manage Circuit Catalog info."""

def __init__(self, name, component_manager, props):
self._component_manager = component_manager
self.props = props
self.name = name
self.component_library = self.props.get("ComponentLibrary", None)

def place(self, inst_name, location=[], angle=0, use_instance_id_netlist=False):
"""Create a component from a library.

Parameters
----------
inst_name : str, optional
Name of the instance. The default is ``None.``
location : list of float, optional
Position on the X axis and Y axis.
angle : optional
Angle rotation in degrees. The default is ``0``.
use_instance_id_netlist : bool, optional
Whether to enable the instance ID in the net list.
The default is ``False``.

Returns
-------
:class:`pyaedt.modeler.Object3d.CircuitComponent`
Circuit Component Object.

References
----------

>>> oEditor.CreateComponent
"""
return self._component_manager.create_component(
inst_name=inst_name,
component_library=self.component_library,
component_name=self.name,
location=location,
angle=angle,
use_instance_id_netlist=use_instance_id_netlist,
)


class ComponentCatalog(object):
"""Class that indexes Circuit Sys Catalog."""

@aedt_exception_handler
def __getitem__(self, compname):
"""Get component from name.

Parameters
----------
compname : str
ID or name of the object.

Returns
-------
:class:`pyaedt.modeler.PrimitivesCircuit.ComponentInfo`
Circuit Component Info.

"""
items = self.find_components("*" + compname)
if items and len(items) == 1:
return self.components[items[0]]
elif len(items) > 1:
self._component_manager._logger.warning("Multiple components found.")
return None
else:
self._component_manager._logger.warning("Component not found.")
return None

def __init__(self, component_manager):
self._component_manager = component_manager
self._app = self._component_manager._app
self.components = {}
self._index_components()

@aedt_exception_handler
def _index_components(self, library_path=None):
if library_path:
sys_files = recursive_glob(library_path, "*.aclb")
root = os.path.normpath(library_path).split(os.path.sep)[-1]
else:
sys_files = recursive_glob(os.path.join(self._app.syslib, self._component_manager.design_libray), "*.aclb")
root = os.path.normpath(self._app.syslib).split(os.path.sep)[-1]
for file in sys_files:
comps = load_entire_aedt_file(file)
for compname, comp_value in comps.items():
if compname not in ["$base_index$", "$index$", "DefInfo"]:
root_name, ext = os.path.splitext(os.path.basename(file))
full_path = os.path.normpath(file).split(os.path.sep)
id = full_path.index(root) + 1
if self._component_manager.design_libray in full_path[id:]:
id += 1
full_path[-1] = full_path[-1].replace(".aclb", "")
comp_value["ComponentLibrary"] = "\\".join(full_path[id:])
self.components["{}:{}".format(root_name, compname)] = ComponentInfo(
compname, self._component_manager, comp_value
)

@aedt_exception_handler
def find_components(self, filter_str="*"):
"""Find all components with given filter wildcards.

Parameters
----------
filter_str : str
Filter String to search.

Returns
list
List of matching component names.
"""
c = []
for el in list(self.components.keys()):
if filter_string(el, filter_str):
c.append(el)
return c
20 changes: 18 additions & 2 deletions pyaedt/modeler/PrimitivesNexxim.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import os

from pyaedt.generic.general_methods import aedt_exception_handler, generate_unique_name
from pyaedt.modeler.PrimitivesCircuit import CircuitComponents
from pyaedt.modeler.PrimitivesCircuit import CircuitComponents, ComponentCatalog
from pyaedt.modeler.Object3d import CircuitComponent


Expand Down Expand Up @@ -52,12 +52,28 @@ def __getitem__(self, partname):

return None

@property
def _logger(self):
return self._app.logger

def __init__(self, modeler):
CircuitComponents.__init__(self, modeler)
self._app = modeler._app
self._modeler = modeler
self._currentId = 0
pass
self._components_catalog = None

@property
def components_catalog(self):
"""Return the syslib component catalog with all info.

Returns
-------
:class:`pyaedt.modeler.PrimitivesCircuit.ComponentCatalog`
"""
if not self._components_catalog:
self._components_catalog = ComponentCatalog(self)
return self._components_catalog

@aedt_exception_handler
def connect_components_in_series(self, components_to_connect):
Expand Down
16 changes: 14 additions & 2 deletions pyaedt/modeler/PrimitivesSimplorer.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pyaedt.generic.general_methods import aedt_exception_handler
from pyaedt.modeler.PrimitivesCircuit import CircuitComponents
from pyaedt.modeler.PrimitivesCircuit import CircuitComponents, ComponentCatalog


class SimplorerComponents(CircuitComponents):
Expand Down Expand Up @@ -60,7 +60,19 @@ def __init__(self, modeler):
self._app = modeler._app
self._modeler = modeler
self._currentId = 0
pass
self._components_catalog = None

@property
def components_catalog(self):
"""Return the syslib component catalog with all info.

Returns
-------
:class:`pyaedt.modeler.PrimitivesCircuit.ComponentCatalog`
"""
if not self._components_catalog:
self._components_catalog = ComponentCatalog(self)
return self._components_catalog

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