Skip to content

Commit cc8807a

Browse files
authored
Merge pull request #62 from ansys-internal/maint/integrate_prs_from_pyaedt
Integrate PRS from pyaedt
2 parents 2b11474 + c0c90e6 commit cc8807a

29 files changed

+2053
-1519
lines changed

.github/workflows/legacy_tests.yml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,8 @@ jobs:
4747

4848
- name: "Executing legacy unit tests"
4949
run: |
50-
pytest -m "legacy and unit" -n 6 -v
50+
pytest -m "legacy and unit" -n auto -v
5151
5252
- name: "Executing legacy system tests (distributing on multiple CPUs)"
5353
run: |
5454
pytest -m "legacy and system and not no_xdist" -n auto -v
55-
56-
- name: "Executing legacy system tests that cannot be distributed"
57-
run: |
58-
pytest -m "legacy and system and no_xdist" -v

doc/source/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ def setup(app):
318318
# specify the location of your github repo
319319
html_theme_options = {
320320
"github_url": "https://github.com/ansys/pyaedt",
321+
"navigation_with_keys": False,
321322
"show_prev_next": False,
322323
"show_breadcrumbs": True,
323324
"collapse_navigation": True,

examples/legacy/01_edb_example.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@
133133
edb.siwave.create_current_source_on_net("IC2", "NetD3_2", "IC2", "GND", 1.0, 0, "I1")
134134
setup = edb.siwave.add_siwave_dc_analysis("myDCIR_4")
135135
setup.use_dc_custom_settings = True
136-
setup.dc_slider_position = 0
136+
setup.set_dc_slider = 0
137137
setup.add_source_terminal_to_ground("V1", 1)
138138

139139

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ show_missing = true
153153

154154
[tool.pytest.ini_options]
155155
minversion = "7.1"
156+
xfail_strict = false
156157
filterwarnings = [
157158
"ignore::DeprecationWarning",
158159
]
@@ -165,7 +166,7 @@ markers = [
165166
"no_licence: mark test that do not need a licence.",
166167
]
167168
testpaths = "tests"
168-
addopts = "-ra --cov=src/pyedb --cov-report html:.cov/html --cov-report xml:.cov/xml --cov-report term -vv"
169+
#addopts = "-ra --cov=src/pyedb --cov-report html:.cov/html --cov-report xml:.cov/xml --cov-report term -vv"
169170

170171
[tool.numpydoc_validation]
171172
checks = [

src/pyedb/grpc/components.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,7 +1010,7 @@ def deactivate_rlc_component(self, component=None, create_circuit_port=False):
10101010
>>> from pyedb.grpc.edb import Edb
10111011
>>> edb_file = r'C:\my_edb_file.aedb'
10121012
>>> edb = Edb(edb_file)
1013-
>>> for cmp in list(edb.components.components.keys()):
1013+
>>> for cmp in list(edb.components.instances.keys()):
10141014
>>> edb.components.deactivate_rlc_component(component=cmp, create_circuit_port=False)
10151015
>>> edb.save_edb()
10161016
>>> edb.close_edb()
@@ -1031,12 +1031,10 @@ def deactivate_rlc_component(self, component=None, create_circuit_port=False):
10311031
self._logger.info("Component %s passed to deactivate is not an RLC.", component.refdes)
10321032
return False
10331033
component.is_enabled = False
1034-
if create_circuit_port:
1035-
return self.add_port_on_rlc_component(component.refdes)
1036-
return True
1034+
return self.add_port_on_rlc_component(component=component.refdes, circuit_ports=create_circuit_port)
10371035

10381036
@pyedb_function_handler()
1039-
def add_port_on_rlc_component(self, component=None):
1037+
def add_port_on_rlc_component(self, component=None, circuit_ports=True):
10401038
"""Deactivate RLC component and replace it with a circuit port.
10411039
The circuit port supports only 2-pin components.
10421040
@@ -1045,6 +1043,10 @@ def add_port_on_rlc_component(self, component=None):
10451043
component : str
10461044
Reference designator of the RLC component.
10471045
1046+
circuit_ports : bool
1047+
``True`` will replace RLC component by circuit ports, ``False`` gap ports compatible with HFSS 3D modeler
1048+
export.
1049+
10481050
Returns
10491051
-------
10501052
bool
@@ -1063,31 +1065,38 @@ def add_port_on_rlc_component(self, component=None):
10631065
pin_layers = self._padstack._get_pin_layer_range(pins[0])
10641066
pos_pin_term = terminal.PointTerminal.create(self._active_layout, pins[0].GetNet(),
10651067
"{}_{}".format(component.refdes, pins[0].GetName()),
1066-
pt,
1068+
pins[0],
10671069
pin_layers[0],
1070+
False,
10681071
)
10691072
if not pos_pin_term: # pragma: no cover
10701073
return False
10711074
neg_pin_loc = self.get_pin_position(pins[1])
10721075
pt = self._pedb.point_data(*neg_pin_loc)
10731076

1074-
neg_pin_term = terminal.PointTerminal.create(
1077+
neg_pin_term = terminal.PadstackInstanceTerminal.create(
10751078
self._active_layout,
10761079
pins[1].net,
10771080
"{}_{}_ref".format(component.refdes, pins[1].GetName()),
1078-
pt,
1081+
pins[1],
10791082
pin_layers[0],
1083+
False,
10801084
)
10811085
if not neg_pin_term: # pragma: no cover
10821086
return False
10831087
pos_pin_term.boundary_type = terminal.BoundaryType.PORT
1084-
pos_pin_term.is_circuit_port = True
10851088
pos_pin_term.name = component.refdes
10861089
neg_pin_term.boundary_type = terminal.BoundaryType.PORT
1087-
neg_pin_term.is_circuit_port = True
10881090
pos_pin_term.reference_terminal = neg_pin_term
1091+
if circuit_ports:
1092+
pos_pin_term.is_circuit_port = True
1093+
neg_pin_term.is_circuit_port = True
1094+
else:
1095+
pos_pin_term.is_circuit_port = False
1096+
neg_pin_term.is_circuit_port = False
10891097
self._logger.info("Component {} has been replaced by port".format(component.refdes))
10901098
return True
1099+
return False
10911100

10921101
@pyedb_function_handler()
10931102
def add_rlc_boundary(self, component=None, circuit_type=True):

src/pyedb/grpc/edb.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,6 @@ def _clean_variables(self):
259259
self._siwave = None
260260
self._hfss = None
261261
self._nets = None
262-
self._setups = {}
263262
self._layout_instance = None
264263
self._variables = None
265264
self._active_cell = None
@@ -2869,7 +2868,7 @@ def build_simulation_project(self, simulation_setup):
28692868
self.edbpath = legacy_name
28702869
self.open_edb()
28712870
return True
2872-
except: # pragma: no cover
2871+
except:
28732872
return False
28742873

28752874
@pyedb_function_handler()
@@ -3027,7 +3026,7 @@ def siwave_dc_setups(self):
30273026
-------
30283027
Dict[str, :class:`pyaedt.edb_core.edb_data.siwave_simulation_setup_data.SiwaveDCSimulationSetup`]
30293028
"""
3030-
return {name: i for name, i in self.setups.items() if i.setup_type == "kSIWaveDCIR"}
3029+
return {name: i for name, i in self.setups.items() if isinstance(i, SiwaveDCSimulationSetup)}
30313030

30323031
@property
30333032
def siwave_ac_setups(self):
@@ -3037,10 +3036,12 @@ def siwave_ac_setups(self):
30373036
-------
30383037
Dict[str, :class:`pyaedt.edb_core.edb_data.siwave_simulation_setup_data.SiwaveSYZSimulationSetup`]
30393038
"""
3040-
return {name: i for name, i in self.setups.items() if i.setup_type == "kSIWave"}
3039+
return {name: i for name, i in self.setups.items() if isinstance(i, SiwaveSYZSimulationSetup)}
3040+
30413041

30423042
def create_hfss_setup(self, name=None):
3043-
"""Create a setup from a template.
3043+
"""Create an HFSS simulation setup from a template.
3044+
30443045
30453046
Parameters
30463047
----------
@@ -3058,8 +3059,7 @@ def create_hfss_setup(self, name=None):
30583059
"""
30593060
if name in self.setups:
30603061
return False
3061-
setup = HfssSimulationSetup(self, name)
3062-
self._setups[name] = setup
3062+
setup = HfssSimulationSetup(self).create(name)
30633063
return setup
30643064

30653065
@pyedb_function_handler()
@@ -3115,8 +3115,7 @@ def create_siwave_dc_setup(self, name=None):
31153115
name = generate_unique_name("Siwave_DC")
31163116
if name in self.setups:
31173117
return False
3118-
setup = SiwaveDCSimulationSetup(self, name)
3119-
self._setups[name] = setup
3118+
setup = SiwaveDCSimulationSetup(self).create(name)
31203119
return setup
31213120

31223121
@pyedb_function_handler()

src/pyedb/grpc/edb_core/edb_data/primitives_data.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,108 @@ def create_edge_port(
844844
else:
845845
return self._app.hfss.create_edge_port_vertical(self.id, pos, name, 50, reference_layer)
846846

847+
@pyedb_function_handler()
848+
def create_via_fence(self, distance, gap, padstack_name):
849+
"""Create via fences on both sides of the trace.
850+
Parameters
851+
----------
852+
distance: str, float
853+
Distance between via fence and trace center line.
854+
gap: str, float
855+
Gap between vias.
856+
padstack_name: str
857+
Name of the via padstack.
858+
Returns
859+
-------
860+
"""
861+
862+
def getAngle(v1, v2): # pragma: no cover
863+
v1_mag = math.sqrt(v1[0] ** 2 + v1[1] ** 2)
864+
v2_mag = math.sqrt(v2[0] ** 2 + v2[1] ** 2)
865+
dotsum = v1[0] * v2[0] + v1[1] * v2[1]
866+
if v1[0] * v2[1] - v1[1] * v2[0] > 0:
867+
scale = 1
868+
else:
869+
scale = -1
870+
dtheta = scale * math.acos(dotsum / (v1_mag * v2_mag))
871+
872+
return dtheta
873+
874+
def getLocations(line, gap): # pragma: no cover
875+
location = [line[0]]
876+
residual = 0
877+
878+
for n in range(len(line) - 1):
879+
x0, y0 = line[n]
880+
x1, y1 = line[n + 1]
881+
length = math.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2)
882+
dx, dy = (x1 - x0) / length, (y1 - y0) / length
883+
x = x0 - dx * residual
884+
y = y0 - dy * residual
885+
length = length + residual
886+
while length >= gap:
887+
x += gap * dx
888+
y += gap * dy
889+
location.append((x, y))
890+
length -= gap
891+
892+
residual = length
893+
return location
894+
895+
def getParalletLines(pts, distance): # pragma: no cover
896+
leftline = []
897+
rightline = []
898+
899+
x0, y0 = pts[0]
900+
x1, y1 = pts[1]
901+
vector = (x1 - x0, y1 - y0)
902+
orientation1 = getAngle((1, 0), vector)
903+
904+
leftturn = orientation1 + math.pi / 2
905+
righrturn = orientation1 - math.pi / 2
906+
leftPt = (x0 + distance * math.cos(leftturn), y0 + distance * math.sin(leftturn))
907+
leftline.append(leftPt)
908+
rightPt = (x0 + distance * math.cos(righrturn), y0 + distance * math.sin(righrturn))
909+
rightline.append(rightPt)
910+
911+
for n in range(1, len(pts) - 1):
912+
x0, y0 = pts[n - 1]
913+
x1, y1 = pts[n]
914+
x2, y2 = pts[n + 1]
915+
916+
v1 = (x1 - x0, y1 - y0)
917+
v2 = (x2 - x1, y2 - y1)
918+
dtheta = getAngle(v1, v2)
919+
orientation1 = getAngle((1, 0), v1)
920+
921+
leftturn = orientation1 + dtheta / 2 + math.pi / 2
922+
righrturn = orientation1 + dtheta / 2 - math.pi / 2
923+
924+
distance2 = distance / math.sin((math.pi - dtheta) / 2)
925+
leftPt = (x1 + distance2 * math.cos(leftturn), y1 + distance2 * math.sin(leftturn))
926+
leftline.append(leftPt)
927+
rightPt = (x1 + distance2 * math.cos(righrturn), y1 + distance2 * math.sin(righrturn))
928+
rightline.append(rightPt)
929+
930+
x0, y0 = pts[-2]
931+
x1, y1 = pts[-1]
932+
933+
vector = (x1 - x0, y1 - y0)
934+
orientation1 = getAngle((1, 0), vector)
935+
leftturn = orientation1 + math.pi / 2
936+
righrturn = orientation1 - math.pi / 2
937+
leftPt = (x1 + distance * math.cos(leftturn), y1 + distance * math.sin(leftturn))
938+
leftline.append(leftPt)
939+
rightPt = (x1 + distance * math.cos(righrturn), y1 + distance * math.sin(righrturn))
940+
rightline.append(rightPt)
941+
return leftline, rightline
942+
943+
distance = self._pedb.edb_value(distance).ToDouble()
944+
gap = self._pedb.edb_value(gap).ToDouble()
945+
center_line = self.get_center_line()
946+
leftline, rightline = getParalletLines(center_line, distance)
947+
for x, y in getLocations(rightline, gap) + getLocations(leftline, gap):
948+
self._pedb.padstacks.place([x, y], padstack_name)
847949

848950
class EdbRectangle(EDBPrimitives):
849951
def __init__(self, raw_primitive, core_app):

src/pyedb/grpc/stackup.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,7 +1526,7 @@ def _import_csv(self, file_path):
15261526
15271527
Parameters
15281528
----------
1529-
fpath : str
1529+
file_path : str
15301530
File path to the CSV file.
15311531
"""
15321532
if not pd:
@@ -1539,17 +1539,17 @@ def _import_csv(self, file_path):
15391539
logger.error("{} doesn't exist in csv".format(name))
15401540
return False
15411541

1542-
for name, l in df.iterrows():
1543-
layer_type = l.Type
1542+
for name, layer_info in df.iterrows():
1543+
layer_type = layer_info.Type
15441544
if name in self.layers:
15451545
layer = self.layers[name]
15461546
layer.type = layer_type
15471547
else:
15481548
layer = self.add_layer(name, layer_type=layer_type, material="copper", fillMaterial="copper")
15491549

1550-
layer.material = l.Material
1551-
layer.thickness = l.Thickness
1552-
layer.dielectric_fill = l.Dielectric_Fill
1550+
layer.material = layer_info.Material
1551+
layer.thickness = layer_info.Thickness
1552+
layer.dielectric_fill = layer_info.Dielectric_Fill
15531553

15541554
lc_new = layer_collection.LayerCollection()
15551555
for name, _ in df.iterrows():

0 commit comments

Comments
 (0)